Merge branch 'develop' into enh-remove-v-code-diff

This commit is contained in:
kakkokari-gtyih 2026-01-24 02:46:33 +09:00
commit e10d3d15c3
24 changed files with 2365 additions and 2263 deletions

View File

@ -54,55 +54,110 @@ jobs:
BASE_MEMORY=$(cat ./artifacts/memory-base.json) BASE_MEMORY=$(cat ./artifacts/memory-base.json)
HEAD_MEMORY=$(cat ./artifacts/memory-head.json) HEAD_MEMORY=$(cat ./artifacts/memory-head.json)
BASE_RSS=$(echo "$BASE_MEMORY" | jq -r '.memory.rss // 0') variation() {
HEAD_RSS=$(echo "$HEAD_MEMORY" | jq -r '.memory.rss // 0') calc() {
BASE=$(echo "$BASE_MEMORY" | jq -r ".${1}.${2} // 0")
HEAD=$(echo "$HEAD_MEMORY" | jq -r ".${1}.${2} // 0")
# Calculate difference DIFF=$((HEAD - BASE))
if [ "$BASE_RSS" -gt 0 ] && [ "$HEAD_RSS" -gt 0 ]; then if [ "$BASE" -gt 0 ]; then
DIFF=$((HEAD_RSS - BASE_RSS)) DIFF_PERCENT=$(echo "scale=2; ($DIFF * 100) / $BASE" | bc)
DIFF_PERCENT=$(echo "scale=2; ($DIFF * 100) / $BASE_RSS" | bc) else
DIFF_PERCENT=0
fi
# Convert to MB for readability # Convert KB to MB for readability
BASE_MB=$(echo "scale=2; $BASE_RSS / 1048576" | bc) BASE_MB=$(echo "scale=2; $BASE / 1024" | bc)
HEAD_MB=$(echo "scale=2; $HEAD_RSS / 1048576" | bc) HEAD_MB=$(echo "scale=2; $HEAD / 1024" | bc)
DIFF_MB=$(echo "scale=2; $DIFF / 1048576" | bc) DIFF_MB=$(echo "scale=2; $DIFF / 1024" | bc)
echo "base_mb=$BASE_MB" >> "$GITHUB_OUTPUT" JSON=$(jq -c -n \
echo "head_mb=$HEAD_MB" >> "$GITHUB_OUTPUT" --argjson base "$BASE_MB" \
echo "diff_mb=$DIFF_MB" >> "$GITHUB_OUTPUT" --argjson head "$HEAD_MB" \
echo "diff_percent=$DIFF_PERCENT" >> "$GITHUB_OUTPUT" --argjson diff "$DIFF_MB" \
echo "has_data=true" >> "$GITHUB_OUTPUT" --argjson diff_percent "$DIFF_PERCENT" \
'{base: $base, head: $head, diff: $diff, diff_percent: $diff_percent}')
# Determine if this is a significant change (more than 5% increase) echo "$JSON"
if [ "$(echo "$DIFF_PERCENT > 5" | bc)" -eq 1 ]; then }
echo "significant_increase=true" >> "$GITHUB_OUTPUT"
else JSON=$(jq -c -n \
echo "significant_increase=false" >> "$GITHUB_OUTPUT" --argjson VmRSS "$(calc $1 VmRSS)" \
fi --argjson VmHWM "$(calc $1 VmHWM)" \
else --argjson VmSize "$(calc $1 VmSize)" \
echo "has_data=false" >> "$GITHUB_OUTPUT" --argjson VmData "$(calc $1 VmData)" \
fi '{VmRSS: $VmRSS, VmHWM: $VmHWM, VmSize: $VmSize, VmData: $VmData}')
echo "$JSON"
}
JSON=$(jq -c -n \
--argjson beforeGc "$(variation beforeGc)" \
--argjson afterGc "$(variation afterGc)" \
--argjson afterRequest "$(variation afterRequest)" \
'{beforeGc: $beforeGc, afterGc: $afterGc, afterRequest: $afterRequest}')
echo "res=$JSON" >> "$GITHUB_OUTPUT"
- id: build-comment - id: build-comment
name: Build memory comment name: Build memory comment
env:
RES: ${{ steps.compare.outputs.res }}
run: | run: |
HEADER="## Backend Memory Usage Comparison" HEADER="## Backend memory usage comparison"
FOOTER="[See workflow logs for details](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})" FOOTER="[See workflow logs for details](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
echo "$HEADER" > ./output.md echo "$HEADER" > ./output.md
echo >> ./output.md echo >> ./output.md
if [ "${{ steps.compare.outputs.has_data }}" == "true" ]; then table() {
echo "| Metric | base | head | Diff |" >> ./output.md echo "| Metric | base (MB) | head (MB) | Diff (MB) | Diff (%) |" >> ./output.md
echo "|--------|------|------|------|" >> ./output.md echo "|--------|------:|------:|------:|------:|" >> ./output.md
echo "| RSS | ${{ steps.compare.outputs.base_mb }} MB | ${{ steps.compare.outputs.head_mb }} MB | ${{ steps.compare.outputs.diff_mb }} MB (${{ steps.compare.outputs.diff_percent }}%) |" >> ./output.md
echo >> ./output.md
if [ "${{ steps.compare.outputs.significant_increase }}" == "true" ]; then line() {
echo "⚠️ **Warning**: Memory usage has increased by more than 5%. Please verify this is not an unintended change." >> ./output.md METRIC=$2
echo >> ./output.md BASE=$(echo "$RES" | jq -r ".${1}.${2}.base")
fi HEAD=$(echo "$RES" | jq -r ".${1}.${2}.head")
else DIFF=$(echo "$RES" | jq -r ".${1}.${2}.diff")
echo "Could not retrieve memory usage data." >> ./output.md DIFF_PERCENT=$(echo "$RES" | jq -r ".${1}.${2}.diff_percent")
if (( $(echo "$DIFF_PERCENT > 0" | bc -l) )); then
DIFF="+$DIFF"
DIFF_PERCENT="+$DIFF_PERCENT"
fi
# highlight VmRSS
if [ "$2" = "VmRSS" ]; then
METRIC="**${METRIC}**"
BASE="**${BASE}**"
HEAD="**${HEAD}**"
DIFF="**${DIFF}**"
DIFF_PERCENT="**${DIFF_PERCENT}**"
fi
echo "| ${METRIC} | ${BASE} MB | ${HEAD} MB | ${DIFF} MB | ${DIFF_PERCENT}% |" >> ./output.md
}
line $1 VmRSS
line $1 VmHWM
line $1 VmSize
line $1 VmData
}
echo "### Before GC" >> ./output.md
table beforeGc
echo >> ./output.md
echo "### After GC" >> ./output.md
table afterGc
echo >> ./output.md
echo "### After Request" >> ./output.md
table afterRequest
echo >> ./output.md
# Determine if this is a significant change (more than 5% increase)
if [ "$(echo "$RES" | jq -r '.afterGc.VmRSS.diff_percent | tonumber > 5')" = "true" ]; then
echo "⚠️ **Warning**: Memory usage has increased by more than 5%. Please verify this is not an unintended change." >> ./output.md
echo >> ./output.md echo >> ./output.md
fi fi

View File

@ -6,7 +6,7 @@
"type": "git", "type": "git",
"url": "https://github.com/misskey-dev/misskey.git" "url": "https://github.com/misskey-dev/misskey.git"
}, },
"packageManager": "pnpm@10.27.0", "packageManager": "pnpm@10.28.0",
"workspaces": [ "workspaces": [
"packages/misskey-js", "packages/misskey-js",
"packages/i18n", "packages/i18n",
@ -52,10 +52,6 @@
"clean-all": "node scripts/clean-all.mjs", "clean-all": "node scripts/clean-all.mjs",
"cleanall": "pnpm clean-all" "cleanall": "pnpm clean-all"
}, },
"resolutions": {
"chokidar": "5.0.0",
"lodash": "4.17.21"
},
"dependencies": { "dependencies": {
"cssnano": "7.1.2", "cssnano": "7.1.2",
"esbuild": "0.27.2", "esbuild": "0.27.2",
@ -63,23 +59,23 @@
"ignore-walk": "8.0.0", "ignore-walk": "8.0.0",
"js-yaml": "4.1.1", "js-yaml": "4.1.1",
"postcss": "8.5.6", "postcss": "8.5.6",
"tar": "7.5.2", "tar": "7.5.6",
"terser": "5.44.1" "terser": "5.46.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.39.2", "@eslint/js": "9.39.2",
"@misskey-dev/eslint-plugin": "2.2.0", "@misskey-dev/eslint-plugin": "2.2.0",
"@types/js-yaml": "4.0.9", "@types/js-yaml": "4.0.9",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"@typescript/native-preview": "7.0.0-dev.20251226.1", "@typescript/native-preview": "7.0.0-dev.20260116.1",
"cross-env": "10.1.0", "cross-env": "10.1.0",
"cypress": "15.8.1", "cypress": "15.9.0",
"eslint": "9.39.2", "eslint": "9.39.2",
"globals": "16.5.0", "globals": "16.5.0",
"ncp": "2.0.0", "ncp": "2.0.0",
"pnpm": "10.27.0", "pnpm": "10.28.0",
"typescript": "5.9.3", "typescript": "5.9.3",
"start-server-and-test": "2.1.3" "start-server-and-test": "2.1.3"
}, },
@ -88,7 +84,9 @@
}, },
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"@aiscript-dev/aiscript-languageserver": "-" "@aiscript-dev/aiscript-languageserver": "-",
"chokidar": "5.0.0",
"lodash": "4.17.23"
}, },
"ignoredBuiltDependencies": [ "ignoredBuiltDependencies": [
"@sentry-internal/node-cpu-profiler", "@sentry-internal/node-cpu-profiler",

View File

@ -41,17 +41,17 @@
}, },
"optionalDependencies": { "optionalDependencies": {
"@swc/core-android-arm64": "1.3.11", "@swc/core-android-arm64": "1.3.11",
"@swc/core-darwin-arm64": "1.15.7", "@swc/core-darwin-arm64": "1.15.8",
"@swc/core-darwin-x64": "1.15.7", "@swc/core-darwin-x64": "1.15.8",
"@swc/core-freebsd-x64": "1.3.11", "@swc/core-freebsd-x64": "1.3.11",
"@swc/core-linux-arm-gnueabihf": "1.15.7", "@swc/core-linux-arm-gnueabihf": "1.15.8",
"@swc/core-linux-arm64-gnu": "1.15.7", "@swc/core-linux-arm64-gnu": "1.15.8",
"@swc/core-linux-arm64-musl": "1.15.7", "@swc/core-linux-arm64-musl": "1.15.8",
"@swc/core-linux-x64-gnu": "1.15.7", "@swc/core-linux-x64-gnu": "1.15.8",
"@swc/core-linux-x64-musl": "1.15.7", "@swc/core-linux-x64-musl": "1.15.8",
"@swc/core-win32-arm64-msvc": "1.15.7", "@swc/core-win32-arm64-msvc": "1.15.8",
"@swc/core-win32-ia32-msvc": "1.15.7", "@swc/core-win32-ia32-msvc": "1.15.8",
"@swc/core-win32-x64-msvc": "1.15.7", "@swc/core-win32-x64-msvc": "1.15.8",
"@tensorflow/tfjs": "4.22.0", "@tensorflow/tfjs": "4.22.0",
"@tensorflow/tfjs-node": "4.22.0", "@tensorflow/tfjs-node": "4.22.0",
"bufferutil": "4.1.0", "bufferutil": "4.1.0",
@ -71,30 +71,30 @@
"utf-8-validate": "6.0.6" "utf-8-validate": "6.0.6"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "3.958.0", "@aws-sdk/client-s3": "3.970.0",
"@aws-sdk/lib-storage": "3.958.0", "@aws-sdk/lib-storage": "3.970.0",
"@discordapp/twemoji": "16.0.1", "@discordapp/twemoji": "16.0.1",
"@fastify/accepts": "5.0.4", "@fastify/accepts": "5.0.4",
"@fastify/cors": "11.2.0", "@fastify/cors": "11.2.0",
"@fastify/express": "4.0.2", "@fastify/express": "4.0.4",
"@fastify/http-proxy": "11.4.1", "@fastify/http-proxy": "11.4.1",
"@fastify/multipart": "9.3.0", "@fastify/multipart": "9.3.0",
"@fastify/static": "8.3.0", "@fastify/static": "8.3.0",
"@kitajs/html": "4.2.11", "@kitajs/html": "4.2.11",
"@misskey-dev/sharp-read-bmp": "1.2.0", "@misskey-dev/sharp-read-bmp": "1.2.0",
"@misskey-dev/summaly": "5.2.5", "@misskey-dev/summaly": "5.2.5",
"@napi-rs/canvas": "0.1.87", "@napi-rs/canvas": "0.1.88",
"@nestjs/common": "11.1.10", "@nestjs/common": "11.1.12",
"@nestjs/core": "11.1.10", "@nestjs/core": "11.1.12",
"@nestjs/testing": "11.1.10", "@nestjs/testing": "11.1.12",
"@peertube/http-signature": "1.7.0", "@peertube/http-signature": "1.7.0",
"@sentry/node": "10.32.1", "@sentry/node": "10.34.0",
"@sentry/profiling-node": "10.32.1", "@sentry/profiling-node": "10.34.0",
"@simplewebauthn/server": "13.2.2", "@simplewebauthn/server": "13.2.2",
"@sinonjs/fake-timers": "15.1.0", "@sinonjs/fake-timers": "15.1.0",
"@smithy/node-http-handler": "4.4.7", "@smithy/node-http-handler": "4.4.8",
"@swc/cli": "0.7.9", "@swc/cli": "0.7.10",
"@swc/core": "1.15.7", "@swc/core": "1.15.8",
"@twemoji/parser": "16.0.0", "@twemoji/parser": "16.0.0",
"accepts": "1.3.8", "accepts": "1.3.8",
"ajv": "8.17.1", "ajv": "8.17.1",
@ -102,8 +102,8 @@
"async-mutex": "0.5.0", "async-mutex": "0.5.0",
"bcryptjs": "3.0.3", "bcryptjs": "3.0.3",
"blurhash": "2.0.5", "blurhash": "2.0.5",
"body-parser": "2.2.1", "body-parser": "2.2.2",
"bullmq": "5.66.3", "bullmq": "5.66.5",
"cacheable-lookup": "7.0.0", "cacheable-lookup": "7.0.0",
"chalk": "5.6.2", "chalk": "5.6.2",
"chalk-template": "1.1.2", "chalk-template": "1.1.2",
@ -112,24 +112,24 @@
"content-disposition": "1.0.1", "content-disposition": "1.0.1",
"date-fns": "4.1.0", "date-fns": "4.1.0",
"deep-email-validator": "0.1.21", "deep-email-validator": "0.1.21",
"fastify": "5.6.2", "fastify": "5.7.1",
"fastify-raw-body": "5.0.0", "fastify-raw-body": "5.0.0",
"feed": "5.1.0", "feed": "5.2.0",
"file-type": "21.2.0", "file-type": "21.3.0",
"fluent-ffmpeg": "2.1.3", "fluent-ffmpeg": "2.1.3",
"form-data": "4.0.5", "form-data": "4.0.5",
"got": "14.6.5", "got": "14.6.6",
"hpagent": "1.2.0", "hpagent": "1.2.0",
"http-link-header": "1.1.3", "http-link-header": "1.1.3",
"i18n": "workspace:*", "i18n": "workspace:*",
"ioredis": "5.8.2", "ioredis": "5.9.2",
"ip-cidr": "4.0.2", "ip-cidr": "4.0.2",
"ipaddr.js": "2.3.0", "ipaddr.js": "2.3.0",
"is-svg": "6.1.0", "is-svg": "6.1.0",
"json5": "2.2.3", "json5": "2.2.3",
"jsonld": "9.0.0", "jsonld": "9.0.0",
"juice": "11.0.3", "juice": "11.1.0",
"meilisearch": "0.54.0", "meilisearch": "0.55.0",
"mfm-js": "0.25.0", "mfm-js": "0.25.0",
"mime-types": "3.0.2", "mime-types": "3.0.2",
"misskey-js": "workspace:*", "misskey-js": "workspace:*",
@ -138,14 +138,14 @@
"nanoid": "5.1.6", "nanoid": "5.1.6",
"nested-property": "4.0.0", "nested-property": "4.0.0",
"node-fetch": "3.3.2", "node-fetch": "3.3.2",
"node-html-parser": "7.0.1", "node-html-parser": "7.0.2",
"nodemailer": "7.0.12", "nodemailer": "7.0.12",
"nsfwjs": "4.2.0", "nsfwjs": "4.2.0",
"oauth2orize": "1.12.0", "oauth2orize": "1.12.0",
"oauth2orize-pkce": "0.1.2", "oauth2orize-pkce": "0.1.2",
"os-utils": "0.0.14", "os-utils": "0.0.14",
"otpauth": "9.4.1", "otpauth": "9.4.1",
"pg": "8.16.3", "pg": "8.17.1",
"pkce-challenge": "5.0.1", "pkce-challenge": "5.0.1",
"probe-image-size": "7.2.3", "probe-image-size": "7.2.3",
"promise-limit": "2.7.0", "promise-limit": "2.7.0",
@ -164,7 +164,7 @@
"slacc": "0.0.10", "slacc": "0.0.10",
"strict-event-emitter-types": "2.0.0", "strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0", "stringz": "2.1.0",
"systeminformation": "5.28.1", "systeminformation": "5.30.5",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
"tmp": "0.2.5", "tmp": "0.2.5",
"tsc-alias": "1.8.16", "tsc-alias": "1.8.16",
@ -172,14 +172,14 @@
"ulid": "3.0.2", "ulid": "3.0.2",
"vary": "1.1.2", "vary": "1.1.2",
"web-push": "3.6.7", "web-push": "3.6.7",
"ws": "8.18.3", "ws": "8.19.0",
"xev": "3.0.2" "xev": "3.0.2"
}, },
"devDependencies": { "devDependencies": {
"@jest/globals": "29.7.0", "@jest/globals": "29.7.0",
"@kitajs/ts-html-plugin": "4.1.3", "@kitajs/ts-html-plugin": "4.1.3",
"@nestjs/platform-express": "11.1.10", "@nestjs/platform-express": "11.1.12",
"@sentry/vue": "10.32.1", "@sentry/vue": "10.34.0",
"@simplewebauthn/types": "12.0.0", "@simplewebauthn/types": "12.0.0",
"@swc/jest": "0.2.39", "@swc/jest": "0.2.39",
"@types/accepts": "1.3.7", "@types/accepts": "1.3.7",
@ -193,8 +193,8 @@
"@types/jsonld": "1.5.15", "@types/jsonld": "1.5.15",
"@types/mime-types": "3.0.1", "@types/mime-types": "3.0.1",
"@types/ms": "2.1.0", "@types/ms": "2.1.0",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@types/nodemailer": "7.0.4", "@types/nodemailer": "7.0.5",
"@types/oauth2orize": "1.11.5", "@types/oauth2orize": "1.11.5",
"@types/oauth2orize-pkce": "0.1.2", "@types/oauth2orize-pkce": "0.1.2",
"@types/pg": "8.16.0", "@types/pg": "8.16.0",
@ -212,22 +212,22 @@
"@types/vary": "1.1.3", "@types/vary": "1.1.3",
"@types/web-push": "3.6.4", "@types/web-push": "3.6.4",
"@types/ws": "8.18.1", "@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"aws-sdk-client-mock": "4.1.0", "aws-sdk-client-mock": "4.1.0",
"cbor": "10.0.11", "cbor": "10.0.11",
"cross-env": "10.1.0", "cross-env": "10.1.0",
"esbuild-plugin-swc": "1.0.1", "esbuild-plugin-swc": "1.0.1",
"eslint-plugin-import": "2.32.0", "eslint-plugin-import": "2.32.0",
"execa": "9.6.1", "execa": "9.6.1",
"fkill": "10.0.1", "fkill": "10.0.3",
"jest": "29.7.0", "jest": "29.7.0",
"jest-mock": "29.7.0", "jest-mock": "29.7.0",
"js-yaml": "4.1.1", "js-yaml": "4.1.1",
"nodemon": "3.1.11", "nodemon": "3.1.11",
"pid-port": "2.0.0", "pid-port": "2.0.1",
"simple-oauth2": "5.1.0", "simple-oauth2": "5.1.0",
"supertest": "7.1.4", "supertest": "7.2.2",
"vite": "7.3.0" "vite": "7.3.1"
} }
} }

View File

@ -14,16 +14,46 @@ import { fork } from 'node:child_process';
import { setTimeout } from 'node:timers/promises'; import { setTimeout } from 'node:timers/promises';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path'; import { dirname, join } from 'node:path';
import * as http from 'node:http';
import * as fs from 'node:fs/promises';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
const SAMPLE_COUNT = 3; // Number of samples to measure
const STARTUP_TIMEOUT = 120000; // 120 seconds timeout for server startup const STARTUP_TIMEOUT = 120000; // 120 seconds timeout for server startup
const MEMORY_SETTLE_TIME = 10000; // Wait 10 seconds after startup for memory to settle const MEMORY_SETTLE_TIME = 10000; // Wait 10 seconds after startup for memory to settle
async function measureMemory() { const keys = {
const startTime = Date.now(); VmPeak: 0,
VmSize: 0,
VmHWM: 0,
VmRSS: 0,
VmData: 0,
VmStk: 0,
VmExe: 0,
VmLib: 0,
VmPTE: 0,
VmSwap: 0,
};
async function getMemoryUsage(pid) {
const status = await fs.readFile(`/proc/${pid}/status`, 'utf-8');
const result = {};
for (const key of Object.keys(keys)) {
const match = status.match(new RegExp(`${key}:\\s+(\\d+)\\s+kB`));
if (match) {
result[key] = parseInt(match[1], 10);
} else {
throw new Error(`Failed to parse ${key} from /proc/${pid}/status`);
}
}
return result;
}
async function measureMemory() {
// Start the Misskey backend server using fork to enable IPC // Start the Misskey backend server using fork to enable IPC
const serverProcess = fork(join(__dirname, '../built/boot/entry.js'), ['expose-gc'], { const serverProcess = fork(join(__dirname, '../built/boot/entry.js'), ['expose-gc'], {
cwd: join(__dirname, '..'), cwd: join(__dirname, '..'),
@ -31,9 +61,9 @@ async function measureMemory() {
...process.env, ...process.env,
NODE_ENV: 'production', NODE_ENV: 'production',
MK_DISABLE_CLUSTERING: '1', MK_DISABLE_CLUSTERING: '1',
MK_FORCE_GC: '1',
}, },
stdio: ['pipe', 'pipe', 'pipe', 'ipc'], stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
execArgv: [...process.execArgv, '--expose-gc'],
}); });
let serverReady = false; let serverReady = false;
@ -59,6 +89,40 @@ async function measureMemory() {
process.stderr.write(`[server error] ${err}\n`); process.stderr.write(`[server error] ${err}\n`);
}); });
async function triggerGc() {
const ok = new Promise((resolve) => {
serverProcess.once('message', (message) => {
if (message === 'gc ok') resolve();
});
});
serverProcess.send('gc');
await ok;
await setTimeout(1000);
}
function createRequest() {
return new Promise((resolve, reject) => {
const req = http.request({
host: 'localhost',
port: 61812,
path: '/api/meta',
method: 'POST',
}, (res) => {
res.on('data', () => { });
res.on('end', () => {
resolve();
});
});
req.on('error', (err) => {
reject(err);
});
req.end();
});
}
// Wait for server to be ready or timeout // Wait for server to be ready or timeout
const startupStartTime = Date.now(); const startupStartTime = Date.now();
while (!serverReady) { while (!serverReady) {
@ -75,46 +139,23 @@ async function measureMemory() {
// Wait for memory to settle // Wait for memory to settle
await setTimeout(MEMORY_SETTLE_TIME); await setTimeout(MEMORY_SETTLE_TIME);
// Get memory usage from the server process via /proc
const pid = serverProcess.pid; const pid = serverProcess.pid;
let memoryInfo;
try { const beforeGc = await getMemoryUsage(pid);
const fs = await import('node:fs/promises');
// Read /proc/[pid]/status for detailed memory info await triggerGc();
const status = await fs.readFile(`/proc/${pid}/status`, 'utf-8');
const vmRssMatch = status.match(/VmRSS:\s+(\d+)\s+kB/);
const vmDataMatch = status.match(/VmData:\s+(\d+)\s+kB/);
const vmSizeMatch = status.match(/VmSize:\s+(\d+)\s+kB/);
memoryInfo = { const afterGc = await getMemoryUsage(pid);
rss: vmRssMatch ? parseInt(vmRssMatch[1], 10) * 1024 : null,
heapUsed: vmDataMatch ? parseInt(vmDataMatch[1], 10) * 1024 : null,
vmSize: vmSizeMatch ? parseInt(vmSizeMatch[1], 10) * 1024 : null,
};
} catch (err) {
// Fallback: use ps command
process.stderr.write(`Warning: Could not read /proc/${pid}/status: ${err}\n`);
const { execSync } = await import('node:child_process'); // create some http requests to simulate load
try { const REQUEST_COUNT = 10;
const ps = execSync(`ps -o rss= -p ${pid}`, { encoding: 'utf-8' }); await Promise.all(
const rssKb = parseInt(ps.trim(), 10); Array.from({ length: REQUEST_COUNT }).map(() => createRequest()),
memoryInfo = { );
rss: rssKb * 1024,
heapUsed: null, await triggerGc();
vmSize: null,
}; const afterRequest = await getMemoryUsage(pid);
} catch {
memoryInfo = {
rss: null,
heapUsed: null,
vmSize: null,
error: 'Could not measure memory',
};
}
}
// Stop the server // Stop the server
serverProcess.kill('SIGTERM'); serverProcess.kill('SIGTERM');
@ -137,15 +178,51 @@ async function measureMemory() {
const result = { const result = {
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
startupTimeMs: startupTime, beforeGc,
memory: memoryInfo, afterGc,
afterRequest,
};
return result;
}
async function main() {
// 直列の方が時間的に分散されて正確そうだから直列でやる
const results = [];
for (let i = 0; i < SAMPLE_COUNT; i++) {
const res = await measureMemory();
results.push(res);
}
// Calculate averages
const beforeGc = structuredClone(keys);
const afterGc = structuredClone(keys);
const afterRequest = structuredClone(keys);
for (const res of results) {
for (const key of Object.keys(keys)) {
beforeGc[key] += res.beforeGc[key];
afterGc[key] += res.afterGc[key];
afterRequest[key] += res.afterRequest[key];
}
}
for (const key of Object.keys(keys)) {
beforeGc[key] = Math.round(beforeGc[key] / SAMPLE_COUNT);
afterGc[key] = Math.round(afterGc[key] / SAMPLE_COUNT);
afterRequest[key] = Math.round(afterRequest[key] / SAMPLE_COUNT);
}
const result = {
timestamp: new Date().toISOString(),
beforeGc,
afterGc,
afterRequest,
}; };
// Output as JSON to stdout // Output as JSON to stdout
console.log(JSON.stringify(result, null, 2)); console.log(JSON.stringify(result, null, 2));
} }
measureMemory().catch((err) => { main().catch((err) => {
console.error(JSON.stringify({ console.error(JSON.stringify({
error: err.message, error: err.message,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),

View File

@ -86,9 +86,17 @@ if (!envOption.disableClustering) {
ev.mount(); ev.mount();
} }
if (envOption.forceGc && global.gc != null) { process.on('message', msg => {
global.gc(); if (msg === 'gc') {
} if (global.gc != null) {
logger.info('Manual GC triggered');
global.gc();
if (process.send != null) process.send('gc ok');
} else {
logger.warn('Manual GC requested but gc is not available. Start the process with --expose-gc to enable this feature.');
}
}
});
readyRef.value = true; readyRef.value = true;

View File

@ -902,7 +902,7 @@ export class QueueService {
}, },
db: { db: {
version: db.redis_version, version: db.redis_version,
mode: db.redis_mode, mode: db.redis_mode as 'cluster' | 'standalone' | 'sentinel',
runId: db.run_id, runId: db.run_id,
processId: db.process_id, processId: db.process_id,
port: parseInt(db.tcp_port), port: parseInt(db.tcp_port),

View File

@ -11,7 +11,6 @@ const envOption = {
verbose: false, verbose: false,
withLogTime: false, withLogTime: false,
quiet: false, quiet: false,
forceGc: false,
}; };
for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) { for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) {

View File

@ -11,15 +11,15 @@
}, },
"devDependencies": { "devDependencies": {
"@types/estree": "1.0.8", "@types/estree": "1.0.8",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"rollup": "4.54.0" "rollup": "4.55.1"
}, },
"dependencies": { "dependencies": {
"i18n": "workspace:*", "i18n": "workspace:*",
"estree-walker": "3.0.3", "estree-walker": "3.0.3",
"magic-string": "0.30.21", "magic-string": "0.30.21",
"vite": "7.3.0" "vite": "7.3.1"
} }
} }

View File

@ -25,12 +25,12 @@
"mfm-js": "0.25.0", "mfm-js": "0.25.0",
"misskey-js": "workspace:*", "misskey-js": "workspace:*",
"punycode.js": "2.3.1", "punycode.js": "2.3.1",
"rollup": "4.54.0", "rollup": "4.55.1",
"sass": "1.97.1", "sass": "1.97.2",
"shiki": "3.21.0", "shiki": "3.21.0",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
"uuid": "13.0.0", "uuid": "13.0.0",
"vite": "7.3.0", "vite": "7.3.1",
"vue": "3.5.26" "vue": "3.5.26"
}, },
"devDependencies": { "devDependencies": {
@ -39,29 +39,29 @@
"@testing-library/vue": "8.1.0", "@testing-library/vue": "8.1.0",
"@types/estree": "1.0.8", "@types/estree": "1.0.8",
"@types/micromatch": "4.0.10", "@types/micromatch": "4.0.10",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/punycode.js": "npm:@types/punycode@2.1.4",
"@types/tinycolor2": "1.4.6", "@types/tinycolor2": "1.4.6",
"@types/ws": "8.18.1", "@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"@vitest/coverage-v8": "4.0.16", "@vitest/coverage-v8": "4.0.17",
"@vue/runtime-core": "3.5.26", "@vue/runtime-core": "3.5.26",
"acorn": "8.15.0", "acorn": "8.15.0",
"cross-env": "10.1.0", "cross-env": "10.1.0",
"eslint-plugin-import": "2.32.0", "eslint-plugin-import": "2.32.0",
"eslint-plugin-vue": "10.6.2", "eslint-plugin-vue": "10.7.0",
"happy-dom": "20.0.11", "happy-dom": "20.3.1",
"intersection-observer": "0.12.2", "intersection-observer": "0.12.2",
"micromatch": "4.0.8", "micromatch": "4.0.8",
"msw": "2.12.6", "msw": "2.12.7",
"nodemon": "3.1.11", "nodemon": "3.1.11",
"prettier": "3.7.4", "prettier": "3.8.0",
"start-server-and-test": "2.1.3", "start-server-and-test": "2.1.3",
"tsx": "4.21.0", "tsx": "4.21.0",
"vite-plugin-turbosnap": "1.0.3", "vite-plugin-turbosnap": "1.0.3",
"vue-component-type-helpers": "3.2.1", "vue-component-type-helpers": "3.2.2",
"vue-eslint-parser": "10.2.0", "vue-eslint-parser": "10.2.0",
"vue-tsc": "3.2.1" "vue-tsc": "3.2.2"
} }
} }

View File

@ -21,11 +21,11 @@
"lint": "pnpm typecheck && pnpm eslint" "lint": "pnpm typecheck && pnpm eslint"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"esbuild": "0.27.2", "esbuild": "0.27.2",
"eslint-plugin-vue": "10.6.2", "eslint-plugin-vue": "10.7.0",
"nodemon": "3.1.11", "nodemon": "3.1.11",
"vue-eslint-parser": "10.2.0" "vue-eslint-parser": "10.2.0"
}, },

View File

@ -24,7 +24,7 @@
"@rollup/plugin-json": "6.1.0", "@rollup/plugin-json": "6.1.0",
"@rollup/plugin-replace": "6.0.3", "@rollup/plugin-replace": "6.0.3",
"@rollup/pluginutils": "5.3.0", "@rollup/pluginutils": "5.3.0",
"@sentry/vue": "10.32.1", "@sentry/vue": "10.34.0",
"@shikijs/transformers": "3.21.0", "@shikijs/transformers": "3.21.0",
"@syuilo/aiscript": "1.2.1", "@syuilo/aiscript": "1.2.1",
"@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0", "@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0",
@ -40,14 +40,14 @@
"chartjs-chart-matrix": "3.0.0", "chartjs-chart-matrix": "3.0.0",
"chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-gradient": "0.6.1",
"chartjs-plugin-zoom": "2.2.0", "chartjs-plugin-zoom": "2.2.0",
"chromatic": "13.3.4", "chromatic": "13.3.5",
"compare-versions": "6.1.1", "compare-versions": "6.1.1",
"cropperjs": "2.1.0", "cropperjs": "2.1.0",
"date-fns": "4.1.0", "date-fns": "4.1.0",
"diff": "8.0.3", "diff": "8.0.3",
"eventemitter3": "5.0.1", "eventemitter3": "5.0.1",
"execa": "9.6.1", "execa": "9.6.1",
"exifreader": "4.33.1", "exifreader": "4.36.0",
"frontend-shared": "workspace:*", "frontend-shared": "workspace:*",
"i18n": "workspace:*", "i18n": "workspace:*",
"icons-subsetter": "workspace:*", "icons-subsetter": "workspace:*",
@ -57,7 +57,7 @@
"is-file-animated": "1.0.2", "is-file-animated": "1.0.2",
"json5": "2.2.3", "json5": "2.2.3",
"matter-js": "0.20.0", "matter-js": "0.20.0",
"mediabunny": "1.27.2", "mediabunny": "1.28.0",
"mfm-js": "0.25.0", "mfm-js": "0.25.0",
"misskey-bubble-game": "workspace:*", "misskey-bubble-game": "workspace:*",
"misskey-js": "workspace:*", "misskey-js": "workspace:*",
@ -66,15 +66,15 @@
"punycode.js": "2.3.1", "punycode.js": "2.3.1",
"qr-code-styling": "1.9.2", "qr-code-styling": "1.9.2",
"qr-scanner": "1.4.2", "qr-scanner": "1.4.2",
"rollup": "4.54.0", "rollup": "4.55.1",
"sanitize-html": "2.17.0", "sanitize-html": "2.17.0",
"sass": "1.97.1", "sass": "1.97.2",
"shiki": "3.21.0", "shiki": "3.21.0",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"three": "0.182.0", "three": "0.182.0",
"throttle-debounce": "5.0.2", "throttle-debounce": "5.0.2",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
"vite": "7.3.0", "vite": "7.3.1",
"vue": "3.5.26", "vue": "3.5.26",
"wanakana": "5.3.1" "wanakana": "5.3.1"
}, },
@ -82,7 +82,7 @@
"@misskey-dev/summaly": "5.2.5", "@misskey-dev/summaly": "5.2.5",
"@storybook/addon-essentials": "8.6.15", "@storybook/addon-essentials": "8.6.15",
"@storybook/addon-interactions": "8.6.15", "@storybook/addon-interactions": "8.6.15",
"@storybook/addon-links": "10.1.10", "@storybook/addon-links": "10.1.11",
"@storybook/addon-mdx-gfm": "8.6.15", "@storybook/addon-mdx-gfm": "8.6.15",
"@storybook/addon-storysource": "8.6.15", "@storybook/addon-storysource": "8.6.15",
"@storybook/blocks": "8.6.15", "@storybook/blocks": "8.6.15",
@ -90,13 +90,13 @@
"@storybook/core-events": "8.6.15", "@storybook/core-events": "8.6.15",
"@storybook/manager-api": "8.6.15", "@storybook/manager-api": "8.6.15",
"@storybook/preview-api": "8.6.15", "@storybook/preview-api": "8.6.15",
"@storybook/react": "10.1.10", "@storybook/react": "10.1.11",
"@storybook/react-vite": "10.1.10", "@storybook/react-vite": "10.1.11",
"@storybook/test": "8.6.15", "@storybook/test": "8.6.15",
"@storybook/theming": "8.6.15", "@storybook/theming": "8.6.15",
"@storybook/types": "8.6.15", "@storybook/types": "8.6.15",
"@storybook/vue3": "10.1.10", "@storybook/vue3": "10.1.11",
"@storybook/vue3-vite": "10.1.10", "@storybook/vue3-vite": "10.1.11",
"@tabler/icons-webfont": "3.35.0", "@tabler/icons-webfont": "3.35.0",
"@testing-library/vue": "8.1.0", "@testing-library/vue": "8.1.0",
"@types/canvas-confetti": "1.9.0", "@types/canvas-confetti": "1.9.0",
@ -104,46 +104,46 @@
"@types/insert-text-at-cursor": "0.3.2", "@types/insert-text-at-cursor": "0.3.2",
"@types/matter-js": "0.20.2", "@types/matter-js": "0.20.2",
"@types/micromatch": "4.0.10", "@types/micromatch": "4.0.10",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/punycode.js": "npm:@types/punycode@2.1.4",
"@types/sanitize-html": "2.16.0", "@types/sanitize-html": "2.16.0",
"@types/seedrandom": "3.0.8", "@types/seedrandom": "3.0.8",
"@types/textarea-caret": "3.0.4", "@types/textarea-caret": "3.0.4",
"@types/throttle-debounce": "5.0.2", "@types/throttle-debounce": "5.0.2",
"@types/tinycolor2": "1.4.6", "@types/tinycolor2": "1.4.6",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"@vitest/coverage-v8": "4.0.16", "@vitest/coverage-v8": "4.0.17",
"@vue/compiler-core": "3.5.26", "@vue/compiler-core": "3.5.26",
"acorn": "8.15.0", "acorn": "8.15.0",
"astring": "1.9.0", "astring": "1.9.0",
"cross-env": "10.1.0", "cross-env": "10.1.0",
"cypress": "15.8.1", "cypress": "15.9.0",
"eslint-plugin-import": "2.32.0", "eslint-plugin-import": "2.32.0",
"eslint-plugin-vue": "10.6.2", "eslint-plugin-vue": "10.7.0",
"estree-walker": "3.0.3", "estree-walker": "3.0.3",
"happy-dom": "20.0.11", "happy-dom": "20.3.1",
"intersection-observer": "0.12.2", "intersection-observer": "0.12.2",
"magic-string": "0.30.21", "magic-string": "0.30.21",
"micromatch": "4.0.8", "micromatch": "4.0.8",
"minimatch": "10.1.1", "minimatch": "10.1.1",
"msw": "2.12.6", "msw": "2.12.7",
"msw-storybook-addon": "2.0.6", "msw-storybook-addon": "2.0.6",
"nodemon": "3.1.11", "nodemon": "3.1.11",
"prettier": "3.7.4", "prettier": "3.8.0",
"react": "19.2.3", "react": "19.2.3",
"react-dom": "19.2.3", "react-dom": "19.2.3",
"seedrandom": "3.0.5", "seedrandom": "3.0.5",
"start-server-and-test": "2.1.3", "start-server-and-test": "2.1.3",
"storybook": "10.1.10", "storybook": "10.1.11",
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
"tsx": "4.21.0", "tsx": "4.21.0",
"vite-plugin-glsl": "1.5.5", "vite-plugin-glsl": "1.5.5",
"vite-plugin-turbosnap": "1.0.3", "vite-plugin-turbosnap": "1.0.3",
"vitest": "4.0.16", "vitest": "4.0.17",
"vitest-fetch-mock": "0.4.5", "vitest-fetch-mock": "0.4.5",
"vue-component-type-helpers": "3.2.1", "vue-component-type-helpers": "3.2.2",
"vue-eslint-parser": "10.2.0", "vue-eslint-parser": "10.2.0",
"vue-tsc": "3.2.1" "vue-tsc": "3.2.2"
} }
} }

View File

@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<div :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && prefer.s.highlightSensitiveMedia) && $style.sensitive]" @click="reveal"> <div :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && prefer.s.highlightSensitiveMedia) && $style.sensitive]" @click="reveal" @contextmenu.stop="onContextmenu">
<component <component
:is="disableImageLink ? 'div' : 'a'" :is="disableImageLink ? 'div' : 'a'"
v-bind="disableImageLink ? { v-bind="disableImageLink ? {
@ -123,7 +123,7 @@ watch(() => props.image, (newImage) => {
immediate: true, immediate: true,
}); });
function showMenu(ev: PointerEvent) { function getMenu() {
const menuItems: MenuItem[] = []; const menuItems: MenuItem[] = [];
menuItems.push({ menuItems.push({
@ -188,9 +188,16 @@ function showMenu(ev: PointerEvent) {
}); });
} }
os.popupMenu(menuItems, ev.currentTarget ?? ev.target); return menuItems;
} }
function showMenu(ev: PointerEvent) {
os.popupMenu(getMenu(), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
}
function onContextmenu(ev: PointerEvent) {
os.contextMenu(getMenu(), ev);
}
</script> </script>
<style lang="scss" module> <style lang="scss" module>

View File

@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
tabindex="0" tabindex="0"
@click="showFileMenu(item, $event)" @click="showFileMenu(item, $event)"
@keydown.space.enter="showFileMenu(item, $event)" @keydown.space.enter="showFileMenu(item, $event)"
@contextmenu.prevent="showFileMenu(item, $event)" @contextmenu.prevent.stop="showFileMenu(item, $event)"
> >
<!-- pointer-eventsをnoneにしておかないとiOSなどでドラッグしたときに画像の方に判定が持ってかれる --> <!-- pointer-eventsをnoneにしておかないとiOSなどでドラッグしたときに画像の方に判定が持ってかれる -->
<MkDriveFileThumbnail style="pointer-events: none;" :data-id="item.id" :class="$style.thumbnail" :file="item" fit="cover"/> <MkDriveFileThumbnail style="pointer-events: none;" :data-id="item.id" :class="$style.thumbnail" :file="item" fit="cover"/>

View File

@ -29,9 +29,9 @@
], ],
"devDependencies": { "devDependencies": {
"@types/js-yaml": "4.0.9", "@types/js-yaml": "4.0.9",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"chokidar": "5.0.0", "chokidar": "5.0.0",
"esbuild": "0.27.2", "esbuild": "0.27.2",
"execa": "9.6.1", "execa": "9.6.1",

View File

@ -11,14 +11,14 @@
"lint": "pnpm typecheck && pnpm eslint" "lint": "pnpm typecheck && pnpm eslint"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@types/wawoff2": "1.0.2", "@types/wawoff2": "1.0.2",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1" "@typescript-eslint/parser": "8.53.0"
}, },
"dependencies": { "dependencies": {
"@tabler/icons-webfont": "3.35.0", "@tabler/icons-webfont": "3.35.0",
"harfbuzzjs": "0.4.14", "harfbuzzjs": "0.4.15",
"tsx": "4.21.0", "tsx": "4.21.0",
"wawoff2": "2.0.1" "wawoff2": "2.0.1"
}, },

View File

@ -25,10 +25,10 @@
}, },
"devDependencies": { "devDependencies": {
"@types/matter-js": "0.20.2", "@types/matter-js": "0.20.2",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@types/seedrandom": "3.0.8", "@types/seedrandom": "3.0.8",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"esbuild": "0.27.2", "esbuild": "0.27.2",
"execa": "9.6.1", "execa": "9.6.1",
"nodemon": "3.1.11" "nodemon": "3.1.11"

View File

@ -7,10 +7,10 @@
"generate": "tsx src/generator.ts && eslint ./built/**/*.ts --fix" "generate": "tsx src/generator.ts && eslint ./built/**/*.ts --fix"
}, },
"devDependencies": { "devDependencies": {
"@readme/openapi-parser": "5.4.0", "@readme/openapi-parser": "5.5.0",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"openapi-types": "12.1.3", "openapi-types": "12.1.3",
"openapi-typescript": "7.10.1", "openapi-typescript": "7.10.1",
"ts-case-convert": "2.1.0", "ts-case-convert": "2.1.0",

View File

@ -37,17 +37,17 @@
"directory": "packages/misskey-js" "directory": "packages/misskey-js"
}, },
"devDependencies": { "devDependencies": {
"@microsoft/api-extractor": "7.55.2", "@microsoft/api-extractor": "7.55.5",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"@vitest/coverage-v8": "4.0.16", "@vitest/coverage-v8": "4.0.17",
"esbuild": "0.27.2", "esbuild": "0.27.2",
"execa": "9.6.1", "execa": "9.6.1",
"ncp": "2.0.0", "ncp": "2.0.0",
"nodemon": "3.1.11", "nodemon": "3.1.11",
"tsd": "0.33.0", "tsd": "0.33.0",
"vitest": "4.0.16", "vitest": "4.0.17",
"vitest-websocket-mock": "0.5.0" "vitest-websocket-mock": "0.5.0"
}, },
"files": [ "files": [

View File

@ -24,9 +24,9 @@
"lint": "pnpm typecheck && pnpm eslint" "lint": "pnpm typecheck && pnpm eslint"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@typescript-eslint/eslint-plugin": "8.50.1", "@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"esbuild": "0.27.2", "esbuild": "0.27.2",
"execa": "9.6.1", "execa": "9.6.1",
"nodemon": "3.1.11" "nodemon": "3.1.11"

View File

@ -15,7 +15,7 @@
"misskey-js": "workspace:*" "misskey-js": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/parser": "8.50.1", "@typescript-eslint/parser": "8.53.0",
"@typescript/lib-webworker": "npm:@types/serviceworker@0.0.74", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.74",
"eslint-plugin-import": "2.32.0", "eslint-plugin-import": "2.32.0",
"nodemon": "3.1.11" "nodemon": "3.1.11"

File diff suppressed because it is too large Load Diff

View File

@ -34,4 +34,6 @@ ignorePatchFailures: false
minimumReleaseAge: 10080 # delay 7days to mitigate supply-chain attack minimumReleaseAge: 10080 # delay 7days to mitigate supply-chain attack
minimumReleaseAgeExclude: minimumReleaseAgeExclude:
- '@syuilo/aiscript' - '@syuilo/aiscript'
- systeminformation # 脆弱性対応。そのうち消すこと - '@fastify/express' # 脆弱性対応。そのうち消すこと
- 'lodash' # 脆弱性対応。そのうち消すこと
- 'tar' # 脆弱性対応。そのうち消すこと

View File

@ -9,16 +9,16 @@
"version": "1.0.0", "version": "1.0.0",
"devDependencies": { "devDependencies": {
"@types/mdast": "4.0.4", "@types/mdast": "4.0.4",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@vitest/coverage-v8": "4.0.15", "@vitest/coverage-v8": "4.0.17",
"mdast-util-to-string": "4.0.0", "mdast-util-to-string": "4.0.0",
"remark": "15.0.1", "remark": "15.0.1",
"remark-parse": "11.0.0", "remark-parse": "11.0.0",
"typescript": "5.9.3", "typescript": "5.9.3",
"unified": "11.0.5", "unified": "11.0.5",
"vite": "7.3.0", "vite": "7.3.1",
"vite-node": "5.2.0", "vite-node": "5.2.0",
"vitest": "4.0.15" "vitest": "4.0.17"
} }
}, },
"node_modules/@babel/helper-string-parser": { "node_modules/@babel/helper-string-parser": {
@ -524,10 +524,11 @@
} }
}, },
"node_modules/@jridgewell/resolve-uri": { "node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
} }
@ -916,12 +917,11 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "24.10.4", "version": "24.10.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz",
"integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~7.16.0" "undici-types": "~7.16.0"
} }
@ -933,18 +933,17 @@
"dev": true "dev": true
}, },
"node_modules/@vitest/coverage-v8": { "node_modules/@vitest/coverage-v8": {
"version": "4.0.15", "version": "4.0.17",
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.15.tgz", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.17.tgz",
"integrity": "sha512-FUJ+1RkpTFW7rQITdgTi93qOCWJobWhBirEPCeXh2SW2wsTlFxy51apDz5gzG+ZEYt/THvWeNmhdAoS9DTwpCw==", "integrity": "sha512-/6zU2FLGg0jsd+ePZcwHRy3+WpNTBBhDY56P4JTRqUN/Dp6CvOEa9HrikcQ4KfV2b2kAHUFB4dl1SuocWXSFEw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@bcoe/v8-coverage": "^1.0.2", "@bcoe/v8-coverage": "^1.0.2",
"@vitest/utils": "4.0.15", "@vitest/utils": "4.0.17",
"ast-v8-to-istanbul": "^0.3.8", "ast-v8-to-istanbul": "^0.3.10",
"istanbul-lib-coverage": "^3.2.2", "istanbul-lib-coverage": "^3.2.2",
"istanbul-lib-report": "^3.0.1", "istanbul-lib-report": "^3.0.1",
"istanbul-lib-source-maps": "^5.0.6",
"istanbul-reports": "^3.2.0", "istanbul-reports": "^3.2.0",
"magicast": "^0.5.1", "magicast": "^0.5.1",
"obug": "^2.1.1", "obug": "^2.1.1",
@ -955,8 +954,8 @@
"url": "https://opencollective.com/vitest" "url": "https://opencollective.com/vitest"
}, },
"peerDependencies": { "peerDependencies": {
"@vitest/browser": "4.0.15", "@vitest/browser": "4.0.17",
"vitest": "4.0.15" "vitest": "4.0.17"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@vitest/browser": { "@vitest/browser": {
@ -965,16 +964,16 @@
} }
}, },
"node_modules/@vitest/expect": { "node_modules/@vitest/expect": {
"version": "4.0.15", "version": "4.0.17",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.15.tgz", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.17.tgz",
"integrity": "sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==", "integrity": "sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@standard-schema/spec": "^1.0.0", "@standard-schema/spec": "^1.0.0",
"@types/chai": "^5.2.2", "@types/chai": "^5.2.2",
"@vitest/spy": "4.0.15", "@vitest/spy": "4.0.17",
"@vitest/utils": "4.0.15", "@vitest/utils": "4.0.17",
"chai": "^6.2.1", "chai": "^6.2.1",
"tinyrainbow": "^3.0.3" "tinyrainbow": "^3.0.3"
}, },
@ -983,13 +982,13 @@
} }
}, },
"node_modules/@vitest/mocker": { "node_modules/@vitest/mocker": {
"version": "4.0.15", "version": "4.0.17",
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.15.tgz", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.17.tgz",
"integrity": "sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==", "integrity": "sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/spy": "4.0.15", "@vitest/spy": "4.0.17",
"estree-walker": "^3.0.3", "estree-walker": "^3.0.3",
"magic-string": "^0.30.21" "magic-string": "^0.30.21"
}, },
@ -1010,9 +1009,9 @@
} }
}, },
"node_modules/@vitest/pretty-format": { "node_modules/@vitest/pretty-format": {
"version": "4.0.15", "version": "4.0.17",
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.15.tgz", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.17.tgz",
"integrity": "sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==", "integrity": "sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1023,13 +1022,13 @@
} }
}, },
"node_modules/@vitest/runner": { "node_modules/@vitest/runner": {
"version": "4.0.15", "version": "4.0.17",
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.15.tgz", "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.17.tgz",
"integrity": "sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==", "integrity": "sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/utils": "4.0.15", "@vitest/utils": "4.0.17",
"pathe": "^2.0.3" "pathe": "^2.0.3"
}, },
"funding": { "funding": {
@ -1037,13 +1036,13 @@
} }
}, },
"node_modules/@vitest/snapshot": { "node_modules/@vitest/snapshot": {
"version": "4.0.15", "version": "4.0.17",
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.15.tgz", "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.17.tgz",
"integrity": "sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==", "integrity": "sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/pretty-format": "4.0.15", "@vitest/pretty-format": "4.0.17",
"magic-string": "^0.30.21", "magic-string": "^0.30.21",
"pathe": "^2.0.3" "pathe": "^2.0.3"
}, },
@ -1052,9 +1051,9 @@
} }
}, },
"node_modules/@vitest/spy": { "node_modules/@vitest/spy": {
"version": "4.0.15", "version": "4.0.17",
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.15.tgz", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.17.tgz",
"integrity": "sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==", "integrity": "sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
@ -1062,13 +1061,13 @@
} }
}, },
"node_modules/@vitest/utils": { "node_modules/@vitest/utils": {
"version": "4.0.15", "version": "4.0.17",
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.15.tgz", "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.17.tgz",
"integrity": "sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==", "integrity": "sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/pretty-format": "4.0.15", "@vitest/pretty-format": "4.0.17",
"tinyrainbow": "^3.0.3" "tinyrainbow": "^3.0.3"
}, },
"funding": { "funding": {
@ -1086,9 +1085,9 @@
} }
}, },
"node_modules/ast-v8-to-istanbul": { "node_modules/ast-v8-to-istanbul": {
"version": "0.3.8", "version": "0.3.10",
"resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.8.tgz", "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.10.tgz",
"integrity": "sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==", "integrity": "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1117,9 +1116,9 @@
} }
}, },
"node_modules/chai": { "node_modules/chai": {
"version": "6.2.1", "version": "6.2.2",
"resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
"integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==", "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -1347,21 +1346,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/istanbul-lib-source-maps": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz",
"integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.23",
"debug": "^4.1.1",
"istanbul-lib-coverage": "^3.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/istanbul-reports": { "node_modules/istanbul-reports": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
@ -2012,7 +1996,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@ -2375,9 +2358,9 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "7.3.0", "version": "7.3.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2473,20 +2456,19 @@
} }
}, },
"node_modules/vitest": { "node_modules/vitest": {
"version": "4.0.15", "version": "4.0.17",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.15.tgz", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.17.tgz",
"integrity": "sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==", "integrity": "sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@vitest/expect": "4.0.15", "@vitest/expect": "4.0.17",
"@vitest/mocker": "4.0.15", "@vitest/mocker": "4.0.17",
"@vitest/pretty-format": "4.0.15", "@vitest/pretty-format": "4.0.17",
"@vitest/runner": "4.0.15", "@vitest/runner": "4.0.17",
"@vitest/snapshot": "4.0.15", "@vitest/snapshot": "4.0.17",
"@vitest/spy": "4.0.15", "@vitest/spy": "4.0.17",
"@vitest/utils": "4.0.15", "@vitest/utils": "4.0.17",
"es-module-lexer": "^1.7.0", "es-module-lexer": "^1.7.0",
"expect-type": "^1.2.2", "expect-type": "^1.2.2",
"magic-string": "^0.30.21", "magic-string": "^0.30.21",
@ -2514,10 +2496,10 @@
"@edge-runtime/vm": "*", "@edge-runtime/vm": "*",
"@opentelemetry/api": "^1.9.0", "@opentelemetry/api": "^1.9.0",
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
"@vitest/browser-playwright": "4.0.15", "@vitest/browser-playwright": "4.0.17",
"@vitest/browser-preview": "4.0.15", "@vitest/browser-preview": "4.0.17",
"@vitest/browser-webdriverio": "4.0.15", "@vitest/browser-webdriverio": "4.0.17",
"@vitest/ui": "4.0.15", "@vitest/ui": "4.0.17",
"happy-dom": "*", "happy-dom": "*",
"jsdom": "*" "jsdom": "*"
}, },

View File

@ -10,15 +10,15 @@
}, },
"devDependencies": { "devDependencies": {
"@types/mdast": "4.0.4", "@types/mdast": "4.0.4",
"@types/node": "24.10.4", "@types/node": "24.10.9",
"@vitest/coverage-v8": "4.0.15", "@vitest/coverage-v8": "4.0.17",
"mdast-util-to-string": "4.0.0", "mdast-util-to-string": "4.0.0",
"remark": "15.0.1", "remark": "15.0.1",
"remark-parse": "11.0.0", "remark-parse": "11.0.0",
"typescript": "5.9.3", "typescript": "5.9.3",
"unified": "11.0.5", "unified": "11.0.5",
"vite": "7.3.0", "vite": "7.3.1",
"vite-node": "5.2.0", "vite-node": "5.2.0",
"vitest": "4.0.15" "vitest": "4.0.17"
} }
} }