From 7bd7e5c4db196a430610797ab640bd409c251e6e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 31 Mar 2026 12:14:45 +0000 Subject: [PATCH 001/578] [skip ci] Update CHANGELOG.md (prepend template) --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ab691e32d0..051b68c239c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## Unreleased + +### General +- + +### Client +- + +### Server +- + + ## 2026.3.2 ### General From dbc5fe2454f10cc71aff480c21cdd5a066439947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 1 Apr 2026 12:16:36 +0900 Subject: [PATCH 002/578] deps: update dependencies (#17263) * deps: update dependencies * fix? * fix * Update AiService.ts * fix * update deps --- package.json | 14 +- packages/backend/package.json | 74 +- packages/backend/src/core/AiService.ts | 4 +- packages/frontend-builder/package.json | 6 +- packages/frontend-embed/package.json | 16 +- packages/frontend-shared/package.json | 4 +- packages/frontend/package.json | 42 +- packages/i18n/package.json | 4 +- packages/icons-subsetter/package.json | 6 +- packages/misskey-bubble-game/package.json | 4 +- packages/misskey-js/generator/package.json | 4 +- packages/misskey-js/package.json | 8 +- packages/misskey-reversi/package.json | 4 +- packages/sw/package.json | 2 +- pnpm-lock.yaml | 2760 ++++++++++---------- pnpm-workspace.yaml | 2 - scripts/changelog-checker/package.json | 4 +- 17 files changed, 1485 insertions(+), 1473 deletions(-) diff --git a/package.json b/package.json index aeff8522c27..b70960417a4 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "type": "git", "url": "https://github.com/misskey-dev/misskey.git" }, - "packageManager": "pnpm@10.32.1", + "packageManager": "pnpm@10.33.0", "workspaces": [ "packages/misskey-js", "packages/i18n", @@ -59,23 +59,23 @@ "ignore-walk": "8.0.0", "js-yaml": "4.1.1", "postcss": "8.5.8", - "tar": "7.5.11", - "terser": "5.46.0" + "tar": "7.5.13", + "terser": "5.46.1" }, "devDependencies": { "@eslint/js": "9.39.4", "@misskey-dev/eslint-plugin": "2.1.0", "@types/js-yaml": "4.0.9", "@types/node": "24.12.0", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", "@typescript/native-preview": "7.0.0-dev.20260116.1", "cross-env": "10.1.0", - "cypress": "15.11.0", + "cypress": "15.13.0", "eslint": "9.39.4", "globals": "17.4.0", "ncp": "2.0.0", - "pnpm": "10.32.1", + "pnpm": "10.33.0", "start-server-and-test": "2.1.5", "typescript": "5.9.3" }, diff --git a/packages/backend/package.json b/packages/backend/package.json index 921e89eff97..6b2e76480b2 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -41,17 +41,17 @@ }, "optionalDependencies": { "@swc/core-android-arm64": "1.3.11", - "@swc/core-darwin-arm64": "1.15.18", - "@swc/core-darwin-x64": "1.15.18", + "@swc/core-darwin-arm64": "1.15.21", + "@swc/core-darwin-x64": "1.15.21", "@swc/core-freebsd-x64": "1.3.11", - "@swc/core-linux-arm-gnueabihf": "1.15.18", - "@swc/core-linux-arm64-gnu": "1.15.18", - "@swc/core-linux-arm64-musl": "1.15.18", - "@swc/core-linux-x64-gnu": "1.15.18", - "@swc/core-linux-x64-musl": "1.15.18", - "@swc/core-win32-arm64-msvc": "1.15.18", - "@swc/core-win32-ia32-msvc": "1.15.18", - "@swc/core-win32-x64-msvc": "1.15.18", + "@swc/core-linux-arm-gnueabihf": "1.15.21", + "@swc/core-linux-arm64-gnu": "1.15.21", + "@swc/core-linux-arm64-musl": "1.15.21", + "@swc/core-linux-x64-gnu": "1.15.21", + "@swc/core-linux-x64-musl": "1.15.21", + "@swc/core-win32-arm64-msvc": "1.15.21", + "@swc/core-win32-ia32-msvc": "1.15.21", + "@swc/core-win32-x64-msvc": "1.15.21", "@tensorflow/tfjs": "4.22.0", "@tensorflow/tfjs-node": "4.22.0", "bufferutil": "4.1.0", @@ -71,30 +71,30 @@ "utf-8-validate": "6.0.6" }, "dependencies": { - "@aws-sdk/client-s3": "3.1008.0", - "@aws-sdk/lib-storage": "3.1008.0", + "@aws-sdk/client-s3": "3.1016.0", + "@aws-sdk/lib-storage": "3.1016.0", "@discordapp/twemoji": "16.0.1", "@fastify/accepts": "5.0.4", "@fastify/cors": "11.2.0", "@fastify/express": "4.0.4", - "@fastify/http-proxy": "11.4.1", + "@fastify/http-proxy": "11.4.2", "@fastify/multipart": "9.4.0", "@fastify/static": "9.0.0", "@kitajs/html": "4.2.13", "@misskey-dev/sharp-read-bmp": "1.2.0", "@misskey-dev/summaly": "5.2.5", - "@napi-rs/canvas": "0.1.96", - "@nestjs/common": "11.1.16", - "@nestjs/core": "11.1.16", - "@nestjs/testing": "11.1.16", + "@napi-rs/canvas": "0.1.97", + "@nestjs/common": "11.1.17", + "@nestjs/core": "11.1.17", + "@nestjs/testing": "11.1.17", "@peertube/http-signature": "1.7.0", - "@sentry/node": "10.43.0", - "@sentry/profiling-node": "10.43.0", + "@sentry/node": "10.45.0", + "@sentry/profiling-node": "10.45.0", "@simplewebauthn/server": "13.3.0", "@sinonjs/fake-timers": "15.1.1", - "@smithy/node-http-handler": "4.4.16", + "@smithy/node-http-handler": "4.5.0", "@swc/cli": "0.8.0", - "@swc/core": "1.15.18", + "@swc/core": "1.15.21", "@twemoji/parser": "16.0.0", "accepts": "1.3.8", "ajv": "8.18.0", @@ -112,35 +112,35 @@ "content-disposition": "1.0.1", "date-fns": "4.1.0", "deep-email-validator": "0.1.21", - "fastify": "5.8.2", + "fastify": "5.8.4", "fastify-raw-body": "5.0.0", "feed": "5.2.0", - "file-type": "21.3.2", + "file-type": "21.3.4", "fluent-ffmpeg": "2.1.3", "form-data": "4.0.5", "got": "14.6.6", "hpagent": "1.2.0", "http-link-header": "1.1.3", "i18n": "workspace:*", - "ioredis": "5.10.0", + "ioredis": "5.10.1", "ip-cidr": "4.0.2", "ipaddr.js": "2.3.0", "is-svg": "6.1.0", "json5": "2.2.3", "jsonld": "9.0.0", "juice": "11.1.1", - "meilisearch": "0.55.0", + "meilisearch": "0.56.0", "mfm-js": "0.25.0", "mime-types": "3.0.2", "misskey-js": "workspace:*", "misskey-reversi": "workspace:*", "ms": "3.0.0-canary.202508261828", - "nanoid": "5.1.6", + "nanoid": "5.1.7", "nested-property": "4.0.0", "node-fetch": "3.3.2", "node-html-parser": "7.1.0", - "nodemailer": "8.0.2", - "nsfwjs": "4.2.0", + "nodemailer": "8.0.3", + "nsfwjs": "4.3.0", "oauth2orize": "1.12.0", "oauth2orize-pkce": "0.1.2", "os-utils": "0.0.14", @@ -157,14 +157,14 @@ "rename": "1.0.4", "rss-parser": "3.13.0", "rxjs": "7.8.2", - "sanitize-html": "2.17.1", + "sanitize-html": "2.17.2", "secure-json-parse": "4.1.0", "semver": "7.7.4", "sharp": "0.33.5", "slacc": "0.0.10", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", - "systeminformation": "5.31.4", + "systeminformation": "5.31.5", "tinycolor2": "1.6.0", "tmp": "0.2.5", "tsc-alias": "1.8.16", @@ -172,14 +172,14 @@ "ulid": "3.0.2", "vary": "1.1.2", "web-push": "3.6.7", - "ws": "8.19.0", + "ws": "8.20.0", "xev": "3.0.2" }, "devDependencies": { "@jest/globals": "29.7.0", "@kitajs/ts-html-plugin": "4.1.4", - "@nestjs/platform-express": "11.1.16", - "@sentry/vue": "10.43.0", + "@nestjs/platform-express": "11.1.17", + "@sentry/vue": "10.45.0", "@simplewebauthn/types": "12.0.0", "@swc/jest": "0.2.39", "@types/accepts": "1.3.7", @@ -197,7 +197,7 @@ "@types/nodemailer": "7.0.11", "@types/oauth2orize": "1.11.5", "@types/oauth2orize-pkce": "0.1.2", - "@types/pg": "8.18.0", + "@types/pg": "8.20.0", "@types/qrcode": "1.5.6", "@types/random-seed": "0.3.5", "@types/ratelimiter": "3.4.6", @@ -212,8 +212,8 @@ "@types/vary": "1.1.3", "@types/web-push": "3.6.4", "@types/ws": "8.18.1", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", "aws-sdk-client-mock": "4.1.0", "cbor": "10.0.12", "cross-env": "10.1.0", @@ -225,7 +225,7 @@ "jest-mock": "29.7.0", "js-yaml": "4.1.1", "nodemon": "3.1.14", - "pid-port": "2.0.1", + "pid-port": "2.1.0", "simple-oauth2": "5.1.0", "supertest": "7.2.2", "vite": "7.3.1" diff --git a/packages/backend/src/core/AiService.ts b/packages/backend/src/core/AiService.ts index cbae280030f..7d60995a7d0 100644 --- a/packages/backend/src/core/AiService.ts +++ b/packages/backend/src/core/AiService.ts @@ -10,7 +10,7 @@ import { Injectable } from '@nestjs/common'; import { Mutex } from 'async-mutex'; import fetch from 'node-fetch'; import { bindThis } from '@/decorators.js'; -import type { NSFWJS, PredictionType } from 'nsfwjs'; +import type { NSFWJS, PredictionType } from 'nsfwjs/core'; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); @@ -43,7 +43,7 @@ export class AiService { tf.env().global.fetch = fetch; if (this.model == null) { - const nsfw = await import('nsfwjs'); + const nsfw = await import('nsfwjs/core'); await this.modelLoadMutex.runExclusive(async () => { if (this.model == null) { this.model = await nsfw.load(`file://${_dirname}/../../nsfw-model/`, { size: 299 }); diff --git a/packages/frontend-builder/package.json b/packages/frontend-builder/package.json index 874a56e02a3..f4326907d20 100644 --- a/packages/frontend-builder/package.json +++ b/packages/frontend-builder/package.json @@ -12,9 +12,9 @@ "devDependencies": { "@types/estree": "1.0.8", "@types/node": "24.12.0", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", - "rollup": "4.59.0" + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", + "rollup": "4.60.0" }, "dependencies": { "i18n": "workspace:*", diff --git a/packages/frontend-embed/package.json b/packages/frontend-embed/package.json index 941651f3eaf..fa5ba3038e3 100644 --- a/packages/frontend-embed/package.json +++ b/packages/frontend-embed/package.json @@ -25,7 +25,7 @@ "mfm-js": "0.25.0", "misskey-js": "workspace:*", "punycode.js": "2.3.1", - "rollup": "4.59.0", + "rollup": "4.60.0", "sass": "1.98.0", "shiki": "3.23.0", "tinycolor2": "1.6.0", @@ -43,25 +43,25 @@ "@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/tinycolor2": "1.4.6", "@types/ws": "8.18.1", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", - "@vitest/coverage-v8": "4.1.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", + "@vitest/coverage-v8": "4.1.1", "@vue/runtime-core": "3.5.30", "acorn": "8.16.0", "cross-env": "10.1.0", "eslint-plugin-import": "2.32.0", "eslint-plugin-vue": "10.8.0", - "happy-dom": "20.8.4", + "happy-dom": "20.8.8", "intersection-observer": "0.12.2", "micromatch": "4.0.8", - "msw": "2.12.10", + "msw": "2.12.14", "nodemon": "3.1.14", "prettier": "3.8.1", "start-server-and-test": "2.1.5", "tsx": "4.21.0", "vite-plugin-turbosnap": "1.0.3", - "vue-component-type-helpers": "3.2.5", + "vue-component-type-helpers": "3.2.6", "vue-eslint-parser": "10.4.0", - "vue-tsc": "3.2.5" + "vue-tsc": "3.2.6" } } diff --git a/packages/frontend-shared/package.json b/packages/frontend-shared/package.json index 817129dabaa..c53695735f9 100644 --- a/packages/frontend-shared/package.json +++ b/packages/frontend-shared/package.json @@ -22,8 +22,8 @@ }, "devDependencies": { "@types/node": "24.12.0", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", "esbuild": "0.27.4", "eslint-plugin-vue": "10.8.0", "nodemon": "3.1.14", diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 5cdf0cf6626..a99918e7b6f 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -24,7 +24,7 @@ "@rollup/plugin-json": "6.1.0", "@rollup/plugin-replace": "6.0.3", "@rollup/pluginutils": "5.3.0", - "@sentry/vue": "10.43.0", + "@sentry/vue": "10.45.0", "@syuilo/aiscript": "1.2.1", "@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0", "@twemoji/parser": "16.0.0", @@ -39,7 +39,7 @@ "chartjs-chart-matrix": "3.0.0", "chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-zoom": "2.2.0", - "chromatic": "15.2.0", + "chromatic": "15.3.1", "compare-versions": "6.1.1", "cropperjs": "2.1.0", "date-fns": "4.1.0", @@ -55,7 +55,7 @@ "is-file-animated": "1.0.2", "json5": "2.2.3", "matter-js": "0.20.0", - "mediabunny": "1.39.2", + "mediabunny": "1.40.1", "mfm-js": "0.25.0", "misskey-bubble-game": "workspace:*", "misskey-js": "workspace:*", @@ -64,8 +64,8 @@ "punycode.js": "2.3.1", "qr-code-styling": "1.9.2", "qr-scanner": "1.4.2", - "rollup": "4.59.0", - "sanitize-html": "2.17.1", + "rollup": "4.60.0", + "sanitize-html": "2.17.2", "sass": "1.98.0", "shiki": "3.23.0", "textarea-caret": "3.1.0", @@ -81,7 +81,7 @@ "@misskey-dev/summaly": "5.2.5", "@storybook/addon-essentials": "8.6.18", "@storybook/addon-interactions": "8.6.18", - "@storybook/addon-links": "10.2.17", + "@storybook/addon-links": "10.3.3", "@storybook/addon-mdx-gfm": "8.6.18", "@storybook/addon-storysource": "8.6.18", "@storybook/blocks": "8.6.18", @@ -89,13 +89,13 @@ "@storybook/core-events": "8.6.18", "@storybook/manager-api": "8.6.18", "@storybook/preview-api": "8.6.18", - "@storybook/react": "10.2.17", - "@storybook/react-vite": "10.2.17", + "@storybook/react": "10.3.3", + "@storybook/react-vite": "10.3.3", "@storybook/test": "8.6.18", "@storybook/theming": "8.6.18", "@storybook/types": "8.6.18", - "@storybook/vue3": "10.2.17", - "@storybook/vue3-vite": "10.2.17", + "@storybook/vue3": "10.3.3", + "@storybook/vue3-vite": "10.3.3", "@tabler/icons-webfont": "3.35.0", "@testing-library/vue": "8.1.0", "@types/canvas-confetti": "1.9.0", @@ -110,23 +110,23 @@ "@types/textarea-caret": "3.0.4", "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", - "@vitest/coverage-v8": "4.1.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", + "@vitest/coverage-v8": "4.1.1", "@vue/compiler-core": "3.5.30", "acorn": "8.16.0", "astring": "1.9.0", "cross-env": "10.1.0", - "cypress": "15.11.0", + "cypress": "15.13.0", "eslint-plugin-import": "2.32.0", "eslint-plugin-vue": "10.8.0", "estree-walker": "3.0.3", - "happy-dom": "20.8.4", + "happy-dom": "20.8.8", "intersection-observer": "0.12.2", "magic-string": "0.30.21", "micromatch": "4.0.8", "minimatch": "10.2.4", - "msw": "2.12.10", + "msw": "2.12.14", "msw-storybook-addon": "2.0.6", "nodemon": "3.1.14", "prettier": "3.8.1", @@ -134,15 +134,15 @@ "react-dom": "19.2.4", "seedrandom": "3.0.5", "start-server-and-test": "2.1.5", - "storybook": "10.2.17", + "storybook": "10.3.3", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "tsx": "4.21.0", - "vite-plugin-glsl": "1.5.5", + "vite-plugin-glsl": "1.5.6", "vite-plugin-turbosnap": "1.0.3", - "vitest": "4.1.0", + "vitest": "4.1.1", "vitest-fetch-mock": "0.4.5", - "vue-component-type-helpers": "3.2.5", + "vue-component-type-helpers": "3.2.6", "vue-eslint-parser": "10.4.0", - "vue-tsc": "3.2.5" + "vue-tsc": "3.2.6" } } diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 3278a0860cb..1b7ba3057ff 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -30,8 +30,8 @@ "devDependencies": { "@types/js-yaml": "4.0.9", "@types/node": "24.12.0", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", "chokidar": "5.0.0", "esbuild": "0.27.4", "execa": "9.6.1", diff --git a/packages/icons-subsetter/package.json b/packages/icons-subsetter/package.json index b05e04178ec..8989d827618 100644 --- a/packages/icons-subsetter/package.json +++ b/packages/icons-subsetter/package.json @@ -13,12 +13,12 @@ "devDependencies": { "@types/node": "24.12.0", "@types/wawoff2": "1.0.2", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0" + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2" }, "dependencies": { "@tabler/icons-webfont": "3.35.0", - "harfbuzzjs": "0.10.0", + "harfbuzzjs": "0.10.1", "tsx": "4.21.0", "wawoff2": "2.0.1" }, diff --git a/packages/misskey-bubble-game/package.json b/packages/misskey-bubble-game/package.json index 137698d0aba..b6f4824b127 100644 --- a/packages/misskey-bubble-game/package.json +++ b/packages/misskey-bubble-game/package.json @@ -27,8 +27,8 @@ "@types/matter-js": "0.20.2", "@types/node": "24.12.0", "@types/seedrandom": "3.0.8", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", "esbuild": "0.27.4", "execa": "9.6.1", "nodemon": "3.1.14" diff --git a/packages/misskey-js/generator/package.json b/packages/misskey-js/generator/package.json index a20fb84c8f9..c6f9c801fff 100644 --- a/packages/misskey-js/generator/package.json +++ b/packages/misskey-js/generator/package.json @@ -9,8 +9,8 @@ "devDependencies": { "@readme/openapi-parser": "5.5.0", "@types/node": "24.12.0", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", "openapi-types": "12.1.3", "openapi-typescript": "7.13.0", "ts-case-convert": "2.1.0", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 57c08561503..abf85c276c5 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -39,15 +39,15 @@ "devDependencies": { "@microsoft/api-extractor": "7.57.7", "@types/node": "24.12.0", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", - "@vitest/coverage-v8": "4.1.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", + "@vitest/coverage-v8": "4.1.1", "esbuild": "0.27.4", "execa": "9.6.1", "ncp": "2.0.0", "nodemon": "3.1.14", "tsd": "0.33.0", - "vitest": "4.1.0", + "vitest": "4.1.1", "vitest-websocket-mock": "0.5.0" }, "files": [ diff --git a/packages/misskey-reversi/package.json b/packages/misskey-reversi/package.json index c8c3090f628..e75c361d9b3 100644 --- a/packages/misskey-reversi/package.json +++ b/packages/misskey-reversi/package.json @@ -25,8 +25,8 @@ }, "devDependencies": { "@types/node": "24.12.0", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", "esbuild": "0.27.4", "execa": "9.6.1", "nodemon": "3.1.14" diff --git a/packages/sw/package.json b/packages/sw/package.json index ae3c6ada0cc..c5d3295730e 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -15,7 +15,7 @@ "misskey-js": "workspace:*" }, "devDependencies": { - "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/parser": "8.57.2", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.74", "eslint-plugin-import": "2.32.0", "nodemon": "3.1.14" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 848d1c3e867..1c16139fa41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,18 +32,18 @@ importers: specifier: 8.5.8 version: 8.5.8 tar: - specifier: 7.5.11 - version: 7.5.11 + specifier: 7.5.13 + version: 7.5.13 terser: - specifier: 5.46.0 - version: 5.46.0 + specifier: 5.46.1 + version: 5.46.1 devDependencies: '@eslint/js': specifier: 9.39.4 version: 9.39.4 '@misskey-dev/eslint-plugin': specifier: 2.1.0 - version: 2.1.0(@eslint/compat@1.4.0(eslint@9.39.4))(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4))(eslint@9.39.4)(globals@17.4.0) + version: 2.1.0(@eslint/compat@1.4.0(eslint@9.39.4))(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4))(eslint@9.39.4)(globals@17.4.0) '@types/js-yaml': specifier: 4.0.9 version: 4.0.9 @@ -51,11 +51,11 @@ importers: specifier: 24.12.0 version: 24.12.0 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@typescript/native-preview': specifier: 7.0.0-dev.20260116.1 version: 7.0.0-dev.20260116.1 @@ -63,8 +63,8 @@ importers: specifier: 10.1.0 version: 10.1.0 cypress: - specifier: 15.11.0 - version: 15.11.0 + specifier: 15.13.0 + version: 15.13.0 eslint: specifier: 9.39.4 version: 9.39.4 @@ -75,8 +75,8 @@ importers: specifier: 2.0.0 version: 2.0.0 pnpm: - specifier: 10.32.1 - version: 10.32.1 + specifier: 10.33.0 + version: 10.33.0 start-server-and-test: specifier: 2.1.5 version: 2.1.5 @@ -91,11 +91,11 @@ importers: packages/backend: dependencies: '@aws-sdk/client-s3': - specifier: 3.1008.0 - version: 3.1008.0 + specifier: 3.1016.0 + version: 3.1016.0 '@aws-sdk/lib-storage': - specifier: 3.1008.0 - version: 3.1008.0(@aws-sdk/client-s3@3.1008.0) + specifier: 3.1016.0 + version: 3.1016.0(@aws-sdk/client-s3@3.1016.0) '@discordapp/twemoji': specifier: 16.0.1 version: 16.0.1 @@ -109,8 +109,8 @@ importers: specifier: 4.0.4 version: 4.0.4 '@fastify/http-proxy': - specifier: 11.4.1 - version: 11.4.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) + specifier: 11.4.2 + version: 11.4.2(bufferutil@4.1.0)(utf-8-validate@6.0.6) '@fastify/multipart': specifier: 9.4.0 version: 9.4.0 @@ -127,26 +127,26 @@ importers: specifier: 5.2.5 version: 5.2.5 '@napi-rs/canvas': - specifier: 0.1.96 - version: 0.1.96 + specifier: 0.1.97 + version: 0.1.97 '@nestjs/common': - specifier: 11.1.16 - version: 11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: 11.1.17 + version: 11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': - specifier: 11.1.16 - version: 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: 11.1.17 + version: 11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/testing': - specifier: 11.1.16 - version: 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16) + specifier: 11.1.17 + version: 11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-express@11.1.17) '@peertube/http-signature': specifier: 1.7.0 version: 1.7.0 '@sentry/node': - specifier: 10.43.0 - version: 10.43.0 + specifier: 10.45.0 + version: 10.45.0 '@sentry/profiling-node': - specifier: 10.43.0 - version: 10.43.0 + specifier: 10.45.0 + version: 10.45.0 '@simplewebauthn/server': specifier: 13.3.0 version: 13.3.0 @@ -154,14 +154,14 @@ importers: specifier: 15.1.1 version: 15.1.1 '@smithy/node-http-handler': - specifier: 4.4.16 - version: 4.4.16 + specifier: 4.5.0 + version: 4.5.0 '@swc/cli': specifier: 0.8.0 - version: 0.8.0(@swc/core@1.15.18)(chokidar@5.0.0) + version: 0.8.0(@swc/core@1.15.21)(chokidar@5.0.0) '@swc/core': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@twemoji/parser': specifier: 16.0.0 version: 16.0.0 @@ -214,8 +214,8 @@ importers: specifier: 0.1.21 version: 0.1.21 fastify: - specifier: 5.8.2 - version: 5.8.2 + specifier: 5.8.4 + version: 5.8.4 fastify-raw-body: specifier: 5.0.0 version: 5.0.0 @@ -223,8 +223,8 @@ importers: specifier: 5.2.0 version: 5.2.0 file-type: - specifier: 21.3.2 - version: 21.3.2 + specifier: 21.3.4 + version: 21.3.4 fluent-ffmpeg: specifier: 2.1.3 version: 2.1.3 @@ -244,8 +244,8 @@ importers: specifier: workspace:* version: link:../i18n ioredis: - specifier: 5.10.0 - version: 5.10.0 + specifier: 5.10.1 + version: 5.10.1 ip-cidr: specifier: 4.0.2 version: 4.0.2 @@ -265,8 +265,8 @@ importers: specifier: 11.1.1 version: 11.1.1 meilisearch: - specifier: 0.55.0 - version: 0.55.0 + specifier: 0.56.0 + version: 0.56.0 mfm-js: specifier: 0.25.0 version: 0.25.0 @@ -283,8 +283,8 @@ importers: specifier: 3.0.0-canary.202508261828 version: 3.0.0-canary.202508261828 nanoid: - specifier: 5.1.6 - version: 5.1.6 + specifier: 5.1.7 + version: 5.1.7 nested-property: specifier: 4.0.0 version: 4.0.0 @@ -295,11 +295,11 @@ importers: specifier: 7.1.0 version: 7.1.0 nodemailer: - specifier: 8.0.2 - version: 8.0.2 + specifier: 8.0.3 + version: 8.0.3 nsfwjs: - specifier: 4.2.0 - version: 4.2.0(@tensorflow/tfjs@4.22.0(encoding@0.1.13)(seedrandom@3.0.5))(buffer@6.0.3) + specifier: 4.3.0 + version: 4.3.0(@tensorflow/tfjs@4.22.0(encoding@0.1.13)(seedrandom@3.0.5))(buffer@6.0.3) oauth2orize: specifier: 1.12.0 version: 1.12.0 @@ -349,8 +349,8 @@ importers: specifier: 7.8.2 version: 7.8.2 sanitize-html: - specifier: 2.17.1 - version: 2.17.1 + specifier: 2.17.2 + version: 2.17.2 secure-json-parse: specifier: 4.1.0 version: 4.1.0 @@ -370,8 +370,8 @@ importers: specifier: 2.1.0 version: 2.1.0 systeminformation: - specifier: 5.31.4 - version: 5.31.4 + specifier: 5.31.5 + version: 5.31.5 tinycolor2: specifier: 1.6.0 version: 1.6.0 @@ -383,7 +383,7 @@ importers: version: 1.8.16 typeorm: specifier: 0.3.28 - version: 0.3.28(ioredis@5.10.0)(pg@8.20.0) + version: 0.3.28(ioredis@5.10.1)(pg@8.20.0) ulid: specifier: 3.0.2 version: 3.0.2 @@ -394,8 +394,8 @@ importers: specifier: 3.6.7 version: 3.6.7 ws: - specifier: 8.19.0 - version: 8.19.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + specifier: 8.20.0 + version: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) xev: specifier: 3.0.2 version: 3.0.2 @@ -407,17 +407,17 @@ importers: specifier: 4.1.4 version: 4.1.4(@kitajs/html@4.2.13)(typescript@5.9.3) '@nestjs/platform-express': - specifier: 11.1.16 - version: 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + specifier: 11.1.17 + version: 11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) '@sentry/vue': - specifier: 10.43.0 - version: 10.43.0(vue@3.5.30(typescript@5.9.3)) + specifier: 10.45.0 + version: 10.45.0(vue@3.5.30(typescript@5.9.3)) '@simplewebauthn/types': specifier: 12.0.0 version: 12.0.0 '@swc/jest': specifier: 0.2.39 - version: 0.2.39(@swc/core@1.15.18) + version: 0.2.39(@swc/core@1.15.21) '@types/accepts': specifier: 1.3.7 version: 1.3.7 @@ -464,8 +464,8 @@ importers: specifier: 0.1.2 version: 0.1.2 '@types/pg': - specifier: 8.18.0 - version: 8.18.0 + specifier: 8.20.0 + version: 8.20.0 '@types/qrcode': specifier: 1.5.6 version: 1.5.6 @@ -509,11 +509,11 @@ importers: specifier: 8.18.1 version: 8.18.1 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) aws-sdk-client-mock: specifier: 4.1.0 version: 4.1.0 @@ -528,7 +528,7 @@ importers: version: 1.0.1 eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + version: 2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) execa: specifier: 9.6.1 version: 9.6.1 @@ -548,8 +548,8 @@ importers: specifier: 3.1.14 version: 3.1.14 pid-port: - specifier: 2.0.1 - version: 2.0.1 + specifier: 2.1.0 + version: 2.1.0 simple-oauth2: specifier: 5.1.0 version: 5.1.0 @@ -558,44 +558,44 @@ importers: version: 7.2.2 vite: specifier: 7.3.1 - version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: '@swc/core-android-arm64': specifier: 1.3.11 version: 1.3.11 '@swc/core-darwin-arm64': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@swc/core-darwin-x64': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@swc/core-freebsd-x64': specifier: 1.3.11 version: 1.3.11 '@swc/core-linux-arm-gnueabihf': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@swc/core-linux-arm64-gnu': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@swc/core-linux-arm64-musl': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@swc/core-linux-x64-gnu': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@swc/core-linux-x64-musl': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@swc/core-win32-arm64-msvc': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@swc/core-win32-ia32-msvc': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@swc/core-win32-x64-msvc': - specifier: 1.15.18 - version: 1.15.18 + specifier: 1.15.21 + version: 1.15.21 '@tensorflow/tfjs': specifier: 4.22.0 version: 4.22.0(encoding@0.1.13)(seedrandom@3.0.5) @@ -667,16 +667,16 @@ importers: version: 2024.1.0 '@rollup/plugin-json': specifier: 6.1.0 - version: 6.1.0(rollup@4.59.0) + version: 6.1.0(rollup@4.60.0) '@rollup/plugin-replace': specifier: 6.0.3 - version: 6.0.3(rollup@4.59.0) + version: 6.0.3(rollup@4.60.0) '@rollup/pluginutils': specifier: 5.3.0 - version: 5.3.0(rollup@4.59.0) + version: 5.3.0(rollup@4.60.0) '@sentry/vue': - specifier: 10.43.0 - version: 10.43.0(vue@3.5.30(typescript@5.9.3)) + specifier: 10.45.0 + version: 10.45.0(vue@3.5.30(typescript@5.9.3)) '@syuilo/aiscript': specifier: 1.2.1 version: 1.2.1 @@ -688,7 +688,7 @@ importers: version: 16.0.0 '@vitejs/plugin-vue': specifier: 6.0.5 - version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) aiscript-vscode: specifier: github:aiscript-dev/aiscript-vscode#v0.1.16 version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/1dc7f60cda78d030dadfc518a33c472202b2ef67 @@ -720,8 +720,8 @@ importers: specifier: 2.2.0 version: 2.2.0(chart.js@4.5.1) chromatic: - specifier: 15.2.0 - version: 15.2.0 + specifier: 15.3.1 + version: 15.3.1 compare-versions: specifier: 6.1.1 version: 6.1.1 @@ -768,8 +768,8 @@ importers: specifier: 0.20.0 version: 0.20.0 mediabunny: - specifier: 1.39.2 - version: 1.39.2 + specifier: 1.40.1 + version: 1.40.1 mfm-js: specifier: 0.25.0 version: 0.25.0 @@ -795,11 +795,11 @@ importers: specifier: 1.4.2 version: 1.4.2 rollup: - specifier: 4.59.0 - version: 4.59.0 + specifier: 4.60.0 + version: 4.60.0 sanitize-html: - specifier: 2.17.1 - version: 2.17.1 + specifier: 2.17.2 + version: 2.17.2 sass: specifier: 1.98.0 version: 1.98.0 @@ -823,7 +823,7 @@ importers: version: 1.13.1(vue@3.5.30(typescript@5.9.3)) vite: specifier: 7.3.1 - version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: specifier: 3.5.30 version: 3.5.30(typescript@5.9.3) @@ -836,55 +836,55 @@ importers: version: 5.2.5 '@storybook/addon-essentials': specifier: 8.6.18 - version: 8.6.18(@types/react@19.2.2)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(@types/react@19.2.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/addon-interactions': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/addon-links': - specifier: 10.2.17 - version: 10.2.17(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + specifier: 10.3.3 + version: 10.3.3(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/addon-mdx-gfm': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/addon-storysource': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/blocks': specifier: 8.6.18 - version: 8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/components': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/core-events': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/manager-api': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/preview-api': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/react': - specifier: 10.2.17 - version: 10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) + specifier: 10.3.3 + version: 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) '@storybook/react-vite': - specifier: 10.2.17 - version: 10.2.17(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) + specifier: 10.3.3 + version: 10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/test': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/theming': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/types': specifier: 8.6.18 - version: 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@storybook/vue3': - specifier: 10.2.17 - version: 10.2.17(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) + specifier: 10.3.3 + version: 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) '@storybook/vue3-vite': - specifier: 10.2.17 - version: 10.2.17(esbuild@0.27.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + specifier: 10.3.3 + version: 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) '@tabler/icons-webfont': specifier: 3.35.0 version: 3.35.0 @@ -928,14 +928,14 @@ importers: specifier: 1.4.6 version: 1.4.6 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': - specifier: 4.1.0 - version: 4.1.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))) + specifier: 4.1.1 + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) '@vue/compiler-core': specifier: 3.5.30 version: 3.5.30 @@ -949,20 +949,20 @@ importers: specifier: 10.1.0 version: 10.1.0 cypress: - specifier: 15.11.0 - version: 15.11.0 + specifier: 15.13.0 + version: 15.13.0 eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + version: 2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) eslint-plugin-vue: specifier: 10.8.0 - version: 10.8.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) + version: 10.8.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) estree-walker: specifier: 3.0.3 version: 3.0.3 happy-dom: - specifier: 20.8.4 - version: 20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6) + specifier: 20.8.8 + version: 20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6) intersection-observer: specifier: 0.12.2 version: 0.12.2 @@ -976,11 +976,11 @@ importers: specifier: 10.2.4 version: 10.2.4 msw: - specifier: 2.12.10 - version: 2.12.10(@types/node@24.12.0)(typescript@5.9.3) + specifier: 2.12.14 + version: 2.12.14(@types/node@24.12.0)(typescript@5.9.3) msw-storybook-addon: specifier: 2.0.6 - version: 2.0.6(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3)) + version: 2.0.6(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3)) nodemon: specifier: 3.1.14 version: 3.1.14 @@ -1000,35 +1000,35 @@ importers: specifier: 2.1.5 version: 2.1.5 storybook: - specifier: 10.2.17 - version: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + specifier: 10.3.3 + version: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(b407b999cadc51b47ccbc8c1fb8ccff6) + version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(568dc48ee0a6363e76595daf2f12f0a3) tsx: specifier: 4.21.0 version: 4.21.0 vite-plugin-glsl: - specifier: 1.5.5 - version: 1.5.5(@rollup/pluginutils@5.3.0(rollup@4.59.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) + specifier: 1.5.6 + version: 1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 vitest: - specifier: 4.1.0 - version: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) + specifier: 4.1.1 + version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vitest-fetch-mock: specifier: 0.4.5 - version: 0.4.5(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))) + version: 0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) vue-component-type-helpers: - specifier: 3.2.5 - version: 3.2.5 + specifier: 3.2.6 + version: 3.2.6 vue-eslint-parser: specifier: 10.4.0 version: 10.4.0(eslint@9.39.4) vue-tsc: - specifier: 3.2.5 - version: 3.2.5(typescript@5.9.3) + specifier: 3.2.6 + version: 3.2.6(typescript@5.9.3) packages/frontend-builder: dependencies: @@ -1043,7 +1043,7 @@ importers: version: 0.30.21 vite: specifier: 7.3.1 - version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) devDependencies: '@types/estree': specifier: 1.0.8 @@ -1052,14 +1052,14 @@ importers: specifier: 24.12.0 version: 24.12.0 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) rollup: - specifier: 4.59.0 - version: 4.59.0 + specifier: 4.60.0 + version: 4.60.0 packages/frontend-embed: dependencies: @@ -1068,19 +1068,19 @@ importers: version: 16.0.1 '@rollup/plugin-json': specifier: 6.1.0 - version: 6.1.0(rollup@4.59.0) + version: 6.1.0(rollup@4.60.0) '@rollup/plugin-replace': specifier: 6.0.3 - version: 6.0.3(rollup@4.59.0) + version: 6.0.3(rollup@4.60.0) '@rollup/pluginutils': specifier: 5.3.0 - version: 5.3.0(rollup@4.59.0) + version: 5.3.0(rollup@4.60.0) '@twemoji/parser': specifier: 16.0.0 version: 16.0.0 '@vitejs/plugin-vue': specifier: 6.0.5 - version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) buraha: specifier: 0.0.1 version: 0.0.1 @@ -1109,8 +1109,8 @@ importers: specifier: 2.3.1 version: 2.3.1 rollup: - specifier: 4.59.0 - version: 4.59.0 + specifier: 4.60.0 + version: 4.60.0 sass: specifier: 1.98.0 version: 1.98.0 @@ -1125,7 +1125,7 @@ importers: version: 13.0.0 vite: specifier: 7.3.1 - version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: specifier: 3.5.30 version: 3.5.30(typescript@5.9.3) @@ -1158,14 +1158,14 @@ importers: specifier: 8.18.1 version: 8.18.1 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': - specifier: 4.1.0 - version: 4.1.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))) + specifier: 4.1.1 + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) '@vue/runtime-core': specifier: 3.5.30 version: 3.5.30 @@ -1177,13 +1177,13 @@ importers: version: 10.1.0 eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + version: 2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) eslint-plugin-vue: specifier: 10.8.0 - version: 10.8.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) + version: 10.8.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) happy-dom: - specifier: 20.8.4 - version: 20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6) + specifier: 20.8.8 + version: 20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6) intersection-observer: specifier: 0.12.2 version: 0.12.2 @@ -1191,8 +1191,8 @@ importers: specifier: 4.0.8 version: 4.0.8 msw: - specifier: 2.12.10 - version: 2.12.10(@types/node@24.12.0)(typescript@5.9.3) + specifier: 2.12.14 + version: 2.12.14(@types/node@24.12.0)(typescript@5.9.3) nodemon: specifier: 3.1.14 version: 3.1.14 @@ -1209,14 +1209,14 @@ importers: specifier: 1.0.3 version: 1.0.3 vue-component-type-helpers: - specifier: 3.2.5 - version: 3.2.5 + specifier: 3.2.6 + version: 3.2.6 vue-eslint-parser: specifier: 10.4.0 version: 10.4.0(eslint@9.39.4) vue-tsc: - specifier: 3.2.5 - version: 3.2.5(typescript@5.9.3) + specifier: 3.2.6 + version: 3.2.6(typescript@5.9.3) packages/frontend-shared: dependencies: @@ -1234,17 +1234,17 @@ importers: specifier: 24.12.0 version: 24.12.0 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) esbuild: specifier: 0.27.4 version: 0.27.4 eslint-plugin-vue: specifier: 10.8.0 - version: 10.8.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) + version: 10.8.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) nodemon: specifier: 3.1.14 version: 3.1.14 @@ -1265,11 +1265,11 @@ importers: specifier: 24.12.0 version: 24.12.0 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) chokidar: specifier: 5.0.0 version: 5.0.0 @@ -1292,8 +1292,8 @@ importers: specifier: 3.35.0 version: 3.35.0 harfbuzzjs: - specifier: 0.10.0 - version: 0.10.0 + specifier: 0.10.1 + version: 0.10.1 tsx: specifier: 4.21.0 version: 4.21.0 @@ -1308,11 +1308,11 @@ importers: specifier: 1.0.2 version: 1.0.2 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) packages/misskey-bubble-game: dependencies: @@ -1336,11 +1336,11 @@ importers: specifier: 3.0.8 version: 3.0.8 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) esbuild: specifier: 0.27.4 version: 0.27.4 @@ -1370,14 +1370,14 @@ importers: specifier: 24.12.0 version: 24.12.0 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': - specifier: 4.1.0 - version: 4.1.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))) + specifier: 4.1.1 + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) esbuild: specifier: 0.27.4 version: 0.27.4 @@ -1394,11 +1394,11 @@ importers: specifier: 0.33.0 version: 0.33.0 vitest: - specifier: 4.1.0 - version: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) + specifier: 4.1.1 + version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vitest-websocket-mock: specifier: 0.5.0 - version: 0.5.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))) + version: 0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) packages/misskey-js/generator: devDependencies: @@ -1409,11 +1409,11 @@ importers: specifier: 24.12.0 version: 24.12.0 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) eslint: specifier: 9.39.4 version: 9.39.4 @@ -1440,11 +1440,11 @@ importers: specifier: 24.12.0 version: 24.12.0 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) esbuild: specifier: 0.27.4 version: 0.27.4 @@ -1471,14 +1471,14 @@ importers: version: link:../misskey-js devDependencies: '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.57.2 + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@typescript/lib-webworker': specifier: npm:@types/serviceworker@0.0.74 version: '@types/serviceworker@0.0.74' eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + version: 2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) nodemon: specifier: 3.1.14 version: 3.1.14 @@ -1553,133 +1553,133 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-s3@3.1008.0': - resolution: {integrity: sha512-w/SIRD25v2zVMbkn8CYIxUsac8yf5Jghkhw5j7EsNWdJhl56m/nWpUX7t1etFUW1cnzpFjZV0lXt0dNFSnbXwA==} + '@aws-sdk/client-s3@3.1016.0': + resolution: {integrity: sha512-E9umet1PolP6I8TpjQQ2W88aIIguyiRQJE98ag6N6QeLgjSZsF+h9l3KclwCRvqUFU68x+HRwrgXxvbIBVFLbA==} engines: {node: '>=20.0.0'} - '@aws-sdk/core@3.973.19': - resolution: {integrity: sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ==} + '@aws-sdk/core@3.973.24': + resolution: {integrity: sha512-vvf82RYQu2GidWAuQq+uIzaPz9V0gSCXVqdVzRosgl5rXcspXOpSD3wFreGGW6AYymPr97Z69kjVnLePBxloDw==} engines: {node: '>=20.0.0'} - '@aws-sdk/crc64-nvme@3.972.4': - resolution: {integrity: sha512-HKZIZLbRyvzo/bXZU7Zmk6XqU+1C9DjI56xd02vwuDIxedxBEqP17t9ExhbP9QFeNq/a3l9GOcyirFXxmbDhmw==} + '@aws-sdk/crc64-nvme@3.972.5': + resolution: {integrity: sha512-2VbTstbjKdT+yKi8m7b3a9CiVac+pL/IY2PHJwsaGkkHmuuqkJZIErPck1h6P3T9ghQMLSdMPyW6Qp7Di5swFg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-env@3.972.17': - resolution: {integrity: sha512-MBAMW6YELzE1SdkOniqr51mrjapQUv8JXSGxtwRjQV0mwVDutVsn22OPAUt4RcLRvdiHQmNBDEFP9iTeSVCOlA==} + '@aws-sdk/credential-provider-env@3.972.22': + resolution: {integrity: sha512-cXp0VTDWT76p3hyK5D51yIKEfpf6/zsUvMfaB8CkyqadJxMQ8SbEeVroregmDlZbtG31wkj9ei0WnftmieggLg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-http@3.972.19': - resolution: {integrity: sha512-9EJROO8LXll5a7eUFqu48k6BChrtokbmgeMWmsH7lBb6lVbtjslUYz/ShLi+SHkYzTomiGBhmzTW7y+H4BxsnA==} + '@aws-sdk/credential-provider-http@3.972.24': + resolution: {integrity: sha512-h694K7+tRuepSRJr09wTvQfaEnjzsKZ5s7fbESrVds02GT/QzViJ94/HCNwM7bUfFxqpPXHxulZfL6Cou0dwPg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-ini@3.972.19': - resolution: {integrity: sha512-pVJVjWqVrPqjpFq7o0mCmeZu1Y0c94OCHSYgivdCD2wfmYVtBbwQErakruhgOD8pcMcx9SCqRw1pzHKR7OGBcA==} + '@aws-sdk/credential-provider-ini@3.972.24': + resolution: {integrity: sha512-O46fFmv0RDFWiWEA9/e6oW92BnsyAXuEgTTasxHligjn2RCr9L/DK773m/NoFaL3ZdNAUz8WxgxunleMnHAkeQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-login@3.972.19': - resolution: {integrity: sha512-jOXdZ1o+CywQKr6gyxgxuUmnGwTTnY2Kxs1PM7fI6AYtDWDnmW/yKXayNqkF8KjP1unflqMWKVbVt5VgmE3L0g==} + '@aws-sdk/credential-provider-login@3.972.24': + resolution: {integrity: sha512-sIk8oa6AzDoUhxsR11svZESqvzGuXesw62Rl2oW6wguZx8i9cdGCvkFg+h5K7iucUZP8wyWibUbJMc+J66cu5g==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-node@3.972.20': - resolution: {integrity: sha512-0xHca2BnPY0kzjDYPH7vk8YbfdBPpWVS67rtqQMalYDQUCBYS37cZ55K6TuFxCoIyNZgSCFrVKr9PXC5BVvQQw==} + '@aws-sdk/credential-provider-node@3.972.25': + resolution: {integrity: sha512-m7dR0Dsva2P+VUpL+VkC0WwiDby5pgmWXkRVDB5rlwv0jXJrQJf7YMtCoM8Wjk0H9jPeCYOxOXXcIgp/qp5Alg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-process@3.972.17': - resolution: {integrity: sha512-c8G8wT1axpJDgaP3xzcy+q8Y1fTi9A2eIQJvyhQ9xuXrUZhlCfXbC0vM9bM1CUXiZppFQ1p7g0tuUMvil/gCPg==} + '@aws-sdk/credential-provider-process@3.972.22': + resolution: {integrity: sha512-Os32s8/4gTZjBk5BtoS/cuTILaj+K72d0dVG7TCJX/fC4598cxwLDmf1AEHEpER5oL3K//yETjvFaz0V8oO5Xw==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-sso@3.972.19': - resolution: {integrity: sha512-kVjQsEU3b///q7EZGrUzol9wzwJFKbEzqJKSq82A9ShrUTEO7FNylTtby3sPV19ndADZh1H3FB3+5ZrvKtEEeg==} + '@aws-sdk/credential-provider-sso@3.972.24': + resolution: {integrity: sha512-PaFv7snEfypU2yXkpvfyWgddEbDLtgVe51wdZlinhc2doubBjUzJZZpgwuF2Jenl1FBydMhNpMjD6SBUM3qdSA==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.19': - resolution: {integrity: sha512-BV1BlTFdG4w4tAihxN7iXDBoNcNewXD4q8uZlNQiUrnqxwGWUhKHODIQVSPlQGxXClEj+63m+cqZskw+ESmeZg==} + '@aws-sdk/credential-provider-web-identity@3.972.24': + resolution: {integrity: sha512-J6H4R1nvr3uBTqD/EeIPAskrBtET4WFfNhpFySr2xW7bVZOXpQfPjrLSIx65jcNjBmLXzWq8QFLdVoGxiGG/SA==} engines: {node: '>=20.0.0'} - '@aws-sdk/lib-storage@3.1008.0': - resolution: {integrity: sha512-SWIzixPt9VG6jz8+tR8VklOi3FXY1J6WMfd1JEtY9gVtJaLGF5tWexIkjUnGHP8B6M6Uk+qC5zdr2Caome5Gfg==} + '@aws-sdk/lib-storage@3.1016.0': + resolution: {integrity: sha512-zSHj28SAKCinrxUiJp2fsAFMqc4AWM9WNOOMayysTgOAAticMip9nVcsbcDJCh0PCB9U+ikZdW7OWSCuw7E5xA==} engines: {node: '>=20.0.0'} peerDependencies: - '@aws-sdk/client-s3': ^3.1008.0 + '@aws-sdk/client-s3': ^3.1016.0 - '@aws-sdk/middleware-bucket-endpoint@3.972.7': - resolution: {integrity: sha512-goX+axlJ6PQlRnzE2bQisZ8wVrlm6dXJfBzMJhd8LhAIBan/w1Kl73fJnalM/S+18VnpzIHumyV6DtgmvqG5IA==} + '@aws-sdk/middleware-bucket-endpoint@3.972.8': + resolution: {integrity: sha512-WR525Rr2QJSETa9a050isktyWi/4yIGcmY3BQ1kpHqb0LqUglQHCS8R27dTJxxWNZvQ0RVGtEZjTCbZJpyF3Aw==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-expect-continue@3.972.7': - resolution: {integrity: sha512-mvWqvm61bmZUKmmrtl2uWbokqpenY3Mc3Jf4nXB/Hse6gWxLPaCQThmhPBDzsPSV8/Odn8V6ovWt3pZ7vy4BFQ==} + '@aws-sdk/middleware-expect-continue@3.972.8': + resolution: {integrity: sha512-5DTBTiotEES1e2jOHAq//zyzCjeMB78lEHd35u15qnrid4Nxm7diqIf9fQQ3Ov0ChH1V3Vvt13thOnrACmfGVQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-flexible-checksums@3.973.5': - resolution: {integrity: sha512-Dp3hqE5W6hG8HQ3Uh+AINx9wjjqYmFHbxede54sGj3akx/haIQrkp85lNdTdC+ouNUcSYNiuGkzmyDREfHX1Gg==} + '@aws-sdk/middleware-flexible-checksums@3.974.4': + resolution: {integrity: sha512-fhCbZXPAyy8btnNbnBlR7Cc1nD54cETSvGn2wey71ehsM89AKPO8Dpco9DBAAgvrUdLrdHQepBXcyX4vxC5OwA==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-host-header@3.972.7': - resolution: {integrity: sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ==} + '@aws-sdk/middleware-host-header@3.972.8': + resolution: {integrity: sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-location-constraint@3.972.7': - resolution: {integrity: sha512-vdK1LJfffBp87Lj0Bw3WdK1rJk9OLDYdQpqoKgmpIZPe+4+HawZ6THTbvjhJt4C4MNnRrHTKHQjkwBiIpDBoig==} + '@aws-sdk/middleware-location-constraint@3.972.8': + resolution: {integrity: sha512-KaUoFuoFPziIa98DSQsTPeke1gvGXlc5ZGMhy+b+nLxZ4A7jmJgLzjEF95l8aOQN2T/qlPP3MrAyELm8ExXucw==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-logger@3.972.7': - resolution: {integrity: sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w==} + '@aws-sdk/middleware-logger@3.972.8': + resolution: {integrity: sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-recursion-detection@3.972.7': - resolution: {integrity: sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ==} + '@aws-sdk/middleware-recursion-detection@3.972.8': + resolution: {integrity: sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-sdk-s3@3.972.19': - resolution: {integrity: sha512-/CtOHHVFg4ZuN6CnLnYkrqWgVEnbOBC4kNiKa+4fldJ9cioDt3dD/f5vpq0cWLOXwmGL2zgVrVxNhjxWpxNMkg==} + '@aws-sdk/middleware-sdk-s3@3.972.24': + resolution: {integrity: sha512-4sXxVC/enYgMkZefNMOzU6C6KtAXEvwVJLgNcUx1dvROH6GvKB5Sm2RGnGzTp0/PwkibIyMw4kOzF8tbLfaBAQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-ssec@3.972.7': - resolution: {integrity: sha512-G9clGVuAml7d8DYzY6DnRi7TIIDRvZ3YpqJPz/8wnWS5fYx/FNWNmkO6iJVlVkQg9BfeMzd+bVPtPJOvC4B+nQ==} + '@aws-sdk/middleware-ssec@3.972.8': + resolution: {integrity: sha512-wqlK0yO/TxEC2UsY9wIlqeeutF6jjLe0f96Pbm40XscTo57nImUk9lBcw0dPgsm0sppFtAkSlDrfpK+pC30Wqw==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-user-agent@3.972.20': - resolution: {integrity: sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA==} + '@aws-sdk/middleware-user-agent@3.972.25': + resolution: {integrity: sha512-QxiMPofvOt8SwSynTOmuZfvvPM1S9QfkESBxB22NMHTRXCJhR5BygLl8IXfC4jELiisQgwsgUby21GtXfX3f/g==} engines: {node: '>=20.0.0'} - '@aws-sdk/nested-clients@3.996.9': - resolution: {integrity: sha512-+RpVtpmQbbtzFOKhMlsRcXM/3f1Z49qTOHaA8gEpHOYruERmog6f2AUtf/oTRLCWjR9H2b3roqryV/hI7QMW8w==} + '@aws-sdk/nested-clients@3.996.14': + resolution: {integrity: sha512-fSESKvh1VbfjtV3QMnRkCPZWkUbQof6T/DOpiLp33yP2wA+rbwwnZeG3XT3Ekljgw2I8X4XaQPnw+zSR8yxJ5Q==} engines: {node: '>=20.0.0'} - '@aws-sdk/region-config-resolver@3.972.7': - resolution: {integrity: sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA==} + '@aws-sdk/region-config-resolver@3.972.9': + resolution: {integrity: sha512-eQ+dFU05ZRC/lC2XpYlYSPlXtX3VT8sn5toxN2Fv7EXlMoA2p9V7vUBKqHunfD4TRLpxUq8Y8Ol/nCqiv327Ng==} engines: {node: '>=20.0.0'} - '@aws-sdk/signature-v4-multi-region@3.996.7': - resolution: {integrity: sha512-mYhh7FY+7OOqjkYkd6+6GgJOsXK1xBWmuR+c5mxJPj2kr5TBNeZq+nUvE9kANWAux5UxDVrNOSiEM/wlHzC3Lg==} + '@aws-sdk/signature-v4-multi-region@3.996.12': + resolution: {integrity: sha512-abRObSqjVeKUUHIZfAp78PTYrEsxCgVKDs/YET357pzT5C02eDDEvmWyeEC2wglWcYC4UTbBFk22gd2YJUlCQg==} engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.1008.0': - resolution: {integrity: sha512-TulwlHQBWcJs668kNUDMZHN51DeLrDsYT59Ux4a/nbvr025gM6HjKJJ3LvnZccam7OS/ZKUVkWomCneRQKJbBg==} + '@aws-sdk/token-providers@3.1015.0': + resolution: {integrity: sha512-3OSD4y110nisRhHzFOjoEeHU4GQL4KpzkX9PxzWaiZe0Yg2+thZKM0Pn9DjYwezH5JYfh/K++xK/SE0IHGrmCQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/types@3.973.5': - resolution: {integrity: sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ==} + '@aws-sdk/types@3.973.6': + resolution: {integrity: sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==} engines: {node: '>=20.0.0'} '@aws-sdk/util-arn-parser@3.972.3': resolution: {integrity: sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-endpoints@3.996.4': - resolution: {integrity: sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA==} + '@aws-sdk/util-endpoints@3.996.5': + resolution: {integrity: sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw==} engines: {node: '>=20.0.0'} '@aws-sdk/util-locate-window@3.893.0': resolution: {integrity: sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==} engines: {node: '>=18.0.0'} - '@aws-sdk/util-user-agent-browser@3.972.7': - resolution: {integrity: sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw==} + '@aws-sdk/util-user-agent-browser@3.972.8': + resolution: {integrity: sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA==} - '@aws-sdk/util-user-agent-node@3.973.6': - resolution: {integrity: sha512-iF7G0prk7AvmOK64FcLvc/fW+Ty1H+vttajL7PvJFReU8urMxfYmynTTuFKDTA76Wgpq3FzTPKwabMQIXQHiXQ==} + '@aws-sdk/util-user-agent-node@3.973.11': + resolution: {integrity: sha512-1qdXbXo2s5MMLpUvw00284LsbhtlQ4ul7Zzdn5n+7p4WVgCMLqhxImpHIrjSoc72E/fyc4Wq8dLtUld2Gsh+lA==} engines: {node: '>=20.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -1687,8 +1687,8 @@ packages: aws-crt: optional: true - '@aws-sdk/xml-builder@3.972.10': - resolution: {integrity: sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA==} + '@aws-sdk/xml-builder@3.972.15': + resolution: {integrity: sha512-PxMRlCFNiQnke9YR29vjFQwz4jq+6Q04rOVFeTDR2K7Qpv9h9FOWOxG+zJjageimYbWqE3bTuLjmryWHAWbvaA==} engines: {node: '>=20.0.0'} '@aws/lambda-invoke-store@0.2.2': @@ -2198,8 +2198,8 @@ packages: '@fastify/forwarded@3.0.1': resolution: {integrity: sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==} - '@fastify/http-proxy@11.4.1': - resolution: {integrity: sha512-sMYEIB0c7qCYutpZyS12c8xnVgmEMSUUVU2XjcNq2JzHf6Hta1BWcpnG5FXxR3WEm48uZNCi0MxnIYtwjwd21Q==} + '@fastify/http-proxy@11.4.2': + resolution: {integrity: sha512-J52YphwK9XMw85Sy0Dx5ExKPntMbG9YQeKcwqfjaYpTUqaCvqGwuySLU9ltIFFyslDZUdiX5JrxeZRxyfD4gaw==} '@fastify/merge-json-schemas@0.2.1': resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} @@ -2207,8 +2207,8 @@ packages: '@fastify/multipart@9.4.0': resolution: {integrity: sha512-Z404bzZeLSXTBmp/trCBuoVFX28pM7rhv849Q5TsbTFZHuk1lc4QjQITTPK92DKVpXmNtJXeHSSc7GYvqFpxAQ==} - '@fastify/otel@0.16.0': - resolution: {integrity: sha512-2304BdM5Q/kUvQC9qJO1KZq3Zn1WWsw+WWkVmFEaj1UE2hEIiuFqrPeglQOwEtw/ftngisqfQ3v70TWMmwhhHA==} + '@fastify/otel@0.17.1': + resolution: {integrity: sha512-K4wyxfUZx2ux5o+b6BtTqouYFVILohLZmSbA2tKUueJstNcBnoGPVhllCaOvbQ3ZrXdUxUC/fyrSWSCqHhdOPg==} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -2686,79 +2686,79 @@ packages: resolution: {integrity: sha512-7G0Uf0yK3f2bjElBLGHIQzgRgMESczOMyYVasq1XK8P5HaXtlW4eQhz9MBL+TQILZLaruq+ClGId+hH0w4jvWw==} engines: {node: '>=18'} - '@napi-rs/canvas-android-arm64@0.1.96': - resolution: {integrity: sha512-ew1sPrN3dGdZ3L4FoohPfnjq0f9/Jk7o+wP7HkQZokcXgIUD6FIyICEWGhMYzv53j63wUcPvZeAwgewX58/egg==} + '@napi-rs/canvas-android-arm64@0.1.97': + resolution: {integrity: sha512-V1c/WVw+NzH8vk7ZK/O8/nyBSCQimU8sfMsB/9qeSvdkGKNU7+mxy/bIF0gTgeBFmHpj30S4E9WHMSrxXGQuVQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/canvas-darwin-arm64@0.1.96': - resolution: {integrity: sha512-Q/wOXZ5PzTqpdmA5eUOcegCf4Go/zz3aZ5DlzSeDpOjFmfwMKh8EzLAoweQ+mJVagcHQyzoJhaTEnrO68TNyNg==} + '@napi-rs/canvas-darwin-arm64@0.1.97': + resolution: {integrity: sha512-ok+SCEF4YejcxuJ9Rm+WWunHHpf2HmiPxfz6z1a/NFQECGXtsY7A4B8XocK1LmT1D7P174MzwPF9Wy3AUAwEPw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/canvas-darwin-x64@0.1.96': - resolution: {integrity: sha512-UrXiQz28tQEvGM1qvyptewOAfmUrrd5+wvi6Rzjj2VprZI8iZ2KIvBD2lTTG1bVF95AbeDeG7PJA0D9sLKaOFA==} + '@napi-rs/canvas-darwin-x64@0.1.97': + resolution: {integrity: sha512-PUP6e6/UGlclUvAQNnuXCcnkpdUou6VYZfQOQxExLp86epOylmiwLkqXIvpFmjoTEDmPmXrI+coL/9EFU1gKPA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.96': - resolution: {integrity: sha512-I90ODxweD8aEP6XKU/NU+biso95MwCtQ2F46dUvhec1HesFi0tq/tAJkYic/1aBSiO/1kGKmSeD1B0duOHhEHQ==} + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.97': + resolution: {integrity: sha512-XyXH2L/cic8eTNtbrXCcvqHtMX/nEOxN18+7rMrAM2XtLYC/EB5s0wnO1FsLMWmK+04ZSLN9FBGipo7kpIkcOw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/canvas-linux-arm64-gnu@0.1.96': - resolution: {integrity: sha512-Dx/0+RFV++w3PcRy+4xNXkghhXjA5d0Mw1bs95emn5Llinp1vihMaA6WJt3oYv2LAHc36+gnrhIBsPhUyI2SGw==} + '@napi-rs/canvas-linux-arm64-gnu@0.1.97': + resolution: {integrity: sha512-Kuq/M3djq0K8ktgz6nPlK7Ne5d4uWeDxPpyKWOjWDK2RIOhHVtLtyLiJw2fuldw7Vn4mhw05EZXCEr4Q76rs9w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-arm64-musl@0.1.96': - resolution: {integrity: sha512-UvOi7fii3IE2KDfEfhh8m+LpzSRvhGK7o1eho99M2M0HTik11k3GX+2qgVx9EtujN3/bhFFS1kSO3+vPMaJ0Mg==} + '@napi-rs/canvas-linux-arm64-musl@0.1.97': + resolution: {integrity: sha512-kKmSkQVnWeqg7qdsiXvYxKhAFuHz3tkBjW/zyQv5YKUPhotpaVhpBGv5LqCngzyuRV85SXoe+OFj+Tv0a0QXkQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@napi-rs/canvas-linux-riscv64-gnu@0.1.96': - resolution: {integrity: sha512-MBSukhGCQ5nRtf9NbFYWOU080yqkZU1PbuH4o1ROvB4CbPl12fchDR35tU83Wz8gWIM9JTn99lBn9DenPIv7Ig==} + '@napi-rs/canvas-linux-riscv64-gnu@0.1.97': + resolution: {integrity: sha512-Jc7I3A51jnEOIAXeLsN/M/+Z28LUeakcsXs07FLq9prXc0eYOtVwsDEv913Gr+06IRo34gJJVgT0TXvmz+N2VA==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-x64-gnu@0.1.96': - resolution: {integrity: sha512-I/ccu2SstyKiV3HIeVzyBIWfrJo8cN7+MSQZPnabewWV6hfJ2nY7Df2WqOHmobBRUw84uGR6zfQHsUEio/m5Vg==} + '@napi-rs/canvas-linux-x64-gnu@0.1.97': + resolution: {integrity: sha512-iDUBe7AilfuBSRbSa8/IGX38Mf+iCSBqoVKLSQ5XaY2JLOaqz1TVyPFEyIck7wT6mRQhQt5sN6ogfjIDfi74tg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-x64-musl@0.1.96': - resolution: {integrity: sha512-H3uov7qnTl73GDT4h52lAqpJPsl1tIUyNPWJyhQ6gHakohNqqRq3uf80+NEpzcytKGEOENP1wX3yGwZxhjiWEQ==} + '@napi-rs/canvas-linux-x64-musl@0.1.97': + resolution: {integrity: sha512-AKLFd/v0Z5fvgqBDqhvqtAdx+fHMJ5t9JcUNKq4FIZ5WH+iegGm8HPdj00NFlCSnm83Fp3Ln8I2f7uq1aIiWaA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@napi-rs/canvas-win32-arm64-msvc@0.1.96': - resolution: {integrity: sha512-ATp6Y+djOjYtkfV/VRH7CZ8I1MEtkUQBmKUbuWw5zWEHHqfL0cEcInE4Cxgx7zkNAhEdBbnH8HMVrqNp+/gwxA==} + '@napi-rs/canvas-win32-arm64-msvc@0.1.97': + resolution: {integrity: sha512-u883Yr6A6fO7Vpsy9YE4FVCIxzzo5sO+7pIUjjoDLjS3vQaNMkVzx5bdIpEL+ob+gU88WDK4VcxYMZ6nmnoX9A==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/canvas-win32-x64-msvc@0.1.96': - resolution: {integrity: sha512-UYGdTltVd+Z8mcIuoqGmAXXUvwH5CLf2M6mIB5B0/JmX5J041jETjqtSYl7gN+aj3k1by/SG6sS0hAwCqyK7zw==} + '@napi-rs/canvas-win32-x64-msvc@0.1.97': + resolution: {integrity: sha512-sWtD2EE3fV0IzN+iiQUqr/Q1SwqWhs2O1FKItFlxtdDkikpEj5g7DKQpY3x55H/MAOnL8iomnlk3mcEeGiUMoQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/canvas@0.1.96': - resolution: {integrity: sha512-6NNmNxvoJKeucVjxaaRUt3La2i5jShgiAbaY3G/72s1Vp3U06XPrAIxkAjBxpDcamEn/t+WJ4OOlGmvILo4/Ew==} + '@napi-rs/canvas@0.1.97': + resolution: {integrity: sha512-8cFniXvrIEnVwuNSRCW9wirRZbHvrD3JVujdS2P5n5xiJZNZMOZcfOvJ1pb66c7jXMKHHglJEDVJGbm8XWFcXQ==} engines: {node: '>= 10'} '@napi-rs/nice-android-arm-eabi@1.1.1': @@ -2874,8 +2874,8 @@ packages: resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} engines: {node: '>= 10'} - '@nestjs/common@11.1.16': - resolution: {integrity: sha512-JSIeW+USuMJkkcNbiOdcPkVCeI3TSnXstIVEPpp3HiaKnPRuSbUUKm9TY9o/XpIcPHWUOQItAtC5BiAwFdVITQ==} + '@nestjs/common@11.1.17': + resolution: {integrity: sha512-hLODw5Abp8OQgA+mUO4tHou4krKgDtUcM9j5Ihxncst9XeyxYBTt2bwZm4e4EQr5E352S4Fyy6V3iFx9ggxKAg==} peerDependencies: class-transformer: '>=0.4.1' class-validator: '>=0.13.2' @@ -2887,8 +2887,8 @@ packages: class-validator: optional: true - '@nestjs/core@11.1.16': - resolution: {integrity: sha512-tXWXyCiqWthelJjrE0KLFjf0O98VEt+WPVx5CrqCf+059kIxJ8y1Vw7Cy7N4fwQafWNrmFL2AfN87DDMbVAY0w==} + '@nestjs/core@11.1.17': + resolution: {integrity: sha512-lD5mAYekTTurF3vDaa8C2OKPnjiz4tsfxIc5XlcSUzOhkwWf6Ay3HKvt6FmvuWQam6uIIHX52Clg+e6tAvf/cg==} engines: {node: '>= 20'} peerDependencies: '@nestjs/common': ^11.0.0 @@ -2905,14 +2905,14 @@ packages: '@nestjs/websockets': optional: true - '@nestjs/platform-express@11.1.16': - resolution: {integrity: sha512-IOegr5+ZfUiMKgk+garsSU4MOkPRhm46e6w8Bp1GcO4vCdl9Piz6FlWAzKVfa/U3Hn/DdzSVJOW3TWcQQFdBDw==} + '@nestjs/platform-express@11.1.17': + resolution: {integrity: sha512-mAf4eOsSBsTOn/VbrUO1gsjW6dVh91qqXPMXun4dN8SnNjf7PTQagM9o8d6ab8ZBpNe6UdZftdrZoDetU+n4Qg==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 - '@nestjs/testing@11.1.16': - resolution: {integrity: sha512-E7/aUCxzeMSJV80L5GWGIuiMyR/1ncS7uOIetAImfbS4ATE1/h2GBafk0qpk+vjFtPIbtoh9BWDGICzUEU5jDA==} + '@nestjs/testing@11.1.17': + resolution: {integrity: sha512-lNffw+z+2USewmw4W0tsK+Rq94A2N4PiHbcqoRUu5y8fnqxQeIWGHhjo5BFCqj7eivqJBhT7WdRydxVq4rAHzg==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -2973,164 +2973,158 @@ packages: resolution: {integrity: sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==} engines: {node: '>=8.0.0'} - '@opentelemetry/api-logs@0.208.0': - resolution: {integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==} + '@opentelemetry/api-logs@0.212.0': + resolution: {integrity: sha512-TEEVrLbNROUkYY51sBJGk7lO/OLjuepch8+hmpM6ffMJQ2z/KVCjdHuCFX6fJj8OkJP2zckPjrJzQtXU3IAsFg==} engines: {node: '>=8.0.0'} - '@opentelemetry/api-logs@0.211.0': - resolution: {integrity: sha512-swFdZq8MCdmdR22jTVGQDhwqDzcI4M10nhjXkLr1EsIzXgZBqm4ZlmmcWsg3TSNf+3mzgOiqveXmBLZuDi2Lgg==} + '@opentelemetry/api-logs@0.213.0': + resolution: {integrity: sha512-zRM5/Qj6G84Ej3F1yt33xBVY/3tnMxtL1fiDIxYbDWYaZ/eudVw3/PBiZ8G7JwUxXxjW8gU4g6LnOyfGKYHYgw==} engines: {node: '>=8.0.0'} '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} - '@opentelemetry/context-async-hooks@2.5.1': - resolution: {integrity: sha512-MHbu8XxCHcBn6RwvCt2Vpn1WnLMNECfNKYB14LI5XypcgH4IE0/DiVifVR9tAkwPMyLXN8dOoPJfya3IryLQVw==} + '@opentelemetry/context-async-hooks@2.6.0': + resolution: {integrity: sha512-L8UyDwqpTcbkIK5cgwDRDYDoEhQoj8wp8BwsO19w3LB1Z41yEQm2VJyNfAi9DrLP/YTqXqWpKHyZfR9/tFYo1Q==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/core@2.5.0': - resolution: {integrity: sha512-ka4H8OM6+DlUhSAZpONu0cPBtPPTQKxbxVzC4CzVx5+K4JnroJVBtDzLAMx4/3CDTJXRvVFhpFjtl4SaiTNoyQ==} + '@opentelemetry/core@2.6.0': + resolution: {integrity: sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/core@2.5.1': - resolution: {integrity: sha512-Dwlc+3HAZqpgTYq0MUyZABjFkcrKTePwuiFVLjahGD8cx3enqihmpAmdgNFO1R4m/sIe5afjJrA25Prqy4NXlA==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - - '@opentelemetry/instrumentation-amqplib@0.58.0': - resolution: {integrity: sha512-fjpQtH18J6GxzUZ+cwNhWUpb71u+DzT7rFkg5pLssDGaEber91Y2WNGdpVpwGivfEluMlNMZumzjEqfg8DeKXQ==} + '@opentelemetry/instrumentation-amqplib@0.60.0': + resolution: {integrity: sha512-q/B2IvoVXRm1M00MvhnzpMN6rKYOszPXVsALi6u0ss4AYHe+TidZEtLW9N1ZhrobI1dSriHnBqqtAOZVAv07sg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-connect@0.54.0': - resolution: {integrity: sha512-43RmbhUhqt3uuPnc16cX6NsxEASEtn8z/cYV8Zpt6EP4p2h9s4FNuJ4Q9BbEQ2C0YlCCB/2crO1ruVz/hWt8fA==} + '@opentelemetry/instrumentation-connect@0.56.0': + resolution: {integrity: sha512-PKp+sSZ7AfzMvGgO3VCyo1inwNu+q7A1k9X88WK4PQ+S6Hp7eFk8pie+sWHDTaARovmqq5V2osav3lQej2B0nw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-dataloader@0.28.0': - resolution: {integrity: sha512-ExXGBp0sUj8yhm6Znhf9jmuOaGDsYfDES3gswZnKr4MCqoBWQdEFn6EoDdt5u+RdbxQER+t43FoUihEfTSqsjA==} + '@opentelemetry/instrumentation-dataloader@0.30.0': + resolution: {integrity: sha512-MXHP2Q38cd2OhzEBKAIXUi9uBlPEYzF6BNJbyjUXBQ6kLaf93kRC41vNMIz0Nl5mnuwK7fDvKT+/lpx7BXRwdg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-express@0.59.0': - resolution: {integrity: sha512-pMKV/qnHiW/Q6pmbKkxt0eIhuNEtvJ7sUAyee192HErlr+a1Jx+FZ3WjfmzhQL1geewyGEiPGkmjjAgNY8TgDA==} + '@opentelemetry/instrumentation-express@0.61.0': + resolution: {integrity: sha512-Xdmqo9RZuZlL29Flg8QdwrrX7eW1CZ7wFQPKHyXljNymgKhN1MCsYuqQ/7uxavhSKwAl7WxkTzKhnqpUApLMvQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-fs@0.30.0': - resolution: {integrity: sha512-n3Cf8YhG7reaj5dncGlRIU7iT40bxPOjsBEA5Bc1a1g6e9Qvb+JFJ7SEiMlPbUw4PBmxE3h40ltE8LZ3zVt6OA==} + '@opentelemetry/instrumentation-fs@0.32.0': + resolution: {integrity: sha512-koR6apx0g0wX6RRiPpjA4AFQUQUbXrK16kq4/SZjVp7u5cffJhNkY4TnITxcGA4acGSPYAfx3NHRIv4Khn1axQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-generic-pool@0.54.0': - resolution: {integrity: sha512-8dXMBzzmEdXfH/wjuRvcJnUFeWzZHUnExkmFJ2uPfa31wmpyBCMxO59yr8f/OXXgSogNgi/uPo9KW9H7LMIZ+g==} + '@opentelemetry/instrumentation-generic-pool@0.56.0': + resolution: {integrity: sha512-fg+Jffs6fqrf0uQS0hom7qBFKsbtpBiBl8+Vkc63Gx8xh6pVh+FhagmiO6oM0m3vyb683t1lP7yGYq22SiDnqg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-graphql@0.58.0': - resolution: {integrity: sha512-+yWVVY7fxOs3j2RixCbvue8vUuJ1inHxN2q1sduqDB0Wnkr4vOzVKRYl/Zy7B31/dcPS72D9lo/kltdOTBM3bQ==} + '@opentelemetry/instrumentation-graphql@0.61.0': + resolution: {integrity: sha512-pUiVASv6nh2XrerTvlbVHh7vKFzscpgwiQ/xvnZuAIzQ5lRjWVdRPUuXbvZJ/Yq79QsE81TZdJ7z9YsXiss1ew==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-hapi@0.57.0': - resolution: {integrity: sha512-Os4THbvls8cTQTVA8ApLfZZztuuqGEeqog0XUnyRW7QVF0d/vOVBEcBCk1pazPFmllXGEdNbbat8e2fYIWdFbw==} + '@opentelemetry/instrumentation-hapi@0.59.0': + resolution: {integrity: sha512-33wa4mEr+9+ztwdgLor1SeBu4Opz4IsmpcLETXAd3VmBrOjez8uQtrsOhPCa5Vhbm5gzDlMYTgFRLQzf8/YHFA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-http@0.211.0': - resolution: {integrity: sha512-n0IaQ6oVll9PP84SjbOCwDjaJasWRHi6BLsbMLiT6tNj7QbVOkuA5sk/EfZczwI0j5uTKl1awQPivO/ldVtsqA==} + '@opentelemetry/instrumentation-http@0.213.0': + resolution: {integrity: sha512-B978Xsm5XEPGhm1P07grDoaOFLHapJPkOG9h016cJsyWWxmiLnPu2M/4Nrm7UCkHSiLnkXgC+zVGUAIahy8EEA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-ioredis@0.59.0': - resolution: {integrity: sha512-875UxzBHWkW+P4Y45SoFM2AR8f8TzBMD8eO7QXGCyFSCUMP5s9vtt/BS8b/r2kqLyaRPK6mLbdnZznK3XzQWvw==} + '@opentelemetry/instrumentation-ioredis@0.61.0': + resolution: {integrity: sha512-hsHDadUtAFbws1YSDc1XW0svGFKiUbqv2td1Cby+UAiwvojm1NyBo/taifH0t8CuFZ0x/2SDm0iuTwrM5pnVOg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-kafkajs@0.20.0': - resolution: {integrity: sha512-yJXOuWZROzj7WmYCUiyT27tIfqBrVtl1/TwVbQyWPz7rL0r1Lu7kWjD0PiVeTCIL6CrIZ7M2s8eBxsTAOxbNvw==} + '@opentelemetry/instrumentation-kafkajs@0.22.0': + resolution: {integrity: sha512-wJU4IBQMUikdJAcTChLFqK5lo+flo7pahqd8DSLv7uMxsdOdAHj6RzKYAm8pPfUS6ItKYutYyuicwKaFwQKsoA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-knex@0.55.0': - resolution: {integrity: sha512-FtTL5DUx5Ka/8VK6P1VwnlUXPa3nrb7REvm5ddLUIeXXq4tb9pKd+/ThB1xM/IjefkRSN3z8a5t7epYw1JLBJQ==} + '@opentelemetry/instrumentation-knex@0.57.0': + resolution: {integrity: sha512-vMCSh8kolEm5rRsc+FZeTZymWmIJwc40hjIKnXH4O0Dv/gAkJJIRXCsPX5cPbe0c0j/34+PsENd0HqKruwhVYw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-koa@0.59.0': - resolution: {integrity: sha512-K9o2skADV20Skdu5tG2bogPKiSpXh4KxfLjz6FuqIVvDJNibwSdu5UvyyBzRVp1rQMV6UmoIk6d3PyPtJbaGSg==} + '@opentelemetry/instrumentation-koa@0.61.0': + resolution: {integrity: sha512-lvrfWe9ShK/D2X4brmx8ZqqeWPfRl8xekU0FCn7C1dHm5k6+rTOOi36+4fnaHAP8lig9Ux6XQ1D4RNIpPCt1WQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.9.0 - '@opentelemetry/instrumentation-lru-memoizer@0.55.0': - resolution: {integrity: sha512-FDBfT7yDGcspN0Cxbu/k8A0Pp1Jhv/m7BMTzXGpcb8ENl3tDj/51U65R5lWzUH15GaZA15HQ5A5wtafklxYj7g==} + '@opentelemetry/instrumentation-lru-memoizer@0.57.0': + resolution: {integrity: sha512-cEqpUocSKJfwDtLYTTJehRLWzkZ2eoePCxfVIgGkGkb83fMB71O+y4MvRHJPbeV2bdoWdOVrl8uO0+EynWhTEA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mongodb@0.64.0': - resolution: {integrity: sha512-pFlCJjweTqVp7B220mCvCld1c1eYKZfQt1p3bxSbcReypKLJTwat+wbL2YZoX9jPi5X2O8tTKFEOahO5ehQGsA==} + '@opentelemetry/instrumentation-mongodb@0.66.0': + resolution: {integrity: sha512-d7m9QnAY+4TCWI4q1QRkfrc6fo/92VwssaB1DzQfXNRvu51b78P+HJlWP7Qg6N6nkwdb9faMZNBCZJfftmszkw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mongoose@0.57.0': - resolution: {integrity: sha512-MthiekrU/BAJc5JZoZeJmo0OTX6ycJMiP6sMOSRTkvz5BrPMYDqaJos0OgsLPL/HpcgHP7eo5pduETuLguOqcg==} + '@opentelemetry/instrumentation-mongoose@0.59.0': + resolution: {integrity: sha512-6/jWU+c1NgznkVLDU/2y0bXV2nJo3o9FWZ9mZ9nN6T/JBNRoMnVXZl2FdBmgH+a5MwaWLs5kmRJTP5oUVGIkPw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mysql2@0.57.0': - resolution: {integrity: sha512-nHSrYAwF7+aV1E1V9yOOP9TchOodb6fjn4gFvdrdQXiRE7cMuffyLLbCZlZd4wsspBzVwOXX8mpURdRserAhNA==} + '@opentelemetry/instrumentation-mysql2@0.59.0': + resolution: {integrity: sha512-n9/xrVCRBfG9egVbffnlU1uhr+HX0vF4GgtAB/Bvm48wpFgRidqD8msBMiym1kRYzmpWvJqTxNT47u1MkgBEdw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mysql@0.57.0': - resolution: {integrity: sha512-HFS/+FcZ6Q7piM7Il7CzQ4VHhJvGMJWjx7EgCkP5AnTntSN5rb5Xi3TkYJHBKeR27A0QqPlGaCITi93fUDs++Q==} + '@opentelemetry/instrumentation-mysql@0.59.0': + resolution: {integrity: sha512-r+V/Fh0sm7Ga8/zk/TI5H5FQRAjwr0RrpfPf8kNIehlsKf12XnvIaZi8ViZkpX0gyPEpLXqzqWD6QHlgObgzZw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-pg@0.63.0': - resolution: {integrity: sha512-dKm/ODNN3GgIQVlbD6ZPxwRc3kleLf95hrRWXM+l8wYo+vSeXtEpQPT53afEf6VFWDVzJK55VGn8KMLtSve/cg==} + '@opentelemetry/instrumentation-pg@0.65.0': + resolution: {integrity: sha512-W0zpHEIEuyZ8zvb3njaX9AAbHgPYOsSWVOoWmv1sjVRSF6ZpBqtlxBWbU+6hhq1TFWBeWJOXZ8nZS/PUFpLJYQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-redis@0.59.0': - resolution: {integrity: sha512-JKv1KDDYA2chJ1PC3pLP+Q9ISMQk6h5ey+99mB57/ARk0vQPGZTTEb4h4/JlcEpy7AYT8HIGv7X6l+br03Neeg==} + '@opentelemetry/instrumentation-redis@0.61.0': + resolution: {integrity: sha512-JnPexA034/0UJRsvH96B0erQoNOqKJZjE2ZRSw9hiTSC23LzE0nJE/u6D+xqOhgUhRnhhcPHq4MdYtmUdYTF+Q==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-tedious@0.30.0': - resolution: {integrity: sha512-bZy9Q8jFdycKQ2pAsyuHYUHNmCxCOGdG6eg1Mn75RvQDccq832sU5OWOBnc12EFUELI6icJkhR7+EQKMBam2GA==} + '@opentelemetry/instrumentation-tedious@0.32.0': + resolution: {integrity: sha512-BQS6gG8RJ1foEqfEZ+wxoqlwfCAzb1ZVG0ad8Gfe4x8T658HJCLGLd4E4NaoQd8EvPfLqOXgzGaE/2U4ytDSWA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-undici@0.21.0': - resolution: {integrity: sha512-gok0LPUOTz2FQ1YJMZzaHcOzDFyT64XJ8M9rNkugk923/p6lDGms/cRW1cqgqp6N6qcd6K6YdVHwPEhnx9BWbw==} + '@opentelemetry/instrumentation-undici@0.23.0': + resolution: {integrity: sha512-LL0VySzKVR2cJSFVZaTYpZl1XTpBGnfzoQPe2W7McS2267ldsaEIqtQY6VXs2KCXN0poFjze5110PIpxHDaDGg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.7.0 @@ -3141,14 +3135,14 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.208.0': - resolution: {integrity: sha512-Eju0L4qWcQS+oXxi6pgh7zvE2byogAkcsVv0OjHF/97iOz1N/aKE6etSGowYkie+YA1uo6DNwdSxaaNnLvcRlA==} + '@opentelemetry/instrumentation@0.212.0': + resolution: {integrity: sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.211.0': - resolution: {integrity: sha512-h0nrZEC/zvI994nhg7EgQ8URIHt0uDTwN90r3qQUdZORS455bbx+YebnGeEuFghUT0HlJSrLF4iHw67f+odY+Q==} + '@opentelemetry/instrumentation@0.213.0': + resolution: {integrity: sha512-3i9NdkET/KvQomeh7UaR/F4r9P25Rx6ooALlWXPIjypcEOUxksCmVu0zA70NBJWlrMW1rPr/LRidFAflLI+s/w==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 @@ -3157,20 +3151,20 @@ packages: resolution: {integrity: sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA==} engines: {node: ^18.19.0 || >=20.6.0} - '@opentelemetry/resources@2.5.1': - resolution: {integrity: sha512-BViBCdE/GuXRlp9k7nS1w6wJvY5fnFX5XvuEtWsTAOQFIO89Eru7lGW3WbfbxtCuZ/GbrJfAziXG0w0dpxL7eQ==} + '@opentelemetry/resources@2.6.0': + resolution: {integrity: sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-trace-base@2.5.1': - resolution: {integrity: sha512-iZH3Gw8cxQn0gjpOjJMmKLd9GIaNh/E3v3ST67vyzLSxHBs14HsG4dy7jMYyC5WXGdBVEcM7U/XTF5hCQxjDMw==} + '@opentelemetry/sdk-trace-base@2.6.0': + resolution: {integrity: sha512-g/OZVkqlxllgFM7qMKqbPV9c1DUPhQ7d4n3pgZFcrnrNft9eJXZM2TNHTPYREJBrtNdRytYyvwjgL5geDKl3EQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/semantic-conventions@1.39.0': - resolution: {integrity: sha512-R5R9tb2AXs2IRLNKLBJDynhkfmx7mX0vi8NkhZb3gUkPWHn6HXk5J8iQ/dql0U3ApfWym4kXXmBDRGO+oeOfjg==} + '@opentelemetry/semantic-conventions@1.40.0': + resolution: {integrity: sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==} engines: {node: '>=14'} '@opentelemetry/sql-common@0.41.2': @@ -3318,8 +3312,8 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@prisma/instrumentation@7.2.0': - resolution: {integrity: sha512-Rh9Z4x5kEj1OdARd7U18AtVrnL6rmLSI0qYShaB4W7Wx5BKbgzndWF+QnuzMb7GLfVdlT5aYCXoPQVYuYtVu0g==} + '@prisma/instrumentation@7.4.2': + resolution: {integrity: sha512-r9JfchJF1Ae6yAxcaLu/V1TGqBhAuSDe3mRNOssBfx1rMzfZ4fdNvrgUBwyb/TNTGXFxlH9AZix5P257x07nrg==} peerDependencies: '@opentelemetry/api': ^1.8 @@ -3379,141 +3373,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.59.0': - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} + '@rollup/rollup-android-arm-eabi@4.60.0': + resolution: {integrity: sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.59.0': - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} + '@rollup/rollup-android-arm64@4.60.0': + resolution: {integrity: sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.59.0': - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} + '@rollup/rollup-darwin-arm64@4.60.0': + resolution: {integrity: sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.59.0': - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} + '@rollup/rollup-darwin-x64@4.60.0': + resolution: {integrity: sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.59.0': - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} + '@rollup/rollup-freebsd-arm64@4.60.0': + resolution: {integrity: sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.59.0': - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} + '@rollup/rollup-freebsd-x64@4.60.0': + resolution: {integrity: sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.0': + resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} + '@rollup/rollup-linux-arm-musleabihf@4.60.0': + resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.59.0': - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} + '@rollup/rollup-linux-arm64-gnu@4.60.0': + resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.59.0': - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} + '@rollup/rollup-linux-arm64-musl@4.60.0': + resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.59.0': - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} + '@rollup/rollup-linux-loong64-gnu@4.60.0': + resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.59.0': - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} + '@rollup/rollup-linux-loong64-musl@4.60.0': + resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + '@rollup/rollup-linux-ppc64-gnu@4.60.0': + resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.59.0': - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} + '@rollup/rollup-linux-ppc64-musl@4.60.0': + resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} + '@rollup/rollup-linux-riscv64-gnu@4.60.0': + resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.59.0': - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} + '@rollup/rollup-linux-riscv64-musl@4.60.0': + resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.59.0': - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + '@rollup/rollup-linux-s390x-gnu@4.60.0': + resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.59.0': - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + '@rollup/rollup-linux-x64-gnu@4.60.0': + resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.59.0': - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + '@rollup/rollup-linux-x64-musl@4.60.0': + resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.59.0': - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} + '@rollup/rollup-openbsd-x64@4.60.0': + resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.59.0': - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + '@rollup/rollup-openharmony-arm64@4.60.0': + resolution: {integrity: sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.59.0': - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + '@rollup/rollup-win32-arm64-msvc@4.60.0': + resolution: {integrity: sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.59.0': - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} + '@rollup/rollup-win32-ia32-msvc@4.60.0': + resolution: {integrity: sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.59.0': - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} + '@rollup/rollup-win32-x64-gnu@4.60.0': + resolution: {integrity: sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.59.0': - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + '@rollup/rollup-win32-x64-msvc@4.60.0': + resolution: {integrity: sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==} cpu: [x64] os: [win32] @@ -3553,36 +3547,36 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@sentry-internal/browser-utils@10.43.0': - resolution: {integrity: sha512-8zYTnzhAPvNkVH1Irs62wl0J/c+0QcJ62TonKnzpSFUUD3V5qz8YDZbjIDGfxy+1EB9fO0sxtddKCzwTHF/MbQ==} + '@sentry-internal/browser-utils@10.45.0': + resolution: {integrity: sha512-ZPZpeIarXKScvquGx2AfNKcYiVNDA4wegMmjyGVsTA2JPmP0TrJoO3UybJS6KGDeee8V3I3EfD/ruauMm7jOFQ==} engines: {node: '>=18'} - '@sentry-internal/feedback@10.43.0': - resolution: {integrity: sha512-YoXuwluP6eOcQxTeTtaWb090++MrLyWOVsUTejzUQQ6LFL13Jwt+bDPF1kvBugMq4a7OHw/UNKQfd6//rZMn2g==} + '@sentry-internal/feedback@10.45.0': + resolution: {integrity: sha512-vCSurazFVq7RUeYiM5X326jA5gOVrWYD6lYX2fbjBOMcyCEhDnveNxMT62zKkZDyNT/jyD194nz/cjntBUkyWA==} engines: {node: '>=18'} '@sentry-internal/node-cpu-profiler@2.2.0': resolution: {integrity: sha512-oLHVYurqZfADPh5hvmQYS5qx8t0UZzT2u6+/68VXsFruQEOnYJTODKgU3BVLmemRs3WE6kCJjPeFdHVYOQGSzQ==} engines: {node: '>=18'} - '@sentry-internal/replay-canvas@10.43.0': - resolution: {integrity: sha512-ZIw1UNKOFXo1LbPCJPMAx9xv7D8TMZQusLDUgb6BsPQJj0igAuwd7KRGTkjjgnrwBp2O/sxcQFRhQhknWk7QPg==} + '@sentry-internal/replay-canvas@10.45.0': + resolution: {integrity: sha512-nvq/AocdZTuD7y0KSiWi3gVaY0s5HOFy86mC/v1kDZmT/jsBAzN5LDkk/f1FvsWma1peqQmpUqxvhC+YIW294Q==} engines: {node: '>=18'} - '@sentry-internal/replay@10.43.0': - resolution: {integrity: sha512-khCXlGrlH1IU7P5zCEAJFestMeH97zDVCekj8OsNNDtN/1BmCJ46k6Xi0EqAUzdJgrOLJeLdoYdgtiIjovZ8Sg==} + '@sentry-internal/replay@10.45.0': + resolution: {integrity: sha512-vjosRoGA1bzhVAEO1oce+CsRdd70quzBeo7WvYqpcUnoLe/Rv8qpOMqWX3j26z7XfFHMExWQNQeLxmtYOArvlw==} engines: {node: '>=18'} - '@sentry/browser@10.43.0': - resolution: {integrity: sha512-2V3I3sXi3SMeiZpKixd9ztokSgK27cmvsD9J5oyOyjhGLTW/6QKCwHbKnluMgQMXq20nixQk5zN4wRjRUma3sg==} + '@sentry/browser@10.45.0': + resolution: {integrity: sha512-e/a8UMiQhqqv706McSIcG6XK+AoQf9INthi2pD+giZfNRTzXTdqHzUT5OIO5hg8Am6eF63nDJc+vrYNPhzs51Q==} engines: {node: '>=18'} - '@sentry/core@10.43.0': - resolution: {integrity: sha512-l0SszQAPiQGWl/ferw8GP3ALyHXiGiRKJaOvNmhGO+PrTQyZTZ6OYyPnGijAFRg58dE1V3RCH/zw5d2xSUIiNg==} + '@sentry/core@10.45.0': + resolution: {integrity: sha512-s69UXxvefeQxuZ5nY7/THtTrIEvJxNVCp3ns4kwoCw1qMpgpvn/296WCKVmM7MiwnaAdzEKnAvLAwaxZc2nM7Q==} engines: {node: '>=18'} - '@sentry/node-core@10.43.0': - resolution: {integrity: sha512-w2H3NSkNMoYOS7o7mR55BM7+xL++dPxMSv1/XDfsra9FYHGppO+Mxk667Ee5k+uDi+wNIioICIh+5XOvZh4+HQ==} + '@sentry/node-core@10.45.0': + resolution: {integrity: sha512-KQZEvLKM344+EqXiA9HIzWbW5hzq6/9nnFUQ8niaBPoOgR9AiJhrccfIscfgb8vjkriiEtzE03OW/4h1CTgZ3Q==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3608,12 +3602,12 @@ packages: '@opentelemetry/semantic-conventions': optional: true - '@sentry/node@10.43.0': - resolution: {integrity: sha512-oNwXcuZUc4uTTr0WbHZBBIKsKwAKvNMTgbXwxfB37CfzV18wbTirbQABZ/Ir3WNxSgi6ZcnC6UE013jF5XWPqw==} + '@sentry/node@10.45.0': + resolution: {integrity: sha512-Kpiq9lRGnJc1ex8SwxOBl+FLQNl4Y137BydVooP7AFiAYZ6ftwHsIEF1bcYXaipHMT1YHS2bdhC2UQaaB2jkuQ==} engines: {node: '>=18'} - '@sentry/opentelemetry@10.43.0': - resolution: {integrity: sha512-+fIcnnLdvBHdq4nKq23t9v/B9D4L97fPWEDksXbpGs11o6BsqY4Tlzmce6cP95iiQhPckCEag3FthSND+BYtYQ==} + '@sentry/opentelemetry@10.45.0': + resolution: {integrity: sha512-PmuGO+p/gC3ZQ8ddOeJ5P9ApnTTm35i12Bpuyb13AckCbNSJFvG2ggZda35JQOmiFU0kKYiwkoFAa8Mvj9od3Q==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3622,13 +3616,13 @@ packages: '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 '@opentelemetry/semantic-conventions': ^1.39.0 - '@sentry/profiling-node@10.43.0': - resolution: {integrity: sha512-mzd+1svmgWjqe4ROlLOjWtLg8DFt7p4tkox5UoLuSGEqVuBsDhNgZAotahhMZrKqRImP+JAmaHO0SWCDQEMPGw==} + '@sentry/profiling-node@10.45.0': + resolution: {integrity: sha512-O1wgw4NuVRZ1c3kbjwZyZoT+iylgWsldgDZA8jhFBNRRJv7XbzJ3NVji5Ksw3W2uRNUrTfFJNC9UV3brqWom8g==} engines: {node: '>=18'} hasBin: true - '@sentry/vue@10.43.0': - resolution: {integrity: sha512-PYBJVHfd7JwnQv92sTnsfLVNwVEKY2wQzXt9aux6QNcKh4g3pyK68PoEBrcCSEHpUb7zs3lJedk3+aeX+kN7fw==} + '@sentry/vue@10.45.0': + resolution: {integrity: sha512-p6ghTgQtiCBZ+Yw0B2xmC69S8AdCRRsYvbTHW7MJYspwNnJDs7rqgCBqOxNhvr3tsKdDuEOEHLtf/5hbKi+8xQ==} engines: {node: '>=18'} peerDependencies: '@tanstack/vue-router': ^1.64.0 @@ -3732,12 +3726,12 @@ packages: resolution: {integrity: sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw==} engines: {node: '>=18.0.0'} - '@smithy/config-resolver@4.4.11': - resolution: {integrity: sha512-YxFiiG4YDAtX7WMN7RuhHZLeTmRRAOyCbr+zB8e3AQzHPnUhS8zXjB1+cniPVQI3xbWsQPM0X2aaIkO/ME0ymw==} + '@smithy/config-resolver@4.4.13': + resolution: {integrity: sha512-iIzMC5NmOUP6WL6o8iPBjFhUhBZ9pPjpUpQYWMUFQqKyXXzOftbfK8zcQCz/jFV1Psmf05BK5ypx4K2r4Tnwdg==} engines: {node: '>=18.0.0'} - '@smithy/core@3.23.11': - resolution: {integrity: sha512-952rGf7hBRnhUIaeLp6q4MptKW8sPFe5VvkoZ5qIzFAtx6c/QZ/54FS3yootsyUSf9gJX/NBqEBNdNR7jMIlpQ==} + '@smithy/core@3.23.12': + resolution: {integrity: sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w==} engines: {node: '>=18.0.0'} '@smithy/credential-provider-imds@4.2.12': @@ -3800,16 +3794,16 @@ packages: resolution: {integrity: sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA==} engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.4.25': - resolution: {integrity: sha512-dqjLwZs2eBxIUG6Qtw8/YZ4DvzHGIf0DA18wrgtfP6a50UIO7e2nY0FPdcbv5tVJKqWCCU5BmGMOUwT7Puan+A==} + '@smithy/middleware-endpoint@4.4.27': + resolution: {integrity: sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.4.42': - resolution: {integrity: sha512-vbwyqHRIpIZutNXZpLAozakzamcINaRCpEy1MYmK6xBeW3xN+TyPRA123GjXnuxZIjc9848MRRCugVMTXxC4Eg==} + '@smithy/middleware-retry@4.4.44': + resolution: {integrity: sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA==} engines: {node: '>=18.0.0'} - '@smithy/middleware-serde@4.2.14': - resolution: {integrity: sha512-+CcaLoLa5apzSRtloOyG7lQvkUw2ZDml3hRh4QiG9WyEPfW5Ke/3tPOPiPjUneuT59Tpn8+c3RVaUvvkkwqZwg==} + '@smithy/middleware-serde@4.2.15': + resolution: {integrity: sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg==} engines: {node: '>=18.0.0'} '@smithy/middleware-stack@4.2.12': @@ -3820,8 +3814,8 @@ packages: resolution: {integrity: sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw==} engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.4.16': - resolution: {integrity: sha512-ULC8UCS/HivdCB3jhi+kLFYe4B5gxH2gi9vHBfEIiRrT2jfKiZNiETJSlzRtE6B26XbBHjPtc8iZKSNqMol9bw==} + '@smithy/node-http-handler@4.5.0': + resolution: {integrity: sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A==} engines: {node: '>=18.0.0'} '@smithy/property-provider@4.2.12': @@ -3852,8 +3846,8 @@ packages: resolution: {integrity: sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw==} engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.12.5': - resolution: {integrity: sha512-UqwYawyqSr/aog8mnLnfbPurS0gi4G7IYDcD28cUIBhsvWs1+rQcL2IwkUQ+QZ7dibaoRzhNF99fAQ9AUcO00w==} + '@smithy/smithy-client@4.12.7': + resolution: {integrity: sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ==} engines: {node: '>=18.0.0'} '@smithy/types@4.13.1': @@ -3888,12 +3882,12 @@ packages: resolution: {integrity: sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.3.41': - resolution: {integrity: sha512-M1w1Ux0rSVvBOxIIiqbxvZvhnjQ+VUjJrugtORE90BbadSTH+jsQL279KRL3Hv0w69rE7EuYkV/4Lepz/NBW9g==} + '@smithy/util-defaults-mode-browser@4.3.43': + resolution: {integrity: sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.2.44': - resolution: {integrity: sha512-YPze3/lD1KmWuZsl9JlfhcgGLX7AXhSoaCDtiPntUjNW5/YY0lOHjkcgxyE9x/h5vvS1fzDifMGjzqnNlNiqOQ==} + '@smithy/util-defaults-mode-node@4.2.47': + resolution: {integrity: sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ==} engines: {node: '>=18.0.0'} '@smithy/util-endpoints@3.3.3': @@ -3912,8 +3906,8 @@ packages: resolution: {integrity: sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ==} engines: {node: '>=18.0.0'} - '@smithy/util-stream@4.5.19': - resolution: {integrity: sha512-v4sa+3xTweL1CLO2UP0p7tvIMH/Rq1X4KKOxd568mpe6LSLMQCnDHs4uv7m3ukpl3HvcN2JH6jiCS0SNRXKP/w==} + '@smithy/util-stream@4.5.20': + resolution: {integrity: sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw==} engines: {node: '>=18.0.0'} '@smithy/util-uri-escape@4.2.2': @@ -3977,11 +3971,11 @@ packages: peerDependencies: storybook: ^8.6.18 - '@storybook/addon-links@10.2.17': - resolution: {integrity: sha512-KY2usxhPpt9AAzD22uBEfdPj1NZyCNyaYXgKkr8r/UeCNt7E7OdVBLNA1QMYZZ5dtIWj9EtY8c55OPuBM7aUkQ==} + '@storybook/addon-links@10.3.3': + resolution: {integrity: sha512-tazBHlB+YbU62bde5DWsq0lnxZjcAsPB3YRUpN2hSMfAySsudRingyWrgu5KeOxXhJvKJj0ohjQvGcMx/wgQUA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.17 + storybook: ^10.3.3 peerDependenciesMeta: react: optional: true @@ -4028,11 +4022,11 @@ packages: react-dom: optional: true - '@storybook/builder-vite@10.2.17': - resolution: {integrity: sha512-m/OBveTLm5ds/tUgHmmbKzgSi/oeCpQwm5rZa49vP2BpAd41Q7ER6TzkOoISzPoNNMAcbVmVc5vn7k6hdbPSHw==} + '@storybook/builder-vite@10.3.3': + resolution: {integrity: sha512-awspKCTZvXyeV3KabL0id62mFbxR5u/5yyGQultwCiSb2/yVgBfip2MAqLyS850pvTiB6QFVM9deOyd2/G/bEA==} peerDependencies: - storybook: ^10.2.17 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + storybook: ^10.3.3 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 '@storybook/components@8.6.18': resolution: {integrity: sha512-55yViiZzPS/cPBuOeW4QGxGqrusjXVyxuknmbYCIwDtFyyvI/CgbjXRHdxNBaIjz+IlftxvBmmSaOqFG5+/dkA==} @@ -4044,12 +4038,12 @@ packages: peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/csf-plugin@10.2.17': - resolution: {integrity: sha512-crHH8i/4mwzeXpWRPgwvwX2vjytW42zyzTRySUax5dTU8o9sjk4y+Z9hkGx3Nmu1TvqseS8v1Z20saZr/tQcWw==} + '@storybook/csf-plugin@10.3.3': + resolution: {integrity: sha512-Utlh7zubm+4iOzBBfzLW4F4vD99UBtl2Do4edlzK2F7krQIcFvR2ontjAE8S1FQVLZAC3WHalCOS+Ch8zf3knA==} peerDependencies: esbuild: '*' rollup: '*' - storybook: ^10.2.17 + storybook: ^10.3.3 vite: '*' webpack: '*' peerDependenciesMeta: @@ -4098,12 +4092,12 @@ packages: peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/react-dom-shim@10.2.17': - resolution: {integrity: sha512-x9Kb7eUSZ1zGsEw/TtWrvs1LwWIdNp8qoOQCgPEjdB07reSJcE8R3+ASWHJThmd4eZf66ZALPJyerejake4Osw==} + '@storybook/react-dom-shim@10.3.3': + resolution: {integrity: sha512-lkhuh4G3UTreU9M3Iz5Dt32c6U+l/4XuvqLtbe1sDHENZH6aPj7y0b5FwnfHyvuTvYRhtbo29xZrF5Bp9kCC0w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.17 + storybook: ^10.3.3 '@storybook/react-dom-shim@8.6.18': resolution: {integrity: sha512-N4xULcAWZQTUv4jy1/d346Tyb4gufuC3UaLCuU/iVSZ1brYF4OW3ANr+096btbMxY8pR/65lmtoqr5CTGwnBvA==} @@ -4112,20 +4106,20 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta storybook: ^8.6.18 - '@storybook/react-vite@10.2.17': - resolution: {integrity: sha512-E/1hNmxVsjy9l3TuaNufSqkdz8saTJUGEs8GRCjKlF7be2wljIwewUxjAT3efk+bxOCw76ZmqGHk6MnRa3y7Gw==} + '@storybook/react-vite@10.3.3': + resolution: {integrity: sha512-qHdlBe1hjqFAGXa8JL7bWTLbP/gDqXbWDm+SYCB646NHh5yvVDkZLwigP5Y+UL7M2ASfqFtosnroUK9tcCM2dw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.17 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + storybook: ^10.3.3 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/react@10.2.17': - resolution: {integrity: sha512-875AVMYil2X9Civil6GFZ8koIzlKxcXbl2eJ7+/GPbhIonTNmwx0qbWPHttjZXUvFuQ4RRtb9KkBwy4TCb/LeA==} + '@storybook/react@10.3.3': + resolution: {integrity: sha512-cGG5TbR8Tdx9zwlpsWyBEfWrejm5iWdYF26EwIhwuKq9GFUTAVrQzo0Rs7Tqc3ZyVhRS/YfsRiWSEH+zmq2JiQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.17 + storybook: ^10.3.3 typescript: '>= 4.9.x' peerDependenciesMeta: typescript: @@ -4151,16 +4145,16 @@ packages: peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/vue3-vite@10.2.17': - resolution: {integrity: sha512-lwQld8w2w+B2xu+rguRn6uSur4gd9BPw2ZXkc1eALnxb5ftDUM3Z9Pylrm58KohCS3JiNFh8KJsu2b+ZxZ319Q==} + '@storybook/vue3-vite@10.3.3': + resolution: {integrity: sha512-jVZIHutDBpYMx62CFDSPHUe5Y+uuabP5VBItrZbEPf8sqx4mcDXc6wsV0SYcYh7fw0q+5YVfYiGASkoVk3i/VA==} peerDependencies: - storybook: ^10.2.17 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + storybook: ^10.3.3 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/vue3@10.2.17': - resolution: {integrity: sha512-o0wTCgCmKA8/3naC4RbanW0WKl/F1bXs1QM9S6pAkqwg7CSfcRjkMXGMWq4Tb9q9B4UPoP61JQGdkkKPN5N+FA==} + '@storybook/vue3@10.3.3': + resolution: {integrity: sha512-crlsH9mjwKg9i/5mVAf/PEqjkHa2FeNoXqfAGzQVelElLZ71R18dEBGGkqGpaHU2ziVlvYKSBWALAU5zT9UZQQ==} peerDependencies: - storybook: ^10.2.17 + storybook: ^10.3.3 vue: ^3.0.0 '@stylistic/eslint-plugin@5.5.0': @@ -4186,14 +4180,14 @@ packages: cpu: [arm64] os: [android] - '@swc/core-darwin-arm64@1.15.18': - resolution: {integrity: sha512-+mIv7uBuSaywN3C9LNuWaX1jJJ3SKfiJuE6Lr3bd+/1Iv8oMU7oLBjYMluX1UrEPzwN2qCdY6Io0yVicABoCwQ==} + '@swc/core-darwin-arm64@1.15.21': + resolution: {integrity: sha512-SA8SFg9dp0qKRH8goWsax6bptFE2EdmPf2YRAQW9WoHGf3XKM1bX0nd5UdwxmC5hXsBUZAYf7xSciCler6/oyA==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.15.18': - resolution: {integrity: sha512-wZle0eaQhnzxWX5V/2kEOI6Z9vl/lTFEC6V4EWcn+5pDjhemCpQv9e/TDJ0GIoiClX8EDWRvuZwh+Z3dhL1NAg==} + '@swc/core-darwin-x64@1.15.21': + resolution: {integrity: sha512-//fOVntgowz9+V90lVsNCtyyrtbHp3jWH6Rch7MXHXbcvbLmbCTmssl5DeedUWLLGiAAW1wksBdqdGYOTjaNLw==} engines: {node: '>=10'} cpu: [x64] os: [darwin] @@ -4204,60 +4198,74 @@ packages: cpu: [x64] os: [freebsd] - '@swc/core-linux-arm-gnueabihf@1.15.18': - resolution: {integrity: sha512-ao61HGXVqrJFHAcPtF4/DegmwEkVCo4HApnotLU8ognfmU8x589z7+tcf3hU+qBiU1WOXV5fQX6W9Nzs6hjxDw==} + '@swc/core-linux-arm-gnueabihf@1.15.21': + resolution: {integrity: sha512-meNI4Sh6h9h8DvIfEc0l5URabYMSuNvyisLmG6vnoYAS43s8ON3NJR8sDHvdP7NJTrLe0q/x2XCn6yL/BeHcZg==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.15.18': - resolution: {integrity: sha512-3xnctOBLIq3kj8PxOCgPrGjBLP/kNOddr6f5gukYt/1IZxsITQaU9TDyjeX6jG+FiCIHjCuWuffsyQDL5Ew1bg==} + '@swc/core-linux-arm64-gnu@1.15.21': + resolution: {integrity: sha512-QrXlNQnHeXqU2EzLlnsPoWEh8/GtNJLvfMiPsDhk+ht6Xv8+vhvZ5YZ/BokNWSIZiWPKLAqR0M7T92YF5tmD3g==} engines: {node: '>=10'} cpu: [arm64] os: [linux] libc: [glibc] - '@swc/core-linux-arm64-musl@1.15.18': - resolution: {integrity: sha512-0a+Lix+FSSHBSBOA0XznCcHo5/1nA6oLLjcnocvzXeqtdjnPb+SvchItHI+lfeiuj1sClYPDvPMLSLyXFaiIKw==} + '@swc/core-linux-arm64-musl@1.15.21': + resolution: {integrity: sha512-8/yGCMO333ultDaMQivE5CjO6oXDPeeg1IV4sphojPkb0Pv0i6zvcRIkgp60xDB+UxLr6VgHgt+BBgqS959E9g==} engines: {node: '>=10'} cpu: [arm64] os: [linux] libc: [musl] - '@swc/core-linux-x64-gnu@1.15.18': - resolution: {integrity: sha512-wG9J8vReUlpaHz4KOD/5UE1AUgirimU4UFT9oZmupUDEofxJKYb1mTA/DrMj0s78bkBiNI+7Fo2EgPuvOJfuAA==} + '@swc/core-linux-ppc64-gnu@1.15.21': + resolution: {integrity: sha512-ucW0HzPx0s1dgRvcvuLSPSA/2Kk/VYTv9st8qe1Kc22Gu0Q0rH9+6TcBTmMuNIp0Xs4BPr1uBttmbO1wEGI49Q==} + engines: {node: '>=10'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-s390x-gnu@1.15.21': + resolution: {integrity: sha512-ulTnOGc5I7YRObE/9NreAhQg94QkiR5qNhhcUZ1iFAYjzg/JGAi1ch+s/Ixe61pMIr8bfVrF0NOaB0f8wjaAfA==} + engines: {node: '>=10'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-gnu@1.15.21': + resolution: {integrity: sha512-D0RokxtM+cPvSqJIKR6uja4hbD+scI9ezo95mBhfSyLUs9wnPPl26sLp1ZPR/EXRdYm3F3S6RUtVi+8QXhT24Q==} engines: {node: '>=10'} cpu: [x64] os: [linux] libc: [glibc] - '@swc/core-linux-x64-musl@1.15.18': - resolution: {integrity: sha512-4nwbVvCphKzicwNWRmvD5iBaZj8JYsRGa4xOxJmOyHlMDpsvvJ2OR2cODlvWyGFH6BYL1MfIAK3qph3hp0Az6g==} + '@swc/core-linux-x64-musl@1.15.21': + resolution: {integrity: sha512-nER8u7VeRfmU6fMDzl1NQAbbB/G7O2avmvCOwIul1uGkZ2/acbPH+DCL9h5+0yd/coNcxMBTL6NGepIew+7C2w==} engines: {node: '>=10'} cpu: [x64] os: [linux] libc: [musl] - '@swc/core-win32-arm64-msvc@1.15.18': - resolution: {integrity: sha512-zk0RYO+LjiBCat2RTMHzAWaMky0cra9loH4oRrLKLLNuL+jarxKLFDA8xTZWEkCPLjUTwlRN7d28eDLLMgtUcQ==} + '@swc/core-win32-arm64-msvc@1.15.21': + resolution: {integrity: sha512-+/AgNBnjYugUA8C0Do4YzymgvnGbztv7j8HKSQLvR/DQgZPoXQ2B3PqB2mTtGh/X5DhlJWiqnunN35JUgWcAeQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.15.18': - resolution: {integrity: sha512-yVuTrZ0RccD5+PEkpcLOBAuPbYBXS6rslENvIXfvJGXSdX5QGi1ehC4BjAMl5FkKLiam4kJECUI0l7Hq7T1vwg==} + '@swc/core-win32-ia32-msvc@1.15.21': + resolution: {integrity: sha512-IkSZj8PX/N4HcaFhMQtzmkV8YSnuNoJ0E6OvMwFiOfejPhiKXvl7CdDsn1f4/emYEIDO3fpgZW9DTaCRMDxaDA==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.15.18': - resolution: {integrity: sha512-7NRmE4hmUQNCbYU3Hn9Tz57mK9Qq4c97ZS+YlamlK6qG9Fb5g/BB3gPDe0iLlJkns/sYv2VWSkm8c3NmbEGjbg==} + '@swc/core-win32-x64-msvc@1.15.21': + resolution: {integrity: sha512-zUyWso7OOENB6e1N1hNuNn8vbvLsTdKQ5WKLgt/JcBNfJhKy/6jmBmqI3GXk/MyvQKd5SLvP7A0F36p7TeDqvw==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.15.18': - resolution: {integrity: sha512-z87aF9GphWp//fnkRsqvtY+inMVPgYW3zSlXH1kJFvRT5H/wiAn+G32qW5l3oEk63KSF1x3Ov0BfHCObAmT8RA==} + '@swc/core@1.15.21': + resolution: {integrity: sha512-fkk7NJcBscrR3/F8jiqlMptRHP650NxqDnspBMrRe5d8xOoCy9MLL5kOBLFXjFLfMo3KQQHhk+/jUULOMlR1uQ==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '>=0.5.17' @@ -4587,8 +4595,8 @@ packages: '@types/pg@8.15.6': resolution: {integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==} - '@types/pg@8.18.0': - resolution: {integrity: sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==} + '@types/pg@8.20.0': + resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} '@types/punycode@2.1.4': resolution: {integrity: sha512-trzh6NzBnq8yw5e35f8xe8VTYjqM3NE7bohBtvDVf/dtUer3zYTLK1Ka3DG3p7bdtoaOHZucma6FfVKlQ134pQ==} @@ -4716,63 +4724,63 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.57.0': - resolution: {integrity: sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==} + '@typescript-eslint/eslint-plugin@8.57.2': + resolution: {integrity: sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.57.0 + '@typescript-eslint/parser': ^8.57.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.57.0': - resolution: {integrity: sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==} + '@typescript-eslint/parser@8.57.2': + resolution: {integrity: sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.57.0': - resolution: {integrity: sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==} + '@typescript-eslint/project-service@8.57.2': + resolution: {integrity: sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.57.0': - resolution: {integrity: sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==} + '@typescript-eslint/scope-manager@8.57.2': + resolution: {integrity: sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.57.0': - resolution: {integrity: sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==} + '@typescript-eslint/tsconfig-utils@8.57.2': + resolution: {integrity: sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.57.0': - resolution: {integrity: sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==} + '@typescript-eslint/type-utils@8.57.2': + resolution: {integrity: sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.57.0': - resolution: {integrity: sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==} + '@typescript-eslint/types@8.57.2': + resolution: {integrity: sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.57.0': - resolution: {integrity: sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==} + '@typescript-eslint/typescript-estree@8.57.2': + resolution: {integrity: sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.57.0': - resolution: {integrity: sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==} + '@typescript-eslint/utils@8.57.2': + resolution: {integrity: sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.57.0': - resolution: {integrity: sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==} + '@typescript-eslint/visitor-keys@8.57.2': + resolution: {integrity: sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260116.1': @@ -4824,11 +4832,11 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vue: ^3.2.25 - '@vitest/coverage-v8@4.1.0': - resolution: {integrity: sha512-nDWulKeik2bL2Va/Wl4x7DLuTKAXa906iRFooIRPR+huHkcvp9QDkPQ2RJdmjOFrqOqvNfoSQLF68deE3xC3CQ==} + '@vitest/coverage-v8@4.1.1': + resolution: {integrity: sha512-nZ4RWwGCoGOQRMmU/Q9wlUY540RVRxJZ9lxFsFfy0QV7Zmo5VVBhB6Sl9Xa0KIp2iIs3zWfPlo9LcY1iqbpzCw==} peerDependencies: - '@vitest/browser': 4.1.0 - vitest: 4.1.0 + '@vitest/browser': 4.1.1 + vitest: 4.1.1 peerDependenciesMeta: '@vitest/browser': optional: true @@ -4839,14 +4847,14 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.1.0': - resolution: {integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==} + '@vitest/expect@4.1.1': + resolution: {integrity: sha512-xAV0fqBTk44Rn6SjJReEQkHP3RrqbJo6JQ4zZ7/uVOiJZRarBtblzrOfFIZeYUrukp2YD6snZG6IBqhOoHTm+A==} - '@vitest/mocker@4.1.0': - resolution: {integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==} + '@vitest/mocker@4.1.1': + resolution: {integrity: sha512-h3BOylsfsCLPeceuCPAAJ+BvNwSENgJa4hXoXu4im0bs9Lyp4URc4JYK4pWLZ4pG/UQn7AT92K6IByi6rE6g3A==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: optional: true @@ -4862,14 +4870,14 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.1.0': - resolution: {integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==} + '@vitest/pretty-format@4.1.1': + resolution: {integrity: sha512-GM+TEQN5WhOygr1lp7skeVjdLPqqWMHsfzXrcHAqZJi/lIVh63H0kaRCY8MDhNWikx19zBUK8ceaLB7X5AH9NQ==} - '@vitest/runner@4.1.0': - resolution: {integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==} + '@vitest/runner@4.1.1': + resolution: {integrity: sha512-f7+FPy75vN91QGWsITueq0gedwUZy1fLtHOCMeQpjs8jTekAHeKP80zfDEnhrleviLHzVSDXIWuCIOFn3D3f8A==} - '@vitest/snapshot@4.1.0': - resolution: {integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==} + '@vitest/snapshot@4.1.1': + resolution: {integrity: sha512-kMVSgcegWV2FibXEx9p9WIKgje58lcTbXgnJixfcg15iK8nzCXhmalL0ZLtTWLW9PH1+1NEDShiFFedB3tEgWg==} '@vitest/spy@2.0.5': resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} @@ -4877,8 +4885,8 @@ packages: '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/spy@4.1.0': - resolution: {integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==} + '@vitest/spy@4.1.1': + resolution: {integrity: sha512-6Ti/KT5OVaiupdIZEuZN7l3CZcR0cxnxt70Z0//3CtwgObwA6jZhmVBA3yrXSVN3gmwjgd7oDNLlsXz526gpRA==} '@vitest/utils@2.0.5': resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} @@ -4889,8 +4897,8 @@ packages: '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.1.0': - resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} + '@vitest/utils@4.1.1': + resolution: {integrity: sha512-cNxAlaB3sHoCdL6pj6yyUXv9Gry1NHNg0kFTXdvSIZXLHsqKH7chiWOkwJ5s5+d/oMwcoG9T0bKU38JZWKusrQ==} '@volar/language-core@2.4.15': resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} @@ -4933,8 +4941,8 @@ packages: typescript: optional: true - '@vue/language-core@3.2.5': - resolution: {integrity: sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==} + '@vue/language-core@3.2.6': + resolution: {integrity: sha512-xYYYX3/aVup576tP/23sEUpgiEnujrENaoNRbaozC1/MA9I6EGFQRJb4xrt/MmUCAGlxTKL2RmT8JLTPqagCkg==} '@vue/reactivity@3.5.30': resolution: {integrity: sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==} @@ -5664,8 +5672,8 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} - chromatic@15.2.0: - resolution: {integrity: sha512-c9tDfE62aiPVPnVab8jQLz+9c9II/CUFZ6T2Kk3hi2hSL+HLkRwX3zjwRYW1z9Shn57R/ORBEpQ3ftufp8EgWA==} + chromatic@15.3.1: + resolution: {integrity: sha512-2u4ow+Hf2xNusaTj9xkfp7pHMJ2pMnmOQxZPWyB+4SNEqjrMz813E6CJJzczBSlZzeY0waYq56uvpK/CkiUNvQ==} hasBin: true peerDependencies: '@chromatic-com/cypress': ^0.*.* || ^1.0.0 @@ -5976,8 +5984,8 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - cypress@15.11.0: - resolution: {integrity: sha512-NXDE6/fqZuzh1Zr53nyhCCa4lcANNTYWQNP9fJO+tzD3qVTDaTUni5xXMuigYjMujQ7CRiT9RkJJONmPQSsDFw==} + cypress@15.13.0: + resolution: {integrity: sha512-hJ9sY++TUC/HlUzHVJpIrDyqKMjlhx5PTXl/A7eA91JNEtUWkJAqefQR5mo9AtLra/9+m+JJaMg2U5Qd0a74Fw==} engines: {node: ^20.1.0 || ^22.0.0 || >=24.0.0} hasBin: true @@ -6640,11 +6648,11 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-builder@1.1.3: - resolution: {integrity: sha512-1o60KoFw2+LWKQu3IdcfcFlGTW4dpqEWmjhYec6H82AYZU2TVBXep6tMl8Z1Y+wM+ZrzCwe3BZ9Vyd9N2rIvmg==} + fast-xml-builder@1.1.4: + resolution: {integrity: sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==} - fast-xml-parser@5.4.1: - resolution: {integrity: sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==} + fast-xml-parser@5.5.8: + resolution: {integrity: sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==} hasBin: true fastify-plugin@5.1.0: @@ -6654,8 +6662,8 @@ packages: resolution: {integrity: sha512-2qfoaQ3BQDhZ1gtbkKZd6n0kKxJISJGM6u/skD9ljdWItAscjXrtZ1lnjr7PavmXX9j4EyCPmBDiIsLn07d5vA==} engines: {node: '>= 10'} - fastify@5.8.2: - resolution: {integrity: sha512-lZmt3navvZG915IE+f7/TIVamxIwmBd+OMB+O9WBzcpIwOo6F0LTh0sluoMFk5VkrKTvvrwIaoJPkir4Z+jtAg==} + fastify@5.8.4: + resolution: {integrity: sha512-sa42J1xylbBAYUWALSBoyXKPDUvM3OoNOibIefA+Oha57FryXKKCZarA1iDntOCWp3O35voZLuDg2mdODXtPzQ==} fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -6702,14 +6710,14 @@ packages: resolution: {integrity: sha512-BfHZtG/l9iMm4Ecianu7P8HRD2tBHLtjXinm4X62XBOYzi7CYA7jyqfJzOvXHqzVrVPYqBo2/GvbARMaaJkKVg==} engines: {node: '>=18'} - file-type@21.3.0: - resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} - engines: {node: '>=20'} - file-type@21.3.2: resolution: {integrity: sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==} engines: {node: '>=20'} + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} + engines: {node: '>=20'} + filename-reserved-regex@3.0.0: resolution: {integrity: sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6980,16 +6988,16 @@ packages: resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==} engines: {node: '>=0.8.0'} - happy-dom@20.8.4: - resolution: {integrity: sha512-GKhjq4OQCYB4VLFBzv8mmccUadwlAusOZOI7hC1D9xDIT5HhzkJK17c4el2f6R6C715P9xB4uiMxeKUa2nHMwQ==} + happy-dom@20.8.8: + resolution: {integrity: sha512-5/F8wxkNxYtsN0bXfMwIyNLZ9WYsoOYPbmoluqVJqv8KBUbcyKZawJ7uYK4WTX8IHBLYv+VXIwfeNDPy1oKMwQ==} engines: {node: '>=20.0.0'} hard-rejection@2.1.0: resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} - harfbuzzjs@0.10.0: - resolution: {integrity: sha512-SN8LVwCOzvTq3OPNd0+EAghgXugItz56wst567D1vs7LnnKGWprhi3EG58aVOBwhN8HEbQxL4I9NDWkcXUutRw==} + harfbuzzjs@0.10.1: + resolution: {integrity: sha512-Snspnku2xVnKvoXkdLeOgDWFmsjv8bhCkiA5o+c12I5NGO+aXsLNYmIjaEfIU//SSzoZ63xaOAb3A7eT/Ju+Sw==} has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} @@ -7076,9 +7084,6 @@ packages: htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} - htmlparser2@9.1.0: resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} @@ -7184,6 +7189,10 @@ packages: import-in-the-middle@2.0.6: resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==} + import-in-the-middle@3.0.0: + resolution: {integrity: sha512-OnGy+eYT7wVejH2XWgLRgbmzujhhVIATQH0ztIeRilwHBjTeG3pD+XnH3PKX0r9gJ0BuJmJ68q/oh9qgXnNDQg==} + engines: {node: '>=18'} + import-lazy@4.0.0: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} engines: {node: '>=8'} @@ -7237,8 +7246,8 @@ packages: resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==} deprecated: The Intersection Observer polyfill is no longer needed and can safely be removed. Intersection Observer has been Baseline since 2019. - ioredis@5.10.0: - resolution: {integrity: sha512-HVBe9OFuqs+Z6n64q09PQvP1/R4Bm+30PAyyD4wIEqssh3v9L21QjCVk4kRLucMBcDokJTcLjsGeVRlq/nH6DA==} + ioredis@5.10.1: + resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} ioredis@5.9.3: @@ -8030,11 +8039,11 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} - mediabunny@1.39.2: - resolution: {integrity: sha512-VcrisGRt+OI7tTPrziucJoCIPYIS/DEWY37TqzQVLWSUUHiyvsiRizEypQ3FOlhfIZ4ytAG/Mw4zxfetCTyKUg==} + mediabunny@1.40.1: + resolution: {integrity: sha512-HU/stGzAkdWaJIly6ypbUVgAUvT9kt39DIg0IaErR7/1fwtTmgUYs4i8uEPYcgcjPjbB9gtBmUXOLnXi6J2LDw==} - meilisearch@0.55.0: - resolution: {integrity: sha512-qSMeiezfDgIqciIeYzh5E4pXDZZD7CtHeWDCs43kN3trLgl5FtfmBAIkljL3huFaOx08feYtC8FfIFUpVwq6rg==} + meilisearch@0.56.0: + resolution: {integrity: sha512-kBXba8DcSrLWHYqopCm2JL90oBy97VdIfHkP1ii7/eHufeEEEk9Zu5Vv/IFQpNzmhEpWszVFVlGvZoI6QJeGzA==} memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} @@ -8313,8 +8322,8 @@ packages: peerDependencies: msw: ^2.0.0 - msw@2.12.10: - resolution: {integrity: sha512-G3VUymSE0/iegFnuipujpwyTM2GuZAKXNeerUSrG2+Eg391wW63xFs5ixWsK9MWzr1AGoSkYGmyAzNgbR3+urw==} + msw@2.12.14: + resolution: {integrity: sha512-4KXa4nVBIBjbDbd7vfQNuQ25eFxug0aropCQFoI0JdOBuJWamkT1yLVIWReFI8SiTRc+H1hKzaNk+cLk2N9rtQ==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -8346,8 +8355,8 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@5.1.6: - resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} + nanoid@5.1.7: + resolution: {integrity: sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==} engines: {node: ^18 || >=20} hasBin: true @@ -8440,8 +8449,8 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - nodemailer@8.0.2: - resolution: {integrity: sha512-zbj002pZAIkWQFxyAaqoxvn+zoIwRnS40hgjqTXudKOOJkiFFgBeNqjgD3/YCR12sZnrghWYBY+yP1ZucdDRpw==} + nodemailer@8.0.3: + resolution: {integrity: sha512-JQNBqvK+bj3NMhUFR3wmCl3SYcOeMotDiwDBvIoCuQdF0PvlIY0BH+FJ2CG7u4cXKPChplE78oowlH/Otsc4ZQ==} engines: {node: '>=6.0.0'} nodemon@3.1.14: @@ -8499,8 +8508,8 @@ packages: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} deprecated: This package is no longer supported. - nsfwjs@4.2.0: - resolution: {integrity: sha512-8eMmV+Hfr3hqSX7PzDJx94kFSP4QiN4/G9+b92I3catgQuqOb9Qmns1nDyVI0jMcWc1sVWdqBIA6eYLvKkryxA==} + nsfwjs@4.3.0: + resolution: {integrity: sha512-WTKDte0vp1X97N1h34P79G/hG+sVT3+TnDz9di1WseIJR93v11E4viNX7Vg9WsO6HYoR772Nzq2iM8jo3XBZ+g==} peerDependencies: '@tensorflow/tfjs': ^4.0.0 buffer: ^6.0.3 @@ -8705,8 +8714,8 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-expression-matcher@1.1.3: - resolution: {integrity: sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ==} + path-expression-matcher@1.2.0: + resolution: {integrity: sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==} engines: {node: '>=14.0.0'} path-is-absolute@1.0.1: @@ -8810,8 +8819,8 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - pid-port@2.0.1: - resolution: {integrity: sha512-pnLo01AmMclw8l+/gfknsP2N351oe8VkVmCLFUvJZ11NRPPmghJrv0OcwsdgPQxsZkFYwm6hPWW0JKmXYCaXAw==} + pid-port@2.1.0: + resolution: {integrity: sha512-KPyrFEIMFmcfYwsQ+hX6AHtu40sqTm6cgJdtt3ppYnEiqXaAdnUB+TPeW80wIsxd3jkURuXztgVp5dR5sZzz2w==} engines: {node: '>=20'} pify@2.3.0: @@ -8859,8 +8868,8 @@ packages: resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} engines: {node: '>=10.13.0'} - pnpm@10.32.1: - resolution: {integrity: sha512-pwaTjw6JrBRWtlY+q07fHR+vM2jRGR/FxZeQ6W3JGORFarLmfWE94QQ9LoyB+HMD5rQNT/7KnfFe8a1Wc0jyvg==} + pnpm@10.33.0: + resolution: {integrity: sha512-EFaLtKavtYyes2MNqQzJUWQXq+vT+rvmc58K55VyjaFJHp21pUTHatjrdXD1xLs9bGN7LLQb/c20f6gjyGSTGQ==} engines: {node: '>=18.12'} hasBin: true @@ -9481,8 +9490,8 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rollup@4.59.0: - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} + rollup@4.60.0: + resolution: {integrity: sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -9531,8 +9540,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sanitize-html@2.17.1: - resolution: {integrity: sha512-ehFCW+q1a4CSOWRAdX97BX/6/PDEkCqw7/0JXZAGQV57FQB3YOkTa/rrzHPeJ+Aghy4vZAFfWMYyfxIiB7F/gw==} + sanitize-html@2.17.2: + resolution: {integrity: sha512-EnffJUl46VE9uvZ0XeWzObHLurClLlT12gsOk1cHyP2Ol1P0BnBnsXmShlBmWVJM+dKieQI68R0tsPY5m/B+Jg==} sass@1.98.0: resolution: {integrity: sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==} @@ -9922,8 +9931,8 @@ packages: react-dom: optional: true - storybook@10.2.17: - resolution: {integrity: sha512-yueTpl5YJqLzQqs3CanxNdAAfFU23iP0j+JVJURE4ghfEtRmWfWoZWLGkVcyjmgum7UmjwAlqRuOjQDNvH89kw==} + storybook@10.3.3: + resolution: {integrity: sha512-tMoRAts9EVqf+mEMPLC6z1DPyHbcPe+CV1MhLN55IKsl0HxNjvVGK44rVPSePbltPE6vIsn4bdRj6CCUt8SJwQ==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -10040,8 +10049,8 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strnum@2.1.2: - resolution: {integrity: sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==} + strnum@2.2.2: + resolution: {integrity: sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==} strtok3@10.3.4: resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} @@ -10093,8 +10102,8 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - systeminformation@5.31.4: - resolution: {integrity: sha512-lZppDyQx91VdS5zJvAyGkmwe+Mq6xY978BDUG2wRkWE+jkmUF5ti8cvOovFQoN5bvSFKCXVkyKEaU5ec3SJiRg==} + systeminformation@5.31.5: + resolution: {integrity: sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ==} engines: {node: '>=8.0.0'} os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true @@ -10111,16 +10120,16 @@ packages: engines: {node: '>=10'} deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - tar@7.5.11: - resolution: {integrity: sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==} + tar@7.5.13: + resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} engines: {node: '>=18'} taskkill@5.0.0: resolution: {integrity: sha512-+HRtZ40Vc+6YfCDWCeAsixwxJgMbPY4HHuTgzPYH3JXvqHWUlsCfy+ylXlAKhFNcuLp4xVeWeFBUhDk+7KYUvQ==} engines: {node: '>=14.16'} - terser@5.46.0: - resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} + terser@5.46.1: + resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} engines: {node: '>=10'} hasBin: true @@ -10624,8 +10633,8 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite-plugin-glsl@1.5.5: - resolution: {integrity: sha512-6NM2P4JkM+1hNSqMhM4eagX03bmhEoTyrOrk68y3Q6KXfdF73QIuCb6BmRZvwLPgXTCOBM3Zc8gL1WxctYnrUQ==} + vite-plugin-glsl@1.5.6: + resolution: {integrity: sha512-h3RfTiaI4cC8hICFZk5TBAAxmIuM0b/qkdrjYpqPtaL8bcxNEoEFXXdlISPGmDQ09eP0aJC8V2/BgTmPXspC8w==} engines: {node: '>= 20.17.0', npm: '>= 10.8.3'} peerDependencies: '@rollup/pluginutils': ^5.x @@ -10691,21 +10700,21 @@ packages: peerDependencies: vitest: '>=3' - vitest@4.1.0: - resolution: {integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==} + vitest@4.1.1: + resolution: {integrity: sha512-yF+o4POL41rpAzj5KVILUxm1GCjKnELvaqmU9TLLUbMfDzuN0UpUR9uaDs+mCtjPe+uYPksXDRLQGGPvj1cTmA==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.0 - '@vitest/browser-preview': 4.1.0 - '@vitest/browser-webdriverio': 4.1.0 - '@vitest/ui': 4.1.0 + '@vitest/browser-playwright': 4.1.1 + '@vitest/browser-preview': 4.1.1 + '@vitest/browser-webdriverio': 4.1.1 + '@vitest/ui': 4.1.1 happy-dom: '*' jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -10758,8 +10767,8 @@ packages: vue-component-type-helpers@2.2.12: resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} - vue-component-type-helpers@3.2.5: - resolution: {integrity: sha512-tkvNr+bU8+xD/onAThIe7CHFvOJ/BO6XCOrxMzeytJq40nTfpGDJuVjyCM8ccGZKfAbGk2YfuZyDMXM56qheZQ==} + vue-component-type-helpers@3.2.6: + resolution: {integrity: sha512-O02tnvIfOQVmnvoWwuSydwRoHjZVt8UEBR+2p4rT35p8GAy5VTlWP8o5qXfJR/GWCN0nVZoYWsVUvx2jwgdBmQ==} vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} @@ -10788,8 +10797,8 @@ packages: peerDependencies: vue: '>=2' - vue-tsc@3.2.5: - resolution: {integrity: sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA==} + vue-tsc@3.2.6: + resolution: {integrity: sha512-gYW/kWI0XrwGzd0PKc7tVB/qpdeAkIZLNZb10/InizkQjHjnT8weZ/vBarZoj4kHKbUTZT/bAVgoOr8x4NsQ/Q==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -10941,8 +10950,8 @@ packages: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -11137,20 +11146,20 @@ snapshots: '@aws-crypto/crc32@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 tslib: 2.8.1 '@aws-crypto/crc32c@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 tslib: 2.8.1 '@aws-crypto/sha1-browser@5.2.0': dependencies: '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@aws-sdk/util-locate-window': 3.893.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -11160,7 +11169,7 @@ snapshots: '@aws-crypto/sha256-js': 5.2.0 '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@aws-sdk/util-locate-window': 3.893.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -11168,7 +11177,7 @@ snapshots: '@aws-crypto/sha256-js@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 tslib: 2.8.1 '@aws-crypto/supports-web-crypto@5.2.0': @@ -11177,35 +11186,35 @@ snapshots: '@aws-crypto/util@5.2.0': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.1008.0': + '@aws-sdk/client-s3@3.1016.0': dependencies: '@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.19 - '@aws-sdk/credential-provider-node': 3.972.20 - '@aws-sdk/middleware-bucket-endpoint': 3.972.7 - '@aws-sdk/middleware-expect-continue': 3.972.7 - '@aws-sdk/middleware-flexible-checksums': 3.973.5 - '@aws-sdk/middleware-host-header': 3.972.7 - '@aws-sdk/middleware-location-constraint': 3.972.7 - '@aws-sdk/middleware-logger': 3.972.7 - '@aws-sdk/middleware-recursion-detection': 3.972.7 - '@aws-sdk/middleware-sdk-s3': 3.972.19 - '@aws-sdk/middleware-ssec': 3.972.7 - '@aws-sdk/middleware-user-agent': 3.972.20 - '@aws-sdk/region-config-resolver': 3.972.7 - '@aws-sdk/signature-v4-multi-region': 3.996.7 - '@aws-sdk/types': 3.973.5 - '@aws-sdk/util-endpoints': 3.996.4 - '@aws-sdk/util-user-agent-browser': 3.972.7 - '@aws-sdk/util-user-agent-node': 3.973.6 - '@smithy/config-resolver': 4.4.11 - '@smithy/core': 3.23.11 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/credential-provider-node': 3.972.25 + '@aws-sdk/middleware-bucket-endpoint': 3.972.8 + '@aws-sdk/middleware-expect-continue': 3.972.8 + '@aws-sdk/middleware-flexible-checksums': 3.974.4 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-location-constraint': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.8 + '@aws-sdk/middleware-sdk-s3': 3.972.24 + '@aws-sdk/middleware-ssec': 3.972.8 + '@aws-sdk/middleware-user-agent': 3.972.25 + '@aws-sdk/region-config-resolver': 3.972.9 + '@aws-sdk/signature-v4-multi-region': 3.996.12 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.11 + '@smithy/config-resolver': 4.4.13 + '@smithy/core': 3.23.12 '@smithy/eventstream-serde-browser': 4.2.12 '@smithy/eventstream-serde-config-resolver': 4.3.12 '@smithy/eventstream-serde-node': 4.2.12 @@ -11216,84 +11225,84 @@ snapshots: '@smithy/invalid-dependency': 4.2.12 '@smithy/md5-js': 4.2.12 '@smithy/middleware-content-length': 4.2.12 - '@smithy/middleware-endpoint': 4.4.25 - '@smithy/middleware-retry': 4.4.42 - '@smithy/middleware-serde': 4.2.14 + '@smithy/middleware-endpoint': 4.4.27 + '@smithy/middleware-retry': 4.4.44 + '@smithy/middleware-serde': 4.2.15 '@smithy/middleware-stack': 4.2.12 '@smithy/node-config-provider': 4.3.12 - '@smithy/node-http-handler': 4.4.16 + '@smithy/node-http-handler': 4.5.0 '@smithy/protocol-http': 5.3.12 - '@smithy/smithy-client': 4.12.5 + '@smithy/smithy-client': 4.12.7 '@smithy/types': 4.13.1 '@smithy/url-parser': 4.2.12 '@smithy/util-base64': 4.3.2 '@smithy/util-body-length-browser': 4.2.2 '@smithy/util-body-length-node': 4.2.3 - '@smithy/util-defaults-mode-browser': 4.3.41 - '@smithy/util-defaults-mode-node': 4.2.44 + '@smithy/util-defaults-mode-browser': 4.3.43 + '@smithy/util-defaults-mode-node': 4.2.47 '@smithy/util-endpoints': 3.3.3 '@smithy/util-middleware': 4.2.12 '@smithy/util-retry': 4.2.12 - '@smithy/util-stream': 4.5.19 + '@smithy/util-stream': 4.5.20 '@smithy/util-utf8': 4.2.2 '@smithy/util-waiter': 4.2.13 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.973.19': + '@aws-sdk/core@3.973.24': dependencies: - '@aws-sdk/types': 3.973.5 - '@aws-sdk/xml-builder': 3.972.10 - '@smithy/core': 3.23.11 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/xml-builder': 3.972.15 + '@smithy/core': 3.23.12 '@smithy/node-config-provider': 4.3.12 '@smithy/property-provider': 4.2.12 '@smithy/protocol-http': 5.3.12 '@smithy/signature-v4': 5.3.12 - '@smithy/smithy-client': 4.12.5 + '@smithy/smithy-client': 4.12.7 '@smithy/types': 4.13.1 '@smithy/util-base64': 4.3.2 '@smithy/util-middleware': 4.2.12 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@aws-sdk/crc64-nvme@3.972.4': + '@aws-sdk/crc64-nvme@3.972.5': dependencies: '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.972.17': + '@aws-sdk/credential-provider-env@3.972.22': dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/types': 3.973.6 '@smithy/property-provider': 4.2.12 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.972.19': + '@aws-sdk/credential-provider-http@3.972.24': dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/types': 3.973.6 '@smithy/fetch-http-handler': 5.3.15 - '@smithy/node-http-handler': 4.4.16 + '@smithy/node-http-handler': 4.5.0 '@smithy/property-provider': 4.2.12 '@smithy/protocol-http': 5.3.12 - '@smithy/smithy-client': 4.12.5 + '@smithy/smithy-client': 4.12.7 '@smithy/types': 4.13.1 - '@smithy/util-stream': 4.5.19 + '@smithy/util-stream': 4.5.20 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.972.19': - dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/credential-provider-env': 3.972.17 - '@aws-sdk/credential-provider-http': 3.972.19 - '@aws-sdk/credential-provider-login': 3.972.19 - '@aws-sdk/credential-provider-process': 3.972.17 - '@aws-sdk/credential-provider-sso': 3.972.19 - '@aws-sdk/credential-provider-web-identity': 3.972.19 - '@aws-sdk/nested-clients': 3.996.9 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/credential-provider-ini@3.972.24': + dependencies: + '@aws-sdk/core': 3.973.24 + '@aws-sdk/credential-provider-env': 3.972.22 + '@aws-sdk/credential-provider-http': 3.972.24 + '@aws-sdk/credential-provider-login': 3.972.24 + '@aws-sdk/credential-provider-process': 3.972.22 + '@aws-sdk/credential-provider-sso': 3.972.24 + '@aws-sdk/credential-provider-web-identity': 3.972.24 + '@aws-sdk/nested-clients': 3.996.14 + '@aws-sdk/types': 3.973.6 '@smithy/credential-provider-imds': 4.2.12 '@smithy/property-provider': 4.2.12 '@smithy/shared-ini-file-loader': 4.4.7 @@ -11302,11 +11311,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-login@3.972.19': + '@aws-sdk/credential-provider-login@3.972.24': dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/nested-clients': 3.996.9 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/nested-clients': 3.996.14 + '@aws-sdk/types': 3.973.6 '@smithy/property-provider': 4.2.12 '@smithy/protocol-http': 5.3.12 '@smithy/shared-ini-file-loader': 4.4.7 @@ -11315,15 +11324,15 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.972.20': + '@aws-sdk/credential-provider-node@3.972.25': dependencies: - '@aws-sdk/credential-provider-env': 3.972.17 - '@aws-sdk/credential-provider-http': 3.972.19 - '@aws-sdk/credential-provider-ini': 3.972.19 - '@aws-sdk/credential-provider-process': 3.972.17 - '@aws-sdk/credential-provider-sso': 3.972.19 - '@aws-sdk/credential-provider-web-identity': 3.972.19 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/credential-provider-env': 3.972.22 + '@aws-sdk/credential-provider-http': 3.972.24 + '@aws-sdk/credential-provider-ini': 3.972.24 + '@aws-sdk/credential-provider-process': 3.972.22 + '@aws-sdk/credential-provider-sso': 3.972.24 + '@aws-sdk/credential-provider-web-identity': 3.972.24 + '@aws-sdk/types': 3.973.6 '@smithy/credential-provider-imds': 4.2.12 '@smithy/property-provider': 4.2.12 '@smithy/shared-ini-file-loader': 4.4.7 @@ -11332,21 +11341,21 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-process@3.972.17': + '@aws-sdk/credential-provider-process@3.972.22': dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/types': 3.973.6 '@smithy/property-provider': 4.2.12 '@smithy/shared-ini-file-loader': 4.4.7 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.972.19': + '@aws-sdk/credential-provider-sso@3.972.24': dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/nested-clients': 3.996.9 - '@aws-sdk/token-providers': 3.1008.0 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/nested-clients': 3.996.14 + '@aws-sdk/token-providers': 3.1015.0 + '@aws-sdk/types': 3.973.6 '@smithy/property-provider': 4.2.12 '@smithy/shared-ini-file-loader': 4.4.7 '@smithy/types': 4.13.1 @@ -11354,11 +11363,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.972.19': + '@aws-sdk/credential-provider-web-identity@3.972.24': dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/nested-clients': 3.996.9 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/nested-clients': 3.996.14 + '@aws-sdk/types': 3.973.6 '@smithy/property-provider': 4.2.12 '@smithy/shared-ini-file-loader': 4.4.7 '@smithy/types': 4.13.1 @@ -11366,20 +11375,20 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/lib-storage@3.1008.0(@aws-sdk/client-s3@3.1008.0)': + '@aws-sdk/lib-storage@3.1016.0(@aws-sdk/client-s3@3.1016.0)': dependencies: - '@aws-sdk/client-s3': 3.1008.0 + '@aws-sdk/client-s3': 3.1016.0 '@smithy/abort-controller': 4.2.12 - '@smithy/middleware-endpoint': 4.4.25 - '@smithy/smithy-client': 4.12.5 + '@smithy/middleware-endpoint': 4.4.27 + '@smithy/smithy-client': 4.12.7 buffer: 5.6.0 events: 3.3.0 stream-browserify: 3.0.0 tslib: 2.8.1 - '@aws-sdk/middleware-bucket-endpoint@3.972.7': + '@aws-sdk/middleware-bucket-endpoint@3.972.8': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@aws-sdk/util-arn-parser': 3.972.3 '@smithy/node-config-provider': 4.3.12 '@smithy/protocol-http': 5.3.12 @@ -11387,126 +11396,126 @@ snapshots: '@smithy/util-config-provider': 4.2.2 tslib: 2.8.1 - '@aws-sdk/middleware-expect-continue@3.972.7': + '@aws-sdk/middleware-expect-continue@3.972.8': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@smithy/protocol-http': 5.3.12 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/middleware-flexible-checksums@3.973.5': + '@aws-sdk/middleware-flexible-checksums@3.974.4': dependencies: '@aws-crypto/crc32': 5.2.0 '@aws-crypto/crc32c': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.973.19 - '@aws-sdk/crc64-nvme': 3.972.4 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/crc64-nvme': 3.972.5 + '@aws-sdk/types': 3.973.6 '@smithy/is-array-buffer': 4.2.2 '@smithy/node-config-provider': 4.3.12 '@smithy/protocol-http': 5.3.12 '@smithy/types': 4.13.1 '@smithy/util-middleware': 4.2.12 - '@smithy/util-stream': 4.5.19 + '@smithy/util-stream': 4.5.20 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.972.7': + '@aws-sdk/middleware-host-header@3.972.8': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@smithy/protocol-http': 5.3.12 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/middleware-location-constraint@3.972.7': + '@aws-sdk/middleware-location-constraint@3.972.8': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.972.7': + '@aws-sdk/middleware-logger@3.972.8': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.972.7': + '@aws-sdk/middleware-recursion-detection@3.972.8': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@aws/lambda-invoke-store': 0.2.2 '@smithy/protocol-http': 5.3.12 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.972.19': + '@aws-sdk/middleware-sdk-s3@3.972.24': dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/types': 3.973.6 '@aws-sdk/util-arn-parser': 3.972.3 - '@smithy/core': 3.23.11 + '@smithy/core': 3.23.12 '@smithy/node-config-provider': 4.3.12 '@smithy/protocol-http': 5.3.12 '@smithy/signature-v4': 5.3.12 - '@smithy/smithy-client': 4.12.5 + '@smithy/smithy-client': 4.12.7 '@smithy/types': 4.13.1 '@smithy/util-config-provider': 4.2.2 '@smithy/util-middleware': 4.2.12 - '@smithy/util-stream': 4.5.19 + '@smithy/util-stream': 4.5.20 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@aws-sdk/middleware-ssec@3.972.7': + '@aws-sdk/middleware-ssec@3.972.8': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.972.20': + '@aws-sdk/middleware-user-agent@3.972.25': dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/types': 3.973.5 - '@aws-sdk/util-endpoints': 3.996.4 - '@smithy/core': 3.23.11 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@smithy/core': 3.23.12 '@smithy/protocol-http': 5.3.12 '@smithy/types': 4.13.1 '@smithy/util-retry': 4.2.12 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.996.9': + '@aws-sdk/nested-clients@3.996.14': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.19 - '@aws-sdk/middleware-host-header': 3.972.7 - '@aws-sdk/middleware-logger': 3.972.7 - '@aws-sdk/middleware-recursion-detection': 3.972.7 - '@aws-sdk/middleware-user-agent': 3.972.20 - '@aws-sdk/region-config-resolver': 3.972.7 - '@aws-sdk/types': 3.973.5 - '@aws-sdk/util-endpoints': 3.996.4 - '@aws-sdk/util-user-agent-browser': 3.972.7 - '@aws-sdk/util-user-agent-node': 3.973.6 - '@smithy/config-resolver': 4.4.11 - '@smithy/core': 3.23.11 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.8 + '@aws-sdk/middleware-user-agent': 3.972.25 + '@aws-sdk/region-config-resolver': 3.972.9 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.11 + '@smithy/config-resolver': 4.4.13 + '@smithy/core': 3.23.12 '@smithy/fetch-http-handler': 5.3.15 '@smithy/hash-node': 4.2.12 '@smithy/invalid-dependency': 4.2.12 '@smithy/middleware-content-length': 4.2.12 - '@smithy/middleware-endpoint': 4.4.25 - '@smithy/middleware-retry': 4.4.42 - '@smithy/middleware-serde': 4.2.14 + '@smithy/middleware-endpoint': 4.4.27 + '@smithy/middleware-retry': 4.4.44 + '@smithy/middleware-serde': 4.2.15 '@smithy/middleware-stack': 4.2.12 '@smithy/node-config-provider': 4.3.12 - '@smithy/node-http-handler': 4.4.16 + '@smithy/node-http-handler': 4.5.0 '@smithy/protocol-http': 5.3.12 - '@smithy/smithy-client': 4.12.5 + '@smithy/smithy-client': 4.12.7 '@smithy/types': 4.13.1 '@smithy/url-parser': 4.2.12 '@smithy/util-base64': 4.3.2 '@smithy/util-body-length-browser': 4.2.2 '@smithy/util-body-length-node': 4.2.3 - '@smithy/util-defaults-mode-browser': 4.3.41 - '@smithy/util-defaults-mode-node': 4.2.44 + '@smithy/util-defaults-mode-browser': 4.3.43 + '@smithy/util-defaults-mode-node': 4.2.47 '@smithy/util-endpoints': 3.3.3 '@smithy/util-middleware': 4.2.12 '@smithy/util-retry': 4.2.12 @@ -11515,28 +11524,28 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/region-config-resolver@3.972.7': + '@aws-sdk/region-config-resolver@3.972.9': dependencies: - '@aws-sdk/types': 3.973.5 - '@smithy/config-resolver': 4.4.11 + '@aws-sdk/types': 3.973.6 + '@smithy/config-resolver': 4.4.13 '@smithy/node-config-provider': 4.3.12 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.996.7': + '@aws-sdk/signature-v4-multi-region@3.996.12': dependencies: - '@aws-sdk/middleware-sdk-s3': 3.972.19 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/middleware-sdk-s3': 3.972.24 + '@aws-sdk/types': 3.973.6 '@smithy/protocol-http': 5.3.12 '@smithy/signature-v4': 5.3.12 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@aws-sdk/token-providers@3.1008.0': + '@aws-sdk/token-providers@3.1015.0': dependencies: - '@aws-sdk/core': 3.973.19 - '@aws-sdk/nested-clients': 3.996.9 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/core': 3.973.24 + '@aws-sdk/nested-clients': 3.996.14 + '@aws-sdk/types': 3.973.6 '@smithy/property-provider': 4.2.12 '@smithy/shared-ini-file-loader': 4.4.7 '@smithy/types': 4.13.1 @@ -11544,7 +11553,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/types@3.973.5': + '@aws-sdk/types@3.973.6': dependencies: '@smithy/types': 4.13.1 tslib: 2.8.1 @@ -11553,9 +11562,9 @@ snapshots: dependencies: tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.996.4': + '@aws-sdk/util-endpoints@3.996.5': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@smithy/types': 4.13.1 '@smithy/url-parser': 4.2.12 '@smithy/util-endpoints': 3.3.3 @@ -11565,26 +11574,26 @@ snapshots: dependencies: tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.972.7': + '@aws-sdk/util-user-agent-browser@3.972.8': dependencies: - '@aws-sdk/types': 3.973.5 + '@aws-sdk/types': 3.973.6 '@smithy/types': 4.13.1 bowser: 2.12.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.973.6': + '@aws-sdk/util-user-agent-node@3.973.11': dependencies: - '@aws-sdk/middleware-user-agent': 3.972.20 - '@aws-sdk/types': 3.973.5 + '@aws-sdk/middleware-user-agent': 3.972.25 + '@aws-sdk/types': 3.973.6 '@smithy/node-config-provider': 4.3.12 '@smithy/types': 4.13.1 '@smithy/util-config-provider': 4.2.2 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.972.10': + '@aws-sdk/xml-builder@3.972.15': dependencies: '@smithy/types': 4.13.1 - fast-xml-parser: 5.4.1 + fast-xml-parser: 5.5.8 tslib: 2.8.1 '@aws/lambda-invoke-store@0.2.2': {} @@ -12100,12 +12109,12 @@ snapshots: '@fastify/forwarded@3.0.1': {} - '@fastify/http-proxy@11.4.1(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + '@fastify/http-proxy@11.4.2(bufferutil@4.1.0)(utf-8-validate@6.0.6)': dependencies: '@fastify/reply-from': 12.5.0 fast-querystring: 1.1.2 fastify-plugin: 5.1.0 - ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -12122,12 +12131,12 @@ snapshots: fastify-plugin: 5.1.0 secure-json-parse: 4.1.0 - '@fastify/otel@0.16.0(@opentelemetry/api@1.9.0)': + '@fastify/otel@0.17.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.212.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 minimatch: 10.2.4 transitivePeerDependencies: - supports-color @@ -12537,11 +12546,11 @@ snapshots: '@types/yargs': 17.0.34 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: glob: 13.0.1 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: typescript: 5.9.3 @@ -12653,14 +12662,14 @@ snapshots: '@misskey-dev/browser-image-resizer@2024.1.0': {} - '@misskey-dev/eslint-plugin@2.1.0(@eslint/compat@1.4.0(eslint@9.39.4))(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4))(eslint@9.39.4)(globals@17.4.0)': + '@misskey-dev/eslint-plugin@2.1.0(@eslint/compat@1.4.0(eslint@9.39.4))(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4))(eslint@9.39.4)(globals@17.4.0)': dependencies: '@eslint/compat': 1.4.0(eslint@9.39.4) '@stylistic/eslint-plugin': 5.5.0(eslint@9.39.4) - '@typescript-eslint/eslint-plugin': 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.2(eslint@9.39.4)(typescript@5.9.3) eslint: 9.39.4 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) globals: 17.4.0 '@misskey-dev/sharp-read-bmp@1.2.0': @@ -12706,52 +12715,52 @@ snapshots: outvariant: 1.4.3 strict-event-emitter: 0.5.1 - '@napi-rs/canvas-android-arm64@0.1.96': + '@napi-rs/canvas-android-arm64@0.1.97': optional: true - '@napi-rs/canvas-darwin-arm64@0.1.96': + '@napi-rs/canvas-darwin-arm64@0.1.97': optional: true - '@napi-rs/canvas-darwin-x64@0.1.96': + '@napi-rs/canvas-darwin-x64@0.1.97': optional: true - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.96': + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.97': optional: true - '@napi-rs/canvas-linux-arm64-gnu@0.1.96': + '@napi-rs/canvas-linux-arm64-gnu@0.1.97': optional: true - '@napi-rs/canvas-linux-arm64-musl@0.1.96': + '@napi-rs/canvas-linux-arm64-musl@0.1.97': optional: true - '@napi-rs/canvas-linux-riscv64-gnu@0.1.96': + '@napi-rs/canvas-linux-riscv64-gnu@0.1.97': optional: true - '@napi-rs/canvas-linux-x64-gnu@0.1.96': + '@napi-rs/canvas-linux-x64-gnu@0.1.97': optional: true - '@napi-rs/canvas-linux-x64-musl@0.1.96': + '@napi-rs/canvas-linux-x64-musl@0.1.97': optional: true - '@napi-rs/canvas-win32-arm64-msvc@0.1.96': + '@napi-rs/canvas-win32-arm64-msvc@0.1.97': optional: true - '@napi-rs/canvas-win32-x64-msvc@0.1.96': + '@napi-rs/canvas-win32-x64-msvc@0.1.97': optional: true - '@napi-rs/canvas@0.1.96': + '@napi-rs/canvas@0.1.97': optionalDependencies: - '@napi-rs/canvas-android-arm64': 0.1.96 - '@napi-rs/canvas-darwin-arm64': 0.1.96 - '@napi-rs/canvas-darwin-x64': 0.1.96 - '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.96 - '@napi-rs/canvas-linux-arm64-gnu': 0.1.96 - '@napi-rs/canvas-linux-arm64-musl': 0.1.96 - '@napi-rs/canvas-linux-riscv64-gnu': 0.1.96 - '@napi-rs/canvas-linux-x64-gnu': 0.1.96 - '@napi-rs/canvas-linux-x64-musl': 0.1.96 - '@napi-rs/canvas-win32-arm64-msvc': 0.1.96 - '@napi-rs/canvas-win32-x64-msvc': 0.1.96 + '@napi-rs/canvas-android-arm64': 0.1.97 + '@napi-rs/canvas-darwin-arm64': 0.1.97 + '@napi-rs/canvas-darwin-x64': 0.1.97 + '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.97 + '@napi-rs/canvas-linux-arm64-gnu': 0.1.97 + '@napi-rs/canvas-linux-arm64-musl': 0.1.97 + '@napi-rs/canvas-linux-riscv64-gnu': 0.1.97 + '@napi-rs/canvas-linux-x64-gnu': 0.1.97 + '@napi-rs/canvas-linux-x64-musl': 0.1.97 + '@napi-rs/canvas-win32-arm64-msvc': 0.1.97 + '@napi-rs/canvas-win32-x64-msvc': 0.1.97 '@napi-rs/nice-android-arm-eabi@1.1.1': optional: true @@ -12825,9 +12834,9 @@ snapshots: '@napi-rs/nice-win32-x64-msvc': 1.1.1 optional: true - '@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - file-type: 21.3.0 + file-type: 21.3.2 iterare: 1.2.1 load-esm: 1.0.3 reflect-metadata: 0.2.2 @@ -12837,9 +12846,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/core@11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/core@11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -12849,12 +12858,12 @@ snapshots: tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) - '@nestjs/platform-express@11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)': + '@nestjs/platform-express@11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)': dependencies: - '@nestjs/common': 11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) cors: 2.8.6 express: 5.2.1 multer: 2.1.1 @@ -12863,13 +12872,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/testing@11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16)': + '@nestjs/testing@11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-express@11.1.17)': dependencies: - '@nestjs/common': 11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) '@noble/hashes@1.8.0': {} @@ -12920,218 +12929,213 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs@0.208.0': + '@opentelemetry/api-logs@0.212.0': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs@0.211.0': + '@opentelemetry/api-logs@0.213.0': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/api@1.9.0': {} - '@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-amqplib@0.60.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.39.0 - - '@opentelemetry/instrumentation-amqplib@0.58.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-connect@0.54.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-connect@0.56.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 '@types/connect': 3.4.38 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-dataloader@0.28.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-dataloader@0.30.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-express@0.59.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-express@0.61.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-fs@0.30.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-fs@0.32.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-generic-pool@0.54.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-generic-pool@0.56.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-graphql@0.58.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-graphql@0.61.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-hapi@0.57.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-hapi@0.59.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-http@0.211.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-http@0.213.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 forwarded-parse: 2.1.2 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-ioredis@0.59.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-ioredis@0.61.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) '@opentelemetry/redis-common': 0.38.2 - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-kafkajs@0.20.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-kafkajs@0.22.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-knex@0.55.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-knex@0.57.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-koa@0.59.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-koa@0.61.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-lru-memoizer@0.55.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-lru-memoizer@0.57.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mongodb@0.64.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-mongodb@0.66.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mongoose@0.57.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-mongoose@0.59.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mysql2@0.57.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-mysql2@0.59.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mysql@0.57.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-mysql@0.59.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 '@types/mysql': 2.15.27 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-pg@0.63.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-pg@0.65.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) '@types/pg': 8.15.6 '@types/pg-pool': 2.0.7 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-redis@0.59.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-redis@0.61.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) '@opentelemetry/redis-common': 0.38.2 - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-tedious@0.30.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-tedious@0.32.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 '@types/tedious': 4.0.14 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-undici@0.21.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-undici@0.23.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color @@ -13144,45 +13148,45 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation@0.212.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.208.0 + '@opentelemetry/api-logs': 0.212.0 import-in-the-middle: 2.0.6 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.211.0 - import-in-the-middle: 2.0.6 + '@opentelemetry/api-logs': 0.213.0 + import-in-the-middle: 3.0.0 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color '@opentelemetry/redis-common@0.38.2': {} - '@opentelemetry/resources@2.5.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/semantic-conventions@1.39.0': {} + '@opentelemetry/semantic-conventions@1.40.0': {} '@opentelemetry/sql-common@0.41.2(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) '@paralleldrive/cuid2@2.3.1': dependencies: @@ -13356,7 +13360,7 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@prisma/instrumentation@7.2.0(@opentelemetry/api@1.9.0)': + '@prisma/instrumentation@7.4.2(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.207.0(@opentelemetry/api@1.9.0) @@ -13410,100 +13414,100 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.2': {} - '@rollup/plugin-json@6.1.0(rollup@4.59.0)': + '@rollup/plugin-json@6.1.0(rollup@4.60.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.60.0) optionalDependencies: - rollup: 4.59.0 + rollup: 4.60.0 - '@rollup/plugin-replace@6.0.3(rollup@4.59.0)': + '@rollup/plugin-replace@6.0.3(rollup@4.60.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.60.0) magic-string: 0.30.21 optionalDependencies: - rollup: 4.59.0 + rollup: 4.60.0 - '@rollup/pluginutils@5.3.0(rollup@4.59.0)': + '@rollup/pluginutils@5.3.0(rollup@4.60.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.59.0 + rollup: 4.60.0 - '@rollup/rollup-android-arm-eabi@4.59.0': + '@rollup/rollup-android-arm-eabi@4.60.0': optional: true - '@rollup/rollup-android-arm64@4.59.0': + '@rollup/rollup-android-arm64@4.60.0': optional: true - '@rollup/rollup-darwin-arm64@4.59.0': + '@rollup/rollup-darwin-arm64@4.60.0': optional: true - '@rollup/rollup-darwin-x64@4.59.0': + '@rollup/rollup-darwin-x64@4.60.0': optional: true - '@rollup/rollup-freebsd-arm64@4.59.0': + '@rollup/rollup-freebsd-arm64@4.60.0': optional: true - '@rollup/rollup-freebsd-x64@4.59.0': + '@rollup/rollup-freebsd-x64@4.60.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + '@rollup/rollup-linux-arm-gnueabihf@4.60.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.59.0': + '@rollup/rollup-linux-arm-musleabihf@4.60.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.59.0': + '@rollup/rollup-linux-arm64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.59.0': + '@rollup/rollup-linux-arm64-musl@4.60.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.59.0': + '@rollup/rollup-linux-loong64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.59.0': + '@rollup/rollup-linux-loong64-musl@4.60.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.59.0': + '@rollup/rollup-linux-ppc64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.59.0': + '@rollup/rollup-linux-ppc64-musl@4.60.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.59.0': + '@rollup/rollup-linux-riscv64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.59.0': + '@rollup/rollup-linux-riscv64-musl@4.60.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.59.0': + '@rollup/rollup-linux-s390x-gnu@4.60.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.59.0': + '@rollup/rollup-linux-x64-gnu@4.60.0': optional: true - '@rollup/rollup-linux-x64-musl@4.59.0': + '@rollup/rollup-linux-x64-musl@4.60.0': optional: true - '@rollup/rollup-openbsd-x64@4.59.0': + '@rollup/rollup-openbsd-x64@4.60.0': optional: true - '@rollup/rollup-openharmony-arm64@4.59.0': + '@rollup/rollup-openharmony-arm64@4.60.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.59.0': + '@rollup/rollup-win32-arm64-msvc@4.60.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.59.0': + '@rollup/rollup-win32-ia32-msvc@4.60.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.59.0': + '@rollup/rollup-win32-x64-gnu@4.60.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.59.0': + '@rollup/rollup-win32-x64-msvc@4.60.0': optional: true '@rtsao/scc@1.1.0': {} @@ -13549,114 +13553,114 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@sentry-internal/browser-utils@10.43.0': + '@sentry-internal/browser-utils@10.45.0': dependencies: - '@sentry/core': 10.43.0 + '@sentry/core': 10.45.0 - '@sentry-internal/feedback@10.43.0': + '@sentry-internal/feedback@10.45.0': dependencies: - '@sentry/core': 10.43.0 + '@sentry/core': 10.45.0 '@sentry-internal/node-cpu-profiler@2.2.0': dependencies: detect-libc: 2.1.2 node-abi: 3.85.0 - '@sentry-internal/replay-canvas@10.43.0': + '@sentry-internal/replay-canvas@10.45.0': dependencies: - '@sentry-internal/replay': 10.43.0 - '@sentry/core': 10.43.0 + '@sentry-internal/replay': 10.45.0 + '@sentry/core': 10.45.0 - '@sentry-internal/replay@10.43.0': + '@sentry-internal/replay@10.45.0': dependencies: - '@sentry-internal/browser-utils': 10.43.0 - '@sentry/core': 10.43.0 + '@sentry-internal/browser-utils': 10.45.0 + '@sentry/core': 10.45.0 - '@sentry/browser@10.43.0': + '@sentry/browser@10.45.0': dependencies: - '@sentry-internal/browser-utils': 10.43.0 - '@sentry-internal/feedback': 10.43.0 - '@sentry-internal/replay': 10.43.0 - '@sentry-internal/replay-canvas': 10.43.0 - '@sentry/core': 10.43.0 + '@sentry-internal/browser-utils': 10.45.0 + '@sentry-internal/feedback': 10.45.0 + '@sentry-internal/replay': 10.45.0 + '@sentry-internal/replay-canvas': 10.45.0 + '@sentry/core': 10.45.0 - '@sentry/core@10.43.0': {} + '@sentry/core@10.45.0': {} - '@sentry/node-core@10.43.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.39.0)': + '@sentry/node-core@10.45.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: - '@sentry/core': 10.43.0 - '@sentry/opentelemetry': 10.43.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.39.0) - import-in-the-middle: 2.0.6 + '@sentry/core': 10.45.0 + '@sentry/opentelemetry': 10.45.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + import-in-the-middle: 3.0.0 optionalDependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/context-async-hooks': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/node@10.43.0': + '@sentry/node@10.45.0': dependencies: - '@fastify/otel': 0.16.0(@opentelemetry/api@1.9.0) + '@fastify/otel': 0.17.1(@opentelemetry/api@1.9.0) '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-amqplib': 0.58.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-connect': 0.54.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-dataloader': 0.28.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-express': 0.59.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-fs': 0.30.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-generic-pool': 0.54.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-graphql': 0.58.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-hapi': 0.57.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-http': 0.211.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-ioredis': 0.59.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-kafkajs': 0.20.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-knex': 0.55.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-koa': 0.59.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-lru-memoizer': 0.55.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mongodb': 0.64.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mongoose': 0.57.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mysql': 0.57.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mysql2': 0.57.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-pg': 0.63.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-redis': 0.59.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-tedious': 0.30.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-undici': 0.21.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 - '@prisma/instrumentation': 7.2.0(@opentelemetry/api@1.9.0) - '@sentry/core': 10.43.0 - '@sentry/node-core': 10.43.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.39.0) - '@sentry/opentelemetry': 10.43.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.39.0) - import-in-the-middle: 2.0.6 + '@opentelemetry/context-async-hooks': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-amqplib': 0.60.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-connect': 0.56.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-dataloader': 0.30.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-express': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-fs': 0.32.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-generic-pool': 0.56.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-graphql': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-hapi': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-http': 0.213.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-ioredis': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-kafkajs': 0.22.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-knex': 0.57.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-koa': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-lru-memoizer': 0.57.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongodb': 0.66.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongoose': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql2': 0.59.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-pg': 0.65.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-redis': 0.61.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-tedious': 0.32.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-undici': 0.23.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@prisma/instrumentation': 7.4.2(@opentelemetry/api@1.9.0) + '@sentry/core': 10.45.0 + '@sentry/node-core': 10.45.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/opentelemetry': 10.45.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) + import-in-the-middle: 3.0.0 transitivePeerDependencies: - supports-color - '@sentry/opentelemetry@10.43.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.39.0)': + '@sentry/opentelemetry@10.45.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.5.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.39.0 - '@sentry/core': 10.43.0 + '@opentelemetry/context-async-hooks': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + '@sentry/core': 10.45.0 - '@sentry/profiling-node@10.43.0': + '@sentry/profiling-node@10.45.0': dependencies: '@sentry-internal/node-cpu-profiler': 2.2.0 - '@sentry/core': 10.43.0 - '@sentry/node': 10.43.0 + '@sentry/core': 10.45.0 + '@sentry/node': 10.45.0 transitivePeerDependencies: - supports-color - '@sentry/vue@10.43.0(vue@3.5.30(typescript@5.9.3))': + '@sentry/vue@10.45.0(vue@3.5.30(typescript@5.9.3))': dependencies: - '@sentry/browser': 10.43.0 - '@sentry/core': 10.43.0 + '@sentry/browser': 10.45.0 + '@sentry/core': 10.45.0 vue: 3.5.30(typescript@5.9.3) '@shikijs/core@3.23.0': @@ -13764,7 +13768,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/config-resolver@4.4.11': + '@smithy/config-resolver@4.4.13': dependencies: '@smithy/node-config-provider': 4.3.12 '@smithy/types': 4.13.1 @@ -13773,7 +13777,7 @@ snapshots: '@smithy/util-middleware': 4.2.12 tslib: 2.8.1 - '@smithy/core@3.23.11': + '@smithy/core@3.23.12': dependencies: '@smithy/protocol-http': 5.3.12 '@smithy/types': 4.13.1 @@ -13781,7 +13785,7 @@ snapshots: '@smithy/util-base64': 4.3.2 '@smithy/util-body-length-browser': 4.2.2 '@smithy/util-middleware': 4.2.12 - '@smithy/util-stream': 4.5.19 + '@smithy/util-stream': 4.5.20 '@smithy/util-utf8': 4.2.2 '@smithy/uuid': 1.1.2 tslib: 2.8.1 @@ -13877,10 +13881,10 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 - '@smithy/middleware-endpoint@4.4.25': + '@smithy/middleware-endpoint@4.4.27': dependencies: - '@smithy/core': 3.23.11 - '@smithy/middleware-serde': 4.2.14 + '@smithy/core': 3.23.12 + '@smithy/middleware-serde': 4.2.15 '@smithy/node-config-provider': 4.3.12 '@smithy/shared-ini-file-loader': 4.4.7 '@smithy/types': 4.13.1 @@ -13888,21 +13892,21 @@ snapshots: '@smithy/util-middleware': 4.2.12 tslib: 2.8.1 - '@smithy/middleware-retry@4.4.42': + '@smithy/middleware-retry@4.4.44': dependencies: '@smithy/node-config-provider': 4.3.12 '@smithy/protocol-http': 5.3.12 '@smithy/service-error-classification': 4.2.12 - '@smithy/smithy-client': 4.12.5 + '@smithy/smithy-client': 4.12.7 '@smithy/types': 4.13.1 '@smithy/util-middleware': 4.2.12 '@smithy/util-retry': 4.2.12 '@smithy/uuid': 1.1.2 tslib: 2.8.1 - '@smithy/middleware-serde@4.2.14': + '@smithy/middleware-serde@4.2.15': dependencies: - '@smithy/core': 3.23.11 + '@smithy/core': 3.23.12 '@smithy/protocol-http': 5.3.12 '@smithy/types': 4.13.1 tslib: 2.8.1 @@ -13919,7 +13923,7 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 - '@smithy/node-http-handler@4.4.16': + '@smithy/node-http-handler@4.5.0': dependencies: '@smithy/abort-controller': 4.2.12 '@smithy/protocol-http': 5.3.12 @@ -13968,14 +13972,14 @@ snapshots: '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@smithy/smithy-client@4.12.5': + '@smithy/smithy-client@4.12.7': dependencies: - '@smithy/core': 3.23.11 - '@smithy/middleware-endpoint': 4.4.25 + '@smithy/core': 3.23.12 + '@smithy/middleware-endpoint': 4.4.27 '@smithy/middleware-stack': 4.2.12 '@smithy/protocol-http': 5.3.12 '@smithy/types': 4.13.1 - '@smithy/util-stream': 4.5.19 + '@smithy/util-stream': 4.5.20 tslib: 2.8.1 '@smithy/types@4.13.1': @@ -14016,20 +14020,20 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.3.41': + '@smithy/util-defaults-mode-browser@4.3.43': dependencies: '@smithy/property-provider': 4.2.12 - '@smithy/smithy-client': 4.12.5 + '@smithy/smithy-client': 4.12.7 '@smithy/types': 4.13.1 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.2.44': + '@smithy/util-defaults-mode-node@4.2.47': dependencies: - '@smithy/config-resolver': 4.4.11 + '@smithy/config-resolver': 4.4.13 '@smithy/credential-provider-imds': 4.2.12 '@smithy/node-config-provider': 4.3.12 '@smithy/property-provider': 4.2.12 - '@smithy/smithy-client': 4.12.5 + '@smithy/smithy-client': 4.12.7 '@smithy/types': 4.13.1 tslib: 2.8.1 @@ -14054,10 +14058,10 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 - '@smithy/util-stream@4.5.19': + '@smithy/util-stream@4.5.20': dependencies: '@smithy/fetch-http-handler': 5.3.15 - '@smithy/node-http-handler': 4.4.16 + '@smithy/node-http-handler': 4.5.0 '@smithy/types': 4.13.1 '@smithy/util-base64': 4.3.2 '@smithy/util-buffer-from': 4.2.2 @@ -14093,155 +14097,155 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-actions@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-actions@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 '@types/uuid': 9.0.8 dequal: 2.0.3 polished: 4.3.1 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) uuid: 9.0.1 - '@storybook/addon-backgrounds@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-backgrounds@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 memoizerific: 1.11.3 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - '@storybook/addon-controls@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-controls@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 dequal: 2.0.3 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - '@storybook/addon-docs@8.6.18(@types/react@19.2.2)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-docs@8.6.18(@types/react@19.2.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.2)(react@19.2.4) - '@storybook/blocks': 8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/csf-plugin': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/react-dom-shim': 8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/blocks': 8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/csf-plugin': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/react-dom-shim': 8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-essentials@8.6.18(@types/react@19.2.2)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': - dependencies: - '@storybook/addon-actions': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/addon-backgrounds': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/addon-controls': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/addon-docs': 8.6.18(@types/react@19.2.2)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/addon-highlight': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/addon-measure': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/addon-outline': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/addon-toolbars': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/addon-viewport': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + '@storybook/addon-essentials@8.6.18(@types/react@19.2.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + dependencies: + '@storybook/addon-actions': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/addon-backgrounds': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/addon-controls': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/addon-docs': 8.6.18(@types/react@19.2.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/addon-highlight': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/addon-measure': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/addon-outline': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/addon-toolbars': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/addon-viewport': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-highlight@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-highlight@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/addon-interactions@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-interactions@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/test': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/instrumenter': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/test': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) polished: 4.3.1 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - '@storybook/addon-links@10.2.17(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-links@10.3.3(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) optionalDependencies: react: 19.2.4 - '@storybook/addon-mdx-gfm@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-mdx-gfm@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: remark-gfm: 4.0.1 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - '@storybook/addon-measure@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-measure@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) tiny-invariant: 1.3.3 - '@storybook/addon-outline@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-outline@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - '@storybook/addon-storysource@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-storysource@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: - '@storybook/source-loader': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/source-loader': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) estraverse: 5.3.0 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) tiny-invariant: 1.3.3 - '@storybook/addon-toolbars@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-toolbars@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/addon-viewport@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/addon-viewport@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: memoizerific: 1.11.3 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/blocks@8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/blocks@8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/icons': 1.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 optionalDependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/builder-vite@10.2.17(esbuild@0.27.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))': + '@storybook/builder-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - '@storybook/csf-plugin': 10.2.17(esbuild@0.27.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + '@storybook/csf-plugin': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup - webpack - '@storybook/components@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/components@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/core-events@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/core-events@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/csf-plugin@10.2.17(esbuild@0.27.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))': + '@storybook/csf-plugin@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) unplugin: 2.3.10 optionalDependencies: esbuild: 0.27.4 - rollup: 4.59.0 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + rollup: 4.60.0 + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) - '@storybook/csf-plugin@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/csf-plugin@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) unplugin: 1.16.1 '@storybook/global@5.0.0': {} @@ -14256,47 +14260,47 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/instrumenter@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/instrumenter@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 '@vitest/utils': 2.1.9 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/manager-api@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/manager-api@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/preview-api@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/preview-api@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/react-dom-shim@10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/react-dom-shim@10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/react-dom-shim@8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/react-dom-shim@8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/react-vite@10.2.17(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))': + '@storybook/react-vite@10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) - '@storybook/builder-vite': 10.2.17(esbuild@0.27.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) - '@storybook/react': 10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@rollup/pluginutils': 5.3.0(rollup@4.60.0) + '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/react': 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 react: 19.2.4 react-docgen: 8.0.2 react-dom: 19.2.4(react@19.2.4) resolve: 1.22.11 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) tsconfig-paths: 4.2.0 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup @@ -14304,53 +14308,54 @@ snapshots: - typescript - webpack - '@storybook/react@10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)': + '@storybook/react@10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/react-dom-shim': 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) react: 19.2.4 react-docgen: 8.0.2 + react-docgen-typescript: 2.4.0(typescript@5.9.3) react-dom: 19.2.4(react@19.2.4) - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@storybook/source-loader@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/source-loader@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: es-toolkit: 1.42.0 estraverse: 5.3.0 prettier: 3.8.1 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/test@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/test@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/instrumenter': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) '@testing-library/dom': 10.4.0 '@testing-library/jest-dom': 6.5.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) '@vitest/expect': 2.0.5 '@vitest/spy': 2.0.5 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/theming@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/theming@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/types@8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': + '@storybook/types@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/vue3-vite@10.2.17(esbuild@0.27.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': + '@storybook/vue3-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': dependencies: - '@storybook/builder-vite': 10.2.17(esbuild@0.27.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) - '@storybook/vue3': 10.2.17(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) + '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/vue3': 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) magic-string: 0.30.21 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) typescript: 5.9.3 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue-component-meta: 2.2.12(typescript@5.9.3) vue-docgen-api: 4.79.2(vue@3.5.30(typescript@5.9.3)) transitivePeerDependencies: @@ -14359,27 +14364,27 @@ snapshots: - vue - webpack - '@storybook/vue3@10.2.17(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3))': + '@storybook/vue3@10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) + storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) type-fest: 2.19.0 vue: 3.5.30(typescript@5.9.3) - vue-component-type-helpers: 3.2.5 + vue-component-type-helpers: 3.2.6 '@stylistic/eslint-plugin@5.5.0(eslint@9.39.4)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/types': 8.57.2 eslint: 9.39.4 eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.3 - '@swc/cli@0.8.0(@swc/core@1.15.18)(chokidar@5.0.0)': + '@swc/cli@0.8.0(@swc/core@1.15.21)(chokidar@5.0.0)': dependencies: - '@swc/core': 1.15.18 + '@swc/core': 1.15.21 '@swc/counter': 0.1.3 '@xhmikosr/bin-wrapper': 13.2.0 commander: 8.3.0 @@ -14401,10 +14406,10 @@ snapshots: '@swc/wasm': 1.2.130 optional: true - '@swc/core-darwin-arm64@1.15.18': + '@swc/core-darwin-arm64@1.15.21': optional: true - '@swc/core-darwin-x64@1.15.18': + '@swc/core-darwin-x64@1.15.21': optional: true '@swc/core-freebsd-x64@1.3.11': @@ -14412,52 +14417,60 @@ snapshots: '@swc/wasm': 1.2.130 optional: true - '@swc/core-linux-arm-gnueabihf@1.15.18': + '@swc/core-linux-arm-gnueabihf@1.15.21': + optional: true + + '@swc/core-linux-arm64-gnu@1.15.21': optional: true - '@swc/core-linux-arm64-gnu@1.15.18': + '@swc/core-linux-arm64-musl@1.15.21': optional: true - '@swc/core-linux-arm64-musl@1.15.18': + '@swc/core-linux-ppc64-gnu@1.15.21': optional: true - '@swc/core-linux-x64-gnu@1.15.18': + '@swc/core-linux-s390x-gnu@1.15.21': optional: true - '@swc/core-linux-x64-musl@1.15.18': + '@swc/core-linux-x64-gnu@1.15.21': optional: true - '@swc/core-win32-arm64-msvc@1.15.18': + '@swc/core-linux-x64-musl@1.15.21': optional: true - '@swc/core-win32-ia32-msvc@1.15.18': + '@swc/core-win32-arm64-msvc@1.15.21': optional: true - '@swc/core-win32-x64-msvc@1.15.18': + '@swc/core-win32-ia32-msvc@1.15.21': optional: true - '@swc/core@1.15.18': + '@swc/core-win32-x64-msvc@1.15.21': + optional: true + + '@swc/core@1.15.21': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.25 optionalDependencies: - '@swc/core-darwin-arm64': 1.15.18 - '@swc/core-darwin-x64': 1.15.18 - '@swc/core-linux-arm-gnueabihf': 1.15.18 - '@swc/core-linux-arm64-gnu': 1.15.18 - '@swc/core-linux-arm64-musl': 1.15.18 - '@swc/core-linux-x64-gnu': 1.15.18 - '@swc/core-linux-x64-musl': 1.15.18 - '@swc/core-win32-arm64-msvc': 1.15.18 - '@swc/core-win32-ia32-msvc': 1.15.18 - '@swc/core-win32-x64-msvc': 1.15.18 + '@swc/core-darwin-arm64': 1.15.21 + '@swc/core-darwin-x64': 1.15.21 + '@swc/core-linux-arm-gnueabihf': 1.15.21 + '@swc/core-linux-arm64-gnu': 1.15.21 + '@swc/core-linux-arm64-musl': 1.15.21 + '@swc/core-linux-ppc64-gnu': 1.15.21 + '@swc/core-linux-s390x-gnu': 1.15.21 + '@swc/core-linux-x64-gnu': 1.15.21 + '@swc/core-linux-x64-musl': 1.15.21 + '@swc/core-win32-arm64-msvc': 1.15.21 + '@swc/core-win32-ia32-msvc': 1.15.21 + '@swc/core-win32-x64-msvc': 1.15.21 '@swc/counter@0.1.3': {} - '@swc/jest@0.2.39(@swc/core@1.15.18)': + '@swc/jest@0.2.39(@swc/core@1.15.21)': dependencies: '@jest/create-cache-key-function': 30.2.0 - '@swc/core': 1.15.18 + '@swc/core': 1.15.21 '@swc/counter': 0.1.3 jsonc-parser: 3.3.1 @@ -14851,7 +14864,7 @@ snapshots: '@types/pg-pool@2.0.7': dependencies: - '@types/pg': 8.18.0 + '@types/pg': 8.20.0 '@types/pg@8.15.6': dependencies: @@ -14859,7 +14872,7 @@ snapshots: pg-protocol: 1.13.0 pg-types: 2.2.0 - '@types/pg@8.18.0': + '@types/pg@8.20.0': dependencies: '@types/node': 24.12.0 pg-protocol: 1.13.0 @@ -14991,14 +15004,14 @@ snapshots: '@types/node': 24.12.0 optional: true - '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/type-utils': 8.57.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.0 + '@typescript-eslint/parser': 8.57.2(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/type-utils': 8.57.2(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.2 eslint: 9.39.4 ignore: 7.0.5 natural-compare: 1.4.0 @@ -15007,41 +15020,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.0 + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.2 debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.4 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.57.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.57.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) - '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 debug: 4.4.3(supports-color@10.2.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.57.0': + '@typescript-eslint/scope-manager@8.57.2': dependencies: - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/visitor-keys': 8.57.0 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/visitor-keys': 8.57.2 - '@typescript-eslint/tsconfig-utils@8.57.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.57.2(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.57.0(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.57.2(eslint@9.39.4)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@9.39.4)(typescript@5.9.3) debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.4 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -15049,14 +15062,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.57.0': {} + '@typescript-eslint/types@8.57.2': {} - '@typescript-eslint/typescript-estree@8.57.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.57.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.57.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/visitor-keys': 8.57.0 + '@typescript-eslint/project-service': 8.57.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/visitor-keys': 8.57.2 debug: 4.4.3(supports-color@10.2.2) minimatch: 10.2.4 semver: 7.7.4 @@ -15066,20 +15079,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.57.0(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/utils@8.57.2(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) eslint: 9.39.4 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.57.0': + '@typescript-eslint/visitor-keys@8.57.2': dependencies: - '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/types': 8.57.2 eslint-visitor-keys: 5.0.1 '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260116.1': @@ -15115,16 +15128,16 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: 3.5.30(typescript@5.9.3) - '@vitest/coverage-v8@4.1.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)))': + '@vitest/coverage-v8@4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)))': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.0 + '@vitest/utils': 4.1.1 ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -15133,7 +15146,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.0.3 - vitest: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@vitest/expect@2.0.5': dependencies: @@ -15150,23 +15163,23 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/expect@4.1.0': + '@vitest/expect@4.1.1': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.0 - '@vitest/utils': 4.1.0 + '@vitest/spy': 4.1.1 + '@vitest/utils': 4.1.1 chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.1.0(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))': + '@vitest/mocker@4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - '@vitest/spy': 4.1.0 + '@vitest/spy': 4.1.1 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.12.10(@types/node@24.12.0)(typescript@5.9.3) - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + msw: 2.12.14(@types/node@24.12.0)(typescript@5.9.3) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) '@vitest/pretty-format@2.0.5': dependencies: @@ -15180,19 +15193,19 @@ snapshots: dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.1.0': + '@vitest/pretty-format@4.1.1': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.1.0': + '@vitest/runner@4.1.1': dependencies: - '@vitest/utils': 4.1.0 + '@vitest/utils': 4.1.1 pathe: 2.0.3 - '@vitest/snapshot@4.1.0': + '@vitest/snapshot@4.1.1': dependencies: - '@vitest/pretty-format': 4.1.0 - '@vitest/utils': 4.1.0 + '@vitest/pretty-format': 4.1.1 + '@vitest/utils': 4.1.1 magic-string: 0.30.21 pathe: 2.0.3 @@ -15204,7 +15217,7 @@ snapshots: dependencies: tinyspy: 4.0.4 - '@vitest/spy@4.1.0': {} + '@vitest/spy@4.1.1': {} '@vitest/utils@2.0.5': dependencies: @@ -15225,9 +15238,9 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 - '@vitest/utils@4.1.0': + '@vitest/utils@4.1.1': dependencies: - '@vitest/pretty-format': 4.1.0 + '@vitest/pretty-format': 4.1.1 convert-source-map: 2.0.0 tinyrainbow: 3.0.3 @@ -15303,7 +15316,7 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@vue/language-core@3.2.5': + '@vue/language-core@3.2.6': dependencies: '@volar/language-core': 2.4.28 '@vue/compiler-dom': 3.5.30 @@ -16200,7 +16213,7 @@ snapshots: chownr@3.0.0: {} - chromatic@15.2.0: {} + chromatic@15.3.1: {} ci-info@3.9.0: {} @@ -16510,7 +16523,7 @@ snapshots: csstype@3.2.3: {} - cypress@15.11.0: + cypress@15.13.0: dependencies: '@cypress/request': 3.0.10 '@cypress/xvfb': 1.2.4(supports-color@8.1.1) @@ -16549,7 +16562,7 @@ snapshots: proxy-from-env: 1.0.0 request-progress: 3.0.0 supports-color: 8.1.1 - systeminformation: 5.31.4 + systeminformation: 5.31.5 tmp: 0.2.5 tree-kill: 1.2.2 tslib: 1.14.1 @@ -16984,7 +16997,7 @@ snapshots: esbuild-plugin-swc@1.0.1: dependencies: - '@swc/core': 1.15.18 + '@swc/core': 1.15.21 deepmerge: 4.3.1 transitivePeerDependencies: - '@swc/helpers' @@ -17053,17 +17066,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.2(eslint@9.39.4)(typescript@5.9.3) eslint: 9.39.4 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -17074,7 +17087,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.4 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -17086,13 +17099,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.2(eslint@9.39.4)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-vue@10.8.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.57.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)): + eslint-plugin-vue@10.8.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) eslint: 9.39.4 @@ -17104,7 +17117,7 @@ snapshots: xml-name-validator: 4.0.0 optionalDependencies: '@stylistic/eslint-plugin': 5.5.0(eslint@9.39.4) - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.2(eslint@9.39.4)(typescript@5.9.3) eslint-rule-docs@1.1.235: {} @@ -17416,14 +17429,15 @@ snapshots: fast-uri@3.1.0: {} - fast-xml-builder@1.1.3: + fast-xml-builder@1.1.4: dependencies: - path-expression-matcher: 1.1.3 + path-expression-matcher: 1.2.0 - fast-xml-parser@5.4.1: + fast-xml-parser@5.5.8: dependencies: - fast-xml-builder: 1.1.3 - strnum: 2.1.2 + fast-xml-builder: 1.1.4 + path-expression-matcher: 1.2.0 + strnum: 2.2.2 fastify-plugin@5.1.0: {} @@ -17433,7 +17447,7 @@ snapshots: raw-body: 3.0.1 secure-json-parse: 2.7.0 - fastify@5.8.2: + fastify@5.8.4: dependencies: '@fastify/ajv-compiler': 4.0.5 '@fastify/error': 4.2.0 @@ -17499,7 +17513,7 @@ snapshots: transitivePeerDependencies: - supports-color - file-type@21.3.0: + file-type@21.3.2: dependencies: '@tokenizer/inflate': 0.4.1 strtok3: 10.3.4 @@ -17508,7 +17522,7 @@ snapshots: transitivePeerDependencies: - supports-color - file-type@21.3.2: + file-type@21.3.4: dependencies: '@tokenizer/inflate': 0.4.1 strtok3: 10.3.4 @@ -17573,7 +17587,7 @@ snapshots: fkill@10.0.3: dependencies: execa: 9.6.1 - pid-port: 2.0.1 + pid-port: 2.1.0 process-exists: 5.0.0 ps-list: 9.0.0 taskkill: 5.0.0 @@ -17843,21 +17857,21 @@ snapshots: hammerjs@2.0.8: {} - happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6): + happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6): dependencies: '@types/node': 24.12.0 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 entities: 7.0.1 whatwg-mimetype: 3.0.0 - ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - bufferutil - utf-8-validate hard-rejection@2.1.0: {} - harfbuzzjs@0.10.0: {} + harfbuzzjs@0.10.1: {} has-bigints@1.1.0: {} @@ -17943,13 +17957,6 @@ snapshots: domutils: 3.2.2 entities: 7.0.1 - htmlparser2@8.0.2: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 4.5.0 - htmlparser2@9.1.0: dependencies: domelementtype: 2.3.0 @@ -18068,6 +18075,13 @@ snapshots: cjs-module-lexer: 2.2.0 module-details-from-path: 1.0.4 + import-in-the-middle@3.0.0: + dependencies: + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + cjs-module-lexer: 2.2.0 + module-details-from-path: 1.0.4 + import-lazy@4.0.0: {} import-local@3.2.0: @@ -18108,7 +18122,7 @@ snapshots: intersection-observer@0.12.2: {} - ioredis@5.10.0: + ioredis@5.10.1: dependencies: '@ioredis/commands': 1.5.1 cluster-key-slot: 1.1.2 @@ -18779,7 +18793,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 15.1.0 - ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -19170,12 +19184,12 @@ snapshots: media-typer@1.1.0: {} - mediabunny@1.39.2: + mediabunny@1.40.1: dependencies: '@types/dom-mediacapture-transform': 0.1.11 '@types/dom-webcodecs': 0.1.13 - meilisearch@0.55.0: {} + meilisearch@0.56.0: {} memoizerific@1.11.3: dependencies: @@ -19542,12 +19556,12 @@ snapshots: optionalDependencies: msgpackr-extract: 3.0.3 - msw-storybook-addon@2.0.6(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3)): + msw-storybook-addon@2.0.6(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3)): dependencies: is-node-process: 1.2.0 - msw: 2.12.10(@types/node@24.12.0)(typescript@5.9.3) + msw: 2.12.14(@types/node@24.12.0)(typescript@5.9.3) - msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3): + msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3): dependencies: '@inquirer/confirm': 5.1.21(@types/node@24.12.0) '@mswjs/interceptors': 0.41.2 @@ -19589,7 +19603,7 @@ snapshots: nanoid@3.3.11: {} - nanoid@5.1.6: {} + nanoid@5.1.7: {} natural-compare@1.4.0: {} @@ -19666,7 +19680,7 @@ snapshots: nopt: 9.0.0 proc-log: 6.1.0 semver: 7.7.4 - tar: 7.5.11 + tar: 7.5.13 tinyglobby: 0.2.15 which: 6.0.0 transitivePeerDependencies: @@ -19681,7 +19695,7 @@ snapshots: node-releases@2.0.27: {} - nodemailer@8.0.2: {} + nodemailer@8.0.3: {} nodemon@3.1.14: dependencies: @@ -19750,7 +19764,7 @@ snapshots: set-blocking: 2.0.0 optional: true - nsfwjs@4.2.0(@tensorflow/tfjs@4.22.0(encoding@0.1.13)(seedrandom@3.0.5))(buffer@6.0.3): + nsfwjs@4.3.0(@tensorflow/tfjs@4.22.0(encoding@0.1.13)(seedrandom@3.0.5))(buffer@6.0.3): dependencies: '@tensorflow/tfjs': 4.22.0(encoding@0.1.13)(seedrandom@3.0.5) buffer: 6.0.3 @@ -19969,7 +19983,7 @@ snapshots: path-exists@4.0.0: {} - path-expression-matcher@1.1.3: {} + path-expression-matcher@1.2.0: {} path-is-absolute@1.0.1: {} @@ -20052,7 +20066,7 @@ snapshots: picomatch@4.0.3: {} - pid-port@2.0.1: + pid-port@2.1.0: dependencies: execa: 9.6.1 @@ -20102,7 +20116,7 @@ snapshots: pngjs@5.0.0: {} - pnpm@10.32.1: {} + pnpm@10.33.0: {} polished@4.3.1: dependencies: @@ -20759,35 +20773,35 @@ snapshots: glob: 7.2.3 optional: true - rollup@4.59.0: + rollup@4.60.0: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.59.0 - '@rollup/rollup-android-arm64': 4.59.0 - '@rollup/rollup-darwin-arm64': 4.59.0 - '@rollup/rollup-darwin-x64': 4.59.0 - '@rollup/rollup-freebsd-arm64': 4.59.0 - '@rollup/rollup-freebsd-x64': 4.59.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 - '@rollup/rollup-linux-arm64-musl': 4.59.0 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 - '@rollup/rollup-linux-loong64-musl': 4.59.0 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 - '@rollup/rollup-linux-x64-gnu': 4.59.0 - '@rollup/rollup-linux-x64-musl': 4.59.0 - '@rollup/rollup-openbsd-x64': 4.59.0 - '@rollup/rollup-openharmony-arm64': 4.59.0 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 - '@rollup/rollup-win32-x64-gnu': 4.59.0 - '@rollup/rollup-win32-x64-msvc': 4.59.0 + '@rollup/rollup-android-arm-eabi': 4.60.0 + '@rollup/rollup-android-arm64': 4.60.0 + '@rollup/rollup-darwin-arm64': 4.60.0 + '@rollup/rollup-darwin-x64': 4.60.0 + '@rollup/rollup-freebsd-arm64': 4.60.0 + '@rollup/rollup-freebsd-x64': 4.60.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.0 + '@rollup/rollup-linux-arm-musleabihf': 4.60.0 + '@rollup/rollup-linux-arm64-gnu': 4.60.0 + '@rollup/rollup-linux-arm64-musl': 4.60.0 + '@rollup/rollup-linux-loong64-gnu': 4.60.0 + '@rollup/rollup-linux-loong64-musl': 4.60.0 + '@rollup/rollup-linux-ppc64-gnu': 4.60.0 + '@rollup/rollup-linux-ppc64-musl': 4.60.0 + '@rollup/rollup-linux-riscv64-gnu': 4.60.0 + '@rollup/rollup-linux-riscv64-musl': 4.60.0 + '@rollup/rollup-linux-s390x-gnu': 4.60.0 + '@rollup/rollup-linux-x64-gnu': 4.60.0 + '@rollup/rollup-linux-x64-musl': 4.60.0 + '@rollup/rollup-openbsd-x64': 4.60.0 + '@rollup/rollup-openharmony-arm64': 4.60.0 + '@rollup/rollup-win32-arm64-msvc': 4.60.0 + '@rollup/rollup-win32-ia32-msvc': 4.60.0 + '@rollup/rollup-win32-x64-gnu': 4.60.0 + '@rollup/rollup-win32-x64-msvc': 4.60.0 fsevents: 2.3.3 router@2.2.0: @@ -20846,11 +20860,11 @@ snapshots: safer-buffer@2.1.2: {} - sanitize-html@2.17.1: + sanitize-html@2.17.2: dependencies: deepmerge: 4.3.1 escape-string-regexp: 4.0.0 - htmlparser2: 8.0.2 + htmlparser2: 10.1.0 is-plain-object: 5.0.0 parse-srcset: 1.0.2 postcss: 8.5.8 @@ -21281,20 +21295,20 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 - storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(b407b999cadc51b47ccbc8c1fb8ccff6): + storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(568dc48ee0a6363e76595daf2f12f0a3): dependencies: - '@storybook/blocks': 8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/components': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/core-events': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/manager-api': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/preview-api': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/theming': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) - '@storybook/types': 8.6.18(storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/blocks': 8.6.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/components': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/core-events': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/manager-api': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/preview-api': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/theming': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) + '@storybook/types': 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) optionalDependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook@10.2.17(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6): + storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -21307,7 +21321,7 @@ snapshots: recast: 0.23.11 semver: 7.7.4 use-sync-external-store: 1.6.0(react@19.2.4) - ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) optionalDependencies: prettier: 3.8.1 transitivePeerDependencies: @@ -21443,7 +21457,7 @@ snapshots: strip-json-comments@3.1.1: {} - strnum@2.1.2: {} + strnum@2.2.2: {} strtok3@10.3.4: dependencies: @@ -21511,7 +21525,7 @@ snapshots: symbol-tree@3.2.4: optional: true - systeminformation@5.31.4: {} + systeminformation@5.31.5: {} tagged-tag@1.0.0: {} @@ -21534,7 +21548,7 @@ snapshots: yallist: 4.0.0 optional: true - tar@7.5.11: + tar@7.5.13: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 @@ -21546,7 +21560,7 @@ snapshots: dependencies: execa: 6.1.0 - terser@5.46.0: + terser@5.46.1: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.16.0 @@ -21801,7 +21815,7 @@ snapshots: typedarray@0.0.6: {} - typeorm@0.3.28(ioredis@5.10.0)(pg@8.20.0): + typeorm@0.3.28(ioredis@5.10.1)(pg@8.20.0): dependencies: '@sqltools/formatter': 1.2.5 ansis: 4.2.0 @@ -21819,7 +21833,7 @@ snapshots: uuid: 11.1.0 yargs: 17.7.2 optionalDependencies: - ioredis: 5.10.0 + ioredis: 5.10.1 pg: 8.20.0 transitivePeerDependencies: - babel-plugin-macros @@ -21996,49 +22010,49 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-plugin-glsl@1.5.5(@rollup/pluginutils@5.3.0(rollup@4.59.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)): + vite-plugin-glsl@1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): dependencies: - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.60.0) esbuild: 0.27.4 vite-plugin-turbosnap@1.0.3: {} - vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0): + vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0): dependencies: esbuild: 0.27.4 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.8 - rollup: 4.59.0 + rollup: 4.60.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.12.0 fsevents: 2.3.3 sass: 1.98.0 - terser: 5.46.0 + terser: 5.46.1 tsx: 4.21.0 - vitest-fetch-mock@0.4.5(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))): + vitest-fetch-mock@0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): dependencies: - vitest: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) - vitest-websocket-mock@0.5.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0))): + vitest-websocket-mock@0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): dependencies: '@vitest/utils': 3.2.4 mock-socket: 9.3.1 - vitest: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) - vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)): + vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): dependencies: - '@vitest/expect': 4.1.0 - '@vitest/mocker': 4.1.0(msw@2.12.10(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0)) - '@vitest/pretty-format': 4.1.0 - '@vitest/runner': 4.1.0 - '@vitest/snapshot': 4.1.0 - '@vitest/spy': 4.1.0 - '@vitest/utils': 4.1.0 + '@vitest/expect': 4.1.1 + '@vitest/mocker': 4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@vitest/pretty-format': 4.1.1 + '@vitest/runner': 4.1.1 + '@vitest/snapshot': 4.1.1 + '@vitest/spy': 4.1.1 + '@vitest/utils': 4.1.1 es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -22050,12 +22064,12 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.12.0 - happy-dom: 20.8.4(bufferutil@4.1.0)(utf-8-validate@6.0.6) + happy-dom: 20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6) jsdom: 27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - msw @@ -22090,7 +22104,7 @@ snapshots: vue-component-type-helpers@2.2.12: {} - vue-component-type-helpers@3.2.5: {} + vue-component-type-helpers@3.2.6: {} vue-demi@0.14.10(vue@3.5.30(typescript@5.9.3)): dependencies: @@ -22128,10 +22142,10 @@ snapshots: dependencies: vue: 3.5.30(typescript@5.9.3) - vue-tsc@3.2.5(typescript@5.9.3): + vue-tsc@3.2.6(typescript@5.9.3): dependencies: '@volar/typescript': 2.4.28 - '@vue/language-core': 3.2.5 + '@vue/language-core': 3.2.6 typescript: 5.9.3 vue@3.5.30(typescript@5.9.3): @@ -22323,7 +22337,7 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 - ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): + ws@8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): optionalDependencies: bufferutil: 4.1.0 utf-8-validate: 6.0.6 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 79a27c7b0d6..9d43518ff6d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -35,5 +35,3 @@ ignorePatchFailures: false minimumReleaseAge: 10080 # delay 7days to mitigate supply-chain attack minimumReleaseAgeExclude: - '@syuilo/aiscript' - - 'tar' # 脆弱性対応 ����消� - - 'fastify' # 脆弱性対応 ����消� diff --git a/scripts/changelog-checker/package.json b/scripts/changelog-checker/package.json index 69a31a92a3b..50f88ffc955 100644 --- a/scripts/changelog-checker/package.json +++ b/scripts/changelog-checker/package.json @@ -11,7 +11,7 @@ "devDependencies": { "@types/mdast": "4.0.4", "@types/node": "24.12.0", - "@vitest/coverage-v8": "4.1.0", + "@vitest/coverage-v8": "4.1.1", "mdast-util-to-string": "4.0.0", "remark": "15.0.1", "remark-parse": "11.0.0", @@ -19,6 +19,6 @@ "unified": "11.0.5", "vite": "7.3.1", "vite-node": "5.3.0", - "vitest": "4.1.0" + "vitest": "4.1.1" } } From 5361a3819b38c5991308d94e01dc7375454d8988 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 14:43:34 +0900 Subject: [PATCH 003/578] =?UTF-8?q?fix(backend):=20/api-doc=20=E3=81=AB?= =?UTF-8?q?=E3=82=A2=E3=82=AF=E3=82=BB=E3=82=B9=E3=81=A7=E3=81=8D=E3=81=AA?= =?UTF-8?q?=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1726?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial plan * fix: fix /api-doc returning 404 after backend minification (#17266) Agent-Logs-Url: https://github.com/misskey-dev/misskey/sessions/8d7d0585-55da-412f-a8ee-dde1b6565026 Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> * enhance: API Doc�HTMLをJSX�生��るよ�� * Update Changelog * chore: remove unused imports [ci skip] --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> --- CHANGELOG.md | 2 +- packages/backend/assets/api-doc.html | 20 -------------- packages/backend/assets/api-doc.png | Bin 5542 -> 0 bytes .../api/openapi/OpenApiServerService.ts | 7 ++--- .../src/server/api/openapi/api-doc.tsx | 26 ++++++++++++++++++ 5 files changed, 30 insertions(+), 25 deletions(-) delete mode 100644 packages/backend/assets/api-doc.html delete mode 100644 packages/backend/assets/api-doc.png create mode 100644 packages/backend/src/server/api/openapi/api-doc.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 051b68c239c..1f52942914d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - ### Server -- +- Fix: `/api-doc` �アクセス�����題を修正 ## 2026.3.2 diff --git a/packages/backend/assets/api-doc.html b/packages/backend/assets/api-doc.html deleted file mode 100644 index 19e0349d47d..00000000000 --- a/packages/backend/assets/api-doc.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - Misskey API - - - - - - - - - diff --git a/packages/backend/assets/api-doc.png b/packages/backend/assets/api-doc.png deleted file mode 100644 index 9b07f1f39805081b6a407095d8c13fbf2805825d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5542 zcmb_f2UHW=)}GKpS9(XPv;;yYp(sd;2uklr3lNYNBTb|#NR=W;s8Usm(mM#KGy$bZ z2N4j33*kZ(K~Uas+kf9%>woM0|9WR;pS{o7-#)XynKh@xT`|&Qpyj3o0Du9luWbSV zkYLabq9zAxfjt~Qs3_bu4K)Fv<{sUV6Xi*_i@u2=0ECM4NnAr~YnlbkZsjgS6${YoUU(et14HN;?bJK|OyZHpD-$W>@HL0YmpYfn ze@+CUvVz>6-Nx5(IyJEweRNzV+*G~ou0EWgKJ3ZMc-A3vUyn9eoa-u1GJ1iE(anJt znR8S9rsPeI_jOM+;y*8IWyzE!v?pf-7aSvUvm4ULir78BpqL_SHjRQPj~}wm*4gN7TIYTq^F?LyTjPPzP5MsL%V@tbvmp65EK@0u-x%!F@jf1xG8^`SGQReV z!ecaZRfr?)wb8HF=ed7$Gv9-~W4YZDEJNHKU9-nCZ18uZvORy+{OYQv)^t-%Mm6Cu zwE94$!gnieIxKa#;$F^_B=?=+wH1=}+9%)9iF&CwN2dwryd;E+4!Etm)ns-|_C-jy zmIbebK#E7)tcC6v?pgOiR@hB(@7AiAr5QcS^OXV*uFO1hZ6B+~a6!V{LHUzwX!(*xXqarMOwfo3hV0IDu!O-4)yz8jwG5U;T zb*k)Zmhd$Ana(Dz$_p(*B!Bftk9yHF^#x)svji^<{YRDSYMBQPah+~elv!(~rW)|; zBY1t%{eF5YFG$(JOp!s+z_{jcfoXBD?X9u{ZTDh(i>5$Q2u7^f{AOEIOWuyT;d9{FGhLtNKIR8J9xCaQFAcjHITE&nTS#P?viy5Gf(iK3@!Kil8j@2sxcONS7vkO>^c24 z3Ev=7Hc}X=u%}&YeG2tSOqB%2P$pPd_pm6PsC_^sw{jm%WUHE5Gn09)-HB z$vg9Ag!!((nY0OKVrDG*HYcdP4LUf5hV7qHZmU-$ycGjV)*|z2a2em=vjG!Qf)3PN zwQYdYsg{iFmc1g8I~h7b&kts7Ef`v81vPw2zs}jLWD=|Qd2WAPzu|cn>2BXq3|}I& zTn@K8bZ_jDwOk%&*x~(ZCq1+KvIjeH3DfXlyP)jj)?7V#kLyt#>^I>AWo_K%AHb0gd<2Pq_ZTyI%#iR z+A~LP#j#o6>O))y!=Mko5A#|PYCfeB`q(A^WvVFOr)#6ulQt4!4*`Hv>=-Mw8yYPM zP=hc~AQS)uw1UA3@`oJ+w#gvmz{#BJ0}3~U@;3|~w0ZupLqS^{#GJ&Q;AA0W06nO| z2^f$AZB|gHfKmbq^=}t5Xq}+{)Ou*cD*|%TvIuD13&6bhxGp{Av0WuT{{qvv8~ImODyeTJWpo0nHWL|RNh z2qw(SE3Pa7L&z#9D4Y>Ps;kJUNy{t9oeTn@p`oFtqvvE`;FJ^O6_oowm*Xygi5f75 zfMkULGA0N)6Xf_Ma0bki67pO5oeJ0{Bd4IGf>P7a(t&`6(kLLj$5 zKS04m$t)1Hz-{Z&NX85c!E%g({c#VvYPOk6@zK~YIr z1&O+#t)r`_kG^PXW^Q3=Wo_f)ig9!Iz3C};v@67&%7Zb>fjDmuk0(!y=LKb*JoQZ-`P?m~W(-`XH&mtrjNzJO2 zT3FLfBP?(7E1NTJl$KpY;e+VT3ANvt{b$6Y{$I@gBKAMLW&wI~2>9{HnSgV^!OwW{ zhh+a1k$O1J{{B$BZx8R55v{*l-a={M;xv~*p)4#WLOuE3vC;XE(T~@?EN7QlR1IXxakY(W)wZwCJUH zr7NE!^WLhG{p_&mYpBeolBcMD|Nf+1bS&dB) zMe*W5QT&!7PY`^~Ud?7^v)b*Bs{zL1esmPk$U06~MI8LIU)d$0s6lbNuHpLt zg^*aP^3Y?lvfVyWR(kQ?-v^ajS9H3=YJ8sZ--$0ad}sN&sg+_!=`qk3|HIHu`Rq*& z&sFXOTN^cFTbs(trv;u?5m~}p^lg1Ag8pw*+{j}bv79YB#CnJ>TzgbshuH;?8{$M!T%p*?4C9*$%_v zs~3?vgC)iUrYur^?IT~i6*dNs_)BSXW=a8mHgoH<=k?Ql*74J41Cb(iYIldwVpHS~ z0eVxJXHFAU?G+tj2GWIlhLlBfaz23jH&t>ME}qCfjS}-9SF1A1AQOyfI`5sRrYS6R zSFzYD@KL{Tj4hA2{yqNC3bn|BM0PsKEr%9K&g8)mQ)~d+dmPU_I%^L`AKxv8K?lis zYzq2%#-ZwygR*J11p3FElFGuXY`t#jR|y{jxqWU&#tCxh*7qFJ_Zmqk^0am6>5e}2 z70tK)5MzrR8q`cSBTV;2K^M@@D-Y*^^+;Wb;v_DIS)>7*U{%rOJHGd2a5wfWQdpJIQ&JT(;I5yJE%(eIuZk_Z^5P%qRqJI6e2Y;D}|d3{atsP98;qF0m|EQu^?ny1ssJdQ~Gl(=N#p){l8-+Z)- z@}54=qm@hi9QIAKzfWC9{FRT=jQXorndN%}{MN$g0EVv`yNsF~wg=W2$)Z^cJWz1xZ3mWK2%ms}6fF%a0I}3Le z6TEId7VC(glnS2mYK~n^igf1O>;}?a_iSB(K)g(P`D8Tn2bU)or_A%JoHH#u?xLCd z*IP1NM#flGF0}d2-%e_WTnsA7G3?YYb`KW|c*mt;Vd3(HmPR9j#dsF{%S+A?Wp;}* zu2U|=XK&hg>iCN0Rc1~xzWF4OQm=X5zKt9cc{uZ$f4cADt15f1pH|^r&r308XzK@j zQSstWIE{5!fj`A!@4+#^FZES1+HzAdcvC1y+y62h-=baD2iwE0C~B1@Qgp9o*DIZw z_=}&{VML7qSQF2RZt|j=ZaU|puy;q0m`WGXPfBe+*6?P(tM}Ot-Y*>uSuG>jLvhC0 z@(tIcqd4~lez~#{CS;Ixwtl=)xUQa{HL!-rb|-hitpXaZ{nHgM99J#al;L>h4tHZ=cM@S`8~H z_B0)+=yh689WQeJ!KbmWOXw^qZxUf0=b zH=E=N8JIHzF_g4K%G`n+m95C!_3$2@568fFGSBdRg?q<9qKS#V4=jIiY-2}yY&gC> zAdtC@Ojp>7P#_ZWSopolwyD>dU7qLQ!ax8Q2D_hC&-k>&8XD_jM*4;lRy0*zy1 z{Ak*J)qp2ms@F|tgJNc2iI&+`*+DC2F;;H7dO+lw^cc^67_r9>hej6X*&*=?W1N^K zD%BFNYU}KAFJGnz#$WxTH1^ITA?RLYNkeP?;D%I%bw1a!mX($=5+`BYt5jKs7!bXeRh(B6kC;F3ug7Vp>zX%~ zBu?uJFsx97&NH^~(ns6Pw~mxbmwzX85M-_j46_7ZgV?v}&U@QGmmZDah>(4So!O6n zdk||jUecVJRecjZIhTe;+9x)zM--m#3w!C>=(v1s&MPD%(ZT%A*Wq047ztnbhi+Yz z$)`kCj$}<2If+E+%FNM`GTA4uRrQsP(z;m&Qr^o7Muy41Xz8L$A92`^IVWqB?y=`c z{vh8;jUW&m-Ee*>O2fV@F=jnJ1lvBLxc}(TesDpdciEucdtAbx@WrKq`?BU6!0Jx!(hA$_QOl8m zk2+Nst`wNGkjiEsGNkrK({Lxp7mueC(IRQ+vsJ8StgOa5z<)!+k7oeiQ>kp=fkPCp zV}*Bh!edY_I1H$MJDtK2a&S3$vy(Hb915W1`?_M?g8%n`citEy zFo65y378k2~H2kd;GRer6C0`dR+jZ;5pU-SW!Hq1wbK(9QLi+tk+$ALxX` Y0Dn85KUKh91VI2=$4L9BmSfaE0N>yk1ONa4 diff --git a/packages/backend/src/server/api/openapi/OpenApiServerService.ts b/packages/backend/src/server/api/openapi/OpenApiServerService.ts index f124aa9f39e..24fc46e4ba5 100644 --- a/packages/backend/src/server/api/openapi/OpenApiServerService.ts +++ b/packages/backend/src/server/api/openapi/OpenApiServerService.ts @@ -3,16 +3,14 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { fileURLToPath } from 'node:url'; import { Inject, Injectable } from '@nestjs/common'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import { genOpenapiSpec } from './gen-spec.js'; +import { ApiDocPage } from './api-doc.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; -const staticAssets = fileURLToPath(new URL('../../../../assets/', import.meta.url)); - @Injectable() export class OpenApiServerService { constructor( @@ -25,7 +23,8 @@ export class OpenApiServerService { public createServer(fastify: FastifyInstance, _options: FastifyPluginOptions, done: (err?: Error) => void) { fastify.get('/api-doc', async (_request, reply) => { reply.header('Cache-Control', 'public, max-age=86400'); - return await reply.sendFile('/api-doc.html', staticAssets); + reply.type('text/html; charset=utf-8'); + reply.send(await ApiDocPage()); }); fastify.get('/api.json', (_request, reply) => { reply.header('Cache-Control', 'public, max-age=600'); diff --git a/packages/backend/src/server/api/openapi/api-doc.tsx b/packages/backend/src/server/api/openapi/api-doc.tsx new file mode 100644 index 00000000000..663d9f5be3f --- /dev/null +++ b/packages/backend/src/server/api/openapi/api-doc.tsx @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export function ApiDocPage() { + return ( + <> + {''} + + + + Misskey API + + + + + + + + + + ); +} From e601fcb729445c3d20ac6e0447e0143348491a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:05:57 +0900 Subject: [PATCH 004/578] deps: Update vite to v8 (#17238) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * deps: Update vite to v8 * fix * migrate some plugins to rolldown-based * fix broken lockfile * wip * update rolldown * override rolldown version * perf * spdx * fix * update vite to 8.0.1 * chore: rewrite rollup-plugin-unwind-css-module-class-name with MagicString * format * swap type definitions * replace using MagicString * provided magicString * fix code style * fix * fix * fix * fix * fix --------- Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> * fix: lint fixes * swap sass with sass-embedded * fix lint * fix: インライン化�れ�Vue SFC出力�対��CSS Module定義削除�効����を修正 * fix * fix: �ックエンド�CSS読�込��方法�悪��を修正 * fix: 使用�れ��preloadを削除 * fix lint [ci skip] * Apply suggestion from @syuilo * Add comment in pnpm-workspace.yaml [ci skip] * update vite/rolldown * remove magic-string --------- Co-authored-by: cm-ayf Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- packages/backend/package.json | 2 +- .../locale-inliner/collect-modifications.ts | 22 +- packages/frontend-builder/package.json | 5 +- .../rollup-plugin-remove-unref-i18n.ts | 27 +- packages/frontend-embed/build.ts | 2 +- .../vite-plugin-json5.ts} | 7 +- packages/frontend-embed/package.json | 5 +- packages/frontend-embed/vite.config.ts | 27 +- ...lugin-unwind-css-module-class-name.test.ts | 347 ++++--- ...lup-plugin-unwind-css-module-class-name.ts | 351 +++---- .../lib/vite-plugin-create-search-index.ts | 39 +- .../vite-plugin-json5.ts} | 7 +- .../frontend/lib/vite-plugin-watch-locales.ts | 6 +- packages/frontend/package.json | 16 +- packages/frontend/vite.config.ts | 40 +- pnpm-lock.yaml | 853 +++++++++++++++--- 16 files changed, 1287 insertions(+), 469 deletions(-) rename packages/frontend-embed/{vite.json5.ts => lib/vite-plugin-json5.ts} (90%) rename packages/frontend/{vite.json5.ts => lib/vite-plugin-json5.ts} (90%) diff --git a/packages/backend/package.json b/packages/backend/package.json index 6b2e76480b2..40d963f3c7a 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -228,6 +228,6 @@ "pid-port": "2.1.0", "simple-oauth2": "5.1.0", "supertest": "7.2.2", - "vite": "7.3.1" + "vite": "8.0.2" } } diff --git a/packages/frontend-builder/locale-inliner/collect-modifications.ts b/packages/frontend-builder/locale-inliner/collect-modifications.ts index 59e5d965172..2e92a407c90 100644 --- a/packages/frontend-builder/locale-inliner/collect-modifications.ts +++ b/packages/frontend-builder/locale-inliner/collect-modifications.ts @@ -3,10 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { parseAst } from 'vite'; +import { parseAst } from 'rolldown/parseAst'; import * as estreeWalker from 'estree-walker'; import { assertNever, assertType } from '../utils.js'; -import type { AstNode, ProgramNode } from 'rollup'; +import type { ESTree as RolldownESTree } from 'rolldown/utils'; +import type { AstNode } from 'rollup'; import type * as estree from 'estree'; import type { LocaleInliner, TextModification } from '../locale-inliner.js'; import type { Logger } from '../logger.js'; @@ -17,7 +18,7 @@ interface WalkerContext { } export function collectModifications(sourceCode: string, fileName: string, fileLogger: Logger, inliner: LocaleInliner): TextModification[] { - let programNode: ProgramNode; + let programNode: RolldownESTree.Program; try { programNode = parseAst(sourceCode); } catch (err) { @@ -35,7 +36,8 @@ export function collectModifications(sourceCode: string, fileName: string, fileL // 1) replace all `scripts/` path literals with locale code // 2) replace all `localStorage.getItem("lang")` with `localeName` variable // 3) replace all `await window.fetch(`/assets/locales/${d}.${x}.json`).then(u=>u.json())` with `localeJson` variable - estreeWalker.walk(programNode, { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (estreeWalker.walk as any)(programNode, { enter(this: WalkerContext, node: Node) { assertType(node); @@ -118,8 +120,9 @@ export function collectModifications(sourceCode: string, fileName: string, fileL // Check if the identifier is already declared in the file. // If it is, we may overwrite it and cause issues so we skip inlining let isSupported = true; - estreeWalker.walk(programNode, { - enter(node) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (estreeWalker.walk as any)(programNode, { + enter(node: Node) { if (node.type === 'VariableDeclaration') { assertType(node); for (const id of node.declarations.flatMap(x => declsOfPattern(x.id))) { @@ -145,8 +148,9 @@ export function collectModifications(sourceCode: string, fileName: string, fileL const toSkip = new Set(); toSkip.add(i18nImport); - estreeWalker.walk(programNode, { - enter(this: WalkerContext, node, parent, property) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (estreeWalker.walk as any)(programNode, { + enter(this: WalkerContext, node: Node, parent: Node | null, property: string | number | symbol | null | undefined) { assertType(node); assertType(parent); if (toSkip.has(node)) { @@ -379,7 +383,7 @@ type SpecifierResult = | { type: 'specifier', localI18nIdentifier: string, importNode: estree.ImportDeclaration & AstNode } ; -function findImportSpecifier(programNode: ProgramNode, i18nFileName: string, i18nSymbol: string): SpecifierResult { +function findImportSpecifier(programNode: RolldownESTree.Program, i18nFileName: string, i18nSymbol: string): SpecifierResult { const imports = programNode.body.filter(x => x.type === 'ImportDeclaration'); const importNode = imports.find(x => x.source.value === `./${i18nFileName}`) as estree.ImportDeclaration | undefined; if (!importNode) return { type: 'no-import' }; diff --git a/packages/frontend-builder/package.json b/packages/frontend-builder/package.json index f4326907d20..28bcc47d632 100644 --- a/packages/frontend-builder/package.json +++ b/packages/frontend-builder/package.json @@ -17,9 +17,10 @@ "rollup": "4.60.0" }, "dependencies": { - "i18n": "workspace:*", "estree-walker": "3.0.3", + "i18n": "workspace:*", "magic-string": "0.30.21", - "vite": "7.3.1" + "rolldown": "1.0.0-rc.11", + "vite": "8.0.2" } } diff --git a/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts b/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts index 4a2bfa67d97..6ff62b8f773 100644 --- a/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts +++ b/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts @@ -4,11 +4,11 @@ */ import * as estreeWalker from 'estree-walker'; -import MagicString from 'magic-string'; +import { RolldownMagicString } from 'rolldown'; import { assertType } from './utils.js'; +import type { ESTree } from 'rolldown/utils'; import type { Plugin } from 'vite'; -import type { CallExpression, Expression, Program } from 'estree'; -import type { AstNode } from 'rollup'; +import type { CallExpression, Expression } from 'estree'; // This plugin transforms `unref(i18n)` to `i18n` in the code, which is useful for removing unnecessary unref calls // and helps locale inliner runs after vite build to inline the locale data into the final build. @@ -23,12 +23,13 @@ export function pluginRemoveUnrefI18n( } = {}): Plugin { return { name: 'UnwindCssModuleClassName', - renderChunk(code) { + renderChunk(code, _chunk, _options, meta) { if (!code.includes('unref(i18n)')) return null; - const ast = this.parse(code) as Program; - const magicString = new MagicString(code); - estreeWalker.walk(ast, { - enter(node) { + const ast = this.parse(code); + const magicString = meta.magicString ?? new RolldownMagicString(code); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (estreeWalker.walk as any)(ast, { + enter(node: ESTree.Node) { if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === 'unref' && node.arguments.length === 1) { // calls to unref with single argument @@ -36,18 +37,16 @@ export function pluginRemoveUnrefI18n( if (arg.type === 'Identifier' && arg.name === i18nSymbolName) { // this is unref(i18n) so replace it with i18n // to replace, remove the 'unref(' and the trailing ')' - assertType(node); - assertType(arg); + assertType(node); + assertType(arg); magicString.remove(node.start, arg.start); magicString.remove(arg.end, node.end); } } }, }); - return { - code: magicString.toString(), - map: magicString.generateMap({ hires: true }), - }; + + return magicString; }, }; } diff --git a/packages/frontend-embed/build.ts b/packages/frontend-embed/build.ts index 4e1f5888028..0b4058f33a7 100644 --- a/packages/frontend-embed/build.ts +++ b/packages/frontend-embed/build.ts @@ -3,7 +3,7 @@ import url from 'node:url'; import path from 'node:path'; import { execa } from 'execa'; import locales from 'i18n'; -import { LocaleInliner } from '../frontend-builder/locale-inliner.js' +import { LocaleInliner } from '../frontend-builder/locale-inliner.js'; import { createLogger } from '../frontend-builder/logger'; // requires node 21 or later diff --git a/packages/frontend-embed/vite.json5.ts b/packages/frontend-embed/lib/vite-plugin-json5.ts similarity index 90% rename from packages/frontend-embed/vite.json5.ts rename to packages/frontend-embed/lib/vite-plugin-json5.ts index 87b67c21424..921324b67a4 100644 --- a/packages/frontend-embed/vite.json5.ts +++ b/packages/frontend-embed/lib/vite-plugin-json5.ts @@ -1,7 +1,10 @@ -// Original: https://github.com/rollup/plugins/tree/8835dd2aed92f408d7dc72d7cc25a9728e16face/packages/json +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ import JSON5 from 'json5'; -import { Plugin } from 'rollup'; +import { Plugin } from 'vite'; import { createFilter, dataToEsm } from '@rollup/pluginutils'; import { RollupJsonOptions } from '@rollup/plugin-json'; diff --git a/packages/frontend-embed/package.json b/packages/frontend-embed/package.json index fa5ba3038e3..3bb8e00d59d 100644 --- a/packages/frontend-embed/package.json +++ b/packages/frontend-embed/package.json @@ -12,7 +12,6 @@ "dependencies": { "@discordapp/twemoji": "16.0.1", "@rollup/plugin-json": "6.1.0", - "@rollup/plugin-replace": "6.0.3", "@rollup/pluginutils": "5.3.0", "@twemoji/parser": "16.0.0", "@vitejs/plugin-vue": "6.0.5", @@ -26,11 +25,9 @@ "misskey-js": "workspace:*", "punycode.js": "2.3.1", "rollup": "4.60.0", - "sass": "1.98.0", "shiki": "3.23.0", "tinycolor2": "1.6.0", "uuid": "13.0.0", - "vite": "7.3.1", "vue": "3.5.30" }, "devDependencies": { @@ -57,8 +54,10 @@ "msw": "2.12.14", "nodemon": "3.1.14", "prettier": "3.8.1", + "sass-embedded": "1.98.0", "start-server-and-test": "2.1.5", "tsx": "4.21.0", + "vite": "8.0.2", "vite-plugin-turbosnap": "1.0.3", "vue-component-type-helpers": "3.2.6", "vue-eslint-parser": "10.4.0", diff --git a/packages/frontend-embed/vite.config.ts b/packages/frontend-embed/vite.config.ts index 9e5c24f9d4d..7f5be591e88 100644 --- a/packages/frontend-embed/vite.config.ts +++ b/packages/frontend-embed/vite.config.ts @@ -7,10 +7,10 @@ import { promises as fsp } from 'fs'; import locales from 'i18n'; import meta from '../../package.json'; import packageInfo from './package.json' with { type: 'json' }; -import pluginJson5 from './vite.json5.js'; +import pluginJson5 from './lib/vite-plugin-json5.js'; import { pluginRemoveUnrefI18n } from '../frontend-builder/rollup-plugin-remove-unref-i18n'; -const url = process.env.NODE_ENV === 'development' ? yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')).url : null; +const url = process.env.NODE_ENV === 'development' ? (yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')) as any).url : null; const host = url ? (new URL(url)).hostname : undefined; const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue']; @@ -113,11 +113,6 @@ export function getConfig(): UserConfig { } }, }, - preprocessorOptions: { - scss: { - api: 'modern-compiler', - }, - }, }, define: { @@ -137,7 +132,10 @@ export function getConfig(): UserConfig { 'safari16', ], manifest: 'manifest.json', - rollupOptions: { + rolldownOptions: { + experimental: { + nativeMagicString: true, + }, input: { i18n: './src/i18n.ts', entry: './src/boot.ts', @@ -145,10 +143,15 @@ export function getConfig(): UserConfig { external: externalPackages.map(p => p.match), preserveEntrySignatures: 'allow-extension', output: { - manualChunks: { - vue: ['vue'], - // dependencies of i18n.ts - 'config': ['@@/js/config.js'], + codeSplitting: { + groups: [{ + name: 'vue', + test: /node_modules[\\/]vue/, + }, { + // dependencies of i18n.ts + name: 'config', + test: /@@[\\/]js[\\/]config\.js/, + }], }, entryFileNames: `scripts/${localesHash}-[hash:8].js`, chunkFileNames: `scripts/${localesHash}-[hash:8].js`, diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts index ccfa08575bd..0a5000f46d5 100644 --- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts @@ -3,15 +3,15 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { parse } from 'acorn'; -import { generate } from 'astring'; import { describe, expect, it } from 'vitest'; import { normalizeClass, unwindCssModuleClassName } from './rollup-plugin-unwind-css-module-class-name.js'; -import type * as estree from 'estree'; +import { parseAst } from 'rolldown/parseAst'; +import type { ESTree } from 'rolldown/utils'; +import { RolldownMagicString } from 'rolldown'; -function parseExpression(code: string): estree.Expression { - const program = parse(code, { ecmaVersion: 'latest', sourceType: 'module' }) as unknown as estree.Program; - const statement = program.body[0] as estree.ExpressionStatement; +function parseExpression(code: string): ESTree.Expression { + const program = parseAst(code, { sourceType: 'module' }); + const statement = program.body[0] as ESTree.ExpressionStatement; return statement.expression; } @@ -57,7 +57,7 @@ describe(normalizeClass.name, () => { }); it('Composition API (standard)', () => { - const ast = parse(` + const code = ` import { c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js'; import { M as MkContainer } from './MkContainer-!~{03M}~.js'; import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js'; @@ -170,17 +170,19 @@ const cssModules = { const index_photos = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); export { index_photos as default }; -`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); - unwindCssModuleClassName(ast); - expect(generate(ast)).toBe(` -import {c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc} from './app-!~{001}~.js'; -import {M as MkContainer} from './MkContainer-!~{03M}~.js'; -import {b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode} from './vue-!~{002}~.js'; +`.slice(1); + const ast = parseAst(code, { sourceType: 'module' }); + const magicString = new RolldownMagicString(code); + unwindCssModuleClassName(ast, magicString); + expect(magicString.toString()).toBe( + ` +import { c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js'; +import { M as MkContainer } from './MkContainer-!~{03M}~.js'; +import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js'; import './photoswipe-!~{003}~.js'; -const _hoisted_1 = createBaseVNode("i", { - class: "ti ti-photo" -}, null, -1); -const index_photos = defineComponent({ + +const _hoisted_1 = /* @__PURE__ */ createBaseVNode("i", { class: "ti ti-photo" }, null, -1); +const index_photos = /* @__PURE__ */ defineComponent({ __name: "index.photos", props: { user: {} @@ -193,12 +195,20 @@ const index_photos = defineComponent({ return store.s.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; } onMounted(() => { - const image = ["image/jpeg", "image/webp", "image/avif", "image/png", "image/gif", "image/apng", "image/vnd.mozilla.apng"]; + const image = [ + "image/jpeg", + "image/webp", + "image/avif", + "image/png", + "image/gif", + "image/apng", + "image/vnd.mozilla.apng" + ]; api("users/notes", { userId: props.user.id, fileType: image, limit: 10 - }).then(notes => { + }).then((notes) => { for (const note of notes) { for (const file of note.files) { images.value.push({ @@ -213,60 +223,77 @@ const index_photos = defineComponent({ return (_ctx, _cache) => { const _component_MkLoading = resolveComponent("MkLoading"); const _component_MkA = resolveComponent("MkA"); - return (openBlock(), createBlock(MkContainer, { + return openBlock(), createBlock(MkContainer, { "max-height": 300, foldable: true }, { - icon: withCtx(() => [_hoisted_1]), - header: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).ts.images), 1)]), - default: withCtx(() => [createBaseVNode("div", { - class: "xenMW" - }, [unref(fetching) ? (openBlock(), createBlock(_component_MkLoading, { - key: 0 - })) : createCommentVNode("", true), !unref(fetching) && unref(images).length > 0 ? (openBlock(), createElementBlock("div", { - key: 1, - class: "xaZzf" - }, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(images), image => { - return (openBlock(), createBlock(_component_MkA, { - key: image.note.id + image.file.id, - class: "xtA8t", - to: unref(notePage)(image.note) - }, { - default: withCtx(() => [createVNode(ImgWithBlurhash, { - hash: image.file.blurhash, - src: thumbnail(image.file), - title: image.file.name - }, null, 8, ["hash", "src", "title"])]), - _: 2 - }, 1032, ["class", "to"])); - }), 128))], 2)) : createCommentVNode("", true), !unref(fetching) && unref(images).length == 0 ? (openBlock(), createElementBlock("p", { - key: 2, - class: "xhYKj" - }, toDisplayString(unref(i18n).ts.nothing), 3)) : createCommentVNode("", true)], 2)]), + icon: withCtx(() => [ + _hoisted_1 + ]), + header: withCtx(() => [ + createTextVNode(toDisplayString(unref(i18n).ts.images), 1) + ]), + default: withCtx(() => [ + createBaseVNode("div", { + class: "xenMW" + }, [ + unref(fetching) ? (openBlock(), createBlock(_component_MkLoading, { key: 0 })) : createCommentVNode("", true), + !unref(fetching) && unref(images).length > 0 ? (openBlock(), createElementBlock("div", { + key: 1, + class: "xaZzf" + }, [ + (openBlock(true), createElementBlock(Fragment, null, renderList(unref(images), (image) => { + return openBlock(), createBlock(_component_MkA, { + key: image.note.id + image.file.id, + class: "xtA8t", + to: unref(notePage)(image.note) + }, { + default: withCtx(() => [ + createVNode(ImgWithBlurhash, { + hash: image.file.blurhash, + src: thumbnail(image.file), + title: image.file.name + }, null, 8, ["hash", "src", "title"]) + ]), + _: 2 + }, 1032, ["class", "to"]); + }), 128)) + ], 2)) : createCommentVNode("", true), + !unref(fetching) && unref(images).length == 0 ? (openBlock(), createElementBlock("p", { + key: 2, + class: "xhYKj" + }, toDisplayString(unref(i18n).ts.nothing), 3)) : createCommentVNode("", true) + ], 2) + ]), _: 1 - })); + }); }; } }); + const root = "xenMW"; const stream = "xaZzf"; const img = "xtA8t"; const empty = "xhYKj"; const style0 = { - root: root, - stream: stream, - img: img, - empty: empty + root: root, + stream: stream, + img: img, + empty: empty }; + const cssModules = { "$style": style0 }; -export {index_photos as default}; -`.slice(1)); + + +export { index_photos as default }; +`.slice(1), + ); }); it('Composition API (with `useCssModule()`)', () => { - const ast = parse(` + const code = ` import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js'; import { d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js'; @@ -437,11 +464,15 @@ const cssModules = { const MkDateSeparatedList = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); export { MkDateSeparatedList as M }; -`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); - unwindCssModuleClassName(ast); - expect(generate(ast)).toBe(` -import {a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup} from './!~{002}~.js'; -import {d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc} from './app-!~{001}~.js'; +`.slice(1); + const ast = parseAst(code, { sourceType: 'module' }); + const magicString = new RolldownMagicString(code); + unwindCssModuleClassName(ast, magicString); + expect(magicString.toString()).toBe( + ` +import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js'; +import { d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js'; + function isDebuggerEnabled(id) { try { return localStorage.getItem(\`DEBUG_\${id}\`) !== null; @@ -458,6 +489,7 @@ function stackTraceInstances() { } return stack; } + const _sfc_main = defineComponent({ props: { items: { @@ -485,7 +517,7 @@ const _sfc_main = defineComponent({ default: false } }, - setup(props, {slots, expose}) { + setup(props, { slots, expose }) { const $style = useCssModule(); function getDateText(time) { const date = new Date(time).getDate(); @@ -495,28 +527,40 @@ const _sfc_main = defineComponent({ day: date.toString() }); } - if (props.items.length === 0) return; + if (props.items.length === 0) + return; const renderChildrenImpl = () => props.items.map((item, i) => { - if (!slots || !slots.default) return; + if (!slots || !slots.default) + return; const el = slots.default({ item })[0]; - if (el.key == null && item.id) el.key = item.id; + if (el.key == null && item.id) + el.key = item.id; if (i !== props.items.length - 1 && new Date(item.createdAt).getDate() !== new Date(props.items[i + 1].createdAt).getDate()) { const separator = h("div", { class: $style["separator"], key: item.id + ":separator" }, h("p", { class: $style["date"] - }, [h("span", { - class: $style["date-1"] - }, [h("i", { - class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` - }), getDateText(item.createdAt)]), h("span", { - class: $style["date-2"] - }, [getDateText(props.items[i + 1].createdAt), h("i", { - class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` - })])])); + }, [ + h("span", { + class: $style["date-1"] + }, [ + h("i", { + class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` + }), + getDateText(item.createdAt) + ]), + h("span", { + class: $style["date-2"] + }, [ + getDateText(props.items[i + 1].createdAt), + h("i", { + class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` + }) + ]) + ])); return [el, separator]; } else { if (props.ad && item._shouldInsertAd_) { @@ -532,17 +576,13 @@ const _sfc_main = defineComponent({ const renderChildren = () => { const children = renderChildrenImpl(); if (isDebuggerEnabled(6864)) { - const nodes = children.flatMap(node => node ?? []); - const keys = new Set(nodes.map(node => node.key)); + const nodes = children.flatMap((node) => node ?? []); + const keys = new Set(nodes.map((node) => node.key)); if (keys.size !== nodes.length) { const id = crypto.randomUUID(); const instances = stackTraceInstances(); toast(instances.reduce((a, c) => \`\${a} at \${c.type.name}\`, \`[DEBUG_6864 (\${id})]: \${nodes.length - keys.size} duplicated keys found\`)); - console.warn({ - id, - debugId: 6864, - stack: instances - }); + console.warn({ id, debugId: 6864, stack: instances }); } } return children; @@ -555,45 +595,136 @@ const _sfc_main = defineComponent({ el.style.top = ""; el.style.left = ""; } - return () => h(prefer.s.animation ? TransitionGroup : "div", { - class: { - [$style["date-separated-list"]]: true, - [$style["date-separated-list-nogap"]]: props.noGap, - [$style["reversed"]]: props.reversed, - [$style["direction-down"]]: props.direction === "down", - [$style["direction-up"]]: props.direction === "up" + return () => h( + prefer.s.animation ? TransitionGroup : "div", + { + class: { + [$style["date-separated-list"]]: true, + [$style["date-separated-list-nogap"]]: props.noGap, + [$style["reversed"]]: props.reversed, + [$style["direction-down"]]: props.direction === "down", + [$style["direction-up"]]: props.direction === "up" + }, + ...prefer.s.animation ? { + name: "list", + tag: "div", + onBeforeLeave, + onLeaveCanceled + } : {} }, - ...prefer.s.animation ? { - name: "list", - tag: "div", - onBeforeLeave, - onLeaveCanceled - } : {} - }, { - default: renderChildren - }); + { default: renderChildren } + ); } }); + const reversed = "xxiZh"; const separator = "xxeDx"; const date = "xxawD"; const style0 = { - "date-separated-list": "xfKPa", - "date-separated-list-nogap": "xf9zr", - "direction-up": "x7AeO", - "direction-down": "xBIqc", - reversed: reversed, - separator: separator, - date: date, - "date-1": "xwtmh", - "date-1-icon": "xsNPa", - "date-2": "x1xvw", - "date-2-icon": "x9ZiG" + "date-separated-list": "xfKPa", + "date-separated-list-nogap": "xf9zr", + "direction-up": "x7AeO", + "direction-down": "xBIqc", + reversed: reversed, + separator: separator, + date: date, + "date-1": "xwtmh", + "date-1-icon": "xsNPa", + "date-2": "x1xvw", + "date-2-icon": "x9ZiG" }; + const cssModules = { "$style": style0 }; -const MkDateSeparatedList = _export_sfc(_sfc_main, [["__cssModules", cssModules]]); -export {MkDateSeparatedList as M}; +const MkDateSeparatedList = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); + +export { MkDateSeparatedList as M }; `.slice(1)); }); + +it('Composition API (inlined output)', () => { + const code = ` +import { a as normalizeClass, b as defineComponent, c as _export_sfc } from './runtime.js'; + +const CurrentComponent = /* @__PURE__ */ _export_sfc(defineComponent({ + __name: "CurrentComponent", + setup() { + return (e, n) => h("div", { + class: normalizeClass([e.$style.root, "extra"]) + }, null, 2); + } +}), [["__cssModules", { + "$style": { + root: "x1234" + } +}]]); + +export { CurrentComponent as default }; +`.slice(1); + const ast = parseAst(code, { sourceType: 'module' }); + const magicString = new RolldownMagicString(code); + unwindCssModuleClassName(ast, magicString); + const output = magicString.toString(); + expect(output).toContain('class: "x1234 extra"'); + expect(output).toContain('defineComponent({'); + expect(output).toContain('}), []);'); + expect(output).not.toContain('$style'); +}); + +it('should keep cssModules when unresolved references remain', () => { + const code = ` +import { a as normalizeClass, b as defineComponent, c as _export_sfc } from './runtime.js'; + +const CurrentComponent = /* @__PURE__ */ _export_sfc(defineComponent({ + __name: "CurrentComponent", + setup() { + return (e, n) => h("div", { + class: normalizeClass([e.$style.root, e.$style[side]]) + }, null, 2); + } +}), [["__cssModules", { + "$style": { + root: "x1234" + } +}]]); + +export { CurrentComponent as default }; +`.slice(1); + const ast = parseAst(code, { sourceType: 'module' }); + const magicString = new RolldownMagicString(code); + unwindCssModuleClassName(ast, magicString); + const output = magicString.toString(); + expect(output).toContain('e.$style[side]'); + expect(output).toContain('__cssModules'); + expect(output).not.toContain('}), []);'); +}); + +it('should inline cssModules references used inside class expressions', () => { + const code = ` +import { a as classHelper, b as defineComponent, c as _export_sfc } from './runtime.js'; + +const CurrentComponent = /* @__PURE__ */ _export_sfc(defineComponent({ + __name: "CurrentComponent", + setup() { + return (e, n) => h("div", { + class: classHelper([e.$style.root, { [e.$style.main]: isActive }]) + }, null, 2); + } +}), [["__cssModules", { + "$style": { + root: "x1234", + main: "x5678" + } +}]]); + +export { CurrentComponent as default }; +`.slice(1); + const ast = parseAst(code, { sourceType: 'module' }); + const magicString = new RolldownMagicString(code); + unwindCssModuleClassName(ast, magicString); + const output = magicString.toString(); + expect(output).toContain('class: classHelper(["x1234", { ["x5678"]: isActive }])'); + expect(output).toContain('}), []);'); + expect(output).not.toContain('$style'); +}); diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts index 7ecb1e9179e..d82f1512fca 100644 --- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts @@ -3,17 +3,16 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { generate } from 'astring'; -import { walk } from '../node_modules/estree-walker/src/index.js'; -import type * as estree from 'estree'; -import type * as estreeWalker from 'estree-walker'; +import * as estreeWalker from 'estree-walker'; import type { Plugin } from 'vite'; +import type { ESTree } from 'rolldown/utils'; +import { RolldownMagicString } from 'rolldown'; -function isFalsyIdentifier(identifier: estree.Identifier): boolean { +function isFalsyIdentifier(identifier: Extract): boolean { return identifier.name === 'undefined' || identifier.name === 'NaN'; } -function normalizeClassWalker(tree: estree.Node, stack: string | undefined): string | null { +function normalizeClassWalker(tree: ESTree.Node, stack: string | undefined): string | null { if (tree.type === 'Identifier') return isFalsyIdentifier(tree) ? '' : null; if (tree.type === 'Literal') return typeof tree.value === 'string' ? tree.value : ''; if (tree.type === 'BinaryExpression') { @@ -26,7 +25,7 @@ function normalizeClassWalker(tree: estree.Node, stack: string | undefined): str if (tree.type === 'TemplateLiteral') { if (tree.expressions.some((x) => x.type !== 'Literal' && (x.type !== 'Identifier' || !isFalsyIdentifier(x)))) return null; return tree.quasis.reduce((a, c, i) => { - const v = i === tree.quasis.length - 1 ? '' : (tree.expressions[i] as Partial).value; + const v = i === tree.quasis.length - 1 ? '' : (tree.expressions[i] as Partial>).value; return a + c.value.raw + (typeof v === 'string' ? v : ''); }, ''); } @@ -72,44 +71,144 @@ function normalizeClassWalker(tree: estree.Node, stack: string | undefined): str tree.type !== 'ChainExpression' && tree.type !== 'ConditionalExpression' && tree.type !== 'LogicalExpression' && - tree.type !== 'MemberExpression') { + tree.type !== 'MemberExpression' + ) { console.error(stack ? `Unexpected node type: ${tree.type} (in ${stack})` : `Unexpected node type: ${tree.type}`); } return null; } -export function normalizeClass(tree: estree.Node, stack?: string): string | null { +export function normalizeClass(tree: ESTree.Node, stack?: string): string | null { const walked = normalizeClassWalker(tree, stack); return walked && walked.replace(/^\s+|\s+(?=\s)|\s+$/g, ''); } -export function unwindCssModuleClassName(ast: estree.Node): void { - (walk as typeof estreeWalker.walk)(ast, { - enter(node, parent): void { +function getPropertyName(node: ESTree.Node, computed: boolean): string | null { + if (node.type === 'Identifier') return computed ? null : node.name; + if (node.type === 'Literal' && typeof node.value === 'string') return node.value; + return null; +} + +function getMemberPropertyName(node: ESTree.MemberExpression['property'], computed: boolean): string | null { + if (node.type === 'Identifier') return computed ? null : node.name; + if (node.type === 'Literal' && typeof node.value === 'string') return node.value; + return null; +} + +function findVariableDeclaration(program: ESTree.Program, name: string): ESTree.VariableDeclaration | null { + return program.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + return x.declarations[0].id.name === name; + }) as ESTree.VariableDeclaration | null; +} + +function resolveObjectExpression(program: ESTree.Program, tree: ESTree.Expression): ESTree.ObjectExpression | null { + if (tree.type === 'ObjectExpression') return tree; + if (tree.type !== 'Identifier') return null; + const declaration = findVariableDeclaration(program, tree.name); + if (declaration?.declarations[0].init?.type !== 'ObjectExpression') return null; + return declaration.declarations[0].init; +} + +function resolveComponentOptions(program: ESTree.Program, tree: ESTree.Expression): ESTree.ObjectExpression | null { + const target = tree.type === 'Identifier' + ? findVariableDeclaration(program, tree.name)?.declarations[0].init ?? null + : tree; + if (target?.type === 'ObjectExpression') return target; + if (target?.type !== 'CallExpression') return null; + if (target.arguments.length !== 1) return null; + if (target.arguments[0].type !== 'ObjectExpression') return null; + return target.arguments[0]; +} + +function resolveModuleTree(program: ESTree.Program, tree: ESTree.Expression): Map | null { + const objectExpression = resolveObjectExpression(program, tree); + if (objectExpression === null) return null; + return new Map(objectExpression.properties.flatMap((property) => { + if (property.type !== 'Property') return []; + const actualKey = getPropertyName(property.key, property.computed); + if (actualKey === null) return []; + if (property.value.type === 'Literal') { + return typeof property.value.value === 'string' ? [[actualKey, property.value.value]] : []; + } + if (property.value.type === 'Identifier') { + const actualValue = findVariableDeclaration(program, property.value.name); + if (actualValue?.declarations[0].init?.type !== 'Literal') return []; + return typeof actualValue.declarations[0].init.value === 'string' ? [[actualKey, actualValue.declarations[0].init.value]] : []; + } + return []; + })); +} + +function resolveModuleForest(program: ESTree.Program, tree: ESTree.Expression): Map> | null { + const objectExpression = resolveObjectExpression(program, tree); + if (objectExpression === null) return null; + return new Map(objectExpression.properties.flatMap((property) => { + if (property.type !== 'Property') return []; + const actualKey = getPropertyName(property.key, property.computed); + if (actualKey === null) return []; + const moduleTree = resolveModuleTree(program, property.value); + return moduleTree === null ? [] : [[actualKey, moduleTree]]; + })); +} + +function findRenderArrow(options: ESTree.ObjectExpression): Extract | null { + const setup = options.properties.find((x) => { + if (x.type !== 'Property') return false; + return getPropertyName(x.key, x.computed) === 'setup'; + }) as Extract | undefined; + if (setup?.value.type !== 'FunctionExpression' && setup?.value.type !== 'ArrowFunctionExpression') return null; + if (setup.value.body == null) return null; + if (setup.value.body.type !== 'BlockStatement') return null; + const render = setup.value.body.body.find((x) => x.type === 'ReturnStatement'); + if (render?.type !== 'ReturnStatement') return null; + return render.argument?.type === 'ArrowFunctionExpression' ? render.argument : null; +} + +function isCssModuleAccess(node: ESTree.Node, ctxName: string, key: string): node is Extract { + if (node.type !== 'MemberExpression') return false; + if (node.object.type !== 'MemberExpression') return false; + if (node.object.object.type !== 'Identifier') return false; + if (node.object.object.name !== ctxName) return false; + return getMemberPropertyName(node.object.property, node.object.computed) === key; + } + +function isCssModuleReference(node: ESTree.Node, ctxName: string, key: string): node is Extract { + if (!isCssModuleAccess(node, ctxName, key)) return false; + return getMemberPropertyName(node.property, node.computed) !== null; +} + +function isClassProperty(node: ESTree.Node | null): node is Extract { + return node?.type === 'Property' && getPropertyName(node.key, node.computed) === 'class'; +} + +export function unwindCssModuleClassName(ast: ESTree.Node, magicString: RolldownMagicString): void { + (estreeWalker.walk as any)(ast, { + enter(node: ESTree.Node, parent: ESTree.Node | null): void { //#region if (parent?.type !== 'Program') return; + if (ast.type !== 'Program') return; if (node.type !== 'VariableDeclaration') return; if (node.declarations.length !== 1) return; if (node.declarations[0].id.type !== 'Identifier') return; const name = node.declarations[0].id.name; if (node.declarations[0].init?.type !== 'CallExpression') return; - if (node.declarations[0].init.callee.type !== 'Identifier') return; - if (node.declarations[0].init.callee.name !== '_export_sfc') return; if (node.declarations[0].init.arguments.length !== 2) return; - if (node.declarations[0].init.arguments[0].type !== 'Identifier') return; - const ident = node.declarations[0].init.arguments[0].name; - if (!ident.startsWith('_sfc_main')) return; + const componentNode = node.declarations[0].init.arguments[0]; + if (componentNode.type !== 'Identifier' && componentNode.type !== 'CallExpression' && componentNode.type !== 'ObjectExpression') return; if (node.declarations[0].init.arguments[1].type !== 'ArrayExpression') return; if (node.declarations[0].init.arguments[1].elements.length === 0) return; - const __cssModulesIndex = node.declarations[0].init.arguments[1].elements.findIndex((x) => { + const cssModulesEntry = node.declarations[0].init.arguments[1].elements.find((x) => { if (x?.type !== 'ArrayExpression') return false; if (x.elements.length !== 2) return false; if (x.elements[0]?.type !== 'Literal') return false; if (x.elements[0].value !== '__cssModules') return false; - if (x.elements[1]?.type !== 'Identifier') return false; return true; - }); - if (!~__cssModulesIndex) return; + }) as ESTree.ArrayExpression | undefined; + const __cssModulesIndex = node.declarations[0].init.arguments[1].elements.indexOf(cssModulesEntry ?? null); + if (cssModulesEntry === undefined || __cssModulesIndex < 0) return; /* This region assumeed that the entered node looks like the following code. * * ```ts @@ -118,21 +217,10 @@ export function unwindCssModuleClassName(ast: estree.Node): void { */ //#endregion //#region - const cssModuleForestName = ((node.declarations[0].init.arguments[1].elements[__cssModulesIndex] as estree.ArrayExpression).elements[1] as estree.Identifier).name; - const cssModuleForestNode = parent.body.find((x) => { - if (x.type !== 'VariableDeclaration') return false; - if (x.declarations.length !== 1) return false; - if (x.declarations[0].id.type !== 'Identifier') return false; - if (x.declarations[0].id.name !== cssModuleForestName) return false; - if (x.declarations[0].init?.type !== 'ObjectExpression') return false; - return true; - }) as unknown as estree.VariableDeclaration; - const moduleForest = new Map((cssModuleForestNode.declarations[0].init as estree.ObjectExpression).properties.flatMap((property) => { - if (property.type !== 'Property') return []; - if (property.key.type !== 'Literal') return []; - if (property.value.type !== 'Identifier') return []; - return [[property.key.value as string, property.value.name as string]]; - })); + const cssModuleForest = cssModulesEntry.elements[1]; + if (cssModuleForest?.type !== 'Identifier' && cssModuleForest?.type !== 'ObjectExpression') return; + const moduleForest = resolveModuleForest(ast, cssModuleForest); + if (moduleForest === null) return; /* This region collected a VariableDeclaration node in the module that looks like the following code. * * ```ts @@ -143,35 +231,13 @@ export function unwindCssModuleClassName(ast: estree.Node): void { */ //#endregion //#region - const sfcMain = parent.body.find((x) => { - if (x.type !== 'VariableDeclaration') return false; - if (x.declarations.length !== 1) return false; - if (x.declarations[0].id.type !== 'Identifier') return false; - if (x.declarations[0].id.name !== ident) return false; - return true; - }) as unknown as estree.VariableDeclaration; - if (sfcMain.declarations[0].init?.type !== 'CallExpression') return; - if (sfcMain.declarations[0].init.callee.type !== 'Identifier') return; - if (sfcMain.declarations[0].init.callee.name !== 'defineComponent') return; - if (sfcMain.declarations[0].init.arguments.length !== 1) return; - if (sfcMain.declarations[0].init.arguments[0].type !== 'ObjectExpression') return; - const setup = sfcMain.declarations[0].init.arguments[0].properties.find((x) => { - if (x.type !== 'Property') return false; - if (x.key.type !== 'Identifier') return false; - if (x.key.name !== 'setup') return false; - return true; - }) as unknown as estree.Property; - if (setup.value.type !== 'FunctionExpression') return; - const render = setup.value.body.body.find((x) => { - if (x.type !== 'ReturnStatement') return false; - return true; - }) as unknown as estree.ReturnStatement; - if (render.argument?.type !== 'ArrowFunctionExpression') return; - if (render.argument.params.length !== 2) return; - const ctx = render.argument.params[0]; + const options = resolveComponentOptions(ast, componentNode); + if (options === null) return; + const render = findRenderArrow(options); + if (render === null) return; + if (render.params.length !== 2) return; + const ctx = render.params[0]; if (ctx.type !== 'Identifier') return; - if (ctx.name !== '_ctx') return; - if (render.argument.body.type !== 'BlockStatement') return; /* This region assumed that `sfcMain` looks like the following code. * * ```ts @@ -186,33 +252,8 @@ export function unwindCssModuleClassName(ast: estree.Node): void { * ``` */ //#endregion - for (const [key, value] of moduleForest) { + for (const [key, moduleTree] of moduleForest) { //#region - const cssModuleTreeNode = parent.body.find((x) => { - if (x.type !== 'VariableDeclaration') return false; - if (x.declarations.length !== 1) return false; - if (x.declarations[0].id.type !== 'Identifier') return false; - if (x.declarations[0].id.name !== value) return false; - return true; - }) as unknown as estree.VariableDeclaration; - if (cssModuleTreeNode.declarations[0].init?.type !== 'ObjectExpression') return; - const moduleTree = new Map(cssModuleTreeNode.declarations[0].init.properties.flatMap((property) => { - if (property.type !== 'Property') return []; - const actualKey = property.key.type === 'Identifier' ? property.key.name : property.key.type === 'Literal' ? property.key.value : null; - if (typeof actualKey !== 'string') return []; - if (property.value.type === 'Literal') return [[actualKey, property.value.value as string]]; - if (property.value.type !== 'Identifier') return []; - const labelledValue = property.value.name; - const actualValue = parent.body.find((x) => { - if (x.type !== 'VariableDeclaration') return false; - if (x.declarations.length !== 1) return false; - if (x.declarations[0].id.type !== 'Identifier') return false; - if (x.declarations[0].id.name !== labelledValue) return false; - return true; - }) as unknown as estree.VariableDeclaration; - if (actualValue.declarations[0].init?.type !== 'Literal') return []; - return [[actualKey, actualValue.declarations[0].init.value as string]]; - })); /* This region collected VariableDeclaration nodes in the module that looks like the following code. * * ```ts @@ -226,17 +267,14 @@ export function unwindCssModuleClassName(ast: estree.Node): void { */ //#endregion //#region - (walk as typeof estreeWalker.walk)(render.argument.body, { - enter(childNode) { - if (childNode.type !== 'MemberExpression') return; - if (childNode.object.type !== 'MemberExpression') return; - if (childNode.object.object.type !== 'Identifier') return; - if (childNode.object.object.name !== ctx.name) return; - if (childNode.object.property.type !== 'Identifier') return; - if (childNode.object.property.name !== key) return; - if (childNode.property.type !== 'Identifier') return; - const actualValue = moduleTree.get(childNode.property.name); + (estreeWalker.walk as any)(render.body, { + enter(childNode: ESTree.Node) { + if (!isCssModuleReference(childNode, ctx.name, key)) return; + const actualKey = getMemberPropertyName(childNode.property, childNode.computed); + if (actualKey === null) return; + const actualValue = moduleTree.get(actualKey); if (actualValue === undefined) return; + magicString.overwrite(childNode.start, childNode.end, JSON.stringify(actualValue)); this.replace({ type: 'Literal', value: actualValue, @@ -276,20 +314,13 @@ export function unwindCssModuleClassName(ast: estree.Node): void { */ //#endregion //#region - (walk as typeof estreeWalker.walk)(render.argument.body, { - enter(childNode) { - if (childNode.type !== 'MemberExpression') return; - if (childNode.object.type !== 'MemberExpression') return; - if (childNode.object.object.type !== 'Identifier') return; - if (childNode.object.object.name !== ctx.name) return; - if (childNode.object.property.type !== 'Identifier') return; - if (childNode.object.property.name !== key) return; - if (childNode.property.type !== 'Identifier') return; - console.error(`Undefined style detected: ${key}.${childNode.property.name} (in ${name})`); - this.replace({ - type: 'Identifier', - name: 'undefined', - }); + (estreeWalker.walk as any)(render.body, { + enter(childNode: ESTree.Node) { + if (!isCssModuleReference(childNode, ctx.name, key)) return; + const actualKey = getMemberPropertyName(childNode.property, childNode.computed); + if (actualKey === null) return; + console.error(`Undefined style detected: ${key}.${actualKey} (in ${name})`); + magicString.overwrite(childNode.start, childNode.end, 'undefined'); }, }); /* This region replaced the reference identifier of missing class names in the render function with `undefined`, as in the following code. @@ -300,7 +331,7 @@ export function unwindCssModuleClassName(ast: estree.Node): void { * ... * return (_ctx, _cache) => { * ... - * return openBlock(), createElementBlock("div", { + * return openBlock(), createElementBlock('div', { * class: normalizeClass(_ctx.$style.hoge), * }, null); * }; @@ -316,7 +347,7 @@ export function unwindCssModuleClassName(ast: estree.Node): void { * ... * return (_ctx, _cache) => { * ... - * return openBlock(), createElementBlock("div", { + * return openBlock(), createElementBlock('div', { * class: normalizeClass(undefined), * }, null); * }; @@ -326,18 +357,15 @@ export function unwindCssModuleClassName(ast: estree.Node): void { */ //#endregion //#region - (walk as typeof estreeWalker.walk)(render.argument.body, { - enter(childNode) { + (estreeWalker.walk as any)(render.body, { + enter(childNode: ESTree.Node, childParent: ESTree.Node | null) { if (childNode.type !== 'CallExpression') return; - if (childNode.callee.type !== 'Identifier') return; - if (childNode.callee.name !== 'normalizeClass') return; if (childNode.arguments.length !== 1) return; + if (childNode.callee.type === 'Identifier' && childNode.callee.name !== 'normalizeClass' && !isClassProperty(childParent)) return; + if (childNode.callee.type !== 'Identifier' && !isClassProperty(childParent)) return; const normalized = normalizeClass(childNode.arguments[0], name); if (normalized === null) return; - this.replace({ - type: 'Literal', - value: normalized, - }); + magicString.overwrite(childNode.start, childNode.end, JSON.stringify(normalized)); }, }); /* This region compiled the `normalizeClass` call into a pseudo-AOT compilation, as in the following code. @@ -374,19 +402,34 @@ export function unwindCssModuleClassName(ast: estree.Node): void { */ //#endregion } - //#region - if (node.declarations[0].init.arguments[1].elements.length === 1) { - (walk as typeof estreeWalker.walk)(ast, { - enter(childNode) { - if (childNode.type !== 'Identifier') return; - if (childNode.name !== ident) return; - this.replace({ - type: 'Identifier', - name: node.declarations[0].id.name, - }); + const hasRemainingCssModuleReference = Array.from(moduleForest.keys()).some((key) => { + let found = false; + (estreeWalker.walk as any)(render.body, { + enter(childNode: ESTree.Node) { + if (!isCssModuleAccess(childNode, ctx.name, key)) return; + found = true; + this.skip(); }, }); - this.remove(); + return found; + }); + if (hasRemainingCssModuleReference) return; + //#region + if (node.declarations[0].init.arguments[1].elements.length === 1) { + if (componentNode.type === 'Identifier') { + (estreeWalker.walk as any)(ast, { + enter(childNode: ESTree.Node) { + if (childNode.type !== 'Identifier') return; + if (childNode.name !== componentNode.name) return; + magicString.overwrite(childNode.start, childNode.end, name); + }, + }); + magicString.remove(node.start, node.end); + } else { + const removeStart = cssModulesEntry.start; + const removeEnd = node.declarations[0].init.arguments[1].end - 1; + magicString.remove(removeStart, removeEnd); + } /* NOTE: The above logic is valid as long as the following two conditions are met. * * - the uniqueness of `ident` is kept throughout the module @@ -411,31 +454,10 @@ export function unwindCssModuleClassName(ast: estree.Node): void { }); */ } else { - this.replace({ - type: 'VariableDeclaration', - declarations: [{ - type: 'VariableDeclarator', - id: { - type: 'Identifier', - name: node.declarations[0].id.name, - }, - init: { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: '_export_sfc', - }, - arguments: [{ - type: 'Identifier', - name: ident, - }, { - type: 'ArrayExpression', - elements: node.declarations[0].init.arguments[1].elements.slice(0, __cssModulesIndex).concat(node.declarations[0].init.arguments[1].elements.slice(__cssModulesIndex + 1)), - }], - }, - }], - kind: 'const', - }); + const nextElement = node.declarations[0].init.arguments[1].elements[__cssModulesIndex + 1]; + const removeStart = node.declarations[0].init.arguments[1].elements[__cssModulesIndex]!.start; + const removeEnd = nextElement ? nextElement.start : node.declarations[0].init.arguments[1].end - 1; + magicString.remove(removeStart, removeEnd); } /* This region removed the `__cssModules` reference from the second argument of `_export_sfc`, as in the following code. * @@ -474,10 +496,11 @@ export function unwindCssModuleClassName(ast: estree.Node): void { export default function pluginUnwindCssModuleClassName(): Plugin { return { name: 'UnwindCssModuleClassName', - renderChunk(code): { code: string } { - const ast = this.parse(code) as unknown as estree.Node; - unwindCssModuleClassName(ast); - return { code: generate(ast) }; + renderChunk(code, _chunk, _options, meta) { + const ast = ('ast' in meta ? meta.ast ?? this.parse(code) : this.parse(code)) as ESTree.Program; + const magicString = meta.magicString ?? new RolldownMagicString(code); + unwindCssModuleClassName(ast, magicString); + return magicString; }, }; } diff --git a/packages/frontend/lib/vite-plugin-create-search-index.ts b/packages/frontend/lib/vite-plugin-create-search-index.ts index cfbba0823c3..4126a4f8c0f 100644 --- a/packages/frontend/lib/vite-plugin-create-search-index.ts +++ b/packages/frontend/lib/vite-plugin-create-search-index.ts @@ -13,11 +13,12 @@ import { type LogOptions, normalizePath, type Plugin, - type PluginOption + type PluginOption, } from 'vite'; import fs from 'node:fs'; import JSON5 from 'json5'; -import MagicString, { SourceMap } from 'magic-string'; +import { RolldownMagicString } from 'rolldown'; +import type { TransformResult } from 'rolldown'; import path from 'node:path' import { hash, toBase62 } from '../vite.config'; import { minimatch } from 'minimatch'; @@ -63,7 +64,7 @@ interface MarkerRelation { let logger = { info: (msg: string, options?: LogOptions) => { }, warn: (msg: string, options?: LogOptions) => { }, - error: (msg: string, options?: LogErrorOptions | unknown) => { }, + error: (msg: string, options?: LogErrorOptions) => { }, }; let loggerInitialized = false; @@ -460,9 +461,18 @@ function propertyAccessProxy(path: string[]): AccessProxy { const i18nProxy = propertyAccessProxy(['i18n']); -export function collectFileMarkers(id: string, code: string): SearchIndexItem[] { +export function collectFileMarkers(id: string, code: string | RolldownMagicString | undefined): SearchIndexItem[] { try { - const { descriptor, errors } = vueSfcParse(code, { + let codeStr: string; + if (typeof code === 'string') { + codeStr = code; + } else if (code != null) { + codeStr = code.toString(); + } else { + throw new Error(`Code is undefined for file ${id}`); + } + + const { descriptor, errors } = vueSfcParse(codeStr, { filename: id, }); @@ -473,7 +483,8 @@ export function collectFileMarkers(id: string, code: string): SearchIndexItem[] return extractUsageInfoFromTemplateAst(descriptor.template?.ast, id); } catch (error) { - logger.error(`Error analyzing file ${id}:`, error); + let _error = error instanceof Error ? error : new Error(String(error)); + logger.error(`Error analyzing file ${id}:`, { error: _error }); } return []; @@ -481,10 +492,7 @@ export function collectFileMarkers(id: string, code: string): SearchIndexItem[] // endregion -type TransformedCode = { - code: string, - map: SourceMap, -}; +type TransformedCode = Exclude; export class MarkerIdAssigner { // key: file id @@ -509,13 +517,12 @@ export class MarkerIdAssigner { } #processImpl(id: string, code: string): TransformedCode { - const s = new MagicString(code); // magic-string �インスタンスを作� + const s = new RolldownMagicString(code); // magic-string �インスタンスを作� const parsed = vueSfcParse(code, { filename: id }); if (!parsed.descriptor.template) { return { - code, - map: s.generateMap({ source: id, includeContent: true }), + code, // テンプレート���場��元�コードを返� }; } const ast = parsed.descriptor.template.ast; // テンプレート AST を�得 @@ -523,8 +530,7 @@ export class MarkerIdAssigner { if (!ast) { return { - code: s.toString(), // 変更後�コードを返� - map: s.generateMap({ source: id, includeContent: true }), // ソースマップも生� (sourceMap: true �必�) + code, }; } @@ -611,7 +617,6 @@ export class MarkerIdAssigner { return { code: s.toString(), // 変更後�コードを返� - map: s.generateMap({ source: id, includeContent: true }), // ソースマップも生� (sourceMap: true �必�) }; } @@ -642,7 +647,7 @@ export class MarkerIdAssigner { } } -// Rollup プラグイン��� export +// Vite プラグイン��� export export default function pluginCreateSearchIndex(options: Options): PluginOption { const assigner = new MarkerIdAssigner(); return [ diff --git a/packages/frontend/vite.json5.ts b/packages/frontend/lib/vite-plugin-json5.ts similarity index 90% rename from packages/frontend/vite.json5.ts rename to packages/frontend/lib/vite-plugin-json5.ts index 87b67c21424..921324b67a4 100644 --- a/packages/frontend/vite.json5.ts +++ b/packages/frontend/lib/vite-plugin-json5.ts @@ -1,7 +1,10 @@ -// Original: https://github.com/rollup/plugins/tree/8835dd2aed92f408d7dc72d7cc25a9728e16face/packages/json +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ import JSON5 from 'json5'; -import { Plugin } from 'rollup'; +import { Plugin } from 'vite'; import { createFilter, dataToEsm } from '@rollup/pluginutils'; import { RollupJsonOptions } from '@rollup/plugin-json'; diff --git a/packages/frontend/lib/vite-plugin-watch-locales.ts b/packages/frontend/lib/vite-plugin-watch-locales.ts index 372e9039d5d..2fed7f60fa1 100644 --- a/packages/frontend/lib/vite-plugin-watch-locales.ts +++ b/packages/frontend/lib/vite-plugin-watch-locales.ts @@ -3,16 +3,16 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import path from 'node:path' +import path from 'node:path'; import locales from 'i18n'; +import type { Plugin } from 'vite'; const localesDir = path.resolve(__dirname, '../../../locales') /** * 外部ファイルを監視��必��応��webSocket�メッセージを�るViteプラグイン - * @returns {import('vite').Plugin} */ -export default function pluginWatchLocales() { +export default function pluginWatchLocales(): Plugin { return { name: 'watch-locales', diff --git a/packages/frontend/package.json b/packages/frontend/package.json index a99918e7b6f..7bcf097ec4a 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -21,10 +21,7 @@ "@github/webauthn-json": "2.1.1", "@mcaptcha/core-glue": "0.1.0-alpha-5", "@misskey-dev/browser-image-resizer": "2024.1.0", - "@rollup/plugin-json": "6.1.0", - "@rollup/plugin-replace": "6.0.3", - "@rollup/pluginutils": "5.3.0", - "@sentry/vue": "10.45.0", + "@sentry/vue": "10.40.0", "@syuilo/aiscript": "1.2.1", "@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0", "@twemoji/parser": "16.0.0", @@ -64,21 +61,20 @@ "punycode.js": "2.3.1", "qr-code-styling": "1.9.2", "qr-scanner": "1.4.2", - "rollup": "4.60.0", - "sanitize-html": "2.17.2", - "sass": "1.98.0", + "sanitize-html": "2.17.1", "shiki": "3.23.0", "textarea-caret": "3.1.0", "three": "0.183.2", "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", "v-code-diff": "1.13.1", - "vite": "7.3.1", "vue": "3.5.30", "wanakana": "5.3.1" }, "devDependencies": { "@misskey-dev/summaly": "5.2.5", + "@rollup/plugin-json": "6.1.0", + "@rollup/pluginutils": "5.3.0", "@storybook/addon-essentials": "8.6.18", "@storybook/addon-interactions": "8.6.18", "@storybook/addon-links": "10.3.3", @@ -123,7 +119,6 @@ "estree-walker": "3.0.3", "happy-dom": "20.8.8", "intersection-observer": "0.12.2", - "magic-string": "0.30.21", "micromatch": "4.0.8", "minimatch": "10.2.4", "msw": "2.12.14", @@ -132,11 +127,14 @@ "prettier": "3.8.1", "react": "19.2.4", "react-dom": "19.2.4", + "rolldown": "1.0.0-rc.11", + "sass-embedded": "1.98.0", "seedrandom": "3.0.5", "start-server-and-test": "2.1.5", "storybook": "10.3.3", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "tsx": "4.21.0", + "vite": "8.0.2", "vite-plugin-glsl": "1.5.6", "vite-plugin-turbosnap": "1.0.3", "vitest": "4.1.1", diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index 260d1215df2..b0617333330 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -1,7 +1,7 @@ import path from 'path'; -import pluginReplace from '@rollup/plugin-replace'; import pluginVue from '@vitejs/plugin-vue'; import pluginGlsl from 'vite-plugin-glsl'; +import { replacePlugin } from 'rolldown/plugins'; import type { UserConfig } from 'vite'; import { defineConfig } from 'vite'; import * as yaml from 'js-yaml'; @@ -11,13 +11,13 @@ import locales from 'i18n'; import meta from '../../package.json'; import packageInfo from './package.json' with { type: 'json' }; import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js'; -import pluginJson5 from './vite.json5.js'; +import pluginJson5 from './lib/vite-plugin-json5.js'; import type { Options as SearchIndexOptions } from './lib/vite-plugin-create-search-index.js'; import pluginCreateSearchIndex from './lib/vite-plugin-create-search-index.js'; import pluginWatchLocales from './lib/vite-plugin-watch-locales.js'; import { pluginRemoveUnrefI18n } from '../frontend-builder/rollup-plugin-remove-unref-i18n.js'; -const url = process.env.NODE_ENV === 'development' ? yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')).url : null; +const url = process.env.NODE_ENV === 'development' ? (yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')) as any).url : null; const host = url ? (new URL(url)).hostname : undefined; const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue']; @@ -121,11 +121,10 @@ export function getConfig(): UserConfig { pluginGlsl({ minify: true }), ...process.env.NODE_ENV === 'production' ? [ - pluginReplace({ + replacePlugin({ + 'isChromatic()': JSON.stringify(false), + }, { preventAssignment: true, - values: { - 'isChromatic()': JSON.stringify(false), - }, }), ] : [], @@ -154,11 +153,6 @@ export function getConfig(): UserConfig { } }, }, - preprocessorOptions: { - scss: { - api: 'modern-compiler', - }, - }, }, define: { @@ -178,7 +172,10 @@ export function getConfig(): UserConfig { 'safari16', ], manifest: 'manifest.json', - rollupOptions: { + rolldownOptions: { + experimental: { + nativeMagicString: true, + }, input: { i18n: './src/i18n.ts', entry: './src/_boot_.ts', @@ -186,11 +183,18 @@ export function getConfig(): UserConfig { external: externalPackages.map(p => p.match), preserveEntrySignatures: 'allow-extension', output: { - manualChunks: { - vue: ['vue'], - photoswipe: ['photoswipe', 'photoswipe/lightbox', 'photoswipe/style.css'], - // dependencies of i18n.ts - 'config': ['@@/js/config.js'], + codeSplitting: { + groups: [{ + name: 'vue', + test: /node_modules[\\/]vue/, + }, { + name: 'photoswipe', + test: /node_modules[\\/]photoswipe/, + }, { + // dependencies of i18n.ts + name: 'config', + test: /@@[\\/]js[\\/]config\.js/, + }], }, entryFileNames: `scripts/${localesHash}-[hash:8].js`, chunkFileNames: `scripts/${localesHash}-[hash:8].js`, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1c16139fa41..32f051d31d6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -557,8 +557,8 @@ importers: specifier: 7.2.2 version: 7.2.2 vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + specifier: 8.0.2 + version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: '@swc/core-android-arm64': specifier: 1.3.11 @@ -665,18 +665,9 @@ importers: '@misskey-dev/browser-image-resizer': specifier: 2024.1.0 version: 2024.1.0 - '@rollup/plugin-json': - specifier: 6.1.0 - version: 6.1.0(rollup@4.60.0) - '@rollup/plugin-replace': - specifier: 6.0.3 - version: 6.0.3(rollup@4.60.0) - '@rollup/pluginutils': - specifier: 5.3.0 - version: 5.3.0(rollup@4.60.0) '@sentry/vue': - specifier: 10.45.0 - version: 10.45.0(vue@3.5.30(typescript@5.9.3)) + specifier: 10.40.0 + version: 10.40.0(vue@3.5.30(typescript@5.9.3)) '@syuilo/aiscript': specifier: 1.2.1 version: 1.2.1 @@ -688,7 +679,7 @@ importers: version: 16.0.0 '@vitejs/plugin-vue': specifier: 6.0.5 - version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) aiscript-vscode: specifier: github:aiscript-dev/aiscript-vscode#v0.1.16 version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/1dc7f60cda78d030dadfc518a33c472202b2ef67 @@ -794,15 +785,9 @@ importers: qr-scanner: specifier: 1.4.2 version: 1.4.2 - rollup: - specifier: 4.60.0 - version: 4.60.0 sanitize-html: - specifier: 2.17.2 - version: 2.17.2 - sass: - specifier: 1.98.0 - version: 1.98.0 + specifier: 2.17.1 + version: 2.17.1 shiki: specifier: 3.23.0 version: 3.23.0 @@ -821,9 +806,6 @@ importers: v-code-diff: specifier: 1.13.1 version: 1.13.1(vue@3.5.30(typescript@5.9.3)) - vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: specifier: 3.5.30 version: 3.5.30(typescript@5.9.3) @@ -834,6 +816,12 @@ importers: '@misskey-dev/summaly': specifier: 5.2.5 version: 5.2.5 + '@rollup/plugin-json': + specifier: 6.1.0 + version: 6.1.0(rollup@4.60.0) + '@rollup/pluginutils': + specifier: 5.3.0 + version: 5.3.0(rollup@4.60.0) '@storybook/addon-essentials': specifier: 8.6.18 version: 8.6.18(@types/react@19.2.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) @@ -869,7 +857,7 @@ importers: version: 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) '@storybook/react-vite': specifier: 10.3.3 - version: 10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/test': specifier: 8.6.18 version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) @@ -884,7 +872,7 @@ importers: version: 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) '@storybook/vue3-vite': specifier: 10.3.3 - version: 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) '@tabler/icons-webfont': specifier: 3.35.0 version: 3.35.0 @@ -935,7 +923,7 @@ importers: version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.1 - version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) '@vue/compiler-core': specifier: 3.5.30 version: 3.5.30 @@ -966,9 +954,6 @@ importers: intersection-observer: specifier: 0.12.2 version: 0.12.2 - magic-string: - specifier: 0.30.21 - version: 0.30.21 micromatch: specifier: 4.0.8 version: 4.0.8 @@ -993,6 +978,12 @@ importers: react-dom: specifier: 19.2.4 version: 19.2.4(react@19.2.4) + rolldown: + specifier: 1.0.0-rc.11 + version: 1.0.0-rc.11 + sass-embedded: + specifier: 1.98.0 + version: 1.98.0 seedrandom: specifier: 3.0.5 version: 3.0.5 @@ -1008,18 +999,21 @@ importers: tsx: specifier: 4.21.0 version: 4.21.0 + vite: + specifier: 8.0.2 + version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vite-plugin-glsl: specifier: 1.5.6 - version: 1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 vitest: specifier: 4.1.1 - version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vitest-fetch-mock: specifier: 0.4.5 - version: 0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) vue-component-type-helpers: specifier: 3.2.6 version: 3.2.6 @@ -1041,9 +1035,12 @@ importers: magic-string: specifier: 0.30.21 version: 0.30.21 + rolldown: + specifier: 1.0.0-rc.11 + version: 1.0.0-rc.11 vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + specifier: 8.0.2 + version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) devDependencies: '@types/estree': specifier: 1.0.8 @@ -1069,9 +1066,6 @@ importers: '@rollup/plugin-json': specifier: 6.1.0 version: 6.1.0(rollup@4.60.0) - '@rollup/plugin-replace': - specifier: 6.0.3 - version: 6.0.3(rollup@4.60.0) '@rollup/pluginutils': specifier: 5.3.0 version: 5.3.0(rollup@4.60.0) @@ -1080,7 +1074,7 @@ importers: version: 16.0.0 '@vitejs/plugin-vue': specifier: 6.0.5 - version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) buraha: specifier: 0.0.1 version: 0.0.1 @@ -1111,9 +1105,6 @@ importers: rollup: specifier: 4.60.0 version: 4.60.0 - sass: - specifier: 1.98.0 - version: 1.98.0 shiki: specifier: 3.23.0 version: 3.23.0 @@ -1123,9 +1114,6 @@ importers: uuid: specifier: 13.0.0 version: 13.0.0 - vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: specifier: 3.5.30 version: 3.5.30(typescript@5.9.3) @@ -1165,7 +1153,7 @@ importers: version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.1 - version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) '@vue/runtime-core': specifier: 3.5.30 version: 3.5.30 @@ -1199,12 +1187,18 @@ importers: prettier: specifier: 3.8.1 version: 3.8.1 + sass-embedded: + specifier: 1.98.0 + version: 1.98.0 start-server-and-test: specifier: 2.1.5 version: 2.1.5 tsx: specifier: 4.21.0 version: 4.21.0 + vite: + specifier: 8.0.2 + version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 @@ -1377,7 +1371,7 @@ importers: version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.1 - version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) esbuild: specifier: 0.27.4 version: 0.27.4 @@ -1395,10 +1389,10 @@ importers: version: 0.33.0 vitest: specifier: 4.1.1 - version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vitest-websocket-mock: specifier: 0.5.0 - version: 0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) packages/misskey-js/generator: devDependencies: @@ -1871,6 +1865,9 @@ packages: '@borewit/text-codec@0.1.1': resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} + '@bufbuild/protobuf@2.11.0': + resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} + '@canvas/image-data@1.1.0': resolution: {integrity: sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA==} @@ -1955,9 +1952,15 @@ packages: '@discordapp/twemoji@16.0.1': resolution: {integrity: sha512-figLiBWzjS5cyrAjLaGjM8AAaowO3qvK8rg5bA2dElB4qsaPMvBVlFDMO2d3x+nC1igt7kgWH4dvNmvvUHUF8w==} + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + '@emnapi/runtime@1.7.1': resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} @@ -2874,6 +2877,9 @@ packages: resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} engines: {node: '>= 10'} + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@nestjs/common@11.1.17': resolution: {integrity: sha512-hLODw5Abp8OQgA+mUO4tHou4krKgDtUcM9j5Ihxncst9XeyxYBTt2bwZm4e4EQr5E352S4Fyy6V3iFx9ggxKAg==} peerDependencies: @@ -3173,6 +3179,9 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 + '@oxc-project/types@0.122.0': + resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} + '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} @@ -3343,6 +3352,104 @@ packages: resolution: {integrity: sha512-2+O+riuIUgVSuLl3Lyh5AplWZyVMNuG2F98/o6NrutKJfW4/GTZdPpZlIphS0HGgcOHgmWcCSHj+dWFlZaGSHw==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} + '@rolldown/binding-android-arm64@1.0.0-rc.11': + resolution: {integrity: sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.11': + resolution: {integrity: sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.11': + resolution: {integrity: sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.11': + resolution: {integrity: sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': + resolution: {integrity: sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': + resolution: {integrity: sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': + resolution: {integrity: sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': + resolution: {integrity: sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.11': + resolution: {integrity: sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': + resolution: {integrity: sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': + resolution: {integrity: sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.11': + resolution: {integrity: sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==} + '@rolldown/pluginutils@1.0.0-rc.2': resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} @@ -3355,15 +3462,6 @@ packages: rollup: optional: true - '@rollup/plugin-replace@6.0.3': - resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} @@ -3547,10 +3645,18 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@sentry-internal/browser-utils@10.40.0': + resolution: {integrity: sha512-3CDeVNBXYOIvBVdT0SOdMZx5LzYDLuhGK/z7A14sYZz4Cd2+f4mSeFDaEOoH/g2SaY2CKR5KGkAADy8IyjZ21w==} + engines: {node: '>=18'} + '@sentry-internal/browser-utils@10.45.0': resolution: {integrity: sha512-ZPZpeIarXKScvquGx2AfNKcYiVNDA4wegMmjyGVsTA2JPmP0TrJoO3UybJS6KGDeee8V3I3EfD/ruauMm7jOFQ==} engines: {node: '>=18'} + '@sentry-internal/feedback@10.40.0': + resolution: {integrity: sha512-V/ixkcdCNMo04KgsCEeNEu966xUUTD6czKT2LOAO5siZACqFjT/Rp9VR1n7QQrVo3sL7P3QNiTHtX0jaeWbwzg==} + engines: {node: '>=18'} + '@sentry-internal/feedback@10.45.0': resolution: {integrity: sha512-vCSurazFVq7RUeYiM5X326jA5gOVrWYD6lYX2fbjBOMcyCEhDnveNxMT62zKkZDyNT/jyD194nz/cjntBUkyWA==} engines: {node: '>=18'} @@ -3559,18 +3665,34 @@ packages: resolution: {integrity: sha512-oLHVYurqZfADPh5hvmQYS5qx8t0UZzT2u6+/68VXsFruQEOnYJTODKgU3BVLmemRs3WE6kCJjPeFdHVYOQGSzQ==} engines: {node: '>=18'} + '@sentry-internal/replay-canvas@10.40.0': + resolution: {integrity: sha512-wzQwilFHO2baeCt0dTMf0eW+rgK8O+mkisf9sQzPXzG3Krr/iVtFg1T5T1Th3YsCsEdn6yQ3hcBPLEXjMSvccg==} + engines: {node: '>=18'} + '@sentry-internal/replay-canvas@10.45.0': resolution: {integrity: sha512-nvq/AocdZTuD7y0KSiWi3gVaY0s5HOFy86mC/v1kDZmT/jsBAzN5LDkk/f1FvsWma1peqQmpUqxvhC+YIW294Q==} engines: {node: '>=18'} + '@sentry-internal/replay@10.40.0': + resolution: {integrity: sha512-vsH2Ut0KIIQIHNdS3zzEGLJ2C9btbpvJIWAVk7l7oft66JzlUNC89qNaQ5SAypjLQx4Ln2V/ZTqfEoNzXOAsoQ==} + engines: {node: '>=18'} + '@sentry-internal/replay@10.45.0': resolution: {integrity: sha512-vjosRoGA1bzhVAEO1oce+CsRdd70quzBeo7WvYqpcUnoLe/Rv8qpOMqWX3j26z7XfFHMExWQNQeLxmtYOArvlw==} engines: {node: '>=18'} + '@sentry/browser@10.40.0': + resolution: {integrity: sha512-nCt3FKUMFad0C6xl5wCK0Jz+qT4Vev4fv6HJRn0YoNRRDQCfsUVxAz7pNyyiPNGM/WCDp9wJpGJsRvbBRd2anw==} + engines: {node: '>=18'} + '@sentry/browser@10.45.0': resolution: {integrity: sha512-e/a8UMiQhqqv706McSIcG6XK+AoQf9INthi2pD+giZfNRTzXTdqHzUT5OIO5hg8Am6eF63nDJc+vrYNPhzs51Q==} engines: {node: '>=18'} + '@sentry/core@10.40.0': + resolution: {integrity: sha512-/wrcHPp9Avmgl6WBimPjS4gj810a1wU5oX9fF1bzJfeIIbF3jTsAbv0oMbgDp0cSDnkwv2+NvcPnn3+c5J6pBA==} + engines: {node: '>=18'} + '@sentry/core@10.45.0': resolution: {integrity: sha512-s69UXxvefeQxuZ5nY7/THtTrIEvJxNVCp3ns4kwoCw1qMpgpvn/296WCKVmM7MiwnaAdzEKnAvLAwaxZc2nM7Q==} engines: {node: '>=18'} @@ -3621,6 +3743,19 @@ packages: engines: {node: '>=18'} hasBin: true + '@sentry/vue@10.40.0': + resolution: {integrity: sha512-VnsGlSgG4RBgxcsGwS5+5XNUZackUsApgKdCjmwkwWchvLMm1S/RXMXBHT01BabcmUNjxmzWEfI7aboVUoLiGA==} + engines: {node: '>=18'} + peerDependencies: + '@tanstack/vue-router': ^1.64.0 + pinia: 2.x || 3.x + vue: 2.x || 3.x + peerDependenciesMeta: + '@tanstack/vue-router': + optional: true + pinia: + optional: true + '@sentry/vue@10.45.0': resolution: {integrity: sha512-p6ghTgQtiCBZ+Yw0B2xmC69S8AdCRRsYvbTHW7MJYspwNnJDs7rqgCBqOxNhvr3tsKdDuEOEHLtf/5hbKi+8xQ==} engines: {node: '>=18'} @@ -4400,6 +4535,9 @@ packages: '@twemoji/parser@16.0.0': resolution: {integrity: sha512-jmuIjkp3OIaEemwMy3sArBwZSuZkRqmueGwRe2Zk4cFzbUJISFBJSZLDUUBNIgq3c+nY49ideYN2OiII6JUqwA==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/accepts@1.3.7': resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} @@ -5778,6 +5916,9 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} + colors@1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} @@ -7084,6 +7225,9 @@ packages: htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + htmlparser2@9.1.0: resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} @@ -7845,6 +7989,80 @@ packages: light-my-request@6.6.0: resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -9490,6 +9708,11 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rolldown@1.0.0-rc.11: + resolution: {integrity: sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.60.0: resolution: {integrity: sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -9540,9 +9763,129 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sanitize-html@2.17.1: + resolution: {integrity: sha512-ehFCW+q1a4CSOWRAdX97BX/6/PDEkCqw7/0JXZAGQV57FQB3YOkTa/rrzHPeJ+Aghy4vZAFfWMYyfxIiB7F/gw==} + sanitize-html@2.17.2: resolution: {integrity: sha512-EnffJUl46VE9uvZ0XeWzObHLurClLlT12gsOk1cHyP2Ol1P0BnBnsXmShlBmWVJM+dKieQI68R0tsPY5m/B+Jg==} + sass-embedded-all-unknown@1.98.0: + resolution: {integrity: sha512-6n4RyK7/1mhdfYvpP3CClS3fGoYqDvRmLClCESS6I7+SAzqjxvGG6u5Fo+cb1nrPNbbilgbM4QKdgcgWHO9NCA==} + cpu: ['!arm', '!arm64', '!riscv64', '!x64'] + + sass-embedded-android-arm64@1.98.0: + resolution: {integrity: sha512-M9Ra98A6vYJHpwhoC/5EuH1eOshQ9ZyNwC8XifUDSbRl/cGeQceT1NReR9wFj3L7s1pIbmes1vMmaY2np0uAKQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + + sass-embedded-android-arm@1.98.0: + resolution: {integrity: sha512-LjGiMhHgu7VL1n7EJxTCre1x14bUsWd9d3dnkS2rku003IWOI/fxc7OXgaKagoVzok1kv09rzO3vFXJR5ZeONQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + + sass-embedded-android-riscv64@1.98.0: + resolution: {integrity: sha512-WPe+0NbaJIZE1fq/RfCZANMeIgmy83x4f+SvFOG7LhUthHpZWcOcrPTsCKKmN3xMT3iw+4DXvqTYOCYGRL3hcQ==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [android] + + sass-embedded-android-x64@1.98.0: + resolution: {integrity: sha512-zrD25dT7OHPEgLWuPEByybnIfx4rnCtfge4clBgjZdZ3lF6E7qNLRBtSBmoFflh6Vg0RlEjJo5VlpnTMBM5MQQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + + sass-embedded-darwin-arm64@1.98.0: + resolution: {integrity: sha512-cgr1z9rBnCdMf8K+JabIaYd9Rag2OJi5mjq08XJfbJGMZV/TA6hFJCLGkr5/+ZOn4/geTM5/3aSfQ8z5EIJAOg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + + sass-embedded-darwin-x64@1.98.0: + resolution: {integrity: sha512-OLBOCs/NPeiMqTdOrMFbVHBQFj19GS3bSVSxIhcCq16ZyhouUkYJEZjxQgzv9SWA2q6Ki8GCqp4k6jMeUY9dcA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + + sass-embedded-linux-arm64@1.98.0: + resolution: {integrity: sha512-axOE3t2MTBwCtkUCbrdM++Gj0gC0fdHJPrgzQ+q1WUmY9NoNMGqflBtk5mBZaWUeha2qYO3FawxCB8lctFwCtw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + libc: glibc + + sass-embedded-linux-arm@1.98.0: + resolution: {integrity: sha512-03baQZCxVyEp8v1NWBRlzGYrmVT/LK7ZrHlF1piscGiGxwfdxoLXVuxsylx3qn/dD/4i/rh7Bzk7reK1br9jvQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + libc: glibc + + sass-embedded-linux-musl-arm64@1.98.0: + resolution: {integrity: sha512-LeqNxQA8y4opjhe68CcFvMzCSrBuJqYVFbwElEj9bagHXQHTp9xVPJRn6VcrC+0VLEDq13HVXMv7RslIuU0zmA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + libc: musl + + sass-embedded-linux-musl-arm@1.98.0: + resolution: {integrity: sha512-OBkjTDPYR4hSaueOGIM6FDpl9nt/VZwbSRpbNu9/eEJcxE8G/vynRugW8KRZmCFjPy8j/jkGBvvS+k9iOqKV3g==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + libc: musl + + sass-embedded-linux-musl-riscv64@1.98.0: + resolution: {integrity: sha512-7w6hSuOHKt8FZsmjRb3iGSxEzM87fO9+M8nt5JIQYMhHTj5C+JY/vcske0v715HCVj5e1xyTnbGXf8FcASeAIw==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + libc: musl + + sass-embedded-linux-musl-x64@1.98.0: + resolution: {integrity: sha512-QikNyDEJOVqPmxyCFkci8ZdCwEssdItfjQFJB+D+Uy5HFqcS5Lv3d3GxWNX/h1dSb23RPyQdQc267ok5SbEyJw==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + libc: musl + + sass-embedded-linux-riscv64@1.98.0: + resolution: {integrity: sha512-E7fNytc/v4xFBQKzgzBddV/jretA4ULAPO6XmtBiQu4zZBdBozuSxsQLe2+XXeb0X4S2GIl72V7IPABdqke/vA==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + libc: glibc + + sass-embedded-linux-x64@1.98.0: + resolution: {integrity: sha512-VsvP0t/uw00mMNPv3vwyYKUrFbqzxQHnRMO+bHdAMjvLw4NFf6mscpym9Bzf+NXwi1ZNKnB6DtXjmcpcvqFqYg==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + libc: glibc + + sass-embedded-unknown-all@1.98.0: + resolution: {integrity: sha512-C4MMzcAo3oEDQnW7L8SBgB9F2Fq5qHPnaYTZRMOH3Mp/7kM4OooBInXpCiiFjLnjY95hzP4KyctVx0uYR6MYlQ==} + os: ['!android', '!darwin', '!linux', '!win32'] + + sass-embedded-win32-arm64@1.98.0: + resolution: {integrity: sha512-nP/10xbAiPbhQkMr3zQfXE4TuOxPzWRQe1Hgbi90jv2R4TbzbqQTuZVOaJf7KOAN4L2Bo6XCTRjK5XkVnwZuwQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + + sass-embedded-win32-x64@1.98.0: + resolution: {integrity: sha512-/lbrVsfbcbdZQ5SJCWcV0NVPd6YRs+FtAnfedp4WbCkO/ZO7Zt/58MvI4X2BVpRY/Nt5ZBo1/7v2gYcQ+J4svQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + + sass-embedded@1.98.0: + resolution: {integrity: sha512-Do7u6iRb6K+lrllcTkB1BXcHwOxcKe3rEfOF/GcCLE2w3WpddakRAosJOHFUR37DpsvimQXEt5abs3NzUjEIqg==} + engines: {node: '>=16.0.0'} + hasBin: true + sass@1.98.0: resolution: {integrity: sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==} engines: {node: '>=14.0.0'} @@ -10102,6 +10445,14 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} + + sync-message-port@1.2.0: + resolution: {integrity: sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==} + engines: {node: '>=16.0.0'} + systeminformation@5.31.5: resolution: {integrity: sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ==} engines: {node: '>=8.0.0'} @@ -10619,6 +10970,9 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -10649,15 +11003,16 @@ packages: vite-plugin-turbosnap@1.0.3: resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==} - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@8.0.2: + resolution: {integrity: sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 jiti: '>=1.21.0' less: ^4.0.0 - lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -10668,12 +11023,14 @@ packages: peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -11793,6 +12150,8 @@ snapshots: '@borewit/text-codec@0.1.1': {} + '@bufbuild/protobuf@2.11.0': {} + '@canvas/image-data@1.1.0': {} '@chainsafe/is-ip@2.1.0': {} @@ -11931,11 +12290,22 @@ snapshots: jsonfile: 5.0.0 universalify: 0.1.2 + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 + optional: true + '@epic-web/invariant@1.0.0': {} '@esbuild/aix-ppc64@0.27.4': @@ -12546,11 +12916,11 @@ snapshots: '@types/yargs': 17.0.34 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: glob: 13.0.1 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: typescript: 5.9.3 @@ -12834,6 +13204,13 @@ snapshots: '@napi-rs/nice-win32-x64-msvc': 1.1.1 optional: true + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + '@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: file-type: 21.3.2 @@ -13188,6 +13565,8 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@oxc-project/types@0.122.0': {} + '@paralleldrive/cuid2@2.3.1': dependencies: '@noble/hashes': 1.8.0 @@ -13412,18 +13791,60 @@ snapshots: transitivePeerDependencies: - supports-color - '@rolldown/pluginutils@1.0.0-rc.2': {} + '@rolldown/binding-android-arm64@1.0.0-rc.11': + optional: true - '@rollup/plugin-json@6.1.0(rollup@4.60.0)': + '@rolldown/binding-darwin-arm64@1.0.0-rc.11': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.11': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.11': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.11': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.60.0) - optionalDependencies: - rollup: 4.60.0 + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': + optional: true - '@rollup/plugin-replace@6.0.3(rollup@4.60.0)': + '@rolldown/pluginutils@1.0.0-rc.11': {} + + '@rolldown/pluginutils@1.0.0-rc.2': {} + + '@rollup/plugin-json@6.1.0(rollup@4.60.0)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.60.0) - magic-string: 0.30.21 optionalDependencies: rollup: 4.60.0 @@ -13553,10 +13974,18 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} + '@sentry-internal/browser-utils@10.40.0': + dependencies: + '@sentry/core': 10.40.0 + '@sentry-internal/browser-utils@10.45.0': dependencies: '@sentry/core': 10.45.0 + '@sentry-internal/feedback@10.40.0': + dependencies: + '@sentry/core': 10.40.0 + '@sentry-internal/feedback@10.45.0': dependencies: '@sentry/core': 10.45.0 @@ -13566,16 +13995,34 @@ snapshots: detect-libc: 2.1.2 node-abi: 3.85.0 + '@sentry-internal/replay-canvas@10.40.0': + dependencies: + '@sentry-internal/replay': 10.40.0 + '@sentry/core': 10.40.0 + '@sentry-internal/replay-canvas@10.45.0': dependencies: '@sentry-internal/replay': 10.45.0 '@sentry/core': 10.45.0 + '@sentry-internal/replay@10.40.0': + dependencies: + '@sentry-internal/browser-utils': 10.40.0 + '@sentry/core': 10.40.0 + '@sentry-internal/replay@10.45.0': dependencies: '@sentry-internal/browser-utils': 10.45.0 '@sentry/core': 10.45.0 + '@sentry/browser@10.40.0': + dependencies: + '@sentry-internal/browser-utils': 10.40.0 + '@sentry-internal/feedback': 10.40.0 + '@sentry-internal/replay': 10.40.0 + '@sentry-internal/replay-canvas': 10.40.0 + '@sentry/core': 10.40.0 + '@sentry/browser@10.45.0': dependencies: '@sentry-internal/browser-utils': 10.45.0 @@ -13584,6 +14031,8 @@ snapshots: '@sentry-internal/replay-canvas': 10.45.0 '@sentry/core': 10.45.0 + '@sentry/core@10.40.0': {} + '@sentry/core@10.45.0': {} '@sentry/node-core@10.45.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)': @@ -13657,6 +14106,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@sentry/vue@10.40.0(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@sentry/browser': 10.40.0 + '@sentry/core': 10.40.0 + vue: 3.5.30(typescript@5.9.3) + '@sentry/vue@10.45.0(vue@3.5.30(typescript@5.9.3))': dependencies: '@sentry/browser': 10.45.0 @@ -14215,12 +14670,12 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/builder-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@storybook/builder-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - '@storybook/csf-plugin': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/csf-plugin': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup @@ -14234,14 +14689,14 @@ snapshots: dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/csf-plugin@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@storybook/csf-plugin@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) unplugin: 2.3.10 optionalDependencies: esbuild: 0.27.4 rollup: 4.60.0 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) '@storybook/csf-plugin@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: @@ -14286,11 +14741,11 @@ snapshots: react-dom: 19.2.4(react@19.2.4) storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/react-vite@10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@storybook/react-vite@10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@rollup/pluginutils': 5.3.0(rollup@4.60.0) - '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/react': 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 @@ -14300,7 +14755,7 @@ snapshots: resolve: 1.22.11 storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) tsconfig-paths: 4.2.0 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup @@ -14348,14 +14803,14 @@ snapshots: dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/vue3-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': + '@storybook/vue3-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': dependencies: - '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/vue3': 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) magic-string: 0.30.21 storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) typescript: 5.9.3 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue-component-meta: 2.2.12(typescript@5.9.3) vue-docgen-api: 4.79.2(vue@3.5.30(typescript@5.9.3)) transitivePeerDependencies: @@ -14660,6 +15115,11 @@ snapshots: '@twemoji/parser@16.0.0': {} + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@types/accepts@1.3.7': dependencies: '@types/node': 24.12.0 @@ -15128,13 +15588,13 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: 3.5.30(typescript@5.9.3) - '@vitest/coverage-v8@4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)))': + '@vitest/coverage-v8@4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.1.1 @@ -15146,7 +15606,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.0.3 - vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@vitest/expect@2.0.5': dependencies: @@ -15172,14 +15632,14 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@vitest/mocker@4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: '@vitest/spy': 4.1.1 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.12.14(@types/node@24.12.0)(typescript@5.9.3) - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) '@vitest/pretty-format@2.0.5': dependencies: @@ -16303,6 +16763,8 @@ snapshots: colorette@2.0.20: {} + colorjs.io@0.5.2: {} + colors@1.4.0: optional: true @@ -17957,6 +18419,13 @@ snapshots: domutils: 3.2.2 entities: 7.0.1 + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + htmlparser2@9.1.0: dependencies: domelementtype: 2.3.0 @@ -18928,6 +19397,55 @@ snapshots: process-warning: 4.0.1 set-cookie-parser: 2.7.1 + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -20773,6 +21291,27 @@ snapshots: glob: 7.2.3 optional: true + rolldown@1.0.0-rc.11: + dependencies: + '@oxc-project/types': 0.122.0 + '@rolldown/pluginutils': 1.0.0-rc.11 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.11 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.11 + '@rolldown/binding-darwin-x64': 1.0.0-rc.11 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.11 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.11 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.11 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.11 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.11 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.11 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.11 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.11 + rollup@4.60.0: dependencies: '@types/estree': 1.0.8 @@ -20860,6 +21399,15 @@ snapshots: safer-buffer@2.1.2: {} + sanitize-html@2.17.1: + dependencies: + deepmerge: 4.3.1 + escape-string-regexp: 4.0.0 + htmlparser2: 8.0.2 + is-plain-object: 5.0.0 + parse-srcset: 1.0.2 + postcss: 8.5.8 + sanitize-html@2.17.2: dependencies: deepmerge: 4.3.1 @@ -20869,6 +21417,93 @@ snapshots: parse-srcset: 1.0.2 postcss: 8.5.8 + sass-embedded-all-unknown@1.98.0: + dependencies: + sass: 1.98.0 + optional: true + + sass-embedded-android-arm64@1.98.0: + optional: true + + sass-embedded-android-arm@1.98.0: + optional: true + + sass-embedded-android-riscv64@1.98.0: + optional: true + + sass-embedded-android-x64@1.98.0: + optional: true + + sass-embedded-darwin-arm64@1.98.0: + optional: true + + sass-embedded-darwin-x64@1.98.0: + optional: true + + sass-embedded-linux-arm64@1.98.0: + optional: true + + sass-embedded-linux-arm@1.98.0: + optional: true + + sass-embedded-linux-musl-arm64@1.98.0: + optional: true + + sass-embedded-linux-musl-arm@1.98.0: + optional: true + + sass-embedded-linux-musl-riscv64@1.98.0: + optional: true + + sass-embedded-linux-musl-x64@1.98.0: + optional: true + + sass-embedded-linux-riscv64@1.98.0: + optional: true + + sass-embedded-linux-x64@1.98.0: + optional: true + + sass-embedded-unknown-all@1.98.0: + dependencies: + sass: 1.98.0 + optional: true + + sass-embedded-win32-arm64@1.98.0: + optional: true + + sass-embedded-win32-x64@1.98.0: + optional: true + + sass-embedded@1.98.0: + dependencies: + '@bufbuild/protobuf': 2.11.0 + colorjs.io: 0.5.2 + immutable: 5.1.5 + rxjs: 7.8.2 + supports-color: 8.1.1 + sync-child-process: 1.0.2 + varint: 6.0.0 + optionalDependencies: + sass-embedded-all-unknown: 1.98.0 + sass-embedded-android-arm: 1.98.0 + sass-embedded-android-arm64: 1.98.0 + sass-embedded-android-riscv64: 1.98.0 + sass-embedded-android-x64: 1.98.0 + sass-embedded-darwin-arm64: 1.98.0 + sass-embedded-darwin-x64: 1.98.0 + sass-embedded-linux-arm: 1.98.0 + sass-embedded-linux-arm64: 1.98.0 + sass-embedded-linux-musl-arm: 1.98.0 + sass-embedded-linux-musl-arm64: 1.98.0 + sass-embedded-linux-musl-riscv64: 1.98.0 + sass-embedded-linux-musl-x64: 1.98.0 + sass-embedded-linux-riscv64: 1.98.0 + sass-embedded-linux-x64: 1.98.0 + sass-embedded-unknown-all: 1.98.0 + sass-embedded-win32-arm64: 1.98.0 + sass-embedded-win32-x64: 1.98.0 + sass@1.98.0: dependencies: chokidar: 5.0.0 @@ -20876,6 +21511,7 @@ snapshots: source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 + optional: true sax@1.5.0: {} @@ -21525,6 +22161,12 @@ snapshots: symbol-tree@3.2.4: optional: true + sync-child-process@1.0.2: + dependencies: + sync-message-port: 1.2.0 + + sync-message-port@1.2.0: {} + systeminformation@5.31.5: {} tagged-tag@1.0.0: {} @@ -21992,6 +22634,8 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + varint@6.0.0: {} + vary@1.1.2: {} verror@1.10.0: @@ -22010,44 +22654,45 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-plugin-glsl@1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): + vite-plugin-glsl@1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): dependencies: - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: '@rollup/pluginutils': 5.3.0(rollup@4.60.0) esbuild: 0.27.4 vite-plugin-turbosnap@1.0.3: {} - vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0): + vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0): dependencies: - esbuild: 0.27.4 - fdir: 6.5.0(picomatch@4.0.3) + lightningcss: 1.32.0 picomatch: 4.0.3 postcss: 8.5.8 - rollup: 4.60.0 + rolldown: 1.0.0-rc.11 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.12.0 + esbuild: 0.27.4 fsevents: 2.3.3 sass: 1.98.0 + sass-embedded: 1.98.0 terser: 5.46.1 tsx: 4.21.0 - vitest-fetch-mock@0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): + vitest-fetch-mock@0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): dependencies: - vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) - vitest-websocket-mock@0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): + vitest-websocket-mock@0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): dependencies: '@vitest/utils': 3.2.4 mock-socket: 9.3.1 - vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) - vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): + vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): dependencies: '@vitest/expect': 4.1.1 - '@vitest/mocker': 4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@vitest/mocker': 4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@vitest/pretty-format': 4.1.1 '@vitest/runner': 4.1.1 '@vitest/snapshot': 4.1.1 @@ -22064,7 +22709,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 From 8169c57bd1d74ea6b60e7562228793c87c53aac3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Apr 2026 11:43:37 -0400 Subject: [PATCH 005/578] fix(backend): handle array or string in alsoKnownAs (#17275) * fix: handle array or string in alsoKnownAs, closes #17274 * style: use more idiomatic toArray() for UserEntityService handling of alsoKnownAs * fix: handle array-valued or unwrapped alsoKnownAs in ApPersonService * doc: note about bugfix for alsoKnownAs --- CHANGELOG.md | 164 +++++++++--------- .../activitypub/models/ApPersonService.ts | 4 +- .../src/core/entities/UserEntityService.ts | 9 +- packages/backend/test/unit/activitypub.ts | 45 +++++ .../test/unit/entities/UserEntityService.ts | 10 ++ 5 files changed, 144 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f52942914d..97b6c057d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ ### Server - Fix: `/api-doc` �アクセス�����題を修正 - +- Fix: support `alsoKnownAs` from remote actors as either array or unwrapped singleton ## 2026.3.2 @@ -43,7 +43,7 @@ - `users/following` � `birthday` プロパティ��推奨��り���。代�り� `users/get-following-users-by-birthday` を�利用����。 ### General -- Enhance: 「も���誕生日�ユーザー�ウィジェット��誕生日�至近�ユーザーも表示��るよ�� +- Enhance: 「も���誕生日�ユーザー�ウィジェット��誕生日�至近�ユーザーも表示��るよ�� (Cherry-picked from https://github.com/MisskeyIO/misskey) - 「今日誕生日�ユーザー��「も���誕生日�ユーザー���称変更�れ��� - Fix: ユーザー�ッシュタグページ�ユーザー�読�込���複�る�題を修正 @@ -99,9 +99,9 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### Client - Enhance: デッキ�UI説明を追加 - Enhance: 設定�ブラウザ�よ��消去�れ��よ���るオプションを追加 -- Fix: �ージョン表記���Play�正��動作����題を修正 +- Fix: �ージョン表記���Play�正��動作����題を修正 �ージョン表記���も�� v0.x 系���実行�れ��。v1.x 系�動作����場��必��ージョン表記を�������。 -- Fix: デッキUI�メニュー�置を下����る�プロファイル削除ボタン�表示�れ���を修正 +- Fix: デッキUI�メニュー�置を下����る�プロファイル削除ボタン�表示�れ���を修正 - Fix: 一部�Unicode絵文字�リアクション�ボタン��ら���題を修正 ### Server @@ -146,11 +146,11 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Fix: ページ�内容���出る����る�題を修正 - Fix: ナビゲーション�ーを下�表示���る����項目数�多��表示�崩れる�題を修正 - Fix: ヘッダーメニュー��ャン�ル�新�作��項目��ャン�ル作�ページ�飛����題を修正 #16816 -- Fix: ラジオボタン�空白��択肢�表示�れる�題を修正 +- Fix: ラジオボタン�空白��択肢�表示�れる�題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1105) - Fix: 一部�シ�ュエーション�投稿フォーム�ツアー�正��表示�れ���題を修正 - Fix: 投稿フォーム�リセットボタン�注釈�リセット�れ���題を修正 -- Fix: Play�AiScript�ージョン判定(v0.x系・v1.x系�判定)�正��動作����題を修正 +- Fix: Play�AiScript�ージョン判定(v0.x系・v1.x系�判定)�正��動作����題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1129) - Fix: フォロー申請をキャンセル�る際�確�ダイアログ�文言��正確��題を修正 - Fix: �回読�込�時�エラー��る����る�題を修正 @@ -160,12 +160,12 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### Server - Enhance: メモリ使用�を削減���� - Enhance: �存関係�更新 -- Fix: ワードミュート�文字数計算を修正 +- Fix: ワードミュート�文字数計算を修正 - Fix: �ャン�ル�リアルタイム更新時��ロックダウン設定���ログイン時�ノートを表示���設定����る場��もノート�表示�れ�����題を修正 -- Fix: DeepL API�APIキー指定方�変更�対応 +- Fix: DeepL API�APIキー指定方�変更�対応 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1096) - 内部実装�変更��対応�能�更新��。Misskey��設定方法�変更��り��ん。 -- Fix: DBレプリケーションを利用�る環境�クエリー�失敗�る�題を修正 +- Fix: DBレプリケーションを利用�る環境�クエリー�失敗�る�題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1123) ## 2025.11.0 @@ -208,7 +208,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ## 2025.10.1 ### General -- Enhance: リモートユーザー�付与��ロール�ッジを表示��るよ��(オプトイン) +- Enhance: リモートユーザー�付与��ロール�ッジを表示��るよ��(オプトイン) パフォーマンス上��題�らデフォルト�無効化�れ����。「コントロールパ�ル > パフォーマンス��ら有効化����。 - �存関係�更新 @@ -335,7 +335,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Enhance: レンダリングパフォーマンス��上 - Enhance: �存ソフトウェア�更新 - Fix: 投稿フォーム�ファイル�アップロード�中止���失敗��際��ンドリングを修正 -- Fix: 一部�設定検索�果�存在���パス��る�題を修正 +- Fix: 一部�設定検索�果�存在���パス��る�題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1171) - Fix: テーマエディタ�動作����題を修正 - Fix: �ャン�ル��イライトページ�ノート�表示�れ���題を修正 @@ -495,7 +495,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Enhance: 画��高�質�プレースホルダを無効化��パフォーマンスを�上��るオプションを追加 - Enhance: 招待�れ��る��加�����ルームを開������招待を承��る����尋�るよ�� - Enhance: リプライ元�アンケート��る���表示�れるよ�� -- Enhance: ノート�サー�ー情報�デザインを改善・パフォーマンス�上 +- Enhance: ノート�サー�ー情報�デザインを改善・パフォーマンス�上 (Based on https://github.com/taiyme/misskey/pull/198, https://github.com/taiyme/misskey/pull/211, https://github.com/taiyme/misskey/pull/283) - Enhance: ユーザー設定�URLプレビューを無効化��るよ�� - Enhance: ヒント�コツを追加 @@ -584,7 +584,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### Server - Enhance: ジョブキュー��功/失敗��ジョブも一定数・一定期間�存�るよ����後�ら�題を調査�る��を容易� -- Enhance: フォロー���るユーザー�らフォロワー�定投稿�ノート�もアンテナ�検知��るよ�� +- Enhance: フォロー���るユーザー�らフォロワー�定投稿�ノート�もアンテナ�検知��るよ�� (Cherry-picked from https://github.com/yojo-art/cherrypick/pull/568 and https://github.com/team-shahu/misskey/pull/38) - Enhance: ユーザー���ノート�表示�高速化�るよ�� - Fix: システムアカウント����サー�ー���期�れ���題を修正 @@ -690,7 +690,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### General - Enhance: プロキシアカウントをシステムアカウント���作��るよ�� -- Enhance: OAuth�外部アプリ�らロゴ��供�れ��る場���れを表示��るよ�� +- Enhance: OAuth�外部アプリ�らロゴ��供�れ��る場���れを表示��るよ�� 書�� https://indieauth.spec.indieweb.org/20220212/#example-2 �準���。 - Fix: システムアカウント�削除��る�題を修正 @@ -704,7 +704,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### Server - Fix: 特定�ケース�ActivityPub�処��デッドロック��る����る�を修正 -- Fix: S3互�オブジェクトストレージ�ファイル�アップロード�失敗�る����る�題を修正 +- Fix: S3互�オブジェクトストレージ�ファイル�アップロード�失敗�る����る�題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/895) @@ -725,7 +725,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Enhance: リアクション�る際�確�ダイアログを表示��るよ�� - Enhance: コントロールパ�ル�ユーザ検索�入力�れ�情報をページ�移������よ�� `#15437` - Enhance: CW�注釈�入力済��文字数を表示 -- Enhance: ノート検索ページ�デザイン調整 +- Enhance: ノート検索ページ�デザイン調整 (Cherry-picked from https://github.com/taiyme/misskey/pull/273) - Fix: ノートページ��クリップ一覧�表示�れ������る�題を修正 - Fix: コンディショナルロールを手動�割り当���る導線を削除 `#13529` @@ -742,7 +742,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Fix: `following/invalidate`�フォロワーを解除�よ�����るユーザー�情報を返�よ�� - Fix: オブジェクトストレージ�設定�Prefixを設定�������場�null���空文字��る�題を修正 - Fix: HTTPプロキシ���除外設定を行��状態�カスタム絵文字�一括イン�ートを�����除外設定�効����を修正( #8766 ) -- Fix: pgroonga��検索時�����キーワード���検索�使用�れる�題を修正 +- Fix: pgroonga��検索時�����キーワード���検索�使用�れる�題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/886) - Fix: メールアドレス�形��正����れ�以��処�を行���よ�� - Fix: `update-meta`�objectStoragePrefix�S3_SAFE��URL-safe���文字列を使���よ�� @@ -752,12 +752,12 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ## 2025.2.0 ### General -- Fix: Docker �ビルド�失敗�る�題を修正 +- Fix: Docker �ビルド�失敗�る�題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/883) ### Client - Fix: パスキー�パスワードレスログイン�出����題を修正 -- Fix: 一部環境�センシティブ�ファイルを�むノート��表示�効����題 +- Fix: 一部環境�センシティブ�ファイルを�むノート��表示�効����題 - Fix: データセー�ー有効時�もユーザーページ�「ファイル�タブ�画��読�込�れ�����題を修正 - Fix: MFM� `sparkle` エフェクト�正��表示�れ���題を修正 - Fix: ページ�URL�スラッシュ���れ��る場��ページ�正��表示�れ���題を修正 @@ -784,14 +784,14 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` * β版���公開����旧画�も引�続�利用�能�� ### Client -- Enhance: PC画���ャン�ル�複数列�表示�れるよ�� +- Enhance: PC画���ャン�ル�複数列�表示�れるよ�� (Cherry-picked from https://github.com/Otaku-Social/maniakey/pull/13) - Enhance: 照会�失敗��場�����由を表示�るよ�� - Enhance: ワードミュート�検知�れ�ワードを表示��るよ�� - Enhance: リモート�ノート�リンクをコピー��るよ�� - Enhance: 連��ホワイトリスト化・無効化�れ��るサー�ー���デザイン修正 - Enhance: AiScript�セーブデータを明示的�削除�る関数`Mk:remove`を追加 -- Enhance: ノート�添付ファイルを一覧��れる「ファイル�タブを追加 +- Enhance: ノート�添付ファイルを一覧��れる「ファイル�タブを追加 (Based on https://github.com/Otaku-Social/maniakey/pull/14) - Enhance: AiScript�拡張API関数����引数�型�ェックをより厳格� - Enhance: クエリパラメータ�uiを一時的�変更��るよ�� #15240 @@ -799,26 +799,26 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Fix: 画�サイズ�変���際�ナビゲーション�ー�自動�折り���れ���題を修正 - Fix: サー�ー情報メニュー�区切り線��足�����を修正 - Fix: ノート�ログイン���るユーザー��見れ��場��ログインダイアログを閉�る���後�動線����る�題を修正 -- Fix: 公開範囲�ホーム�ノート�埋�込�ウィジェット�読�込�れ���題を修正 +- Fix: 公開範囲�ホーム�ノート�埋�込�ウィジェット�読�込�れ���題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/803) - Fix: 絵文字管�画��一部�絵文字�表示�れ���題を修正 - Fix: プラグイン `register_note_view_interruptor` �ノート�サー�ー情報�書���������題を修正 - Fix: Botプロテクション�設定変更時�実際�検証を通������存����よ��( #15137 ) - Fix: ノート検索�使用����場��も�ャン�ル�ノート検索欄������題を修正 - Fix: `Ui:C:select`�値�変更�画���映�れ���題を修正 -- Fix: MiAuth��画�����処��失敗��場��もコール�ックURL��移������題を修正 +- Fix: MiAuth��画�����処��失敗��場��もコール�ックURL��移������題を修正 (Cherry-picked from https://github.com/TeamNijimiss/misskey/commit/800359623e41a662551d774de15b0437b6849bb4) - Fix: ノート作�画��ファイル�添付�能個数を超��もノートボタン�押�����題を修正 - Fix: 「アカウントを管��画���ユーザー情報��得�失敗��アカウント(削除�れ�アカウント��)�表示�れ���題を修正 - Fix: MacOS�Chrome系ブラウザを使用���る場���Misskeyを閉��際�他�タブ�オーディオ機能�干渉�る�題を修正 - Fix: 言語データ�キャッシュ状��よ����埋�込�ウィジェット�正��起動����題を修正 - Fix: 「削除��編集��ノート�引用を解除出������題を修正( #14476 ) -- Fix: RSSウィジェット�正��表示�れ���題を修正 +- Fix: RSSウィジェット�正��表示�れ���題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/857) - Fix: ワードミュート��存失敗時�APIエラー��り���れる事��る�を修正 - Fix: アンケート�リモート�絵文字�正���画�����題�修正 (Cherry-picked from https://github.com/yojo-art/cherrypick/pull/153) -- Fix: �ログイン時�サー�ー概�画��メニューボタン�押�������る�を修正 +- Fix: �ログイン時�サー�ー概�画��メニューボタン�押�������る�を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/656) - Fix: URL�����ら`#pswp`���れ��る場��画�ビューワー�ブラウザ�戻るボタン�閉�られ���題を修正 - Fix: ロール作�画��設定��るアイコンデコレーション�最大�付個数を16�制� @@ -827,18 +827,18 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### Server - Enhance: pg_bigm�利用��るよ��ノート�検索をILIKE演算����LIKE演算��LOWER()を���テキスト�対��行�よ�� - Enhance: ノート検索��択肢���pgroonga�対応 ( #14730 ) -- Enhance: �ャート更新時�DB��時接続���よ�� +- Enhance: �ャート更新時�DB��時接続���よ�� (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/830) - Enhance: config(default.yml)�らSQLログ全文を出力�る���を設定�能� ( #15266 ) - Fix: ユーザー�プロフィール画�をアドレス入力���直接表示��際�概�タブ��画�失敗�る�題�修正( #15032 ) -- Fix: 起動��疎通�ェック�機能���������題を修正 +- Fix: 起動��疎通�ェック�機能���������題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/737) - Fix: ノート�閲覧�ログイン必須���もFeed�ノート�表示�れ�����題を修正 - Fix: 絵文字�連��ライセンス欄を相互�やり�り�るよ�� ( #10859, #14109 ) - Fix: ロックダウン�れ�期間指定�ノート�Streaming経由�LTL�出��る�を修正 ( #15200 ) - Fix: disableClustering設定時��期化ロジックを調整( #15223 ) - Fix: URL�URI�異�るエンティティ�照会�失敗�る�題を修正( #15039 ) -- Fix: ActivityPubリクエスト�����判定�正�����題を修正 +- Fix: ActivityPubリクエスト�����判定�正�����題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/869) - Fix: `/api/pages/update`��`name`を指定���リクエスト�る�エラー�発生�る�題を修正 - Fix: AIセンシティブ判定� arm64 環境�動作����題を修正 @@ -864,12 +864,12 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Fix: �知ら�作�時�画�URL入力欄を空欄�変更�����を修正 ( #14976 ) ### Client -- Enhance: Bull Dashboard�Relationship Queue�状態も確���るよ�� +- Enhance: Bull Dashboard�Relationship Queue�状態も確���るよ�� (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751) - Enhance: ドライブ�ソート���るよ�� - Enhance: アイコンデコレーション管�画��改善 - Enhance: 「��るラッキー���得�件を変更 -- Enhance: 投稿フォーム�Escキーを押����IME入力中�らフォームを閉���よ��( #10866 ) +- Enhance: 投稿フォーム�Escキーを押����IME入力中�らフォームを閉���よ��( #10866 ) - Enhance: MiAuth, OAuth���画��改善 - ��アカウント��証�よ�����る�����るよ�� - �証�るアカウントを切り替�られるよ�� @@ -877,29 +877,29 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Enhance: カタルーニャ語 (ca-ES) �対応 - Enhance: 個別�知ら�ページ��Metaタグを出力�るよ�� - Enhance: ノート詳細画��ロール��ッジを表示 -- Enhance: �去��信��フォローリクエストを確���るよ�� +- Enhance: �去��信��フォローリクエストを確���るよ�� (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/663) - Enhance: サイド�ーを簡��展開・折り�����るよ�� ( #14981 ) - Enhance: リノートメニュー�「リノート�詳細�を追加 - Enhance: �ログイン状態�Misskeyを開��際�パフォーマンスを�上 - Fix: 通知�範囲指定�設定項目�必���通知設定�も範囲指定�設定����る�題を修正 -- Fix: Turnstile�失敗・期�切れ��際�も�功扱���������題を修正 +- Fix: Turnstile�失敗・期�切れ��際�も�功扱���������題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768) - Fix: デッキ�タイムラインカラム�「センシティブ�ファイルを�むノートを表示�設定�使用�������題を修正 - Fix: Encode RSS urls with escape sequences before fetching allowing query parameters to be used - Fix: リンク切れを修正 -- Fix: ノート投稿ボタン�ホ�ー時�スタイル��用�れ�����を修正 +- Fix: ノート投稿ボタン�ホ�ー時�スタイル��用�れ�����を修正 (Cherry-picked from https://github.com/taiyme/misskey/pull/305) - Fix: メールアドレス登録有効化時�「完了�ダイアログボックス�表示�件を修正 -- Fix: 画�幅�狭�環境�デザイン�崩れる�題を修正 +- Fix: 画�幅�狭�環境�デザイン�崩れる�題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/815) -- Fix: TypeScript�型�ェック対象ファイルを�定��ビルドを高速化�るよ�� +- Fix: TypeScript�型�ェック対象ファイルを�定��ビルドを高速化�るよ�� (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/725) ### Server - Enhance: Docker�Node.jsを22.11.0�更新 -- Enhance: 起動��疎通�ェック��DB�メイン以外�Redis�疎通確�も行�よ�� - (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/588) +- Enhance: 起動��疎通�ェック��DB�メイン以外�Redis�疎通確�も行�よ�� + (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/588) (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/715) - Enhance: リモートユーザー�照会をオリジナル�リダイレクト�るよ�� - Fix: sharedInbox�無�Actor����リモートユーザーを照会���� @@ -907,18 +907,18 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Fix: フォロワー��メッセージ�絵文字をemojis���るよ�� - Fix: Nested proxy requestsを検出��際�ブロック�るよ�� [ghsa-gq5q-c77c-v236](https://github.com/misskey-dev/misskey/security/advisories/ghsa-gq5q-c77c-v236) -- Fix: 招待コード�発行�能�残り数算出�使用���ロール�リシー�値����題を修正 +- Fix: 招待コード�発行�能�残り数算出�使用���ロール�リシー�値����題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/706) -- Fix: 連����信時��acct�大�文字�区別�れ����正��メンション�処��れ������る�題を修正 +- Fix: 連����信時��acct�大�文字�区別�れ����正��メンション�処��れ������る�題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/711) -- Fix: ローカルユーザー��メンションを�むノート�連��れる際�正��URL�変��れ������る�題を修正 +- Fix: ローカルユーザー��メンションを�むノート�連��れる際�正��URL�変��れ������る�題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/712) -- Fix: FTT無効時�ユーザーリストタイムライン�使用�����題を修正 +- Fix: FTT無効時�ユーザーリストタイムライン�使用�����題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/709) -- Fix: User Webhookテスト機能�Mock Payloadを修正 -- Fix: アカウント削除�モデレーションログ�動作������を修正 (#14996) +- Fix: User Webhookテスト機能�Mock Payloadを修正 +- Fix: アカウント削除�モデレーションログ�動作������を修正 (#14996) - Fix: リノートミュート�新�投稿通知�対��作用��������題を修正 -- Fix: Inbox�処��生�るエラーを誤��Activity���処��る����る�題を修正 +- Fix: Inbox�処��生�るエラーを誤��Activity���処��る����る�題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/730) - Fix: セキュリティ�関�る修正 @@ -945,13 +945,13 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Enhance: 個人宛��知ら��「�����を押��自動的�アーカイブ�れるよ�� - Fix: `admin/emoji/update`エンド�イント�id��指定��時�正�エラー�発生�る�グを修正 - Fix: RBT有効時�リノート�リアクション��映�れ���題を修正 -- Fix: キュー�エラーログを簡略化�るよ�� +- Fix: キュー�エラーログを簡略化�るよ�� (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/649) ## 2024.10.0 ### Note -- セキュリティ�上����サー�ー�期設定時�使用�る�期パスワードを設定��るよ���り���。今後Misskeyサー�ーを新��設置�る際����回�起動��コンフィグファイル�`setupPassword`をコメントアウト���期パスワードを設定�る��を�������。(����期設定を完了���るサー�ー��������変更�伴�対応�る必���り��ん) +- セキュリティ�上����サー�ー�期設定時�使用�る�期パスワードを設定��るよ���り���。今後Misskeyサー�ーを新��設置�る際����回�起動��コンフィグファイル�`setupPassword`をコメントアウト���期パスワードを設定�る��を�������。(����期設定を完了���るサー�ー��������変更�伴�対応�る必���り��ん) - ホスティングサービスを�営���る場���コンフィグファイルを構築�る際�`setupPassword`をランダム�値�設定��ユーザー�通知�るよ��システムを更新�る��を�������。 - ����期パスワード�設定�れ����場��も�期設定を行�����能��(UI上��期パスワード�入力欄を空欄��る�続行����)。 - ユーザーデータを読�込む際�型�一部変更�れ���。 @@ -971,7 +971,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### Client - Enhance: デザイン�調整 - Enhance: ログイン画���証フローを改善 -- Fix: クライアント上��時間ベース�実績�得動作�実績�得後も発動�����題を修正 +- Fix: クライアント上��時間ベース�実績�得動作�実績�得後も発動�����題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/657) ### Server @@ -989,7 +989,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Feat: フォロー�れ�際�メッセージを設定��るよ�� - Feat: 連�をホワイトリスト制���るよ�� - Feat: UserWebhook�SystemWebhook�テスト�信機能を追加 (#14445) -- Feat: モデレーター�ユーザー����ら�ファイル�添付�れ��るノートを検索��るよ�� +- Feat: モデレーター�ユーザー����ら�ファイル�添付�れ��るノートを検索��るよ�� (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/680) - Feat: データエクス�ート�完了��際�通知を発行�るよ�� - Enhance: ユーザー�よるコンテンツイン�ート���をロール�リシー�制御��るよ�� @@ -1008,12 +1008,12 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Fix: サー�ーメトリクス�2�以上�る�リロード直後�表示������る�題を修正 - Fix: コントロールパ�ル内�Ap requests内��ャート�表示��������題を修正 - Fix: 月�����日�セパレータ�表示�れ���を修正 -- Fix: タッ�画��レンジスライダーを�作�る�ツール�ップ�複数表示�れる�題を修正 +- Fix: タッ�画��レンジスライダーを�作�る�ツール�ップ�複数表示�れる�題を修正 (Cherry-picked from https://github.com/taiyme/misskey/pull/265) -- Fix: 縦横比�極端�カスタム絵文字を表示�る際�レイアウト�崩れる箇所��る�を修正 +- Fix: 縦横比�極端�カスタム絵文字を表示�る際�レイアウト�崩れる箇所��る�を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/725) - Fix: 設定変更時�リロード確�ダイアログ�複数個表示�れる����る�題を修正 -- Fix: ファイル�詳細ページ�ファイル�説明�改行�正��表示�れ���題を修正 +- Fix: ファイル�詳細ページ�ファイル�説明�改行�正��表示�れ���題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/bde6bb0bd2e8b0d027e724d2acdb8ae0585a8110) - Fix: 一部画��ページ�ーション�動作����������を修正 ( #12766 , #11449 ) @@ -1022,14 +1022,14 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Fix: アンテナ�書�込�時�キーワード�与�られ����場��エラーをApiError���投�るよ�� - ��変更�より�公�フロントエンド��入力��備�内部エラー���報告�れる代�り�一般的�エラーダイアログ�報告�れ�� - Fix: ファイル�サイズ�制�を超��アップロード�れ�際�エラーを返������題を修正 -- Fix: 外部ページを解��る際��ページ����られ�関連リソースも読�込�れ�����題を修正 +- Fix: 外部ページを解��る際��ページ����られ�関連リソースも読�込�れ�����題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/26e0412fbb91447c37e8fb06ffb0487346063bb8) - Fix: Continue importing from file if single emoji import fails -- Fix: `Retry-After`ヘッダー��信�れ�����題を修正 +- Fix: `Retry-After`ヘッダー��信�れ�����題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/8a982c61c01909e7540ff1be9f019df07c3f0624) -- Fix: サー�ーサイド�DOM解�完了時�リソースを開放�るよ�� +- Fix: サー�ーサイド�DOM解�完了時�リソースを開放�るよ�� (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/634) -- Fix: ``を追��照会�る��OKレス�ンス�返��れ�場���� +- Fix: ``を追��照会�る��OKレス�ンス�返��れ�場���� (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/633) - Fix: メール�スタイル��用�れ�������題を修正 @@ -1058,15 +1058,15 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - 通知ページや通知カラム(デッキ)を開���る状態�����新��発生��通知�既読�れ���題�修正�れ��。 - �れ�より�プッシュ通知�有効���件下�環境�����プッシュ通知�常�発生������題も修正�れ��。 - Fix: Play�種エンド�イント�返り値�`visibility`���れ�����題を修正 -- Fix: サー�ー情報�得�際�モデレーター�定�情報��得��������る�を修正 +- Fix: サー�ー情報�得�際�モデレーター�定�情報��得��������る�を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/582) -- Fix: 公開範囲�ダイレクト�ノートをユーザーアクティビティ��ャート生��使用���よ�� +- Fix: 公開範囲�ダイレクト�ノートをユーザーアクティビティ��ャート生��使用���よ�� (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/679) - Fix: ActivityPub�エンティティタイプ判定��明�タイプを�����場��も処�を継続�るよ�� - キュー処����り�改善�れる�能性��り�� - Fix: リ�ーシ�対局設定�変更��映�れ���を修正 - Fix: 無制��ストリーミング��ャン�ル�接続��る�題を修正 -- Fix: ベースロール��リシーを変更��際�モデログ�記録�れ���を修正 +- Fix: ベースロール��リシーを変更��際�モデログ�記録�れ���を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/700) - Fix: Prevent memory leak from memory caches (#14310) - Fix: More reliable memory cache eviction (#14311) @@ -1098,9 +1098,9 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Enhance: 内蔵APIドキュメント�デザイン・パフォーマンスを改善 - Enhance: �ログイン時�他サー�ー��移�るアクションを追加 - Enhance: �ログイン時��イライトTL�デザインを改善 -- Enhance: フロントエンド�アクセシビリティ改善 +- Enhance: フロントエンド�アクセシビリティ改善 (Based on https://github.com/taiyme/misskey/pull/226) -- Enhance: サー�ー情報ページ・������ページを改善 +- Enhance: サー�ー情報ページ・������ページを改善 (Cherry-picked from https://github.com/taiyme/misskey/pull/238) - Enhance: AiScriptを0.19.0�アップデート - Enhance: Allow negative delay for MFM animation elements (`tada`, `jelly`, `twitch`, `shake`, `spin`, `jump`, `bounce`, `rainbow`) @@ -1109,7 +1109,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Enhance: 検索(ノート/ユーザー)�����入力�空白���れ��る場��照会を行���よ�� - Enhance: 検索(ノート/ユーザー)�����照会を行�������ッシュタグ�ノート/ユーザー一覧ページを表示�る�����確�ダイアログを出�よ�� - Enhance: 検索(ノート/ユーザー)� `@` �ら始�る文字列(`@user@host`��)を入力�る����ユーザーを照会��るよ�� -- Enhance: ドライブ�ファイル・フォルダをドラッグ����も移動��るよ�� +- Enhance: ドライブ�ファイル・フォルダをドラッグ����も移動��るよ�� (Cherry-picked from https://github.com/nafu-at/misskey/commit/b89c2af6945c6a9f9f10e83f54d2bcf0f240b0b4, https://github.com/nafu-at/misskey/commit/8a7d710c6acb83f50c83f050bd1423c764d60a99) - Enhance: デッキ�アンテナ・リスト�択画��ら�れ�れを新�作���るよ�� - Enhance: ブラウザ�コンテキストメニューを使用��るよ�� @@ -1117,19 +1117,19 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Fix: `/about#federation` ページ����インスタンス��ャート�表示�れ��������題を修正 - Fix: ユーザーページ�追加情報�ラベルを投稿者�サー�ー�絵文字�表示�る (#13968) - Fix: リ�ーシ�対局を正��共有��������る�題を修正 -- Fix: コントロールパ�ル�ベースロール��リシーを編集��もUI上��変更��映�れ���題を修正 +- Fix: コントロールパ�ル�ベースロール��リシーを編集��もUI上��変更��映�れ���題を修正 - Fix: アンテナ�編集画��ボタン�隙間を追加 - Fix: テーマプレビュー�見れ���題を修正 -- Fix: ショートカットキー�連打��る�題を修正 +- Fix: ショートカットキー�連打��る�題を修正 (Cherry-picked from https://github.com/taiyme/misskey/pull/234) - Fix: MkSignin.vue�credentialRequest�らReactivityを削除(Proxy�Passkey�証処��渡る��を��る��) -- Fix: 「アニメーション画�を�生�����オン����もサー�ー��ナー画�・背景画��アニメーション������題を修正 +- Fix: 「アニメーション画�を�生�����オン����もサー�ー��ナー画�・背景画��アニメーション������題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/574) - Fix: Twitch�埋�込��開����題を修正 - Fix: �メニュー�高��ウィンドウ�ら��出る����る�題を修正 - Fix: 個人宛��ダイアログ形���知ら���時表示�れ���題を修正 - Fix: 一部�画��センシティブ指定�れ��る���画��何も表示�れ������る�を修正 -- Fix: リアクション��ユーザー一覧�ユーザー����出る�題を修正 +- Fix: リアクション��ユーザー一覧�ユーザー����出る�題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/672) - Fix: `/share`ページ����絵文字ピッカーを開���������題を修正 - Fix: deck ui�通知音���る�題 (#14029) @@ -1172,14 +1172,14 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` 4. フォロー������アクティブ�ユーザ ���自分自身�アカウントもサジェスト�れるよ���り���。 -- Fix: 一般ユーザー�ら見�ユーザー��ッジ�一覧�公開�れ����も����れる����る�題を修正 +- Fix: 一般ユーザー�ら見�ユーザー��ッジ�一覧�公開�れ����も����れる����る�題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/652) - Fix: ユーザー�リアクション一覧�ミュート/ブロック�機能��������題を修正 - Fix: FTT有効時�リモートユーザー�ノート�HTL�キャッシュ�れる�題を修正 - Fix: 一部�通知�ローカル上�リモートユーザー�対��行�れ����題を修正 - Fix: エラーメッセージ�誤字を修正 (#14213) - Fix: ソーシャルタイムライン�ローカルタイムライン�表示�れる自分��リプライ�表示�れ���題を修正 -- Fix: リノート�ミュート��用�れる���時間���る����る�題を修正 +- Fix: リノート�ミュート��用�れる���時間���る����る�題を修正 (Cherry-picked from https://github.com/Type4ny-Project/Type4ny/commit/e9601029b52e0ad43d9131b555b614e56c84ebc1) - Fix: Steaming API��正�データを���場��動作��安定��る�題 #14251 - Fix: `users/search`���� `@` �ら始�る文字列�与�られ�際�処��正�������題を修正 @@ -1206,7 +1206,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### General - Feat: エラートラッキング�Sentryを使用��るよ���り��� - Enhance: URLプレビュー�有効化・無効化を設定��るよ�� #13569 -- Enhance: アンテナ�Bot�よるノートを除外��るよ�� +- Enhance: アンテナ�Bot�よるノートを除外��るよ�� (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545) - Enhance: クリップ�ノート数を表示�るよ�� - Enhance: コンディショナルロール��件���以下を新��追加 (#13667) @@ -1225,7 +1225,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### Client - Feat: アップロード�るファイル���をランダム文字列���るよ�� -- Feat: 個別��知ら��リンク�飛�るよ�� +- Feat: 個別��知ら��リンク�飛�るよ�� (Based on https://github.com/MisskeyIO/misskey/pull/639) - Enhance: 自分�ノート�添付ファイル�ら直接ファイル�詳細ページ�飛�るよ�� - Enhance: 広告�Misskey��一ドメイン�場��Router��移�るよ�� @@ -1255,9 +1255,9 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Fix: 一部�ページ内リンク�正��動作����題を修正 - Fix: 周年�実績��年を考慮����題を修正 - Fix: ローカルURL�プレビュー�ップアップ�左上�表示�れる -- Fix: WebGL2をサ�ート���ブラウザ�「季節�応��画��演出��有効�����る���Misskey�起動�����る�題を修正 +- Fix: WebGL2をサ�ート���ブラウザ�「季節�応��画��演出��有効�����る���Misskey�起動�����る�題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/459) -- Fix: ページタイトル�ローカルユーザー�リモートユーザー�区別������題を修正 +- Fix: ページタイトル�ローカルユーザー�リモートユーザー�区別������題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/528) - Fix: コードブロック�シンタックス�イライト�使用�れる定義ファイルをCDN�ら�得�るよ�� #13177 - CDN�ら�得��Misskey本体��ンドル�る場��`pacakges/frontend/vite.config.ts`を修正������。 @@ -1280,13 +1280,13 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Enhance: ドライブ�ファイル�NSFW����個別�連��れるよ�� (#13756) - �能�場��ノート�添付ファイル�センシティブ判定�ファイル����り�� - Fix: リモート�ら���れ�アクティビティ�JSON-LD compactionを��る -- Fix: フォローリクエストを作��る際�既存�も��削除�るよ�� +- Fix: フォローリクエストを作��る際�既存�も��削除�るよ�� (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440) - Fix: エンド�イント`notes/translate`�エラーを改善 - Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632) - Fix: 一部�音声ファイル�映�ファイル���扱�れる�題を修正 - Fix: リプライ���引用リノート��CW���引用リノート�純粋�リノート���誤��扱�れ�����題を修正 -- Fix: 登録�メール�証�必須�����る場��登録�れ��るメールアドレスを削除����よ�� +- Fix: 登録�メール�証�必須�����る場��登録�れ��るメールアドレスを削除����よ�� (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/606) - Fix: Add Cache-Control to Bull Board - Fix: nginx経由�/files/�Rangeリクエスト�れ�場��正��応答�����を修正 @@ -1479,10 +1479,10 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### Note - �存関係�更新�伴��Node.js 20.10.0�最��件��り��� - 絵文字�追加辞書を既�インストール���る場����手数����インストール����願���� -- 絵文字ピッカー�ピン留�表示�る絵文字設定�「リアクション用��「絵文字入力用��分�れ���。以��設定�「リアクション用����使用�れ��。 +- 絵文字ピッカー�ピン留�表示�る絵文字設定�「リアクション用��「絵文字入力用��分�れ���。以��設定�「リアクション用����使用�れ��。 - **影響:** - �れ�より�投稿フォーム�ら表示�れる絵文字ピッカー�ピン留�絵文字�リセット�れ�よ��感�る�も�れ��ん(新設�れ�"ピン留�(全般)"�設定�使�れる��)。 + **影響:** + �れ�より�投稿フォーム�ら表示�れる絵文字ピッカー�ピン留�絵文字�リセット�れ�よ��感�る�も�れ��ん(新設�れ�"ピン留�(全般)"�設定�使�れる��)。 投稿用�ピン留�絵文字をアップデート��状態��る���以下�手順��作���。 1. 「設定�メニュー�移動��「絵文字ピッカー�タブを�択���。 @@ -1529,7 +1529,7 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` - Enhance: Unicode 15.0�サ�ート - Enhance: コードブロック��イライト機能を利用�る��言語を明示的�指定��るよ�� - MFM�コードブロックを利用�る際��図����イライト�起�ら��よ���り��� - - 逆��MFM�コード�イライトを利用���際�言語を明示的�指定�る必���り�� + - 逆��MFM�コード�イライトを利用���際�言語を明示的�指定�る必���り�� (例: ` ```js ` → Javascript, ` ```ais ` → AiScript) - Enhance: 絵文字���オートコンプリート�Shift+Tabを押����候補を�択��るよ�� - Enhance: �ャン�ル�新��投稿��る場���ッジを表示��る @@ -1936,9 +1936,9 @@ v2025.12.0�行�れ�「config�`trustProxy`�デフォルト値を`false` ### General - 招待機能を改善���� - * �去�発行��招待コードを確���るよ���り��� - * ロール���招待コード�発行数制��制�対象期間�有効期�を設定��るよ���り��� - * 招待コードを作���ユーザー�使用��ユーザーを確���るよ���り��� + * �去�発行��招待コードを確���るよ���り��� + * ロール���招待コード�発行数制��制�対象期間�有効期�を設定��るよ���り��� + * 招待コードを作���ユーザー�使用��ユーザーを確���るよ���り��� - ユーザー�ロール�期�付��アサイン�れ��る場����期�をユーザー�モデレーションページ�確���るよ���り��� - identicon生�を無効���パフォーマンスを�上��る�����るよ���り��� - サー�ー�マシン情報�公開を無効���パフォーマンスを�上��る�����るよ���り��� @@ -2101,9 +2101,9 @@ Meilisearch�設定�`index`�必���り���。値�Misskeyサー * 「フォロワー����投稿�検索�果�表示�れ��ん。 - 新�登録��簡潔�ルールをユーザー�表示��る�サー�ールール機能を追加 - ユーザー��自分用メモ機能 - * ユーザー�対���自分���見られるメモを追加��るよ���り���。 + * ユーザー�対���自分���見られるメモを追加��るよ���り���。 (自分自身�対��もメモを追加����。) - * ユーザーメニュー�ら追加����。 + * ユーザーメニュー�ら追加����。 (デスクトップ表示��username����ボタン�らも追加�能) - �ャン�ル�色を設定��るよ���り���。�ノート�設定��色�インジケーター�表示�れ��。 - �ャン�ルをアーカイブ��るよ���り���。 diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index ebe8e9c9649..39396cb7411 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -376,7 +376,7 @@ export class ApPersonService implements OnModuleInit { isLocked: person.manuallyApprovesFollowers, movedToUri: person.movedTo, movedAt: person.movedTo ? new Date() : null, - alsoKnownAs: person.alsoKnownAs, + alsoKnownAs: toArray(person.alsoKnownAs), isExplorable: person.discoverable, username: person.preferredUsername, usernameLower: person.preferredUsername?.toLowerCase(), @@ -568,7 +568,7 @@ export class ApPersonService implements OnModuleInit { isCat: (person as any).isCat === true, isLocked: person.manuallyApprovesFollowers, movedToUri: person.movedTo ?? null, - alsoKnownAs: person.alsoKnownAs ?? null, + alsoKnownAs: person.alsoKnownAs ? toArray(person.alsoKnownAs) : null, isExplorable: person.discoverable, ...(await this.resolveAvatarAndBanner(exist, person.icon, person.image).catch(() => ({}))), } as Partial & Pick; diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 0f4051e7b89..996f0bad2e8 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -51,6 +51,7 @@ import { ChatService } from '@/core/ChatService.js'; import type { OnModuleInit } from '@nestjs/common'; import type { NoteEntityService } from './NoteEntityService.js'; import type { PageEntityService } from './PageEntityService.js'; +import { toArray } from '@/misc/prelude/array.js'; const Ajv = _Ajv.default; const ajv = new Ajv(); @@ -527,10 +528,10 @@ export class UserEntityService implements OnModuleInit { url: profile!.url, uri: user.uri, movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null, - alsoKnownAs: user.alsoKnownAs - ? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null))) - .then(xs => xs.length === 0 ? null : xs.filter(x => x != null)) - : null, + alsoKnownAs: user.alsoKnownAs ? + Promise.all(toArray(user.alsoKnownAs).map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null))) + .then(xs => xs.length === 0 ? null : xs.filter(x => x != null)) + : null, createdAt: this.idService.parse(user.id).date.toISOString(), updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null, diff --git a/packages/backend/test/unit/activitypub.ts b/packages/backend/test/unit/activitypub.ts index c6e09bdda2d..3022818b68d 100644 --- a/packages/backend/test/unit/activitypub.ts +++ b/packages/backend/test/unit/activitypub.ts @@ -224,6 +224,51 @@ describe('ActivityPub', () => { }); }); + describe('alsoKnownAs field', () => { + test('Handle alsoKnownAs as an array', async () => { + const actor = { + ...createRandomActor(), + alsoKnownAs: ['https://example.com/users/alice', 'https://example.com/users/alice2'], + }; + + resolver.register(actor.id, actor); + + const user = await personService.createPerson(actor.id, resolver); + + assert.deepStrictEqual(user.alsoKnownAs, actor.alsoKnownAs); + }); + + test('Handle alsoKnownAs as a string', async () => { + const actor = { + ...createRandomActor(), + alsoKnownAs: 'https://example.com/users/alice', + }; + + resolver.register(actor.id, actor); + + const user = await personService.createPerson(actor.id, resolver); + + assert.deepStrictEqual(user.alsoKnownAs, [actor.alsoKnownAs]); + }); + + test('Update person with alsoKnownAs as a string', async () => { + const actor = createRandomActor(); + resolver.register(actor.id, actor); + const user = await personService.createPerson(actor.id, resolver); + + const updatedActor = { + ...actor, + alsoKnownAs: 'https://example.com/users/alice', + }; + resolver.register(actor.id, updatedActor); + + await personService.updatePerson(actor.id, resolver, updatedActor); + + const updatedUser = await personService.fetchPerson(actor.id); + assert.deepStrictEqual(updatedUser?.alsoKnownAs, [updatedActor.alsoKnownAs]); + }); + }); + describe('Collection visibility', () => { test('Public following/followers', async () => { const actor = createRandomActor(); diff --git a/packages/backend/test/unit/entities/UserEntityService.ts b/packages/backend/test/unit/entities/UserEntityService.ts index ca6a639be8d..706c4a85c39 100644 --- a/packages/backend/test/unit/entities/UserEntityService.ts +++ b/packages/backend/test/unit/entities/UserEntityService.ts @@ -248,6 +248,16 @@ describe('UserEntityService', () => { expect(actual.achievements).toEqual(achievements); }); + test('alsoKnownAs as string does not throw', async () => { + const me = await createUser(); + const who = await createUser(); + + const whoWithStringAlsoKnownAs: MiUser = { ...who, alsoKnownAs: 'https://remote.example.com/users/alice' as any }; + + const actual = await service.pack(whoWithStringAlsoKnownAs, me, { schema: 'UserDetailedNotMe' }) as any; + expect(Array.isArray(actual.alsoKnownAs)).toBe(true); + }); + describe('packMany�よるpreload��る時�preload�無�時�pack��果�����る�見��', () => { test('no-preload', async() => { const me = await createUser(); From 0b7b59f1e2c2d6782c5dfddb86f3037815d73c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sun, 5 Apr 2026 17:22:17 +0900 Subject: [PATCH 006/578] =?UTF-8?q?enhance(frontend):=20=E3=83=81=E3=83=A3?= =?UTF-8?q?=E3=83=B3=E3=83=8D=E3=83=AB=E6=8C=87=E5=AE=9A=E3=83=AA=E3=83=8E?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=81=A7=E3=83=AA=E3=83=8E=E3=83=BC=E3=83=88?= =?UTF-8?q?=E5=85=88=E3=81=AE=E3=83=81=E3=83=A3=E3=83=B3=E3=83=8D=E3=83=AB?= =?UTF-8?q?=E3=81=AB=E7=A7=BB=E5=8B=95=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=20(#17280)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(frontend): �ャン�ル指定リノート�リノート先��ャン�ル�移動��るよ�� * Update Changelog * fix condition * refactor --- CHANGELOG.md | 2 +- locales/ja-JP.yml | 1 + packages/frontend/src/components/MkNote.vue | 22 ++++++--- .../src/components/MkNoteDetailed.vue | 45 +++++++++++++------ .../components/MkStreamingNotesTimeline.vue | 3 +- packages/frontend/src/di.ts | 3 +- packages/i18n/src/autogen/locale.ts | 4 ++ 7 files changed, 59 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97b6c057d38..b5d712db13a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - ### Client -- +- Enhance: �ャン�ル指定リノート�リノート先��ャン�ル�移動��るよ�� ### Server - Fix: `/api-doc` �アクセス�����題を修正 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 4af17dd39e7..93679aa24b6 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1408,6 +1408,7 @@ frame: "フレーム" presets: "プリセット" zeroPadding: "ゼロ埋�" nothingToConfigure: "設定項目��り��ん" +viewRenotedChannel: "リノート先��ャン�ルを見る" _imageEditing: _vars: diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index c78cc444258..ba68971034d 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -263,7 +263,7 @@ const emit = defineEmits<{ const inTimeline = inject('inTimeline', false); const tl_withSensitive = inject>('tl_withSensitive', ref(true)); -const inChannel = inject('inChannel', null); +const inChannel = inject(DI.inChannel, null); const currentClip = inject | null>('currentClip', null); let note = deepClone(props.note); @@ -650,23 +650,35 @@ async function showRenoteMenu() { }; } - const renoteDetailsMenu: MenuItem = { + const renoteDetailsMenu: MenuItem[] = [{ type: 'link', text: i18n.ts.renoteDetails, icon: 'ti ti-info-circle', to: notePage(note), - }; + }]; + + if ( + props.note.channelId != null && + (inChannel == null || props.note.channelId !== inChannel.value) + ) { + renoteDetailsMenu.push({ + type: 'link', + text: i18n.ts.viewRenotedChannel, + icon: 'ti ti-device-tv', + to: `/channels/${props.note.channelId}`, + }); + } if (isMyRenote) { os.popupMenu([ - renoteDetailsMenu, + ...renoteDetailsMenu, getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote), { type: 'divider' }, getUnrenote(), ], renoteTime.value); } else { os.popupMenu([ - renoteDetailsMenu, + ...renoteDetailsMenu, getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote), { type: 'divider' }, getAbuseNoteMenu(note, i18n.ts.reportAbuseRenote), diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 083e3e5da06..114edc6204d 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -238,6 +238,7 @@ import { isLink } from '@@/js/is-link.js'; import { host } from '@@/js/config.js'; import type { OpenOnRemoteOptions } from '@/utility/please-login.js'; import type { Keymap } from '@/utility/hotkey.js'; +import type { MenuItem } from '@/types/menu.js'; import MkNoteSub from '@/components/MkNoteSub.vue'; import MkNoteSimple from '@/components/MkNoteSimple.vue'; import MkReactionsViewer from '@/components/MkReactionsViewer.vue'; @@ -286,7 +287,7 @@ const props = withDefaults(defineProps<{ initialTab: 'replies', }); -const inChannel = inject('inChannel', null); +const inChannel = inject(DI.inChannel, null); let note = deepClone(props.note); @@ -581,18 +582,36 @@ async function showRenoteMenu() { const isLoggedIn = await pleaseLogin({ openOnRemote: pleaseLoginContext.value }); if (!isLoggedIn) return; - os.popupMenu([{ - text: i18n.ts.unrenote, - icon: 'ti ti-trash', - danger: true, - action: () => { - misskeyApi('notes/delete', { - noteId: note.id, - }).then(() => { - globalEvents.emit('noteDeleted', note.id); - }); - }, - }], renoteTime.value); + const menu: MenuItem[] = []; + + if (isMyRenote) { + menu.push({ + text: i18n.ts.unrenote, + icon: 'ti ti-trash', + danger: true, + action: () => { + misskeyApi('notes/delete', { + noteId: note.id, + }).then(() => { + globalEvents.emit('noteDeleted', note.id); + }); + }, + }); + } + + if ( + props.note.channelId != null && + (inChannel == null || props.note.channelId !== inChannel.value) + ) { + menu.push({ + type: 'link', + text: i18n.ts.viewRenotedChannel, + icon: 'ti ti-device-tv', + to: `/channels/${props.note.channelId}`, + }); + } + + os.popupMenu(menu, renoteTime.value); } function focus() { diff --git a/packages/frontend/src/components/MkStreamingNotesTimeline.vue b/packages/frontend/src/components/MkStreamingNotesTimeline.vue index 9784d8e017e..00fd778a5ea 100644 --- a/packages/frontend/src/components/MkStreamingNotesTimeline.vue +++ b/packages/frontend/src/components/MkStreamingNotesTimeline.vue @@ -74,6 +74,7 @@ import { store } from '@/store.js'; import MkNote from '@/components/MkNote.vue'; import MkButton from '@/components/MkButton.vue'; import { i18n } from '@/i18n.js'; +import { DI } from '@/di.js'; import { globalEvents, useGlobalEvent } from '@/events.js'; import { isSeparatorNeeded, getSeparatorInfo } from '@/utility/timeline-date-separate.js'; import { Paginator } from '@/utility/paginator.js'; @@ -101,7 +102,7 @@ const props = withDefaults(defineProps<{ provide('inTimeline', true); provide('tl_withSensitive', computed(() => props.withSensitive)); -provide('inChannel', computed(() => props.src === 'channel')); +provide(DI.inChannel, computed(() => props.src === 'channel' ? props.channel ?? null : null)); let paginator: IPaginator; diff --git a/packages/frontend/src/di.ts b/packages/frontend/src/di.ts index f09782ea388..eddb0dcb35f 100644 --- a/packages/frontend/src/di.ts +++ b/packages/frontend/src/di.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import type { InjectionKey, Ref } from 'vue'; +import type { InjectionKey, Ref, ComputedRef } from 'vue'; import type { PageMetadata } from '@/page.js'; import type { Router } from '@/router.js'; @@ -18,4 +18,5 @@ export const DI = { mfmEmojiReactCallback: Symbol() as InjectionKey<(emoji: string) => void>, inModal: Symbol() as InjectionKey, inAppSearchMarkerId: Symbol() as InjectionKey>, + inChannel: Symbol() as InjectionKey | null>, // �在開���る�ャン�ル�ID }; diff --git a/packages/i18n/src/autogen/locale.ts b/packages/i18n/src/autogen/locale.ts index 05a21953747..69e7346a596 100644 --- a/packages/i18n/src/autogen/locale.ts +++ b/packages/i18n/src/autogen/locale.ts @@ -5647,6 +5647,10 @@ export interface Locale extends ILocale { * 設定項目��り��ん */ "nothingToConfigure": string; + /** + * リノート先��ャン�ルを見る + */ + "viewRenotedChannel": string; "_imageEditing": { "_vars": { /** From a18c909ba3ddbb5c3268b70cc05a3d384bf8ff6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 6 Apr 2026 20:15:57 +0900 Subject: [PATCH 007/578] Revert "deps: Update vite to v8" (#17283) Revert "deps: Update vite to v8 (#17238)" This reverts commit e601fcb729445c3d20ac6e0447e0143348491a43. --- packages/backend/package.json | 2 +- .../locale-inliner/collect-modifications.ts | 22 +- packages/frontend-builder/package.json | 5 +- .../rollup-plugin-remove-unref-i18n.ts | 27 +- packages/frontend-embed/build.ts | 2 +- packages/frontend-embed/package.json | 5 +- packages/frontend-embed/vite.config.ts | 27 +- .../vite-plugin-json5.ts => vite.json5.ts} | 7 +- ...lugin-unwind-css-module-class-name.test.ts | 347 +++---- ...lup-plugin-unwind-css-module-class-name.ts | 351 ++++--- .../lib/vite-plugin-create-search-index.ts | 39 +- .../frontend/lib/vite-plugin-watch-locales.ts | 6 +- packages/frontend/package.json | 16 +- packages/frontend/vite.config.ts | 40 +- .../vite-plugin-json5.ts => vite.json5.ts} | 7 +- pnpm-lock.yaml | 853 +++--------------- 16 files changed, 469 insertions(+), 1287 deletions(-) rename packages/frontend-embed/{lib/vite-plugin-json5.ts => vite.json5.ts} (90%) rename packages/frontend/{lib/vite-plugin-json5.ts => vite.json5.ts} (90%) diff --git a/packages/backend/package.json b/packages/backend/package.json index 40d963f3c7a..6b2e76480b2 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -228,6 +228,6 @@ "pid-port": "2.1.0", "simple-oauth2": "5.1.0", "supertest": "7.2.2", - "vite": "8.0.2" + "vite": "7.3.1" } } diff --git a/packages/frontend-builder/locale-inliner/collect-modifications.ts b/packages/frontend-builder/locale-inliner/collect-modifications.ts index 2e92a407c90..59e5d965172 100644 --- a/packages/frontend-builder/locale-inliner/collect-modifications.ts +++ b/packages/frontend-builder/locale-inliner/collect-modifications.ts @@ -3,11 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { parseAst } from 'rolldown/parseAst'; +import { parseAst } from 'vite'; import * as estreeWalker from 'estree-walker'; import { assertNever, assertType } from '../utils.js'; -import type { ESTree as RolldownESTree } from 'rolldown/utils'; -import type { AstNode } from 'rollup'; +import type { AstNode, ProgramNode } from 'rollup'; import type * as estree from 'estree'; import type { LocaleInliner, TextModification } from '../locale-inliner.js'; import type { Logger } from '../logger.js'; @@ -18,7 +17,7 @@ interface WalkerContext { } export function collectModifications(sourceCode: string, fileName: string, fileLogger: Logger, inliner: LocaleInliner): TextModification[] { - let programNode: RolldownESTree.Program; + let programNode: ProgramNode; try { programNode = parseAst(sourceCode); } catch (err) { @@ -36,8 +35,7 @@ export function collectModifications(sourceCode: string, fileName: string, fileL // 1) replace all `scripts/` path literals with locale code // 2) replace all `localStorage.getItem("lang")` with `localeName` variable // 3) replace all `await window.fetch(`/assets/locales/${d}.${x}.json`).then(u=>u.json())` with `localeJson` variable - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (estreeWalker.walk as any)(programNode, { + estreeWalker.walk(programNode, { enter(this: WalkerContext, node: Node) { assertType(node); @@ -120,9 +118,8 @@ export function collectModifications(sourceCode: string, fileName: string, fileL // Check if the identifier is already declared in the file. // If it is, we may overwrite it and cause issues so we skip inlining let isSupported = true; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (estreeWalker.walk as any)(programNode, { - enter(node: Node) { + estreeWalker.walk(programNode, { + enter(node) { if (node.type === 'VariableDeclaration') { assertType(node); for (const id of node.declarations.flatMap(x => declsOfPattern(x.id))) { @@ -148,9 +145,8 @@ export function collectModifications(sourceCode: string, fileName: string, fileL const toSkip = new Set(); toSkip.add(i18nImport); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (estreeWalker.walk as any)(programNode, { - enter(this: WalkerContext, node: Node, parent: Node | null, property: string | number | symbol | null | undefined) { + estreeWalker.walk(programNode, { + enter(this: WalkerContext, node, parent, property) { assertType(node); assertType(parent); if (toSkip.has(node)) { @@ -383,7 +379,7 @@ type SpecifierResult = | { type: 'specifier', localI18nIdentifier: string, importNode: estree.ImportDeclaration & AstNode } ; -function findImportSpecifier(programNode: RolldownESTree.Program, i18nFileName: string, i18nSymbol: string): SpecifierResult { +function findImportSpecifier(programNode: ProgramNode, i18nFileName: string, i18nSymbol: string): SpecifierResult { const imports = programNode.body.filter(x => x.type === 'ImportDeclaration'); const importNode = imports.find(x => x.source.value === `./${i18nFileName}`) as estree.ImportDeclaration | undefined; if (!importNode) return { type: 'no-import' }; diff --git a/packages/frontend-builder/package.json b/packages/frontend-builder/package.json index 28bcc47d632..f4326907d20 100644 --- a/packages/frontend-builder/package.json +++ b/packages/frontend-builder/package.json @@ -17,10 +17,9 @@ "rollup": "4.60.0" }, "dependencies": { - "estree-walker": "3.0.3", "i18n": "workspace:*", + "estree-walker": "3.0.3", "magic-string": "0.30.21", - "rolldown": "1.0.0-rc.11", - "vite": "8.0.2" + "vite": "7.3.1" } } diff --git a/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts b/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts index 6ff62b8f773..4a2bfa67d97 100644 --- a/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts +++ b/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts @@ -4,11 +4,11 @@ */ import * as estreeWalker from 'estree-walker'; -import { RolldownMagicString } from 'rolldown'; +import MagicString from 'magic-string'; import { assertType } from './utils.js'; -import type { ESTree } from 'rolldown/utils'; import type { Plugin } from 'vite'; -import type { CallExpression, Expression } from 'estree'; +import type { CallExpression, Expression, Program } from 'estree'; +import type { AstNode } from 'rollup'; // This plugin transforms `unref(i18n)` to `i18n` in the code, which is useful for removing unnecessary unref calls // and helps locale inliner runs after vite build to inline the locale data into the final build. @@ -23,13 +23,12 @@ export function pluginRemoveUnrefI18n( } = {}): Plugin { return { name: 'UnwindCssModuleClassName', - renderChunk(code, _chunk, _options, meta) { + renderChunk(code) { if (!code.includes('unref(i18n)')) return null; - const ast = this.parse(code); - const magicString = meta.magicString ?? new RolldownMagicString(code); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (estreeWalker.walk as any)(ast, { - enter(node: ESTree.Node) { + const ast = this.parse(code) as Program; + const magicString = new MagicString(code); + estreeWalker.walk(ast, { + enter(node) { if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === 'unref' && node.arguments.length === 1) { // calls to unref with single argument @@ -37,16 +36,18 @@ export function pluginRemoveUnrefI18n( if (arg.type === 'Identifier' && arg.name === i18nSymbolName) { // this is unref(i18n) so replace it with i18n // to replace, remove the 'unref(' and the trailing ')' - assertType(node); - assertType(arg); + assertType(node); + assertType(arg); magicString.remove(node.start, arg.start); magicString.remove(arg.end, node.end); } } }, }); - - return magicString; + return { + code: magicString.toString(), + map: magicString.generateMap({ hires: true }), + }; }, }; } diff --git a/packages/frontend-embed/build.ts b/packages/frontend-embed/build.ts index 0b4058f33a7..4e1f5888028 100644 --- a/packages/frontend-embed/build.ts +++ b/packages/frontend-embed/build.ts @@ -3,7 +3,7 @@ import url from 'node:url'; import path from 'node:path'; import { execa } from 'execa'; import locales from 'i18n'; -import { LocaleInliner } from '../frontend-builder/locale-inliner.js'; +import { LocaleInliner } from '../frontend-builder/locale-inliner.js' import { createLogger } from '../frontend-builder/logger'; // requires node 21 or later diff --git a/packages/frontend-embed/package.json b/packages/frontend-embed/package.json index 3bb8e00d59d..fa5ba3038e3 100644 --- a/packages/frontend-embed/package.json +++ b/packages/frontend-embed/package.json @@ -12,6 +12,7 @@ "dependencies": { "@discordapp/twemoji": "16.0.1", "@rollup/plugin-json": "6.1.0", + "@rollup/plugin-replace": "6.0.3", "@rollup/pluginutils": "5.3.0", "@twemoji/parser": "16.0.0", "@vitejs/plugin-vue": "6.0.5", @@ -25,9 +26,11 @@ "misskey-js": "workspace:*", "punycode.js": "2.3.1", "rollup": "4.60.0", + "sass": "1.98.0", "shiki": "3.23.0", "tinycolor2": "1.6.0", "uuid": "13.0.0", + "vite": "7.3.1", "vue": "3.5.30" }, "devDependencies": { @@ -54,10 +57,8 @@ "msw": "2.12.14", "nodemon": "3.1.14", "prettier": "3.8.1", - "sass-embedded": "1.98.0", "start-server-and-test": "2.1.5", "tsx": "4.21.0", - "vite": "8.0.2", "vite-plugin-turbosnap": "1.0.3", "vue-component-type-helpers": "3.2.6", "vue-eslint-parser": "10.4.0", diff --git a/packages/frontend-embed/vite.config.ts b/packages/frontend-embed/vite.config.ts index 7f5be591e88..9e5c24f9d4d 100644 --- a/packages/frontend-embed/vite.config.ts +++ b/packages/frontend-embed/vite.config.ts @@ -7,10 +7,10 @@ import { promises as fsp } from 'fs'; import locales from 'i18n'; import meta from '../../package.json'; import packageInfo from './package.json' with { type: 'json' }; -import pluginJson5 from './lib/vite-plugin-json5.js'; +import pluginJson5 from './vite.json5.js'; import { pluginRemoveUnrefI18n } from '../frontend-builder/rollup-plugin-remove-unref-i18n'; -const url = process.env.NODE_ENV === 'development' ? (yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')) as any).url : null; +const url = process.env.NODE_ENV === 'development' ? yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')).url : null; const host = url ? (new URL(url)).hostname : undefined; const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue']; @@ -113,6 +113,11 @@ export function getConfig(): UserConfig { } }, }, + preprocessorOptions: { + scss: { + api: 'modern-compiler', + }, + }, }, define: { @@ -132,10 +137,7 @@ export function getConfig(): UserConfig { 'safari16', ], manifest: 'manifest.json', - rolldownOptions: { - experimental: { - nativeMagicString: true, - }, + rollupOptions: { input: { i18n: './src/i18n.ts', entry: './src/boot.ts', @@ -143,15 +145,10 @@ export function getConfig(): UserConfig { external: externalPackages.map(p => p.match), preserveEntrySignatures: 'allow-extension', output: { - codeSplitting: { - groups: [{ - name: 'vue', - test: /node_modules[\\/]vue/, - }, { - // dependencies of i18n.ts - name: 'config', - test: /@@[\\/]js[\\/]config\.js/, - }], + manualChunks: { + vue: ['vue'], + // dependencies of i18n.ts + 'config': ['@@/js/config.js'], }, entryFileNames: `scripts/${localesHash}-[hash:8].js`, chunkFileNames: `scripts/${localesHash}-[hash:8].js`, diff --git a/packages/frontend-embed/lib/vite-plugin-json5.ts b/packages/frontend-embed/vite.json5.ts similarity index 90% rename from packages/frontend-embed/lib/vite-plugin-json5.ts rename to packages/frontend-embed/vite.json5.ts index 921324b67a4..87b67c21424 100644 --- a/packages/frontend-embed/lib/vite-plugin-json5.ts +++ b/packages/frontend-embed/vite.json5.ts @@ -1,10 +1,7 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ +// Original: https://github.com/rollup/plugins/tree/8835dd2aed92f408d7dc72d7cc25a9728e16face/packages/json import JSON5 from 'json5'; -import { Plugin } from 'vite'; +import { Plugin } from 'rollup'; import { createFilter, dataToEsm } from '@rollup/pluginutils'; import { RollupJsonOptions } from '@rollup/plugin-json'; diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts index 0a5000f46d5..ccfa08575bd 100644 --- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts @@ -3,15 +3,15 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { parse } from 'acorn'; +import { generate } from 'astring'; import { describe, expect, it } from 'vitest'; import { normalizeClass, unwindCssModuleClassName } from './rollup-plugin-unwind-css-module-class-name.js'; -import { parseAst } from 'rolldown/parseAst'; -import type { ESTree } from 'rolldown/utils'; -import { RolldownMagicString } from 'rolldown'; +import type * as estree from 'estree'; -function parseExpression(code: string): ESTree.Expression { - const program = parseAst(code, { sourceType: 'module' }); - const statement = program.body[0] as ESTree.ExpressionStatement; +function parseExpression(code: string): estree.Expression { + const program = parse(code, { ecmaVersion: 'latest', sourceType: 'module' }) as unknown as estree.Program; + const statement = program.body[0] as estree.ExpressionStatement; return statement.expression; } @@ -57,7 +57,7 @@ describe(normalizeClass.name, () => { }); it('Composition API (standard)', () => { - const code = ` + const ast = parse(` import { c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js'; import { M as MkContainer } from './MkContainer-!~{03M}~.js'; import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js'; @@ -170,19 +170,17 @@ const cssModules = { const index_photos = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); export { index_photos as default }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - expect(magicString.toString()).toBe( - ` -import { c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js'; -import { M as MkContainer } from './MkContainer-!~{03M}~.js'; -import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js'; +`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); + unwindCssModuleClassName(ast); + expect(generate(ast)).toBe(` +import {c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc} from './app-!~{001}~.js'; +import {M as MkContainer} from './MkContainer-!~{03M}~.js'; +import {b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode} from './vue-!~{002}~.js'; import './photoswipe-!~{003}~.js'; - -const _hoisted_1 = /* @__PURE__ */ createBaseVNode("i", { class: "ti ti-photo" }, null, -1); -const index_photos = /* @__PURE__ */ defineComponent({ +const _hoisted_1 = createBaseVNode("i", { + class: "ti ti-photo" +}, null, -1); +const index_photos = defineComponent({ __name: "index.photos", props: { user: {} @@ -195,20 +193,12 @@ const index_photos = /* @__PURE__ */ defineComponent({ return store.s.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; } onMounted(() => { - const image = [ - "image/jpeg", - "image/webp", - "image/avif", - "image/png", - "image/gif", - "image/apng", - "image/vnd.mozilla.apng" - ]; + const image = ["image/jpeg", "image/webp", "image/avif", "image/png", "image/gif", "image/apng", "image/vnd.mozilla.apng"]; api("users/notes", { userId: props.user.id, fileType: image, limit: 10 - }).then((notes) => { + }).then(notes => { for (const note of notes) { for (const file of note.files) { images.value.push({ @@ -223,77 +213,60 @@ const index_photos = /* @__PURE__ */ defineComponent({ return (_ctx, _cache) => { const _component_MkLoading = resolveComponent("MkLoading"); const _component_MkA = resolveComponent("MkA"); - return openBlock(), createBlock(MkContainer, { + return (openBlock(), createBlock(MkContainer, { "max-height": 300, foldable: true }, { - icon: withCtx(() => [ - _hoisted_1 - ]), - header: withCtx(() => [ - createTextVNode(toDisplayString(unref(i18n).ts.images), 1) - ]), - default: withCtx(() => [ - createBaseVNode("div", { - class: "xenMW" - }, [ - unref(fetching) ? (openBlock(), createBlock(_component_MkLoading, { key: 0 })) : createCommentVNode("", true), - !unref(fetching) && unref(images).length > 0 ? (openBlock(), createElementBlock("div", { - key: 1, - class: "xaZzf" - }, [ - (openBlock(true), createElementBlock(Fragment, null, renderList(unref(images), (image) => { - return openBlock(), createBlock(_component_MkA, { - key: image.note.id + image.file.id, - class: "xtA8t", - to: unref(notePage)(image.note) - }, { - default: withCtx(() => [ - createVNode(ImgWithBlurhash, { - hash: image.file.blurhash, - src: thumbnail(image.file), - title: image.file.name - }, null, 8, ["hash", "src", "title"]) - ]), - _: 2 - }, 1032, ["class", "to"]); - }), 128)) - ], 2)) : createCommentVNode("", true), - !unref(fetching) && unref(images).length == 0 ? (openBlock(), createElementBlock("p", { - key: 2, - class: "xhYKj" - }, toDisplayString(unref(i18n).ts.nothing), 3)) : createCommentVNode("", true) - ], 2) - ]), + icon: withCtx(() => [_hoisted_1]), + header: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).ts.images), 1)]), + default: withCtx(() => [createBaseVNode("div", { + class: "xenMW" + }, [unref(fetching) ? (openBlock(), createBlock(_component_MkLoading, { + key: 0 + })) : createCommentVNode("", true), !unref(fetching) && unref(images).length > 0 ? (openBlock(), createElementBlock("div", { + key: 1, + class: "xaZzf" + }, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(images), image => { + return (openBlock(), createBlock(_component_MkA, { + key: image.note.id + image.file.id, + class: "xtA8t", + to: unref(notePage)(image.note) + }, { + default: withCtx(() => [createVNode(ImgWithBlurhash, { + hash: image.file.blurhash, + src: thumbnail(image.file), + title: image.file.name + }, null, 8, ["hash", "src", "title"])]), + _: 2 + }, 1032, ["class", "to"])); + }), 128))], 2)) : createCommentVNode("", true), !unref(fetching) && unref(images).length == 0 ? (openBlock(), createElementBlock("p", { + key: 2, + class: "xhYKj" + }, toDisplayString(unref(i18n).ts.nothing), 3)) : createCommentVNode("", true)], 2)]), _: 1 - }); + })); }; } }); - const root = "xenMW"; const stream = "xaZzf"; const img = "xtA8t"; const empty = "xhYKj"; const style0 = { - root: root, - stream: stream, - img: img, - empty: empty + root: root, + stream: stream, + img: img, + empty: empty }; - const cssModules = { "$style": style0 }; - - -export { index_photos as default }; -`.slice(1), - ); +export {index_photos as default}; +`.slice(1)); }); it('Composition API (with `useCssModule()`)', () => { - const code = ` + const ast = parse(` import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js'; import { d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js'; @@ -464,15 +437,11 @@ const cssModules = { const MkDateSeparatedList = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); export { MkDateSeparatedList as M }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - expect(magicString.toString()).toBe( - ` -import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js'; -import { d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js'; - +`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); + unwindCssModuleClassName(ast); + expect(generate(ast)).toBe(` +import {a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup} from './!~{002}~.js'; +import {d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc} from './app-!~{001}~.js'; function isDebuggerEnabled(id) { try { return localStorage.getItem(\`DEBUG_\${id}\`) !== null; @@ -489,7 +458,6 @@ function stackTraceInstances() { } return stack; } - const _sfc_main = defineComponent({ props: { items: { @@ -517,7 +485,7 @@ const _sfc_main = defineComponent({ default: false } }, - setup(props, { slots, expose }) { + setup(props, {slots, expose}) { const $style = useCssModule(); function getDateText(time) { const date = new Date(time).getDate(); @@ -527,40 +495,28 @@ const _sfc_main = defineComponent({ day: date.toString() }); } - if (props.items.length === 0) - return; + if (props.items.length === 0) return; const renderChildrenImpl = () => props.items.map((item, i) => { - if (!slots || !slots.default) - return; + if (!slots || !slots.default) return; const el = slots.default({ item })[0]; - if (el.key == null && item.id) - el.key = item.id; + if (el.key == null && item.id) el.key = item.id; if (i !== props.items.length - 1 && new Date(item.createdAt).getDate() !== new Date(props.items[i + 1].createdAt).getDate()) { const separator = h("div", { class: $style["separator"], key: item.id + ":separator" }, h("p", { class: $style["date"] - }, [ - h("span", { - class: $style["date-1"] - }, [ - h("i", { - class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` - }), - getDateText(item.createdAt) - ]), - h("span", { - class: $style["date-2"] - }, [ - getDateText(props.items[i + 1].createdAt), - h("i", { - class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` - }) - ]) - ])); + }, [h("span", { + class: $style["date-1"] + }, [h("i", { + class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` + }), getDateText(item.createdAt)]), h("span", { + class: $style["date-2"] + }, [getDateText(props.items[i + 1].createdAt), h("i", { + class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` + })])])); return [el, separator]; } else { if (props.ad && item._shouldInsertAd_) { @@ -576,13 +532,17 @@ const _sfc_main = defineComponent({ const renderChildren = () => { const children = renderChildrenImpl(); if (isDebuggerEnabled(6864)) { - const nodes = children.flatMap((node) => node ?? []); - const keys = new Set(nodes.map((node) => node.key)); + const nodes = children.flatMap(node => node ?? []); + const keys = new Set(nodes.map(node => node.key)); if (keys.size !== nodes.length) { const id = crypto.randomUUID(); const instances = stackTraceInstances(); toast(instances.reduce((a, c) => \`\${a} at \${c.type.name}\`, \`[DEBUG_6864 (\${id})]: \${nodes.length - keys.size} duplicated keys found\`)); - console.warn({ id, debugId: 6864, stack: instances }); + console.warn({ + id, + debugId: 6864, + stack: instances + }); } } return children; @@ -595,136 +555,45 @@ const _sfc_main = defineComponent({ el.style.top = ""; el.style.left = ""; } - return () => h( - prefer.s.animation ? TransitionGroup : "div", - { - class: { - [$style["date-separated-list"]]: true, - [$style["date-separated-list-nogap"]]: props.noGap, - [$style["reversed"]]: props.reversed, - [$style["direction-down"]]: props.direction === "down", - [$style["direction-up"]]: props.direction === "up" - }, - ...prefer.s.animation ? { - name: "list", - tag: "div", - onBeforeLeave, - onLeaveCanceled - } : {} + return () => h(prefer.s.animation ? TransitionGroup : "div", { + class: { + [$style["date-separated-list"]]: true, + [$style["date-separated-list-nogap"]]: props.noGap, + [$style["reversed"]]: props.reversed, + [$style["direction-down"]]: props.direction === "down", + [$style["direction-up"]]: props.direction === "up" }, - { default: renderChildren } - ); + ...prefer.s.animation ? { + name: "list", + tag: "div", + onBeforeLeave, + onLeaveCanceled + } : {} + }, { + default: renderChildren + }); } }); - const reversed = "xxiZh"; const separator = "xxeDx"; const date = "xxawD"; const style0 = { - "date-separated-list": "xfKPa", - "date-separated-list-nogap": "xf9zr", - "direction-up": "x7AeO", - "direction-down": "xBIqc", - reversed: reversed, - separator: separator, - date: date, - "date-1": "xwtmh", - "date-1-icon": "xsNPa", - "date-2": "x1xvw", - "date-2-icon": "x9ZiG" + "date-separated-list": "xfKPa", + "date-separated-list-nogap": "xf9zr", + "direction-up": "x7AeO", + "direction-down": "xBIqc", + reversed: reversed, + separator: separator, + date: date, + "date-1": "xwtmh", + "date-1-icon": "xsNPa", + "date-2": "x1xvw", + "date-2-icon": "x9ZiG" }; - const cssModules = { "$style": style0 }; -const MkDateSeparatedList = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); - -export { MkDateSeparatedList as M }; +const MkDateSeparatedList = _export_sfc(_sfc_main, [["__cssModules", cssModules]]); +export {MkDateSeparatedList as M}; `.slice(1)); }); - -it('Composition API (inlined output)', () => { - const code = ` -import { a as normalizeClass, b as defineComponent, c as _export_sfc } from './runtime.js'; - -const CurrentComponent = /* @__PURE__ */ _export_sfc(defineComponent({ - __name: "CurrentComponent", - setup() { - return (e, n) => h("div", { - class: normalizeClass([e.$style.root, "extra"]) - }, null, 2); - } -}), [["__cssModules", { - "$style": { - root: "x1234" - } -}]]); - -export { CurrentComponent as default }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - const output = magicString.toString(); - expect(output).toContain('class: "x1234 extra"'); - expect(output).toContain('defineComponent({'); - expect(output).toContain('}), []);'); - expect(output).not.toContain('$style'); -}); - -it('should keep cssModules when unresolved references remain', () => { - const code = ` -import { a as normalizeClass, b as defineComponent, c as _export_sfc } from './runtime.js'; - -const CurrentComponent = /* @__PURE__ */ _export_sfc(defineComponent({ - __name: "CurrentComponent", - setup() { - return (e, n) => h("div", { - class: normalizeClass([e.$style.root, e.$style[side]]) - }, null, 2); - } -}), [["__cssModules", { - "$style": { - root: "x1234" - } -}]]); - -export { CurrentComponent as default }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - const output = magicString.toString(); - expect(output).toContain('e.$style[side]'); - expect(output).toContain('__cssModules'); - expect(output).not.toContain('}), []);'); -}); - -it('should inline cssModules references used inside class expressions', () => { - const code = ` -import { a as classHelper, b as defineComponent, c as _export_sfc } from './runtime.js'; - -const CurrentComponent = /* @__PURE__ */ _export_sfc(defineComponent({ - __name: "CurrentComponent", - setup() { - return (e, n) => h("div", { - class: classHelper([e.$style.root, { [e.$style.main]: isActive }]) - }, null, 2); - } -}), [["__cssModules", { - "$style": { - root: "x1234", - main: "x5678" - } -}]]); - -export { CurrentComponent as default }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - const output = magicString.toString(); - expect(output).toContain('class: classHelper(["x1234", { ["x5678"]: isActive }])'); - expect(output).toContain('}), []);'); - expect(output).not.toContain('$style'); -}); diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts index d82f1512fca..7ecb1e9179e 100644 --- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts @@ -3,16 +3,17 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import * as estreeWalker from 'estree-walker'; +import { generate } from 'astring'; +import { walk } from '../node_modules/estree-walker/src/index.js'; +import type * as estree from 'estree'; +import type * as estreeWalker from 'estree-walker'; import type { Plugin } from 'vite'; -import type { ESTree } from 'rolldown/utils'; -import { RolldownMagicString } from 'rolldown'; -function isFalsyIdentifier(identifier: Extract): boolean { +function isFalsyIdentifier(identifier: estree.Identifier): boolean { return identifier.name === 'undefined' || identifier.name === 'NaN'; } -function normalizeClassWalker(tree: ESTree.Node, stack: string | undefined): string | null { +function normalizeClassWalker(tree: estree.Node, stack: string | undefined): string | null { if (tree.type === 'Identifier') return isFalsyIdentifier(tree) ? '' : null; if (tree.type === 'Literal') return typeof tree.value === 'string' ? tree.value : ''; if (tree.type === 'BinaryExpression') { @@ -25,7 +26,7 @@ function normalizeClassWalker(tree: ESTree.Node, stack: string | undefined): str if (tree.type === 'TemplateLiteral') { if (tree.expressions.some((x) => x.type !== 'Literal' && (x.type !== 'Identifier' || !isFalsyIdentifier(x)))) return null; return tree.quasis.reduce((a, c, i) => { - const v = i === tree.quasis.length - 1 ? '' : (tree.expressions[i] as Partial>).value; + const v = i === tree.quasis.length - 1 ? '' : (tree.expressions[i] as Partial).value; return a + c.value.raw + (typeof v === 'string' ? v : ''); }, ''); } @@ -71,144 +72,44 @@ function normalizeClassWalker(tree: ESTree.Node, stack: string | undefined): str tree.type !== 'ChainExpression' && tree.type !== 'ConditionalExpression' && tree.type !== 'LogicalExpression' && - tree.type !== 'MemberExpression' - ) { + tree.type !== 'MemberExpression') { console.error(stack ? `Unexpected node type: ${tree.type} (in ${stack})` : `Unexpected node type: ${tree.type}`); } return null; } -export function normalizeClass(tree: ESTree.Node, stack?: string): string | null { +export function normalizeClass(tree: estree.Node, stack?: string): string | null { const walked = normalizeClassWalker(tree, stack); return walked && walked.replace(/^\s+|\s+(?=\s)|\s+$/g, ''); } -function getPropertyName(node: ESTree.Node, computed: boolean): string | null { - if (node.type === 'Identifier') return computed ? null : node.name; - if (node.type === 'Literal' && typeof node.value === 'string') return node.value; - return null; -} - -function getMemberPropertyName(node: ESTree.MemberExpression['property'], computed: boolean): string | null { - if (node.type === 'Identifier') return computed ? null : node.name; - if (node.type === 'Literal' && typeof node.value === 'string') return node.value; - return null; -} - -function findVariableDeclaration(program: ESTree.Program, name: string): ESTree.VariableDeclaration | null { - return program.body.find((x) => { - if (x.type !== 'VariableDeclaration') return false; - if (x.declarations.length !== 1) return false; - if (x.declarations[0].id.type !== 'Identifier') return false; - return x.declarations[0].id.name === name; - }) as ESTree.VariableDeclaration | null; -} - -function resolveObjectExpression(program: ESTree.Program, tree: ESTree.Expression): ESTree.ObjectExpression | null { - if (tree.type === 'ObjectExpression') return tree; - if (tree.type !== 'Identifier') return null; - const declaration = findVariableDeclaration(program, tree.name); - if (declaration?.declarations[0].init?.type !== 'ObjectExpression') return null; - return declaration.declarations[0].init; -} - -function resolveComponentOptions(program: ESTree.Program, tree: ESTree.Expression): ESTree.ObjectExpression | null { - const target = tree.type === 'Identifier' - ? findVariableDeclaration(program, tree.name)?.declarations[0].init ?? null - : tree; - if (target?.type === 'ObjectExpression') return target; - if (target?.type !== 'CallExpression') return null; - if (target.arguments.length !== 1) return null; - if (target.arguments[0].type !== 'ObjectExpression') return null; - return target.arguments[0]; -} - -function resolveModuleTree(program: ESTree.Program, tree: ESTree.Expression): Map | null { - const objectExpression = resolveObjectExpression(program, tree); - if (objectExpression === null) return null; - return new Map(objectExpression.properties.flatMap((property) => { - if (property.type !== 'Property') return []; - const actualKey = getPropertyName(property.key, property.computed); - if (actualKey === null) return []; - if (property.value.type === 'Literal') { - return typeof property.value.value === 'string' ? [[actualKey, property.value.value]] : []; - } - if (property.value.type === 'Identifier') { - const actualValue = findVariableDeclaration(program, property.value.name); - if (actualValue?.declarations[0].init?.type !== 'Literal') return []; - return typeof actualValue.declarations[0].init.value === 'string' ? [[actualKey, actualValue.declarations[0].init.value]] : []; - } - return []; - })); -} - -function resolveModuleForest(program: ESTree.Program, tree: ESTree.Expression): Map> | null { - const objectExpression = resolveObjectExpression(program, tree); - if (objectExpression === null) return null; - return new Map(objectExpression.properties.flatMap((property) => { - if (property.type !== 'Property') return []; - const actualKey = getPropertyName(property.key, property.computed); - if (actualKey === null) return []; - const moduleTree = resolveModuleTree(program, property.value); - return moduleTree === null ? [] : [[actualKey, moduleTree]]; - })); -} - -function findRenderArrow(options: ESTree.ObjectExpression): Extract | null { - const setup = options.properties.find((x) => { - if (x.type !== 'Property') return false; - return getPropertyName(x.key, x.computed) === 'setup'; - }) as Extract | undefined; - if (setup?.value.type !== 'FunctionExpression' && setup?.value.type !== 'ArrowFunctionExpression') return null; - if (setup.value.body == null) return null; - if (setup.value.body.type !== 'BlockStatement') return null; - const render = setup.value.body.body.find((x) => x.type === 'ReturnStatement'); - if (render?.type !== 'ReturnStatement') return null; - return render.argument?.type === 'ArrowFunctionExpression' ? render.argument : null; -} - -function isCssModuleAccess(node: ESTree.Node, ctxName: string, key: string): node is Extract { - if (node.type !== 'MemberExpression') return false; - if (node.object.type !== 'MemberExpression') return false; - if (node.object.object.type !== 'Identifier') return false; - if (node.object.object.name !== ctxName) return false; - return getMemberPropertyName(node.object.property, node.object.computed) === key; - } - -function isCssModuleReference(node: ESTree.Node, ctxName: string, key: string): node is Extract { - if (!isCssModuleAccess(node, ctxName, key)) return false; - return getMemberPropertyName(node.property, node.computed) !== null; -} - -function isClassProperty(node: ESTree.Node | null): node is Extract { - return node?.type === 'Property' && getPropertyName(node.key, node.computed) === 'class'; -} - -export function unwindCssModuleClassName(ast: ESTree.Node, magicString: RolldownMagicString): void { - (estreeWalker.walk as any)(ast, { - enter(node: ESTree.Node, parent: ESTree.Node | null): void { +export function unwindCssModuleClassName(ast: estree.Node): void { + (walk as typeof estreeWalker.walk)(ast, { + enter(node, parent): void { //#region if (parent?.type !== 'Program') return; - if (ast.type !== 'Program') return; if (node.type !== 'VariableDeclaration') return; if (node.declarations.length !== 1) return; if (node.declarations[0].id.type !== 'Identifier') return; const name = node.declarations[0].id.name; if (node.declarations[0].init?.type !== 'CallExpression') return; + if (node.declarations[0].init.callee.type !== 'Identifier') return; + if (node.declarations[0].init.callee.name !== '_export_sfc') return; if (node.declarations[0].init.arguments.length !== 2) return; - const componentNode = node.declarations[0].init.arguments[0]; - if (componentNode.type !== 'Identifier' && componentNode.type !== 'CallExpression' && componentNode.type !== 'ObjectExpression') return; + if (node.declarations[0].init.arguments[0].type !== 'Identifier') return; + const ident = node.declarations[0].init.arguments[0].name; + if (!ident.startsWith('_sfc_main')) return; if (node.declarations[0].init.arguments[1].type !== 'ArrayExpression') return; if (node.declarations[0].init.arguments[1].elements.length === 0) return; - const cssModulesEntry = node.declarations[0].init.arguments[1].elements.find((x) => { + const __cssModulesIndex = node.declarations[0].init.arguments[1].elements.findIndex((x) => { if (x?.type !== 'ArrayExpression') return false; if (x.elements.length !== 2) return false; if (x.elements[0]?.type !== 'Literal') return false; if (x.elements[0].value !== '__cssModules') return false; + if (x.elements[1]?.type !== 'Identifier') return false; return true; - }) as ESTree.ArrayExpression | undefined; - const __cssModulesIndex = node.declarations[0].init.arguments[1].elements.indexOf(cssModulesEntry ?? null); - if (cssModulesEntry === undefined || __cssModulesIndex < 0) return; + }); + if (!~__cssModulesIndex) return; /* This region assumeed that the entered node looks like the following code. * * ```ts @@ -217,10 +118,21 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - const cssModuleForest = cssModulesEntry.elements[1]; - if (cssModuleForest?.type !== 'Identifier' && cssModuleForest?.type !== 'ObjectExpression') return; - const moduleForest = resolveModuleForest(ast, cssModuleForest); - if (moduleForest === null) return; + const cssModuleForestName = ((node.declarations[0].init.arguments[1].elements[__cssModulesIndex] as estree.ArrayExpression).elements[1] as estree.Identifier).name; + const cssModuleForestNode = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== cssModuleForestName) return false; + if (x.declarations[0].init?.type !== 'ObjectExpression') return false; + return true; + }) as unknown as estree.VariableDeclaration; + const moduleForest = new Map((cssModuleForestNode.declarations[0].init as estree.ObjectExpression).properties.flatMap((property) => { + if (property.type !== 'Property') return []; + if (property.key.type !== 'Literal') return []; + if (property.value.type !== 'Identifier') return []; + return [[property.key.value as string, property.value.name as string]]; + })); /* This region collected a VariableDeclaration node in the module that looks like the following code. * * ```ts @@ -231,13 +143,35 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - const options = resolveComponentOptions(ast, componentNode); - if (options === null) return; - const render = findRenderArrow(options); - if (render === null) return; - if (render.params.length !== 2) return; - const ctx = render.params[0]; + const sfcMain = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== ident) return false; + return true; + }) as unknown as estree.VariableDeclaration; + if (sfcMain.declarations[0].init?.type !== 'CallExpression') return; + if (sfcMain.declarations[0].init.callee.type !== 'Identifier') return; + if (sfcMain.declarations[0].init.callee.name !== 'defineComponent') return; + if (sfcMain.declarations[0].init.arguments.length !== 1) return; + if (sfcMain.declarations[0].init.arguments[0].type !== 'ObjectExpression') return; + const setup = sfcMain.declarations[0].init.arguments[0].properties.find((x) => { + if (x.type !== 'Property') return false; + if (x.key.type !== 'Identifier') return false; + if (x.key.name !== 'setup') return false; + return true; + }) as unknown as estree.Property; + if (setup.value.type !== 'FunctionExpression') return; + const render = setup.value.body.body.find((x) => { + if (x.type !== 'ReturnStatement') return false; + return true; + }) as unknown as estree.ReturnStatement; + if (render.argument?.type !== 'ArrowFunctionExpression') return; + if (render.argument.params.length !== 2) return; + const ctx = render.argument.params[0]; if (ctx.type !== 'Identifier') return; + if (ctx.name !== '_ctx') return; + if (render.argument.body.type !== 'BlockStatement') return; /* This region assumed that `sfcMain` looks like the following code. * * ```ts @@ -252,8 +186,33 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown * ``` */ //#endregion - for (const [key, moduleTree] of moduleForest) { + for (const [key, value] of moduleForest) { //#region + const cssModuleTreeNode = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== value) return false; + return true; + }) as unknown as estree.VariableDeclaration; + if (cssModuleTreeNode.declarations[0].init?.type !== 'ObjectExpression') return; + const moduleTree = new Map(cssModuleTreeNode.declarations[0].init.properties.flatMap((property) => { + if (property.type !== 'Property') return []; + const actualKey = property.key.type === 'Identifier' ? property.key.name : property.key.type === 'Literal' ? property.key.value : null; + if (typeof actualKey !== 'string') return []; + if (property.value.type === 'Literal') return [[actualKey, property.value.value as string]]; + if (property.value.type !== 'Identifier') return []; + const labelledValue = property.value.name; + const actualValue = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== labelledValue) return false; + return true; + }) as unknown as estree.VariableDeclaration; + if (actualValue.declarations[0].init?.type !== 'Literal') return []; + return [[actualKey, actualValue.declarations[0].init.value as string]]; + })); /* This region collected VariableDeclaration nodes in the module that looks like the following code. * * ```ts @@ -267,14 +226,17 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - (estreeWalker.walk as any)(render.body, { - enter(childNode: ESTree.Node) { - if (!isCssModuleReference(childNode, ctx.name, key)) return; - const actualKey = getMemberPropertyName(childNode.property, childNode.computed); - if (actualKey === null) return; - const actualValue = moduleTree.get(actualKey); + (walk as typeof estreeWalker.walk)(render.argument.body, { + enter(childNode) { + if (childNode.type !== 'MemberExpression') return; + if (childNode.object.type !== 'MemberExpression') return; + if (childNode.object.object.type !== 'Identifier') return; + if (childNode.object.object.name !== ctx.name) return; + if (childNode.object.property.type !== 'Identifier') return; + if (childNode.object.property.name !== key) return; + if (childNode.property.type !== 'Identifier') return; + const actualValue = moduleTree.get(childNode.property.name); if (actualValue === undefined) return; - magicString.overwrite(childNode.start, childNode.end, JSON.stringify(actualValue)); this.replace({ type: 'Literal', value: actualValue, @@ -314,13 +276,20 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - (estreeWalker.walk as any)(render.body, { - enter(childNode: ESTree.Node) { - if (!isCssModuleReference(childNode, ctx.name, key)) return; - const actualKey = getMemberPropertyName(childNode.property, childNode.computed); - if (actualKey === null) return; - console.error(`Undefined style detected: ${key}.${actualKey} (in ${name})`); - magicString.overwrite(childNode.start, childNode.end, 'undefined'); + (walk as typeof estreeWalker.walk)(render.argument.body, { + enter(childNode) { + if (childNode.type !== 'MemberExpression') return; + if (childNode.object.type !== 'MemberExpression') return; + if (childNode.object.object.type !== 'Identifier') return; + if (childNode.object.object.name !== ctx.name) return; + if (childNode.object.property.type !== 'Identifier') return; + if (childNode.object.property.name !== key) return; + if (childNode.property.type !== 'Identifier') return; + console.error(`Undefined style detected: ${key}.${childNode.property.name} (in ${name})`); + this.replace({ + type: 'Identifier', + name: 'undefined', + }); }, }); /* This region replaced the reference identifier of missing class names in the render function with `undefined`, as in the following code. @@ -331,7 +300,7 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown * ... * return (_ctx, _cache) => { * ... - * return openBlock(), createElementBlock('div', { + * return openBlock(), createElementBlock("div", { * class: normalizeClass(_ctx.$style.hoge), * }, null); * }; @@ -347,7 +316,7 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown * ... * return (_ctx, _cache) => { * ... - * return openBlock(), createElementBlock('div', { + * return openBlock(), createElementBlock("div", { * class: normalizeClass(undefined), * }, null); * }; @@ -357,15 +326,18 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - (estreeWalker.walk as any)(render.body, { - enter(childNode: ESTree.Node, childParent: ESTree.Node | null) { + (walk as typeof estreeWalker.walk)(render.argument.body, { + enter(childNode) { if (childNode.type !== 'CallExpression') return; + if (childNode.callee.type !== 'Identifier') return; + if (childNode.callee.name !== 'normalizeClass') return; if (childNode.arguments.length !== 1) return; - if (childNode.callee.type === 'Identifier' && childNode.callee.name !== 'normalizeClass' && !isClassProperty(childParent)) return; - if (childNode.callee.type !== 'Identifier' && !isClassProperty(childParent)) return; const normalized = normalizeClass(childNode.arguments[0], name); if (normalized === null) return; - magicString.overwrite(childNode.start, childNode.end, JSON.stringify(normalized)); + this.replace({ + type: 'Literal', + value: normalized, + }); }, }); /* This region compiled the `normalizeClass` call into a pseudo-AOT compilation, as in the following code. @@ -402,34 +374,19 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion } - const hasRemainingCssModuleReference = Array.from(moduleForest.keys()).some((key) => { - let found = false; - (estreeWalker.walk as any)(render.body, { - enter(childNode: ESTree.Node) { - if (!isCssModuleAccess(childNode, ctx.name, key)) return; - found = true; - this.skip(); - }, - }); - return found; - }); - if (hasRemainingCssModuleReference) return; //#region if (node.declarations[0].init.arguments[1].elements.length === 1) { - if (componentNode.type === 'Identifier') { - (estreeWalker.walk as any)(ast, { - enter(childNode: ESTree.Node) { - if (childNode.type !== 'Identifier') return; - if (childNode.name !== componentNode.name) return; - magicString.overwrite(childNode.start, childNode.end, name); - }, - }); - magicString.remove(node.start, node.end); - } else { - const removeStart = cssModulesEntry.start; - const removeEnd = node.declarations[0].init.arguments[1].end - 1; - magicString.remove(removeStart, removeEnd); - } + (walk as typeof estreeWalker.walk)(ast, { + enter(childNode) { + if (childNode.type !== 'Identifier') return; + if (childNode.name !== ident) return; + this.replace({ + type: 'Identifier', + name: node.declarations[0].id.name, + }); + }, + }); + this.remove(); /* NOTE: The above logic is valid as long as the following two conditions are met. * * - the uniqueness of `ident` is kept throughout the module @@ -454,10 +411,31 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown }); */ } else { - const nextElement = node.declarations[0].init.arguments[1].elements[__cssModulesIndex + 1]; - const removeStart = node.declarations[0].init.arguments[1].elements[__cssModulesIndex]!.start; - const removeEnd = nextElement ? nextElement.start : node.declarations[0].init.arguments[1].end - 1; - magicString.remove(removeStart, removeEnd); + this.replace({ + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: node.declarations[0].id.name, + }, + init: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: '_export_sfc', + }, + arguments: [{ + type: 'Identifier', + name: ident, + }, { + type: 'ArrayExpression', + elements: node.declarations[0].init.arguments[1].elements.slice(0, __cssModulesIndex).concat(node.declarations[0].init.arguments[1].elements.slice(__cssModulesIndex + 1)), + }], + }, + }], + kind: 'const', + }); } /* This region removed the `__cssModules` reference from the second argument of `_export_sfc`, as in the following code. * @@ -496,11 +474,10 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown export default function pluginUnwindCssModuleClassName(): Plugin { return { name: 'UnwindCssModuleClassName', - renderChunk(code, _chunk, _options, meta) { - const ast = ('ast' in meta ? meta.ast ?? this.parse(code) : this.parse(code)) as ESTree.Program; - const magicString = meta.magicString ?? new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - return magicString; + renderChunk(code): { code: string } { + const ast = this.parse(code) as unknown as estree.Node; + unwindCssModuleClassName(ast); + return { code: generate(ast) }; }, }; } diff --git a/packages/frontend/lib/vite-plugin-create-search-index.ts b/packages/frontend/lib/vite-plugin-create-search-index.ts index 4126a4f8c0f..cfbba0823c3 100644 --- a/packages/frontend/lib/vite-plugin-create-search-index.ts +++ b/packages/frontend/lib/vite-plugin-create-search-index.ts @@ -13,12 +13,11 @@ import { type LogOptions, normalizePath, type Plugin, - type PluginOption, + type PluginOption } from 'vite'; import fs from 'node:fs'; import JSON5 from 'json5'; -import { RolldownMagicString } from 'rolldown'; -import type { TransformResult } from 'rolldown'; +import MagicString, { SourceMap } from 'magic-string'; import path from 'node:path' import { hash, toBase62 } from '../vite.config'; import { minimatch } from 'minimatch'; @@ -64,7 +63,7 @@ interface MarkerRelation { let logger = { info: (msg: string, options?: LogOptions) => { }, warn: (msg: string, options?: LogOptions) => { }, - error: (msg: string, options?: LogErrorOptions) => { }, + error: (msg: string, options?: LogErrorOptions | unknown) => { }, }; let loggerInitialized = false; @@ -461,18 +460,9 @@ function propertyAccessProxy(path: string[]): AccessProxy { const i18nProxy = propertyAccessProxy(['i18n']); -export function collectFileMarkers(id: string, code: string | RolldownMagicString | undefined): SearchIndexItem[] { +export function collectFileMarkers(id: string, code: string): SearchIndexItem[] { try { - let codeStr: string; - if (typeof code === 'string') { - codeStr = code; - } else if (code != null) { - codeStr = code.toString(); - } else { - throw new Error(`Code is undefined for file ${id}`); - } - - const { descriptor, errors } = vueSfcParse(codeStr, { + const { descriptor, errors } = vueSfcParse(code, { filename: id, }); @@ -483,8 +473,7 @@ export function collectFileMarkers(id: string, code: string | RolldownMagicStrin return extractUsageInfoFromTemplateAst(descriptor.template?.ast, id); } catch (error) { - let _error = error instanceof Error ? error : new Error(String(error)); - logger.error(`Error analyzing file ${id}:`, { error: _error }); + logger.error(`Error analyzing file ${id}:`, error); } return []; @@ -492,7 +481,10 @@ export function collectFileMarkers(id: string, code: string | RolldownMagicStrin // endregion -type TransformedCode = Exclude; +type TransformedCode = { + code: string, + map: SourceMap, +}; export class MarkerIdAssigner { // key: file id @@ -517,12 +509,13 @@ export class MarkerIdAssigner { } #processImpl(id: string, code: string): TransformedCode { - const s = new RolldownMagicString(code); // magic-string �インスタンスを作� + const s = new MagicString(code); // magic-string �インスタンスを作� const parsed = vueSfcParse(code, { filename: id }); if (!parsed.descriptor.template) { return { - code, // テンプレート���場��元�コードを返� + code, + map: s.generateMap({ source: id, includeContent: true }), }; } const ast = parsed.descriptor.template.ast; // テンプレート AST を�得 @@ -530,7 +523,8 @@ export class MarkerIdAssigner { if (!ast) { return { - code, + code: s.toString(), // 変更後�コードを返� + map: s.generateMap({ source: id, includeContent: true }), // ソースマップも生� (sourceMap: true �必�) }; } @@ -617,6 +611,7 @@ export class MarkerIdAssigner { return { code: s.toString(), // 変更後�コードを返� + map: s.generateMap({ source: id, includeContent: true }), // ソースマップも生� (sourceMap: true �必�) }; } @@ -647,7 +642,7 @@ export class MarkerIdAssigner { } } -// Vite プラグイン��� export +// Rollup プラグイン��� export export default function pluginCreateSearchIndex(options: Options): PluginOption { const assigner = new MarkerIdAssigner(); return [ diff --git a/packages/frontend/lib/vite-plugin-watch-locales.ts b/packages/frontend/lib/vite-plugin-watch-locales.ts index 2fed7f60fa1..372e9039d5d 100644 --- a/packages/frontend/lib/vite-plugin-watch-locales.ts +++ b/packages/frontend/lib/vite-plugin-watch-locales.ts @@ -3,16 +3,16 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import path from 'node:path'; +import path from 'node:path' import locales from 'i18n'; -import type { Plugin } from 'vite'; const localesDir = path.resolve(__dirname, '../../../locales') /** * 外部ファイルを監視��必��応��webSocket�メッセージを�るViteプラグイン + * @returns {import('vite').Plugin} */ -export default function pluginWatchLocales(): Plugin { +export default function pluginWatchLocales() { return { name: 'watch-locales', diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 7bcf097ec4a..a99918e7b6f 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -21,7 +21,10 @@ "@github/webauthn-json": "2.1.1", "@mcaptcha/core-glue": "0.1.0-alpha-5", "@misskey-dev/browser-image-resizer": "2024.1.0", - "@sentry/vue": "10.40.0", + "@rollup/plugin-json": "6.1.0", + "@rollup/plugin-replace": "6.0.3", + "@rollup/pluginutils": "5.3.0", + "@sentry/vue": "10.45.0", "@syuilo/aiscript": "1.2.1", "@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0", "@twemoji/parser": "16.0.0", @@ -61,20 +64,21 @@ "punycode.js": "2.3.1", "qr-code-styling": "1.9.2", "qr-scanner": "1.4.2", - "sanitize-html": "2.17.1", + "rollup": "4.60.0", + "sanitize-html": "2.17.2", + "sass": "1.98.0", "shiki": "3.23.0", "textarea-caret": "3.1.0", "three": "0.183.2", "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", "v-code-diff": "1.13.1", + "vite": "7.3.1", "vue": "3.5.30", "wanakana": "5.3.1" }, "devDependencies": { "@misskey-dev/summaly": "5.2.5", - "@rollup/plugin-json": "6.1.0", - "@rollup/pluginutils": "5.3.0", "@storybook/addon-essentials": "8.6.18", "@storybook/addon-interactions": "8.6.18", "@storybook/addon-links": "10.3.3", @@ -119,6 +123,7 @@ "estree-walker": "3.0.3", "happy-dom": "20.8.8", "intersection-observer": "0.12.2", + "magic-string": "0.30.21", "micromatch": "4.0.8", "minimatch": "10.2.4", "msw": "2.12.14", @@ -127,14 +132,11 @@ "prettier": "3.8.1", "react": "19.2.4", "react-dom": "19.2.4", - "rolldown": "1.0.0-rc.11", - "sass-embedded": "1.98.0", "seedrandom": "3.0.5", "start-server-and-test": "2.1.5", "storybook": "10.3.3", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "tsx": "4.21.0", - "vite": "8.0.2", "vite-plugin-glsl": "1.5.6", "vite-plugin-turbosnap": "1.0.3", "vitest": "4.1.1", diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index b0617333330..260d1215df2 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -1,7 +1,7 @@ import path from 'path'; +import pluginReplace from '@rollup/plugin-replace'; import pluginVue from '@vitejs/plugin-vue'; import pluginGlsl from 'vite-plugin-glsl'; -import { replacePlugin } from 'rolldown/plugins'; import type { UserConfig } from 'vite'; import { defineConfig } from 'vite'; import * as yaml from 'js-yaml'; @@ -11,13 +11,13 @@ import locales from 'i18n'; import meta from '../../package.json'; import packageInfo from './package.json' with { type: 'json' }; import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js'; -import pluginJson5 from './lib/vite-plugin-json5.js'; +import pluginJson5 from './vite.json5.js'; import type { Options as SearchIndexOptions } from './lib/vite-plugin-create-search-index.js'; import pluginCreateSearchIndex from './lib/vite-plugin-create-search-index.js'; import pluginWatchLocales from './lib/vite-plugin-watch-locales.js'; import { pluginRemoveUnrefI18n } from '../frontend-builder/rollup-plugin-remove-unref-i18n.js'; -const url = process.env.NODE_ENV === 'development' ? (yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')) as any).url : null; +const url = process.env.NODE_ENV === 'development' ? yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')).url : null; const host = url ? (new URL(url)).hostname : undefined; const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue']; @@ -121,10 +121,11 @@ export function getConfig(): UserConfig { pluginGlsl({ minify: true }), ...process.env.NODE_ENV === 'production' ? [ - replacePlugin({ - 'isChromatic()': JSON.stringify(false), - }, { + pluginReplace({ preventAssignment: true, + values: { + 'isChromatic()': JSON.stringify(false), + }, }), ] : [], @@ -153,6 +154,11 @@ export function getConfig(): UserConfig { } }, }, + preprocessorOptions: { + scss: { + api: 'modern-compiler', + }, + }, }, define: { @@ -172,10 +178,7 @@ export function getConfig(): UserConfig { 'safari16', ], manifest: 'manifest.json', - rolldownOptions: { - experimental: { - nativeMagicString: true, - }, + rollupOptions: { input: { i18n: './src/i18n.ts', entry: './src/_boot_.ts', @@ -183,18 +186,11 @@ export function getConfig(): UserConfig { external: externalPackages.map(p => p.match), preserveEntrySignatures: 'allow-extension', output: { - codeSplitting: { - groups: [{ - name: 'vue', - test: /node_modules[\\/]vue/, - }, { - name: 'photoswipe', - test: /node_modules[\\/]photoswipe/, - }, { - // dependencies of i18n.ts - name: 'config', - test: /@@[\\/]js[\\/]config\.js/, - }], + manualChunks: { + vue: ['vue'], + photoswipe: ['photoswipe', 'photoswipe/lightbox', 'photoswipe/style.css'], + // dependencies of i18n.ts + 'config': ['@@/js/config.js'], }, entryFileNames: `scripts/${localesHash}-[hash:8].js`, chunkFileNames: `scripts/${localesHash}-[hash:8].js`, diff --git a/packages/frontend/lib/vite-plugin-json5.ts b/packages/frontend/vite.json5.ts similarity index 90% rename from packages/frontend/lib/vite-plugin-json5.ts rename to packages/frontend/vite.json5.ts index 921324b67a4..87b67c21424 100644 --- a/packages/frontend/lib/vite-plugin-json5.ts +++ b/packages/frontend/vite.json5.ts @@ -1,10 +1,7 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ +// Original: https://github.com/rollup/plugins/tree/8835dd2aed92f408d7dc72d7cc25a9728e16face/packages/json import JSON5 from 'json5'; -import { Plugin } from 'vite'; +import { Plugin } from 'rollup'; import { createFilter, dataToEsm } from '@rollup/pluginutils'; import { RollupJsonOptions } from '@rollup/plugin-json'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32f051d31d6..1c16139fa41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -557,8 +557,8 @@ importers: specifier: 7.2.2 version: 7.2.2 vite: - specifier: 8.0.2 - version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + specifier: 7.3.1 + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: '@swc/core-android-arm64': specifier: 1.3.11 @@ -665,9 +665,18 @@ importers: '@misskey-dev/browser-image-resizer': specifier: 2024.1.0 version: 2024.1.0 + '@rollup/plugin-json': + specifier: 6.1.0 + version: 6.1.0(rollup@4.60.0) + '@rollup/plugin-replace': + specifier: 6.0.3 + version: 6.0.3(rollup@4.60.0) + '@rollup/pluginutils': + specifier: 5.3.0 + version: 5.3.0(rollup@4.60.0) '@sentry/vue': - specifier: 10.40.0 - version: 10.40.0(vue@3.5.30(typescript@5.9.3)) + specifier: 10.45.0 + version: 10.45.0(vue@3.5.30(typescript@5.9.3)) '@syuilo/aiscript': specifier: 1.2.1 version: 1.2.1 @@ -679,7 +688,7 @@ importers: version: 16.0.0 '@vitejs/plugin-vue': specifier: 6.0.5 - version: 6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) aiscript-vscode: specifier: github:aiscript-dev/aiscript-vscode#v0.1.16 version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/1dc7f60cda78d030dadfc518a33c472202b2ef67 @@ -785,9 +794,15 @@ importers: qr-scanner: specifier: 1.4.2 version: 1.4.2 + rollup: + specifier: 4.60.0 + version: 4.60.0 sanitize-html: - specifier: 2.17.1 - version: 2.17.1 + specifier: 2.17.2 + version: 2.17.2 + sass: + specifier: 1.98.0 + version: 1.98.0 shiki: specifier: 3.23.0 version: 3.23.0 @@ -806,6 +821,9 @@ importers: v-code-diff: specifier: 1.13.1 version: 1.13.1(vue@3.5.30(typescript@5.9.3)) + vite: + specifier: 7.3.1 + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: specifier: 3.5.30 version: 3.5.30(typescript@5.9.3) @@ -816,12 +834,6 @@ importers: '@misskey-dev/summaly': specifier: 5.2.5 version: 5.2.5 - '@rollup/plugin-json': - specifier: 6.1.0 - version: 6.1.0(rollup@4.60.0) - '@rollup/pluginutils': - specifier: 5.3.0 - version: 5.3.0(rollup@4.60.0) '@storybook/addon-essentials': specifier: 8.6.18 version: 8.6.18(@types/react@19.2.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) @@ -857,7 +869,7 @@ importers: version: 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) '@storybook/react-vite': specifier: 10.3.3 - version: 10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/test': specifier: 8.6.18 version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) @@ -872,7 +884,7 @@ importers: version: 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) '@storybook/vue3-vite': specifier: 10.3.3 - version: 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) '@tabler/icons-webfont': specifier: 3.35.0 version: 3.35.0 @@ -923,7 +935,7 @@ importers: version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.1 - version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) '@vue/compiler-core': specifier: 3.5.30 version: 3.5.30 @@ -954,6 +966,9 @@ importers: intersection-observer: specifier: 0.12.2 version: 0.12.2 + magic-string: + specifier: 0.30.21 + version: 0.30.21 micromatch: specifier: 4.0.8 version: 4.0.8 @@ -978,12 +993,6 @@ importers: react-dom: specifier: 19.2.4 version: 19.2.4(react@19.2.4) - rolldown: - specifier: 1.0.0-rc.11 - version: 1.0.0-rc.11 - sass-embedded: - specifier: 1.98.0 - version: 1.98.0 seedrandom: specifier: 3.0.5 version: 3.0.5 @@ -999,21 +1008,18 @@ importers: tsx: specifier: 4.21.0 version: 4.21.0 - vite: - specifier: 8.0.2 - version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vite-plugin-glsl: specifier: 1.5.6 - version: 1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 vitest: specifier: 4.1.1 - version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vitest-fetch-mock: specifier: 0.4.5 - version: 0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) vue-component-type-helpers: specifier: 3.2.6 version: 3.2.6 @@ -1035,12 +1041,9 @@ importers: magic-string: specifier: 0.30.21 version: 0.30.21 - rolldown: - specifier: 1.0.0-rc.11 - version: 1.0.0-rc.11 vite: - specifier: 8.0.2 - version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + specifier: 7.3.1 + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) devDependencies: '@types/estree': specifier: 1.0.8 @@ -1066,6 +1069,9 @@ importers: '@rollup/plugin-json': specifier: 6.1.0 version: 6.1.0(rollup@4.60.0) + '@rollup/plugin-replace': + specifier: 6.0.3 + version: 6.0.3(rollup@4.60.0) '@rollup/pluginutils': specifier: 5.3.0 version: 5.3.0(rollup@4.60.0) @@ -1074,7 +1080,7 @@ importers: version: 16.0.0 '@vitejs/plugin-vue': specifier: 6.0.5 - version: 6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) buraha: specifier: 0.0.1 version: 0.0.1 @@ -1105,6 +1111,9 @@ importers: rollup: specifier: 4.60.0 version: 4.60.0 + sass: + specifier: 1.98.0 + version: 1.98.0 shiki: specifier: 3.23.0 version: 3.23.0 @@ -1114,6 +1123,9 @@ importers: uuid: specifier: 13.0.0 version: 13.0.0 + vite: + specifier: 7.3.1 + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: specifier: 3.5.30 version: 3.5.30(typescript@5.9.3) @@ -1153,7 +1165,7 @@ importers: version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.1 - version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) '@vue/runtime-core': specifier: 3.5.30 version: 3.5.30 @@ -1187,18 +1199,12 @@ importers: prettier: specifier: 3.8.1 version: 3.8.1 - sass-embedded: - specifier: 1.98.0 - version: 1.98.0 start-server-and-test: specifier: 2.1.5 version: 2.1.5 tsx: specifier: 4.21.0 version: 4.21.0 - vite: - specifier: 8.0.2 - version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 @@ -1371,7 +1377,7 @@ importers: version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.1 - version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) esbuild: specifier: 0.27.4 version: 0.27.4 @@ -1389,10 +1395,10 @@ importers: version: 0.33.0 vitest: specifier: 4.1.1 - version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vitest-websocket-mock: specifier: 0.5.0 - version: 0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) packages/misskey-js/generator: devDependencies: @@ -1865,9 +1871,6 @@ packages: '@borewit/text-codec@0.1.1': resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} - '@bufbuild/protobuf@2.11.0': - resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} - '@canvas/image-data@1.1.0': resolution: {integrity: sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA==} @@ -1952,15 +1955,9 @@ packages: '@discordapp/twemoji@16.0.1': resolution: {integrity: sha512-figLiBWzjS5cyrAjLaGjM8AAaowO3qvK8rg5bA2dElB4qsaPMvBVlFDMO2d3x+nC1igt7kgWH4dvNmvvUHUF8w==} - '@emnapi/core@1.9.1': - resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} - '@emnapi/runtime@1.7.1': resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} - '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} @@ -2877,9 +2874,6 @@ packages: resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} engines: {node: '>= 10'} - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} - '@nestjs/common@11.1.17': resolution: {integrity: sha512-hLODw5Abp8OQgA+mUO4tHou4krKgDtUcM9j5Ihxncst9XeyxYBTt2bwZm4e4EQr5E352S4Fyy6V3iFx9ggxKAg==} peerDependencies: @@ -3179,9 +3173,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 - '@oxc-project/types@0.122.0': - resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} - '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} @@ -3352,104 +3343,6 @@ packages: resolution: {integrity: sha512-2+O+riuIUgVSuLl3Lyh5AplWZyVMNuG2F98/o6NrutKJfW4/GTZdPpZlIphS0HGgcOHgmWcCSHj+dWFlZaGSHw==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} - '@rolldown/binding-android-arm64@1.0.0-rc.11': - resolution: {integrity: sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.0.0-rc.11': - resolution: {integrity: sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.0-rc.11': - resolution: {integrity: sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.0.0-rc.11': - resolution: {integrity: sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': - resolution: {integrity: sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': - resolution: {integrity: sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': - resolution: {integrity: sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': - resolution: {integrity: sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': - resolution: {integrity: sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': - resolution: {integrity: sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': - resolution: {integrity: sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': - resolution: {integrity: sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.0.0-rc.11': - resolution: {integrity: sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': - resolution: {integrity: sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': - resolution: {integrity: sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.0-rc.11': - resolution: {integrity: sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==} - '@rolldown/pluginutils@1.0.0-rc.2': resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} @@ -3462,6 +3355,15 @@ packages: rollup: optional: true + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} @@ -3645,18 +3547,10 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@sentry-internal/browser-utils@10.40.0': - resolution: {integrity: sha512-3CDeVNBXYOIvBVdT0SOdMZx5LzYDLuhGK/z7A14sYZz4Cd2+f4mSeFDaEOoH/g2SaY2CKR5KGkAADy8IyjZ21w==} - engines: {node: '>=18'} - '@sentry-internal/browser-utils@10.45.0': resolution: {integrity: sha512-ZPZpeIarXKScvquGx2AfNKcYiVNDA4wegMmjyGVsTA2JPmP0TrJoO3UybJS6KGDeee8V3I3EfD/ruauMm7jOFQ==} engines: {node: '>=18'} - '@sentry-internal/feedback@10.40.0': - resolution: {integrity: sha512-V/ixkcdCNMo04KgsCEeNEu966xUUTD6czKT2LOAO5siZACqFjT/Rp9VR1n7QQrVo3sL7P3QNiTHtX0jaeWbwzg==} - engines: {node: '>=18'} - '@sentry-internal/feedback@10.45.0': resolution: {integrity: sha512-vCSurazFVq7RUeYiM5X326jA5gOVrWYD6lYX2fbjBOMcyCEhDnveNxMT62zKkZDyNT/jyD194nz/cjntBUkyWA==} engines: {node: '>=18'} @@ -3665,34 +3559,18 @@ packages: resolution: {integrity: sha512-oLHVYurqZfADPh5hvmQYS5qx8t0UZzT2u6+/68VXsFruQEOnYJTODKgU3BVLmemRs3WE6kCJjPeFdHVYOQGSzQ==} engines: {node: '>=18'} - '@sentry-internal/replay-canvas@10.40.0': - resolution: {integrity: sha512-wzQwilFHO2baeCt0dTMf0eW+rgK8O+mkisf9sQzPXzG3Krr/iVtFg1T5T1Th3YsCsEdn6yQ3hcBPLEXjMSvccg==} - engines: {node: '>=18'} - '@sentry-internal/replay-canvas@10.45.0': resolution: {integrity: sha512-nvq/AocdZTuD7y0KSiWi3gVaY0s5HOFy86mC/v1kDZmT/jsBAzN5LDkk/f1FvsWma1peqQmpUqxvhC+YIW294Q==} engines: {node: '>=18'} - '@sentry-internal/replay@10.40.0': - resolution: {integrity: sha512-vsH2Ut0KIIQIHNdS3zzEGLJ2C9btbpvJIWAVk7l7oft66JzlUNC89qNaQ5SAypjLQx4Ln2V/ZTqfEoNzXOAsoQ==} - engines: {node: '>=18'} - '@sentry-internal/replay@10.45.0': resolution: {integrity: sha512-vjosRoGA1bzhVAEO1oce+CsRdd70quzBeo7WvYqpcUnoLe/Rv8qpOMqWX3j26z7XfFHMExWQNQeLxmtYOArvlw==} engines: {node: '>=18'} - '@sentry/browser@10.40.0': - resolution: {integrity: sha512-nCt3FKUMFad0C6xl5wCK0Jz+qT4Vev4fv6HJRn0YoNRRDQCfsUVxAz7pNyyiPNGM/WCDp9wJpGJsRvbBRd2anw==} - engines: {node: '>=18'} - '@sentry/browser@10.45.0': resolution: {integrity: sha512-e/a8UMiQhqqv706McSIcG6XK+AoQf9INthi2pD+giZfNRTzXTdqHzUT5OIO5hg8Am6eF63nDJc+vrYNPhzs51Q==} engines: {node: '>=18'} - '@sentry/core@10.40.0': - resolution: {integrity: sha512-/wrcHPp9Avmgl6WBimPjS4gj810a1wU5oX9fF1bzJfeIIbF3jTsAbv0oMbgDp0cSDnkwv2+NvcPnn3+c5J6pBA==} - engines: {node: '>=18'} - '@sentry/core@10.45.0': resolution: {integrity: sha512-s69UXxvefeQxuZ5nY7/THtTrIEvJxNVCp3ns4kwoCw1qMpgpvn/296WCKVmM7MiwnaAdzEKnAvLAwaxZc2nM7Q==} engines: {node: '>=18'} @@ -3743,19 +3621,6 @@ packages: engines: {node: '>=18'} hasBin: true - '@sentry/vue@10.40.0': - resolution: {integrity: sha512-VnsGlSgG4RBgxcsGwS5+5XNUZackUsApgKdCjmwkwWchvLMm1S/RXMXBHT01BabcmUNjxmzWEfI7aboVUoLiGA==} - engines: {node: '>=18'} - peerDependencies: - '@tanstack/vue-router': ^1.64.0 - pinia: 2.x || 3.x - vue: 2.x || 3.x - peerDependenciesMeta: - '@tanstack/vue-router': - optional: true - pinia: - optional: true - '@sentry/vue@10.45.0': resolution: {integrity: sha512-p6ghTgQtiCBZ+Yw0B2xmC69S8AdCRRsYvbTHW7MJYspwNnJDs7rqgCBqOxNhvr3tsKdDuEOEHLtf/5hbKi+8xQ==} engines: {node: '>=18'} @@ -4535,9 +4400,6 @@ packages: '@twemoji/parser@16.0.0': resolution: {integrity: sha512-jmuIjkp3OIaEemwMy3sArBwZSuZkRqmueGwRe2Zk4cFzbUJISFBJSZLDUUBNIgq3c+nY49ideYN2OiII6JUqwA==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - '@types/accepts@1.3.7': resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} @@ -5916,9 +5778,6 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - colorjs.io@0.5.2: - resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} - colors@1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} @@ -7225,9 +7084,6 @@ packages: htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} - htmlparser2@9.1.0: resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} @@ -7989,80 +7845,6 @@ packages: light-my-request@6.6.0: resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} - engines: {node: '>= 12.0.0'} - lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -9708,11 +9490,6 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rolldown@1.0.0-rc.11: - resolution: {integrity: sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - rollup@4.60.0: resolution: {integrity: sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -9763,129 +9540,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sanitize-html@2.17.1: - resolution: {integrity: sha512-ehFCW+q1a4CSOWRAdX97BX/6/PDEkCqw7/0JXZAGQV57FQB3YOkTa/rrzHPeJ+Aghy4vZAFfWMYyfxIiB7F/gw==} - sanitize-html@2.17.2: resolution: {integrity: sha512-EnffJUl46VE9uvZ0XeWzObHLurClLlT12gsOk1cHyP2Ol1P0BnBnsXmShlBmWVJM+dKieQI68R0tsPY5m/B+Jg==} - sass-embedded-all-unknown@1.98.0: - resolution: {integrity: sha512-6n4RyK7/1mhdfYvpP3CClS3fGoYqDvRmLClCESS6I7+SAzqjxvGG6u5Fo+cb1nrPNbbilgbM4QKdgcgWHO9NCA==} - cpu: ['!arm', '!arm64', '!riscv64', '!x64'] - - sass-embedded-android-arm64@1.98.0: - resolution: {integrity: sha512-M9Ra98A6vYJHpwhoC/5EuH1eOshQ9ZyNwC8XifUDSbRl/cGeQceT1NReR9wFj3L7s1pIbmes1vMmaY2np0uAKQ==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [android] - - sass-embedded-android-arm@1.98.0: - resolution: {integrity: sha512-LjGiMhHgu7VL1n7EJxTCre1x14bUsWd9d3dnkS2rku003IWOI/fxc7OXgaKagoVzok1kv09rzO3vFXJR5ZeONQ==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [android] - - sass-embedded-android-riscv64@1.98.0: - resolution: {integrity: sha512-WPe+0NbaJIZE1fq/RfCZANMeIgmy83x4f+SvFOG7LhUthHpZWcOcrPTsCKKmN3xMT3iw+4DXvqTYOCYGRL3hcQ==} - engines: {node: '>=14.0.0'} - cpu: [riscv64] - os: [android] - - sass-embedded-android-x64@1.98.0: - resolution: {integrity: sha512-zrD25dT7OHPEgLWuPEByybnIfx4rnCtfge4clBgjZdZ3lF6E7qNLRBtSBmoFflh6Vg0RlEjJo5VlpnTMBM5MQQ==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [android] - - sass-embedded-darwin-arm64@1.98.0: - resolution: {integrity: sha512-cgr1z9rBnCdMf8K+JabIaYd9Rag2OJi5mjq08XJfbJGMZV/TA6hFJCLGkr5/+ZOn4/geTM5/3aSfQ8z5EIJAOg==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [darwin] - - sass-embedded-darwin-x64@1.98.0: - resolution: {integrity: sha512-OLBOCs/NPeiMqTdOrMFbVHBQFj19GS3bSVSxIhcCq16ZyhouUkYJEZjxQgzv9SWA2q6Ki8GCqp4k6jMeUY9dcA==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [darwin] - - sass-embedded-linux-arm64@1.98.0: - resolution: {integrity: sha512-axOE3t2MTBwCtkUCbrdM++Gj0gC0fdHJPrgzQ+q1WUmY9NoNMGqflBtk5mBZaWUeha2qYO3FawxCB8lctFwCtw==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [linux] - libc: glibc - - sass-embedded-linux-arm@1.98.0: - resolution: {integrity: sha512-03baQZCxVyEp8v1NWBRlzGYrmVT/LK7ZrHlF1piscGiGxwfdxoLXVuxsylx3qn/dD/4i/rh7Bzk7reK1br9jvQ==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [linux] - libc: glibc - - sass-embedded-linux-musl-arm64@1.98.0: - resolution: {integrity: sha512-LeqNxQA8y4opjhe68CcFvMzCSrBuJqYVFbwElEj9bagHXQHTp9xVPJRn6VcrC+0VLEDq13HVXMv7RslIuU0zmA==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [linux] - libc: musl - - sass-embedded-linux-musl-arm@1.98.0: - resolution: {integrity: sha512-OBkjTDPYR4hSaueOGIM6FDpl9nt/VZwbSRpbNu9/eEJcxE8G/vynRugW8KRZmCFjPy8j/jkGBvvS+k9iOqKV3g==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [linux] - libc: musl - - sass-embedded-linux-musl-riscv64@1.98.0: - resolution: {integrity: sha512-7w6hSuOHKt8FZsmjRb3iGSxEzM87fO9+M8nt5JIQYMhHTj5C+JY/vcske0v715HCVj5e1xyTnbGXf8FcASeAIw==} - engines: {node: '>=14.0.0'} - cpu: [riscv64] - os: [linux] - libc: musl - - sass-embedded-linux-musl-x64@1.98.0: - resolution: {integrity: sha512-QikNyDEJOVqPmxyCFkci8ZdCwEssdItfjQFJB+D+Uy5HFqcS5Lv3d3GxWNX/h1dSb23RPyQdQc267ok5SbEyJw==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [linux] - libc: musl - - sass-embedded-linux-riscv64@1.98.0: - resolution: {integrity: sha512-E7fNytc/v4xFBQKzgzBddV/jretA4ULAPO6XmtBiQu4zZBdBozuSxsQLe2+XXeb0X4S2GIl72V7IPABdqke/vA==} - engines: {node: '>=14.0.0'} - cpu: [riscv64] - os: [linux] - libc: glibc - - sass-embedded-linux-x64@1.98.0: - resolution: {integrity: sha512-VsvP0t/uw00mMNPv3vwyYKUrFbqzxQHnRMO+bHdAMjvLw4NFf6mscpym9Bzf+NXwi1ZNKnB6DtXjmcpcvqFqYg==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [linux] - libc: glibc - - sass-embedded-unknown-all@1.98.0: - resolution: {integrity: sha512-C4MMzcAo3oEDQnW7L8SBgB9F2Fq5qHPnaYTZRMOH3Mp/7kM4OooBInXpCiiFjLnjY95hzP4KyctVx0uYR6MYlQ==} - os: ['!android', '!darwin', '!linux', '!win32'] - - sass-embedded-win32-arm64@1.98.0: - resolution: {integrity: sha512-nP/10xbAiPbhQkMr3zQfXE4TuOxPzWRQe1Hgbi90jv2R4TbzbqQTuZVOaJf7KOAN4L2Bo6XCTRjK5XkVnwZuwQ==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [win32] - - sass-embedded-win32-x64@1.98.0: - resolution: {integrity: sha512-/lbrVsfbcbdZQ5SJCWcV0NVPd6YRs+FtAnfedp4WbCkO/ZO7Zt/58MvI4X2BVpRY/Nt5ZBo1/7v2gYcQ+J4svQ==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [win32] - - sass-embedded@1.98.0: - resolution: {integrity: sha512-Do7u6iRb6K+lrllcTkB1BXcHwOxcKe3rEfOF/GcCLE2w3WpddakRAosJOHFUR37DpsvimQXEt5abs3NzUjEIqg==} - engines: {node: '>=16.0.0'} - hasBin: true - sass@1.98.0: resolution: {integrity: sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==} engines: {node: '>=14.0.0'} @@ -10445,14 +10102,6 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - sync-child-process@1.0.2: - resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} - engines: {node: '>=16.0.0'} - - sync-message-port@1.2.0: - resolution: {integrity: sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==} - engines: {node: '>=16.0.0'} - systeminformation@5.31.5: resolution: {integrity: sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ==} engines: {node: '>=8.0.0'} @@ -10970,9 +10619,6 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - varint@6.0.0: - resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -11003,16 +10649,15 @@ packages: vite-plugin-turbosnap@1.0.3: resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==} - vite@8.0.2: - resolution: {integrity: sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 - esbuild: ^0.27.0 jiti: '>=1.21.0' less: ^4.0.0 + lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -11023,14 +10668,12 @@ packages: peerDependenciesMeta: '@types/node': optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true jiti: optional: true less: optional: true + lightningcss: + optional: true sass: optional: true sass-embedded: @@ -12150,8 +11793,6 @@ snapshots: '@borewit/text-codec@0.1.1': {} - '@bufbuild/protobuf@2.11.0': {} - '@canvas/image-data@1.1.0': {} '@chainsafe/is-ip@2.1.0': {} @@ -12290,22 +11931,11 @@ snapshots: jsonfile: 5.0.0 universalify: 0.1.2 - '@emnapi/core@1.9.1': - dependencies: - '@emnapi/wasi-threads': 1.2.0 - tslib: 2.8.1 - optional: true - '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.0': - dependencies: - tslib: 2.8.1 - optional: true - '@epic-web/invariant@1.0.0': {} '@esbuild/aix-ppc64@0.27.4': @@ -12916,11 +12546,11 @@ snapshots: '@types/yargs': 17.0.34 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: glob: 13.0.1 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: typescript: 5.9.3 @@ -13204,13 +12834,6 @@ snapshots: '@napi-rs/nice-win32-x64-msvc': 1.1.1 optional: true - '@napi-rs/wasm-runtime@1.1.1': - dependencies: - '@emnapi/core': 1.9.1 - '@emnapi/runtime': 1.7.1 - '@tybys/wasm-util': 0.10.1 - optional: true - '@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: file-type: 21.3.2 @@ -13565,8 +13188,6 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) - '@oxc-project/types@0.122.0': {} - '@paralleldrive/cuid2@2.3.1': dependencies: '@noble/hashes': 1.8.0 @@ -13791,55 +13412,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@rolldown/binding-android-arm64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-darwin-arm64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-darwin-x64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-freebsd-x64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': - optional: true - - '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-wasm32-wasi@1.0.0-rc.11': - dependencies: - '@napi-rs/wasm-runtime': 1.1.1 - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': - optional: true - - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': - optional: true - - '@rolldown/pluginutils@1.0.0-rc.11': {} - '@rolldown/pluginutils@1.0.0-rc.2': {} '@rollup/plugin-json@6.1.0(rollup@4.60.0)': @@ -13848,6 +13420,13 @@ snapshots: optionalDependencies: rollup: 4.60.0 + '@rollup/plugin-replace@6.0.3(rollup@4.60.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.60.0) + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.60.0 + '@rollup/pluginutils@5.3.0(rollup@4.60.0)': dependencies: '@types/estree': 1.0.8 @@ -13974,18 +13553,10 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@sentry-internal/browser-utils@10.40.0': - dependencies: - '@sentry/core': 10.40.0 - '@sentry-internal/browser-utils@10.45.0': dependencies: '@sentry/core': 10.45.0 - '@sentry-internal/feedback@10.40.0': - dependencies: - '@sentry/core': 10.40.0 - '@sentry-internal/feedback@10.45.0': dependencies: '@sentry/core': 10.45.0 @@ -13995,34 +13566,16 @@ snapshots: detect-libc: 2.1.2 node-abi: 3.85.0 - '@sentry-internal/replay-canvas@10.40.0': - dependencies: - '@sentry-internal/replay': 10.40.0 - '@sentry/core': 10.40.0 - '@sentry-internal/replay-canvas@10.45.0': dependencies: '@sentry-internal/replay': 10.45.0 '@sentry/core': 10.45.0 - '@sentry-internal/replay@10.40.0': - dependencies: - '@sentry-internal/browser-utils': 10.40.0 - '@sentry/core': 10.40.0 - '@sentry-internal/replay@10.45.0': dependencies: '@sentry-internal/browser-utils': 10.45.0 '@sentry/core': 10.45.0 - '@sentry/browser@10.40.0': - dependencies: - '@sentry-internal/browser-utils': 10.40.0 - '@sentry-internal/feedback': 10.40.0 - '@sentry-internal/replay': 10.40.0 - '@sentry-internal/replay-canvas': 10.40.0 - '@sentry/core': 10.40.0 - '@sentry/browser@10.45.0': dependencies: '@sentry-internal/browser-utils': 10.45.0 @@ -14031,8 +13584,6 @@ snapshots: '@sentry-internal/replay-canvas': 10.45.0 '@sentry/core': 10.45.0 - '@sentry/core@10.40.0': {} - '@sentry/core@10.45.0': {} '@sentry/node-core@10.45.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)': @@ -14106,12 +13657,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@sentry/vue@10.40.0(vue@3.5.30(typescript@5.9.3))': - dependencies: - '@sentry/browser': 10.40.0 - '@sentry/core': 10.40.0 - vue: 3.5.30(typescript@5.9.3) - '@sentry/vue@10.45.0(vue@3.5.30(typescript@5.9.3))': dependencies: '@sentry/browser': 10.45.0 @@ -14670,12 +14215,12 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/builder-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@storybook/builder-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - '@storybook/csf-plugin': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/csf-plugin': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup @@ -14689,14 +14234,14 @@ snapshots: dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/csf-plugin@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@storybook/csf-plugin@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) unplugin: 2.3.10 optionalDependencies: esbuild: 0.27.4 rollup: 4.60.0 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) '@storybook/csf-plugin@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: @@ -14741,11 +14286,11 @@ snapshots: react-dom: 19.2.4(react@19.2.4) storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/react-vite@10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@storybook/react-vite@10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@rollup/pluginutils': 5.3.0(rollup@4.60.0) - '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/react': 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 @@ -14755,7 +14300,7 @@ snapshots: resolve: 1.22.11 storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) tsconfig-paths: 4.2.0 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup @@ -14803,14 +14348,14 @@ snapshots: dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/vue3-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': + '@storybook/vue3-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': dependencies: - '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/vue3': 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) magic-string: 0.30.21 storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) typescript: 5.9.3 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue-component-meta: 2.2.12(typescript@5.9.3) vue-docgen-api: 4.79.2(vue@3.5.30(typescript@5.9.3)) transitivePeerDependencies: @@ -15115,11 +14660,6 @@ snapshots: '@twemoji/parser@16.0.0': {} - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 - optional: true - '@types/accepts@1.3.7': dependencies: '@types/node': 24.12.0 @@ -15588,13 +15128,13 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: 3.5.30(typescript@5.9.3) - '@vitest/coverage-v8@4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)))': + '@vitest/coverage-v8@4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.1.1 @@ -15606,7 +15146,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.0.3 - vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@vitest/expect@2.0.5': dependencies: @@ -15632,14 +15172,14 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@vitest/mocker@4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: '@vitest/spy': 4.1.1 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.12.14(@types/node@24.12.0)(typescript@5.9.3) - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) '@vitest/pretty-format@2.0.5': dependencies: @@ -16763,8 +16303,6 @@ snapshots: colorette@2.0.20: {} - colorjs.io@0.5.2: {} - colors@1.4.0: optional: true @@ -18419,13 +17957,6 @@ snapshots: domutils: 3.2.2 entities: 7.0.1 - htmlparser2@8.0.2: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 4.5.0 - htmlparser2@9.1.0: dependencies: domelementtype: 2.3.0 @@ -19397,55 +18928,6 @@ snapshots: process-warning: 4.0.1 set-cookie-parser: 2.7.1 - lightningcss-android-arm64@1.32.0: - optional: true - - lightningcss-darwin-arm64@1.32.0: - optional: true - - lightningcss-darwin-x64@1.32.0: - optional: true - - lightningcss-freebsd-x64@1.32.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.32.0: - optional: true - - lightningcss-linux-arm64-gnu@1.32.0: - optional: true - - lightningcss-linux-arm64-musl@1.32.0: - optional: true - - lightningcss-linux-x64-gnu@1.32.0: - optional: true - - lightningcss-linux-x64-musl@1.32.0: - optional: true - - lightningcss-win32-arm64-msvc@1.32.0: - optional: true - - lightningcss-win32-x64-msvc@1.32.0: - optional: true - - lightningcss@1.32.0: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 - lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -21291,27 +20773,6 @@ snapshots: glob: 7.2.3 optional: true - rolldown@1.0.0-rc.11: - dependencies: - '@oxc-project/types': 0.122.0 - '@rolldown/pluginutils': 1.0.0-rc.11 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.11 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.11 - '@rolldown/binding-darwin-x64': 1.0.0-rc.11 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.11 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.11 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.11 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.11 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.11 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.11 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.11 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.11 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.11 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.11 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.11 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.11 - rollup@4.60.0: dependencies: '@types/estree': 1.0.8 @@ -21399,15 +20860,6 @@ snapshots: safer-buffer@2.1.2: {} - sanitize-html@2.17.1: - dependencies: - deepmerge: 4.3.1 - escape-string-regexp: 4.0.0 - htmlparser2: 8.0.2 - is-plain-object: 5.0.0 - parse-srcset: 1.0.2 - postcss: 8.5.8 - sanitize-html@2.17.2: dependencies: deepmerge: 4.3.1 @@ -21417,93 +20869,6 @@ snapshots: parse-srcset: 1.0.2 postcss: 8.5.8 - sass-embedded-all-unknown@1.98.0: - dependencies: - sass: 1.98.0 - optional: true - - sass-embedded-android-arm64@1.98.0: - optional: true - - sass-embedded-android-arm@1.98.0: - optional: true - - sass-embedded-android-riscv64@1.98.0: - optional: true - - sass-embedded-android-x64@1.98.0: - optional: true - - sass-embedded-darwin-arm64@1.98.0: - optional: true - - sass-embedded-darwin-x64@1.98.0: - optional: true - - sass-embedded-linux-arm64@1.98.0: - optional: true - - sass-embedded-linux-arm@1.98.0: - optional: true - - sass-embedded-linux-musl-arm64@1.98.0: - optional: true - - sass-embedded-linux-musl-arm@1.98.0: - optional: true - - sass-embedded-linux-musl-riscv64@1.98.0: - optional: true - - sass-embedded-linux-musl-x64@1.98.0: - optional: true - - sass-embedded-linux-riscv64@1.98.0: - optional: true - - sass-embedded-linux-x64@1.98.0: - optional: true - - sass-embedded-unknown-all@1.98.0: - dependencies: - sass: 1.98.0 - optional: true - - sass-embedded-win32-arm64@1.98.0: - optional: true - - sass-embedded-win32-x64@1.98.0: - optional: true - - sass-embedded@1.98.0: - dependencies: - '@bufbuild/protobuf': 2.11.0 - colorjs.io: 0.5.2 - immutable: 5.1.5 - rxjs: 7.8.2 - supports-color: 8.1.1 - sync-child-process: 1.0.2 - varint: 6.0.0 - optionalDependencies: - sass-embedded-all-unknown: 1.98.0 - sass-embedded-android-arm: 1.98.0 - sass-embedded-android-arm64: 1.98.0 - sass-embedded-android-riscv64: 1.98.0 - sass-embedded-android-x64: 1.98.0 - sass-embedded-darwin-arm64: 1.98.0 - sass-embedded-darwin-x64: 1.98.0 - sass-embedded-linux-arm: 1.98.0 - sass-embedded-linux-arm64: 1.98.0 - sass-embedded-linux-musl-arm: 1.98.0 - sass-embedded-linux-musl-arm64: 1.98.0 - sass-embedded-linux-musl-riscv64: 1.98.0 - sass-embedded-linux-musl-x64: 1.98.0 - sass-embedded-linux-riscv64: 1.98.0 - sass-embedded-linux-x64: 1.98.0 - sass-embedded-unknown-all: 1.98.0 - sass-embedded-win32-arm64: 1.98.0 - sass-embedded-win32-x64: 1.98.0 - sass@1.98.0: dependencies: chokidar: 5.0.0 @@ -21511,7 +20876,6 @@ snapshots: source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 - optional: true sax@1.5.0: {} @@ -22161,12 +21525,6 @@ snapshots: symbol-tree@3.2.4: optional: true - sync-child-process@1.0.2: - dependencies: - sync-message-port: 1.2.0 - - sync-message-port@1.2.0: {} - systeminformation@5.31.5: {} tagged-tag@1.0.0: {} @@ -22634,8 +21992,6 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - varint@6.0.0: {} - vary@1.1.2: {} verror@1.10.0: @@ -22654,45 +22010,44 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-plugin-glsl@1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): + vite-plugin-glsl@1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): dependencies: - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: '@rollup/pluginutils': 5.3.0(rollup@4.60.0) esbuild: 0.27.4 vite-plugin-turbosnap@1.0.3: {} - vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0): + vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0): dependencies: - lightningcss: 1.32.0 + esbuild: 0.27.4 + fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.8 - rolldown: 1.0.0-rc.11 + rollup: 4.60.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.12.0 - esbuild: 0.27.4 fsevents: 2.3.3 sass: 1.98.0 - sass-embedded: 1.98.0 terser: 5.46.1 tsx: 4.21.0 - vitest-fetch-mock@0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): + vitest-fetch-mock@0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): dependencies: - vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) - vitest-websocket-mock@0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): + vitest-websocket-mock@0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): dependencies: '@vitest/utils': 3.2.4 mock-socket: 9.3.1 - vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) - vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): + vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): dependencies: '@vitest/expect': 4.1.1 - '@vitest/mocker': 4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@vitest/mocker': 4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@vitest/pretty-format': 4.1.1 '@vitest/runner': 4.1.1 '@vitest/snapshot': 4.1.1 @@ -22709,7 +22064,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 From 367766d864c686cfc88f250f43c94be052db9db6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 6 Apr 2026 11:16:40 +0000 Subject: [PATCH 008/578] Bump version to 2026.4.0-alpha.0 --- CHANGELOG.md | 2 +- package.json | 2 +- packages/misskey-js/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5d712db13a..612ea3c371f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Unreleased +## 2026.4.0 ### General - diff --git a/package.json b/package.json index b70960417a4..527fa179877 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2026.3.2", + "version": "2026.4.0-alpha.0", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index abf85c276c5..9983e84354a 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2026.3.2", + "version": "2026.4.0-alpha.0", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From ae34578c6fb180387bc9e9107b7052e5be7b7aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 6 Apr 2026 22:28:44 +0900 Subject: [PATCH 009/578] =?UTF-8?q?refactor(frontend):=20MkButton=E3=81=AE?= =?UTF-8?q?props=E7=AD=89=E6=95=B4=E7=90=86=20(#17282)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(frontend): MkButton�props等整� * fix --- packages/frontend/src/components/MkButton.vue | 87 ++++++++++++------- .../src/components/MkVisitorDashboard.vue | 2 +- packages/frontend/src/pages/about.emojis.vue | 2 +- packages/frontend/src/pages/admin/abuses.vue | 2 +- packages/frontend/src/pages/channels.vue | 2 +- .../src/pages/page-editor/page-editor.vue | 2 +- .../src/pages/settings/2fa.qrdialog.vue | 2 +- .../frontend/src/pages/settings/profile.vue | 2 +- packages/frontend/src/pages/verify-email.vue | 2 +- 9 files changed, 63 insertions(+), 40 deletions(-) diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index 854ed31ed52..8bcd1972055 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -4,14 +4,12 @@ SPDX-License-Identifier: AGPL-3.0-only --> - + + diff --git a/packages/frontend/src/components/MkPopupMenu.vue b/packages/frontend/src/components/MkPopupMenu.vue index 4942ffe2323..11b116d430c 100644 --- a/packages/frontend/src/components/MkPopupMenu.vue +++ b/packages/frontend/src/components/MkPopupMenu.vue @@ -4,8 +4,31 @@ SPDX-License-Identifier: AGPL-3.0-only --> @@ -21,6 +44,8 @@ defineProps<{ width?: number; anchorElement?: HTMLElement | null; returnFocusTo?: HTMLElement | null; + debugDisablePredictionCone?: boolean; + debugShowPredictionCone?: boolean; }>(); const emit = defineEmits<{ diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index f7b59612c43..8e78127e8e0 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -640,6 +640,8 @@ export function popupMenu(items: (MenuItem | null)[], anchorElement?: HTMLElemen width?: number; onClosing?: () => void; onClosed?: () => void; + debugDisablePredictionCone?: boolean; + debugShowPredictionCone?: boolean; }): Promise { if (!(anchorElement instanceof HTMLElement)) { anchorElement = null; @@ -653,6 +655,8 @@ export function popupMenu(items: (MenuItem | null)[], anchorElement?: HTMLElemen width: options?.width, align: options?.align, returnFocusTo, + debugDisablePredictionCone: options?.debugDisablePredictionCone, + debugShowPredictionCone: options?.debugShowPredictionCone, }, { closed: () => { resolve(); diff --git a/packages/frontend/src/pages/debug.vue b/packages/frontend/src/pages/debug.vue index 9c0761f0b1c..44418d613b1 100644 --- a/packages/frontend/src/pages/debug.vue +++ b/packages/frontend/src/pages/debug.vue @@ -7,30 +7,46 @@ SPDX-License-Identifier: AGPL-3.0-only
- - - - + + - - - - - - - +
+ + + + -
- Error - Warning - Info - Success - Question -
+ + + + + + + + +
+ Error + Warning + Info + Success + Question +
+
+
+ + + + +
+ select without guard + select with guard + select with guard (visualize) +
+
@@ -47,6 +63,7 @@ import MkSelect from '@/components/MkSelect.vue'; import MkButton from '@/components/MkButton.vue'; import { useMkSelect } from '@/composables/use-mkselect.js'; import * as os from '@/os.js'; +import MkFolder from '@/components/MkFolder.vue'; const { model: resultType, @@ -74,6 +91,64 @@ const { initialValue: 'info', }); +function select(ev: PointerEvent, enablePredictionCone: boolean, showPredictionCone: boolean) { + os.popupMenu([ + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', action: () => {} }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + ] }, + ], ev.currentTarget ?? ev.target, { + debugDisablePredictionCone: !enablePredictionCone, + debugShowPredictionCone: showPredictionCone, + }).then((value) => { + console.log('Selected:', value); + }); +} + definePage(() => ({ title: 'DEBUG ROOM', icon: 'ti ti-help-circle', From b9923d0a238f54144d2cd29b72138be741d070ce Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:30:26 +0900 Subject: [PATCH 011/578] New Crowdin updates (#17260) * New translations ja-jp.yml (Thai) * New translations ja-jp.yml (Lao) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Spanish) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Italian) --- locales/ca-ES.yml | 7 ++++--- locales/es-ES.yml | 2 +- locales/it-IT.yml | 7 ++++--- locales/ko-KR.yml | 1 + locales/lo-LA.yml | 1 + locales/th-TH.yml | 2 ++ locales/zh-CN.yml | 1 + locales/zh-TW.yml | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index f2867585c21..ae7f4a03f1a 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -1073,8 +1073,8 @@ thisPostMayBeAnnoying: "Aquesta nota pot ser molesta per algú." thisPostMayBeAnnoyingHome: "Publicar a la línia de temps d'Inici" thisPostMayBeAnnoyingCancel: "Cancel·lar " thisPostMayBeAnnoyingIgnore: "Publicar de totes maneres" -collapseRenotes: "Col·lapsar les renotes que ja has vist" -collapseRenotesDescription: "Col·lapse les notes a les quals ja has reaccionat o que ja has renotat" +collapseRenotes: "Col·lapsar els impulsos que ja has vist" +collapseRenotesDescription: "Col·lapse les notes a les quals ja has reaccionat o que ja has impulsat." internalServerError: "Error intern del servidor" internalServerErrorDescription: "El servidor ha fallat de manera inexplicable." copyErrorInfo: "Copiar la informació de l'error " @@ -1408,6 +1408,7 @@ frame: "Marc" presets: "Predefinit" zeroPadding: "Sense omplir" nothingToConfigure: "No hi ha res a configurar" +viewRenotedChannel: "Mirar el canal d'impulsos " _imageEditing: _vars: caption: "Títol de l'arxiu" @@ -1687,7 +1688,7 @@ _initialTutorial: description: "Pots limitar qui pot veure les teves notes." public: "La teva nota serà visible per a tots els usuaris." home: "Publicar només a línia de temps d'Inici. La gent que visiti el teu perfil o mitjançant les remotes també la podran veure." - followers: "Només visible per a seguidors. Només els teus seguidors la podran veure i ningú més. Ningú més podrà fer renotes." + followers: "Només visible per a seguidors. Només els teus seguidors la podran veure i ningú més. Ningú més podrà fer impulsos." direct: "Només visible per a alguns seguidors, el destinatari rebre una notificació. Es pot fer servir com una alternativa als missatges directes." doNotSendConfidencialOnDirect1: "Tingues cura quan enviïs informació sensible." doNotSendConfidencialOnDirect2: "Els administradors del servidor poden veure tot el que escrius. Ves compte quan enviïs informació sensible en enviar notes directes a altres usuaris en servidors de poca confiança." diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 72b78921284..3c7852cd055 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -3312,7 +3312,7 @@ _clientPerformanceIssueTip: _clip: tip: "Clip es una función que permite organizar varias notas." _userLists: - tip: "Las listas pueden contener cualquier usuario que especifiques al crearlas, la lista creada puede mostrarse entonces como una línea de tiempo mostrando solo los usuarios especificados." + tip: "Puedes crear listas que incluyan a cualquier usuario. Las listas creadas se pueden visualizar en forma de cronología." watermark: "Marca de Agua" defaultPreset: "Por defecto" _watermarkEditor: diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 2401bd84aa0..08c91972512 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -1,7 +1,7 @@ --- _lang_: "Italiano" headlineMisskey: "Rete collegata tramite Note" -introMisskey: "Eccoci! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \n\n📡 Puoi pubblicare «Note» per condividere ciò che sta succedendo o per dire a tutti qualcosa su di te. \n\n� Puoi reagire inviando emoji rapidi alle «Note» provenienti da altri profili nel Fediverso.\n\n🚀 Esplora un nuovo mondo insieme a noi!" +introMisskey: "Eccoci! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \n📡 Puoi pubblicare «Note» per condividere ciò che sta succedendo o per dire a tutti qualcosa su di te. \n� Puoi reagire inviando emoji rapidi alle «Note» provenienti da altri profili nel Fediverso.\n🚀 Esplora un nuovo mondo insieme a noi!" poweredByMisskeyDescription: "{name} è uno dei servizi (chiamati istanze) che utilizzano la piattaforma open source Misskey." monthAndDay: "{day}/{month}" search: "Cerca" @@ -1408,6 +1408,7 @@ frame: "Cornice" presets: "Preimpostato" zeroPadding: "Al vivo" nothingToConfigure: "Niente da configurare" +viewRenotedChannel: "Visualizza il canale del Rinota" _imageEditing: _vars: caption: "Didascalia dell'immagine" @@ -3338,7 +3339,7 @@ _watermarkEditor: stripeWidth: "Larghezza della linea" stripeFrequency: "Il numero di linee" polkadot: "A pallini" - checker: "revisore" + checker: "Scacchiera" polkadotMainDotOpacity: "Opacità del punto principale" polkadotMainDotRadius: "Dimensione del punto principale" polkadotSubDotOpacity: "Opacità del punto secondario" @@ -3367,7 +3368,7 @@ _imageEffector: zoomLines: "Linea di saturazione" stripe: "Strisce" polkadot: "A pallini" - checker: "revisore" + checker: "Scacchiera" blockNoise: "Attenua rumore" tearing: "Strappa immagine" fill: "Riempimento" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 52da6d071a0..294791cce31 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1408,6 +1408,7 @@ frame: "프레임" presets: "프리셋" zeroPadding: "0으로 채우기" nothingToConfigure: "설정 항목� 없습니다." +viewRenotedChannel: "리노트� 채� 보기" _imageEditing: _vars: caption: "파� 설명" diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml index 7017d817332..3779155ae16 100644 --- a/locales/lo-LA.yml +++ b/locales/lo-LA.yml @@ -5,6 +5,7 @@ introMisskey: "�ິນດີຕ້ອນຮັບ! Misskey ເປັນຊອ poweredByMisskeyDescription: "{name} �ມ່ນສ່ວນໜຶ່ງຂອງ�ານບ�ລິ�ານທີ່ຂັບເຄື່ອນໂດ��ພລດຟອມ open source. Misskey (ເອີ້ນວ່າ \"Misskey instance\")" monthAndDay: "ເດືອນ{month} / ວັນ{day}" search: "ຄົ້ນຫາ" +reset: "ຣີເຊັດ" notifications: "�ານ�ຈ້ງເຕືອນ" username: "ຊື່ຜູ້ໃຊ້" password: "ລະຫັດຜ່ານ" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 6bcff59979a..bd53d283006 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -3401,6 +3401,8 @@ _imageEffector: threshold: "เทรชโฮลด์" centerX: "�ลาง X" centerY: "�ลาง Y" + density: "ความหนาทึบ" + zoomLinesOutlineThickness: "ความหนาของเงาเส้น" zoomLinesMaskSize: "ขนาดพื้นที่ตรง�ลาง" circle: "ทรง�ลม" drafts: "ร่าง" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 5cfa90e9100..cda2fc65317 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1408,6 +1408,7 @@ frame: "边框" presets: "预设值" zeroPadding: "填充 0" nothingToConfigure: "没有项目" +viewRenotedChannel: "查看转帖所属频�" _imageEditing: _vars: caption: "文件标题" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index fa8a3eead85..c1347f54c0b 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -10,7 +10,7 @@ notifications: "通知" username: "使用者�稱" password: "密碼" initialPasswordForSetup: "啟動�始設定的密碼" -initialPasswordIsIncorrect: "啟動�始設定的密碼錯誤。" +initialPasswordIsIncorrect: "啟動�始設定密碼錯誤。" initialPasswordForSetupDescription: "如果您自己安�了 Misskey,請使用您在設定檔中輸入的密碼。\n如果您使用 Misskey 的託管�務之類的�務,請使用�供的密碼。\n如果您尚未設定密碼,請將其留空並繼續。" forgotPassword: "忘記密碼" fetchingAsApObject: "從�邦宇宙�得中..." @@ -1408,6 +1408,7 @@ frame: "邊框" presets: "�設值" zeroPadding: "補零" nothingToConfigure: "無�設定的項目" +viewRenotedChannel: "顯示轉發貼文者的頻�" _imageEditing: _vars: caption: "檔案標題" From d4a5048aae13f1e2807a3d2175a0bb0cd4941197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Tue, 7 Apr 2026 20:35:06 +0900 Subject: [PATCH 012/578] =?UTF-8?q?fix(frontend):=20router=E3=81=8CmatchAl?= =?UTF-8?q?l=E3=81=AB=E5=85=A5=E3=81=A3=E3=81=9F=E9=9A=9B=E3=81=AB?= =?UTF-8?q?=E4=B8=80=E5=BA=A6=20`location.href`=20=E3=81=AB=E3=82=88?= =?UTF-8?q?=E3=82=8B=E9=81=B7=E7=A7=BB=E3=82=92=E8=A9=A6=E3=81=BF=E3=82=8B?= =?UTF-8?q?=E6=8C=99=E5=8B=95=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=20(#17281)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(frontend): follow-up of #13509 * fix: fix use of inappropriate method * Update CHANGELOG.md [ci skip] --- CHANGELOG.md | 1 + .../frontend/src/components/MkPageWindow.vue | 22 ++++- .../frontend/src/components/global/MkA.vue | 7 +- packages/frontend/src/lib/nirax.ts | 87 ++++++++++++++----- .../frontend/src/pages/drive.file.info.vue | 2 +- packages/frontend/src/router.ts | 8 ++ 6 files changed, 99 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 612ea3c371f..cec53e38476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Client - Enhance: �ャン�ル指定リノート�リノート先��ャン�ル�移動��るよ�� +- Fix: 一部�ページ内リンク�正��動作����題を修正 ### Server - Fix: `/api-doc` �アクセス�����題を修正 diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue index 4b6467fdda2..f2acec32f0e 100644 --- a/packages/frontend/src/components/MkPageWindow.vue +++ b/packages/frontend/src/components/MkPageWindow.vue @@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only - - diff --git a/packages/frontend/src/pages/admin/roles.policy-editor.folder.vue b/packages/frontend/src/pages/admin/roles.policy-editor.folder.vue new file mode 100644 index 00000000000..ae36f4e2793 --- /dev/null +++ b/packages/frontend/src/pages/admin/roles.policy-editor.folder.vue @@ -0,0 +1,93 @@ + + + + + + + diff --git a/packages/frontend/src/pages/admin/roles.policy-editor.vue b/packages/frontend/src/pages/admin/roles.policy-editor.vue new file mode 100644 index 00000000000..f93cb703e6c --- /dev/null +++ b/packages/frontend/src/pages/admin/roles.policy-editor.vue @@ -0,0 +1,471 @@ + + + + + + + diff --git a/packages/frontend/src/pages/admin/roles.vue b/packages/frontend/src/pages/admin/roles.vue index e65a3c5ba88..94fc75657ad 100644 --- a/packages/frontend/src/pages/admin/roles.vue +++ b/packages/frontend/src/pages/admin/roles.vue @@ -17,310 +17,11 @@ SPDX-License-Identifier: AGPL-3.0-only - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + {{ i18n.ts._role.new }} @@ -345,14 +46,11 @@ SPDX-License-Identifier: AGPL-3.0-only - - diff --git a/packages/frontend/src/components/MkCropperDialog.vue b/packages/frontend/src/components/MkCropperDialog.vue index 1fad936d164..c0fe75a5948 100644 --- a/packages/frontend/src/components/MkCropperDialog.vue +++ b/packages/frontend/src/components/MkCropperDialog.vue @@ -34,7 +34,7 @@ import * as Misskey from 'misskey-js'; import Cropper from 'cropperjs'; import tinycolor from 'tinycolor2'; import MkModalWindow from '@/components/MkModalWindow.vue'; -import * as os from '@/os.js'; +import { themeManager } from '@/theme.js'; import { i18n } from '@/i18n.js'; const props = defineProps<{ @@ -105,10 +105,10 @@ onMounted(() => { cropper = new Cropper(imgEl.value, { }); - const computedStyle = getComputedStyle(window.document.documentElement); + const themeValue = themeManager.currentCompiledTheme!; const selection = cropper.getCropperSelection()!; - selection.themeColor = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString(); + selection.themeColor = tinycolor(themeValue.accent).toHexString(); if (props.aspectRatio != null) selection.aspectRatio = props.aspectRatio; selection.initialAspectRatio = props.aspectRatio ?? 1; selection.outlined = true; diff --git a/packages/frontend/src/components/MkFoldableSection.vue b/packages/frontend/src/components/MkFoldableSection.vue index 0fa7bea7abc..ee152ca4dfe 100644 --- a/packages/frontend/src/components/MkFoldableSection.vue +++ b/packages/frontend/src/components/MkFoldableSection.vue @@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'; import { miLocalStorage } from '@/local-storage.js'; import { prefer } from '@/preferences.js'; -import { globalEvents } from '@/events.js'; +import { themeManager } from '@/theme.js'; import { getBgColor } from '@/utility/get-bg-color.js'; const miLocalStoragePrefix = 'ui:folder:' as const; @@ -92,11 +92,11 @@ function updateBgColor() { onMounted(() => { updateBgColor(); - globalEvents.on('themeChanging', updateBgColor); + themeManager.on('themeChanging', updateBgColor); }); onBeforeUnmount(() => { - globalEvents.off('themeChanging', updateBgColor); + themeManager.off('themeChanging', updateBgColor); }); diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue index 864f53d09cc..1def3de97a4 100644 --- a/packages/frontend/src/components/MkFolder.vue +++ b/packages/frontend/src/components/MkFolder.vue @@ -100,6 +100,7 @@ import { nextTick, onMounted, ref, useTemplateRef, watch } from 'vue'; import { prefer } from '@/preferences.js'; import { getBgColor } from '@/utility/get-bg-color.js'; import { pageFolderTeleportCount, popup } from '@/os.js'; +import { themeManager } from '@/theme.js'; import MkFolderPage from '@/components/MkFolderPage.vue'; import { deviceKind } from '@/utility/device-kind.js'; @@ -192,9 +193,9 @@ async function toggle(ev: PointerEvent) { } onMounted(() => { - const computedStyle = getComputedStyle(window.document.documentElement); + const themeValue = themeManager.currentCompiledTheme!; const parentBg = getBgColor(rootEl.value?.parentElement) ?? 'transparent'; - const myBg = computedStyle.getPropertyValue('--MI_THEME-panel'); + const myBg = themeValue.panel; bgSame.value = parentBg === myBg; }); diff --git a/packages/frontend/src/components/MkInstanceStats.vue b/packages/frontend/src/components/MkInstanceStats.vue index 368fa5be27f..721e4e88deb 100644 --- a/packages/frontend/src/components/MkInstanceStats.vue +++ b/packages/frontend/src/components/MkInstanceStats.vue @@ -73,6 +73,7 @@ import MkRetentionHeatmap from '@/components/MkRetentionHeatmap.vue'; import MkRetentionLineChart from '@/components/MkRetentionLineChart.vue'; import { initChart } from '@/utility/init-chart.js'; import { useMkSelect } from '@/composables/use-mkselect.js'; +import { themeManager } from '@/theme.js'; initChart(); @@ -186,7 +187,7 @@ function createDoughnut(chartEl: HTMLCanvasElement, tooltip: ReturnType x.name), datasets: [{ backgroundColor: data.map(x => x.color), - borderColor: getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel'), + borderColor: themeManager.currentCompiledTheme!.panel, borderWidth: 2, hoverOffset: 0, data: data.map(x => x.value), diff --git a/packages/frontend/src/components/MkMiniChart.vue b/packages/frontend/src/components/MkMiniChart.vue index 582073b8782..0275c33f89d 100644 --- a/packages/frontend/src/components/MkMiniChart.vue +++ b/packages/frontend/src/components/MkMiniChart.vue @@ -33,6 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 0bafa1074ca..83fadef2fae 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -15,6 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only +
@@ -94,12 +95,14 @@ import XMobileFooterMenu from '@/ui/_common_/mobile-footer-menu.vue'; import XTitlebar from '@/ui/_common_/titlebar.vue'; import XPreferenceRestore from '@/ui/_common_/PreferenceRestore.vue'; import XReloadSuggestion from '@/ui/_common_/ReloadSuggestion.vue'; +import XThemePreviewing from '@/ui/_common_/ThemePreviewing.vue'; import * as os from '@/os.js'; import { $i } from '@/i.js'; import { i18n } from '@/i18n.js'; import { deviceKind } from '@/utility/device-kind.js'; import { prefer } from '@/preferences.js'; import { store } from '@/store.js'; +import { isPreviewMode as isThemePreviewMode } from '@/theme.js'; import XMainColumn from '@/ui/deck/main-column.vue'; import XTlColumn from '@/ui/deck/tl-column.vue'; import XAntennaColumn from '@/ui/deck/antenna-column.vue'; diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 95582edea14..13bf1e5175c 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -14,6 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+
@@ -40,8 +41,10 @@ import type { PageMetadata } from '@/page.js'; import XMobileFooterMenu from '@/ui/_common_/mobile-footer-menu.vue'; import XPreferenceRestore from '@/ui/_common_/PreferenceRestore.vue'; import XReloadSuggestion from '@/ui/_common_/ReloadSuggestion.vue'; +import XThemePreviewing from '@/ui/_common_/ThemePreviewing.vue'; import XTitlebar from '@/ui/_common_/titlebar.vue'; import XSidebar from '@/ui/_common_/navbar.vue'; +import { isPreviewMode as isThemePreviewMode } from '@/theme.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/i.js'; diff --git a/packages/frontend/src/utility/code-highlighter.ts b/packages/frontend/src/utility/code-highlighter.ts index 4fdaf242021..8c8a54969ff 100644 --- a/packages/frontend/src/utility/code-highlighter.ts +++ b/packages/frontend/src/utility/code-highlighter.ts @@ -44,7 +44,7 @@ export async function getTheme(mode: 'light' | 'dark', getName = false): Promise _res.type = mode; if (getName) { - return _res.name; + return _res.name!; } return _res; } diff --git a/packages/frontend/src/utility/init-chart.ts b/packages/frontend/src/utility/init-chart.ts index 260899c1d75..c04fd415731 100644 --- a/packages/frontend/src/utility/init-chart.ts +++ b/packages/frontend/src/utility/init-chart.ts @@ -24,6 +24,7 @@ import { import gradient from 'chartjs-plugin-gradient'; import zoomPlugin from 'chartjs-plugin-zoom'; import { MatrixController, MatrixElement } from 'chartjs-chart-matrix'; +import { themeManager } from '@/theme.js'; import { store } from '@/store.js'; import 'chartjs-adapter-date-fns'; @@ -50,7 +51,7 @@ export function initChart() { ); // フォントカラー - Chart.defaults.color = getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-fg'); + Chart.defaults.color = themeManager.currentCompiledTheme!.fg; Chart.defaults.borderColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; diff --git a/packages/frontend/src/utility/popout.ts b/packages/frontend/src/utility/popout.ts index 7e0222c459e..bbea7062c9c 100644 --- a/packages/frontend/src/utility/popout.ts +++ b/packages/frontend/src/utility/popout.ts @@ -11,8 +11,9 @@ export function popout(path: string, w?: HTMLElement) { url = appendQuery(url, 'zen'); if (w) { const position = w.getBoundingClientRect(); - const width = parseInt(getComputedStyle(w, '').width, 10); - const height = parseInt(getComputedStyle(w, '').height, 10); + const computedStyle = getComputedStyle(w, ''); + const width = parseInt(computedStyle.width, 10); + const height = parseInt(computedStyle.height, 10); const x = window.screenX + position.left; const y = window.screenY + position.top; window.open(url, url, diff --git a/packages/frontend/src/utility/theme-editor.ts b/packages/frontend/src/utility/theme-editor.ts index 74175703c3e..8f6789a47d3 100644 --- a/packages/frontend/src/utility/theme-editor.ts +++ b/packages/frontend/src/utility/theme-editor.ts @@ -5,8 +5,8 @@ import { genId } from '@/utility/id.js'; -import type { Theme } from '@/theme.js'; -import { themeProps } from '@/theme.js'; +import type { Theme } from '@@/js/theme.js'; +import { themeProps } from '@@/js/theme.js'; export type Default = null; export type Color = string; diff --git a/packages/frontend/test/theme.test.ts b/packages/frontend/test/theme.test.ts new file mode 100644 index 00000000000..c2c71dd1fff --- /dev/null +++ b/packages/frontend/test/theme.test.ts @@ -0,0 +1,188 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { afterEach, assert, beforeEach, describe, test, vi } from 'vitest'; +import type { Theme } from '@@/js/theme.js'; +import lightTheme from '@@/themes/_light.json5'; +import darkTheme from '@@/themes/_dark.json5'; +import './init'; + +vi.mock('@/i18n.js', () => ({ + i18n: { + ts: { + _theme: { + alreadyInstalled: 'already installed', + invalid: 'invalid', + }, + }, + }, + updateI18n: vi.fn(), +})); + +vi.mock('@/os.js', () => ({ + alert: vi.fn(), +})); + +const cloneTheme = (value: T): T => structuredClone(value); + +const createTheme = (base: 'light' | 'dark', options: { + id: string; + name: string; + accent: string; + bg: string; + fg: string; +}): Theme => { + const builtin = base === 'dark' ? darkTheme : lightTheme; + + return { + id: options.id, + name: options.name, + author: 'tester', + base, + props: { + ...cloneTheme(builtin.props), + accent: options.accent, + bg: options.bg, + fg: options.fg, + }, + }; +}; + +const primaryTheme = createTheme('light', { + id: 'primary-theme', + name: 'Primary Theme', + accent: '#224488', + bg: '#faf7f2', + fg: '#1a1a1a', +}); + +const previewTheme = createTheme('dark', { + id: 'preview-theme', + name: 'Preview Theme', + accent: '#55aa33', + bg: '#101820', + fg: '#f4f4f4', +}); + +const replacementTheme = createTheme('dark', { + id: 'replacement-theme', + name: 'Replacement Theme', + accent: '#bb5500', + bg: '#18110f', + fg: '#f6e7df', +}); + +const loadThemeModule = async () => { + vi.resetModules(); + return await import('@/theme.js'); +}; + +const resetDocument = () => { + window.localStorage.clear(); + document.head.innerHTML = ''; + document.documentElement.className = ''; + document.documentElement.removeAttribute('data-color-scheme'); + document.documentElement.style.cssText = ''; + Reflect.deleteProperty(document, 'startViewTransition'); + Object.defineProperty(document, 'visibilityState', { + configurable: true, + value: 'visible', + }); +}; + +describe('ThemeManager', () => { + beforeEach(() => { + resetDocument(); + }); + + afterEach(() => { + window.localStorage.clear(); + }); + + test('通常テーマ�用後�プレビュー��在テーマ��を切り替��キャッシュ����る', async () => { + const { themeManager, isPreviewMode } = await loadThemeModule(); + + themeManager.updateTheme(primaryTheme); + const cachedTheme = window.localStorage.getItem('theme'); + const cachedThemeId = window.localStorage.getItem('themeId'); + + themeManager.previewTheme(previewTheme); + + assert.strictEqual(themeManager.theme?.id, primaryTheme.id); + assert.strictEqual(themeManager.currentTheme?.id, previewTheme.id); + assert.strictEqual(themeManager.currentThemeId, previewTheme.id); + assert.strictEqual(themeManager.isPreviewMode, true); + assert.strictEqual(isPreviewMode.value, true); + assert.strictEqual(document.documentElement.dataset.colorScheme, 'dark'); + assert.strictEqual(document.documentElement.style.getPropertyValue('--MI_THEME-accent'), themeManager.currentCompiledTheme?.accent); + assert.strictEqual(window.localStorage.getItem('theme'), cachedTheme); + assert.strictEqual(window.localStorage.getItem('themeId'), cachedThemeId); + }); + + test('プレビュー解除�元�テーマ� DOM 状態�復元�れる', async () => { + const { themeManager, isPreviewMode } = await loadThemeModule(); + + themeManager.updateTheme(primaryTheme); + const originalCompiledThemeColor = themeManager.currentCompiledTheme?.htmlThemeColor; + + themeManager.previewTheme(previewTheme); + const previewCompiledThemeColor = themeManager.currentCompiledTheme?.htmlThemeColor; + assert.strictEqual(themeManager.currentTheme?.id, previewTheme.id); + assert.notStrictEqual(previewCompiledThemeColor, originalCompiledThemeColor); + + themeManager.clearPreview(); + + assert.strictEqual(themeManager.theme?.id, primaryTheme.id); + assert.strictEqual(themeManager.currentTheme?.id, primaryTheme.id); + assert.strictEqual(themeManager.currentCompiledTheme?.htmlThemeColor, originalCompiledThemeColor); + assert.strictEqual(themeManager.isPreviewMode, false); + assert.strictEqual(isPreviewMode.value, false); + assert.strictEqual(document.documentElement.dataset.colorScheme, 'light'); + assert.strictEqual(document.documentElement.style.getPropertyValue('--MI_THEME-accent'), themeManager.currentCompiledTheme?.accent); + assert.strictEqual(document.head.querySelector('meta[name="theme-color"]')?.getAttribute('content'), originalCompiledThemeColor); + assert.strictEqual(window.localStorage.getItem('themeId'), primaryTheme.id); + }); + + test('プレビュー中�通常テーマを更新�る�プレビューを抜��新��通常テーマ��用�れる', async () => { + const { themeManager, isPreviewMode } = await loadThemeModule(); + + themeManager.updateTheme(primaryTheme); + themeManager.previewTheme(previewTheme); + themeManager.updateTheme(replacementTheme); + + assert.strictEqual(themeManager.theme?.id, replacementTheme.id); + assert.strictEqual(themeManager.currentTheme?.id, replacementTheme.id); + assert.strictEqual(themeManager.isPreviewMode, false); + assert.strictEqual(isPreviewMode.value, false); + assert.strictEqual(document.documentElement.dataset.colorScheme, 'dark'); + assert.strictEqual(document.documentElement.style.getPropertyValue('--MI_THEME-accent'), themeManager.currentCompiledTheme?.accent); + assert.strictEqual(window.localStorage.getItem('themeId'), replacementTheme.id); + }); + + test('themeChanging � themeChanged �プレビュー�用�復帰����発��る', async () => { + const { themeManager } = await loadThemeModule(); + const events: string[] = []; + + themeManager.on('themeChanging', () => { + events.push('themeChanging'); + }); + themeManager.on('themeChanged', () => { + events.push('themeChanged'); + }); + + themeManager.updateTheme(primaryTheme); + themeManager.previewTheme(previewTheme); + themeManager.clearPreview(); + + assert.deepStrictEqual(events, [ + 'themeChanging', + 'themeChanged', + 'themeChanging', + 'themeChanged', + 'themeChanging', + 'themeChanged', + ]); + }); +}); diff --git a/packages/frontend/test/tsconfig.json b/packages/frontend/test/tsconfig.json index 952435e122b..12c00b740cf 100644 --- a/packages/frontend/test/tsconfig.json +++ b/packages/frontend/test/tsconfig.json @@ -23,7 +23,8 @@ "resolveJsonModule": true, "isolatedModules": true, "paths": { - "@/*": ["../src/*"] + "@/*": ["../src/*"], + "@@/*": ["../../frontend-shared/*"] }, "typeRoots": [ "../node_modules/@types" @@ -37,6 +38,7 @@ "compileOnSave": false, "include": [ "./**/*.ts", - "../src/**/*.vue" + "../src/**/*.vue", + "../@types/**/*.d.ts" ] } diff --git a/packages/i18n/src/autogen/locale.ts b/packages/i18n/src/autogen/locale.ts index 07e9a3afc1a..80f62f78fc2 100644 --- a/packages/i18n/src/autogen/locale.ts +++ b/packages/i18n/src/autogen/locale.ts @@ -5651,6 +5651,14 @@ export interface Locale extends ILocale { * リノート先��ャン�ルを見る */ "viewRenotedChannel": string; + /** + * テーマ�プレビュー中 + */ + "previewingTheme": string; + /** + * 元�戻� + */ + "previewingThemeRestore": string; "_imageEditing": { "_vars": { /** diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1413aae61c..9fabae7389c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1169,9 +1169,18 @@ importers: i18n: specifier: workspace:* version: link:../i18n + json5: + specifier: 2.2.3 + version: 2.2.3 misskey-js: specifier: workspace:* version: link:../misskey-js + shiki: + specifier: 4.0.2 + version: 4.0.2 + tinycolor2: + specifier: 1.6.0 + version: 1.6.0 vue: specifier: 3.5.33 version: 3.5.33(typescript@5.9.3) @@ -1179,21 +1188,18 @@ importers: '@types/node': specifier: 24.12.2 version: 24.12.2 + '@types/tinycolor2': + specifier: 1.4.6 + version: 1.4.6 '@typescript-eslint/eslint-plugin': specifier: 8.59.0 version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.59.0 version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) - esbuild: - specifier: 0.28.0 - version: 0.28.0 eslint-plugin-vue: specifier: 10.9.0 version: 10.9.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) - nodemon: - specifier: 3.1.14 - version: 3.1.14 vue-eslint-parser: specifier: 10.4.0 version: 10.4.0(eslint@9.39.4) diff --git a/scripts/clean-all.mjs b/scripts/clean-all.mjs index dc750af4137..f232be77fd5 100644 --- a/scripts/clean-all.mjs +++ b/scripts/clean-all.mjs @@ -13,7 +13,6 @@ const __dirname = import.meta.dirname; fs.rmSync(__dirname + '/../packages/backend/src-js', { recursive: true, force: true }); fs.rmSync(__dirname + '/../packages/backend/node_modules', { recursive: true, force: true }); - fs.rmSync(__dirname + '/../packages/frontend-shared/built', { recursive: true, force: true }); fs.rmSync(__dirname + '/../packages/frontend-shared/node_modules', { recursive: true, force: true }); fs.rmSync(__dirname + '/../packages/frontend-builder/node_modules', { recursive: true, force: true }); diff --git a/scripts/clean.mjs b/scripts/clean.mjs index faa6011ee92..a1f444ad4bf 100644 --- a/scripts/clean.mjs +++ b/scripts/clean.mjs @@ -10,7 +10,6 @@ const __dirname = import.meta.dirname; (async () => { fs.rmSync(__dirname + '/../packages/backend/built', { recursive: true, force: true }); fs.rmSync(__dirname + '/../packages/backend/src-js', { recursive: true, force: true }); - fs.rmSync(__dirname + '/../packages/frontend-shared/built', { recursive: true, force: true }); fs.rmSync(__dirname + '/../packages/frontend/built', { recursive: true, force: true }); fs.rmSync(__dirname + '/../packages/frontend-embed/built', { recursive: true, force: true }); fs.rmSync(__dirname + '/../packages/icons-subsetter/built', { recursive: true, force: true }); diff --git a/scripts/dev.mjs b/scripts/dev.mjs index c47a33b7fae..54fba71f0f1 100644 --- a/scripts/dev.mjs +++ b/scripts/dev.mjs @@ -70,12 +70,6 @@ execa('pnpm', ['--filter', 'backend', 'dev'], { stderr: process.stderr, }); -execa('pnpm', ['--filter', 'frontend-shared', 'watch', '--no-clean'], { - cwd: _dirname + '/../', - stdout: process.stdout, - stderr: process.stderr, -}); - execa('pnpm', ['--filter', 'frontend', 'watch'], { cwd: _dirname + '/../', stdout: process.stdout, From b73ac26612c04b78e7688b769e55c3eff2d24ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Thu, 7 May 2026 13:37:36 +0900 Subject: [PATCH 091/578] Update CHANGELOG.md --- CHANGELOG.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f80ab9991fd..851d1626ee7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,10 @@ - ### Client -- +- Enhance: テーマ�プレビュー時�リロード���も��テーマ�戻�るよ�� +- Fix: テーマエディター使用時��最��変更���用�れる�題を修正 +- Fix: テーマ�プレビュー時�既存�テーマ�ID�被���る場��プレビュー�����題を修正 +- Fix: テーマ�インストールエラー�表示を改善 ### Server - @@ -19,10 +22,6 @@ ### Client - Enhance: ノート�詳細表示��公開範囲�表示を改善 (Cherry-picked from https://github.com/kokonect-link/cherrypick/commit/ecc75563f4e428b66adccc379bf317b5b21ed8e6) -- Enhance: テーマ�プレビュー時�リロード���も��テーマ�戻�るよ�� -- Fix: テーマエディター使用時��最��変更���用�れる�題を修正 -- Fix: テーマ�プレビュー時�既存�テーマ�ID�被���る場��プレビュー�����題を修正 -- Fix: テーマ�インストールエラー�表示を改善 - Fix: ロール設定画��ロールをアサイン/アサイン解除��際�リロード����も画���映�れるよ�修正 ### Server From 9027129b5838a59cd9e4cba7f74ad0fa8abf80e1 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 8 May 2026 18:26:05 +0900 Subject: [PATCH 092/578] =?UTF-8?q?enhance(frontend):=20MkInput=E3=81=A7th?= =?UTF-8?q?rottle=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20?= =?UTF-8?q?&=20delay=E8=A8=AD=E5=AE=9A=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/MkInput.vue | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/components/MkInput.vue b/packages/frontend/src/components/MkInput.vue index aebeefe165f..1622e57d640 100644 --- a/packages/frontend/src/components/MkInput.vue +++ b/packages/frontend/src/components/MkInput.vue @@ -53,7 +53,7 @@ type ModelValueType = + + +``` + +## 国際化 (i18n) + +- 文字列リテラルを直書����。 +- 引数��: `i18n.ts.` ��照�る (例: `i18n.ts.deleted`)。 +- 引数�り: `i18n.tsx.(...)` �関数呼�出��る (例: `i18n.tsx.takeOverConfirm({ name })`)。 +- 新�キー� **`locales/ja-JP.yml` ��** �追加�る (他言語� Crowdin �自動�信)。 +- `i18n` � `packages/frontend/src/i18n.ts` (���共有モジュール) �ら import �る。 + +## モーダル / 通知 + +- `os.ts` (`packages/frontend/src/os.ts`) 経由�呼�。 +- `os.alert(...)` / `os.confirm(...)` / `os.popup(...)` / `os.success(...)` ��。 +- ブラウザ標準� `window.alert()` / `window.confirm()` を **直接呼���**。 + +## アクセシビリティ (PR レビュー�指摘�れや��点) + +- クリック�ンドラを付�る�ら `
+ + + + + + +
+
+
+ + + + +
+
+
+
+
+
+
{{ i18n.ts.notificationSoundSettings }} @@ -64,8 +86,9 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/i18n/src/autogen/locale.ts b/packages/i18n/src/autogen/locale.ts index 80f62f78fc2..e13458c22d3 100644 --- a/packages/i18n/src/autogen/locale.ts +++ b/packages/i18n/src/autogen/locale.ts @@ -4880,6 +4880,10 @@ export interface Locale extends ILocale { * 投稿�通知を解除 */ "unnotifyNotes": string; + /** + * 投稿通知を設定��ユーザー + */ + "notifyUsers": string; /** * �証 */ diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 7989568e1d4..852ccbb9b90 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2162,6 +2162,8 @@ declare namespace entities { UsersListsUpdateMembershipRequest, UsersNotesRequest, UsersNotesResponse, + UsersNotifyListRequest, + UsersNotifyListResponse, UsersPagesRequest, UsersPagesResponse, UsersReactionsRequest, @@ -3827,6 +3829,12 @@ type UsersNotesRequest = operations['users___notes']['requestBody']['content'][' // @public (undocumented) type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json']; +// @public (undocumented) +type UsersNotifyListRequest = operations['users___notify___list']['requestBody']['content']['application/json']; + +// @public (undocumented) +type UsersNotifyListResponse = operations['users___notify___list']['responses']['200']['content']['application/json']; + // @public (undocumented) type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index 93b97e91d4c..395156ad938 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -4697,6 +4697,17 @@ declare module '../api.js' { credential?: string | null, ): Promise>; + /** + * List of following users with notification enabled. + * + * **Credential required**: *Yes* / **Permission**: *read:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + /** * Show all pages this user created. * diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 2d4e0fe35e4..dbbc44cb7bb 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -640,6 +640,8 @@ import type { UsersListsUpdateMembershipRequest, UsersNotesRequest, UsersNotesResponse, + UsersNotifyListRequest, + UsersNotifyListResponse, UsersPagesRequest, UsersPagesResponse, UsersReactionsRequest, @@ -1084,6 +1086,7 @@ export type Endpoints = { 'users/lists/update': { req: UsersListsUpdateRequest; res: UsersListsUpdateResponse }; 'users/lists/update-membership': { req: UsersListsUpdateMembershipRequest; res: EmptyResponse }; 'users/notes': { req: UsersNotesRequest; res: UsersNotesResponse }; + 'users/notify/list': { req: UsersNotifyListRequest; res: UsersNotifyListResponse }; 'users/pages': { req: UsersPagesRequest; res: UsersPagesResponse }; 'users/reactions': { req: UsersReactionsRequest; res: UsersReactionsResponse }; 'users/recommendation': { req: UsersRecommendationRequest; res: UsersRecommendationResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index a49dd729e6b..c2f845d8ccb 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -643,6 +643,8 @@ export type UsersListsUpdateResponse = operations['users___lists___update']['res export type UsersListsUpdateMembershipRequest = operations['users___lists___update-membership']['requestBody']['content']['application/json']; export type UsersNotesRequest = operations['users___notes']['requestBody']['content']['application/json']; export type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json']; +export type UsersNotifyListRequest = operations['users___notify___list']['requestBody']['content']['application/json']; +export type UsersNotifyListResponse = operations['users___notify___list']['responses']['200']['content']['application/json']; export type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json']; export type UsersPagesResponse = operations['users___pages']['responses']['200']['content']['application/json']; export type UsersReactionsRequest = operations['users___reactions']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 7c794247360..ecc64039d71 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -3852,6 +3852,15 @@ export type paths = { */ post: operations['users___notes']; }; + '/users/notify/list': { + /** + * users/notify/list + * @description List of following users with notification enabled. + * + * **Credential required**: *Yes* / **Permission**: *read:following* + */ + post: operations['users___notify___list']; + }; '/users/pages': { /** * users/pages @@ -36047,6 +36056,78 @@ export interface operations { }; }; }; + users___notify___list: { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + sinceDate?: number; + untilDate?: number; + /** @default 10 */ + limit?: number; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['UserDetailed'][]; + }; + }; + /** @description Client error */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; users___pages: { requestBody: { content: { From e2335567005ccd6e45db1556ae1095bb00d87e52 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 12 May 2026 21:35:47 +0900 Subject: [PATCH 102/578] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ee5cfbbc42..648613809b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### General - Enhance: Unicode 17.0 ��録�れ��る絵文字�処�・表示�対応 - Fluent Emojiや端末�イティブ�絵文字を利用���る場���最新�絵文字�対応���ら�正��表示�����能性��り��。絵文字�表示����場���表示�使用�る絵文字をTwemoji�切り替���利用����。 +- 投稿通知設定��ユーザーをリスト�見る�����るよ�� ### Client - Enhance: テーマ�プレビュー時�リロード���も��テーマ�戻�るよ�� From f4bca4641ca78b6851439b0608e4da30862893f5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 14 May 2026 00:54:20 +0000 Subject: [PATCH 103/578] Bump version to 2026.5.2-beta.0 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 54b3459c990..1fae251d266 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2026.5.2-alpha.0", + "version": "2026.5.2-beta.0", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 36538ada75e..11af21f2fee 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2026.5.2-alpha.0", + "version": "2026.5.2-beta.0", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From a3227c99eded686df968e6075900cbdbe6ccde39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Thu, 14 May 2026 22:51:57 +0900 Subject: [PATCH 104/578] deps: update dependencies (#17400) * deps: Update Dependencies * run pnpm dedupe * update some major packages * update to pnpm v11 * update systeminformation * fix indent * fix: rollback sharp to 0.33 --- .npmrc | 3 - package.json | 31 +- packages/backend/package.json | 42 +- packages/frontend-builder/package.json | 12 +- packages/frontend-embed/package.json | 22 +- packages/frontend-shared/package.json | 8 +- packages/frontend/package.json | 50 +- packages/i18n/package.json | 4 +- packages/icons-subsetter/package.json | 4 +- packages/misskey-bubble-game/package.json | 4 +- packages/misskey-js/generator/package.json | 6 +- packages/misskey-js/package.json | 4 +- packages/misskey-reversi/package.json | 4 +- packages/sw/package.json | 2 +- pnpm-lock.yaml | 5937 +++++++++---------- pnpm-workspace.yaml | 49 +- scripts/changelog-checker/package-lock.json | 168 +- scripts/changelog-checker/package.json | 2 +- 18 files changed, 2959 insertions(+), 3393 deletions(-) delete mode 100644 .npmrc diff --git a/.npmrc b/.npmrc deleted file mode 100644 index daebfd52180..00000000000 --- a/.npmrc +++ /dev/null @@ -1,3 +0,0 @@ -engine-strict = true -save-exact = true -shell-emulator = true diff --git a/package.json b/package.json index 1fae251d266..1a32dc48bec 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "type": "git", "url": "https://github.com/misskey-dev/misskey.git" }, - "packageManager": "pnpm@10.33.2", + "packageManager": "pnpm@11.1.2", "workspaces": [ "packages/misskey-js", "packages/i18n", @@ -53,44 +53,33 @@ "cleanall": "pnpm clean-all" }, "dependencies": { - "cssnano": "7.1.7", + "cssnano": "8.0.0", "esbuild": "0.28.0", "execa": "9.6.1", "ignore-walk": "8.0.0", "js-yaml": "4.1.1", - "postcss": "8.5.10", - "tar": "7.5.13", - "terser": "5.46.2" + "postcss": "8.5.14", + "tar": "7.5.14", + "terser": "5.47.1" }, "devDependencies": { "@eslint/js": "9.39.4", "@misskey-dev/eslint-plugin": "2.1.0", "@types/js-yaml": "4.0.9", "@types/node": "24.12.2", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", "@typescript/native-preview": "7.0.0-dev.20260426.1", "cross-env": "10.1.0", - "cypress": "15.14.1", + "cypress": "15.14.2", "eslint": "9.39.4", - "globals": "17.5.0", + "globals": "17.6.0", "ncp": "2.0.0", - "pnpm": "10.33.2", + "pnpm": "11.1.2", "start-server-and-test": "3.0.2", "typescript": "5.9.3" }, "optionalDependencies": { "@tensorflow/tfjs-core": "4.22.0" - }, - "pnpm": { - "overrides": { - "@aiscript-dev/aiscript-languageserver": "-", - "chokidar": "5.0.0", - "lodash": "4.18.1" - }, - "ignoredBuiltDependencies": [ - "@sentry-internal/node-cpu-profiler", - "exifreader" - ] } } diff --git a/packages/backend/package.json b/packages/backend/package.json index 0f8f28aceb9..3a03407bfb7 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -53,8 +53,8 @@ "utf-8-validate": "6.0.6" }, "dependencies": { - "@aws-sdk/client-s3": "3.1037.0", - "@aws-sdk/lib-storage": "3.1037.0", + "@aws-sdk/client-s3": "3.1044.0", + "@aws-sdk/lib-storage": "3.1044.0", "@fastify/accepts": "5.0.4", "@fastify/cors": "11.2.0", "@fastify/express": "4.0.5", @@ -66,16 +66,16 @@ "@misskey-dev/emoji-data": "17.0.3", "@misskey-dev/sharp-read-bmp": "1.2.0", "@misskey-dev/summaly": "5.3.0", - "@napi-rs/canvas": "0.1.100", + "@napi-rs/canvas": "1.0.0", "@nestjs/common": "11.1.19", "@nestjs/core": "11.1.19", "@nestjs/testing": "11.1.19", - "@oxc-project/runtime": "0.127.0", + "@oxc-project/runtime": "0.129.0", "@peertube/http-signature": "1.7.0", - "@sentry/node": "10.50.0", - "@sentry/profiling-node": "10.50.0", + "@sentry/node": "10.52.0", + "@sentry/profiling-node": "10.52.0", "@simplewebauthn/server": "13.3.0", - "@sinonjs/fake-timers": "15.3.2", + "@sinonjs/fake-timers": "15.4.0", "@smithy/node-http-handler": "4.6.1", "accepts": "1.3.8", "ajv": "8.20.0", @@ -84,7 +84,7 @@ "bcryptjs": "3.0.3", "blurhash": "2.0.5", "body-parser": "2.2.2", - "bullmq": "5.76.2", + "bullmq": "5.76.6", "cacheable-lookup": "7.0.0", "chalk": "5.6.2", "chalk-template": "1.1.2", @@ -99,28 +99,28 @@ "file-type": "22.0.1", "fluent-ffmpeg": "2.1.3", "form-data": "4.0.5", - "got": "15.0.3", + "got": "15.0.5", "hpagent": "1.2.0", "http-link-header": "1.1.3", "i18n": "workspace:*", "ioredis": "5.10.1", "ip-cidr": "4.0.2", - "ipaddr.js": "2.3.0", + "ipaddr.js": "2.4.0", "is-svg": "6.1.0", "json5": "2.2.3", "jsonld": "9.0.0", "juice": "11.1.1", - "meilisearch": "0.57.0", + "meilisearch": "0.58.0", "mfm-js": "0.26.0", "mime-types": "3.0.2", "misskey-js": "workspace:*", "misskey-reversi": "workspace:*", "ms": "3.0.0-canary.202508261828", - "nanoid": "5.1.9", + "nanoid": "5.1.11", "nested-property": "4.0.0", "node-fetch": "3.3.2", "node-html-parser": "7.1.0", - "nodemailer": "8.0.6", + "nodemailer": "8.0.7", "nsfwjs": "4.3.0", "oauth2orize": "1.12.0", "oauth2orize-pkce": "0.1.2", @@ -128,7 +128,7 @@ "otpauth": "9.5.1", "pg": "8.20.0", "pkce-challenge": "6.0.0", - "probe-image-size": "7.2.3", + "probe-image-size": "7.3.0", "promise-limit": "2.7.0", "qrcode": "1.5.4", "random-seed": "0.3.0", @@ -145,10 +145,10 @@ "slacc": "0.1.5", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", - "systeminformation": "5.31.5", + "systeminformation": "5.31.6", "tinycolor2": "1.6.0", "tmp": "0.2.5", - "tsc-alias": "1.8.16", + "tsc-alias": "1.8.17", "typeorm": "0.3.28", "ulid": "3.0.2", "vary": "1.1.2", @@ -160,7 +160,7 @@ "@kitajs/ts-html-plugin": "4.1.4", "@nestjs/platform-express": "11.1.19", "@rollup/plugin-esm-shim": "0.1.8", - "@sentry/vue": "10.50.0", + "@sentry/vue": "10.52.0", "@types/accepts": "1.3.7", "@types/archiver": "7.0.0", "@types/body-parser": "1.19.6", @@ -191,8 +191,8 @@ "@types/vary": "1.1.3", "@types/web-push": "3.6.4", "@types/ws": "8.18.1", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", "@vitest/coverage-v8": "4.1.5", "aws-sdk-client-mock": "4.1.0", "cbor": "10.0.12", @@ -202,10 +202,10 @@ "fkill": "10.0.3", "js-yaml": "4.1.1", "pid-port": "2.1.1", - "rolldown": "1.0.0-rc.15", + "rolldown": "1.0.0", "simple-oauth2": "5.1.0", "supertest": "7.2.2", - "vite": "8.0.10", + "vite": "8.0.11", "vitest": "4.1.5", "vitest-mock-extended": "4.0.0" } diff --git a/packages/frontend-builder/package.json b/packages/frontend-builder/package.json index ce4d809484c..03f9ab6dad2 100644 --- a/packages/frontend-builder/package.json +++ b/packages/frontend-builder/package.json @@ -10,17 +10,17 @@ "./*": "./js/*" }, "devDependencies": { - "@types/estree": "1.0.8", + "@types/estree": "1.0.9", "@types/node": "24.12.2", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", - "rollup": "4.60.2" + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", + "rollup": "4.60.3" }, "dependencies": { "estree-walker": "3.0.3", "i18n": "workspace:*", "magic-string": "0.30.21", - "rolldown": "1.0.0-rc.15", - "vite": "8.0.10" + "rolldown": "1.0.0", + "vite": "8.0.11" } } diff --git a/packages/frontend-embed/package.json b/packages/frontend-embed/package.json index 879894ed440..196c3e0dcfd 100644 --- a/packages/frontend-embed/package.json +++ b/packages/frontend-embed/package.json @@ -22,43 +22,43 @@ "mfm-js": "0.26.0", "misskey-js": "workspace:*", "punycode.js": "2.3.1", - "rollup": "4.60.2", + "rollup": "4.60.3", "shiki": "4.0.2", "tinycolor2": "1.6.0", "uuid": "14.0.0", - "vue": "3.5.33" + "vue": "3.5.34" }, "devDependencies": { "@misskey-dev/emoji-assets": "17.0.3", "@misskey-dev/summaly": "5.3.0", "@tabler/icons-webfont": "3.35.0", "@testing-library/vue": "8.1.0", - "@types/estree": "1.0.8", + "@types/estree": "1.0.9", "@types/micromatch": "4.0.10", "@types/node": "24.12.2", "@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/tinycolor2": "1.4.6", "@types/ws": "8.18.1", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", "@vitest/coverage-v8": "4.1.5", - "@vue/runtime-core": "3.5.33", + "@vue/runtime-core": "3.5.34", "acorn": "8.16.0", "cross-env": "10.1.0", "eslint-plugin-import": "2.32.0", - "eslint-plugin-vue": "10.9.0", + "eslint-plugin-vue": "10.9.1", "happy-dom": "20.9.0", "intersection-observer": "0.12.2", "micromatch": "4.0.8", - "msw": "2.13.6", + "msw": "2.14.3", "prettier": "3.8.3", "sass-embedded": "1.99.0", "start-server-and-test": "3.0.2", "tsx": "4.21.0", - "vite": "8.0.10", + "vite": "8.0.11", "vite-plugin-turbosnap": "1.0.3", - "vue-component-type-helpers": "3.2.7", + "vue-component-type-helpers": "3.2.8", "vue-eslint-parser": "10.4.0", - "vue-tsc": "3.2.7" + "vue-tsc": "3.2.8" } } diff --git a/packages/frontend-shared/package.json b/packages/frontend-shared/package.json index ce9b3278b38..1d324c2dd76 100644 --- a/packages/frontend-shared/package.json +++ b/packages/frontend-shared/package.json @@ -10,9 +10,9 @@ "devDependencies": { "@types/node": "24.12.2", "@types/tinycolor2": "1.4.6", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", - "eslint-plugin-vue": "10.9.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", + "eslint-plugin-vue": "10.9.1", "vue-eslint-parser": "10.4.0" }, "files": [ @@ -25,6 +25,6 @@ "misskey-js": "workspace:*", "shiki": "4.0.2", "tinycolor2": "1.6.0", - "vue": "3.5.33" + "vue": "3.5.34" } } diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 0d929e9e325..1392160c5aa 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -20,7 +20,7 @@ "@mcaptcha/core-glue": "0.1.0-alpha-5", "@misskey-dev/browser-image-resizer": "2024.1.0", "@misskey-dev/emoji-data": "17.0.3", - "@sentry/vue": "10.50.0", + "@sentry/vue": "10.52.0", "@simplewebauthn/browser": "13.3.0", "@syuilo/aiscript": "1.2.1", "@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0", @@ -32,10 +32,10 @@ "canvas-confetti": "1.9.4", "chart.js": "4.5.1", "chartjs-adapter-date-fns": "3.0.0", - "chartjs-chart-matrix": "3.0.0", + "chartjs-chart-matrix": "3.0.4", "chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-zoom": "2.2.0", - "chromatic": "16.6.0", + "chromatic": "16.9.0", "compare-versions": "6.1.1", "cropperjs": "2.1.1", "date-fns": "4.1.0", @@ -47,11 +47,11 @@ "icons-subsetter": "workspace:*", "idb-keyval": "6.2.2", "insert-text-at-cursor": "0.3.0", - "ios-haptics": "0.1.4", + "ios-haptics": "0.1.5", "is-file-animated": "1.0.2", "json5": "2.2.3", "matter-js": "0.20.0", - "mediabunny": "1.41.0", + "mediabunny": "1.44.1", "mfm-js": "0.26.0", "misskey-bubble-game": "workspace:*", "misskey-js": "workspace:*", @@ -67,7 +67,7 @@ "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", "v-code-diff": "1.13.1", - "vue": "3.5.33", + "vue": "3.5.34", "wanakana": "5.3.1" }, "devDependencies": { @@ -77,7 +77,7 @@ "@rollup/pluginutils": "5.3.0", "@storybook/addon-essentials": "8.6.18", "@storybook/addon-interactions": "8.6.18", - "@storybook/addon-links": "10.3.5", + "@storybook/addon-links": "10.3.6", "@storybook/addon-mdx-gfm": "8.6.18", "@storybook/addon-storysource": "8.6.18", "@storybook/blocks": "8.6.18", @@ -85,17 +85,17 @@ "@storybook/core-events": "8.6.18", "@storybook/manager-api": "8.6.18", "@storybook/preview-api": "8.6.18", - "@storybook/react": "10.3.5", - "@storybook/react-vite": "10.3.5", + "@storybook/react": "10.3.6", + "@storybook/react-vite": "10.3.6", "@storybook/test": "8.6.18", "@storybook/theming": "8.6.18", "@storybook/types": "8.6.18", - "@storybook/vue3": "10.3.5", - "@storybook/vue3-vite": "10.3.5", + "@storybook/vue3": "10.3.6", + "@storybook/vue3-vite": "10.3.6", "@tabler/icons-webfont": "3.35.0", "@testing-library/vue": "8.1.0", "@types/canvas-confetti": "1.9.0", - "@types/estree": "1.0.8", + "@types/estree": "1.0.9", "@types/insert-text-at-cursor": "0.3.2", "@types/matter-js": "0.20.2", "@types/micromatch": "4.0.10", @@ -106,41 +106,41 @@ "@types/textarea-caret": "3.0.4", "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", "@vitest/coverage-v8": "4.1.5", - "@vue/compiler-core": "3.5.33", + "@vue/compiler-core": "3.5.34", "acorn": "8.16.0", "astring": "1.9.0", "cross-env": "10.1.0", - "cypress": "15.14.1", + "cypress": "15.14.2", "eslint-plugin-import": "2.32.0", - "eslint-plugin-vue": "10.9.0", + "eslint-plugin-vue": "10.9.1", "estree-walker": "3.0.3", "happy-dom": "20.9.0", "intersection-observer": "0.12.2", "micromatch": "4.0.8", "minimatch": "10.2.5", - "msw": "2.13.6", + "msw": "2.14.3", "msw-storybook-addon": "2.0.7", "nodemon": "3.1.14", "prettier": "3.8.3", - "react": "19.2.5", - "react-dom": "19.2.5", - "rolldown": "1.0.0-rc.15", + "react": "19.2.6", + "react-dom": "19.2.6", + "rolldown": "1.0.0", "sass-embedded": "1.99.0", "seedrandom": "3.0.5", "start-server-and-test": "3.0.2", - "storybook": "10.3.5", + "storybook": "10.3.6", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "tsx": "4.21.0", - "vite": "8.0.10", + "vite": "8.0.11", "vite-plugin-glsl": "1.6.0", "vite-plugin-turbosnap": "1.0.3", "vitest": "4.1.5", "vitest-fetch-mock": "0.4.5", - "vue-component-type-helpers": "3.2.7", + "vue-component-type-helpers": "3.2.8", "vue-eslint-parser": "10.4.0", - "vue-tsc": "3.2.7" + "vue-tsc": "3.2.8" } } diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 24c2588a4d0..2876e18e43b 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -30,8 +30,8 @@ "devDependencies": { "@types/js-yaml": "4.0.9", "@types/node": "24.12.2", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", "chokidar": "5.0.0", "esbuild": "0.28.0", "execa": "9.6.1", diff --git a/packages/icons-subsetter/package.json b/packages/icons-subsetter/package.json index 76488968c39..0903da3c096 100644 --- a/packages/icons-subsetter/package.json +++ b/packages/icons-subsetter/package.json @@ -13,8 +13,8 @@ "devDependencies": { "@types/node": "24.12.2", "@types/wawoff2": "1.0.2", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0" + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2" }, "dependencies": { "@tabler/icons-webfont": "3.35.0", diff --git a/packages/misskey-bubble-game/package.json b/packages/misskey-bubble-game/package.json index ca86bf280b1..fa6b52cc592 100644 --- a/packages/misskey-bubble-game/package.json +++ b/packages/misskey-bubble-game/package.json @@ -27,8 +27,8 @@ "@types/matter-js": "0.20.2", "@types/node": "24.12.2", "@types/seedrandom": "3.0.8", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", "esbuild": "0.28.0", "execa": "9.6.1", "nodemon": "3.1.14" diff --git a/packages/misskey-js/generator/package.json b/packages/misskey-js/generator/package.json index b97a4426065..e9e0f7451a2 100644 --- a/packages/misskey-js/generator/package.json +++ b/packages/misskey-js/generator/package.json @@ -7,10 +7,10 @@ "generate": "tsx src/generator.ts && eslint ./built/**/*.ts --fix" }, "devDependencies": { - "@readme/openapi-parser": "6.0.1", + "@readme/openapi-parser": "6.1.1", "@types/node": "24.12.2", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", "openapi-types": "12.1.3", "openapi-typescript": "7.13.0", "ts-case-convert": "2.1.0", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 11af21f2fee..90045fd12a8 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -39,8 +39,8 @@ "devDependencies": { "@microsoft/api-extractor": "7.58.7", "@types/node": "24.12.2", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", "@vitest/coverage-v8": "4.1.5", "esbuild": "0.28.0", "execa": "9.6.1", diff --git a/packages/misskey-reversi/package.json b/packages/misskey-reversi/package.json index 9e0fbdde2cf..c09ff272896 100644 --- a/packages/misskey-reversi/package.json +++ b/packages/misskey-reversi/package.json @@ -25,8 +25,8 @@ }, "devDependencies": { "@types/node": "24.12.2", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", "esbuild": "0.28.0", "execa": "9.6.1", "nodemon": "3.1.14" diff --git a/packages/sw/package.json b/packages/sw/package.json index 2001c608c12..def3bb7645b 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -15,7 +15,7 @@ "misskey-js": "workspace:*" }, "devDependencies": { - "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/parser": "8.59.2", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.74", "eslint-plugin-import": "2.32.0", "nodemon": "3.1.14" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 65198c29246..0d4fb2acfd5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,8 +14,8 @@ importers: .: dependencies: cssnano: - specifier: 7.1.7 - version: 7.1.7(postcss@8.5.10) + specifier: 8.0.0 + version: 8.0.0(postcss@8.5.14) esbuild: specifier: 0.28.0 version: 0.28.0 @@ -29,21 +29,21 @@ importers: specifier: 4.1.1 version: 4.1.1 postcss: - specifier: 8.5.10 - version: 8.5.10 + specifier: 8.5.14 + version: 8.5.14 tar: - specifier: 7.5.13 - version: 7.5.13 + specifier: 7.5.14 + version: 7.5.14 terser: - specifier: 5.46.2 - version: 5.46.2 + specifier: 5.47.1 + version: 5.47.1 devDependencies: '@eslint/js': specifier: 9.39.4 version: 9.39.4 '@misskey-dev/eslint-plugin': specifier: 2.1.0 - version: 2.1.0(@eslint/compat@1.4.0(eslint@9.39.4))(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/eslint-plugin@8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4))(eslint@9.39.4)(globals@17.5.0) + version: 2.1.0(@eslint/compat@2.0.5(eslint@9.39.4))(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4))(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4))(eslint@9.39.4)(globals@17.6.0) '@types/js-yaml': specifier: 4.0.9 version: 4.0.9 @@ -51,11 +51,11 @@ importers: specifier: 24.12.2 version: 24.12.2 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) '@typescript/native-preview': specifier: 7.0.0-dev.20260426.1 version: 7.0.0-dev.20260426.1 @@ -63,20 +63,20 @@ importers: specifier: 10.1.0 version: 10.1.0 cypress: - specifier: 15.14.1 - version: 15.14.1 + specifier: 15.14.2 + version: 15.14.2 eslint: specifier: 9.39.4 version: 9.39.4 globals: - specifier: 17.5.0 - version: 17.5.0 + specifier: 17.6.0 + version: 17.6.0 ncp: specifier: 2.0.0 version: 2.0.0 pnpm: - specifier: 10.33.2 - version: 10.33.2 + specifier: 11.1.2 + version: 11.1.2 start-server-and-test: specifier: 3.0.2 version: 3.0.2 @@ -86,16 +86,16 @@ importers: optionalDependencies: '@tensorflow/tfjs-core': specifier: 4.22.0 - version: 4.22.0(encoding@0.1.13) + version: 4.22.0 packages/backend: dependencies: '@aws-sdk/client-s3': - specifier: 3.1037.0 - version: 3.1037.0 + specifier: 3.1044.0 + version: 3.1044.0 '@aws-sdk/lib-storage': - specifier: 3.1037.0 - version: 3.1037.0(@aws-sdk/client-s3@3.1037.0) + specifier: 3.1044.0 + version: 3.1044.0(@aws-sdk/client-s3@3.1044.0) '@fastify/accepts': specifier: 5.0.4 version: 5.0.4 @@ -130,8 +130,8 @@ importers: specifier: 5.3.0 version: 5.3.0 '@napi-rs/canvas': - specifier: 0.1.100 - version: 0.1.100 + specifier: 1.0.0 + version: 1.0.0 '@nestjs/common': specifier: 11.1.19 version: 11.1.19(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -142,23 +142,23 @@ importers: specifier: 11.1.19 version: 11.1.19(@nestjs/common@11.1.19(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/platform-express@11.1.19) '@oxc-project/runtime': - specifier: 0.127.0 - version: 0.127.0 + specifier: 0.129.0 + version: 0.129.0 '@peertube/http-signature': specifier: 1.7.0 version: 1.7.0 '@sentry/node': - specifier: 10.50.0 - version: 10.50.0 + specifier: 10.52.0 + version: 10.52.0 '@sentry/profiling-node': - specifier: 10.50.0 - version: 10.50.0 + specifier: 10.52.0 + version: 10.52.0 '@simplewebauthn/server': specifier: 13.3.0 version: 13.3.0 '@sinonjs/fake-timers': - specifier: 15.3.2 - version: 15.3.2 + specifier: 15.4.0 + version: 15.4.0 '@smithy/node-http-handler': specifier: 4.6.1 version: 4.6.1 @@ -184,8 +184,8 @@ importers: specifier: 2.2.2 version: 2.2.2 bullmq: - specifier: 5.76.2 - version: 5.76.2 + specifier: 5.76.6 + version: 5.76.6 cacheable-lookup: specifier: 7.0.0 version: 7.0.0 @@ -229,8 +229,8 @@ importers: specifier: 4.0.5 version: 4.0.5 got: - specifier: 15.0.3 - version: 15.0.3 + specifier: 15.0.5 + version: 15.0.5 hpagent: specifier: 1.2.0 version: 1.2.0 @@ -247,8 +247,8 @@ importers: specifier: 4.0.2 version: 4.0.2 ipaddr.js: - specifier: 2.3.0 - version: 2.3.0 + specifier: 2.4.0 + version: 2.4.0 is-svg: specifier: 6.1.0 version: 6.1.0 @@ -262,8 +262,8 @@ importers: specifier: 11.1.1 version: 11.1.1 meilisearch: - specifier: 0.57.0 - version: 0.57.0 + specifier: 0.58.0 + version: 0.58.0 mfm-js: specifier: 0.26.0 version: 0.26.0 @@ -280,8 +280,8 @@ importers: specifier: 3.0.0-canary.202508261828 version: 3.0.0-canary.202508261828 nanoid: - specifier: 5.1.9 - version: 5.1.9 + specifier: 5.1.11 + version: 5.1.11 nested-property: specifier: 4.0.0 version: 4.0.0 @@ -292,11 +292,11 @@ importers: specifier: 7.1.0 version: 7.1.0 nodemailer: - specifier: 8.0.6 - version: 8.0.6 + specifier: 8.0.7 + version: 8.0.7 nsfwjs: specifier: 4.3.0 - version: 4.3.0(@tensorflow/tfjs@4.22.0(encoding@0.1.13)(seedrandom@3.0.5))(buffer@6.0.3) + version: 4.3.0(@tensorflow/tfjs@4.22.0(seedrandom@3.0.5))(buffer@6.0.3) oauth2orize: specifier: 1.12.0 version: 1.12.0 @@ -316,8 +316,8 @@ importers: specifier: 6.0.0 version: 6.0.0 probe-image-size: - specifier: 7.2.3 - version: 7.2.3 + specifier: 7.3.0 + version: 7.3.0 promise-limit: specifier: 2.7.0 version: 2.7.0 @@ -367,8 +367,8 @@ importers: specifier: 2.1.0 version: 2.1.0 systeminformation: - specifier: 5.31.5 - version: 5.31.5 + specifier: 5.31.6 + version: 5.31.6 tinycolor2: specifier: 1.6.0 version: 1.6.0 @@ -376,8 +376,8 @@ importers: specifier: 0.2.5 version: 0.2.5 tsc-alias: - specifier: 1.8.16 - version: 1.8.16 + specifier: 1.8.17 + version: 1.8.17 typeorm: specifier: 0.3.28 version: 0.3.28(ioredis@5.10.1)(pg@8.20.0) @@ -405,10 +405,10 @@ importers: version: 11.1.19(@nestjs/common@11.1.19(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) '@rollup/plugin-esm-shim': specifier: 0.1.8 - version: 0.1.8(rollup@4.60.2) + version: 0.1.8(rollup@4.60.3) '@sentry/vue': - specifier: 10.50.0 - version: 10.50.0(vue@3.5.33(typescript@5.9.3)) + specifier: 10.52.0 + version: 10.52.0(vue@3.5.34(typescript@5.9.3)) '@types/accepts': specifier: 1.3.7 version: 1.3.7 @@ -500,11 +500,11 @@ importers: specifier: 8.18.1 version: 8.18.1 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.5 version: 4.1.5(vitest@4.1.5) @@ -519,7 +519,7 @@ importers: version: 10.1.0 eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + version: 2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) execa: specifier: 9.6.1 version: 9.6.1 @@ -533,8 +533,8 @@ importers: specifier: 2.1.1 version: 2.1.1 rolldown: - specifier: 1.0.0-rc.15 - version: 1.0.0-rc.15 + specifier: 1.0.0 + version: 1.0.0 simple-oauth2: specifier: 5.1.0 version: 5.1.0 @@ -542,21 +542,21 @@ importers: specifier: 7.2.2 version: 7.2.2 vite: - specifier: 8.0.10 - version: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + specifier: 8.0.11 + version: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) vitest: specifier: 4.1.5 - version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) vitest-mock-extended: specifier: 4.0.0 version: 4.0.0(typescript@5.9.3)(vitest@4.1.5) optionalDependencies: '@tensorflow/tfjs': specifier: 4.22.0 - version: 4.22.0(encoding@0.1.13)(seedrandom@3.0.5) + version: 4.22.0(seedrandom@3.0.5) '@tensorflow/tfjs-node': specifier: 4.22.0 - version: 4.22.0(encoding@0.1.13)(seedrandom@3.0.5) + version: 4.22.0(seedrandom@3.0.5) bufferutil: specifier: 4.1.0 version: 4.1.0 @@ -618,8 +618,8 @@ importers: specifier: 17.0.3 version: 17.0.3 '@sentry/vue': - specifier: 10.50.0 - version: 10.50.0(vue@3.5.33(typescript@5.9.3)) + specifier: 10.52.0 + version: 10.52.0(vue@3.5.34(typescript@5.9.3)) '@simplewebauthn/browser': specifier: 13.3.0 version: 13.3.0 @@ -631,7 +631,7 @@ importers: version: '@syuilo/aiscript@0.19.0' '@vitejs/plugin-vue': specifier: 6.0.6 - version: 6.0.6(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))(vue@3.5.33(typescript@5.9.3)) + version: 6.0.6(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))(vue@3.5.34(typescript@5.9.3)) aiscript-vscode: specifier: github:aiscript-dev/aiscript-vscode#v0.1.16 version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/1dc7f60cda78d030dadfc518a33c472202b2ef67 @@ -654,8 +654,8 @@ importers: specifier: 3.0.0 version: 3.0.0(chart.js@4.5.1)(date-fns@4.1.0) chartjs-chart-matrix: - specifier: 3.0.0 - version: 3.0.0(chart.js@4.5.1) + specifier: 3.0.4 + version: 3.0.4(chart.js@4.5.1) chartjs-plugin-gradient: specifier: 0.6.1 version: 0.6.1(chart.js@4.5.1) @@ -663,8 +663,8 @@ importers: specifier: 2.2.0 version: 2.2.0(chart.js@4.5.1) chromatic: - specifier: 16.6.0 - version: 16.6.0 + specifier: 16.9.0 + version: 16.9.0 compare-versions: specifier: 6.1.1 version: 6.1.1 @@ -699,8 +699,8 @@ importers: specifier: 0.3.0 version: 0.3.0 ios-haptics: - specifier: 0.1.4 - version: 0.1.4 + specifier: 0.1.5 + version: 0.1.5 is-file-animated: specifier: 1.0.2 version: 1.0.2 @@ -711,8 +711,8 @@ importers: specifier: 0.20.0 version: 0.20.0 mediabunny: - specifier: 1.41.0 - version: 1.41.0 + specifier: 1.44.1 + version: 1.44.1 mfm-js: specifier: 0.26.0 version: 0.26.0 @@ -757,10 +757,10 @@ importers: version: 1.6.0 v-code-diff: specifier: 1.13.1 - version: 1.13.1(vue@3.5.33(typescript@5.9.3)) + version: 1.13.1(vue@3.5.34(typescript@5.9.3)) vue: - specifier: 3.5.33 - version: 3.5.33(typescript@5.9.3) + specifier: 3.5.34 + version: 3.5.34(typescript@5.9.3) wanakana: specifier: 5.3.1 version: 5.3.1 @@ -773,73 +773,73 @@ importers: version: 5.3.0 '@rollup/plugin-json': specifier: 6.1.0 - version: 6.1.0(rollup@4.60.2) + version: 6.1.0(rollup@4.60.3) '@rollup/pluginutils': specifier: 5.3.0 - version: 5.3.0(rollup@4.60.2) + version: 5.3.0(rollup@4.60.3) '@storybook/addon-essentials': specifier: 8.6.18 - version: 8.6.18(@types/react@19.2.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(@types/react@19.2.14)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/addon-interactions': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/addon-links': - specifier: 10.3.5 - version: 10.3.5(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + specifier: 10.3.6 + version: 10.3.6(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/addon-mdx-gfm': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/addon-storysource': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/blocks': specifier: 8.6.18 - version: 8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/components': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/core-events': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/manager-api': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/preview-api': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/react': - specifier: 10.3.5 - version: 10.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(typescript@5.9.3) + specifier: 10.3.6 + version: 10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(typescript@5.9.3) '@storybook/react-vite': - specifier: 10.3.5 - version: 10.3.5(esbuild@0.28.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(rollup@4.60.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + specifier: 10.3.6 + version: 10.3.6(esbuild@0.28.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(rollup@4.60.3)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) '@storybook/test': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/theming': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/types': specifier: 8.6.18 - version: 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + version: 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@storybook/vue3': - specifier: 10.3.5 - version: 10.3.5(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vue@3.5.33(typescript@5.9.3)) + specifier: 10.3.6 + version: 10.3.6(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vue@3.5.34(typescript@5.9.3)) '@storybook/vue3-vite': - specifier: 10.3.5 - version: 10.3.5(esbuild@0.28.0)(rollup@4.60.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))(vue@3.5.33(typescript@5.9.3)) + specifier: 10.3.6 + version: 10.3.6(esbuild@0.28.0)(rollup@4.60.3)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))(vue@3.5.34(typescript@5.9.3)) '@tabler/icons-webfont': specifier: 3.35.0 version: 3.35.0 '@testing-library/vue': specifier: 8.1.0 - version: 8.1.0(@vue/compiler-sfc@3.5.33)(vue@3.5.33(typescript@5.9.3)) + version: 8.1.0(@vue/compiler-dom@3.5.34)(@vue/compiler-sfc@3.5.34)(@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3)))(vue@3.5.34(typescript@5.9.3)) '@types/canvas-confetti': specifier: 1.9.0 version: 1.9.0 '@types/estree': - specifier: 1.0.8 - version: 1.0.8 + specifier: 1.0.9 + version: 1.0.9 '@types/insert-text-at-cursor': specifier: 0.3.2 version: 0.3.2 @@ -871,17 +871,17 @@ importers: specifier: 1.4.6 version: 1.4.6 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.5 version: 4.1.5(vitest@4.1.5) '@vue/compiler-core': - specifier: 3.5.33 - version: 3.5.33 + specifier: 3.5.34 + version: 3.5.34 acorn: specifier: 8.16.0 version: 8.16.0 @@ -892,14 +892,14 @@ importers: specifier: 10.1.0 version: 10.1.0 cypress: - specifier: 15.14.1 - version: 15.14.1 + specifier: 15.14.2 + version: 15.14.2 eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + version: 2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) eslint-plugin-vue: - specifier: 10.9.0 - version: 10.9.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) + specifier: 10.9.1 + version: 10.9.1(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4))(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) estree-walker: specifier: 3.0.3 version: 3.0.3 @@ -916,11 +916,11 @@ importers: specifier: 10.2.5 version: 10.2.5 msw: - specifier: 2.13.6 - version: 2.13.6(@types/node@24.12.2)(typescript@5.9.3) + specifier: 2.14.3 + version: 2.14.3(@types/node@24.12.2)(typescript@5.9.3) msw-storybook-addon: specifier: 2.0.7 - version: 2.0.7(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3)) + version: 2.0.7(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3)) nodemon: specifier: 3.1.14 version: 3.1.14 @@ -928,14 +928,14 @@ importers: specifier: 3.8.3 version: 3.8.3 react: - specifier: 19.2.5 - version: 19.2.5 + specifier: 19.2.6 + version: 19.2.6 react-dom: - specifier: 19.2.5 - version: 19.2.5(react@19.2.5) + specifier: 19.2.6 + version: 19.2.6(react@19.2.6) rolldown: - specifier: 1.0.0-rc.15 - version: 1.0.0-rc.15 + specifier: 1.0.0 + version: 1.0.0 sass-embedded: specifier: 1.99.0 version: 1.99.0 @@ -946,38 +946,38 @@ importers: specifier: 3.0.2 version: 3.0.2 storybook: - specifier: 10.3.5 - version: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + specifier: 10.3.6 + version: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(97c00992be6c92d700516236c15b3de8) + version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(267bf2f6efbfa841ce5c842b3f261858) tsx: specifier: 4.21.0 version: 4.21.0 vite: - specifier: 8.0.10 - version: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + specifier: 8.0.11 + version: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) vite-plugin-glsl: specifier: 1.6.0 - version: 1.6.0(@rollup/pluginutils@5.3.0(rollup@4.60.2))(esbuild@0.28.0)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + version: 1.6.0(@rollup/pluginutils@5.3.0(rollup@4.60.3))(esbuild@0.28.0)(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 vitest: specifier: 4.1.5 - version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) vitest-fetch-mock: specifier: 0.4.5 version: 0.4.5(vitest@4.1.5) vue-component-type-helpers: - specifier: 3.2.7 - version: 3.2.7 + specifier: 3.2.8 + version: 3.2.8 vue-eslint-parser: specifier: 10.4.0 version: 10.4.0(eslint@9.39.4) vue-tsc: - specifier: 3.2.7 - version: 3.2.7(typescript@5.9.3) + specifier: 3.2.8 + version: 3.2.8(typescript@5.9.3) packages/frontend-builder: dependencies: @@ -991,39 +991,39 @@ importers: specifier: 0.30.21 version: 0.30.21 rolldown: - specifier: 1.0.0-rc.15 - version: 1.0.0-rc.15 + specifier: 1.0.0 + version: 1.0.0 vite: - specifier: 8.0.10 - version: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + specifier: 8.0.11 + version: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) devDependencies: '@types/estree': - specifier: 1.0.8 - version: 1.0.8 + specifier: 1.0.9 + version: 1.0.9 '@types/node': specifier: 24.12.2 version: 24.12.2 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) rollup: - specifier: 4.60.2 - version: 4.60.2 + specifier: 4.60.3 + version: 4.60.3 packages/frontend-embed: dependencies: '@rollup/plugin-json': specifier: 6.1.0 - version: 6.1.0(rollup@4.60.2) + version: 6.1.0(rollup@4.60.3) '@rollup/pluginutils': specifier: 5.3.0 - version: 5.3.0(rollup@4.60.2) + version: 5.3.0(rollup@4.60.3) '@vitejs/plugin-vue': specifier: 6.0.6 - version: 6.0.6(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))(vue@3.5.33(typescript@5.9.3)) + version: 6.0.6(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))(vue@3.5.34(typescript@5.9.3)) buraha: specifier: 0.0.1 version: 0.0.1 @@ -1052,8 +1052,8 @@ importers: specifier: 2.3.1 version: 2.3.1 rollup: - specifier: 4.60.2 - version: 4.60.2 + specifier: 4.60.3 + version: 4.60.3 shiki: specifier: 4.0.2 version: 4.0.2 @@ -1064,8 +1064,8 @@ importers: specifier: 14.0.0 version: 14.0.0 vue: - specifier: 3.5.33 - version: 3.5.33(typescript@5.9.3) + specifier: 3.5.34 + version: 3.5.34(typescript@5.9.3) devDependencies: '@misskey-dev/emoji-assets': specifier: 17.0.3 @@ -1078,10 +1078,10 @@ importers: version: 3.35.0 '@testing-library/vue': specifier: 8.1.0 - version: 8.1.0(@vue/compiler-sfc@3.5.33)(vue@3.5.33(typescript@5.9.3)) + version: 8.1.0(@vue/compiler-dom@3.5.34)(@vue/compiler-sfc@3.5.34)(@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3)))(vue@3.5.34(typescript@5.9.3)) '@types/estree': - specifier: 1.0.8 - version: 1.0.8 + specifier: 1.0.9 + version: 1.0.9 '@types/micromatch': specifier: 4.0.10 version: 4.0.10 @@ -1098,17 +1098,17 @@ importers: specifier: 8.18.1 version: 8.18.1 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.5 version: 4.1.5(vitest@4.1.5) '@vue/runtime-core': - specifier: 3.5.33 - version: 3.5.33 + specifier: 3.5.34 + version: 3.5.34 acorn: specifier: 8.16.0 version: 8.16.0 @@ -1117,10 +1117,10 @@ importers: version: 10.1.0 eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + version: 2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) eslint-plugin-vue: - specifier: 10.9.0 - version: 10.9.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) + specifier: 10.9.1 + version: 10.9.1(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4))(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) happy-dom: specifier: 20.9.0 version: 20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1131,8 +1131,8 @@ importers: specifier: 4.0.8 version: 4.0.8 msw: - specifier: 2.13.6 - version: 2.13.6(@types/node@24.12.2)(typescript@5.9.3) + specifier: 2.14.3 + version: 2.14.3(@types/node@24.12.2)(typescript@5.9.3) prettier: specifier: 3.8.3 version: 3.8.3 @@ -1146,20 +1146,20 @@ importers: specifier: 4.21.0 version: 4.21.0 vite: - specifier: 8.0.10 - version: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + specifier: 8.0.11 + version: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 vue-component-type-helpers: - specifier: 3.2.7 - version: 3.2.7 + specifier: 3.2.8 + version: 3.2.8 vue-eslint-parser: specifier: 10.4.0 version: 10.4.0(eslint@9.39.4) vue-tsc: - specifier: 3.2.7 - version: 3.2.7(typescript@5.9.3) + specifier: 3.2.8 + version: 3.2.8(typescript@5.9.3) packages/frontend-shared: dependencies: @@ -1182,8 +1182,8 @@ importers: specifier: 1.6.0 version: 1.6.0 vue: - specifier: 3.5.33 - version: 3.5.33(typescript@5.9.3) + specifier: 3.5.34 + version: 3.5.34(typescript@5.9.3) devDependencies: '@types/node': specifier: 24.12.2 @@ -1192,14 +1192,14 @@ importers: specifier: 1.4.6 version: 1.4.6 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) eslint-plugin-vue: - specifier: 10.9.0 - version: 10.9.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) + specifier: 10.9.1 + version: 10.9.1(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4))(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)) vue-eslint-parser: specifier: 10.4.0 version: 10.4.0(eslint@9.39.4) @@ -1217,11 +1217,11 @@ importers: specifier: 24.12.2 version: 24.12.2 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) chokidar: specifier: 5.0.0 version: 5.0.0 @@ -1260,11 +1260,11 @@ importers: specifier: 1.0.2 version: 1.0.2 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) packages/misskey-bubble-game: dependencies: @@ -1288,11 +1288,11 @@ importers: specifier: 3.0.8 version: 3.0.8 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) esbuild: specifier: 0.28.0 version: 0.28.0 @@ -1322,11 +1322,11 @@ importers: specifier: 24.12.2 version: 24.12.2 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.5 version: 4.1.5(vitest@4.1.5) @@ -1347,7 +1347,7 @@ importers: version: 0.33.0 vitest: specifier: 4.1.5 - version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) vitest-websocket-mock: specifier: 0.5.0 version: 0.5.0(vitest@4.1.5) @@ -1355,17 +1355,17 @@ importers: packages/misskey-js/generator: devDependencies: '@readme/openapi-parser': - specifier: 6.0.1 - version: 6.0.1(openapi-types@12.1.3) + specifier: 6.1.1 + version: 6.1.1(openapi-types@12.1.3) '@types/node': specifier: 24.12.2 version: 24.12.2 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) eslint: specifier: 9.39.4 version: 9.39.4 @@ -1392,11 +1392,11 @@ importers: specifier: 24.12.2 version: 24.12.2 '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) esbuild: specifier: 0.28.0 version: 0.28.0 @@ -1423,23 +1423,20 @@ importers: version: link:../misskey-js devDependencies: '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.4)(typescript@5.9.3) + specifier: 8.59.2 + version: 8.59.2(eslint@9.39.4)(typescript@5.9.3) '@typescript/lib-webworker': specifier: npm:@types/serviceworker@0.0.74 version: '@types/serviceworker@0.0.74' eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + version: 2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) nodemon: specifier: 3.1.14 version: 3.1.14 packages: - '@acemir/cssom@0.9.31': - resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} - '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} @@ -1473,15 +1470,6 @@ packages: peerDependencies: '@types/json-schema': ^7.0.15 - '@asamuzakjp/css-color@4.1.2': - resolution: {integrity: sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==} - - '@asamuzakjp/dom-selector@6.7.8': - resolution: {integrity: sha512-stisC1nULNc9oH5lakAj8MH88ZxeGxzyWNDfbdCxvJSJIvDsHNZqYvscGTgy/ysgXWLJPt6K/4t0/GjvtKcFJQ==} - - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - '@aws-crypto/crc32@5.2.0': resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} engines: {node: '>=16.0.0'} @@ -1505,55 +1493,55 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-s3@3.1037.0': - resolution: {integrity: sha512-DBmA1jAW8ST6C4srBxeL1/RLIir/d8WOm4s4mi59mGp6mBktHM59Kwb7GuURaCO60cotuce5zr0sKpMLPcBQyA==} + '@aws-sdk/client-s3@3.1044.0': + resolution: {integrity: sha512-yT3g0Oi0b+pJBJswNxRwWLLBoExQhRx9Iz2rUy1xV0slMogTQN+DSjChI95XTDtpGEcY0qnIK6UYX0XCYdhOKg==} engines: {node: '>=20.0.0'} - '@aws-sdk/core@3.974.5': - resolution: {integrity: sha512-lMPlYlYfQdNZhlkJgnkmESwrY+hNh3PljmZ+37oAqLNdJ6rnILAwFSyc6B3bJeDOtMORNnMQIej0aTRuOlDyhQ==} + '@aws-sdk/core@3.974.8': + resolution: {integrity: sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw==} engines: {node: '>=20.0.0'} '@aws-sdk/crc64-nvme@3.972.7': resolution: {integrity: sha512-QUagVVBbC8gODCF6e1aV0mE2TXWB9Opz4k8EJFdNrujUVQm5R4AjJa1mpOqzwOuROBzqJU9zawzig7M96L8Ejg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-env@3.972.31': - resolution: {integrity: sha512-X/yGB73LmDW/6MdDJGCDzZBUXnM3ys4vs9l+5ZTJmiEswDdP1OjeoAFlFjVGS9o4KB2wZWQ9KOfdVNSSK6Ep3w==} + '@aws-sdk/credential-provider-env@3.972.34': + resolution: {integrity: sha512-XT0jtf8Fw9JE6ppsQeoNnZRiG+jqRixMT1v1ZR17G60UvVdsQmTG8nbEyHuEPfMxDXEhfdARaM/XiEhca4lGHQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-http@3.972.33': - resolution: {integrity: sha512-c0ZF+lwoWVvX5iCaGKL5T/4DnIw88CGqxA0BcBs3U86mIp5EZYPVg+KSPkMXOyokmADvNewiMUfSG2uFwjRp0g==} + '@aws-sdk/credential-provider-http@3.972.36': + resolution: {integrity: sha512-DPoGWfy7J7RKxvbf5kOKIGQkD2ek3dbKgzKIGrnLuvZBz5myU+Im/H6pmc14QcnFbqHMqxvtWSgRDSJW3qXLQg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-ini@3.972.35': - resolution: {integrity: sha512-jsU4u/cRkKFLKQS0k918FQ27fzXLG5ENiLWQMYE6581zLeI2hWh04ptlrvZMB3wJT/5d+vSzJk74X1CMFr4y8Q==} + '@aws-sdk/credential-provider-ini@3.972.38': + resolution: {integrity: sha512-oDzUBu2MGJFgoar05sPMCwSrhw44ASyccrHzj66vO69OZqi7I6hZZxXfuPLC8OCzW7C+sU+bI73XHij41yekgQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-login@3.972.35': - resolution: {integrity: sha512-5oa3j0cA50jPqgNhZ9XdJVopuzUf1klRb28/2MfLYWWiPi9DRVvbrBWT+DidbHTT36520VuXZJahQwR+YgSjrg==} + '@aws-sdk/credential-provider-login@3.972.38': + resolution: {integrity: sha512-g1NosS8qe4OF++G2UFCM5ovSkgipC7YYor5KCWatG0UoMSO5YFj9C8muePlyVmOBV/WTI16Jo3/s1NUo/o1Bww==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-node@3.972.36': - resolution: {integrity: sha512-4nT2T8Z7vH8KE9EdjEsuIlHpZSlcaK2PrKbQBjuUGU46BCCzF3WvP0u0Uiosni3Ykmmn4rWLVawoOCLotUtCbg==} + '@aws-sdk/credential-provider-node@3.972.39': + resolution: {integrity: sha512-HEswDQyxUtadoZ/bJsPPENHg7R0Lzym5LuMksJeHvqhCOpP+rtkDLKI4/ZChH4w3cf5kG8n6bZuI8PzajoiqMg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-process@3.972.31': - resolution: {integrity: sha512-eKeT4MXumpBJsrDLCYcSzIkFPVTFn/es7It2oogp2OhU/ic7P/+xzFpQx9ZhwtXS57Mc5S42BPWi7lHmvs/nYg==} + '@aws-sdk/credential-provider-process@3.972.34': + resolution: {integrity: sha512-T3IFs4EVmVi1dVN5RciFnklCANSzvrQd/VuHY9ThHSQmYkTogjcGkoJEr+oNUPQZnso52183088NqysMPji1/Q==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-sso@3.972.35': - resolution: {integrity: sha512-bCuBdfnj0KGDMdLp6utMTLiJcFN2ek9EgZinxQZZSc3FxjJ/HSqeqab2cjbnoNfy8RM6suDCsRkmVY1izp9I+A==} + '@aws-sdk/credential-provider-sso@3.972.38': + resolution: {integrity: sha512-5ZxG+t0+3Q3QPh8KEjX6syskhgNf7I0MN7oGioTf6Lm1NTjfP7sIcYGNsthXC2qR8vcD3edNZwCr2ovfSSWuRA==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.35': - resolution: {integrity: sha512-swW6Bwvl8lanyEMtZOWE/oR6yqcRQH4HTQZUVsnDVgoXvRjRywpYpLv2BWwjUFyjPrqsdX6FeTkf4tMSe/qFTQ==} + '@aws-sdk/credential-provider-web-identity@3.972.38': + resolution: {integrity: sha512-lYHFF30DGI20jZcYX8cm6Ns0V7f1dDN6g/MBDLTyD/5iw+bXs3yBr2iAiHDkx4RFU5JgsnZvCHYKiRVPRdmOgw==} engines: {node: '>=20.0.0'} - '@aws-sdk/lib-storage@3.1037.0': - resolution: {integrity: sha512-ZFg5Vf4RKS48xTm7DfXTeR0Rvn/Fcu6YFdRygGnvhA+gW3W0WtsRqM1CzkWevYBztdUUAsZqtGbMj9Eu0OaeEg==} + '@aws-sdk/lib-storage@3.1044.0': + resolution: {integrity: sha512-VMyTkaF87RwDmrNPMmfxRADc4SIU0P85q/WzMpr+6e8MfLzHA/lUSkndM4FLEcEBh/AYUUqbBPHxs+WT6xIHLA==} engines: {node: '>=20.0.0'} peerDependencies: - '@aws-sdk/client-s3': ^3.1037.0 + '@aws-sdk/client-s3': ^3.1044.0 '@aws-sdk/middleware-bucket-endpoint@3.972.10': resolution: {integrity: sha512-Vbc2frZH7wXlMNd+ZZSXUEs/l1Sv8Jj4zUnIfwrYF5lwaLdXHZ9xx4U3rjUcaye3HRhFVc+E5DbBxpRAbB16BA==} @@ -1563,8 +1551,8 @@ packages: resolution: {integrity: sha512-2Yn0f1Qiq/DjxYR3wfI3LokXnjOhFM7Ssn4LTdFDIxRMCE6I32MAsVnhPX1cUZsuVA9tiZtwwhlSLAtFGxAZlQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-flexible-checksums@3.974.13': - resolution: {integrity: sha512-b6QUe2hQX9XsnCzp6mtzVaERhganDKeb8lmGL6pVhr7rRVH9S9keDFW7uKytuuqmcY5943FixoGqn/QL+sbUBA==} + '@aws-sdk/middleware-flexible-checksums@3.974.16': + resolution: {integrity: sha512-6ru8doI0/XzszqLIPXf0E/V7HhAw1Pu94010XCKYtBUfD0LxF0BuOzrUf8OQGR6j2o6wgKTHUniOmndQycHwCA==} engines: {node: '>=20.0.0'} '@aws-sdk/middleware-host-header@3.972.10': @@ -1583,32 +1571,32 @@ packages: resolution: {integrity: sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-sdk-s3@3.972.34': - resolution: {integrity: sha512-/UL96JKjsjdodcRRMKl99tLQvK6Oi9ptLC9iU1yiTF/ruaDX0mtBBtnLNZDxIZRJOCVOtB49ed1YaTadqygk8Q==} + '@aws-sdk/middleware-sdk-s3@3.972.37': + resolution: {integrity: sha512-Km7M+i8DrLArVzrid1gfxeGhYHBd3uxvE77g0s5a52zPSVosxzQBnJ0gwWb6NIp/DOk8gsBMhi7V+cpJG0ndTA==} engines: {node: '>=20.0.0'} '@aws-sdk/middleware-ssec@3.972.10': resolution: {integrity: sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-user-agent@3.972.35': - resolution: {integrity: sha512-hOFWNOjVmOocpRlrU04nYxjMOeoe0Obu5AXEuhB8zblMCPl3cG1hdluQCZERRKFyhMQjwZnDbhSHjoMUjetFGw==} + '@aws-sdk/middleware-user-agent@3.972.38': + resolution: {integrity: sha512-iz+B29TXcAZsJpwB+AwG/TTGA5l/VnmMZ2UxtiySOZjI6gCdmviXPwdgzcmuazMy16rXoPY4mYCGe7zdNKfx5A==} engines: {node: '>=20.0.0'} - '@aws-sdk/nested-clients@3.997.3': - resolution: {integrity: sha512-SivE6GP228IVgfsrr2c/vqTg95X0Qj39Yw4uIrcddpkUzIltNMoNOR62leHOLhODfjv9K8X2mPTwS69A5kT0nQ==} + '@aws-sdk/nested-clients@3.997.6': + resolution: {integrity: sha512-WBDnqatJl+kGObpfmfSxqnXeYTu3Me8wx8WCtvoxX3pfWrrTv8I4WTMSSs7PZqcRcVh8WeUKMgGFjMG+52SR1w==} engines: {node: '>=20.0.0'} '@aws-sdk/region-config-resolver@3.972.13': resolution: {integrity: sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A==} engines: {node: '>=20.0.0'} - '@aws-sdk/signature-v4-multi-region@3.996.22': - resolution: {integrity: sha512-/rXhMXteD+BqhFd0nYprAgcZ/KtU+963uftPqd3tiFcFfooHZINXUGtOmo2SQjRVauCTNqIEzkwuSETdZFqTTA==} + '@aws-sdk/signature-v4-multi-region@3.996.25': + resolution: {integrity: sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw==} engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.1036.0': - resolution: {integrity: sha512-aNSJ6jjDYayxN9ZA1JpycVScX93Lx03kKZ1EXt3DGOTahcWVLJj3oLAlop0xKP+vP2Ga2t49p1tEaMkTbCCaZA==} + '@aws-sdk/token-providers@3.1041.0': + resolution: {integrity: sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw==} engines: {node: '>=20.0.0'} '@aws-sdk/types@3.973.8': @@ -1623,15 +1611,15 @@ packages: resolution: {integrity: sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-locate-window@3.893.0': - resolution: {integrity: sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==} - engines: {node: '>=18.0.0'} + '@aws-sdk/util-locate-window@3.965.5': + resolution: {integrity: sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/util-user-agent-browser@3.972.10': resolution: {integrity: sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==} - '@aws-sdk/util-user-agent-node@3.973.21': - resolution: {integrity: sha512-Av4UHTcAWgdvbN0IP9pbtf4Qa1+6LtJqQdZWj5pLn5J67w0pnJJAZZ+7JPPcj2KN3378zD2JDM9DwJKEyvyMTQ==} + '@aws-sdk/util-user-agent-node@3.973.24': + resolution: {integrity: sha512-ZWwlkjcIp7cEL8ZfTpTAPNkwx25p7xol0xlKoWVVf22+nsjwmLcHYtTPjIV1cSpmB/b6DaK4cb1fSkvCXHgRdw==} engines: {node: '>=20.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -1639,44 +1627,44 @@ packages: aws-crt: optional: true - '@aws-sdk/xml-builder@3.972.19': - resolution: {integrity: sha512-Cw8IOMdBUEIl8ZlhRC3Dc/E64D5B5/8JhV6vhPLiPfJwcRC84S6F8aBOIi/N4vR9ZyA4I5Cc0Ateb/9EHaJXeQ==} + '@aws-sdk/xml-builder@3.972.22': + resolution: {integrity: sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA==} engines: {node: '>=20.0.0'} - '@aws/lambda-invoke-store@0.2.2': - resolution: {integrity: sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg==} + '@aws/lambda-invoke-store@0.2.4': + resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} engines: {node: '>=18.0.0'} - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.5': - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + '@babel/compat-data@7.29.3': + resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.5': - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1693,12 +1681,12 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.2': - resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} engines: {node: '>=6.0.0'} hasBin: true @@ -1706,12 +1694,16 @@ packages: resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} '@babel/types@7.29.0': @@ -1725,14 +1717,14 @@ packages: '@borewit/text-codec@0.2.2': resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} - '@bufbuild/protobuf@2.11.0': - resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} + '@bufbuild/protobuf@2.12.0': + resolution: {integrity: sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==} '@canvas/image-data@1.1.0': resolution: {integrity: sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA==} - '@colordx/core@5.4.2': - resolution: {integrity: sha512-oC//VDid7CrDg+iXE/8RBq1s+MP+EFh5ggJOkpM9+ZathjC736A67Yg9LMAQULQ1blj9E0m0g8PubOu1/HniaQ==} + '@colordx/core@5.4.3': + resolution: {integrity: sha512-kIxYSfA5T8HXjav55UaaH/o/cKivF6jCCGIb8eqtcsfI46wsvlSiT8jMDyrl779qLec3c2c2oHBZo4oAhvbjrQ==} '@cropper/element-canvas@2.1.1': resolution: {integrity: sha512-QHiHnPHsykkc4salOiCLOIKWPK3sLQ1SzpJYFE/yQPvqTPu6ERZNcxVwB1x7WhNN+SdP0S0CEHPYIkgIfUo7VA==} @@ -1767,37 +1759,6 @@ packages: '@cropper/utils@2.1.1': resolution: {integrity: sha512-0eQs08WyQUNFMfU3ieE091dEQkrW0YdgZ3n6Thnk1EUQv45ypfiL+MevHwr7UzNnUlqUYR2FNSCgE6qBxK0sFw==} - '@csstools/color-helpers@6.0.1': - resolution: {integrity: sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ==} - engines: {node: '>=20.19.0'} - - '@csstools/css-calc@3.0.0': - resolution: {integrity: sha512-q4d82GTl8BIlh/dTnVsWmxnbWJeb3kiU8eUH71UxlxnS+WIaALmtzTL8gR15PkYOexMQYVk0CO4qIG93C1IvPA==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 - - '@csstools/css-color-parser@4.0.1': - resolution: {integrity: sha512-vYwO15eRBEkeF6xjAno/KQ61HacNhfQuuU/eGwH67DplL0zD5ZixUa563phQvUelA07yDczIXdtmYojCphKJcw==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 - - '@csstools/css-parser-algorithms@4.0.0': - resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-tokenizer': ^4.0.0 - - '@csstools/css-syntax-patches-for-csstree@1.0.26': - resolution: {integrity: sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA==} - - '@csstools/css-tokenizer@4.0.0': - resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} - engines: {node: '>=20.19.0'} - '@cypress/request@3.0.10': resolution: {integrity: sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==} engines: {node: '>= 6'} @@ -1805,30 +1766,24 @@ packages: '@cypress/xvfb@1.2.4': resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} - '@digitalbazaar/http-client@4.2.0': - resolution: {integrity: sha512-OGju/GYp0V72qlZ/Pd4jGEwqBwT/Za/tw+Z3AC7lgMheGqsbhTZrtc5iLz9z59G/Q53QyE2fnjHV8N9wjBpiWA==} + '@digitalbazaar/http-client@4.3.0': + resolution: {integrity: sha512-6lMpxpt9BOmqHKGs9Xm6DP4LlZTBFer/ZjHvP3FcW3IaUWYIWC7dw5RFZnvw4fP57kAVcm1dp3IF+Y50qhBvAw==} engines: {node: '>=18.0'} '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@emnapi/core@1.9.2': - resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} - '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/runtime@1.9.2': - resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} - '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} - '@esbuild/aix-ppc64@0.27.4': - resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1839,8 +1794,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.4': - resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1851,8 +1806,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.4': - resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1863,8 +1818,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.4': - resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -1875,8 +1830,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.4': - resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1887,8 +1842,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.4': - resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1899,8 +1854,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.4': - resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1911,8 +1866,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.4': - resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1923,8 +1878,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.4': - resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1935,8 +1890,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.4': - resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1947,8 +1902,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.4': - resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1959,8 +1914,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.4': - resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1971,8 +1926,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.4': - resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1983,8 +1938,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.4': - resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1995,8 +1950,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.4': - resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -2007,8 +1962,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.4': - resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -2019,8 +1974,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.4': - resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -2031,8 +1986,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.4': - resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -2043,8 +1998,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.4': - resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -2055,8 +2010,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.4': - resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -2067,8 +2022,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.4': - resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -2079,8 +2034,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.4': - resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -2091,8 +2046,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.4': - resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -2103,8 +2058,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.4': - resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -2115,8 +2070,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.4': - resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -2127,8 +2082,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.4': - resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -2149,11 +2104,11 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@1.4.0': - resolution: {integrity: sha512-DEzm5dKeDBPm3r08Ixli/0cmxr8LkRdwxMRUIJBlSCpAwSrvFEJpVBzV+66JhDxiaqKxnRzCXhtiMiczF7Hglg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/compat@2.0.5': + resolution: {integrity: sha512-IbHDbHJfkVNv6xjlET8AIVo/K1NQt7YT4Rp6ok/clyBGcpRx1l6gv0Rq3vBvYfPJIZt6ODf66Zq08FJNDpnzgg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: - eslint: ^8.40 || 9 + eslint: ^8.40 || 9 || 10 peerDependenciesMeta: eslint: optional: true @@ -2166,14 +2121,14 @@ packages: resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.16.0': - resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.17.0': resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@eslint/eslintrc@3.3.5': resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2205,8 +2160,8 @@ packages: '@fastify/cors@11.2.0': resolution: {integrity: sha512-LbLHBuSAdGdSFZYTLVA3+Ch2t+sA6nq3Ejc6XLAKiQ6ViS2qFnvicpj0htsx03FyYeLs04HfRNBsz/a8SvbcUw==} - '@fastify/deepmerge@3.1.0': - resolution: {integrity: sha512-lCVONBQINyNhM6LLezB6+2afusgEYR4G8xenMsfe+AT+iZ7Ca6upM5Ha8UkZuYSnuMw3GWl/BiPXnLMi/gSxuQ==} + '@fastify/deepmerge@3.2.1': + resolution: {integrity: sha512-N5Oqvltoa2r9z1tbx4xjky0oRR60v+T47Ic4J1ukoVQcptLOrIdRnCSdTGmOmajZuHVKlTnfcmrjyqsGEW1ztA==} '@fastify/error@4.2.0': resolution: {integrity: sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==} @@ -2271,8 +2226,8 @@ packages: '@hapi/pinpoint@2.0.1': resolution: {integrity: sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==} - '@hapi/tlds@1.1.4': - resolution: {integrity: sha512-Fq+20dxsxLaUn5jSSWrdtSRcIUba2JquuorF9UW1wIJS5cSUwxIsO2GIhaWynPRflvxSzFN+gxKte2HEW1OuoA==} + '@hapi/tlds@1.1.6': + resolution: {integrity: sha512-xdi7A/4NZokvV0ewovme3aUO5kQhW9pQ2YD1hRqZGhhSi5rBv4usHYidVocXSi9eihYsznZxLtAiEYYUL6VBGw==} engines: {node: '>=14.0.0'} '@hapi/topo@5.1.0': @@ -2281,18 +2236,22 @@ packages: '@hapi/topo@6.0.2': resolution: {integrity: sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==} - '@hapi/wreck@18.1.0': - resolution: {integrity: sha512-0z6ZRCmFEfV/MQqkQomJ7sl/hyxvcZM7LtuVqN3vdAO4vM9eBbowl0kaqQj9EJJQab+3Uuh1GxbGIBFy4NfJ4w==} + '@hapi/wreck@18.1.1': + resolution: {integrity: sha512-UwTeGBfAnB/1mkw4gD6IQGI/bgMu7iGmqgT8K+xxye3z4ZHhCZlmS2wuHBJmENhBJSKqvoYzJ71ds3Xfq4gofQ==} '@hexagon/base64@1.1.28': resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -2466,10 +2425,6 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - '@isaacs/cliui@9.0.0': - resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} - engines: {node: '>=18'} - '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -2619,83 +2574,83 @@ packages: cpu: [x64] os: [win32] - '@mswjs/interceptors@0.41.6': - resolution: {integrity: sha512-qmDvJIjcNsZ6tXWy2G9yuCgMPTTn35GMA3dPpSLm7QJVpbQzYdw0ALy1bKoivXnEM3U93/OrK+/M719b+fg84Q==} + '@mswjs/interceptors@0.41.8': + resolution: {integrity: sha512-pRLMNKTSGRoLq+KnEB/7OY5vijw1XmcheAAOiv6pj7W1FG32kAGqj1C/RK/cqxRGr1Fh+zBi8sDur8kj3EQv6A==} engines: {node: '>=18'} - '@napi-rs/canvas-android-arm64@0.1.100': - resolution: {integrity: sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==} + '@napi-rs/canvas-android-arm64@1.0.0': + resolution: {integrity: sha512-3hNKJObUK7JsCF9aJlVCs1J0/KE/gGfZNeK8MO1ge6bB3aicr5walGme9t9No1f/oyk9GgvdAT/rjSdsx3gbIw==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/canvas-darwin-arm64@0.1.100': - resolution: {integrity: sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==} + '@napi-rs/canvas-darwin-arm64@1.0.0': + resolution: {integrity: sha512-ZIja19/BiGz2puhki+WUYSRriwFeFJ8Mi9eK3hZdSS85w4Y60cuEAJVhMCfKwswQkKkUtrnzdKMBuO7TupvexA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/canvas-darwin-x64@0.1.100': - resolution: {integrity: sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==} + '@napi-rs/canvas-darwin-x64@1.0.0': + resolution: {integrity: sha512-hImggWc82jqZVpEsFR9S7PE9OQYjq/H/D7vwCGB6X1jRH+UVBP1+1niJTPBOat1B154T6GKK7/kcFtoWgjgFzQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.100': - resolution: {integrity: sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==} + '@napi-rs/canvas-linux-arm-gnueabihf@1.0.0': + resolution: {integrity: sha512-hlJRy6d+kWLKVOG/+1rEvNQVURZ0DxxRPJsLmEWwhwiXZUJc0BF5o9esALHSEP4CoJK4wChRtj3hnyBgVx2oWA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/canvas-linux-arm64-gnu@0.1.100': - resolution: {integrity: sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==} + '@napi-rs/canvas-linux-arm64-gnu@1.0.0': + resolution: {integrity: sha512-5Hru4T3RXkosRQafcjelv7AUzw9mXqmGYsxnzeDDOWveFCJyEPMSJltvGCM+jfH98seOCbfwm9KyFg6Jm5FhAA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-arm64-musl@0.1.100': - resolution: {integrity: sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==} + '@napi-rs/canvas-linux-arm64-musl@1.0.0': + resolution: {integrity: sha512-LTUl9jS8WsLSUGaxQZKQkxfluOJRpgvBuxxdM4pYcjib+di8AU4OzQc6+L6SzGMLcKc9H0RAjojRatBhTMqYdg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@napi-rs/canvas-linux-riscv64-gnu@0.1.100': - resolution: {integrity: sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==} + '@napi-rs/canvas-linux-riscv64-gnu@1.0.0': + resolution: {integrity: sha512-Iz931SAZf+WVDzpjk52Q3ffW3zw0YflFwEZMgs036Wfu1kX/LrwT9wGjsuSqyduqefUkl91/vTdAjn8hQu5ezA==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-x64-gnu@0.1.100': - resolution: {integrity: sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==} + '@napi-rs/canvas-linux-x64-gnu@1.0.0': + resolution: {integrity: sha512-pFEQ5eFK4JusgN1K6KkO9DKP/Hi1WMJOkF8Ch03/khTc4bFbCKkCCsJG4YcOMOW9bI4XbT2/eMAWxhO0xaWgPA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-x64-musl@0.1.100': - resolution: {integrity: sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==} + '@napi-rs/canvas-linux-x64-musl@1.0.0': + resolution: {integrity: sha512-jnvr8NrLHiZ3NCiOKWqDbkI4Ah+QDrqtZ+sddPZBltEb1mQ2coSvCSJYfict+oAwcm0c970oTmVySpjKP/lnaA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@napi-rs/canvas-win32-arm64-msvc@0.1.100': - resolution: {integrity: sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==} + '@napi-rs/canvas-win32-arm64-msvc@1.0.0': + resolution: {integrity: sha512-y2j9/Gfd5joqiqxdP/L1smqjQ+uAx3C4N0EC7bDHrnZEEH8ToM/OC5p3uHvtj4Lq591aHj+ArL01UDLNwT5HgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/canvas-win32-x64-msvc@0.1.100': - resolution: {integrity: sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==} + '@napi-rs/canvas-win32-x64-msvc@1.0.0': + resolution: {integrity: sha512-qwdhh9N6Gge/hC4pL9S1tQp0iKwhSl/dYjg7+RGp9k26iRGRi5MqqUyKGOXIWli0zOcuy5Y2wIH/jk2ry6i/jA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/canvas@0.1.100': - resolution: {integrity: sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==} + '@napi-rs/canvas@1.0.0': + resolution: {integrity: sha512-Jqxcy1XOIqj+lH9sl1GT+il6GR3uQv13vI2mrwubP3uT8Olak2ClDrK2RnxlQKjwv8BRr4b3ug0YR7c6hBX8wg==} engines: {node: '>= 10'} '@napi-rs/wasm-runtime@1.1.4': @@ -2777,14 +2732,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@npmcli/agent@4.0.0': - resolution: {integrity: sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==} - engines: {node: ^20.17.0 || >=22.9.0} - - '@npmcli/fs@5.0.0': - resolution: {integrity: sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==} - engines: {node: ^20.17.0 || >=22.9.0} - '@nuxt/opencollective@0.4.1': resolution: {integrity: sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==} engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} @@ -2827,6 +2774,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/core@2.7.1': + resolution: {integrity: sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/instrumentation-amqplib@0.61.0': resolution: {integrity: sha512-mCKoyTGfRNisge4br0NpOFSy2Z1NnEW8hbCJdUDdJFHrPqVzc4IIBPA/vX0U+LUcQqrQvJX+HMIU0dbDRe0i0Q==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2875,12 +2828,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-ioredis@0.62.0': - resolution: {integrity: sha512-ZYt//zcPve8qklaZX+5Z4MkU7UpEkFRrxsf2cnaKYBitqDnsCN69CPAuuMOX6NYdW2rG9sFy7V/QWtBlP5XiNQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-kafkajs@0.23.0': resolution: {integrity: sha512-4K+nVo+zI+aDz0Z85SObwbdixIbzS9moIuKJaYsdlzcHYnKOPtB7ya8r8Ezivy/GVIBHiKJVq4tv+BEkgOMLaQ==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2935,12 +2882,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-redis@0.62.0': - resolution: {integrity: sha512-y3pPpot7WzR/8JtHcYlTYsyY8g+pbFhAqbwAuG5bLPnR6v6pt1rQc0DpH0OlGP/9CZbWBP+Zhwp9yFoygf/ZXQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-tedious@0.33.0': resolution: {integrity: sha512-Q6WQwAD01MMTub31GlejoiFACYNw26J426wyjvU7by7fDIr2nZXNW4vhTGs7i7F0TnXBO3xN688g1tdUgYwJ5w==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2965,18 +2906,14 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/redis-common@0.38.2': - resolution: {integrity: sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA==} - engines: {node: ^18.19.0 || >=20.6.0} - - '@opentelemetry/resources@2.6.1': - resolution: {integrity: sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA==} + '@opentelemetry/resources@2.7.1': + resolution: {integrity: sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-trace-base@2.6.1': - resolution: {integrity: sha512-r86ut4T1e8vNwB35CqCcKd45yzqH6/6Wzvpk2/cZB8PsPLlZFTvrh8yfOS3CYZYcUmAx4hHTZJ8AO8Dj8nrdhw==} + '@opentelemetry/sdk-trace-base@2.7.1': + resolution: {integrity: sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' @@ -2991,139 +2928,142 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 - '@oxc-project/runtime@0.127.0': - resolution: {integrity: sha512-UQYLxAhDDPHm++szfa4z0RTdcPq5vaywrAoEA2n1YaAKeanXQdjHsoT6x1gP3U97RN8LZ7yHsSOrKPCcA6mCqw==} + '@oxc-project/runtime@0.129.0': + resolution: {integrity: sha512-0+S67blQakgeNqoKGozOUp5rQBrz2ynXZ2QIINXZPiafsD0YL0UogB9hAWc1S7k6VSNwKYC/N7MqT0V6IzpHkQ==} engines: {node: ^20.19.0 || >=22.12.0} - '@oxc-project/types@0.124.0': - resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} + '@oxc-project/types@0.128.0': + resolution: {integrity: sha512-huv1Y/LzBJkBVHt3OlC7u0zHBW9qXf1FdD7sGmc1rXc2P1mTwHssYv7jyGx5KAACSCH+9B3Bhn6Z9luHRvf7pQ==} - '@oxc-project/types@0.127.0': - resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} + '@oxc-project/types@0.129.0': + resolution: {integrity: sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==} '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} - '@parcel/watcher-android-arm64@2.5.1': - resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [android] - '@parcel/watcher-darwin-arm64@2.5.1': - resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [darwin] - '@parcel/watcher-darwin-x64@2.5.1': - resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [darwin] - '@parcel/watcher-freebsd-x64@2.5.1': - resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [freebsd] - '@parcel/watcher-linux-arm-glibc@2.5.1': - resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] libc: [glibc] - '@parcel/watcher-linux-arm-musl@2.5.1': - resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] libc: [musl] - '@parcel/watcher-linux-arm64-glibc@2.5.1': - resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@parcel/watcher-linux-arm64-musl@2.5.1': - resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] libc: [musl] - '@parcel/watcher-linux-x64-glibc@2.5.1': - resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] libc: [glibc] - '@parcel/watcher-linux-x64-musl@2.5.1': - resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] libc: [musl] - '@parcel/watcher-win32-arm64@2.5.1': - resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [win32] - '@parcel/watcher-win32-ia32@2.5.1': - resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} engines: {node: '>= 10.0.0'} cpu: [ia32] os: [win32] - '@parcel/watcher-win32-x64@2.5.1': - resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [win32] - '@parcel/watcher@2.5.1': - resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} engines: {node: '>= 10.0.0'} - '@peculiar/asn1-android@2.6.0': - resolution: {integrity: sha512-cBRCKtYPF7vJGN76/yG8VbxRcHLPF3HnkoHhKOZeHpoVtbMYfY9ROKtH3DtYUY9m8uI1Mh47PRhHf2hSK3xcSQ==} + '@peculiar/asn1-android@2.7.0': + resolution: {integrity: sha512-iD3VskhVQnM4nE3PN9cBdPTR7JrqZy3FYk+uD2CeG6DUqKoANqaEfx0f7izPmW+Qm5JBM35ek+viLCmjy18ByQ==} + + '@peculiar/asn1-cms@2.7.0': + resolution: {integrity: sha512-hew63shtzzvBcSHbhm+cyAmKe6AIfinT9hzEqSPjDC6opTTMKmTkQ0gHuN2KsWlvqiKw1S/fS94fhag/FJkioQ==} - '@peculiar/asn1-cms@2.6.0': - resolution: {integrity: sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA==} + '@peculiar/asn1-csr@2.7.0': + resolution: {integrity: sha512-VVsAyGqErT9D1SY4aEqozThXMVI+ssVRiv2DDeYuvpBKLIgZ3hYs3Ay3u/VSoKq6ESFi9cf6rf3IOOzfwh7oMA==} - '@peculiar/asn1-csr@2.6.0': - resolution: {integrity: sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ==} + '@peculiar/asn1-ecc@2.7.0': + resolution: {integrity: sha512-n7KEs/Q/wrB415cxy4fHOBhegp4NdJ15fkJPwcB/3/8iNBQC2L/N7SChJPKDJPZGYH0jD4Tg4/0vnHmwghnbKw==} - '@peculiar/asn1-ecc@2.6.1': - resolution: {integrity: sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==} + '@peculiar/asn1-pfx@2.7.0': + resolution: {integrity: sha512-V/nrlQVmhg7lYAsM7E13UDL5erAwFv6kCIVFqNaMIHSVi7dngcT839JkRTkQBqznMG98l2XjxYk74ZztAohZzA==} - '@peculiar/asn1-pfx@2.6.0': - resolution: {integrity: sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ==} + '@peculiar/asn1-pkcs8@2.7.0': + resolution: {integrity: sha512-9GTl1nE8Mx1kTZ+7QyYatDyKsm34QcWRBFkY1iPvWC3X4Dona5s/tlLiQsx5WzVdZqiMBZNYT0buyw4/vbhnjw==} - '@peculiar/asn1-pkcs8@2.6.0': - resolution: {integrity: sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA==} + '@peculiar/asn1-pkcs9@2.7.0': + resolution: {integrity: sha512-Bh7m+OuIaSEllPQcSd9OSp93F4ROWH7sbITWV8MI+8dwsjE5111/87VxiWVvYFKyww3vp39geLv9ENqhwWHcew==} - '@peculiar/asn1-pkcs9@2.6.0': - resolution: {integrity: sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw==} + '@peculiar/asn1-rsa@2.7.0': + resolution: {integrity: sha512-/qvENQrXyTZURjMqSeofHul0JJt2sNSzSwk36pl2olkHbaioMQgrASDZAlHXl0xUlnVbHj0uGgOrBMTb5x2aJQ==} - '@peculiar/asn1-rsa@2.6.1': - resolution: {integrity: sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==} + '@peculiar/asn1-schema@2.7.0': + resolution: {integrity: sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg==} - '@peculiar/asn1-schema@2.6.0': - resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==} + '@peculiar/asn1-x509-attr@2.7.0': + resolution: {integrity: sha512-NS8e7SOgXipkzUPLF/sce7ukpMpWjhxYsH0n6Y+bHYo4TTxOb95Zv7hqwSuL212mj5YxovjdOKQOgH1As3E94w==} - '@peculiar/asn1-x509-attr@2.6.0': - resolution: {integrity: sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA==} + '@peculiar/asn1-x509@2.7.0': + resolution: {integrity: sha512-mUn9RRrkGDnG4ALfunDmzyRW5dg+sWCj/pfnCCqEHYbkGxEpvUt6iVJv8Yw1cyp6SWZ26ZE5oSmI5SqEaen15g==} - '@peculiar/asn1-x509@2.6.1': - resolution: {integrity: sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==} + '@peculiar/utils@2.0.3': + resolution: {integrity: sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==} '@peculiar/x509@1.14.3': resolution: {integrity: sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==} @@ -3151,8 +3091,8 @@ packages: peerDependencies: ajv: 4.11.8 - 8 - '@readme/openapi-parser@6.0.1': - resolution: {integrity: sha512-uMtwMPVv86Xr5Y6A+QFrxLwWW1irJp3TIz7R3Zs2WaX383MPYX5kaQemPBsaHCu58ZULd+bosNIGUoFW8KM5Ew==} + '@readme/openapi-parser@6.1.1': + resolution: {integrity: sha512-sfCU2LldkkPp2ThlGaTgw0TJCerUd2TF5k1s+jE9KQfuV8DTcroodSNeyy3CzBKtLvDJwf1QV6L1inJBfKRJjA==} engines: {node: '>=20'} peerDependencies: openapi-types: '>=7' @@ -3161,214 +3101,214 @@ packages: resolution: {integrity: sha512-9FC/6ho8uFa8fV50+FPy/ngWN53jaUu4GRXlAjcxIRrzhltJnpKkBG2Tp0IDraFJeWrOpk84RJ9EMEEYzaI1Bw==} engines: {node: '>=18'} - '@redocly/ajv@8.17.1': - resolution: {integrity: sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==} + '@redocly/ajv@8.11.2': + resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} - '@redocly/config@0.22.2': - resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==} + '@redocly/config@0.22.0': + resolution: {integrity: sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==} - '@redocly/openapi-core@1.34.6': - resolution: {integrity: sha512-2+O+riuIUgVSuLl3Lyh5AplWZyVMNuG2F98/o6NrutKJfW4/GTZdPpZlIphS0HGgcOHgmWcCSHj+dWFlZaGSHw==} + '@redocly/openapi-core@1.34.14': + resolution: {integrity: sha512-y+xFx+Zz54Xhr8jUdnLENYnt7Y7GEDL6Q03ga7rTtX8DVwefX9H+hQEPgJp1nda7vdH+wJ9/HBVvyfBuW9x6rA==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} - '@rolldown/binding-android-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==} + '@rolldown/binding-android-arm64@1.0.0': + resolution: {integrity: sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-android-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} + '@rolldown/binding-android-arm64@1.0.0-rc.18': + resolution: {integrity: sha512-lIDyUAfD7U3+BWKzdxMbJcsYHuqXqmGz40aeRqvuAm3y5TkJSYTBW2RDrn65DJFPQqVjUAUqq5uz8urzQ8aBdQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==} + '@rolldown/binding-darwin-arm64@1.0.0': + resolution: {integrity: sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.18': + resolution: {integrity: sha512-apJq2ktnGp27nSInMR5Vcj8kY6xJzDAvfdIFlpDcAK/w4cDO58qVoi1YQsES/SKiFNge/6e4CUzgjfHduYqWpQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.15': - resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==} + '@rolldown/binding-darwin-x64@1.0.0': + resolution: {integrity: sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.17': - resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} + '@rolldown/binding-darwin-x64@1.0.0-rc.18': + resolution: {integrity: sha512-5Ofot8xbs+pxRHJqm9/9N/4sTQOvdrwEsmPE9pdLEEoAbdZtG6F2LMDfO1sp6ZAtXJuJV/21ew2srq3W8NXB5g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': - resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==} + '@rolldown/binding-freebsd-x64@1.0.0': + resolution: {integrity: sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': - resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.18': + resolution: {integrity: sha512-7h8eeOTT1eyqJyx64BFCnWZpNm486hGWt2sqeLLgDxA0xI1oGZ9H7gK1S85uNGmBhkdPwa/6reTxfFFKvIsebw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': - resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0': + resolution: {integrity: sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': - resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.18': + resolution: {integrity: sha512-eRcm/HVt9U/JFu5RKAEKwGQYtDCKWLiaH6wOnsSEp6NMBb/3Os8LgHZlNyzMpFVNmiiMFlfb2zEnebfzJrHFmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==} + '@rolldown/binding-linux-arm64-gnu@1.0.0': + resolution: {integrity: sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.18': + resolution: {integrity: sha512-SOrT/cT4ukTmgnrEz/Hg3m7LBnuCLW9psDeMKrimRWY4I8DmnO7Lco8W2vtqPmMkbVu8iJ+g4GFLVLLOVjJ9DQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==} + '@rolldown/binding-linux-arm64-musl@1.0.0': + resolution: {integrity: sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': - resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.18': + resolution: {integrity: sha512-QWjdxN1HJCpBTAcZ5N5F7wju3gVPzRzSpmGzx7na0c/1qpN9CFil+xt+l9lV/1M6/gqHSNXCiqPfwhVJPeLnug==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0': + resolution: {integrity: sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.18': + resolution: {integrity: sha512-ugCOyj7a4d9h3q9B+wXmf6g3a68UsjGh6dob5DHevHGMwDUbhsYNbSPxJsENcIttJZ9jv7qGM2UesLw5jqIhdg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==} + '@rolldown/binding-linux-s390x-gnu@1.0.0': + resolution: {integrity: sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.18': + resolution: {integrity: sha512-kKWRhbsotpXkGbcd5dllUWg5gEXcDAa8u5YnP9AV5DYNbvJHGzzuwv7dpmhc8NqKMJldl0a+x76IHbspEpEmdA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==} + '@rolldown/binding-linux-x64-gnu@1.0.0': + resolution: {integrity: sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.18': + resolution: {integrity: sha512-uCo8ElcCIAMyYAZyuIZ81oFkhTSIllNvUCHCAlbhlN4ji3uC28h7IIdlXyIvGO7HsuqnV9p3rD/bpH7XhIyhRw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==} + '@rolldown/binding-linux-x64-musl@1.0.0': + resolution: {integrity: sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': - resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.18': + resolution: {integrity: sha512-XNOQZtuE6yUIvx4rwGemwh8kpL1xvU41FXy/s9K7T/3JVcqGzo3NfKM2HrbrGgfPYGFW42f07Wk++aOC6B9NWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==} + '@rolldown/binding-openharmony-arm64@1.0.0': + resolution: {integrity: sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.18': + resolution: {integrity: sha512-tSn/kzrfa7tNOXr7sEacDBN4YsIqTyLqh45IO0nHDwtpKIDNDJr+VFojt+4klSpChxB29JLyduSsE0MKEwa65A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': - resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==} - engines: {node: '>=14.0.0'} + '@rolldown/binding-wasm32-wasi@1.0.0': + resolution: {integrity: sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': - resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.18': + resolution: {integrity: sha512-+J9YGmc+czgqlhYmwun3S3O0FIZhsH8ep2456xwjAdIOmuJxM7xz4P4PtrxU+Bz17a/5bqPA8o3HAAoX0teUdg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==} + '@rolldown/binding-win32-arm64-msvc@1.0.0': + resolution: {integrity: sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': - resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.18': + resolution: {integrity: sha512-zsu47DgU0FQzSwi6sU9dZoEdUv7pc1AptSEz/Z8HBg54sV0Pbs3N0+CrIbTsgiu6EyoaNN9CHboqbLaz9lhOyQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==} + '@rolldown/binding-win32-x64-msvc@1.0.0': + resolution: {integrity: sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': - resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.18': + resolution: {integrity: sha512-7H+3yqGgmnlDTRRhw/xpYY9J1kf4GC681nVc4GqKhExZTDrVVrV2tsOR9kso0fvgBdcTCcQShx4SLLoHgaLwhg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@rolldown/pluginutils@1.0.0': + resolution: {integrity: sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==} + '@rolldown/pluginutils@1.0.0-rc.13': resolution: {integrity: sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==} - '@rolldown/pluginutils@1.0.0-rc.15': - resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} - - '@rolldown/pluginutils@1.0.0-rc.17': - resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} + '@rolldown/pluginutils@1.0.0-rc.18': + resolution: {integrity: sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==} '@rollup/plugin-esm-shim@0.1.8': resolution: {integrity: sha512-xEU0b/BShgDDSPjidhJd4R74J9xZ9jLVtFWNGtsUXyEsdwwwB1a3XOAwwGaNIyUHD6EhxPO21JMfUmJWoMn7SA==} @@ -3397,141 +3337,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.60.2': - resolution: {integrity: sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==} + '@rollup/rollup-android-arm-eabi@4.60.3': + resolution: {integrity: sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.2': - resolution: {integrity: sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==} + '@rollup/rollup-android-arm64@4.60.3': + resolution: {integrity: sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.2': - resolution: {integrity: sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==} + '@rollup/rollup-darwin-arm64@4.60.3': + resolution: {integrity: sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.2': - resolution: {integrity: sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==} + '@rollup/rollup-darwin-x64@4.60.3': + resolution: {integrity: sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.2': - resolution: {integrity: sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==} + '@rollup/rollup-freebsd-arm64@4.60.3': + resolution: {integrity: sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.2': - resolution: {integrity: sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==} + '@rollup/rollup-freebsd-x64@4.60.3': + resolution: {integrity: sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.2': - resolution: {integrity: sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.2': - resolution: {integrity: sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==} + '@rollup/rollup-linux-arm-musleabihf@4.60.3': + resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.2': - resolution: {integrity: sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==} + '@rollup/rollup-linux-arm64-gnu@4.60.3': + resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.2': - resolution: {integrity: sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==} + '@rollup/rollup-linux-arm64-musl@4.60.3': + resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.2': - resolution: {integrity: sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==} + '@rollup/rollup-linux-loong64-gnu@4.60.3': + resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.2': - resolution: {integrity: sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==} + '@rollup/rollup-linux-loong64-musl@4.60.3': + resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.2': - resolution: {integrity: sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==} + '@rollup/rollup-linux-ppc64-gnu@4.60.3': + resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.2': - resolution: {integrity: sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==} + '@rollup/rollup-linux-ppc64-musl@4.60.3': + resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.2': - resolution: {integrity: sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==} + '@rollup/rollup-linux-riscv64-gnu@4.60.3': + resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.2': - resolution: {integrity: sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==} + '@rollup/rollup-linux-riscv64-musl@4.60.3': + resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.2': - resolution: {integrity: sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==} + '@rollup/rollup-linux-s390x-gnu@4.60.3': + resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.2': - resolution: {integrity: sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==} + '@rollup/rollup-linux-x64-gnu@4.60.3': + resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.2': - resolution: {integrity: sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==} + '@rollup/rollup-linux-x64-musl@4.60.3': + resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.2': - resolution: {integrity: sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==} + '@rollup/rollup-openbsd-x64@4.60.3': + resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.60.2': - resolution: {integrity: sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==} + '@rollup/rollup-openharmony-arm64@4.60.3': + resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.60.2': - resolution: {integrity: sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==} + '@rollup/rollup-win32-arm64-msvc@4.60.3': + resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.2': - resolution: {integrity: sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==} + '@rollup/rollup-win32-ia32-msvc@4.60.3': + resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.2': - resolution: {integrity: sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==} + '@rollup/rollup-win32-x64-gnu@4.60.3': + resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.60.2': - resolution: {integrity: sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==} + '@rollup/rollup-win32-x64-msvc@4.60.3': + resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} cpu: [x64] os: [win32] @@ -3571,36 +3511,36 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@sentry-internal/browser-utils@10.50.0': - resolution: {integrity: sha512-42bxyRTxnCmYlWnvz4CxikuQNanw8UNma2WJrtxJ0f1MAJV2GhQGSHDLnA+lvFlmiz6qct3pfen/NXGyOTegTA==} + '@sentry-internal/browser-utils@10.52.0': + resolution: {integrity: sha512-x/yEPZdpH6NGQeoeQnV9tj8reAH8twNttiltGZl2o8Rk7sQeUfe7E8yuYP2XbJ2RqyZK5qRS3COrNyMPzf6KFA==} engines: {node: '>=18'} - '@sentry-internal/feedback@10.50.0': - resolution: {integrity: sha512-0k9XZF0wn86f77mIO2U3gNNyDZooy139CnEanRzHinrN106vVzvBZ6TUEQoHtoO1fqQxr+nWWVrqV/PXUqk47w==} + '@sentry-internal/feedback@10.52.0': + resolution: {integrity: sha512-5kAn1W8ZvCuHtEHXpq6iRkUMdNCilwww+YxaN2yofVrCivAbB3Ha5JJUMqmWOPW0pC27zGYmoJMIDvG+PczUxA==} engines: {node: '>=18'} - '@sentry-internal/node-cpu-profiler@2.2.0': - resolution: {integrity: sha512-oLHVYurqZfADPh5hvmQYS5qx8t0UZzT2u6+/68VXsFruQEOnYJTODKgU3BVLmemRs3WE6kCJjPeFdHVYOQGSzQ==} + '@sentry-internal/node-cpu-profiler@2.3.0': + resolution: {integrity: sha512-kwmgzQjo3nt+td1QGjmb62j8WC/QJmo+G3o1xIDPaKGUBjct2S/TZKoZdDca8SRlZ5NJAaGXkHSSr3cOA9glrg==} engines: {node: '>=18'} - '@sentry-internal/replay-canvas@10.50.0': - resolution: {integrity: sha512-jx6RKBmcJSWdI92qDGS/sBv1w+7Cww879Z/moX7bw7ipHa/Ts3iDcB3rgZwvhmi17U+mvYsbJeL2DXkPo3TjPw==} + '@sentry-internal/replay-canvas@10.52.0': + resolution: {integrity: sha512-BI5ie4dxPuUJ344CXVSnAxY1xZCbghglPSCIlTOYODpR9so9yo5IZh+Mwspt0oWsUMaxWJiQSNYlbPWi7WDavg==} engines: {node: '>=18'} - '@sentry-internal/replay@10.50.0': - resolution: {integrity: sha512-51FYNfnvVLAWw1rrEWPFfwHuMRb9mkVCFGA4J9/un7SpeGBsQDziGB0Di4fsCxI7+EdSBpfLHPF0csKtCCw0oQ==} + '@sentry-internal/replay@10.52.0': + resolution: {integrity: sha512-diywyuc/H7VTUR+W5ryVmLF+0X4UP1OskMqb6V8RSAvJHcj2JmIm7uP+Fc6ACTno+b6AUShwT/L4xVXzO6X9Cw==} engines: {node: '>=18'} - '@sentry/browser@10.50.0': - resolution: {integrity: sha512-1f6rAvET6myiTaSeYqvaaBwvq1LfxqWjAPIoAW/NVC9bPMkeEcuvgDajHrnZMrBeWoJ81NMyoLkyX+iOc7MoFA==} + '@sentry/browser@10.52.0': + resolution: {integrity: sha512-ijL9jN86oXwXQWbwhPlEb70ODJSEmjxQEQdnZkC4gDWbjswcwvRsVJPYk+1xl2ir2iZixRIHipVxDcLwian35g==} engines: {node: '>=18'} - '@sentry/core@10.50.0': - resolution: {integrity: sha512-J4A+vzUO3adl0TkFCjaN1+4miamrjHiEIYuLHiuu1lmAjq5WIVw32ObvAh4yMwNtxyaEMosTrrh5M6f12XSJFg==} + '@sentry/core@10.52.0': + resolution: {integrity: sha512-VA/kAqLhkMnRWY2RXdBLyTemR9D4m7MVRy/gyapoq9yvllVPx9WXbvKgnMP2LQp7mFgT/oLFvw58aQKaYTGn3A==} engines: {node: '>=18'} - '@sentry/node-core@10.50.0': - resolution: {integrity: sha512-Eb1BYf4Lc7ZYmdX3acKP6SgyGikrBA370gbGHaWI5jRu7G7vig8sIu1ghPmY5AlvqBPOetado7GniXr6fAXbTw==} + '@sentry/node-core@10.52.0': + resolution: {integrity: sha512-IG7MBtLRPQ2LuU+kbD14AFZroZgAeUmJQTP1FI/F8n56O31+p+9R703LuBTpvZr6sm+eRYDMWcGYYkfLHRVjwg==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3623,12 +3563,12 @@ packages: '@opentelemetry/semantic-conventions': optional: true - '@sentry/node@10.50.0': - resolution: {integrity: sha512-TvwzFQu8MGKzMQ2/tqxcNzFA8UG2kKTB+GDmA4uOzx3+GT849YZRRSJzEXCmYhk1teVd2fbmgqyYY2nyLF5a+Q==} + '@sentry/node@10.52.0': + resolution: {integrity: sha512-9+p3KJUk3rHO1HOEZuSknP2RgKCJZONDm4HWgkVDtVBtocb66KLtVlMjc59d2/bWP7tM3wc877tpG30quFfU9g==} engines: {node: '>=18'} - '@sentry/opentelemetry@10.50.0': - resolution: {integrity: sha512-axn3pgDPveGdaMUC0abMCmFN7ux2pA5ebPufCef4lMIsyg7BBQvaEJ+vE19wjstMaBCAJGsdZlL3eeP2rtgRMw==} + '@sentry/opentelemetry@10.52.0': + resolution: {integrity: sha512-Sc7StsvC0bwhMcgDfTRWUIexO5cNzzKUurvUwtpgQUnxO7AzexU3lkY3yHYDsCbWYAEQMXAgQYQtbcqoh+Ie7g==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3636,13 +3576,13 @@ packages: '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 '@opentelemetry/semantic-conventions': ^1.39.0 - '@sentry/profiling-node@10.50.0': - resolution: {integrity: sha512-fKavmoOJdst07/Mf8Zvz8QEbn8RDM10I1tdwSTmC8n77zm5IEQll7eYHP8e77VWuXHXggfVn5WNQfG2uDrECaA==} + '@sentry/profiling-node@10.52.0': + resolution: {integrity: sha512-1vTrELjKsRB0O/1WIrbj5zjChKwYSJ1rHU/4ZrCQPeMioJaqAJP2Hzy81TS6RVR78pXswQj+z2+PF4uOjb9Mlg==} engines: {node: '>=18'} hasBin: true - '@sentry/vue@10.50.0': - resolution: {integrity: sha512-xo2Nq+74KRh3OuZBVnejDiRZaqbnuUKUi6h2hRefFLnbsN3aU76NR0CekWzaabpczWvQRhLn7DC0s0m+pXeDAQ==} + '@sentry/vue@10.52.0': + resolution: {integrity: sha512-6MHYKXGQz39yFJ27HzNYGWJtmwDhEwp7EvCm6cJPBlXQNbYOoNTDrzq4TuI0cLJzyAW7mIQ+k4n4iMpa6EbfaA==} engines: {node: '>=18'} peerDependencies: '@tanstack/vue-router': ^1.64.0 @@ -3701,8 +3641,8 @@ packages: resolution: {integrity: sha512-MLHYFrYG8/wK2i+86XMhiecK72nMaHKKt4bo+7Q1TbuG9iGjlSdfkPWKO5ZFE/BX+ygCJ7pr8H/AJeyAj1EaTQ==} engines: {node: '>=20.0.0'} - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} '@sindresorhus/is@8.0.0': resolution: {integrity: sha512-YvOsokBE5NsyHuXMnwEVB7lgFk6lX8F4OXCruYVgFII0hUHof0RGUvhMoabVt9hRqbg+qVzayzEG24RCcxcYeA==} @@ -3718,21 +3658,12 @@ packages: '@sinonjs/fake-timers@11.2.2': resolution: {integrity: sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==} - '@sinonjs/fake-timers@13.0.5': - resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} - - '@sinonjs/fake-timers@15.3.2': - resolution: {integrity: sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==} + '@sinonjs/fake-timers@15.4.0': + resolution: {integrity: sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==} '@sinonjs/samsam@8.0.3': resolution: {integrity: sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==} - '@sinonjs/text-encoding@0.7.3': - resolution: {integrity: sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==} - deprecated: |- - Deprecated: no longer maintained and no longer used by Sinon packages. See - https://github.com/sinonjs/nise/issues/243 for replacement details. - '@smithy/chunked-blob-reader-native@4.2.3': resolution: {integrity: sha512-jA5k5Udn7Y5717L86h4EIv06wIr3xn8GM1qHRi/Nf31annXcXHJjBKvgztnbn2TxH3xWrPBfgwHsOwZf0UmQWw==} engines: {node: '>=18.0.0'} @@ -3813,8 +3744,8 @@ packages: resolution: {integrity: sha512-ZZkgyjnJppiZbIm6Qbx92pbXYi1uzenIvGhBSCDlc7NwuAkiqSgS75j1czAD25ZLs2FjMjYy1q7gyRVWG6JA0Q==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.5.5': - resolution: {integrity: sha512-wnYOpB5vATFKWrY2Z9Alb0KhjZI6AbzU6Fbz3Hq2GnURdRYWB4q+qWivQtSTwXcmWUA3MZ6krfwL6Cq5MAbxsA==} + '@smithy/middleware-retry@4.5.7': + resolution: {integrity: sha512-bRt6ZImqVSeTk39Nm81K20ObIiAZ3WefY7G6+iz/0tZjs4dgRRjvRX2sgsH+zi6iDCRR/aQvQofLKxxz4rPBZg==} engines: {node: '>=18.0.0'} '@smithy/middleware-serde@4.2.20': @@ -3849,8 +3780,8 @@ packages: resolution: {integrity: sha512-hr+YyqBD23GVvRxGGrcc/oOeNlK3PzT5Fu4dzrDXxzS1LpFiuL2PQQqKPs87M79aW7ziMs+nvB3qdw77SqE7Lw==} engines: {node: '>=18.0.0'} - '@smithy/service-error-classification@4.3.0': - resolution: {integrity: sha512-9jKsBYQRPR0xBLgc2415RsA5PIcP2sis4oBdN9s0D13cg1B1284mNTjx9Yc+BEERXzuPm5ObktI96OxsKh8E9A==} + '@smithy/service-error-classification@4.3.1': + resolution: {integrity: sha512-aUQuDGh760ts/8MU+APjIZhlLPKhIIfqyzZaJikLEIMrdxFvxuLYD0WxWzaYWpmLbQlXDe9p7EWM3HsBe0K6Gw==} engines: {node: '>=18.0.0'} '@smithy/shared-ini-file-loader@4.4.9': @@ -3917,8 +3848,8 @@ packages: resolution: {integrity: sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw==} engines: {node: '>=18.0.0'} - '@smithy/util-retry@4.3.4': - resolution: {integrity: sha512-FY1UQQ1VFmMwiYp1GVS4MeaGD5O0blLNYK0xCRHU+mJgeoH/hSY8Ld8sJWKQ6uznkh14HveRGQJncgPyNl9J+A==} + '@smithy/util-retry@4.3.8': + resolution: {integrity: sha512-LUIxbTBi+OpvXpg91poGA6BdyoleMDLnfXjVDqyi2RvZmTveY5loE/FgYUBCR5LU2BThW2SoZRh8dTIIy38IPw==} engines: {node: '>=18.0.0'} '@smithy/util-stream@4.5.25': @@ -3937,8 +3868,8 @@ packages: resolution: {integrity: sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==} engines: {node: '>=18.0.0'} - '@smithy/util-waiter@4.2.16': - resolution: {integrity: sha512-GtclrKoZ3Lt7jPQ7aTIYKfjY92OgceScftVnkTsG8e1KV8rkvZgN+ny6YSRhd9hxB8rZtwVbmln7NTvE5O3GmQ==} + '@smithy/util-waiter@4.3.0': + resolution: {integrity: sha512-JyjYmLAfS+pdxF92o4yLgEoy0zhayKTw73FU1aofLWwLcJw7iSqIY2exGmMTrl/lmZugP5p/zxdFSippJDfKWA==} engines: {node: '>=18.0.0'} '@smithy/uuid@1.1.2': @@ -3986,11 +3917,11 @@ packages: peerDependencies: storybook: ^8.6.18 - '@storybook/addon-links@10.3.5': - resolution: {integrity: sha512-Xe2wCGZ+hpZ0cDqAIBHk+kPc8nODNbu585ghd5bLrlYJMDVXoNM/fIlkrLgjIDVbfpgeJLUEg7vldJrn+FyOLw==} + '@storybook/addon-links@10.3.6': + resolution: {integrity: sha512-tv9Xd68qRGBAvEubaxNo3FuFq4GwuMiBriD+gLGuFK0+/u3cnkuA264aoR1v6YCH3sT3er3+MBimuyKM3jLDxg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.3.5 + storybook: ^10.3.6 peerDependenciesMeta: react: optional: true @@ -4037,10 +3968,10 @@ packages: react-dom: optional: true - '@storybook/builder-vite@10.3.5': - resolution: {integrity: sha512-i4KwCOKbhtlbQIbhm53+Kk7bMnxa0cwTn1pxmtA/x5wm1Qu7FrrBQV0V0DNjkUqzcSKo1CjspASJV/HlY0zYlw==} + '@storybook/builder-vite@10.3.6': + resolution: {integrity: sha512-gpvR/sE4BcrFtmQZ+Ker7zD23oQzoVeqD9nF6cK6yzY+Q0svJXyX2EPmFG4y+EwygD5/vNzDpP84gGMut8VRwg==} peerDependencies: - storybook: ^10.3.5 + storybook: ^10.3.6 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 '@storybook/components@8.6.18': @@ -4053,12 +3984,12 @@ packages: peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/csf-plugin@10.3.5': - resolution: {integrity: sha512-qlEzNKxOjq86pvrbuMwiGD/bylnsXk1dg7ve0j77YFjEEchqtl7qTlrXvFdNaLA89GhW6D/EV6eOCu/eobPDgw==} + '@storybook/csf-plugin@10.3.6': + resolution: {integrity: sha512-9kBf7VRdRqTSIYo+rPtVn5yjYYyK8kP2QhEYx3oiXvfwy4RexmbJnhk/tXa/lNiTqukA1TqaWQ2+5MqF4fu6YQ==} peerDependencies: esbuild: '*' rollup: '*' - storybook: ^10.3.5 + storybook: ^10.3.6 vite: '*' webpack: '*' peerDependenciesMeta: @@ -4086,8 +4017,8 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - '@storybook/icons@2.0.1': - resolution: {integrity: sha512-/smVjw88yK3CKsiuR71vNgWQ9+NuY2L+e8X7IMrFjexjm6ZR8ULrV2DRkTA61aV6ryefslzHEGDInGpnNeIocg==} + '@storybook/icons@2.0.2': + resolution: {integrity: sha512-KZBCpXsshAIjczYNXR/rlxEtCUX/eAbpFNwKi8bcOomrLA4t/SyPz5RF+lVPO2oZBUE4sAkt43mfJUevQDSEEw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -4107,12 +4038,12 @@ packages: peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/react-dom-shim@10.3.5': - resolution: {integrity: sha512-Gw8R7XZm0zSUH0XAuxlQJhmizsLzyD6x00KOlP6l7oW9eQHXGfxg3seNDG3WrSAcW07iP1/P422kuiriQlOv7g==} + '@storybook/react-dom-shim@10.3.6': + resolution: {integrity: sha512-/Tu1gPu+Fw+zOnAGmxRmOD30FX3a04LxcTAKflEtdpmtIMVR5bA3qpjy+f5YhoyDCecbXyKmL1OeIU2FIIZHqQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.3.5 + storybook: ^10.3.6 '@storybook/react-dom-shim@8.6.18': resolution: {integrity: sha512-N4xULcAWZQTUv4jy1/d346Tyb4gufuC3UaLCuU/iVSZ1brYF4OW3ANr+096btbMxY8pR/65lmtoqr5CTGwnBvA==} @@ -4121,20 +4052,20 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta storybook: ^8.6.18 - '@storybook/react-vite@10.3.5': - resolution: {integrity: sha512-UB5sJHeh26bfd8sNMx2YPGYRYmErIdTRaLOT28m4bykQIa1l9IgVktsYg/geW7KsJU0lXd3oTbnUjLD+enpi3w==} + '@storybook/react-vite@10.3.6': + resolution: {integrity: sha512-tySQRc+8q7V2NkylQMNJjDV8zXy6tkxb8oDqw/DIhHhI9Xn77MTKVZ8Cihbo5NMm7HYTB6xDKr6wqdSMgdufYQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.3.5 + storybook: ^10.3.6 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/react@10.3.5': - resolution: {integrity: sha512-tpLTLaVGoA6fLK3ReyGzZUricq7lyPaV2hLPpj5wqdXLV/LpRtAHClUpNoPDYSBjlnSjL81hMZijbkGC3mA+gw==} + '@storybook/react@10.3.6': + resolution: {integrity: sha512-oZQZ6xayWe5IdHmFUTL0TL8rX/gpNNh9gWhT2vzW5eeUvlkVG/RBKdsja6Ndrk2s1D9vcnwiI6r6CNXy3IEEmg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.3.5 + storybook: ^10.3.6 typescript: '>= 4.9.x' peerDependenciesMeta: typescript: @@ -4160,23 +4091,23 @@ packages: peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/vue3-vite@10.3.5': - resolution: {integrity: sha512-9a0FDU9lsGDxnTQoDna9fmRx6+tUvnimb61bAcfZeigGyx127qT9rylvSC3WVKTBiQ/o4Dg76v44HIv+ew/DsQ==} + '@storybook/vue3-vite@10.3.6': + resolution: {integrity: sha512-49rwk3jRU3j0rjtuSVIIMUhv+6iPvW8v9LKVI3XVVU4//RkZjGa6FA/hMVTmtMzU1yOtlDGYB6Ku9PvOTG56nA==} peerDependencies: - storybook: ^10.3.5 + storybook: ^10.3.6 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/vue3@10.3.5': - resolution: {integrity: sha512-PxgnIlem+w0iCxf+YBMPm7T/v75ax1fzqkrVA3C1c/UQ8pckmJxx7Gfs+84GnPWA6Q4G1F2mJ2FsWWneivkQ1g==} + '@storybook/vue3@10.3.6': + resolution: {integrity: sha512-QXBq+l8h9DkrDxMKLkHp/1rGrFi3jGzng5YOsWmUfiJFNe0Nbj8ezGODr4Lgcc4SK8G3eBk/QRfBflmIcf+2gw==} peerDependencies: - storybook: ^10.3.5 + storybook: ^10.3.6 vue: ^3.0.0 - '@stylistic/eslint-plugin@5.5.0': - resolution: {integrity: sha512-IeZF+8H0ns6prg4VrkhgL+yrvDXWDH2cKchrbh80ejG9dQgZWp10epHMbgRuQvgchLII/lfh6Xn3lu6+6L86Hw==} + '@stylistic/eslint-plugin@5.10.0': + resolution: {integrity: sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: '>=9.0.0' + eslint: ^9.0.0 || ^10.0.0 '@syuilo/aiscript@0.19.0': resolution: {integrity: sha512-ZWG4s1m6RrFjE7NeIMaxFz769YO1jW5ReTrOROrEO4IHheOrjxxJ/Ffe2TUNqX9/XxDloMwfWplKhfSzx8LGMA==} @@ -4279,8 +4210,8 @@ packages: resolution: {integrity: sha512-JSSdNiS0wgd8GHhBwnMAI18Y8XPhLVN+dNelPfZCXFhy9Lb3NbnFyp9JKxxr54jSUkEJPk3cidvCoHducSaRMQ==} engines: {node: '>=14.17'} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} '@types/accepts@1.3.7': resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} @@ -4331,8 +4262,8 @@ packages: '@types/cookiejar@2.1.5': resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -4352,14 +4283,20 @@ packages: '@types/eslint@7.29.0': resolution: {integrity: sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/express-serve-static-core@5.1.0': - resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/express-serve-static-core@5.1.1': + resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} - '@types/express@5.0.4': - resolution: {integrity: sha512-g64dbryHk7loCIrsa0R3shBnEu5p6LPJ09bu9NG58+jz+cRUjFrc3Bz0kNQ7j9bXeCsrRDvNET1G54P/GJkAyA==} + '@types/express@5.0.6': + resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} '@types/fluent-ffmpeg@2.1.28': resolution: {integrity: sha512-5ovxsDwBcPfJ+eYs1I/ZpcYCnkce7pvH9AHSvrZllAp1ZPpTRDZAFjF3TRFbukxSgIYTTNYePbS0rKUmaxVbXw==} @@ -4370,8 +4307,8 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - '@types/http-cache-semantics@4.0.4': - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + '@types/http-cache-semantics@4.2.0': + resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} @@ -4415,9 +4352,6 @@ packages: '@types/mime-types@3.0.1': resolution: {integrity: sha512-xRMsfuQbnRq1Ef+C+RKaENOxXX87Ygl38W1vDfPHRku02TgQr+Qd8iivLtAMcR0KF5/29xlnFihkTlbqFrGOVQ==} - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - '@types/minimist@1.2.5': resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} @@ -4466,8 +4400,8 @@ packages: '@types/qrcode@1.5.6': resolution: {integrity: sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==} - '@types/qs@6.14.0': - resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + '@types/qs@6.15.1': + resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} '@types/random-seed@0.3.5': resolution: {integrity: sha512-CftxcDPAHgs0SLHU2dt+ZlDPJfGqLW3sZlC/ATr5vJDSe5tRLeOne7HMvCOJnFyF8e1U41wqzs3h6AMC613xtA==} @@ -4478,8 +4412,8 @@ packages: '@types/ratelimiter@3.4.6': resolution: {integrity: sha512-Bv6WLSXPGLVsBjkizXtn+ef78R92e36/DFQo2wXPTHtp1cYXF6rCULMqf9WcZPAtyMZMvQAtIPeYMA1xAyxghw==} - '@types/react@19.2.2': - resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} '@types/readdir-glob@1.1.5': resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} @@ -4502,14 +4436,11 @@ packages: '@types/semver@7.7.1': resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} - '@types/send@0.17.6': - resolution: {integrity: sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==} - '@types/send@1.2.1': resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} - '@types/serve-static@1.15.10': - resolution: {integrity: sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==} + '@types/serve-static@2.2.0': + resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} '@types/serviceworker@0.0.74': resolution: {integrity: sha512-HNt7NJHrjGtCmI3h1+rsb1g/ZY0iy5KaeenfEV7zAWPSaCs49hEUvgH++V1BHNwlLfB3sbjPh3pSiNixfYjb1w==} @@ -4580,63 +4511,63 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.59.0': - resolution: {integrity: sha512-HyAZtpdkgZwpq8Sz3FSUvCR4c+ScbuWa9AksK2Jweub7w4M3yTz4O11AqVJzLYjy/B9ZWPyc81I+mOdJU/bDQw==} + '@typescript-eslint/eslint-plugin@8.59.2': + resolution: {integrity: sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.59.0 + '@typescript-eslint/parser': ^8.59.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.59.0': - resolution: {integrity: sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg==} + '@typescript-eslint/parser@8.59.2': + resolution: {integrity: sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.59.0': - resolution: {integrity: sha512-Lw5ITrR5s5TbC19YSvlr63ZfLaJoU6vtKTHyB0GQOpX0W7d5/Ir6vUahWi/8Sps/nOukZQ0IB3SmlxZnjaKVnw==} + '@typescript-eslint/project-service@8.59.2': + resolution: {integrity: sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.59.0': - resolution: {integrity: sha512-UzR16Ut8IpA3Mc4DbgAShlPPkVm8xXMWafXxB0BocaVRHs8ZGakAxGRskF7FId3sdk9lgGD73GSFaWmWFDE4dg==} + '@typescript-eslint/scope-manager@8.59.2': + resolution: {integrity: sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.59.0': - resolution: {integrity: sha512-91Sbl3s4Kb3SybliIY6muFBmHVv+pYXfybC4Oolp3dvk8BvIE3wOPc+403CWIT7mJNkfQRGtdqghzs2+Z91Tqg==} + '@typescript-eslint/tsconfig-utils@8.59.2': + resolution: {integrity: sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.59.0': - resolution: {integrity: sha512-3TRiZaQSltGqGeNrJzzr1+8YcEobKH9rHnqIp/1psfKFmhRQDNMGP5hBufanYTGznwShzVLs3Mz+gDN7HkWfXg==} + '@typescript-eslint/type-utils@8.59.2': + resolution: {integrity: sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.59.0': - resolution: {integrity: sha512-nLzdsT1gdOgFxxxwrlNVUBzSNBEEHJ86bblmk4QAS6stfig7rcJzWKqCyxFy3YRRHXDWEkb2NralA1nOYkkm/A==} + '@typescript-eslint/types@8.59.2': + resolution: {integrity: sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.59.0': - resolution: {integrity: sha512-O9Re9P1BmBLFJyikRbQpLku/QA3/AueZNO9WePLBwQrvkixTmDe8u76B6CYUAITRl/rHawggEqUGn5QIkVRLMw==} + '@typescript-eslint/typescript-estree@8.59.2': + resolution: {integrity: sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.59.0': - resolution: {integrity: sha512-I1R/K7V07XsMJ12Oaxg/O9GfrysGTmCRhvZJBv0RE0NcULMzjqVpR5kRRQjHsz3J/bElU7HwCO7zkqL+MSUz+g==} + '@typescript-eslint/utils@8.59.2': + resolution: {integrity: sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.59.0': - resolution: {integrity: sha512-/uejZt4dSere1bx12WLlPfv8GktzcaDtuJ7s42/HEZ5zGj9oxRaD4bj7qwSunXkf+pbAhFt2zjpHYUiT5lHf0Q==} + '@typescript-eslint/visitor-keys@8.59.2': + resolution: {integrity: sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260426.1': @@ -4686,9 +4617,8 @@ packages: engines: {node: '>=16.20.0'} hasBin: true - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - deprecated: Potential CWE-502 - Update to 1.3.1 or higher + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} '@vitejs/plugin-vue@6.0.6': resolution: {integrity: sha512-u9HHgfrq3AjXlysn0eINFnWQOJQLO9WN6VprZ8FXl7A2bYisv3Hui9Ij+7QZ41F/WYWarHjwBbXtD7dKg3uxbg==} @@ -4783,17 +4713,17 @@ packages: '@volar/typescript@2.4.28': resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} - '@vue/compiler-core@3.5.33': - resolution: {integrity: sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==} + '@vue/compiler-core@3.5.34': + resolution: {integrity: sha512-s9cLyK5mLcvZ4Agva5QgRsQyLKvts9WbU9DB6NqiZkkGEdwmcEiylj5Jbwkp680drF/NNCV8OlAJSe+yMLxaJw==} - '@vue/compiler-dom@3.5.33': - resolution: {integrity: sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==} + '@vue/compiler-dom@3.5.34': + resolution: {integrity: sha512-EbF/T++k0e2MMZlJsBhzK8Sgwt0HcIPOhzn1CTB/lv6sQcyk+OWf8YeiLxZp3ro7MbbLcAfAJ6sEvjFWuNgUCw==} - '@vue/compiler-sfc@3.5.33': - resolution: {integrity: sha512-UTUvRO9cY+rROrx/pvN9P5Z7FgA6QGfokUCfhQE4EnmUj3rVnK+CHI0LsEO1pg+I7//iRYMUfcNcCPe7tg0CoA==} + '@vue/compiler-sfc@3.5.34': + resolution: {integrity: sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg==} - '@vue/compiler-ssr@3.5.33': - resolution: {integrity: sha512-IErjYdnj1qIupG5xxiVIYiiRvDhGWV4zuh/RCrwfYpuL+HWQzeU6lCk/nF9r7olWMnjKxCAkOctT2qFWFkzb1A==} + '@vue/compiler-ssr@3.5.34': + resolution: {integrity: sha512-cDtTHKibkThKGHH1SP+WdccquNRYQDFH6rRjQCqT9G2ltFAfoR5pUftpab/z+aM5mW9HLLVQW7hfKKQe/1GBeQ==} '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} @@ -4806,28 +4736,35 @@ packages: typescript: optional: true - '@vue/language-core@3.2.7': - resolution: {integrity: sha512-Gn4q/tRxbpVGLEuARQ43p3YELlNAFgRUVCgW9U5Cr+5q4vfD2bWDWpl3ABbJMXUt5xlE1dF8dkigg2aUq7JYYw==} + '@vue/language-core@3.2.8': + resolution: {integrity: sha512-9OiSPQFiAAWNVnXb0d2dcTmcKnFQamhuNES6ayyISrb/mwPWVgoGdAqSfCWqKhQpa3D5gDTcYD+w7ObiheZ81g==} - '@vue/reactivity@3.5.33': - resolution: {integrity: sha512-p8UfIqyIhb0rYGlSgSBV+lPhF2iUSBcRy7enhTmPqKWadHy9kcOFYF1AejYBP9P+avnd3OBbD49DU4pLWX/94A==} + '@vue/reactivity@3.5.34': + resolution: {integrity: sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ==} - '@vue/runtime-core@3.5.33': - resolution: {integrity: sha512-UpFF45RI9//a7rvq7RdOQblb4tup7hHG9QsmIrxkFQLzQ7R8/iNQ5LE15NhLZ1/WcHMU2b47u6P33CPUelHyIQ==} + '@vue/runtime-core@3.5.34': + resolution: {integrity: sha512-mKeBYvu8tcMSLhypAHBmriUFfWXKTCF/23Z4jiCoYK3UtWepkliViNLuR90V9XOyD62mUxs9p1jsrpK3CCGIzw==} - '@vue/runtime-dom@3.5.33': - resolution: {integrity: sha512-IOxMsAOwquhfITgmOgaPYl7/j8gKUxUFoflRc+u4LxyD3+783xne8vNta1PONVCvCV9A0w7hkyEepINDqfO0tw==} + '@vue/runtime-dom@3.5.34': + resolution: {integrity: sha512-e8kZzERmCwUnBRVsgSQlAfrfU2rGoy0FFKPBXSlfEjc/O3KfA7QP0t1/2ZylrbchjmIKB4dPTd07A6WPr0eOrg==} - '@vue/server-renderer@3.5.33': - resolution: {integrity: sha512-0xylq/8/h44lVG0pZFknv1XIdEgymq2E9n59uTWJBG+dIgiT0TMCSsxrN7nO16Z0MU0MPjFcguBbZV8Itk52Hw==} + '@vue/server-renderer@3.5.34': + resolution: {integrity: sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew==} peerDependencies: - vue: 3.5.33 + vue: 3.5.34 - '@vue/shared@3.5.33': - resolution: {integrity: sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==} + '@vue/shared@3.5.34': + resolution: {integrity: sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==} - '@vue/test-utils@2.4.6': - resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} + '@vue/test-utils@2.4.10': + resolution: {integrity: sha512-SmoZ5EA1kYiAFs9NkYdiFFQF+cSnUwnvlYEbY+DogWQZUiqOm/Y29eSbc5T6yi75SgSF9863SBeXniIEoPajCA==} + peerDependencies: + '@vue/compiler-dom': 3.x + '@vue/server-renderer': 3.x + vue: 3.x + peerDependenciesMeta: + '@vue/server-renderer': + optional: true '@webcontainer/env@1.1.1': resolution: {integrity: sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng==} @@ -4835,10 +4772,9 @@ packages: '@webgpu/types@0.1.38': resolution: {integrity: sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==} - '@xmldom/xmldom@0.9.9': - resolution: {integrity: sha512-qycIHAucxy/LXAYIjmLmtQ8q9GPnMbnjG1KXhWm9o5sCr6pOYDATkMPiTNa6/v8eELyqOQ2FsEqeoFYmgv/gJg==} + '@xmldom/xmldom@0.9.10': + resolution: {integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==} engines: {node: '>=14.6'} - deprecated: this version has critical issues, please update to the latest version abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -4886,8 +4822,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - adm-zip@0.5.16: - resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} + adm-zip@0.5.17: + resolution: {integrity: sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==} engines: {node: '>=12.0'} agent-base@4.3.0: @@ -4902,12 +4838,8 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/1dc7f60cda78d030dadfc518a33c472202b2ef67: - resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/1dc7f60cda78d030dadfc518a33c472202b2ef67} + resolution: {gitHosted: true, tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/1dc7f60cda78d030dadfc518a33c472202b2ef67} version: 0.1.16 engines: {vscode: ^1.83.0} @@ -4927,8 +4859,8 @@ packages: ajv: optional: true - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} @@ -4958,6 +4890,10 @@ packages: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -5068,8 +5004,8 @@ packages: asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - asn1js@3.0.6: - resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + asn1js@3.0.10: + resolution: {integrity: sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==} engines: {node: '>=12.0.0'} assert-never@1.4.0: @@ -5090,10 +5026,6 @@ packages: ast-v8-to-istanbul@1.0.0: resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} - astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true @@ -5126,8 +5058,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - avvio@9.1.0: - resolution: {integrity: sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==} + avvio@9.2.0: + resolution: {integrity: sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==} aws-sdk-client-mock@4.1.0: resolution: {integrity: sha512-h/tOYTkXEsAcV3//6C1/7U4ifSpKyJvb6auveAepqqNJl6TdZaPFEtKjBQNf8UxQdDP850knB2i/whq4zlsxJw==} @@ -5138,11 +5070,11 @@ packages: aws4@1.13.2: resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} - axios@1.15.0: - resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==} + axios@1.16.0: + resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==} - b4a@1.7.3: - resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} + b4a@1.8.1: + resolution: {integrity: sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==} peerDependencies: react-native-b4a: '*' peerDependenciesMeta: @@ -5159,23 +5091,56 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - balanced-match@4.0.2: - resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==} - engines: {node: 20 || >=22} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.7.1: + resolution: {integrity: sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-os@3.9.1: + resolution: {integrity: sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==} + engines: {bare: '>=1.14.0'} - bare-events@2.8.1: - resolution: {integrity: sha512-oxSAxTS1hRfnyit2CL5QpAOS5ixfBjj6ex3yTNvXyY/kE719jQ/IjuESJBK2w5v4wwQRAHGseVJXx9QBYOtFGQ==} + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.13.1: + resolution: {integrity: sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==} peerDependencies: bare-abort-controller: '*' + bare-buffer: '*' + bare-events: '*' peerDependenciesMeta: bare-abort-controller: optional: true + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.4.3: + resolution: {integrity: sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.19: - resolution: {integrity: sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==} + baseline-browser-mapping@2.10.27: + resolution: {integrity: sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==} engines: {node: '>=6.0.0'} hasBin: true @@ -5186,9 +5151,6 @@ packages: resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==} hasBin: true - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - blob-util@2.0.2: resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} @@ -5198,8 +5160,8 @@ packages: blurhash@2.0.5: resolution: {integrity: sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==} - bn.js@4.12.2: - resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} + bn.js@4.12.3: + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} @@ -5208,14 +5170,14 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - bowser@2.12.1: - resolution: {integrity: sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==} + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} brace-expansion@5.0.5: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} @@ -5259,8 +5221,8 @@ packages: resolution: {integrity: sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==} engines: {node: '>=6.14.2'} - bullmq@5.76.2: - resolution: {integrity: sha512-kkNU6TPAjqV3Ep0kIaYhT79Z2IMoA7vadqjmr/zvmPicg0K/cOAecqZTihD726LbI043yPU0MBv/nMQmd5rNIg==} + bullmq@5.76.6: + resolution: {integrity: sha512-vlmL3B3NVMRy6se3c7jPHn1Nhqxrg7+wlv1t3XAQFBYZNJDMLP0OO5x2AX5ca7DAuS1SU/C+VfYi+NHVoFK1QQ==} engines: {node: '>=12.22.0'} bundle-name@4.1.0: @@ -5282,10 +5244,6 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - cacache@20.0.3: - resolution: {integrity: sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==} - engines: {node: ^20.17.0 || >=22.9.0} - cacheable-lookup@7.0.0: resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} engines: {node: '>=14.16'} @@ -5302,8 +5260,8 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} engines: {node: '>= 0.4'} call-bound@1.0.4: @@ -5325,8 +5283,8 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001788: - resolution: {integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==} + caniuse-lite@1.0.30001792: + resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} canonicalize@2.1.0: resolution: {integrity: sha512-F705O3xrsUtgt98j7leetNhTWPe+5S72rlL5O4jA1pKqBVQ/dT1O1D6PFxmSXvc0SUOinWS57DKx0I3CHrXJHQ==} @@ -5401,8 +5359,8 @@ packages: chart.js: '>=2.8.0' date-fns: '>=2.0.0' - chartjs-chart-matrix@3.0.0: - resolution: {integrity: sha512-lUWC1UaWkxGdG02dBJ5r1ppbSYB/uWmwAh11VEs7V3ZQItNCk4am+rmacwkgeb+SQeEj2hP9Qq4oGsUmPl/1lQ==} + chartjs-chart-matrix@3.0.4: + resolution: {integrity: sha512-thkswkjZEtmZph+JUU65GjSxfAIKkLedVAhKz6umIs8zO+y+gHIuzovEtS1FqRXzubMXCX2RcglbQjHsL8g0Xw==} peerDependencies: chart.js: '>=3.0.0' @@ -5416,8 +5374,8 @@ packages: peerDependencies: chart.js: '>=3.2.0' - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} check-more-types@2.24.0: @@ -5447,8 +5405,8 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} - chromatic@16.6.0: - resolution: {integrity: sha512-cxRHMa3HJYrQtuL1F3J2x6wuVvfP+d7frUzltS7SiCVE8HbUBQTejH6TzveTKAHzErgrMrXjxvjD37bOTi4Mhw==} + chromatic@16.9.0: + resolution: {integrity: sha512-KJ1qvHMMP3jYZksxA229dREL81TeS+XxerRgd83klJIgtuQdY8kYg5TClNaF+K9HAzHmF19VIDHF6d0XwsRqzQ==} hasBin: true peerDependencies: '@chromatic-com/cypress': ^0.*.* || ^1.0.0 @@ -5466,28 +5424,24 @@ packages: resolution: {integrity: sha512-zFyPtyC0SZ6Zu79b9sOYtXZcgrsXe0RpePrzRyj52hYVFG1+Rk6rBqjjOEk+GNQwc3PIX+86teQMok970pod1g==} engines: {node: '>=20'} - ci-info@4.3.1: - resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} cjs-module-lexer@2.2.0: resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} cli-table3@0.6.1: resolution: {integrity: sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==} engines: {node: 10.* || >= 12.*} - cli-truncate@2.1.0: - resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} - engines: {node: '>=8'} + cli-truncate@5.2.0: + resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} + engines: {node: '>=20'} cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} @@ -5632,8 +5586,8 @@ packages: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} cookie@1.1.1: @@ -5681,12 +5635,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-declaration-sorter@7.3.0: - resolution: {integrity: sha512-LQF6N/3vkAMYF4xoHLJfG718HRJh34Z8BnNhd6bosOMIVjMlhuZK5++oZa3uYAgrI5+7x2o27gUqTR2U/KjUOQ==} - engines: {node: ^14 || ^16 || >=18} - peerDependencies: - postcss: ^8.0.9 - css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -5694,8 +5642,8 @@ packages: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - css-tree@3.1.0: - resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} css-what@6.2.2: @@ -5710,37 +5658,33 @@ packages: engines: {node: '>=4'} hasBin: true - cssnano-preset-default@7.0.15: - resolution: {integrity: sha512-60kx7lJ40//HA85cIfQXSOJFby2D2V1pOMNHVCxue3KFWCjRzmiQyL9OvI+NAhwUlaojOfF9eK3nGvrJLCBUfQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + cssnano-preset-default@8.0.0: + resolution: {integrity: sha512-uIJx5WOQ2vlH0HwKZz3AbhYffVvYTUcS2S76gr3oLnU2i9qn7yy3LLs0rk3YAtBB9gayYr0aTvk0pZ6MlenUlw==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - cssnano-utils@5.0.2: - resolution: {integrity: sha512-kt41WLK7FLKfePzPi645Y+/NtW/nNM7Su6nlNUfJyRNW3JcuU3JU7+cWJc+JexTeZ8dRBvFufefdG2XpXkIo0A==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + cssnano-utils@6.0.0: + resolution: {integrity: sha512-ztS9W/+uaDn+bkYmDhs+GdMveHJ3CL8IPNHpRqDUQXv5GJOTQAJjV1XUOInr9esLXSabQV1pLRZlJpyUwEqDyQ==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - cssnano@7.1.7: - resolution: {integrity: sha512-N5LGn/OlhMxDTvKACwUPMzT34SSj1b022pvUAE/Vh6r2WD1aUCbc+QNIP/JjX9VVxebdJWZQ3352Lt4oF7dQ/g==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + cssnano@8.0.0: + resolution: {integrity: sha512-FBjMD2UTnAshdTNoFnF6vLICR3/gCypkWdveXbxpO+cPlJZ3RYdYOv84ibCxEHzo5Wuoy7yAmBkmUGuLLzoUwA==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 csso@5.0.5: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - cssstyle@5.3.7: - resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==} - engines: {node: '>=20'} - csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - cypress@15.14.1: - resolution: {integrity: sha512-AkuiHNSnmm0a+h/horcvbjmY6dWpCe1Ebp1R0LjMP5I6pjMaNA50Mw1YP/d07pLHJ/sV8FZoGecUWFCJ/Nifpw==} + cypress@15.14.2: + resolution: {integrity: sha512-xMWg/iEImeIThRQZdnf3BFJT1a84apM/R91Feoa4vVWGuYWDphMT5jLhRVTBVlCgi+6axegF1zqhNyjhug2SsQ==} engines: {node: ^20.1.0 || ^22.0.0 || >=24.0.0} hasBin: true @@ -5752,10 +5696,6 @@ packages: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} - data-urls@6.0.1: - resolution: {integrity: sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==} - engines: {node: '>=20'} - data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -5771,8 +5711,8 @@ packages: date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} - dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} @@ -5810,9 +5750,6 @@ packages: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - decode-bmp@0.2.1: resolution: {integrity: sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==} engines: {node: '>=8.6.0'} @@ -5821,15 +5758,15 @@ packages: resolution: {integrity: sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==} engines: {node: '>=8.6'} - decode-named-character-reference@1.2.0: - resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} decompress-response@10.0.0: resolution: {integrity: sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==} engines: {node: '>=20'} - dedent@1.7.0: - resolution: {integrity: sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==} + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: @@ -5859,8 +5796,8 @@ packages: resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} - default-browser@5.4.0: - resolution: {integrity: sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==} + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} engines: {node: '>=18'} define-data-property@1.1.4: @@ -5894,11 +5831,6 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -5916,12 +5848,12 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + diff@5.2.2: + resolution: {integrity: sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==} engines: {node: '>=0.3.1'} - diff@8.0.2: - resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} dijkstrajs@1.0.3: @@ -5984,16 +5916,16 @@ packages: ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - editorconfig@1.0.4: - resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + editorconfig@1.0.7: + resolution: {integrity: sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==} engines: {node: '>=14'} hasBin: true ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.336: - resolution: {integrity: sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==} + electron-to-chromium@1.5.352: + resolution: {integrity: sha512-9wHk8x6dyuimoe18EdiDPWKExNdxYqo4fn4FwOVVper6RxT3cmpBwBkWWfSOCYJjQdIco/nPhJhNLmn4Ufg1Yg==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -6015,16 +5947,9 @@ packages: encoding-sniffer@0.2.1: resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} - encoding@0.1.13: - resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -6044,14 +5969,15 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - err-code@2.0.3: - resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} engines: {node: '>= 0.4'} es-define-property@1.0.1: @@ -6065,8 +5991,8 @@ packages: es-get-iterator@1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - es-module-lexer@2.0.0: - resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} @@ -6084,8 +6010,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.42.0: - resolution: {integrity: sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==} + es-toolkit@1.46.1: + resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==} es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} @@ -6093,8 +6019,8 @@ packages: es6-promisify@5.0.0: resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - esbuild@0.27.4: - resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} hasBin: true @@ -6117,10 +6043,6 @@ packages: escape-regexp@0.0.1: resolution: {integrity: sha512-jVgdsYRa7RKxTT6MKNC3gdT+BF0Gfhpel19+HMRZJC2L0PufB0XOBuXBoXj29NKHwuktnAXd1Z1lyiH/8vOTpw==} - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -6133,8 +6055,8 @@ packages: resolution: {integrity: sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==} engines: {node: '>=10'} - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + eslint-import-resolver-node@0.3.10: + resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} eslint-module-utils@2.12.1: resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} @@ -6167,14 +6089,14 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-vue@10.9.0: - resolution: {integrity: sha512-EFNNzu4HqtTRb5DJINpyd+u3bDdzETWDMpCzG+UBHz1tpsnMDCeOcf61u4Wy/cbXnMymK+MT9bjH7KcG1fItSw==} + eslint-plugin-vue@10.9.1: + resolution: {integrity: sha512-cHB0Tf4Duvzwecwd/AqWzZvF/QszE13BhjVUpVXWCy9AeMR5GjkAjP3i85vqgLgOuTmkHR1OJ5oMeqLHtuw8zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 '@typescript-eslint/parser': ^7.0.0 || ^8.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - vue-eslint-parser: ^10.0.0 + vue-eslint-parser: ^10.3.0 peerDependenciesMeta: '@stylistic/eslint-plugin': optional: true @@ -6188,6 +6110,10 @@ packages: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6217,13 +6143,17 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -6333,8 +6263,8 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - fast-json-stringify@6.1.1: - resolution: {integrity: sha512-DbgptncYEXZqDUOEl4krff4mUiVrTZZVI7BBrQR/T3BqMj/eM1flTC1Uk2uUoLcWCxjT95xKulV/Lc6hhOZsBQ==} + fast-json-stringify@6.4.0: + resolution: {integrity: sha512-ibRCQ0GZKJIQ+P3Et1h0LhPgp3PMTYk0MH8O+kW3lNYsvmaQww5Nn3f1jf73Q0jR1Yz3a1CDP4/NZD3vOajWJQ==} fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} @@ -6351,17 +6281,17 @@ packages: fast-string-width@3.0.2: resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} fast-wrap-ansi@0.2.0: resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} - fast-xml-builder@1.1.5: - resolution: {integrity: sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==} + fast-xml-builder@1.1.9: + resolution: {integrity: sha512-jcyKVSEX13iseJqg7n/KWw+xnu/7fdrZ333Fac54KjHDIELVCfDDJXYIm6DTJ0Su4gSzrhqiK0DzY/wZbF40mw==} - fast-xml-parser@5.7.1: - resolution: {integrity: sha512-8Cc3f8GUGUULg34pBch/KGyPLglS+OFs05deyOlY7fL2MTagYPKrVQNmR1fLF/yJ9PH5ZSTd3YDF6pnmeZU+zA==} + fast-xml-parser@5.7.2: + resolution: {integrity: sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==} hasBin: true fastify-plugin@5.1.0: @@ -6397,10 +6327,6 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} - figures@3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} - figures@6.1.0: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} @@ -6421,12 +6347,12 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@2.1.0: - resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} - engines: {node: '>= 0.8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} - find-my-way@9.3.0: - resolution: {integrity: sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==} + find-my-way@9.6.0: + resolution: {integrity: sha512-Zf4Xve4RymLl7NgaavNebZ01joJ8MfVerOG43wy7SHLO+r+K0C6d/SE0BiR7AV5V1VOCFlOP7ecdo+I4qmiHrQ==} engines: {node: '>=20'} find-up@4.1.0: @@ -6445,16 +6371,16 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} fluent-ffmpeg@2.1.3: resolution: {integrity: sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==} engines: {node: '>=18'} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -6496,8 +6422,8 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} - fs-extra@11.3.2: - resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + fs-extra@11.3.5: + resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} engines: {node: '>=14.14'} fs-extra@9.1.0: @@ -6508,10 +6434,6 @@ packages: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} - fs-minipass@3.0.3: - resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -6547,8 +6469,8 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.4.0: - resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} get-intrinsic@1.3.0: @@ -6575,8 +6497,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} @@ -6594,9 +6516,9 @@ packages: deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true - glob@13.0.1: - resolution: {integrity: sha512-B7U/vJpE3DkJ5WXTgTpTRN63uV42DseiXXKMwG14LQBXmsdeIoHAPbU/MEo6II0k5ED74uc2ZGTC6MwHFQhF6w==} - engines: {node: 20 || >=22} + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -6610,8 +6532,8 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@17.5.0: - resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==} + globals@17.6.0: + resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==} engines: {node: '>=18'} globalthis@1.0.4: @@ -6633,11 +6555,15 @@ packages: resolution: {integrity: sha512-630of5aMTYM6g6epok5nuqvctP8InJISvt39iNt7y0r27rcGCdiPv9Cc6EbwfnkyT1g/shBoVhvDjtXZUbn/Rw==} engines: {node: '>=22'} + got@15.0.5: + resolution: {integrity: sha512-PMIMaZuYUCK43+Z9JWEXea4kkX2b3301m81D5TS6QpfG4PmNyirzEdO/Oa2OHAN4GsjnPfvWCWsshKN2rq4/gQ==} + engines: {node: '>=22'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphql@16.13.2: - resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==} + graphql@16.14.0: + resolution: {integrity: sha512-BBvQ/406p+4CZbTpCbVPSxfzrZrbnuWSP1ELYgyS6B+hNeKzgrdB4JczCa5VZUBQrDa9hUngm0KnexY6pJRN5Q==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} hammerjs@2.0.8: @@ -6692,8 +6618,8 @@ packages: resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} engines: {node: '>=8'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} hast-util-to-html@9.0.5: @@ -6724,10 +6650,6 @@ packages: resolution: {integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==} engines: {node: '>=14'} - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} - html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} @@ -6746,10 +6668,6 @@ packages: http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -6758,10 +6676,6 @@ packages: resolution: {integrity: sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==} engines: {node: '>=6.0.0'} - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - http-signature@1.4.0: resolution: {integrity: sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==} engines: {node: '>=0.10'} @@ -6810,10 +6724,6 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - iconv-lite@0.7.0: - resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} - engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -6849,8 +6759,8 @@ packages: import-in-the-middle@2.0.6: resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==} - import-in-the-middle@3.0.0: - resolution: {integrity: sha512-OnGy+eYT7wVejH2XWgLRgbmzujhhVIATQH0ztIeRilwHBjTeG3pD+XnH3PKX0r9gJ0BuJmJ68q/oh9qgXnNDQg==} + import-in-the-middle@3.0.1: + resolution: {integrity: sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==} engines: {node: '>=18'} import-lazy@4.0.0: @@ -6886,8 +6796,9 @@ packages: insert-text-at-cursor@0.3.0: resolution: {integrity: sha512-/nPtyeX9xPUvxZf+r0518B7uqNKlP+LqNJqSiXFEaa2T71rWIwTVXGH7hB9xO/EVdwa5/pWlFCPwShOW81XIxQ==} - install-artifact-from-github@1.4.0: - resolution: {integrity: sha512-+y6WywKZREw5rq7U2jvr2nmZpT7cbWbQQ0N/qfcseYnzHFz2cZz1Et52oY+XttYuYeTkI8Y+R2JNWj68MpQFSg==} + install-artifact-from-github@1.6.0: + resolution: {integrity: sha512-wKsuzN8fy8QK7iEUqyWTQmvZ1QFGPn1xyl3/1iIIDthDjS7Hn9HoPwHlNakZirWbCsbad0lZMkr6Xfbpe1pUzw==} + engines: {node: '>=18'} hasBin: true internal-slot@1.1.0: @@ -6902,12 +6813,8 @@ packages: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} - ios-haptics@0.1.4: - resolution: {integrity: sha512-94FJcSuvmhe4mHTX4Uauj+/2yhs56m4BLkRScy1vNvkv7H1cSjsvfT+olc1sYOUqWlPhtVttAFBHex0cY9CE7Q==} - - ip-address@10.0.1: - resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} - engines: {node: '>= 12'} + ios-haptics@0.1.5: + resolution: {integrity: sha512-quSSgC4pKFkXV0SzKPRB8jOh7GYl9nYvgIYYcmFMqOkk2WSJ/ocfN5O0F/w8cqzUxKP2z+4tiJRO3eGE3qU05g==} ip-address@9.0.5: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} @@ -6925,6 +6832,10 @@ packages: resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} engines: {node: '>= 10'} + ipaddr.js@2.4.0: + resolution: {integrity: sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==} + engines: {node: '>= 10'} + irregular-plurals@3.5.0: resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} engines: {node: '>=8'} @@ -6959,8 +6870,8 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} engines: {node: '>= 0.4'} is-data-view@1.0.2: @@ -6994,6 +6905,10 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + is-generator-function@1.1.2: resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} @@ -7046,9 +6961,6 @@ packages: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - is-promise@2.2.2: resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} @@ -7118,8 +7030,8 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} isarray@1.0.0: @@ -7131,9 +7043,9 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isexe@3.1.1: - resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} - engines: {node: '>=16'} + isexe@4.0.0: + resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} + engines: {node: '>=20'} isstream@0.1.2: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} @@ -7157,10 +7069,6 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jackspeak@4.2.3: - resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} - engines: {node: 20 || >=22} - jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7175,8 +7083,8 @@ packages: joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} - joi@18.1.2: - resolution: {integrity: sha512-rF5MAmps5esSlhCA+N1b6IYHDw9j/btzGaqfgie522jS02Ju/HXBxamlXVlKEHAxoMKQL77HWI8jlqWsFuekZA==} + joi@18.2.1: + resolution: {integrity: sha512-2/OKlogiESf2Nh3TFCrRjrr9z1DRHeW0I+KReF67+4J0Ns+8hBtHRmoWAZ2OFU6I5+TWLEe6sVlSdXPjHm5UbQ==} engines: {node: '>= 20'} js-beautify@1.15.4: @@ -7211,15 +7119,6 @@ packages: jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - jsdom@27.2.0: - resolution: {integrity: sha512-454TI39PeRDW1LgpyLPyURtB4Zx1tklSr6+OFOipsxGUH1WMTvk6C65JQdrj455+DP2uJ1+veBEHTGFKWVLFoA==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -7258,8 +7157,8 @@ packages: engines: {node: '>=6'} hasBin: true - jsonfile@6.2.0: - resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} jsonld@9.0.0: resolution: {integrity: sha512-pjMIdkXfC1T2wrX9B9i2uXhGdyCmgec3qgMht+TDj+S0qX3bjWMQUfL7NeqEhuRTi8G5ESzmL9uGlST7nzSEWg==} @@ -7291,8 +7190,8 @@ packages: jwa@2.0.1: resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - jws@4.0.0: - resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -7304,8 +7203,8 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - ky@1.14.0: - resolution: {integrity: sha512-Rczb6FMM6JT0lvrOlP5WUOCB7s9XKxzwgErzhKlKde1bEV90FXplV1o87fpt4PU/asJFiqjYJxAJyzJhcrxOsQ==} + ky@1.14.3: + resolution: {integrity: sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==} engines: {node: '>=18'} lazy-ass@1.6.0: @@ -7408,14 +7307,9 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - listr2@3.14.0: - resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} - engines: {node: '>=10.0.0'} - peerDependencies: - enquirer: '>= 2.3.0 < 3' - peerDependenciesMeta: - enquirer: - optional: true + listr2@9.0.5: + resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} + engines: {node: '>=20.0.0'} load-esm@1.0.3: resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} @@ -7454,9 +7348,9 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} - log-update@4.0.0: - resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} - engines: {node: '>=10'} + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} long@4.0.0: resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} @@ -7478,8 +7372,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.5: - resolution: {integrity: sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==} + lru-cache@11.3.6: + resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -7518,10 +7412,6 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - make-fetch-happen@15.0.3: - resolution: {integrity: sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw==} - engines: {node: ^20.17.0 || >=22.9.0} - map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -7546,8 +7436,8 @@ packages: mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - mdast-util-from-markdown@2.0.2: - resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} mdast-util-gfm-autolink-literal@2.0.1: resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} @@ -7570,8 +7460,8 @@ packages: mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - mdast-util-to-hast@13.2.0: - resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} mdast-util-to-markdown@2.1.2: resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} @@ -7582,8 +7472,8 @@ packages: mdn-data@2.0.28: resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} - mdn-data@2.12.2: - resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} @@ -7593,11 +7483,11 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} - mediabunny@1.41.0: - resolution: {integrity: sha512-cJWBHvAyRNgTbsx8Z2oHptX/PdiywwsS+GIvv2k9eioXSOzzAemBsHwf7jM6fvW3b65azvZGP9RLuO1DI8JmdA==} + mediabunny@1.44.1: + resolution: {integrity: sha512-Frx7nlYFDHPYPgkn3JsWsAExetSIImr5F1Hoz0+fXvV9OAXs02LVtrlmtj/SVaF1RPEUPyeIo9wRBH685u79pQ==} - meilisearch@0.57.0: - resolution: {integrity: sha512-J3ZdX6MjguEIG9Yo+duRZeVsbMdRuwM2OFvJUs8wZSeBADYZ2qc1eajlClKLRqS/mAhGh2bLiU5SbmhKXKuWSw==} + meilisearch@0.58.0: + resolution: {integrity: sha512-MXFlU+JVG2I3tDI4brS3UHxEv2fjOROP24TPP16c8dGHTulb1kxMgXvKP0x4ImvUcsVVJFi4QXP0JNDS/TaWaw==} engines: {node: ^20.19.0 || >=22.12.0} memoizerific@1.11.3: @@ -7750,6 +7640,10 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + mimic-response@4.0.0: resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -7772,16 +7666,12 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} engines: {node: '>=10'} - minimatch@9.0.1: - resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} - engines: {node: '>=16 || 14 >=14.17'} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} minimist-options@4.1.0: @@ -7791,26 +7681,6 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass-collect@2.0.1: - resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} - engines: {node: '>=16 || 14 >=14.17'} - - minipass-fetch@5.0.0: - resolution: {integrity: sha512-fiCdUALipqgPWrOVTz9fw0XhcazULXOSU6ie40DDbX1F49p1dBrSRBuswndTx1x3vEb/g0FT7vC4c4C2u/mh3A==} - engines: {node: ^20.17.0 || >=22.9.0} - - minipass-flush@1.0.5: - resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} - engines: {node: '>= 8'} - - minipass-pipeline@1.2.4: - resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} - engines: {node: '>=8'} - - minipass-sized@1.0.3: - resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} - engines: {node: '>=8'} - minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -7819,8 +7689,8 @@ packages: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} minizlib@2.1.2: @@ -7860,16 +7730,16 @@ packages: resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==} hasBin: true - msgpackr@1.11.5: - resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==} + msgpackr@2.0.1: + resolution: {integrity: sha512-9J+tqTEsbHqY8YohazYgty7LgerFIWxvMLpUjqETSmjHojtJm2WnX2kK/2a1fLI7CO7ERP1YSEUXMucz4j+yBA==} msw-storybook-addon@2.0.7: resolution: {integrity: sha512-TGmlxXy2TsaB6QcClVKRxqvay5f93xoLguHOihRFQ+gIEIyiyvcoQjkEeuOe7Y9qvddzGB1LyFomzPo9/EpnuQ==} peerDependencies: msw: ^2.0.0 - msw@2.13.6: - resolution: {integrity: sha512-GAJbQy8Ra/Ydjt0Hb2MGT2qhzd83J3+QZMHdH85uW7r/XkKc846+Ma2PLif5hGvTm5Yqa+wkcstpim0WeLZU9g==} + msw@2.14.3: + resolution: {integrity: sha512-kk8G5cocVlJ4wsKMGZegn2H6XLOEKjbA+nSJE2354e/SRp4mDicCHUYnMXpymzVcVDCs+GUAsmNqSn+yHv4T2A==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -7896,13 +7766,13 @@ packages: nan@2.26.2: resolution: {integrity: sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@5.1.9: - resolution: {integrity: sha512-ZUvP7KeBLe3OZ1ypw6dI/TzYJuvHP77IM4Ry73waSQTLn8/g8rpdjfyVAh7t1/+FjBtG4lCP42MEbDxOsRpBMw==} + nanoid@5.1.11: + resolution: {integrity: sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==} engines: {node: ^18 || >=20} hasBin: true @@ -7929,11 +7799,11 @@ packages: nested-property@4.0.0: resolution: {integrity: sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==} - nise@6.1.1: - resolution: {integrity: sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==} + nise@6.1.5: + resolution: {integrity: sha512-SnRDPDBjxZZoU2n0+gzzLtSvo1OZo7j6jnbXsoh3AFxEGhaFU7ZF0TmefuKERq79wxR2U+MPn7ArW+Tl+clC3A==} - node-abi@3.85.0: - resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==} + node-abi@3.92.0: + resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==} engines: {node: '>=10'} node-abort-controller@3.1.1: @@ -7947,6 +7817,10 @@ packages: engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead + node-exports-info@1.6.0: + resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} + engines: {node: '>= 0.4'} + node-fetch@2.6.13: resolution: {integrity: sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==} engines: {node: 4.x || >=6.0.0} @@ -7977,19 +7851,19 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true - node-gyp@12.2.0: - resolution: {integrity: sha512-q23WdzrQv48KozXlr0U1v9dwO/k59NHeSzn6loGcasyf0UnSrtzs8kRxM+mfwJSf0DkX0s43hcqgnSO4/VNthQ==} + node-gyp@12.3.0: + resolution: {integrity: sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==} engines: {node: ^20.17.0 || >=22.9.0} hasBin: true node-html-parser@7.1.0: resolution: {integrity: sha512-iJo8b2uYGT40Y8BTyy5ufL6IVbN8rbm/1QK2xffXU/1a/v3AAa0d1YAoqBNYqaS4R/HajkWIpIfdE6KcyFh1AQ==} - node-releases@2.0.37: - resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} + node-releases@2.0.38: + resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} - nodemailer@8.0.6: - resolution: {integrity: sha512-Nm2XeuDwwy2wi5A+8jPWwQwNzcjNjhWdE3pVLoXEusxJqCnAPAgnBGkSmiLknbnWuOF9qraRpYZjfxqtKZ4tPw==} + nodemailer@8.0.7: + resolution: {integrity: sha512-pkjE4mkBzQjdJT4/UmlKl3pX0rC9fZmjh7c6C9o7lv66Ac6w9WCnzPzhbPNxwZAzlF4mdq4CSWB5+FbK6FWCow==} engines: {node: '>=6.0.0'} nodemon@3.1.14: @@ -8083,6 +7957,10 @@ packages: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + object.fromentries@2.0.8: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} @@ -8121,11 +7999,15 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} - oniguruma-parser@0.12.1: - resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} - oniguruma-to-es@4.3.4: - resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} open@10.2.0: resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} @@ -8180,14 +8062,6 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - - p-map@7.0.3: - resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} - engines: {node: '>=18'} - p-queue@6.6.2: resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} engines: {node: '>=8'} @@ -8231,9 +8105,6 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - parse5@8.0.0: - resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -8268,9 +8139,9 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.1: - resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} - engines: {node: 20 || >=22} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} @@ -8336,8 +8207,8 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} picomatch@4.0.4: @@ -8352,14 +8223,14 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pino-abstract-transport@2.0.0: - resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} - pino-std-serializers@7.0.0: - resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} - pino@10.1.0: - resolution: {integrity: sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==} + pino@10.3.1: + resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} hasBin: true pkce-challenge@6.0.0: @@ -8385,9 +8256,9 @@ packages: resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} engines: {node: '>=10.13.0'} - pnpm@10.33.2: - resolution: {integrity: sha512-qQ+vb+6rca1sblf5Tg/hoS9dzCLNdU20CulZPraj4LaxLjVAIYuzeuCDQEsfLObbKkEh6XmCm0r/lLmfSdoc+A==} - engines: {node: '>=18.12'} + pnpm@11.1.2: + resolution: {integrity: sha512-QVocwll0cx51RVwUaDcb50xapft2IbUNQFbSIkUWCfEUEvI/1gLmFp8eBgRmZB95hZfhvpYaEGiINqZ7FlaUmQ==} + engines: {node: '>=22.13'} hasBin: true polished@4.3.1: @@ -8404,179 +8275,179 @@ packages: peerDependencies: postcss: ^8.4.38 - postcss-colormin@7.0.9: - resolution: {integrity: sha512-EZpoUlmbXQUpe+g4ZaGM2kjGlHrQ7Bjzb3xHcNrC9ysI1tGoib6DAYvxg6aB7MGxsjgLF+Qx/jwZQkJ5cKDvXA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-colormin@8.0.0: + resolution: {integrity: sha512-KKwMmsSgsmdYXqrjQeqL3tnuIFtctiR1GEMHdjNpDpz/TCRkkkok2mMcreK2zVV3l7POWOmAkR2xYHUpRUK1DA==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-convert-values@7.0.11: - resolution: {integrity: sha512-H+s7P0f9jJylSysAHs3/5MhAx7GthDO05uw1h56L2xyEqpiLTFLEqBNw3PUYzD5p/AKwWaigCXf6FGELpOw9lw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-convert-values@8.0.0: + resolution: {integrity: sha512-Ohtj3rNZWawTRePv5NCHTy8VJSdJ/G/uKuxcxJreOMichuqcT6uEl2TAnopVeJCJ/c13jaSqg7m63yFLM5zBsA==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-discard-comments@7.0.7: - resolution: {integrity: sha512-FJhE3fSte7HaRNL4iwD8LTG9vWqj3puxXIdig6LfrFqc1TJRUhY4kXOkeTXZZfTXYny+k+SO7fd2fymj1wduJg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-discard-comments@8.0.0: + resolution: {integrity: sha512-zGpvVLj2sbagEp+BTVETvAfkZdGVA6rALNujDK/WTIjdf1/rQOxOG8BBzkI8UQgnw8SkL6xffAfbtGMHFypadw==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-discard-duplicates@7.0.3: - resolution: {integrity: sha512-9cRxXwhEM/aNZon1qZyToX4NmjbFbxOGbww+0CnbYFDbbPRGZ8jg4IbM8UlA+CzkXxM35itxyaHKNqBBg/RTDg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-discard-duplicates@8.0.0: + resolution: {integrity: sha512-zjRyYmNGI3PTipKBBtCgExlmZXQn49KvKoaiNnR2g+iXxeNk7GY5Js2ULtZXPrCYeqjPagrzKIBNcBocvXCR7g==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-discard-empty@7.0.2: - resolution: {integrity: sha512-NZFouOmOwtngJVgkNeI1LtkzFdYqIurxgy4wq3qNvIiXFURTZ3b/K7q3dP3QitlWQ5imHDQL0qSorItQhoxb1g==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-discard-empty@8.0.0: + resolution: {integrity: sha512-kxPJg6EqahbBvm+l7hpYYCtpsv8dlz7Tv6wJXUXZaeuY0WGS61DxfGdZR4uVB/Cx+yi3iOHQVSqpSHKMFaBg6Q==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-discard-overridden@7.0.2: - resolution: {integrity: sha512-Ym01X4v6U3sY8X0P1J9P+RTar+7JyLTOzDrxKSeaArFsLmkVu4KcAKPBWDYRIyZ/q4jwpSPnOnekeSSqXSXKUw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-discard-overridden@8.0.0: + resolution: {integrity: sha512-sW2OWH3l9p0FmBSVr228uztFseqroZxwgD7SGF0Ks0dRPDttSo3P8FK5ZBLtWBH2A5+chpB0J2fB/T8heKHLBw==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-merge-longhand@7.0.6: - resolution: {integrity: sha512-lDsWeKRsssX/9vKFpingoRiuvGajtOGCJhs1kyaTJ5fzaVzs0aPPYe38UZ/ukMFEA5iuRIjQJHIkH2niYO3ubQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-merge-longhand@8.0.0: + resolution: {integrity: sha512-YDmAmQ8H+ljfomVpSXvr9NA0GP01fraQJqjWBYoMVGg6rOT+PJLwPyeVo2ekn4WB4ZVSH5ddtK3DTRxbz6CFzg==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-merge-rules@7.0.10: - resolution: {integrity: sha512-UXYKxkg8Cy1so/evF7AE/25PNXZb3E0SrvjdbtbGf+MW+doLenKqRLQzz6YZW469ktiXK2MVLFWtel/DftCV0Q==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-merge-rules@8.0.0: + resolution: {integrity: sha512-bgstL5mpi41dDpnYGDUcI3M814NWkCMcIWpwDqEHXkHg3BT7b4XRAfNEuwJncZOVn/67kVKvWzhfv/7xyrp2uQ==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-minify-font-values@7.0.2: - resolution: {integrity: sha512-Z82NUmnvhPrvMUaHfkaAVBmWQq9F8Dox4Dy0LiwbaTxfmDUWLQtS+0WCgKViwdWCPPajiY9YzoQftgqKdXkM5g==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-minify-font-values@8.0.0: + resolution: {integrity: sha512-EnOHQEnSt6oH5NrL1DMFAQuwB2IOimFXTCzc9bKfUeH1jREbqIF5MAK4gQJQOC4mPUwJt4sWifAmNZ1qLu6j3Q==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-minify-gradients@7.0.4: - resolution: {integrity: sha512-g8MNeNyN+lbwKy8DCtJ6zU6awBL0InBsSOaKmgZ1MdRLVItLQUNFNAzzzBnOp4qowOcyyB6GetTlQ0/0UNXvag==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-minify-gradients@8.0.0: + resolution: {integrity: sha512-43iAnYIGk0ZjNx5X/rkIcHi6dhmu/vEjY0kqfUfxPuJRO+V7jx8uKIdcnL0dpfNoC5J9TSh3EtzLWbq0gpqnWA==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-minify-params@7.0.8: - resolution: {integrity: sha512-DIUKM5DZGTmxN7KFKT+rxt0FdPDmRrdK/k3n3+6Po+N/QYn06juwagHcfOVBG0CfCHwcnI612GAUCZc3eT+ZEg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-minify-params@8.0.0: + resolution: {integrity: sha512-z7w4QO7G55l4vMUK1Lmx03GW7iyRLgf2V5Dz/7ioSPLnXRjeD+b7m0XfAXUGrbBYYrJ6bXPk+3LoX5u4JfAcSg==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-minify-selectors@7.1.0: - resolution: {integrity: sha512-HYl/6I0aL+UvpA10t65BSa7h+tVjBgE6oRI5N/3ylX3vtwvlDL67G3FT3vYDPnTksxr0riiyJcT0tBtyRVoloA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-minify-selectors@8.0.0: + resolution: {integrity: sha512-pQKzVGjUfOVP8QH95lXN/cpMcwHvdsqF3tQTEWPsRPnHw2SZ7G9c69oWDfjWkpCd81APF8E34QKUEUo+qUp5qw==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-normalize-charset@7.0.2: - resolution: {integrity: sha512-YoINoiR4YKlzfB95Y93b0DSxWy7FLw+1SADIaznMHb88AKizpzfF80tolmiDEbYr1UM4r4Hw+NZq37SwT5f3uw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-normalize-charset@8.0.0: + resolution: {integrity: sha512-s88FUNDSUD8m0wBYvTQQcubVts6zhXwBU8zCD4vkRKiecd0v8cOjHVIF9r/i+5xzS/WG3f98qq4XsOM0JqvfLA==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-normalize-display-values@7.0.2: - resolution: {integrity: sha512-wu/NTSjnp8sX5TnEHVPN+eScjAtRs18ELtEduG+Ek3GxjeUDUT+VAA3PJjVIXBcVIk6fiLYFj2iKH0q99S3T2Q==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-normalize-display-values@8.0.0: + resolution: {integrity: sha512-gG2nBxD27fiw6Luinb1QYKdM/Co5GornRJgSD+JTwNH4PGKxImP0qyruDDav49aHUPLY3qrL3qN3LvybO7IzxQ==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-normalize-positions@7.0.3: - resolution: {integrity: sha512-1CJI++oA3yK/fQlPUcEngUfcSWS08Pkt9fK+jVgL53mmtHDBHi0YiuB0m3D9BXwZjmfvCc2GQmFqCAF/CVcPzQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-normalize-positions@8.0.0: + resolution: {integrity: sha512-t/wGqpehS20Ke7kc4QAsWpH+AJjUdMK/V5qV2RhrXkj8hO/fT1t1MJ8NL7sedWYk7ZqC7eISEJQonW5j0tU1MQ==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-normalize-repeat-style@7.0.3: - resolution: {integrity: sha512-RvImJ2Ml4LZSx31qC2C8LDiz65IgBNATtwEr9r3Aue+D0cCGbj4rjNojb/uGpEm4QxnOTzFqMvaDYuKiT1Cmpg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-normalize-repeat-style@8.0.0: + resolution: {integrity: sha512-3ebOmGdCYKrBYyGKc1xhj0unEnW7beZpVU7JohVeGl7mTxR+7T6egpaawTWAVsB0pEIhcsbJVOjPKCJSoRO6Zg==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-normalize-string@7.0.2: - resolution: {integrity: sha512-FqtrUh2BU2MnVeLeWBbJ2rwOjuDnA91XvoImc1BbgMWIxdxiPTaquflBHsmFBA3xh3pC3wPZO9W5MaIc7wU/Xw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-normalize-string@8.0.0: + resolution: {integrity: sha512-TvWCGZ/e04Tv31uJvOUtbexkfgUnqmQ3M2P5DkAaVzvOj+BvTkG2QjpA5Y71SL1SPxJcj4M23fNh+RDVCmG8kA==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-normalize-timing-functions@7.0.2: - resolution: {integrity: sha512-5H5fpXBnMACEXzn7k9RP7qWZ1eWg8cuZkUuFygStY7icOj+UucwMWXeMmdkF/iITvTVa7fP85tdRCJeznpdFfQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-normalize-timing-functions@8.0.0: + resolution: {integrity: sha512-uEfaXst5Xgqxv7geYUuz6vs9mn88K2NPY2RoIzM3BMmSjsdTSeppV9x2qIgrxsisdbSqF6IVhzI2occcte3hTA==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-normalize-unicode@7.0.8: - resolution: {integrity: sha512-imCM3cwK3hvlAG4z1AzYM24m8BPA3/Jk/S71wfbn2I6+E2b+UwFaGvlNqydihXTSl3OFPeQXztqCzg+NGeSibQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-normalize-unicode@8.0.0: + resolution: {integrity: sha512-+WYngZaChEeTHZmWhmKtnJ4gTzWdINEaFcgWBnu6WdVu8Ftim8OBTcw768DuCC/3Aax9bZ9WkwrLGHym2Lzf+A==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-normalize-url@7.0.2: - resolution: {integrity: sha512-bLnNY7t76NLRb9QQyCVmCN4qwoHxiq6vABH/CXav9wTuR6dNGHGQ72AyO/+h2quWxZk3l7BqxNL1vtDi9H6y1g==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-normalize-url@8.0.0: + resolution: {integrity: sha512-4Mz9hZHn/QIB+YtFqTXrDmE2193GYxGb3F8uMfLvMicaEXCCUlDIJ658gFFJbqEGl9FYzwPtRiuNgbwlO9kkBg==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-normalize-whitespace@7.0.2: - resolution: {integrity: sha512-TNSVkuhkeOhl36WruQlflxOb7HweoeZowSusNpfsM1+ZvqJ24Mc+xksu05ecMQxlu+0zgI8pyznO2EWqDCQbLA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-normalize-whitespace@8.0.0: + resolution: {integrity: sha512-V1f8tYnwIP5tscOXQFTKK8Y5EJ+R2GMpFJ6FjzwoKoQnhbqQy3IeSrDjJJb8JjVos8ut6Osi80Zybpayv/XjIQ==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-ordered-values@7.0.3: - resolution: {integrity: sha512-FTt6R9RF7NAYfpOHa2XFPm89FVuo5GiIbcfwOXFy1MYF38BeiNW9ke8ybw9Pk62eEsUlRVVbxHWA3B7ERYqOOA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-ordered-values@8.0.0: + resolution: {integrity: sha512-Dg9+itb6lmD0bxqhQyHCtXAwYRh0wUrx6Mp4/BNXgkLoJmdYMmWi+V+Pypw79Q6iQhxA8KFMHqLBITQJV2gKMA==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-reduce-initial@7.0.8: - resolution: {integrity: sha512-VeVRmbgpgTZuRcDQdqnsB4iYTeS2dBRV07UdwK6V3x61F1xTQ2pgIzHBIR4rQYRlXRNKBTGYYhEL1eNA7w9vaQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-reduce-initial@8.0.0: + resolution: {integrity: sha512-DChcE9d528AKrlpCTHjhsAiOsWCk4H9ApHPS1QqRT3praObWTiWyn6W1UddGpc46K9LQnHwUu4YwaPUukGtXVA==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-reduce-transforms@7.0.2: - resolution: {integrity: sha512-OV5P9hMnf7kEkeXVXyS5ESqxbIls7a3TqFymUAV5JICO/9YCBEU+QQhQjZiDHaLwFdV7/CL481kVeBUk5FdY3w==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-reduce-transforms@8.0.0: + resolution: {integrity: sha512-cLZT0som7vvumQT9XQCnSKOSnRinNQZd1Hm+J723Ney13E8CIydDhw6JwzsjPtgnYThTqn9Q45906gz6wxaAsw==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 postcss-selector-parser@7.1.1: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} - postcss-svgo@7.1.2: - resolution: {integrity: sha512-ixExc8m+/68yuSYQzV/1DgtTup/7nI2dN9eiDS5GMRUzeCH4q9UcqeZPwcSVhdf8ay9fRwXDUHwcY5/XzQSszQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >= 18} + postcss-svgo@8.0.0: + resolution: {integrity: sha512-Q2fMSYEiNE1ioDc/3sxvI24NdgA/MJno2XLNpOxgv8aCcJbym8mZY10/lDY5+AWCIc3Aiqzy2Wcp9/zaIXBZgQ==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 - postcss-unique-selectors@7.0.6: - resolution: {integrity: sha512-cDxnYw1QuBMW5w3svZ0BlYF0IA4Amr+1JoTLXzu6vDFPNwohN2QU+sPZNx15b930LR7ce+/600h28/cYoxO9vw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + postcss-unique-selectors@8.0.0: + resolution: {integrity: sha512-iObuolUX+ITJfMU2QQFQdh31JgSjNLPNjVs6YGAqBHvOvAWXMMNget6donQl83aQaeS32i5XeKZURUW/WBxIUw==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.10: - resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} + postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} - postgres-bytea@1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} engines: {node: '>=0.10.0'} postgres-date@1.0.7: @@ -8612,8 +8483,8 @@ packages: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} - probe-image-size@7.2.3: - resolution: {integrity: sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==} + probe-image-size@7.3.0: + resolution: {integrity: sha512-7CaDeBwiAbh6ohXsvLbAZhO7wzsZAmaevfxe39qvCwRh8LyaZfDlBGGLU1CCTgrTLtCOdwBBhjOrIHaIIimHfQ==} proc-log@6.1.0: resolution: {integrity: sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==} @@ -8643,10 +8514,6 @@ packages: promise-limit@2.7.0: resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} - promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} - promise@7.3.1: resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} @@ -8681,8 +8548,8 @@ packages: pug-attrs@3.0.0: resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==} - pug-code-gen@3.0.3: - resolution: {integrity: sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==} + pug-code-gen@3.0.4: + resolution: {integrity: sha512-6okWYIKdasTyXICyEtvobmTZAVX57JkzgzIi4iRJlin8kmhG+Xry2dsus+Mun/nGCn6F2U49haHI5mkELXB14g==} pug-error@2.1.0: resolution: {integrity: sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==} @@ -8711,11 +8578,11 @@ packages: pug-walk@2.0.0: resolution: {integrity: sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==} - pug@3.0.3: - resolution: {integrity: sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==} + pug@3.0.4: + resolution: {integrity: sha512-kFfq5mMzrS7+wrl5pLJzZEzemx34OQ0w4SARfhy/3yxTlhbstsudDwJzhf1hP02yHzbjoVMSXUj/Sz6RNfMyXg==} - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} @@ -8747,8 +8614,12 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - qs@6.14.1: - resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} + qs@6.14.2: + resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} + engines: {node: '>=0.6'} + + qs@6.15.1: + resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} engines: {node: '>=0.6'} queue-lit@1.5.2: @@ -8780,8 +8651,8 @@ packages: ratelimiter@3.4.1: resolution: {integrity: sha512-5FJbRW/Jkkdk29ksedAfWFkQkhbUrMx3QJGwMKAypeIiQf4yrLW+gtPKZiaWt4zPrtw1uGufOjGO7UGM6VllsQ==} - raw-body@3.0.1: - resolution: {integrity: sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} rdf-canonize@5.0.0: @@ -8796,14 +8667,14 @@ packages: peerDependencies: typescript: '>= 4.3.x' - react-docgen@8.0.2: - resolution: {integrity: sha512-+NRMYs2DyTP4/tqWz371Oo50JqmWltR1h2gcdgUMAWZJIAvrd0/SqlCfx7tpzpl/s36rzw6qH2MjoNrxtRNYhA==} + react-docgen@8.0.3: + resolution: {integrity: sha512-aEZ9qP+/M+58x2qgfSFEWH1BxLyHe5+qkLNJOZQb5iGS017jpbRnoKhNRrXPeA6RfBrZO5wZrT9DMC1UqE1f1w==} engines: {node: ^20.9.0 || >=22} - react-dom@19.2.5: - resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} peerDependencies: - react: ^19.2.5 + react: ^19.2.6 react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -8811,8 +8682,8 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react@19.2.5: - resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} engines: {node: '>=0.10.0'} read-pkg-up@7.0.1: @@ -8880,8 +8751,8 @@ packages: regex-utilities@2.3.0: resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - regex@6.0.1: - resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} @@ -8927,8 +8798,13 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.6: + resolution: {integrity: sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==} engines: {node: '>= 0.4'} hasBin: true @@ -8936,20 +8812,16 @@ packages: resolution: {integrity: sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==} engines: {node: '>=20'} - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} ret@0.5.0: resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} engines: {node: '>=10'} - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - - rettime@0.11.7: - resolution: {integrity: sha512-DoAm1WjR1eH7z8sHPtvvUMIZh4/CSKkGCz6CxPqOrEAnOGtOuHSnSE9OC+razqxKuf4ub7pAYyl/vZV0vGs5tg==} + rettime@0.11.11: + resolution: {integrity: sha512-ILJRqVWBCTlg9r42fFgwVZx1gnFAcQF8mRoMkbgQfIrjEDf9nbBFDFx00oloOa+Q869FUtaYDXZvEfnecQSCoQ==} reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} @@ -8968,18 +8840,18 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rolldown@1.0.0-rc.15: - resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==} + rolldown@1.0.0: + resolution: {integrity: sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rolldown@1.0.0-rc.17: - resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} + rolldown@1.0.0-rc.18: + resolution: {integrity: sha512-phmyKBpuBdRYDf4hgyynGAYn/rDDe+iZXKVJ7WX5b1zQzpLkP5oJRPGsfJuHdzPMlyyEO/4sPW6yfSx2gf7lVg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.60.2: - resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==} + rollup@4.60.3: + resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -9000,8 +8872,8 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} engines: {node: '>=0.4'} safe-buffer@5.1.2: @@ -9018,8 +8890,9 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} - safe-regex2@5.0.0: - resolution: {integrity: sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==} + safe-regex2@5.1.1: + resolution: {integrity: sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==} + hasBin: true safe-stable-stringify@2.5.0: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} @@ -9153,14 +9026,10 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - sax@1.5.0: - resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -9186,19 +9055,19 @@ packages: engines: {node: '>=10'} hasBin: true - send@1.2.0: - resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} - serve-static@2.2.0: - resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-cookie-parser@2.7.1: - resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} set-cookie-parser@3.1.0: resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} @@ -9242,8 +9111,8 @@ packages: resolution: {integrity: sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==} engines: {node: '>=20'} - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} side-channel-map@1.0.1: @@ -9370,31 +9239,19 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - slice-ansi@3.0.0: - resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} - engines: {node: '>=8'} + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} - slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} + slice-ansi@8.0.0: + resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} + engines: {node: '>=20'} slick@1.12.2: resolution: {integrity: sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==} - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - socks-proxy-agent@8.0.5: - resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} - engines: {node: '>= 14'} - - socks@2.8.7: - resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - - sonic-boom@4.2.0: - resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} @@ -9419,8 +9276,8 @@ packages: spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.22: - resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + spdx-license-ids@3.0.23: + resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} @@ -9441,10 +9298,6 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - ssri@13.0.0: - resolution: {integrity: sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==} - engines: {node: ^20.17.0 || >=22.9.0} - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -9456,23 +9309,19 @@ packages: engines: {node: ^22 || >=24} hasBin: true - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - std-env@4.0.0: - resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640: - resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640} + resolution: {gitHosted: true, tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640} version: 0.0.0 peerDependencies: '@storybook/blocks': ^7.0.0-rc.4 @@ -9490,14 +9339,17 @@ packages: react-dom: optional: true - storybook@10.3.5: - resolution: {integrity: sha512-uBSZu/GZa9aEIW3QMGvdQPMZWhGxSe4dyRWU8B3/Vd47Gy/XLC7tsBxRr13txmmPOEDHZR94uLuq0H50fvuqBw==} + storybook@10.3.6: + resolution: {integrity: sha512-vbSz7g/1rGMC1uAULqMZjALkIuLu2QABqfhRYhyr/11kzyesi+vAmwyJLukZP1FfecxGOgMwOh6GS0YsGpHAvQ==} hasBin: true peerDependencies: prettier: ^2 || ^3 + vite-plus: ^0.1.15 peerDependenciesMeta: prettier: optional: true + vite-plus: + optional: true stream-browserify@3.0.0: resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} @@ -9509,8 +9361,8 @@ packages: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} - streamx@2.23.0: - resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + streamx@2.25.0: + resolution: {integrity: sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==} strict-event-emitter-types@2.0.0: resolution: {integrity: sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==} @@ -9534,6 +9386,10 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} + string-width@8.2.1: + resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} + engines: {node: '>=20'} + string.prototype.trim@1.2.10: resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} @@ -9562,8 +9418,8 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.2: - resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-bom@3.0.0: @@ -9601,11 +9457,11 @@ packages: resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} engines: {node: '>=18'} - stylehacks@7.0.10: - resolution: {integrity: sha512-sRJ7klmhe/Fl5woJcbJUa2qP1Ueffsl1CQI4ePvqXLkZmcIuAt09aP9uT/FOFPqXh9Rh8M5UkgEnwTdTKn/Aag==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + stylehacks@8.0.0: + resolution: {integrity: sha512-sWyjaJvBqHoVKYPbQ8JRvrGSPaYWtWrJsU+fGVtwKB1GE1rRPu3rC7T6UCuXLoL00Dwb+tsHe2T904r8Vnsx8w==} + engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.14 superagent@10.3.0: resolution: {integrity: sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==} @@ -9644,9 +9500,6 @@ packages: engines: {node: '>=16'} hasBin: true - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - sync-child-process@1.0.2: resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} engines: {node: '>=16.0.0'} @@ -9655,8 +9508,8 @@ packages: resolution: {integrity: sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==} engines: {node: '>=16.0.0'} - systeminformation@5.31.5: - resolution: {integrity: sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ==} + systeminformation@5.31.6: + resolution: {integrity: sha512-Uv2b2uGGM6ns+26czgW2cYRabYdnswM0ddSOOlryHOaelzsmDSet1iM/NT7VOYxW8x/BW+HkY+b1Ve2pLTSGSA==} engines: {node: '>=8.0.0'} os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true @@ -9665,35 +9518,39 @@ packages: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} - tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + tar-stream@3.2.0: + resolution: {integrity: sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==} tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - tar@7.5.13: - resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} + tar@7.5.14: + resolution: {integrity: sha512-/7sHKgQO3JLP9ESlwTYUUftHUadOURUqq23xs1vjcnp8Vss6k0wCfzulyEtk5g91pjvnuriimGlyG7k6msrzRw==} engines: {node: '>=18'} taskkill@5.0.0: resolution: {integrity: sha512-+HRtZ40Vc+6YfCDWCeAsixwxJgMbPY4HHuTgzPYH3JXvqHWUlsCfy+ylXlAKhFNcuLp4xVeWeFBUhDk+7KYUvQ==} engines: {node: '>=14.16'} - terser@5.46.2: - resolution: {integrity: sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==} + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} + + terser@5.47.1: + resolution: {integrity: sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==} engines: {node: '>=10'} hasBin: true - text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + text-decoder@1.2.7: + resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} textarea-caret@3.1.0: resolution: {integrity: sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==} - thread-stream@3.1.0: - resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + thread-stream@4.0.0: + resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} + engines: {node: '>=20'} three@0.184.0: resolution: {integrity: sha512-wtTRjG92pM5eUg/KuUnHsqSAlPM296brTOcLgMRqEeylYTh/CdtvKUvCyyCQTzFuStieWxvZb8mVTMvdPyUpxg==} @@ -9705,9 +9562,6 @@ packages: throttleit@1.0.1: resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==} - through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -9717,8 +9571,8 @@ packages: tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} tinyglobby@0.2.16: @@ -9748,15 +9602,15 @@ packages: tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} - tldts-core@7.0.18: - resolution: {integrity: sha512-jqJC13oP4FFAahv4JT/0WTDrCF9Okv7lpKtOZUGPLiAnNbACcSg8Y8T+Z9xthOmRBqi/Sob4yi0TE0miRCvF7Q==} + tldts-core@7.0.30: + resolution: {integrity: sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==} tldts@6.1.86: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true - tldts@7.0.18: - resolution: {integrity: sha512-lCcgTAgMxQ1JKOWrVGo6E69Ukbnx4Gc1wiYLRf6J5NN4HRYJtCby1rPF8rkQ4a6qqoFBK5dvjJ1zJ0F7VfDSvw==} + tldts@7.0.30: + resolution: {integrity: sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==} hasBin: true tmp@0.2.5: @@ -9804,10 +9658,6 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - tr46@6.0.0: - resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} - engines: {node: '>=20'} - tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -9835,8 +9685,8 @@ packages: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} - ts-essentials@10.1.1: - resolution: {integrity: sha512-4aTB7KLHKmUvkjNj8V+EdnmuVTiECzn3K+zIbRthumvHu+j44x3w63xpfs0JL3NGIzGXqoQ7AV591xHO+XrOTw==} + ts-essentials@10.2.0: + resolution: {integrity: sha512-z9FlLywg0XEV46Ws1FwYN4NZDMr9qAe38lTTtgVBqzhhyEgwrnCUkFe4MEqnvar1kY1kFEnlkp56bxn2g0V+UA==} peerDependencies: typescript: '>=4.5.0' peerDependenciesMeta: @@ -9846,8 +9696,8 @@ packages: ts-map@1.0.3: resolution: {integrity: sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==} - tsc-alias@1.8.16: - resolution: {integrity: sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==} + tsc-alias@1.8.17: + resolution: {integrity: sha512-EIduCZHqbNwPm8BZYfq1aD7BQ697A4h6uSGMOFQfYGoQwfrYFTKwYfy9Bv42YxHkduVBcn9Zx0DkX111DKskyg==} engines: {node: '>=16.20.2'} hasBin: true @@ -10011,8 +9861,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} uid2@0.0.4: resolution: {integrity: sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==} @@ -10039,8 +9889,8 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@6.22.0: - resolution: {integrity: sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==} + undici@6.25.0: + resolution: {integrity: sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==} engines: {node: '>=18.17'} undici@7.25.0: @@ -10054,14 +9904,6 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} - unique-filename@5.0.0: - resolution: {integrity: sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==} - engines: {node: ^20.17.0 || >=22.9.0} - - unique-slug@6.0.0: - resolution: {integrity: sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==} - engines: {node: ^20.17.0 || >=22.9.0} - unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} @@ -10074,8 +9916,8 @@ packages: unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} @@ -10109,6 +9951,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + uri-js-replace@1.0.1: + resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -10132,6 +9977,10 @@ packages: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} + hasBin: true + uuid@14.0.0: resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} hasBin: true @@ -10195,13 +10044,13 @@ packages: vite-plugin-turbosnap@1.0.3: resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==} - vite@8.0.10: - resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==} + vite@8.0.11: + resolution: {integrity: sha512-Jz1mxtUBR5xTT65VOdJZUUeoyLtqljmFkiUXhPTLZka3RDc9vpi/xXkyrnsdRcm2lIi3l3GPMnAidTsEGIj3Ow==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 + '@vitejs/devtools': ^0.1.18 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -10328,8 +10177,8 @@ packages: vue-component-type-helpers@2.2.12: resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} - vue-component-type-helpers@3.2.7: - resolution: {integrity: sha512-+gPp5YGmhfsj1IN+xUo7y0fb4clfnOiiUA39y07yW1VzCRjzVgwLbtmdWlghh7mXrPsEaYc7rrIir/HT6C8vYQ==} + vue-component-type-helpers@3.2.8: + resolution: {integrity: sha512-9689efAXhN/EV86plgkL/XFiJSXhGtWPG6JDboZ+QnjlUWUUQrQ0ILKQtw4iQsuwIwu5k6Aw+JnehDe7161e7A==} vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} @@ -10358,24 +10207,20 @@ packages: peerDependencies: vue: '>=2' - vue-tsc@3.2.7: - resolution: {integrity: sha512-zc1tL3HoQni1zGTGrwBVRQb7rGP5SWdu/m4rGB6JcnAC5MT5LFZIxF7Y+EJEnt4hGF23d60rXH7gRjHGb5KQQQ==} + vue-tsc@3.2.8: + resolution: {integrity: sha512-27vTLJ6Q2370obOd0PFYoYoKnmXJ521uUIedrs3Zhhhg/8YG10VOCMmwt+JQslatpAMTDbnWiitLnoD5VlIvog==} hasBin: true peerDependencies: typescript: '>=5.0.0' - vue@3.5.33: - resolution: {integrity: sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==} + vue@3.5.34: + resolution: {integrity: sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} - wait-on@9.0.5: resolution: {integrity: sha512-qgnbHDfDTRIp73ANEJNRW/7kn8CrDUcvZz18xotJQku/P4saTGkbIzvnMZebPmVvVNUiRq1qWAPyqCH+W4H8KA==} engines: {node: '>=20.0.0'} @@ -10405,10 +10250,6 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webidl-conversions@8.0.1: - resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} - engines: {node: '>=20'} - webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} @@ -10425,14 +10266,6 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-mimetype@5.0.0: - resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} - engines: {node: '>=20'} - - whatwg-url@15.1.0: - resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} - engines: {node: '>=20'} - whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -10451,8 +10284,8 @@ packages: which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} engines: {node: '>= 0.4'} which@1.3.1: @@ -10464,8 +10297,8 @@ packages: engines: {node: '>= 8'} hasBin: true - which@6.0.0: - resolution: {integrity: sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==} + which@6.0.1: + resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} engines: {node: ^20.17.0 || >=22.9.0} hasBin: true @@ -10531,10 +10364,6 @@ packages: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - xml2js@0.5.0: resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} engines: {node: '>=4.0.0'} @@ -10543,9 +10372,6 @@ packages: resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} engines: {node: '>=4.0'} - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -10622,9 +10448,6 @@ packages: snapshots: - '@acemir/cssom@0.9.31': - optional: true - '@adobe/css-tools@4.4.4': {} '@analytics/cookie-utils@0.2.14': @@ -10668,27 +10491,6 @@ snapshots: '@types/json-schema': 7.0.15 js-yaml: 4.1.1 - '@asamuzakjp/css-color@4.1.2': - dependencies: - '@csstools/css-calc': 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - lru-cache: 11.2.5 - optional: true - - '@asamuzakjp/dom-selector@6.7.8': - dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.1.0 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.5 - optional: true - - '@asamuzakjp/nwsapi@2.3.9': - optional: true - '@aws-crypto/crc32@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 @@ -10706,7 +10508,7 @@ snapshots: '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.973.8 - '@aws-sdk/util-locate-window': 3.893.0 + '@aws-sdk/util-locate-window': 3.965.5 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -10716,7 +10518,7 @@ snapshots: '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.973.8 - '@aws-sdk/util-locate-window': 3.893.0 + '@aws-sdk/util-locate-window': 3.965.5 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -10736,29 +10538,29 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.1037.0': + '@aws-sdk/client-s3@3.1044.0': dependencies: '@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.974.5 - '@aws-sdk/credential-provider-node': 3.972.36 + '@aws-sdk/core': 3.974.8 + '@aws-sdk/credential-provider-node': 3.972.39 '@aws-sdk/middleware-bucket-endpoint': 3.972.10 '@aws-sdk/middleware-expect-continue': 3.972.10 - '@aws-sdk/middleware-flexible-checksums': 3.974.13 + '@aws-sdk/middleware-flexible-checksums': 3.974.16 '@aws-sdk/middleware-host-header': 3.972.10 '@aws-sdk/middleware-location-constraint': 3.972.10 '@aws-sdk/middleware-logger': 3.972.10 '@aws-sdk/middleware-recursion-detection': 3.972.11 - '@aws-sdk/middleware-sdk-s3': 3.972.34 + '@aws-sdk/middleware-sdk-s3': 3.972.37 '@aws-sdk/middleware-ssec': 3.972.10 - '@aws-sdk/middleware-user-agent': 3.972.35 + '@aws-sdk/middleware-user-agent': 3.972.38 '@aws-sdk/region-config-resolver': 3.972.13 - '@aws-sdk/signature-v4-multi-region': 3.996.22 + '@aws-sdk/signature-v4-multi-region': 3.996.25 '@aws-sdk/types': 3.973.8 '@aws-sdk/util-endpoints': 3.996.8 '@aws-sdk/util-user-agent-browser': 3.972.10 - '@aws-sdk/util-user-agent-node': 3.973.21 + '@aws-sdk/util-user-agent-node': 3.973.24 '@smithy/config-resolver': 4.4.17 '@smithy/core': 3.23.17 '@smithy/eventstream-serde-browser': 4.2.14 @@ -10772,7 +10574,7 @@ snapshots: '@smithy/md5-js': 4.2.14 '@smithy/middleware-content-length': 4.2.14 '@smithy/middleware-endpoint': 4.4.32 - '@smithy/middleware-retry': 4.5.5 + '@smithy/middleware-retry': 4.5.7 '@smithy/middleware-serde': 4.2.20 '@smithy/middleware-stack': 4.2.14 '@smithy/node-config-provider': 4.3.14 @@ -10788,18 +10590,18 @@ snapshots: '@smithy/util-defaults-mode-node': 4.2.54 '@smithy/util-endpoints': 3.4.2 '@smithy/util-middleware': 4.2.14 - '@smithy/util-retry': 4.3.4 + '@smithy/util-retry': 4.3.8 '@smithy/util-stream': 4.5.25 '@smithy/util-utf8': 4.2.2 - '@smithy/util-waiter': 4.2.16 + '@smithy/util-waiter': 4.3.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.974.5': + '@aws-sdk/core@3.974.8': dependencies: '@aws-sdk/types': 3.973.8 - '@aws-sdk/xml-builder': 3.972.19 + '@aws-sdk/xml-builder': 3.972.22 '@smithy/core': 3.23.17 '@smithy/node-config-provider': 4.3.14 '@smithy/property-provider': 4.2.14 @@ -10809,7 +10611,7 @@ snapshots: '@smithy/types': 4.14.1 '@smithy/util-base64': 4.3.2 '@smithy/util-middleware': 4.2.14 - '@smithy/util-retry': 4.3.4 + '@smithy/util-retry': 4.3.8 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 @@ -10818,17 +10620,17 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.972.31': + '@aws-sdk/credential-provider-env@3.972.34': dependencies: - '@aws-sdk/core': 3.974.5 + '@aws-sdk/core': 3.974.8 '@aws-sdk/types': 3.973.8 '@smithy/property-provider': 4.2.14 '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.972.33': + '@aws-sdk/credential-provider-http@3.972.36': dependencies: - '@aws-sdk/core': 3.974.5 + '@aws-sdk/core': 3.974.8 '@aws-sdk/types': 3.973.8 '@smithy/fetch-http-handler': 5.3.17 '@smithy/node-http-handler': 4.6.1 @@ -10839,16 +10641,16 @@ snapshots: '@smithy/util-stream': 4.5.25 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.972.35': + '@aws-sdk/credential-provider-ini@3.972.38': dependencies: - '@aws-sdk/core': 3.974.5 - '@aws-sdk/credential-provider-env': 3.972.31 - '@aws-sdk/credential-provider-http': 3.972.33 - '@aws-sdk/credential-provider-login': 3.972.35 - '@aws-sdk/credential-provider-process': 3.972.31 - '@aws-sdk/credential-provider-sso': 3.972.35 - '@aws-sdk/credential-provider-web-identity': 3.972.35 - '@aws-sdk/nested-clients': 3.997.3 + '@aws-sdk/core': 3.974.8 + '@aws-sdk/credential-provider-env': 3.972.34 + '@aws-sdk/credential-provider-http': 3.972.36 + '@aws-sdk/credential-provider-login': 3.972.38 + '@aws-sdk/credential-provider-process': 3.972.34 + '@aws-sdk/credential-provider-sso': 3.972.38 + '@aws-sdk/credential-provider-web-identity': 3.972.38 + '@aws-sdk/nested-clients': 3.997.6 '@aws-sdk/types': 3.973.8 '@smithy/credential-provider-imds': 4.2.14 '@smithy/property-provider': 4.2.14 @@ -10858,10 +10660,10 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-login@3.972.35': + '@aws-sdk/credential-provider-login@3.972.38': dependencies: - '@aws-sdk/core': 3.974.5 - '@aws-sdk/nested-clients': 3.997.3 + '@aws-sdk/core': 3.974.8 + '@aws-sdk/nested-clients': 3.997.6 '@aws-sdk/types': 3.973.8 '@smithy/property-provider': 4.2.14 '@smithy/protocol-http': 5.3.14 @@ -10871,14 +10673,14 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.972.36': + '@aws-sdk/credential-provider-node@3.972.39': dependencies: - '@aws-sdk/credential-provider-env': 3.972.31 - '@aws-sdk/credential-provider-http': 3.972.33 - '@aws-sdk/credential-provider-ini': 3.972.35 - '@aws-sdk/credential-provider-process': 3.972.31 - '@aws-sdk/credential-provider-sso': 3.972.35 - '@aws-sdk/credential-provider-web-identity': 3.972.35 + '@aws-sdk/credential-provider-env': 3.972.34 + '@aws-sdk/credential-provider-http': 3.972.36 + '@aws-sdk/credential-provider-ini': 3.972.38 + '@aws-sdk/credential-provider-process': 3.972.34 + '@aws-sdk/credential-provider-sso': 3.972.38 + '@aws-sdk/credential-provider-web-identity': 3.972.38 '@aws-sdk/types': 3.973.8 '@smithy/credential-provider-imds': 4.2.14 '@smithy/property-provider': 4.2.14 @@ -10888,20 +10690,20 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-process@3.972.31': + '@aws-sdk/credential-provider-process@3.972.34': dependencies: - '@aws-sdk/core': 3.974.5 + '@aws-sdk/core': 3.974.8 '@aws-sdk/types': 3.973.8 '@smithy/property-provider': 4.2.14 '@smithy/shared-ini-file-loader': 4.4.9 '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.972.35': + '@aws-sdk/credential-provider-sso@3.972.38': dependencies: - '@aws-sdk/core': 3.974.5 - '@aws-sdk/nested-clients': 3.997.3 - '@aws-sdk/token-providers': 3.1036.0 + '@aws-sdk/core': 3.974.8 + '@aws-sdk/nested-clients': 3.997.6 + '@aws-sdk/token-providers': 3.1041.0 '@aws-sdk/types': 3.973.8 '@smithy/property-provider': 4.2.14 '@smithy/shared-ini-file-loader': 4.4.9 @@ -10910,10 +10712,10 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.972.35': + '@aws-sdk/credential-provider-web-identity@3.972.38': dependencies: - '@aws-sdk/core': 3.974.5 - '@aws-sdk/nested-clients': 3.997.3 + '@aws-sdk/core': 3.974.8 + '@aws-sdk/nested-clients': 3.997.6 '@aws-sdk/types': 3.973.8 '@smithy/property-provider': 4.2.14 '@smithy/shared-ini-file-loader': 4.4.9 @@ -10922,9 +10724,9 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/lib-storage@3.1037.0(@aws-sdk/client-s3@3.1037.0)': + '@aws-sdk/lib-storage@3.1044.0(@aws-sdk/client-s3@3.1044.0)': dependencies: - '@aws-sdk/client-s3': 3.1037.0 + '@aws-sdk/client-s3': 3.1044.0 '@smithy/middleware-endpoint': 4.4.32 '@smithy/protocol-http': 5.3.14 '@smithy/smithy-client': 4.12.13 @@ -10951,12 +10753,12 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-flexible-checksums@3.974.13': + '@aws-sdk/middleware-flexible-checksums@3.974.16': dependencies: '@aws-crypto/crc32': 5.2.0 '@aws-crypto/crc32c': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.974.5 + '@aws-sdk/core': 3.974.8 '@aws-sdk/crc64-nvme': 3.972.7 '@aws-sdk/types': 3.973.8 '@smithy/is-array-buffer': 4.2.2 @@ -10990,14 +10792,14 @@ snapshots: '@aws-sdk/middleware-recursion-detection@3.972.11': dependencies: '@aws-sdk/types': 3.973.8 - '@aws/lambda-invoke-store': 0.2.2 + '@aws/lambda-invoke-store': 0.2.4 '@smithy/protocol-http': 5.3.14 '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.972.34': + '@aws-sdk/middleware-sdk-s3@3.972.37': dependencies: - '@aws-sdk/core': 3.974.5 + '@aws-sdk/core': 3.974.8 '@aws-sdk/types': 3.973.8 '@aws-sdk/util-arn-parser': 3.972.3 '@smithy/core': 3.23.17 @@ -11018,32 +10820,32 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.972.35': + '@aws-sdk/middleware-user-agent@3.972.38': dependencies: - '@aws-sdk/core': 3.974.5 + '@aws-sdk/core': 3.974.8 '@aws-sdk/types': 3.973.8 '@aws-sdk/util-endpoints': 3.996.8 '@smithy/core': 3.23.17 '@smithy/protocol-http': 5.3.14 '@smithy/types': 4.14.1 - '@smithy/util-retry': 4.3.4 + '@smithy/util-retry': 4.3.8 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.997.3': + '@aws-sdk/nested-clients@3.997.6': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.974.5 + '@aws-sdk/core': 3.974.8 '@aws-sdk/middleware-host-header': 3.972.10 '@aws-sdk/middleware-logger': 3.972.10 '@aws-sdk/middleware-recursion-detection': 3.972.11 - '@aws-sdk/middleware-user-agent': 3.972.35 + '@aws-sdk/middleware-user-agent': 3.972.38 '@aws-sdk/region-config-resolver': 3.972.13 - '@aws-sdk/signature-v4-multi-region': 3.996.22 + '@aws-sdk/signature-v4-multi-region': 3.996.25 '@aws-sdk/types': 3.973.8 '@aws-sdk/util-endpoints': 3.996.8 '@aws-sdk/util-user-agent-browser': 3.972.10 - '@aws-sdk/util-user-agent-node': 3.973.21 + '@aws-sdk/util-user-agent-node': 3.973.24 '@smithy/config-resolver': 4.4.17 '@smithy/core': 3.23.17 '@smithy/fetch-http-handler': 5.3.17 @@ -11051,7 +10853,7 @@ snapshots: '@smithy/invalid-dependency': 4.2.14 '@smithy/middleware-content-length': 4.2.14 '@smithy/middleware-endpoint': 4.4.32 - '@smithy/middleware-retry': 4.5.5 + '@smithy/middleware-retry': 4.5.7 '@smithy/middleware-serde': 4.2.20 '@smithy/middleware-stack': 4.2.14 '@smithy/node-config-provider': 4.3.14 @@ -11067,7 +10869,7 @@ snapshots: '@smithy/util-defaults-mode-node': 4.2.54 '@smithy/util-endpoints': 3.4.2 '@smithy/util-middleware': 4.2.14 - '@smithy/util-retry': 4.3.4 + '@smithy/util-retry': 4.3.8 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 transitivePeerDependencies: @@ -11081,19 +10883,19 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.996.22': + '@aws-sdk/signature-v4-multi-region@3.996.25': dependencies: - '@aws-sdk/middleware-sdk-s3': 3.972.34 + '@aws-sdk/middleware-sdk-s3': 3.972.37 '@aws-sdk/types': 3.973.8 '@smithy/protocol-http': 5.3.14 '@smithy/signature-v4': 5.3.14 '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/token-providers@3.1036.0': + '@aws-sdk/token-providers@3.1041.0': dependencies: - '@aws-sdk/core': 3.974.5 - '@aws-sdk/nested-clients': 3.997.3 + '@aws-sdk/core': 3.974.8 + '@aws-sdk/nested-clients': 3.997.6 '@aws-sdk/types': 3.973.8 '@smithy/property-provider': 4.2.14 '@smithy/shared-ini-file-loader': 4.4.9 @@ -11119,7 +10921,7 @@ snapshots: '@smithy/util-endpoints': 3.4.2 tslib: 2.8.1 - '@aws-sdk/util-locate-window@3.893.0': + '@aws-sdk/util-locate-window@3.965.5': dependencies: tslib: 2.8.1 @@ -11127,44 +10929,45 @@ snapshots: dependencies: '@aws-sdk/types': 3.973.8 '@smithy/types': 4.14.1 - bowser: 2.12.1 + bowser: 2.14.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.973.21': + '@aws-sdk/util-user-agent-node@3.973.24': dependencies: - '@aws-sdk/middleware-user-agent': 3.972.35 + '@aws-sdk/middleware-user-agent': 3.972.38 '@aws-sdk/types': 3.973.8 '@smithy/node-config-provider': 4.3.14 '@smithy/types': 4.14.1 '@smithy/util-config-provider': 4.2.2 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.972.19': + '@aws-sdk/xml-builder@3.972.22': dependencies: + '@nodable/entities': 2.1.0 '@smithy/types': 4.14.1 - fast-xml-parser: 5.7.1 + fast-xml-parser: 5.7.2 tslib: 2.8.1 - '@aws/lambda-invoke-store@0.2.2': {} + '@aws/lambda-invoke-store@0.2.4': {} - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.5': {} + '@babel/compat-data@7.29.3': {} - '@babel/core@7.28.5': + '@babel/core@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.29.2 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.3 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 @@ -11175,17 +10978,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.5': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.27.2': + '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.5 + '@babel/compat-data': 7.29.3 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.2 lru-cache: 5.1.1 @@ -11193,19 +10996,19 @@ snapshots: '@babel/helper-globals@7.28.0': {} - '@babel/helper-module-imports@7.27.1': + '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color @@ -11215,30 +11018,32 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.28.4': + '@babel/helpers@7.29.2': dependencies: - '@babel/template': 7.27.2 + '@babel/template': 7.28.6 '@babel/types': 7.29.0 - '@babel/parser@7.29.2': + '@babel/parser@7.29.3': dependencies: '@babel/types': 7.29.0 '@babel/runtime@7.28.6': {} - '@babel/template@7.27.2': + '@babel/runtime@7.29.2': {} + + '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.29.2 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 - '@babel/traverse@7.28.5': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.2 - '@babel/template': 7.27.2 + '@babel/parser': 7.29.3 + '@babel/template': 7.28.6 '@babel/types': 7.29.0 debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: @@ -11253,11 +11058,11 @@ snapshots: '@borewit/text-codec@0.2.2': {} - '@bufbuild/protobuf@2.11.0': {} + '@bufbuild/protobuf@2.12.0': {} '@canvas/image-data@1.1.0': {} - '@colordx/core@5.4.2': {} + '@colordx/core@5.4.3': {} '@cropper/element-canvas@2.1.1': dependencies: @@ -11325,34 +11130,6 @@ snapshots: '@cropper/utils@2.1.1': {} - '@csstools/color-helpers@6.0.1': - optional: true - - '@csstools/css-calc@3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - optional: true - - '@csstools/css-color-parser@4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/color-helpers': 6.0.1 - '@csstools/css-calc': 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - optional: true - - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-tokenizer': 4.0.0 - optional: true - - '@csstools/css-syntax-patches-for-csstree@1.0.26': - optional: true - - '@csstools/css-tokenizer@4.0.0': - optional: true - '@cypress/request@3.0.10': dependencies: aws-sign2: 0.7.0 @@ -11368,7 +11145,7 @@ snapshots: json-stringify-safe: 5.0.1 mime-types: 2.1.35 performance-now: 2.1.0 - qs: 6.14.1 + qs: 6.14.2 safe-buffer: 5.2.1 tough-cookie: 5.1.2 tunnel-agent: 0.6.0 @@ -11381,10 +11158,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@digitalbazaar/http-client@4.2.0': + '@digitalbazaar/http-client@4.3.0': dependencies: - ky: 1.14.0 - undici: 6.22.0 + ky: 1.14.3 + undici: 6.25.0 '@emnapi/core@1.10.0': dependencies: @@ -11392,22 +11169,11 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/core@1.9.2': - dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true - '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.2': - dependencies: - tslib: 2.8.1 - optional: true - '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 @@ -11415,157 +11181,157 @@ snapshots: '@epic-web/invariant@1.0.0': {} - '@esbuild/aix-ppc64@0.27.4': + '@esbuild/aix-ppc64@0.27.7': optional: true '@esbuild/aix-ppc64@0.28.0': optional: true - '@esbuild/android-arm64@0.27.4': + '@esbuild/android-arm64@0.27.7': optional: true '@esbuild/android-arm64@0.28.0': optional: true - '@esbuild/android-arm@0.27.4': + '@esbuild/android-arm@0.27.7': optional: true '@esbuild/android-arm@0.28.0': optional: true - '@esbuild/android-x64@0.27.4': + '@esbuild/android-x64@0.27.7': optional: true '@esbuild/android-x64@0.28.0': optional: true - '@esbuild/darwin-arm64@0.27.4': + '@esbuild/darwin-arm64@0.27.7': optional: true '@esbuild/darwin-arm64@0.28.0': optional: true - '@esbuild/darwin-x64@0.27.4': + '@esbuild/darwin-x64@0.27.7': optional: true '@esbuild/darwin-x64@0.28.0': optional: true - '@esbuild/freebsd-arm64@0.27.4': + '@esbuild/freebsd-arm64@0.27.7': optional: true '@esbuild/freebsd-arm64@0.28.0': optional: true - '@esbuild/freebsd-x64@0.27.4': + '@esbuild/freebsd-x64@0.27.7': optional: true '@esbuild/freebsd-x64@0.28.0': optional: true - '@esbuild/linux-arm64@0.27.4': + '@esbuild/linux-arm64@0.27.7': optional: true '@esbuild/linux-arm64@0.28.0': optional: true - '@esbuild/linux-arm@0.27.4': + '@esbuild/linux-arm@0.27.7': optional: true '@esbuild/linux-arm@0.28.0': optional: true - '@esbuild/linux-ia32@0.27.4': + '@esbuild/linux-ia32@0.27.7': optional: true '@esbuild/linux-ia32@0.28.0': optional: true - '@esbuild/linux-loong64@0.27.4': + '@esbuild/linux-loong64@0.27.7': optional: true '@esbuild/linux-loong64@0.28.0': optional: true - '@esbuild/linux-mips64el@0.27.4': + '@esbuild/linux-mips64el@0.27.7': optional: true '@esbuild/linux-mips64el@0.28.0': optional: true - '@esbuild/linux-ppc64@0.27.4': + '@esbuild/linux-ppc64@0.27.7': optional: true '@esbuild/linux-ppc64@0.28.0': optional: true - '@esbuild/linux-riscv64@0.27.4': + '@esbuild/linux-riscv64@0.27.7': optional: true '@esbuild/linux-riscv64@0.28.0': optional: true - '@esbuild/linux-s390x@0.27.4': + '@esbuild/linux-s390x@0.27.7': optional: true '@esbuild/linux-s390x@0.28.0': optional: true - '@esbuild/linux-x64@0.27.4': + '@esbuild/linux-x64@0.27.7': optional: true '@esbuild/linux-x64@0.28.0': optional: true - '@esbuild/netbsd-arm64@0.27.4': + '@esbuild/netbsd-arm64@0.27.7': optional: true '@esbuild/netbsd-arm64@0.28.0': optional: true - '@esbuild/netbsd-x64@0.27.4': + '@esbuild/netbsd-x64@0.27.7': optional: true '@esbuild/netbsd-x64@0.28.0': optional: true - '@esbuild/openbsd-arm64@0.27.4': + '@esbuild/openbsd-arm64@0.27.7': optional: true '@esbuild/openbsd-arm64@0.28.0': optional: true - '@esbuild/openbsd-x64@0.27.4': + '@esbuild/openbsd-x64@0.27.7': optional: true '@esbuild/openbsd-x64@0.28.0': optional: true - '@esbuild/openharmony-arm64@0.27.4': + '@esbuild/openharmony-arm64@0.27.7': optional: true '@esbuild/openharmony-arm64@0.28.0': optional: true - '@esbuild/sunos-x64@0.27.4': + '@esbuild/sunos-x64@0.27.7': optional: true '@esbuild/sunos-x64@0.28.0': optional: true - '@esbuild/win32-arm64@0.27.4': + '@esbuild/win32-arm64@0.27.7': optional: true '@esbuild/win32-arm64@0.28.0': optional: true - '@esbuild/win32-ia32@0.27.4': + '@esbuild/win32-ia32@0.27.7': optional: true '@esbuild/win32-ia32@0.28.0': optional: true - '@esbuild/win32-x64@0.27.4': + '@esbuild/win32-x64@0.27.7': optional: true '@esbuild/win32-x64@0.28.0': @@ -11578,9 +11344,9 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@1.4.0(eslint@9.39.4)': + '@eslint/compat@2.0.5(eslint@9.39.4)': dependencies: - '@eslint/core': 0.16.0 + '@eslint/core': 1.2.1 optionalDependencies: eslint: 9.39.4 @@ -11596,17 +11362,17 @@ snapshots: dependencies: '@eslint/core': 0.17.0 - '@eslint/core@0.16.0': + '@eslint/core@0.17.0': dependencies: '@types/json-schema': 7.0.15 - '@eslint/core@0.17.0': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 '@eslint/eslintrc@3.3.5': dependencies: - ajv: 6.14.0 + ajv: 6.15.0 debug: 4.4.3(supports-color@10.2.2) espree: 10.4.0 globals: 14.0.0 @@ -11638,7 +11404,7 @@ snapshots: dependencies: ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) - fast-uri: 3.1.0 + fast-uri: 3.1.2 '@fastify/busboy@3.2.0': {} @@ -11647,7 +11413,7 @@ snapshots: fastify-plugin: 5.1.0 toad-cache: 3.7.0 - '@fastify/deepmerge@3.1.0': {} + '@fastify/deepmerge@3.2.1': {} '@fastify/error@4.2.0': {} @@ -11660,7 +11426,7 @@ snapshots: '@fastify/fast-json-stringify-compiler@5.0.3': dependencies: - fast-json-stringify: 6.1.1 + fast-json-stringify: 6.4.0 '@fastify/forwarded@3.0.1': {} @@ -11681,7 +11447,7 @@ snapshots: '@fastify/multipart@10.0.0': dependencies: '@fastify/busboy': 3.2.0 - '@fastify/deepmerge': 3.1.0 + '@fastify/deepmerge': 3.2.1 '@fastify/error': 4.2.0 fastify-plugin: 5.1.0 secure-json-parse: 4.1.0 @@ -11689,7 +11455,7 @@ snapshots: '@fastify/otel@0.18.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.212.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 minimatch: 10.2.5 @@ -11699,7 +11465,7 @@ snapshots: '@fastify/proxy-addr@5.1.0': dependencies: '@fastify/forwarded': 3.0.1 - ipaddr.js: 2.3.0 + ipaddr.js: 2.4.0 '@fastify/reply-from@12.6.2': dependencies: @@ -11726,11 +11492,11 @@ snapshots: content-disposition: 1.1.0 fastify-plugin: 5.1.0 fastq: 1.20.1 - glob: 13.0.1 + glob: 13.0.6 '@file-type/xml@0.4.4': dependencies: - sax: 1.5.0 + sax: 1.6.0 strtok3: 10.3.5 '@hapi/address@5.1.1': @@ -11751,7 +11517,7 @@ snapshots: '@hapi/pinpoint@2.0.1': {} - '@hapi/tlds@1.1.4': {} + '@hapi/tlds@1.1.6': {} '@hapi/topo@5.1.0': dependencies: @@ -11761,7 +11527,7 @@ snapshots: dependencies: '@hapi/hoek': 11.0.7 - '@hapi/wreck@18.1.0': + '@hapi/wreck@18.1.1': dependencies: '@hapi/boom': 10.0.1 '@hapi/bourne': 3.0.0 @@ -11769,13 +11535,18 @@ snapshots: '@hexagon/base64@1.1.28': {} - '@humanfs/core@0.19.1': {} + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/momoa@2.0.4': {} @@ -11890,26 +11661,24 @@ snapshots: dependencies: string-width: 5.1.2 string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@isaacs/cliui@9.0.0': {} - '@isaacs/fs-minipass@4.0.1': dependencies: - minipass: 7.1.2 + minipass: 7.1.3 '@jest/schemas@29.6.3': dependencies: - '@sinclair/typebox': 0.27.8 + '@sinclair/typebox': 0.27.10 - '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@5.9.3)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@5.9.3)(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))': dependencies: - glob: 13.0.1 + glob: 13.0.6 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) optionalDependencies: typescript: 5.9.3 @@ -11959,12 +11728,12 @@ snapshots: '@lukeed/ms@2.0.2': {} - '@mapbox/node-pre-gyp@1.0.9(encoding@0.1.13)': + '@mapbox/node-pre-gyp@1.0.9': dependencies: detect-libc: 2.1.2 https-proxy-agent: 5.0.1 make-dir: 3.1.0 - node-fetch: 2.7.0(encoding@0.1.13) + node-fetch: 2.7.0 nopt: 5.0.0 npmlog: 5.0.1 rimraf: 3.0.2 @@ -11977,11 +11746,11 @@ snapshots: '@mcaptcha/core-glue@0.1.0-alpha-5': {} - '@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.5)': + '@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.6)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 19.2.2 - react: 19.2.5 + '@types/react': 19.2.14 + react: 19.2.6 '@microsoft/api-extractor-model@7.33.8(@types/node@24.12.2)': dependencies: @@ -12000,9 +11769,9 @@ snapshots: '@rushstack/rig-package': 0.7.3 '@rushstack/terminal': 0.24.0(@types/node@24.12.2) '@rushstack/ts-command-line': 5.3.9(@types/node@24.12.2) - diff: 8.0.2 + diff: 8.0.4 minimatch: 10.2.3 - resolve: 1.22.11 + resolve: 1.22.12 semver: 7.7.4 source-map: 0.6.1 typescript: 5.9.3 @@ -12014,7 +11783,7 @@ snapshots: '@microsoft/tsdoc': 0.16.0 ajv: 8.18.0 jju: 1.4.0 - resolve: 1.22.11 + resolve: 1.22.12 '@microsoft/tsdoc@0.16.0': {} @@ -12026,15 +11795,15 @@ snapshots: '@misskey-dev/emoji-data@17.0.3': {} - '@misskey-dev/eslint-plugin@2.1.0(@eslint/compat@1.4.0(eslint@9.39.4))(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/eslint-plugin@8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4))(eslint@9.39.4)(globals@17.5.0)': + '@misskey-dev/eslint-plugin@2.1.0(@eslint/compat@2.0.5(eslint@9.39.4))(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4))(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3))(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4))(eslint@9.39.4)(globals@17.6.0)': dependencies: - '@eslint/compat': 1.4.0(eslint@9.39.4) - '@stylistic/eslint-plugin': 5.5.0(eslint@9.39.4) - '@typescript-eslint/eslint-plugin': 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/parser': 8.59.0(eslint@9.39.4)(typescript@5.9.3) + '@eslint/compat': 2.0.5(eslint@9.39.4) + '@stylistic/eslint-plugin': 5.10.0(eslint@9.39.4) + '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.2(eslint@9.39.4)(typescript@5.9.3) eslint: 9.39.4 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) - globals: 17.5.0 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4) + globals: 17.6.0 '@misskey-dev/sharp-read-bmp@1.2.0': dependencies: @@ -12072,7 +11841,7 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': optional: true - '@mswjs/interceptors@0.41.6': + '@mswjs/interceptors@0.41.8': dependencies: '@open-draft/deferred-promise': 2.2.0 '@open-draft/logger': 0.3.0 @@ -12081,65 +11850,58 @@ snapshots: outvariant: 1.4.3 strict-event-emitter: 0.5.1 - '@napi-rs/canvas-android-arm64@0.1.100': + '@napi-rs/canvas-android-arm64@1.0.0': optional: true - '@napi-rs/canvas-darwin-arm64@0.1.100': + '@napi-rs/canvas-darwin-arm64@1.0.0': optional: true - '@napi-rs/canvas-darwin-x64@0.1.100': + '@napi-rs/canvas-darwin-x64@1.0.0': optional: true - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.100': + '@napi-rs/canvas-linux-arm-gnueabihf@1.0.0': optional: true - '@napi-rs/canvas-linux-arm64-gnu@0.1.100': + '@napi-rs/canvas-linux-arm64-gnu@1.0.0': optional: true - '@napi-rs/canvas-linux-arm64-musl@0.1.100': + '@napi-rs/canvas-linux-arm64-musl@1.0.0': optional: true - '@napi-rs/canvas-linux-riscv64-gnu@0.1.100': + '@napi-rs/canvas-linux-riscv64-gnu@1.0.0': optional: true - '@napi-rs/canvas-linux-x64-gnu@0.1.100': + '@napi-rs/canvas-linux-x64-gnu@1.0.0': optional: true - '@napi-rs/canvas-linux-x64-musl@0.1.100': + '@napi-rs/canvas-linux-x64-musl@1.0.0': optional: true - '@napi-rs/canvas-win32-arm64-msvc@0.1.100': + '@napi-rs/canvas-win32-arm64-msvc@1.0.0': optional: true - '@napi-rs/canvas-win32-x64-msvc@0.1.100': + '@napi-rs/canvas-win32-x64-msvc@1.0.0': optional: true - '@napi-rs/canvas@0.1.100': + '@napi-rs/canvas@1.0.0': optionalDependencies: - '@napi-rs/canvas-android-arm64': 0.1.100 - '@napi-rs/canvas-darwin-arm64': 0.1.100 - '@napi-rs/canvas-darwin-x64': 0.1.100 - '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.100 - '@napi-rs/canvas-linux-arm64-gnu': 0.1.100 - '@napi-rs/canvas-linux-arm64-musl': 0.1.100 - '@napi-rs/canvas-linux-riscv64-gnu': 0.1.100 - '@napi-rs/canvas-linux-x64-gnu': 0.1.100 - '@napi-rs/canvas-linux-x64-musl': 0.1.100 - '@napi-rs/canvas-win32-arm64-msvc': 0.1.100 - '@napi-rs/canvas-win32-x64-msvc': 0.1.100 + '@napi-rs/canvas-android-arm64': 1.0.0 + '@napi-rs/canvas-darwin-arm64': 1.0.0 + '@napi-rs/canvas-darwin-x64': 1.0.0 + '@napi-rs/canvas-linux-arm-gnueabihf': 1.0.0 + '@napi-rs/canvas-linux-arm64-gnu': 1.0.0 + '@napi-rs/canvas-linux-arm64-musl': 1.0.0 + '@napi-rs/canvas-linux-riscv64-gnu': 1.0.0 + '@napi-rs/canvas-linux-x64-gnu': 1.0.0 + '@napi-rs/canvas-linux-x64-musl': 1.0.0 + '@napi-rs/canvas-win32-arm64-msvc': 1.0.0 + '@napi-rs/canvas-win32-x64-msvc': 1.0.0 '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.1 - optional: true - - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': - dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@tybys/wasm-util': 0.10.1 + '@tybys/wasm-util': 0.10.2 optional: true '@nestjs/common@11.1.19(reflect-metadata@0.2.2)(rxjs@7.8.2)': @@ -12206,20 +11968,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@npmcli/agent@4.0.0': - dependencies: - agent-base: 7.1.4 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6(supports-color@10.2.2) - lru-cache: 11.2.5 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - - '@npmcli/fs@5.0.0': - dependencies: - semver: 7.7.4 - '@nuxt/opencollective@0.4.1': dependencies: consola: 3.4.2 @@ -12256,10 +12004,15 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/instrumentation-amqplib@0.61.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: @@ -12268,7 +12021,7 @@ snapshots: '@opentelemetry/instrumentation-connect@0.57.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@types/connect': 3.4.38 @@ -12285,7 +12038,7 @@ snapshots: '@opentelemetry/instrumentation-fs@0.33.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color @@ -12307,7 +12060,7 @@ snapshots: '@opentelemetry/instrumentation-hapi@0.60.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: @@ -12323,15 +12076,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-ioredis@0.62.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/redis-common': 0.38.2 - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - '@opentelemetry/instrumentation-kafkajs@0.23.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -12351,7 +12095,7 @@ snapshots: '@opentelemetry/instrumentation-koa@0.62.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: @@ -12375,7 +12119,7 @@ snapshots: '@opentelemetry/instrumentation-mongoose@0.60.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: @@ -12402,7 +12146,7 @@ snapshots: '@opentelemetry/instrumentation-pg@0.66.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.1) @@ -12411,15 +12155,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-redis@0.62.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/redis-common': 0.38.2 - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - '@opentelemetry/instrumentation-tedious@0.33.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -12451,24 +12186,22 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/api-logs': 0.214.0 - import-in-the-middle: 3.0.0 + import-in-the-middle: 3.0.1 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color - '@opentelemetry/redis-common@0.38.2': {} - - '@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@opentelemetry/semantic-conventions@1.40.0': {} @@ -12476,170 +12209,174 @@ snapshots: '@opentelemetry/sql-common@0.41.2(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@oxc-project/runtime@0.127.0': {} + '@oxc-project/runtime@0.129.0': {} - '@oxc-project/types@0.124.0': {} + '@oxc-project/types@0.128.0': {} - '@oxc-project/types@0.127.0': {} + '@oxc-project/types@0.129.0': {} '@paralleldrive/cuid2@2.3.1': dependencies: '@noble/hashes': 1.8.0 - '@parcel/watcher-android-arm64@2.5.1': + '@parcel/watcher-android-arm64@2.5.6': optional: true - '@parcel/watcher-darwin-arm64@2.5.1': + '@parcel/watcher-darwin-arm64@2.5.6': optional: true - '@parcel/watcher-darwin-x64@2.5.1': + '@parcel/watcher-darwin-x64@2.5.6': optional: true - '@parcel/watcher-freebsd-x64@2.5.1': + '@parcel/watcher-freebsd-x64@2.5.6': optional: true - '@parcel/watcher-linux-arm-glibc@2.5.1': + '@parcel/watcher-linux-arm-glibc@2.5.6': optional: true - '@parcel/watcher-linux-arm-musl@2.5.1': + '@parcel/watcher-linux-arm-musl@2.5.6': optional: true - '@parcel/watcher-linux-arm64-glibc@2.5.1': + '@parcel/watcher-linux-arm64-glibc@2.5.6': optional: true - '@parcel/watcher-linux-arm64-musl@2.5.1': + '@parcel/watcher-linux-arm64-musl@2.5.6': optional: true - '@parcel/watcher-linux-x64-glibc@2.5.1': + '@parcel/watcher-linux-x64-glibc@2.5.6': optional: true - '@parcel/watcher-linux-x64-musl@2.5.1': + '@parcel/watcher-linux-x64-musl@2.5.6': optional: true - '@parcel/watcher-win32-arm64@2.5.1': + '@parcel/watcher-win32-arm64@2.5.6': optional: true - '@parcel/watcher-win32-ia32@2.5.1': + '@parcel/watcher-win32-ia32@2.5.6': optional: true - '@parcel/watcher-win32-x64@2.5.1': + '@parcel/watcher-win32-x64@2.5.6': optional: true - '@parcel/watcher@2.5.1': + '@parcel/watcher@2.5.6': dependencies: - detect-libc: 1.0.3 + detect-libc: 2.1.2 is-glob: 4.0.3 - micromatch: 4.0.8 node-addon-api: 7.1.1 + picomatch: 4.0.4 optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.1 - '@parcel/watcher-darwin-arm64': 2.5.1 - '@parcel/watcher-darwin-x64': 2.5.1 - '@parcel/watcher-freebsd-x64': 2.5.1 - '@parcel/watcher-linux-arm-glibc': 2.5.1 - '@parcel/watcher-linux-arm-musl': 2.5.1 - '@parcel/watcher-linux-arm64-glibc': 2.5.1 - '@parcel/watcher-linux-arm64-musl': 2.5.1 - '@parcel/watcher-linux-x64-glibc': 2.5.1 - '@parcel/watcher-linux-x64-musl': 2.5.1 - '@parcel/watcher-win32-arm64': 2.5.1 - '@parcel/watcher-win32-ia32': 2.5.1 - '@parcel/watcher-win32-x64': 2.5.1 - optional: true - - '@peculiar/asn1-android@2.6.0': - dependencies: - '@peculiar/asn1-schema': 2.6.0 - asn1js: 3.0.6 + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + optional: true + + '@peculiar/asn1-android@2.7.0': + dependencies: + '@peculiar/asn1-schema': 2.7.0 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-cms@2.6.0': + '@peculiar/asn1-cms@2.7.0': dependencies: - '@peculiar/asn1-schema': 2.6.0 - '@peculiar/asn1-x509': 2.6.1 - '@peculiar/asn1-x509-attr': 2.6.0 - asn1js: 3.0.6 + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-x509': 2.7.0 + '@peculiar/asn1-x509-attr': 2.7.0 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-csr@2.6.0': + '@peculiar/asn1-csr@2.7.0': dependencies: - '@peculiar/asn1-schema': 2.6.0 - '@peculiar/asn1-x509': 2.6.1 - asn1js: 3.0.6 + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-x509': 2.7.0 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-ecc@2.6.1': + '@peculiar/asn1-ecc@2.7.0': dependencies: - '@peculiar/asn1-schema': 2.6.0 - '@peculiar/asn1-x509': 2.6.1 - asn1js: 3.0.6 + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-x509': 2.7.0 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-pfx@2.6.0': + '@peculiar/asn1-pfx@2.7.0': dependencies: - '@peculiar/asn1-cms': 2.6.0 - '@peculiar/asn1-pkcs8': 2.6.0 - '@peculiar/asn1-rsa': 2.6.1 - '@peculiar/asn1-schema': 2.6.0 - asn1js: 3.0.6 + '@peculiar/asn1-cms': 2.7.0 + '@peculiar/asn1-pkcs8': 2.7.0 + '@peculiar/asn1-rsa': 2.7.0 + '@peculiar/asn1-schema': 2.7.0 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-pkcs8@2.6.0': + '@peculiar/asn1-pkcs8@2.7.0': dependencies: - '@peculiar/asn1-schema': 2.6.0 - '@peculiar/asn1-x509': 2.6.1 - asn1js: 3.0.6 + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-x509': 2.7.0 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-pkcs9@2.6.0': + '@peculiar/asn1-pkcs9@2.7.0': dependencies: - '@peculiar/asn1-cms': 2.6.0 - '@peculiar/asn1-pfx': 2.6.0 - '@peculiar/asn1-pkcs8': 2.6.0 - '@peculiar/asn1-schema': 2.6.0 - '@peculiar/asn1-x509': 2.6.1 - '@peculiar/asn1-x509-attr': 2.6.0 - asn1js: 3.0.6 + '@peculiar/asn1-cms': 2.7.0 + '@peculiar/asn1-pfx': 2.7.0 + '@peculiar/asn1-pkcs8': 2.7.0 + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-x509': 2.7.0 + '@peculiar/asn1-x509-attr': 2.7.0 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-rsa@2.6.1': + '@peculiar/asn1-rsa@2.7.0': dependencies: - '@peculiar/asn1-schema': 2.6.0 - '@peculiar/asn1-x509': 2.6.1 - asn1js: 3.0.6 + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-x509': 2.7.0 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-schema@2.6.0': + '@peculiar/asn1-schema@2.7.0': dependencies: - asn1js: 3.0.6 - pvtsutils: 1.3.6 + '@peculiar/utils': 2.0.3 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-x509-attr@2.6.0': + '@peculiar/asn1-x509-attr@2.7.0': dependencies: - '@peculiar/asn1-schema': 2.6.0 - '@peculiar/asn1-x509': 2.6.1 - asn1js: 3.0.6 + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-x509': 2.7.0 + asn1js: 3.0.10 tslib: 2.8.1 - '@peculiar/asn1-x509@2.6.1': + '@peculiar/asn1-x509@2.7.0': + dependencies: + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/utils': 2.0.3 + asn1js: 3.0.10 + tslib: 2.8.1 + + '@peculiar/utils@2.0.3': dependencies: - '@peculiar/asn1-schema': 2.6.0 - asn1js: 3.0.6 - pvtsutils: 1.3.6 tslib: 2.8.1 '@peculiar/x509@1.14.3': dependencies: - '@peculiar/asn1-cms': 2.6.0 - '@peculiar/asn1-csr': 2.6.0 - '@peculiar/asn1-ecc': 2.6.1 - '@peculiar/asn1-pkcs9': 2.6.0 - '@peculiar/asn1-rsa': 2.6.1 - '@peculiar/asn1-schema': 2.6.0 - '@peculiar/asn1-x509': 2.6.1 + '@peculiar/asn1-cms': 2.7.0 + '@peculiar/asn1-csr': 2.7.0 + '@peculiar/asn1-ecc': 2.7.0 + '@peculiar/asn1-pkcs9': 2.7.0 + '@peculiar/asn1-rsa': 2.7.0 + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-x509': 2.7.0 pvtsutils: 1.3.6 reflect-metadata: 0.2.2 tslib: 2.8.1 @@ -12665,15 +12402,15 @@ snapshots: '@readme/better-ajv-errors@2.4.0(ajv@8.20.0)': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.29.2 '@humanwhocodes/momoa': 2.0.4 ajv: 8.20.0 jsonpointer: 5.0.1 leven: 3.1.0 picocolors: 1.1.1 - '@readme/openapi-parser@6.0.1(openapi-types@12.1.3)': + '@readme/openapi-parser@6.1.1(openapi-types@12.1.3)': dependencies: '@apidevtools/json-schema-ref-parser': 14.2.1(@types/json-schema@7.0.15) '@readme/better-ajv-errors': 2.4.0(ajv@8.20.0) @@ -12685,227 +12422,227 @@ snapshots: '@readme/openapi-schemas@3.1.0': {} - '@redocly/ajv@8.17.1': + '@redocly/ajv@8.11.2': dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + uri-js-replace: 1.0.1 - '@redocly/config@0.22.2': {} + '@redocly/config@0.22.0': {} - '@redocly/openapi-core@1.34.6(supports-color@10.2.2)': + '@redocly/openapi-core@1.34.14(supports-color@10.2.2)': dependencies: - '@redocly/ajv': 8.17.1 - '@redocly/config': 0.22.2 + '@redocly/ajv': 8.11.2 + '@redocly/config': 0.22.0 colorette: 1.4.0 https-proxy-agent: 7.0.6(supports-color@10.2.2) js-levenshtein: 1.1.6 js-yaml: 4.1.1 - minimatch: 5.1.6 + minimatch: 5.1.9 pluralize: 8.0.0 yaml-ast-parser: 0.0.43 transitivePeerDependencies: - supports-color - '@rolldown/binding-android-arm64@1.0.0-rc.15': + '@rolldown/binding-android-arm64@1.0.0': optional: true - '@rolldown/binding-android-arm64@1.0.0-rc.17': + '@rolldown/binding-android-arm64@1.0.0-rc.18': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': + '@rolldown/binding-darwin-arm64@1.0.0': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': + '@rolldown/binding-darwin-arm64@1.0.0-rc.18': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.15': + '@rolldown/binding-darwin-x64@1.0.0': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.17': + '@rolldown/binding-darwin-x64@1.0.0-rc.18': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': + '@rolldown/binding-freebsd-x64@1.0.0': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': + '@rolldown/binding-freebsd-x64@1.0.0-rc.18': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.18': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-arm64-gnu@1.0.0': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.18': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': + '@rolldown/binding-linux-arm64-musl@1.0.0': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.18': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-ppc64-gnu@1.0.0': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.18': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-s390x-gnu@1.0.0': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.18': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-x64-gnu@1.0.0': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.18': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + '@rolldown/binding-linux-x64-musl@1.0.0': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.18': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + '@rolldown/binding-openharmony-arm64@1.0.0': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.18': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': + '@rolldown/binding-wasm32-wasi@1.0.0': dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.18': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': + '@rolldown/binding-win32-arm64-msvc@1.0.0': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.18': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': + '@rolldown/binding-win32-x64-msvc@1.0.0': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.18': optional: true - '@rolldown/pluginutils@1.0.0-rc.13': {} + '@rolldown/pluginutils@1.0.0': {} - '@rolldown/pluginutils@1.0.0-rc.15': {} + '@rolldown/pluginutils@1.0.0-rc.13': {} - '@rolldown/pluginutils@1.0.0-rc.17': {} + '@rolldown/pluginutils@1.0.0-rc.18': {} - '@rollup/plugin-esm-shim@0.1.8(rollup@4.60.2)': + '@rollup/plugin-esm-shim@0.1.8(rollup@4.60.3)': dependencies: magic-string: 0.30.21 mlly: 1.8.2 optionalDependencies: - rollup: 4.60.2 + rollup: 4.60.3 - '@rollup/plugin-json@6.1.0(rollup@4.60.2)': + '@rollup/plugin-json@6.1.0(rollup@4.60.3)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.60.2) + '@rollup/pluginutils': 5.3.0(rollup@4.60.3) optionalDependencies: - rollup: 4.60.2 + rollup: 4.60.3 - '@rollup/pluginutils@5.3.0(rollup@4.60.2)': + '@rollup/pluginutils@5.3.0(rollup@4.60.3)': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.4 optionalDependencies: - rollup: 4.60.2 + rollup: 4.60.3 - '@rollup/rollup-android-arm-eabi@4.60.2': + '@rollup/rollup-android-arm-eabi@4.60.3': optional: true - '@rollup/rollup-android-arm64@4.60.2': + '@rollup/rollup-android-arm64@4.60.3': optional: true - '@rollup/rollup-darwin-arm64@4.60.2': + '@rollup/rollup-darwin-arm64@4.60.3': optional: true - '@rollup/rollup-darwin-x64@4.60.2': + '@rollup/rollup-darwin-x64@4.60.3': optional: true - '@rollup/rollup-freebsd-arm64@4.60.2': + '@rollup/rollup-freebsd-arm64@4.60.3': optional: true - '@rollup/rollup-freebsd-x64@4.60.2': + '@rollup/rollup-freebsd-x64@4.60.3': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.2': + '@rollup/rollup-linux-arm-musleabihf@4.60.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.2': + '@rollup/rollup-linux-arm64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.2': + '@rollup/rollup-linux-arm64-musl@4.60.3': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.2': + '@rollup/rollup-linux-loong64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.2': + '@rollup/rollup-linux-loong64-musl@4.60.3': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.2': + '@rollup/rollup-linux-ppc64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.2': + '@rollup/rollup-linux-ppc64-musl@4.60.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.2': + '@rollup/rollup-linux-riscv64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.2': + '@rollup/rollup-linux-riscv64-musl@4.60.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.2': + '@rollup/rollup-linux-s390x-gnu@4.60.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.2': + '@rollup/rollup-linux-x64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-x64-musl@4.60.2': + '@rollup/rollup-linux-x64-musl@4.60.3': optional: true - '@rollup/rollup-openbsd-x64@4.60.2': + '@rollup/rollup-openbsd-x64@4.60.3': optional: true - '@rollup/rollup-openharmony-arm64@4.60.2': + '@rollup/rollup-openharmony-arm64@4.60.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.2': + '@rollup/rollup-win32-arm64-msvc@4.60.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.2': + '@rollup/rollup-win32-ia32-msvc@4.60.3': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.2': + '@rollup/rollup-win32-x64-gnu@4.60.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.60.2': + '@rollup/rollup-win32-x64-msvc@4.60.3': optional: true '@rtsao/scc@1.1.0': {} @@ -12915,10 +12652,10 @@ snapshots: ajv: 8.18.0 ajv-draft-04: 1.0.0(ajv@8.18.0) ajv-formats: 3.0.1(ajv@8.18.0) - fs-extra: 11.3.2 + fs-extra: 11.3.5 import-lazy: 4.0.0 jju: 1.4.0 - resolve: 1.22.11 + resolve: 1.22.12 semver: 7.7.4 optionalDependencies: '@types/node': 24.12.2 @@ -12930,7 +12667,7 @@ snapshots: '@rushstack/rig-package@0.7.3': dependencies: jju: 1.4.0 - resolve: 1.22.11 + resolve: 1.22.12 '@rushstack/terminal@0.24.0(@types/node@24.12.2)': dependencies: @@ -12951,56 +12688,56 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@sentry-internal/browser-utils@10.50.0': + '@sentry-internal/browser-utils@10.52.0': dependencies: - '@sentry/core': 10.50.0 + '@sentry/core': 10.52.0 - '@sentry-internal/feedback@10.50.0': + '@sentry-internal/feedback@10.52.0': dependencies: - '@sentry/core': 10.50.0 + '@sentry/core': 10.52.0 - '@sentry-internal/node-cpu-profiler@2.2.0': + '@sentry-internal/node-cpu-profiler@2.3.0': dependencies: detect-libc: 2.1.2 - node-abi: 3.85.0 + node-abi: 3.92.0 - '@sentry-internal/replay-canvas@10.50.0': + '@sentry-internal/replay-canvas@10.52.0': dependencies: - '@sentry-internal/replay': 10.50.0 - '@sentry/core': 10.50.0 + '@sentry-internal/replay': 10.52.0 + '@sentry/core': 10.52.0 - '@sentry-internal/replay@10.50.0': + '@sentry-internal/replay@10.52.0': dependencies: - '@sentry-internal/browser-utils': 10.50.0 - '@sentry/core': 10.50.0 + '@sentry-internal/browser-utils': 10.52.0 + '@sentry/core': 10.52.0 - '@sentry/browser@10.50.0': + '@sentry/browser@10.52.0': dependencies: - '@sentry-internal/browser-utils': 10.50.0 - '@sentry-internal/feedback': 10.50.0 - '@sentry-internal/replay': 10.50.0 - '@sentry-internal/replay-canvas': 10.50.0 - '@sentry/core': 10.50.0 + '@sentry-internal/browser-utils': 10.52.0 + '@sentry-internal/feedback': 10.52.0 + '@sentry-internal/replay': 10.52.0 + '@sentry-internal/replay-canvas': 10.52.0 + '@sentry/core': 10.52.0 - '@sentry/core@10.50.0': {} + '@sentry/core@10.52.0': {} - '@sentry/node-core@10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': + '@sentry/node-core@10.52.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: - '@sentry/core': 10.50.0 - '@sentry/opentelemetry': 10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - import-in-the-middle: 3.0.0 + '@sentry/core': 10.52.0 + '@sentry/opentelemetry': 10.52.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) + import-in-the-middle: 3.0.1 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/node@10.50.0': + '@sentry/node@10.52.0': dependencies: '@fastify/otel': 0.18.0(@opentelemetry/api@1.9.1) '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-amqplib': 0.61.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-connect': 0.57.0(@opentelemetry/api@1.9.1) @@ -13010,7 +12747,6 @@ snapshots: '@opentelemetry/instrumentation-graphql': 0.62.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-hapi': 0.60.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-http': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-ioredis': 0.62.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-kafkajs': 0.23.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-knex': 0.58.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-koa': 0.62.0(@opentelemetry/api@1.9.1) @@ -13020,41 +12756,40 @@ snapshots: '@opentelemetry/instrumentation-mysql': 0.60.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-mysql2': 0.60.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-pg': 0.66.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-redis': 0.62.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-tedious': 0.33.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@prisma/instrumentation': 7.6.0(@opentelemetry/api@1.9.1) - '@sentry/core': 10.50.0 - '@sentry/node-core': 10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - '@sentry/opentelemetry': 10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - import-in-the-middle: 3.0.0 + '@sentry/core': 10.52.0 + '@sentry/node-core': 10.52.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/opentelemetry': 10.52.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) + import-in-the-middle: 3.0.1 transitivePeerDependencies: - '@opentelemetry/exporter-trace-otlp-http' - supports-color - '@sentry/opentelemetry@10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': + '@sentry/opentelemetry@10.52.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/core': 10.50.0 + '@sentry/core': 10.52.0 - '@sentry/profiling-node@10.50.0': + '@sentry/profiling-node@10.52.0': dependencies: - '@sentry-internal/node-cpu-profiler': 2.2.0 - '@sentry/core': 10.50.0 - '@sentry/node': 10.50.0 + '@sentry-internal/node-cpu-profiler': 2.3.0 + '@sentry/core': 10.52.0 + '@sentry/node': 10.52.0 transitivePeerDependencies: - '@opentelemetry/exporter-trace-otlp-http' - supports-color - '@sentry/vue@10.50.0(vue@3.5.33(typescript@5.9.3))': + '@sentry/vue@10.52.0(vue@3.5.34(typescript@5.9.3))': dependencies: - '@sentry/browser': 10.50.0 - '@sentry/core': 10.50.0 - vue: 3.5.33(typescript@5.9.3) + '@sentry/browser': 10.52.0 + '@sentry/core': 10.52.0 + vue: 3.5.34(typescript@5.9.3) '@shikijs/core@4.0.2': dependencies: @@ -13068,7 +12803,7 @@ snapshots: dependencies: '@shikijs/types': 4.0.2 '@shikijs/vscode-textmate': 10.0.2 - oniguruma-to-es: 4.3.4 + oniguruma-to-es: 4.3.6 '@shikijs/engine-oniguruma@4.0.2': dependencies: @@ -13110,14 +12845,14 @@ snapshots: dependencies: '@hexagon/base64': 1.1.28 '@levischuck/tiny-cbor': 0.2.11 - '@peculiar/asn1-android': 2.6.0 - '@peculiar/asn1-ecc': 2.6.1 - '@peculiar/asn1-rsa': 2.6.1 - '@peculiar/asn1-schema': 2.6.0 - '@peculiar/asn1-x509': 2.6.1 + '@peculiar/asn1-android': 2.7.0 + '@peculiar/asn1-ecc': 2.7.0 + '@peculiar/asn1-rsa': 2.7.0 + '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-x509': 2.7.0 '@peculiar/x509': 1.14.3 - '@sinclair/typebox@0.27.8': {} + '@sinclair/typebox@0.27.10': {} '@sindresorhus/is@8.0.0': {} @@ -13131,11 +12866,7 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers@13.0.5': - dependencies: - '@sinonjs/commons': 3.0.1 - - '@sinonjs/fake-timers@15.3.2': + '@sinonjs/fake-timers@15.4.0': dependencies: '@sinonjs/commons': 3.0.1 @@ -13144,8 +12875,6 @@ snapshots: '@sinonjs/commons': 3.0.1 type-detect: 4.1.0 - '@sinonjs/text-encoding@0.7.3': {} - '@smithy/chunked-blob-reader-native@4.2.3': dependencies: '@smithy/util-base64': 4.3.2 @@ -13279,16 +13008,16 @@ snapshots: '@smithy/util-middleware': 4.2.14 tslib: 2.8.1 - '@smithy/middleware-retry@4.5.5': + '@smithy/middleware-retry@4.5.7': dependencies: '@smithy/core': 3.23.17 '@smithy/node-config-provider': 4.3.14 '@smithy/protocol-http': 5.3.14 - '@smithy/service-error-classification': 4.3.0 + '@smithy/service-error-classification': 4.3.1 '@smithy/smithy-client': 4.12.13 '@smithy/types': 4.14.1 '@smithy/util-middleware': 4.2.14 - '@smithy/util-retry': 4.3.4 + '@smithy/util-retry': 4.3.8 '@smithy/uuid': 1.1.2 tslib: 2.8.1 @@ -13339,7 +13068,7 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/service-error-classification@4.3.0': + '@smithy/service-error-classification@4.3.1': dependencies: '@smithy/types': 4.14.1 @@ -13439,9 +13168,9 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/util-retry@4.3.4': + '@smithy/util-retry@4.3.8': dependencies: - '@smithy/service-error-classification': 4.3.0 + '@smithy/service-error-classification': 4.3.1 '@smithy/types': 4.14.1 tslib: 2.8.1 @@ -13470,7 +13199,7 @@ snapshots: '@smithy/util-buffer-from': 4.2.2 tslib: 2.8.1 - '@smithy/util-waiter@4.2.16': + '@smithy/util-waiter@4.3.0': dependencies: '@smithy/types': 4.14.1 tslib: 2.8.1 @@ -13483,210 +13212,210 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-actions@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-actions@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 '@types/uuid': 9.0.8 dequal: 2.0.3 polished: 4.3.1 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) uuid: 9.0.1 - '@storybook/addon-backgrounds@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-backgrounds@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 memoizerific: 1.11.3 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - '@storybook/addon-controls@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-controls@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 dequal: 2.0.3 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - '@storybook/addon-docs@8.6.18(@types/react@19.2.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-docs@8.6.18(@types/react@19.2.14)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - '@mdx-js/react': 3.1.1(@types/react@19.2.2)(react@19.2.5) - '@storybook/blocks': 8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/csf-plugin': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/react-dom-shim': 8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.6) + '@storybook/blocks': 8.6.18(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/csf-plugin': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/react-dom-shim': 8.6.18(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-essentials@8.6.18(@types/react@19.2.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': - dependencies: - '@storybook/addon-actions': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/addon-backgrounds': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/addon-controls': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/addon-docs': 8.6.18(@types/react@19.2.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/addon-highlight': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/addon-measure': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/addon-outline': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/addon-toolbars': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/addon-viewport': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + '@storybook/addon-essentials@8.6.18(@types/react@19.2.14)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': + dependencies: + '@storybook/addon-actions': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/addon-backgrounds': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/addon-controls': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/addon-docs': 8.6.18(@types/react@19.2.14)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/addon-highlight': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/addon-measure': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/addon-outline': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/addon-toolbars': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/addon-viewport': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-highlight@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-highlight@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/addon-interactions@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-interactions@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/test': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + '@storybook/instrumenter': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/test': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) polished: 4.3.1 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - '@storybook/addon-links@10.3.5(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-links@10.3.6(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) optionalDependencies: - react: 19.2.5 + react: 19.2.6 - '@storybook/addon-mdx-gfm@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-mdx-gfm@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: remark-gfm: 4.0.1 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - '@storybook/addon-measure@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-measure@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) tiny-invariant: 1.3.3 - '@storybook/addon-outline@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-outline@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - '@storybook/addon-storysource@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-storysource@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - '@storybook/source-loader': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + '@storybook/source-loader': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) estraverse: 5.3.0 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) tiny-invariant: 1.3.3 - '@storybook/addon-toolbars@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-toolbars@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/addon-viewport@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/addon-viewport@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: memoizerific: 1.11.3 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/blocks@8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/blocks@8.6.18(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - '@storybook/icons': 1.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + '@storybook/icons': 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 optionalDependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - '@storybook/builder-vite@10.3.5(esbuild@0.28.0)(rollup@4.60.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))': + '@storybook/builder-vite@10.3.6(esbuild@0.28.0)(rollup@4.60.3)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))': dependencies: - '@storybook/csf-plugin': 10.3.5(esbuild@0.28.0)(rollup@4.60.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + '@storybook/csf-plugin': 10.3.6(esbuild@0.28.0)(rollup@4.60.3)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - vite: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup - webpack - '@storybook/components@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/components@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/core-events@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/core-events@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/csf-plugin@10.3.5(esbuild@0.28.0)(rollup@4.60.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))': + '@storybook/csf-plugin@10.3.6(esbuild@0.28.0)(rollup@4.60.3)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))': dependencies: - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) unplugin: 2.3.11 optionalDependencies: esbuild: 0.28.0 - rollup: 4.60.2 - vite: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + rollup: 4.60.3 + vite: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) - '@storybook/csf-plugin@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/csf-plugin@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) unplugin: 1.16.1 '@storybook/global@5.0.0': {} - '@storybook/icons@1.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@storybook/icons@1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - '@storybook/icons@2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@storybook/icons@2.0.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - '@storybook/instrumenter@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/instrumenter@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 '@vitest/utils': 2.1.9 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/manager-api@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/manager-api@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/preview-api@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/preview-api@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/react-dom-shim@10.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/react-dom-shim@10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/react-dom-shim@8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/react-dom-shim@8.6.18(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/react-vite@10.3.5(esbuild@0.28.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(rollup@4.60.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))': + '@storybook/react-vite@10.3.6(esbuild@0.28.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(rollup@4.60.3)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) - '@rollup/pluginutils': 5.3.0(rollup@4.60.2) - '@storybook/builder-vite': 10.3.5(esbuild@0.28.0)(rollup@4.60.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) - '@storybook/react': 10.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(typescript@5.9.3) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) + '@rollup/pluginutils': 5.3.0(rollup@4.60.3) + '@storybook/builder-vite': 10.3.6(esbuild@0.28.0)(rollup@4.60.3)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) + '@storybook/react': 10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 - react: 19.2.5 - react-docgen: 8.0.2 - react-dom: 19.2.5(react@19.2.5) - resolve: 1.22.11 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + react: 19.2.6 + react-docgen: 8.0.3 + react-dom: 19.2.6(react@19.2.6) + resolve: 1.22.12 + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) tsconfig-paths: 4.2.0 - vite: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup @@ -13694,74 +13423,74 @@ snapshots: - typescript - webpack - '@storybook/react@10.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(typescript@5.9.3)': + '@storybook/react@10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - react: 19.2.5 - react-docgen: 8.0.2 + '@storybook/react-dom-shim': 10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + react: 19.2.6 + react-docgen: 8.0.3 react-docgen-typescript: 2.4.0(typescript@5.9.3) - react-dom: 19.2.5(react@19.2.5) - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + react-dom: 19.2.6(react@19.2.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@storybook/source-loader@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/source-loader@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - es-toolkit: 1.42.0 + es-toolkit: 1.46.1 estraverse: 5.3.0 prettier: 3.8.3 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/test@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/test@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + '@storybook/instrumenter': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) '@testing-library/dom': 10.4.0 '@testing-library/jest-dom': 6.5.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) '@vitest/expect': 2.0.5 '@vitest/spy': 2.0.5 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/theming@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/theming@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/types@8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))': + '@storybook/types@8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))': dependencies: - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) - '@storybook/vue3-vite@10.3.5(esbuild@0.28.0)(rollup@4.60.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))(vue@3.5.33(typescript@5.9.3))': + '@storybook/vue3-vite@10.3.6(esbuild@0.28.0)(rollup@4.60.3)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))(vue@3.5.34(typescript@5.9.3))': dependencies: - '@storybook/builder-vite': 10.3.5(esbuild@0.28.0)(rollup@4.60.2)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) - '@storybook/vue3': 10.3.5(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vue@3.5.33(typescript@5.9.3)) + '@storybook/builder-vite': 10.3.6(esbuild@0.28.0)(rollup@4.60.3)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) + '@storybook/vue3': 10.3.6(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vue@3.5.34(typescript@5.9.3)) magic-string: 0.30.21 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) typescript: 5.9.3 - vite: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) vue-component-meta: 2.2.12(typescript@5.9.3) - vue-docgen-api: 4.79.2(vue@3.5.33(typescript@5.9.3)) + vue-docgen-api: 4.79.2(vue@3.5.34(typescript@5.9.3)) transitivePeerDependencies: - esbuild - rollup - vue - webpack - '@storybook/vue3@10.3.5(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6))(vue@3.5.33(typescript@5.9.3))': + '@storybook/vue3@10.3.6(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6))(vue@3.5.34(typescript@5.9.3))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6) + storybook: 10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6) type-fest: 2.19.0 - vue: 3.5.33(typescript@5.9.3) - vue-component-type-helpers: 3.2.7 + vue: 3.5.34(typescript@5.9.3) + vue-component-type-helpers: 3.2.8 - '@stylistic/eslint-plugin@5.5.0(eslint@9.39.4)': + '@stylistic/eslint-plugin@5.10.0(eslint@9.39.4)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/types': 8.59.2 eslint: 9.39.4 eslint-visitor-keys: 4.2.1 espree: 10.4.0 @@ -13787,55 +13516,55 @@ snapshots: '@tabler/icons@3.35.0': {} - '@tensorflow/tfjs-backend-cpu@4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13))': + '@tensorflow/tfjs-backend-cpu@4.22.0(@tensorflow/tfjs-core@4.22.0)': dependencies: - '@tensorflow/tfjs-core': 4.22.0(encoding@0.1.13) + '@tensorflow/tfjs-core': 4.22.0 '@types/seedrandom': 2.4.34 seedrandom: 3.0.5 - '@tensorflow/tfjs-backend-webgl@4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13))': + '@tensorflow/tfjs-backend-webgl@4.22.0(@tensorflow/tfjs-core@4.22.0)': dependencies: - '@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13)) - '@tensorflow/tfjs-core': 4.22.0(encoding@0.1.13) + '@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs-core': 4.22.0 '@types/offscreencanvas': 2019.3.0 '@types/seedrandom': 2.4.34 seedrandom: 3.0.5 - '@tensorflow/tfjs-converter@4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13))': + '@tensorflow/tfjs-converter@4.22.0(@tensorflow/tfjs-core@4.22.0)': dependencies: - '@tensorflow/tfjs-core': 4.22.0(encoding@0.1.13) + '@tensorflow/tfjs-core': 4.22.0 - '@tensorflow/tfjs-core@4.22.0(encoding@0.1.13)': + '@tensorflow/tfjs-core@4.22.0': dependencies: '@types/long': 4.0.2 '@types/offscreencanvas': 2019.7.3 '@types/seedrandom': 2.4.34 '@webgpu/types': 0.1.38 long: 4.0.0 - node-fetch: 2.6.13(encoding@0.1.13) + node-fetch: 2.6.13 seedrandom: 3.0.5 transitivePeerDependencies: - encoding - '@tensorflow/tfjs-data@4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13))(encoding@0.1.13)(seedrandom@3.0.5)': + '@tensorflow/tfjs-data@4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5)': dependencies: - '@tensorflow/tfjs-core': 4.22.0(encoding@0.1.13) + '@tensorflow/tfjs-core': 4.22.0 '@types/node-fetch': 2.6.13 - node-fetch: 2.6.13(encoding@0.1.13) + node-fetch: 2.6.13 seedrandom: 3.0.5 string_decoder: 1.3.0 transitivePeerDependencies: - encoding - '@tensorflow/tfjs-layers@4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13))': + '@tensorflow/tfjs-layers@4.22.0(@tensorflow/tfjs-core@4.22.0)': dependencies: - '@tensorflow/tfjs-core': 4.22.0(encoding@0.1.13) + '@tensorflow/tfjs-core': 4.22.0 - '@tensorflow/tfjs-node@4.22.0(encoding@0.1.13)(seedrandom@3.0.5)': + '@tensorflow/tfjs-node@4.22.0(seedrandom@3.0.5)': dependencies: - '@mapbox/node-pre-gyp': 1.0.9(encoding@0.1.13) - '@tensorflow/tfjs': 4.22.0(encoding@0.1.13)(seedrandom@3.0.5) - adm-zip: 0.5.16 + '@mapbox/node-pre-gyp': 1.0.9 + '@tensorflow/tfjs': 4.22.0(seedrandom@3.0.5) + adm-zip: 0.5.17 google-protobuf: 3.21.4 https-proxy-agent: 2.2.4 progress: 2.0.3 @@ -13847,14 +13576,14 @@ snapshots: - supports-color optional: true - '@tensorflow/tfjs@4.22.0(encoding@0.1.13)(seedrandom@3.0.5)': + '@tensorflow/tfjs@4.22.0(seedrandom@3.0.5)': dependencies: - '@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13)) - '@tensorflow/tfjs-backend-webgl': 4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13)) - '@tensorflow/tfjs-converter': 4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13)) - '@tensorflow/tfjs-core': 4.22.0(encoding@0.1.13) - '@tensorflow/tfjs-data': 4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13))(encoding@0.1.13)(seedrandom@3.0.5) - '@tensorflow/tfjs-layers': 4.22.0(@tensorflow/tfjs-core@4.22.0(encoding@0.1.13)) + '@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs-backend-webgl': 4.22.0(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs-converter': 4.22.0(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs-core': 4.22.0 + '@tensorflow/tfjs-data': 4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5) + '@tensorflow/tfjs-layers': 4.22.0(@tensorflow/tfjs-core@4.22.0) argparse: 1.0.10 chalk: 4.1.2 core-js: 3.29.1 @@ -13866,8 +13595,8 @@ snapshots: '@testing-library/dom@10.4.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.29.2 '@types/aria-query': 5.0.4 aria-query: 5.3.0 chalk: 4.1.2 @@ -13877,8 +13606,8 @@ snapshots: '@testing-library/dom@9.3.4': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.29.2 '@types/aria-query': 5.0.4 aria-query: 5.1.3 chalk: 4.1.2 @@ -13913,14 +13642,17 @@ snapshots: dependencies: '@testing-library/dom': 10.4.0 - '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.5.33)(vue@3.5.33(typescript@5.9.3))': + '@testing-library/vue@8.1.0(@vue/compiler-dom@3.5.34)(@vue/compiler-sfc@3.5.34)(@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3)))(vue@3.5.34(typescript@5.9.3))': dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@testing-library/dom': 9.3.4 - '@vue/test-utils': 2.4.6 - vue: 3.5.33(typescript@5.9.3) + '@vue/test-utils': 2.4.10(@vue/compiler-dom@3.5.34)(@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3)))(vue@3.5.34(typescript@5.9.3)) + vue: 3.5.34(typescript@5.9.3) optionalDependencies: - '@vue/compiler-sfc': 3.5.33 + '@vue/compiler-sfc': 3.5.34 + transitivePeerDependencies: + - '@vue/compiler-dom' + - '@vue/server-renderer' '@tokenizer/inflate@0.4.1': dependencies: @@ -13933,7 +13665,7 @@ snapshots: '@tsd/typescript@5.9.3': {} - '@tybys/wasm-util@0.10.1': + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true @@ -13952,7 +13684,7 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 @@ -13964,7 +13696,7 @@ snapshots: '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': @@ -13997,7 +13729,7 @@ snapshots: '@types/cookiejar@2.1.5': {} - '@types/debug@4.1.12': + '@types/debug@4.1.13': dependencies: '@types/ms': 2.1.0 @@ -14015,23 +13747,27 @@ snapshots: '@types/eslint@7.29.0': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 + '@types/esrecurse@4.3.1': {} + '@types/estree@1.0.8': {} - '@types/express-serve-static-core@5.1.0': + '@types/estree@1.0.9': {} + + '@types/express-serve-static-core@5.1.1': dependencies: '@types/node': 24.12.2 - '@types/qs': 6.14.0 + '@types/qs': 6.15.1 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 - '@types/express@5.0.4': + '@types/express@5.0.6': dependencies: '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 5.1.0 - '@types/serve-static': 1.15.10 + '@types/express-serve-static-core': 5.1.1 + '@types/serve-static': 2.2.0 '@types/fluent-ffmpeg@2.1.28': dependencies: @@ -14043,7 +13779,7 @@ snapshots: dependencies: '@types/unist': 3.0.3 - '@types/http-cache-semantics@4.0.4': {} + '@types/http-cache-semantics@4.2.0': {} '@types/http-errors@2.0.5': {} @@ -14079,8 +13815,6 @@ snapshots: '@types/mime-types@3.0.1': {} - '@types/mime@1.3.5': {} - '@types/minimist@1.2.5': {} '@types/ms@2.1.0': {} @@ -14110,7 +13844,7 @@ snapshots: '@types/oauth2orize@1.11.5': dependencies: - '@types/express': 5.0.4 + '@types/express': 5.0.6 '@types/node': 24.12.2 '@types/offscreencanvas@2019.3.0': {} @@ -14139,7 +13873,7 @@ snapshots: dependencies: '@types/node': 24.12.2 - '@types/qs@6.14.0': {} + '@types/qs@6.15.1': {} '@types/random-seed@0.3.5': {} @@ -14147,7 +13881,7 @@ snapshots: '@types/ratelimiter@3.4.6': {} - '@types/react@19.2.2': + '@types/react@19.2.14': dependencies: csstype: 3.2.3 @@ -14169,20 +13903,14 @@ snapshots: '@types/semver@7.7.1': {} - '@types/send@0.17.6': - dependencies: - '@types/mime': 1.3.5 - '@types/node': 24.12.2 - '@types/send@1.2.1': dependencies: '@types/node': 24.12.2 - '@types/serve-static@1.15.10': + '@types/serve-static@2.2.0': dependencies: '@types/http-errors': 2.0.5 '@types/node': 24.12.2 - '@types/send': 0.17.6 '@types/serviceworker@0.0.74': {} @@ -14255,14 +13983,14 @@ snapshots: '@types/node': 24.12.2 optional: true - '@typescript-eslint/eslint-plugin@8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.59.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.59.0 - '@typescript-eslint/type-utils': 8.59.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.0 + '@typescript-eslint/parser': 8.59.2(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/type-utils': 8.59.2(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.2 eslint: 9.39.4 ignore: 7.0.5 natural-compare: 1.4.0 @@ -14271,41 +13999,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.59.0 - '@typescript-eslint/types': 8.59.0 - '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.0 + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.2 debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.4 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.59.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.3) - '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.9.3) + '@typescript-eslint/types': 8.59.2 debug: 4.4.3(supports-color@10.2.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.59.0': + '@typescript-eslint/scope-manager@8.59.2': dependencies: - '@typescript-eslint/types': 8.59.0 - '@typescript-eslint/visitor-keys': 8.59.0 + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/visitor-keys': 8.59.2 - '@typescript-eslint/tsconfig-utils@8.59.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.59.2(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.59.0(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.2(eslint@9.39.4)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.59.0 - '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.0(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4)(typescript@5.9.3) debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.4 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -14313,14 +14041,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.59.0': {} + '@typescript-eslint/types@8.59.2': {} - '@typescript-eslint/typescript-estree@8.59.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.59.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.3) - '@typescript-eslint/types': 8.59.0 - '@typescript-eslint/visitor-keys': 8.59.0 + '@typescript-eslint/project-service': 8.59.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.9.3) + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/visitor-keys': 8.59.2 debug: 4.4.3(supports-color@10.2.2) minimatch: 10.2.5 semver: 7.7.4 @@ -14330,20 +14058,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.59.0(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/utils@8.59.2(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@typescript-eslint/scope-manager': 8.59.0 - '@typescript-eslint/types': 8.59.0 - '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) eslint: 9.39.4 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.59.0': + '@typescript-eslint/visitor-keys@8.59.2': dependencies: - '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/types': 8.59.2 eslint-visitor-keys: 5.0.1 '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260426.1': @@ -14377,13 +14105,13 @@ snapshots: '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260426.1 '@typescript/native-preview-win32-x64': 7.0.0-dev.20260426.1 - '@ungap/structured-clone@1.3.0': {} + '@ungap/structured-clone@1.3.1': {} - '@vitejs/plugin-vue@6.0.6(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))(vue@3.5.33(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.6(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))(vue@3.5.34(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.13 - vite: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) - vue: 3.5.33(typescript@5.9.3) + vite: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) + vue: 3.5.34(typescript@5.9.3) '@vitest/coverage-v8@4.1.5(vitest@4.1.5)': dependencies: @@ -14395,9 +14123,9 @@ snapshots: istanbul-reports: 3.2.0 magicast: 0.5.2 obug: 2.1.1 - std-env: 4.0.0 + std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) '@vitest/expect@2.0.5': dependencies: @@ -14423,14 +14151,14 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.5(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0))': + '@vitest/mocker@4.1.5(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0))': dependencies: '@vitest/spy': 4.1.5 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.13.6(@types/node@24.12.2)(typescript@5.9.3) - vite: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + msw: 2.14.3(@types/node@24.12.2)(typescript@5.9.3) + vite: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) '@vitest/pretty-format@2.0.5': dependencies: @@ -14519,35 +14247,35 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue/compiler-core@3.5.33': + '@vue/compiler-core@3.5.34': dependencies: - '@babel/parser': 7.29.2 - '@vue/shared': 3.5.33 + '@babel/parser': 7.29.3 + '@vue/shared': 3.5.34 entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.33': + '@vue/compiler-dom@3.5.34': dependencies: - '@vue/compiler-core': 3.5.33 - '@vue/shared': 3.5.33 + '@vue/compiler-core': 3.5.34 + '@vue/shared': 3.5.34 - '@vue/compiler-sfc@3.5.33': + '@vue/compiler-sfc@3.5.34': dependencies: - '@babel/parser': 7.29.2 - '@vue/compiler-core': 3.5.33 - '@vue/compiler-dom': 3.5.33 - '@vue/compiler-ssr': 3.5.33 - '@vue/shared': 3.5.33 + '@babel/parser': 7.29.3 + '@vue/compiler-core': 3.5.34 + '@vue/compiler-dom': 3.5.34 + '@vue/compiler-ssr': 3.5.34 + '@vue/shared': 3.5.34 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.10 + postcss: 8.5.14 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.33': + '@vue/compiler-ssr@3.5.34': dependencies: - '@vue/compiler-dom': 3.5.33 - '@vue/shared': 3.5.33 + '@vue/compiler-dom': 3.5.34 + '@vue/shared': 3.5.34 '@vue/compiler-vue2@2.7.16': dependencies: @@ -14557,60 +14285,64 @@ snapshots: '@vue/language-core@2.2.12(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.15 - '@vue/compiler-dom': 3.5.33 + '@vue/compiler-dom': 3.5.34 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.33 + '@vue/shared': 3.5.34 alien-signals: 1.0.13 - minimatch: 9.0.5 + minimatch: 9.0.9 muggle-string: 0.4.1 path-browserify: 1.0.1 optionalDependencies: typescript: 5.9.3 - '@vue/language-core@3.2.7': + '@vue/language-core@3.2.8': dependencies: '@volar/language-core': 2.4.28 - '@vue/compiler-dom': 3.5.33 - '@vue/shared': 3.5.33 + '@vue/compiler-dom': 3.5.34 + '@vue/shared': 3.5.34 alien-signals: 3.1.2 muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.4 - '@vue/reactivity@3.5.33': + '@vue/reactivity@3.5.34': dependencies: - '@vue/shared': 3.5.33 + '@vue/shared': 3.5.34 - '@vue/runtime-core@3.5.33': + '@vue/runtime-core@3.5.34': dependencies: - '@vue/reactivity': 3.5.33 - '@vue/shared': 3.5.33 + '@vue/reactivity': 3.5.34 + '@vue/shared': 3.5.34 - '@vue/runtime-dom@3.5.33': + '@vue/runtime-dom@3.5.34': dependencies: - '@vue/reactivity': 3.5.33 - '@vue/runtime-core': 3.5.33 - '@vue/shared': 3.5.33 + '@vue/reactivity': 3.5.34 + '@vue/runtime-core': 3.5.34 + '@vue/shared': 3.5.34 csstype: 3.2.3 - '@vue/server-renderer@3.5.33(vue@3.5.33(typescript@5.9.3))': + '@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.33 - '@vue/shared': 3.5.33 - vue: 3.5.33(typescript@5.9.3) + '@vue/compiler-ssr': 3.5.34 + '@vue/shared': 3.5.34 + vue: 3.5.34(typescript@5.9.3) - '@vue/shared@3.5.33': {} + '@vue/shared@3.5.34': {} - '@vue/test-utils@2.4.6': + '@vue/test-utils@2.4.10(@vue/compiler-dom@3.5.34)(@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3)))(vue@3.5.34(typescript@5.9.3))': dependencies: + '@vue/compiler-dom': 3.5.34 js-beautify: 1.15.4 - vue-component-type-helpers: 2.2.12 + vue: 3.5.34(typescript@5.9.3) + vue-component-type-helpers: 3.2.8 + optionalDependencies: + '@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@5.9.3)) '@webcontainer/env@1.1.1': {} '@webgpu/types@0.1.38': {} - '@xmldom/xmldom@0.9.9': + '@xmldom/xmldom@0.9.10': optional: true abbrev@1.1.1: @@ -14648,7 +14380,7 @@ snapshots: acorn@8.16.0: {} - adm-zip@0.5.16: + adm-zip@0.5.17: optional: true agent-base@4.3.0: @@ -14665,11 +14397,6 @@ snapshots: agent-base@7.1.4: {} - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/1dc7f60cda78d030dadfc518a33c472202b2ef67: dependencies: vscode-languageclient: 9.0.1 @@ -14690,7 +14417,7 @@ snapshots: optionalDependencies: ajv: 8.20.0 - ajv@6.14.0: + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -14700,14 +14427,14 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 + fast-uri: 3.1.2 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 + fast-uri: 3.1.2 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -14734,6 +14461,10 @@ snapshots: dependencies: type-fest: 0.21.3 + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -14774,10 +14505,11 @@ snapshots: buffer-crc32: 1.0.0 readable-stream: 4.7.0 readdir-glob: 1.1.3 - tar-stream: 3.1.7 + tar-stream: 3.2.0 zip-stream: 6.0.1 transitivePeerDependencies: - bare-abort-controller + - bare-buffer - react-native-b4a are-we-there-yet@2.0.0: @@ -14811,10 +14543,10 @@ snapshots: array-includes@3.1.9: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 is-string: 1.1.1 @@ -14824,34 +14556,34 @@ snapshots: array.prototype.findlastindex@1.2.6: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-errors: 1.3.0 es-object-atoms: 1.1.1 es-shim-unscopables: 1.1.0 array.prototype.flat@1.3.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-shim-unscopables: 1.1.0 array.prototype.flatmap@1.3.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-shim-unscopables: 1.1.0 arraybuffer.prototype.slice@1.0.4: dependencies: array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-errors: 1.3.0 get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 @@ -14862,7 +14594,7 @@ snapshots: asn1.js@5.4.1: dependencies: - bn.js: 4.12.2 + bn.js: 4.12.3 inherits: 2.0.4 minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 @@ -14871,7 +14603,7 @@ snapshots: dependencies: safer-buffer: 2.1.2 - asn1js@3.0.6: + asn1js@3.0.10: dependencies: pvtsutils: 1.3.6 pvutils: 1.1.5 @@ -14893,8 +14625,6 @@ snapshots: estree-walker: 3.0.3 js-tokens: 10.0.0 - astral-regex@2.0.0: {} - astring@1.9.0: {} async-function@1.0.0: {} @@ -14917,7 +14647,7 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - avvio@9.1.0: + avvio@9.2.0: dependencies: '@fastify/error': 4.2.0 fastq: 1.20.1 @@ -14932,15 +14662,15 @@ snapshots: aws4@1.13.2: {} - axios@1.15.0(debug@4.4.3): + axios@1.16.0(debug@4.4.3): dependencies: - follow-redirects: 1.15.11(debug@4.4.3) + follow-redirects: 1.16.0(debug@4.4.3) form-data: 4.0.5 proxy-from-env: 2.1.0 transitivePeerDependencies: - debug - b4a@1.7.3: {} + b4a@1.8.1: {} babel-walk@3.0.0-canary-5: dependencies: @@ -14950,15 +14680,43 @@ snapshots: balanced-match@1.0.2: {} - balanced-match@4.0.2: + balanced-match@4.0.4: {} + + bare-events@2.8.2: {} + + bare-fs@4.7.1: dependencies: - jackspeak: 4.2.3 + bare-events: 2.8.2 + bare-path: 3.0.0 + bare-stream: 2.13.1(bare-events@2.8.2) + bare-url: 2.4.3 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + bare-os@3.9.1: {} - bare-events@2.8.1: {} + bare-path@3.0.0: + dependencies: + bare-os: 3.9.1 + + bare-stream@2.13.1(bare-events@2.8.2): + dependencies: + streamx: 2.25.0 + teex: 1.0.1 + optionalDependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - react-native-b4a + + bare-url@2.4.3: + dependencies: + bare-path: 3.0.0 base64-js@1.5.1: {} - baseline-browser-mapping@2.10.19: {} + baseline-browser-mapping@2.10.27: {} bcrypt-pbkdf@1.0.2: dependencies: @@ -14966,18 +14724,13 @@ snapshots: bcryptjs@3.0.3: {} - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - optional: true - blob-util@2.0.2: {} bluebird@3.7.2: {} blurhash@2.0.5: {} - bn.js@4.12.2: {} + bn.js@4.12.3: {} body-parser@2.2.2: dependencies: @@ -14987,28 +14740,28 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.14.1 - raw-body: 3.0.1 + qs: 6.15.1 + raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: - supports-color boolbase@1.0.0: {} - bowser@2.12.1: {} + bowser@2.14.1: {} - brace-expansion@1.1.12: + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.2: + brace-expansion@2.1.0: dependencies: balanced-match: 1.0.2 brace-expansion@5.0.5: dependencies: - balanced-match: 4.0.2 + balanced-match: 4.0.4 braces@3.0.3: dependencies: @@ -15023,10 +14776,10 @@ snapshots: browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.19 - caniuse-lite: 1.0.30001788 - electron-to-chromium: 1.5.336 - node-releases: 2.0.37 + baseline-browser-mapping: 2.10.27 + caniuse-lite: 1.0.30001792 + electron-to-chromium: 1.5.352 + node-releases: 2.0.38 update-browserslist-db: 1.2.3(browserslist@4.28.2) buffer-crc32@0.2.13: {} @@ -15057,11 +14810,11 @@ snapshots: node-gyp-build: 4.8.4 optional: true - bullmq@5.76.2: + bullmq@5.76.6: dependencies: cron-parser: 4.9.0 ioredis: 5.10.1 - msgpackr: 1.11.5 + msgpackr: 2.0.1 node-abort-controller: 3.1.1 semver: 7.7.4 tslib: 2.8.1 @@ -15082,25 +14835,11 @@ snapshots: bytes@3.1.2: {} - cacache@20.0.3: - dependencies: - '@npmcli/fs': 5.0.0 - fs-minipass: 3.0.3 - glob: 13.0.1 - lru-cache: 11.2.5 - minipass: 7.1.2 - minipass-collect: 2.0.1 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - p-map: 7.0.3 - ssri: 13.0.0 - unique-filename: 5.0.0 - cacheable-lookup@7.0.0: {} cacheable-request@13.0.18: dependencies: - '@types/http-cache-semantics': 4.0.4 + '@types/http-cache-semantics': 4.2.0 get-stream: 9.0.1 http-cache-semantics: 4.2.0 keyv: 5.6.0 @@ -15115,7 +14854,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bind@1.0.8: + call-bind@1.0.9: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 @@ -15140,11 +14879,11 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.28.2 - caniuse-lite: 1.0.30001788 + caniuse-lite: 1.0.30001792 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001788: {} + caniuse-lite@1.0.30001792: {} canonicalize@2.1.0: {} @@ -15161,7 +14900,7 @@ snapshots: chai@5.3.3: dependencies: assertion-error: 2.0.1 - check-error: 2.1.1 + check-error: 2.1.3 deep-eql: 5.0.2 loupe: 3.2.1 pathval: 2.0.1 @@ -15209,7 +14948,7 @@ snapshots: chart.js: 4.5.1 date-fns: 4.1.0 - chartjs-chart-matrix@3.0.0(chart.js@4.5.1): + chartjs-chart-matrix@3.0.4(chart.js@4.5.1): dependencies: chart.js: 4.5.1 @@ -15223,7 +14962,7 @@ snapshots: chart.js: 4.5.1 hammerjs: 2.0.8 - check-error@2.1.1: {} + check-error@2.1.3: {} check-more-types@2.24.0: {} @@ -15247,7 +14986,7 @@ snapshots: parse5: 7.3.0 parse5-htmlparser2-tree-adapter: 7.1.0 parse5-parser-stream: 7.1.2 - undici: 6.22.0 + undici: 6.25.0 whatwg-mimetype: 4.0.0 cheerio@1.2.0: @@ -15273,21 +15012,19 @@ snapshots: chownr@3.0.0: {} - chromatic@16.6.0: + chromatic@16.9.0: dependencies: semver: 7.7.4 chunk-data@0.1.0: {} - ci-info@4.3.1: {} + ci-info@4.4.0: {} cjs-module-lexer@2.2.0: {} - clean-stack@2.2.0: {} - - cli-cursor@3.1.0: + cli-cursor@5.0.0: dependencies: - restore-cursor: 3.1.0 + restore-cursor: 5.1.0 cli-table3@0.6.1: dependencies: @@ -15295,10 +15032,10 @@ snapshots: optionalDependencies: colors: 1.4.0 - cli-truncate@2.1.0: + cli-truncate@5.2.0: dependencies: - slice-ansi: 3.0.0 - string-width: 4.2.3 + slice-ansi: 8.0.0 + string-width: 8.2.1 cli-width@4.1.0: {} @@ -15323,7 +15060,7 @@ snapshots: cliui@9.0.1: dependencies: string-width: 7.2.0 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrap-ansi: 9.0.2 cluster-key-slot@1.1.2: {} @@ -15417,7 +15154,7 @@ snapshots: constantinople@4.0.1: dependencies: - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 content-disposition@1.1.0: {} @@ -15428,7 +15165,7 @@ snapshots: cookie-signature@1.2.2: {} - cookie@0.7.1: {} + cookie@0.7.2: {} cookie@1.1.1: {} @@ -15472,10 +15209,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-declaration-sorter@7.3.0(postcss@8.5.10): - dependencies: - postcss: 8.5.10 - css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -15489,9 +15222,9 @@ snapshots: mdn-data: 2.0.28 source-map-js: 1.2.1 - css-tree@3.1.0: + css-tree@3.2.1: dependencies: - mdn-data: 2.12.2 + mdn-data: 2.27.1 source-map-js: 1.2.1 css-what@6.2.2: {} @@ -15500,65 +15233,56 @@ snapshots: cssesc@3.0.0: {} - cssnano-preset-default@7.0.15(postcss@8.5.10): + cssnano-preset-default@8.0.0(postcss@8.5.14): dependencies: browserslist: 4.28.2 - css-declaration-sorter: 7.3.0(postcss@8.5.10) - cssnano-utils: 5.0.2(postcss@8.5.10) - postcss: 8.5.10 - postcss-calc: 10.1.1(postcss@8.5.10) - postcss-colormin: 7.0.9(postcss@8.5.10) - postcss-convert-values: 7.0.11(postcss@8.5.10) - postcss-discard-comments: 7.0.7(postcss@8.5.10) - postcss-discard-duplicates: 7.0.3(postcss@8.5.10) - postcss-discard-empty: 7.0.2(postcss@8.5.10) - postcss-discard-overridden: 7.0.2(postcss@8.5.10) - postcss-merge-longhand: 7.0.6(postcss@8.5.10) - postcss-merge-rules: 7.0.10(postcss@8.5.10) - postcss-minify-font-values: 7.0.2(postcss@8.5.10) - postcss-minify-gradients: 7.0.4(postcss@8.5.10) - postcss-minify-params: 7.0.8(postcss@8.5.10) - postcss-minify-selectors: 7.1.0(postcss@8.5.10) - postcss-normalize-charset: 7.0.2(postcss@8.5.10) - postcss-normalize-display-values: 7.0.2(postcss@8.5.10) - postcss-normalize-positions: 7.0.3(postcss@8.5.10) - postcss-normalize-repeat-style: 7.0.3(postcss@8.5.10) - postcss-normalize-string: 7.0.2(postcss@8.5.10) - postcss-normalize-timing-functions: 7.0.2(postcss@8.5.10) - postcss-normalize-unicode: 7.0.8(postcss@8.5.10) - postcss-normalize-url: 7.0.2(postcss@8.5.10) - postcss-normalize-whitespace: 7.0.2(postcss@8.5.10) - postcss-ordered-values: 7.0.3(postcss@8.5.10) - postcss-reduce-initial: 7.0.8(postcss@8.5.10) - postcss-reduce-transforms: 7.0.2(postcss@8.5.10) - postcss-svgo: 7.1.2(postcss@8.5.10) - postcss-unique-selectors: 7.0.6(postcss@8.5.10) - - cssnano-utils@5.0.2(postcss@8.5.10): - dependencies: - postcss: 8.5.10 - - cssnano@7.1.7(postcss@8.5.10): - dependencies: - cssnano-preset-default: 7.0.15(postcss@8.5.10) + cssnano-utils: 6.0.0(postcss@8.5.14) + postcss: 8.5.14 + postcss-calc: 10.1.1(postcss@8.5.14) + postcss-colormin: 8.0.0(postcss@8.5.14) + postcss-convert-values: 8.0.0(postcss@8.5.14) + postcss-discard-comments: 8.0.0(postcss@8.5.14) + postcss-discard-duplicates: 8.0.0(postcss@8.5.14) + postcss-discard-empty: 8.0.0(postcss@8.5.14) + postcss-discard-overridden: 8.0.0(postcss@8.5.14) + postcss-merge-longhand: 8.0.0(postcss@8.5.14) + postcss-merge-rules: 8.0.0(postcss@8.5.14) + postcss-minify-font-values: 8.0.0(postcss@8.5.14) + postcss-minify-gradients: 8.0.0(postcss@8.5.14) + postcss-minify-params: 8.0.0(postcss@8.5.14) + postcss-minify-selectors: 8.0.0(postcss@8.5.14) + postcss-normalize-charset: 8.0.0(postcss@8.5.14) + postcss-normalize-display-values: 8.0.0(postcss@8.5.14) + postcss-normalize-positions: 8.0.0(postcss@8.5.14) + postcss-normalize-repeat-style: 8.0.0(postcss@8.5.14) + postcss-normalize-string: 8.0.0(postcss@8.5.14) + postcss-normalize-timing-functions: 8.0.0(postcss@8.5.14) + postcss-normalize-unicode: 8.0.0(postcss@8.5.14) + postcss-normalize-url: 8.0.0(postcss@8.5.14) + postcss-normalize-whitespace: 8.0.0(postcss@8.5.14) + postcss-ordered-values: 8.0.0(postcss@8.5.14) + postcss-reduce-initial: 8.0.0(postcss@8.5.14) + postcss-reduce-transforms: 8.0.0(postcss@8.5.14) + postcss-svgo: 8.0.0(postcss@8.5.14) + postcss-unique-selectors: 8.0.0(postcss@8.5.14) + + cssnano-utils@6.0.0(postcss@8.5.14): + dependencies: + postcss: 8.5.14 + + cssnano@8.0.0(postcss@8.5.14): + dependencies: + cssnano-preset-default: 8.0.0(postcss@8.5.14) lilconfig: 3.1.3 - postcss: 8.5.10 + postcss: 8.5.14 csso@5.0.5: dependencies: css-tree: 2.2.1 - cssstyle@5.3.7: - dependencies: - '@asamuzakjp/css-color': 4.1.2 - '@csstools/css-syntax-patches-for-csstree': 1.0.26 - css-tree: 3.1.0 - lru-cache: 11.2.5 - optional: true - csstype@3.2.3: {} - cypress@15.14.1: + cypress@15.14.2: dependencies: '@cypress/request': 3.0.10 '@cypress/xvfb': 1.2.4(supports-color@8.1.1) @@ -15571,23 +15295,20 @@ snapshots: buffer: 5.7.1 cachedir: 2.4.0 chalk: 4.1.2 - ci-info: 4.3.1 - cli-cursor: 3.1.0 + ci-info: 4.4.0 cli-table3: 0.6.1 commander: 6.2.1 common-tags: 1.8.2 - dayjs: 1.11.19 + dayjs: 1.11.20 debug: 4.4.3(supports-color@8.1.1) - enquirer: 2.4.1 eventemitter2: 6.4.7 execa: 4.1.0 executable: 4.1.1 extract-zip: 2.0.1(supports-color@8.1.1) - figures: 3.2.0 fs-extra: 9.1.0 hasha: 5.2.2 is-installed-globally: 0.4.0 - listr2: 3.14.0(enquirer@2.4.1) + listr2: 9.0.5 lodash: 4.18.1 log-symbols: 4.1.0 minimist: 1.2.8 @@ -15597,7 +15318,7 @@ snapshots: proxy-from-env: 1.0.0 request-progress: 3.0.0 supports-color: 8.1.1 - systeminformation: 5.31.5 + systeminformation: 5.31.6 tmp: 0.2.5 tree-kill: 1.2.2 tslib: 1.14.1 @@ -15610,12 +15331,6 @@ snapshots: data-uri-to-buffer@4.0.1: {} - data-urls@6.0.1: - dependencies: - whatwg-mimetype: 5.0.0 - whatwg-url: 15.1.0 - optional: true - data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -15636,7 +15351,7 @@ snapshots: date-fns@4.1.0: {} - dayjs@1.11.19: {} + dayjs@1.11.20: {} de-indent@1.0.2: {} @@ -15675,9 +15390,6 @@ snapshots: decamelize@1.2.0: {} - decimal.js@10.6.0: - optional: true - decode-bmp@0.2.1: dependencies: '@canvas/image-data': 1.1.0 @@ -15689,7 +15401,7 @@ snapshots: decode-bmp: 0.2.1 to-data-view: 1.1.0 - decode-named-character-reference@1.2.0: + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -15697,7 +15409,7 @@ snapshots: dependencies: mimic-response: 4.0.0 - dedent@1.7.0: {} + dedent@1.7.2: {} deep-email-validator@0.1.27: dependencies: @@ -15709,7 +15421,7 @@ snapshots: deep-equal@2.2.3: dependencies: array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 + call-bind: 1.0.9 es-get-iterator: 1.1.3 get-intrinsic: 1.3.0 is-arguments: 1.2.0 @@ -15725,7 +15437,7 @@ snapshots: side-channel: 1.1.0 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.19 + which-typed-array: 1.1.20 deep-is@0.1.4: {} @@ -15733,7 +15445,7 @@ snapshots: default-browser-id@5.0.1: {} - default-browser@5.4.0: + default-browser@5.5.0: dependencies: bundle-name: 4.1.0 default-browser-id: 5.0.1 @@ -15763,9 +15475,6 @@ snapshots: dequal@2.0.3: {} - detect-libc@1.0.3: - optional: true - detect-libc@2.1.2: {} devlop@1.1.0: @@ -15781,9 +15490,9 @@ snapshots: diff-sequences@29.6.3: {} - diff@5.2.0: {} + diff@5.2.2: {} - diff@8.0.2: {} + diff@8.0.4: {} dijkstrajs@1.0.3: {} @@ -15846,16 +15555,16 @@ snapshots: dependencies: safe-buffer: 5.2.1 - editorconfig@1.0.4: + editorconfig@1.0.7: dependencies: '@one-ini/wasm': 0.1.1 commander: 10.0.1 - minimatch: 9.0.1 + minimatch: 9.0.9 semver: 7.7.4 ee-first@1.1.1: {} - electron-to-chromium@1.5.336: {} + electron-to-chromium@1.5.352: {} emoji-regex@10.6.0: {} @@ -15872,20 +15581,10 @@ snapshots: iconv-lite: 0.6.3 whatwg-encoding: 3.1.1 - encoding@0.1.13: - dependencies: - iconv-lite: 0.6.3 - optional: true - end-of-stream@1.4.5: dependencies: once: 1.4.0 - enquirer@2.4.1: - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - entities@2.2.0: {} entities@4.5.0: {} @@ -15896,18 +15595,18 @@ snapshots: env-paths@2.2.1: {} - err-code@2.0.3: {} + environment@1.1.0: {} error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 - es-abstract@1.24.0: + es-abstract@1.24.2: dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 data-view-buffer: 1.0.2 data-view-byte-length: 1.0.2 @@ -15926,7 +15625,7 @@ snapshots: has-property-descriptors: 1.0.2 has-proto: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.3 internal-slot: 1.1.0 is-array-buffer: 3.0.5 is-callable: 1.2.7 @@ -15944,7 +15643,7 @@ snapshots: object.assign: 4.1.7 own-keys: 1.0.1 regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 + safe-array-concat: 1.1.4 safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 set-proto: 1.0.0 @@ -15957,7 +15656,7 @@ snapshots: typed-array-byte-offset: 1.0.4 typed-array-length: 1.0.7 unbox-primitive: 1.1.0 - which-typed-array: 1.1.19 + which-typed-array: 1.1.20 es-define-property@1.0.1: {} @@ -15965,7 +15664,7 @@ snapshots: es-get-iterator@1.1.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 get-intrinsic: 1.3.0 has-symbols: 1.1.0 is-arguments: 1.2.0 @@ -15975,7 +15674,7 @@ snapshots: isarray: 2.0.5 stop-iteration-iterator: 1.1.0 - es-module-lexer@2.0.0: {} + es-module-lexer@2.1.0: {} es-object-atoms@1.1.1: dependencies: @@ -15986,11 +15685,11 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 es-shim-unscopables@1.1.0: dependencies: - hasown: 2.0.2 + hasown: 2.0.3 es-to-primitive@1.3.0: dependencies: @@ -15998,7 +15697,7 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.42.0: {} + es-toolkit@1.46.1: {} es6-promise@4.2.8: optional: true @@ -16008,34 +15707,34 @@ snapshots: es6-promise: 4.2.8 optional: true - esbuild@0.27.4: + esbuild@0.27.7: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.4 - '@esbuild/android-arm': 0.27.4 - '@esbuild/android-arm64': 0.27.4 - '@esbuild/android-x64': 0.27.4 - '@esbuild/darwin-arm64': 0.27.4 - '@esbuild/darwin-x64': 0.27.4 - '@esbuild/freebsd-arm64': 0.27.4 - '@esbuild/freebsd-x64': 0.27.4 - '@esbuild/linux-arm': 0.27.4 - '@esbuild/linux-arm64': 0.27.4 - '@esbuild/linux-ia32': 0.27.4 - '@esbuild/linux-loong64': 0.27.4 - '@esbuild/linux-mips64el': 0.27.4 - '@esbuild/linux-ppc64': 0.27.4 - '@esbuild/linux-riscv64': 0.27.4 - '@esbuild/linux-s390x': 0.27.4 - '@esbuild/linux-x64': 0.27.4 - '@esbuild/netbsd-arm64': 0.27.4 - '@esbuild/netbsd-x64': 0.27.4 - '@esbuild/openbsd-arm64': 0.27.4 - '@esbuild/openbsd-x64': 0.27.4 - '@esbuild/openharmony-arm64': 0.27.4 - '@esbuild/sunos-x64': 0.27.4 - '@esbuild/win32-arm64': 0.27.4 - '@esbuild/win32-ia32': 0.27.4 - '@esbuild/win32-x64': 0.27.4 + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 esbuild@0.28.0: optionalDependencies: @@ -16074,8 +15773,6 @@ snapshots: escape-regexp@0.0.1: {} - escape-string-regexp@1.0.5: {} - escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} @@ -16091,25 +15788,25 @@ snapshots: string-width: 4.2.3 supports-hyperlinks: 2.3.0 - eslint-import-resolver-node@0.3.9: + eslint-import-resolver-node@0.3.10: dependencies: debug: 3.2.7(supports-color@8.1.1) - is-core-module: 2.16.1 - resolve: 1.22.11 + is-core-module: 2.16.2 + resolve: 2.0.0-next.6 transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 8.59.0(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.2(eslint@9.39.4)(typescript@5.9.3) eslint: 9.39.4 - eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-node: 0.3.10 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -16119,10 +15816,10 @@ snapshots: debug: 3.2.7(supports-color@8.1.1) doctrine: 2.1.0 eslint: 9.39.4 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4) - hasown: 2.0.2 - is-core-module: 2.16.1 + eslint-import-resolver-node: 0.3.10 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4) + hasown: 2.0.3 + is-core-module: 2.16.2 is-glob: 4.0.3 minimatch: 3.1.5 object.fromentries: 2.0.8 @@ -16132,13 +15829,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.59.0(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.2(eslint@9.39.4)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-vue@10.9.0(@stylistic/eslint-plugin@5.5.0(eslint@9.39.4))(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)): + eslint-plugin-vue@10.9.1(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4))(@typescript-eslint/parser@8.59.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(vue-eslint-parser@10.4.0(eslint@9.39.4)): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) eslint: 9.39.4 @@ -16149,8 +15846,8 @@ snapshots: vue-eslint-parser: 10.4.0(eslint@9.39.4) xml-name-validator: 4.0.0 optionalDependencies: - '@stylistic/eslint-plugin': 5.5.0(eslint@9.39.4) - '@typescript-eslint/parser': 8.59.0(eslint@9.39.4)(typescript@5.9.3) + '@stylistic/eslint-plugin': 5.10.0(eslint@9.39.4) + '@typescript-eslint/parser': 8.59.2(eslint@9.39.4)(typescript@5.9.3) eslint-rule-docs@1.1.235: {} @@ -16159,6 +15856,13 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 + eslint-scope@9.1.2: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 + esrecurse: 4.3.0 + estraverse: 5.3.0 + eslint-visitor-keys@3.4.3: {} eslint-visitor-keys@4.2.1: {} @@ -16175,11 +15879,11 @@ snapshots: '@eslint/eslintrc': 3.3.5 '@eslint/js': 9.39.4 '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 + '@types/estree': 1.0.9 + ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3(supports-color@10.2.2) @@ -16187,7 +15891,7 @@ snapshots: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - esquery: 1.6.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 @@ -16212,9 +15916,15 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 + espree@11.2.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 5.0.1 + esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -16228,7 +15938,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esutils@2.0.3: {} @@ -16244,7 +15954,7 @@ snapshots: events-universal@1.0.1: dependencies: - bare-events: 2.8.1 + bare-events: 2.8.2 transitivePeerDependencies: - bare-abort-controller @@ -16307,7 +16017,7 @@ snapshots: exifreader@4.38.1: optionalDependencies: - '@xmldom/xmldom': 0.9.9 + '@xmldom/xmldom': 0.9.10 expect-type@1.3.0: {} @@ -16319,14 +16029,14 @@ snapshots: body-parser: 2.2.2 content-disposition: 1.1.0 content-type: 1.0.5 - cookie: 0.7.1 + cookie: 0.7.2 cookie-signature: 1.2.2 debug: 4.4.3(supports-color@10.2.2) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 2.1.0 + finalhandler: 2.1.1 fresh: 2.0.0 http-errors: 2.0.1 merge-descriptors: 2.0.0 @@ -16335,11 +16045,11 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.14.1 + qs: 6.15.1 range-parser: 1.2.1 router: 2.2.0 - send: 1.2.0 - serve-static: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 statuses: 2.0.2 type-is: 2.0.1 vary: 1.1.2 @@ -16378,12 +16088,12 @@ snapshots: fast-json-stable-stringify@2.1.0: {} - fast-json-stringify@6.1.1: + fast-json-stringify@6.4.0: dependencies: '@fastify/merge-json-schemas': 0.2.1 ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) - fast-uri: 3.1.0 + fast-uri: 3.1.2 json-schema-ref-resolver: 3.0.0 rfdc: 1.4.1 @@ -16401,20 +16111,20 @@ snapshots: dependencies: fast-string-truncated-width: 3.0.3 - fast-uri@3.1.0: {} + fast-uri@3.1.2: {} fast-wrap-ansi@0.2.0: dependencies: fast-string-width: 3.0.2 - fast-xml-builder@1.1.5: + fast-xml-builder@1.1.9: dependencies: path-expression-matcher: 1.5.0 - fast-xml-parser@5.7.1: + fast-xml-parser@5.7.2: dependencies: '@nodable/entities': 2.1.0 - fast-xml-builder: 1.1.5 + fast-xml-builder: 1.1.9 path-expression-matcher: 1.5.0 strnum: 2.2.3 @@ -16423,7 +16133,7 @@ snapshots: fastify-raw-body@5.0.0: dependencies: fastify-plugin: 5.1.0 - raw-body: 3.0.1 + raw-body: 3.0.2 secure-json-parse: 2.7.0 fastify@5.8.5: @@ -16433,11 +16143,11 @@ snapshots: '@fastify/fast-json-stringify-compiler': 5.0.3 '@fastify/proxy-addr': 5.1.0 abstract-logging: 2.0.1 - avvio: 9.1.0 - fast-json-stringify: 6.1.1 - find-my-way: 9.3.0 + avvio: 9.2.0 + fast-json-stringify: 6.4.0 + find-my-way: 9.6.0 light-my-request: 6.6.0 - pino: 10.1.0 + pino: 10.3.1 process-warning: 5.0.0 rfdc: 1.4.1 secure-json-parse: 4.1.0 @@ -16465,10 +16175,6 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 - figures@3.2.0: - dependencies: - escape-string-regexp: 1.0.5 - figures@6.1.0: dependencies: is-unicode-supported: 2.1.0 @@ -16499,7 +16205,7 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.0: + finalhandler@2.1.1: dependencies: debug: 4.4.3(supports-color@10.2.2) encodeurl: 2.0.0 @@ -16510,11 +16216,11 @@ snapshots: transitivePeerDependencies: - supports-color - find-my-way@9.3.0: + find-my-way@9.6.0: dependencies: fast-deep-equal: 3.1.3 fast-querystring: 1.1.2 - safe-regex2: 5.0.0 + safe-regex2: 5.1.1 find-up@4.1.0: dependencies: @@ -16536,17 +16242,17 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.2 keyv: 4.5.4 - flatted@3.3.3: {} + flatted@3.4.2: {} fluent-ffmpeg@2.1.3: dependencies: async: 0.2.10 which: 1.3.1 - follow-redirects@1.15.11(debug@4.4.3): + follow-redirects@1.16.0(debug@4.4.3): optionalDependencies: debug: 4.4.3(supports-color@10.2.2) @@ -16566,7 +16272,7 @@ snapshots: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 - hasown: 2.0.2 + hasown: 2.0.3 mime-types: 2.1.35 formdata-polyfill@4.0.10: @@ -16585,17 +16291,17 @@ snapshots: fresh@2.0.0: {} - fs-extra@11.3.2: + fs-extra@11.3.5: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 fs-minipass@2.1.0: @@ -16603,10 +16309,6 @@ snapshots: minipass: 3.3.6 optional: true - fs-minipass@3.0.3: - dependencies: - minipass: 7.1.2 - fs.realpath@1.0.0: optional: true @@ -16617,11 +16319,11 @@ snapshots: function.prototype.name@1.1.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 - hasown: 2.0.2 + hasown: 2.0.3 is-callable: 1.2.7 functions-have-names@1.2.3: {} @@ -16645,7 +16347,7 @@ snapshots: get-caller-file@2.0.5: {} - get-east-asian-width@1.4.0: {} + get-east-asian-width@1.5.0: {} get-intrinsic@1.3.0: dependencies: @@ -16657,7 +16359,7 @@ snapshots: get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.3 math-intrinsics: 1.1.0 get-proto@1.0.1: @@ -16667,7 +16369,7 @@ snapshots: get-stream@5.2.0: dependencies: - pump: 3.0.3 + pump: 3.0.4 get-stream@6.0.1: {} @@ -16682,7 +16384,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-tsconfig@4.13.0: + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -16702,16 +16404,16 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 + minimatch: 9.0.9 + minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@13.0.1: + glob@13.0.6: dependencies: minimatch: 10.2.5 - minipass: 7.1.2 - path-scurry: 2.0.1 + minipass: 7.1.3 + path-scurry: 2.0.2 glob@7.2.3: dependencies: @@ -16729,7 +16431,7 @@ snapshots: globals@14.0.0: {} - globals@17.5.0: {} + globals@17.6.0: {} globalthis@1.0.4: dependencies: @@ -16765,9 +16467,24 @@ snapshots: type-fest: 5.6.0 uint8array-extras: 1.5.0 + got@15.0.5: + dependencies: + '@sindresorhus/is': 8.0.0 + byte-counter: 0.1.0 + cacheable-lookup: 7.0.0 + cacheable-request: 13.0.18 + chunk-data: 0.1.0 + decompress-response: 10.0.0 + http2-wrapper: 2.2.1 + keyv: 5.6.0 + lowercase-keys: 4.0.1 + responselike: 4.0.2 + type-fest: 5.6.0 + uint8array-extras: 1.5.0 + graceful-fs@4.2.11: {} - graphql@16.13.2: {} + graphql@16.14.0: {} hammerjs@2.0.8: {} @@ -16817,7 +16534,7 @@ snapshots: is-stream: 2.0.1 type-fest: 0.8.1 - hasown@2.0.2: + hasown@2.0.3: dependencies: function-bind: 1.1.2 @@ -16829,7 +16546,7 @@ snapshots: comma-separated-tokens: 2.0.3 hast-util-whitespace: 3.0.0 html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.0 + mdast-util-to-hast: 13.2.1 property-information: 7.1.0 space-separated-tokens: 2.0.2 stringify-entities: 4.0.4 @@ -16856,11 +16573,6 @@ snapshots: hpagent@1.2.0: {} - html-encoding-sniffer@4.0.0: - dependencies: - whatwg-encoding: 3.1.1 - optional: true - html-entities@2.6.0: {} html-escaper@2.0.2: {} @@ -16883,14 +16595,6 @@ snapshots: http-cache-semantics@4.2.0: {} - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -16901,13 +16605,6 @@ snapshots: http-link-header@1.1.3: {} - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3(supports-color@10.2.2) - transitivePeerDependencies: - - supports-color - http-signature@1.4.0: dependencies: assert-plus: 1.0.0 @@ -16960,10 +16657,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.7.0: - dependencies: - safer-buffer: 2.1.2 - iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -16996,7 +16689,7 @@ snapshots: cjs-module-lexer: 2.2.0 module-details-from-path: 1.0.4 - import-in-the-middle@3.0.0: + import-in-the-middle@3.0.1: dependencies: acorn: 8.16.0 acorn-import-attributes: 1.9.5(acorn@8.16.0) @@ -17025,12 +16718,12 @@ snapshots: insert-text-at-cursor@0.3.0: {} - install-artifact-from-github@1.4.0: {} + install-artifact-from-github@1.6.0: {} internal-slot@1.1.0: dependencies: es-errors: 1.3.0 - hasown: 2.0.2 + hasown: 2.0.3 side-channel: 1.1.0 intersection-observer@0.12.2: {} @@ -17049,9 +16742,7 @@ snapshots: transitivePeerDependencies: - supports-color - ios-haptics@0.1.4: {} - - ip-address@10.0.1: {} + ios-haptics@0.1.5: {} ip-address@9.0.5: dependencies: @@ -17066,6 +16757,8 @@ snapshots: ipaddr.js@2.3.0: {} + ipaddr.js@2.4.0: {} + irregular-plurals@3.5.0: {} is-arguments@1.2.0: @@ -17075,7 +16768,7 @@ snapshots: is-array-buffer@3.0.5: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 @@ -17102,9 +16795,9 @@ snapshots: is-callable@1.2.7: {} - is-core-module@2.16.1: + is-core-module@2.16.2: dependencies: - hasown: 2.0.2 + hasown: 2.0.3 is-data-view@1.0.2: dependencies: @@ -17134,6 +16827,10 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.5.0 + is-generator-function@1.1.2: dependencies: call-bound: 1.0.4 @@ -17176,9 +16873,6 @@ snapshots: is-plain-object@5.0.0: {} - is-potential-custom-element-name@1.0.1: - optional: true - is-promise@2.2.2: {} is-promise@4.0.0: {} @@ -17188,7 +16882,7 @@ snapshots: call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 is-set@2.0.3: {} @@ -17219,7 +16913,7 @@ snapshots: is-typed-array@1.1.15: dependencies: - which-typed-array: 1.1.19 + which-typed-array: 1.1.20 is-typedarray@1.0.0: {} @@ -17238,7 +16932,7 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 - is-wsl@3.1.0: + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -17248,7 +16942,7 @@ snapshots: isexe@2.0.0: {} - isexe@3.1.1: {} + isexe@4.0.0: {} isstream@0.1.2: {} @@ -17273,10 +16967,6 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jackspeak@4.2.3: - dependencies: - '@isaacs/cliui': 9.0.0 - jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -17296,20 +16986,20 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 - joi@18.1.2: + joi@18.2.1: dependencies: '@hapi/address': 5.1.1 '@hapi/formula': 3.0.2 '@hapi/hoek': 11.0.7 '@hapi/pinpoint': 2.0.1 - '@hapi/tlds': 1.1.4 + '@hapi/tlds': 1.1.6 '@hapi/topo': 6.0.2 '@standard-schema/spec': 1.1.0 js-beautify@1.15.4: dependencies: config-chain: 1.1.13 - editorconfig: 1.0.4 + editorconfig: 1.0.7 glob: 10.5.0 js-cookie: 3.0.5 nopt: 7.2.1 @@ -17332,34 +17022,6 @@ snapshots: jsbn@1.1.0: {} - jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): - dependencies: - '@acemir/cssom': 0.9.31 - '@asamuzakjp/dom-selector': 6.7.8 - cssstyle: 5.3.7 - data-urls: 6.0.1 - decimal.js: 10.6.0 - html-encoding-sniffer: 4.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6(supports-color@10.2.2) - is-potential-custom-element-name: 1.0.1 - parse5: 8.0.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 6.0.1 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.1 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 - ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - optional: true - jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -17386,7 +17048,7 @@ snapshots: json5@2.2.3: {} - jsonfile@6.2.0: + jsonfile@6.2.1: dependencies: universalify: 2.0.1 optionalDependencies: @@ -17394,7 +17056,7 @@ snapshots: jsonld@9.0.0: dependencies: - '@digitalbazaar/http-client': 4.2.0 + '@digitalbazaar/http-client': 4.3.0 canonicalize: 2.1.0 lru-cache: 6.0.0 rdf-canonize: 5.0.0 @@ -17437,7 +17099,7 @@ snapshots: ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - jws@4.0.0: + jws@4.0.1: dependencies: jwa: 2.0.1 safe-buffer: 5.2.1 @@ -17452,7 +17114,7 @@ snapshots: kind-of@6.0.3: {} - ky@1.14.0: {} + ky@1.14.3: {} lazy-ass@1.6.0: {} @@ -17471,7 +17133,7 @@ snapshots: dependencies: cookie: 1.1.1 process-warning: 4.0.1 - set-cookie-parser: 2.7.1 + set-cookie-parser: 2.7.2 lightningcss-android-arm64@1.32.0: optional: true @@ -17526,18 +17188,14 @@ snapshots: lines-and-columns@1.2.4: {} - listr2@3.14.0(enquirer@2.4.1): + listr2@9.0.5: dependencies: - cli-truncate: 2.1.0 + cli-truncate: 5.2.0 colorette: 2.0.20 - log-update: 4.0.0 - p-map: 4.0.0 + eventemitter3: 5.0.4 + log-update: 6.1.0 rfdc: 1.4.1 - rxjs: 7.8.2 - through: 2.3.8 - wrap-ansi: 7.0.0 - optionalDependencies: - enquirer: 2.4.1 + wrap-ansi: 9.0.2 load-esm@1.0.3: {} @@ -17568,12 +17226,13 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 - log-update@4.0.0: + log-update@6.1.0: dependencies: - ansi-escapes: 4.3.2 - cli-cursor: 3.1.0 - slice-ansi: 4.0.0 - wrap-ansi: 6.2.0 + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 long@4.0.0: {} @@ -17587,7 +17246,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.5: {} + lru-cache@11.3.6: {} lru-cache@5.1.1: dependencies: @@ -17609,7 +17268,7 @@ snapshots: magicast@0.5.2: dependencies: - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 source-map-js: 1.2.1 @@ -17624,22 +17283,6 @@ snapshots: dependencies: semver: 7.7.4 - make-fetch-happen@15.0.3: - dependencies: - '@npmcli/agent': 4.0.0 - cacache: 20.0.3 - http-cache-semantics: 4.2.0 - minipass: 7.1.2 - minipass-fetch: 5.0.0 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - negotiator: 1.0.0 - proc-log: 6.1.0 - promise-retry: 2.0.1 - ssri: 13.0.0 - transitivePeerDependencies: - - supports-color - map-obj@1.0.1: {} map-obj@4.3.0: {} @@ -17659,11 +17302,11 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.2: + mdast-util-from-markdown@2.0.3: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 micromark: 4.0.2 @@ -17688,7 +17331,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: @@ -17697,7 +17340,7 @@ snapshots: mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -17707,7 +17350,7 @@ snapshots: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -17716,14 +17359,14 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm@3.1.0: dependencies: - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-gfm-autolink-literal: 2.0.1 mdast-util-gfm-footnote: 2.1.0 mdast-util-gfm-strikethrough: 2.0.0 @@ -17738,16 +17381,16 @@ snapshots: '@types/mdast': 4.0.4 unist-util-is: 6.0.1 - mdast-util-to-hast@13.2.0: + mdast-util-to-hast@13.2.1: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.0 + '@ungap/structured-clone': 1.3.1 devlop: 1.1.0 micromark-util-sanitize-uri: 2.0.1 trim-lines: 3.0.1 unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 mdast-util-to-markdown@2.1.2: @@ -17759,7 +17402,7 @@ snapshots: mdast-util-to-string: 4.0.0 micromark-util-classify-character: 2.0.1 micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 zwitch: 2.0.4 mdast-util-to-string@4.0.0: @@ -17768,18 +17411,18 @@ snapshots: mdn-data@2.0.28: {} - mdn-data@2.12.2: {} + mdn-data@2.27.1: {} media-typer@0.3.0: {} media-typer@1.1.0: {} - mediabunny@1.41.0: + mediabunny@1.44.1: dependencies: '@types/dom-mediacapture-transform': 0.1.11 '@types/dom-webcodecs': 0.1.13 - meilisearch@0.57.0: {} + meilisearch@0.58.0: {} memoizerific@1.11.3: dependencies: @@ -17816,7 +17459,7 @@ snapshots: micromark-core-commonmark@2.0.3: dependencies: - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-factory-destination: 2.0.1 micromark-factory-label: 2.0.1 @@ -17949,7 +17592,7 @@ snapshots: micromark-util-decode-string@2.0.1: dependencies: - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 micromark-util-character: 2.1.1 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-symbol: 2.0.1 @@ -17985,9 +17628,9 @@ snapshots: micromark@4.0.2: dependencies: - '@types/debug': 4.1.12 + '@types/debug': 4.1.13 debug: 4.4.3(supports-color@10.2.2) - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-factory-space: 2.0.1 @@ -18008,7 +17651,7 @@ snapshots: micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 + picomatch: 2.3.2 mime-db@1.52.0: {} @@ -18030,6 +17673,8 @@ snapshots: mimic-fn@4.0.0: {} + mimic-function@5.0.1: {} + mimic-response@4.0.0: {} min-indent@1.0.1: {} @@ -18046,19 +17691,15 @@ snapshots: minimatch@3.1.5: dependencies: - brace-expansion: 1.1.12 + brace-expansion: 1.1.14 - minimatch@5.1.6: + minimatch@5.1.9: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 2.1.0 - minimatch@9.0.1: + minimatch@9.0.9: dependencies: - brace-expansion: 2.0.2 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 + brace-expansion: 2.1.0 minimist-options@4.1.0: dependencies: @@ -18068,38 +17709,15 @@ snapshots: minimist@1.2.8: {} - minipass-collect@2.0.1: - dependencies: - minipass: 7.1.2 - - minipass-fetch@5.0.0: - dependencies: - minipass: 7.1.2 - minipass-sized: 1.0.3 - minizlib: 3.1.0 - optionalDependencies: - encoding: 0.1.13 - - minipass-flush@1.0.5: - dependencies: - minipass: 3.3.6 - - minipass-pipeline@1.2.4: - dependencies: - minipass: 3.3.6 - - minipass-sized@1.0.3: - dependencies: - minipass: 3.3.6 - minipass@3.3.6: dependencies: yallist: 4.0.0 + optional: true minipass@5.0.0: optional: true - minipass@7.1.2: {} + minipass@7.1.3: {} minizlib@2.1.2: dependencies: @@ -18109,7 +17727,7 @@ snapshots: minizlib@3.1.0: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 mkdirp@1.0.4: optional: true @@ -18119,7 +17737,7 @@ snapshots: acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.3 + ufo: 1.6.4 mock-socket@9.3.1: {} @@ -18143,29 +17761,29 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 optional: true - msgpackr@1.11.5: + msgpackr@2.0.1: optionalDependencies: msgpackr-extract: 3.0.3 - msw-storybook-addon@2.0.7(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3)): + msw-storybook-addon@2.0.7(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3)): dependencies: is-node-process: 1.2.0 - msw: 2.13.6(@types/node@24.12.2)(typescript@5.9.3) + msw: 2.14.3(@types/node@24.12.2)(typescript@5.9.3) - msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3): + msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3): dependencies: '@inquirer/confirm': 6.0.12(@types/node@24.12.2) - '@mswjs/interceptors': 0.41.6 + '@mswjs/interceptors': 0.41.8 '@open-draft/deferred-promise': 3.0.0 '@types/statuses': 2.0.6 cookie: 1.1.1 - graphql: 16.13.2 + graphql: 16.14.0 headers-polyfill: 5.0.1 is-node-process: 1.2.0 outvariant: 1.4.3 path-to-regexp: 6.3.0 picocolors: 1.1.1 - rettime: 0.11.7 + rettime: 0.11.11 statuses: 2.0.2 strict-event-emitter: 0.5.1 tough-cookie: 6.0.1 @@ -18192,9 +17810,9 @@ snapshots: nan@2.26.2: {} - nanoid@3.3.11: {} + nanoid@3.3.12: {} - nanoid@5.1.9: {} + nanoid@5.1.11: {} natural-compare@1.4.0: {} @@ -18204,7 +17822,7 @@ snapshots: dependencies: debug: 3.2.7(supports-color@8.1.1) iconv-lite: 0.4.24 - sax: 1.5.0 + sax: 1.6.0 transitivePeerDependencies: - supports-color @@ -18214,15 +17832,14 @@ snapshots: nested-property@4.0.0: {} - nise@6.1.1: + nise@6.1.5: dependencies: '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers': 13.0.5 - '@sinonjs/text-encoding': 0.7.3 + '@sinonjs/fake-timers': 15.4.0 just-extend: 6.2.0 path-to-regexp: 8.4.2 - node-abi@3.85.0: + node-abi@3.92.0: dependencies: semver: 7.7.4 @@ -18233,17 +17850,20 @@ snapshots: node-domexception@1.0.0: {} - node-fetch@2.6.13(encoding@0.1.13): + node-exports-info@1.6.0: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 + + node-fetch@2.6.13: dependencies: whatwg-url: 5.0.0 - optionalDependencies: - encoding: 0.1.13 - node-fetch@2.7.0(encoding@0.1.13): + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 - optionalDependencies: - encoding: 0.1.13 optional: true node-fetch@3.3.2: @@ -18260,29 +17880,27 @@ snapshots: node-gyp-build@4.8.4: optional: true - node-gyp@12.2.0: + node-gyp@12.3.0: dependencies: env-paths: 2.2.1 exponential-backoff: 3.1.3 graceful-fs: 4.2.11 - make-fetch-happen: 15.0.3 nopt: 9.0.0 proc-log: 6.1.0 semver: 7.7.4 - tar: 7.5.13 + tar: 7.5.14 tinyglobby: 0.2.16 - which: 6.0.0 - transitivePeerDependencies: - - supports-color + undici: 6.25.0 + which: 6.0.1 node-html-parser@7.1.0: dependencies: css-select: 5.2.2 he: 1.2.0 - node-releases@2.0.37: {} + node-releases@2.0.38: {} - nodemailer@8.0.6: {} + nodemailer@8.0.7: {} nodemon@3.1.14: dependencies: @@ -18315,14 +17933,14 @@ snapshots: normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.11 + resolve: 1.22.12 semver: 5.7.2 validate-npm-package-license: 3.0.4 normalize-package-data@3.0.3: dependencies: hosted-git-info: 4.1.0 - is-core-module: 2.16.1 + is-core-module: 2.16.2 semver: 7.7.4 validate-npm-package-license: 3.0.4 @@ -18351,9 +17969,9 @@ snapshots: set-blocking: 2.0.0 optional: true - nsfwjs@4.3.0(@tensorflow/tfjs@4.22.0(encoding@0.1.13)(seedrandom@3.0.5))(buffer@6.0.3): + nsfwjs@4.3.0(@tensorflow/tfjs@4.22.0(seedrandom@3.0.5))(buffer@6.0.3): dependencies: - '@tensorflow/tfjs': 4.22.0(encoding@0.1.13)(seedrandom@3.0.5) + '@tensorflow/tfjs': 4.22.0(seedrandom@3.0.5) buffer: 6.0.3 nth-check@2.1.1: @@ -18376,36 +17994,43 @@ snapshots: object-is@1.1.6: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 object-keys@1.1.1: {} object.assign@4.1.7: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 has-symbols: 1.1.0 object-keys: 1.1.1 + object.entries@1.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + object.fromentries@2.0.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-object-atoms: 1.1.1 object.groupby@1.0.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 object.values@1.2.1: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -18432,17 +18057,21 @@ snapshots: dependencies: mimic-fn: 4.0.0 - oniguruma-parser@0.12.1: {} + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + oniguruma-parser@0.12.2: {} - oniguruma-to-es@4.3.4: + oniguruma-to-es@4.3.6: dependencies: - oniguruma-parser: 0.12.1 - regex: 6.0.1 + oniguruma-parser: 0.12.2 + regex: 6.1.0 regex-recursion: 6.0.2 open@10.2.0: dependencies: - default-browser: 5.4.0 + default-browser: 5.5.0 define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 wsl-utils: 0.1.0 @@ -18451,7 +18080,7 @@ snapshots: openapi-typescript@7.13.0(typescript@5.9.3): dependencies: - '@redocly/openapi-core': 1.34.6(supports-color@10.2.2) + '@redocly/openapi-core': 1.34.14(supports-color@10.2.2) ansi-colors: 4.1.3 change-case: 5.4.4 parse-json: 8.3.0 @@ -18502,12 +18131,6 @@ snapshots: dependencies: p-limit: 3.1.0 - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 - - p-map@7.0.3: {} - p-queue@6.6.2: dependencies: eventemitter3: 4.0.7 @@ -18527,14 +18150,14 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.0 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 parse-json@8.3.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.0 index-to-position: 1.2.0 type-fest: 4.41.0 @@ -18555,11 +18178,6 @@ snapshots: dependencies: entities: 6.0.1 - parse5@8.0.0: - dependencies: - entities: 6.0.1 - optional: true - parseurl@1.3.3: {} path-browserify@1.0.1: {} @@ -18580,12 +18198,12 @@ snapshots: path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 - minipass: 7.1.2 + minipass: 7.1.3 - path-scurry@2.0.1: + path-scurry@2.0.2: dependencies: - lru-cache: 11.2.5 - minipass: 7.1.2 + lru-cache: 11.3.6 + minipass: 7.1.3 path-to-regexp@6.3.0: {} @@ -18618,7 +18236,7 @@ snapshots: dependencies: pg-int8: 1.0.1 postgres-array: 2.0.0 - postgres-bytea: 1.0.0 + postgres-bytea: 1.0.1 postgres-date: 1.0.7 postgres-interval: 1.2.0 @@ -18640,7 +18258,7 @@ snapshots: picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.2: {} picomatch@4.0.4: {} @@ -18650,25 +18268,25 @@ snapshots: pify@2.3.0: {} - pino-abstract-transport@2.0.0: + pino-abstract-transport@3.0.0: dependencies: split2: 4.2.0 - pino-std-serializers@7.0.0: {} + pino-std-serializers@7.1.0: {} - pino@10.1.0: + pino@10.3.1: dependencies: '@pinojs/redact': 0.4.0 atomic-sleep: 1.0.0 on-exit-leak-free: 2.1.2 - pino-abstract-transport: 2.0.0 - pino-std-serializers: 7.0.0 + pino-abstract-transport: 3.0.0 + pino-std-serializers: 7.1.0 process-warning: 5.0.0 quick-format-unescaped: 4.0.4 real-require: 0.2.0 safe-stable-stringify: 2.5.0 - sonic-boom: 4.2.0 - thread-stream: 3.1.0 + sonic-boom: 4.2.1 + thread-stream: 4.0.0 pkce-challenge@6.0.0: {} @@ -18690,152 +18308,152 @@ snapshots: pngjs@5.0.0: {} - pnpm@10.33.2: {} + pnpm@11.1.2: {} polished@4.3.1: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 possible-typed-array-names@1.1.0: {} - postcss-calc@10.1.1(postcss@8.5.10): + postcss-calc@10.1.1(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - postcss-colormin@7.0.9(postcss@8.5.10): + postcss-colormin@8.0.0(postcss@8.5.14): dependencies: - '@colordx/core': 5.4.2 + '@colordx/core': 5.4.3 browserslist: 4.28.2 caniuse-api: 3.0.0 - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-convert-values@7.0.11(postcss@8.5.10): + postcss-convert-values@8.0.0(postcss@8.5.14): dependencies: browserslist: 4.28.2 - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-discard-comments@7.0.7(postcss@8.5.10): + postcss-discard-comments@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-selector-parser: 7.1.1 - postcss-discard-duplicates@7.0.3(postcss@8.5.10): + postcss-discard-duplicates@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 - postcss-discard-empty@7.0.2(postcss@8.5.10): + postcss-discard-empty@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 - postcss-discard-overridden@7.0.2(postcss@8.5.10): + postcss-discard-overridden@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 - postcss-merge-longhand@7.0.6(postcss@8.5.10): + postcss-merge-longhand@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - stylehacks: 7.0.10(postcss@8.5.10) + stylehacks: 8.0.0(postcss@8.5.14) - postcss-merge-rules@7.0.10(postcss@8.5.10): + postcss-merge-rules@8.0.0(postcss@8.5.14): dependencies: browserslist: 4.28.2 caniuse-api: 3.0.0 - cssnano-utils: 5.0.2(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 6.0.0(postcss@8.5.14) + postcss: 8.5.14 postcss-selector-parser: 7.1.1 - postcss-minify-font-values@7.0.2(postcss@8.5.10): + postcss-minify-font-values@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-minify-gradients@7.0.4(postcss@8.5.10): + postcss-minify-gradients@8.0.0(postcss@8.5.14): dependencies: - '@colordx/core': 5.4.2 - cssnano-utils: 5.0.2(postcss@8.5.10) - postcss: 8.5.10 + '@colordx/core': 5.4.3 + cssnano-utils: 6.0.0(postcss@8.5.14) + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-minify-params@7.0.8(postcss@8.5.10): + postcss-minify-params@8.0.0(postcss@8.5.14): dependencies: browserslist: 4.28.2 - cssnano-utils: 5.0.2(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 6.0.0(postcss@8.5.14) + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-minify-selectors@7.1.0(postcss@8.5.10): + postcss-minify-selectors@8.0.0(postcss@8.5.14): dependencies: browserslist: 4.28.2 caniuse-api: 3.0.0 cssesc: 3.0.0 - postcss: 8.5.10 + postcss: 8.5.14 postcss-selector-parser: 7.1.1 - postcss-normalize-charset@7.0.2(postcss@8.5.10): + postcss-normalize-charset@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 - postcss-normalize-display-values@7.0.2(postcss@8.5.10): + postcss-normalize-display-values@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-normalize-positions@7.0.3(postcss@8.5.10): + postcss-normalize-positions@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-normalize-repeat-style@7.0.3(postcss@8.5.10): + postcss-normalize-repeat-style@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-normalize-string@7.0.2(postcss@8.5.10): + postcss-normalize-string@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-normalize-timing-functions@7.0.2(postcss@8.5.10): + postcss-normalize-timing-functions@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-normalize-unicode@7.0.8(postcss@8.5.10): + postcss-normalize-unicode@8.0.0(postcss@8.5.14): dependencies: browserslist: 4.28.2 - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-normalize-url@7.0.2(postcss@8.5.10): + postcss-normalize-url@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-normalize-whitespace@7.0.2(postcss@8.5.10): + postcss-normalize-whitespace@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-ordered-values@7.0.3(postcss@8.5.10): + postcss-ordered-values@8.0.0(postcss@8.5.14): dependencies: - cssnano-utils: 5.0.2(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 6.0.0(postcss@8.5.14) + postcss: 8.5.14 postcss-value-parser: 4.2.0 - postcss-reduce-initial@7.0.8(postcss@8.5.10): + postcss-reduce-initial@8.0.0(postcss@8.5.14): dependencies: browserslist: 4.28.2 caniuse-api: 3.0.0 - postcss: 8.5.10 + postcss: 8.5.14 - postcss-reduce-transforms@7.0.2(postcss@8.5.10): + postcss-reduce-transforms@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 postcss-selector-parser@7.1.1: @@ -18843,28 +18461,28 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-svgo@7.1.2(postcss@8.5.10): + postcss-svgo@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-value-parser: 4.2.0 svgo: 4.0.1 - postcss-unique-selectors@7.0.6(postcss@8.5.10): + postcss-unique-selectors@8.0.0(postcss@8.5.14): dependencies: - postcss: 8.5.10 + postcss: 8.5.14 postcss-selector-parser: 7.1.1 postcss-value-parser@4.2.0: {} - postcss@8.5.10: + postcss@8.5.14: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 postgres-array@2.0.0: {} - postgres-bytea@1.0.0: {} + postgres-bytea@1.0.1: {} postgres-date@1.0.7: {} @@ -18894,7 +18512,7 @@ snapshots: dependencies: parse-ms: 4.0.0 - probe-image-size@7.2.3: + probe-image-size@7.3.0: dependencies: lodash.merge: 4.6.2 needle: 2.9.1 @@ -18921,11 +18539,6 @@ snapshots: promise-limit@2.7.0: {} - promise-retry@2.0.1: - dependencies: - err-code: 2.0.3 - retry: 0.12.0 - promise@7.3.1: dependencies: asap: 2.0.6 @@ -18955,7 +18568,7 @@ snapshots: js-stringify: 1.0.2 pug-runtime: 3.0.1 - pug-code-gen@3.0.3: + pug-code-gen@3.0.4: dependencies: constantinople: 4.0.1 doctypes: 1.1.0 @@ -18974,7 +18587,7 @@ snapshots: jstransformer: 1.0.0 pug-error: 2.1.0 pug-walk: 2.0.0 - resolve: 1.22.11 + resolve: 1.22.12 pug-lexer@5.0.1: dependencies: @@ -19005,9 +18618,9 @@ snapshots: pug-walk@2.0.0: {} - pug@3.0.3: + pug@3.0.4: dependencies: - pug-code-gen: 3.0.3 + pug-code-gen: 3.0.4 pug-filters: 4.0.0 pug-lexer: 5.0.1 pug-linker: 4.0.0 @@ -19016,7 +18629,7 @@ snapshots: pug-runtime: 3.0.1 pug-strip-comments: 2.0.0 - pump@3.0.3: + pump@3.0.4: dependencies: end-of-stream: 1.4.5 once: 1.4.0 @@ -19047,7 +18660,11 @@ snapshots: pngjs: 5.0.0 yargs: 15.4.1 - qs@6.14.1: + qs@6.14.2: + dependencies: + side-channel: 1.1.0 + + qs@6.15.1: dependencies: side-channel: 1.1.0 @@ -19069,11 +18686,11 @@ snapshots: ratelimiter@3.4.1: {} - raw-body@3.0.1: + raw-body@3.0.2: dependencies: bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.7.0 + http-errors: 2.0.1 + iconv-lite: 0.7.2 unpipe: 1.0.0 rdf-canonize@5.0.0: @@ -19082,41 +18699,39 @@ snapshots: re2@1.24.0: dependencies: - install-artifact-from-github: 1.4.0 + install-artifact-from-github: 1.6.0 nan: 2.26.2 - node-gyp: 12.2.0 - transitivePeerDependencies: - - supports-color + node-gyp: 12.3.0 react-docgen-typescript@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 - react-docgen@8.0.2: + react-docgen@8.0.3: dependencies: - '@babel/core': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 '@types/doctrine': 0.0.9 '@types/resolve': 1.20.6 doctrine: 3.0.0 - resolve: 1.22.11 + resolve: 1.22.12 strip-indent: 4.1.1 transitivePeerDependencies: - supports-color - react-dom@19.2.5(react@19.2.5): + react-dom@19.2.6(react@19.2.6): dependencies: - react: 19.2.5 + react: 19.2.6 scheduler: 0.27.0 react-is@17.0.2: {} react-is@18.3.1: {} - react@19.2.5: {} + react@19.2.6: {} read-pkg-up@7.0.1: dependencies: @@ -19157,7 +18772,7 @@ snapshots: readdir-glob@1.1.3: dependencies: - minimatch: 5.1.6 + minimatch: 5.1.9 readdirp@5.0.0: {} @@ -19188,9 +18803,9 @@ snapshots: reflect.getprototypeof@1.0.10: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 @@ -19205,13 +18820,13 @@ snapshots: regex-utilities@2.3.0: {} - regex@6.0.1: + regex@6.1.0: dependencies: regex-utilities: 2.3.0 regexp.prototype.flags@1.5.4: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-errors: 1.3.0 get-proto: 1.0.1 @@ -19232,7 +18847,7 @@ snapshots: remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 micromark-util-types: 2.0.2 unified: 11.0.5 transitivePeerDependencies: @@ -19273,9 +18888,19 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve@1.22.11: + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.6: dependencies: - is-core-module: 2.16.1 + es-errors: 1.3.0 + is-core-module: 2.16.2 + node-exports-info: 1.6.0 + object-keys: 1.1.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -19283,16 +18908,14 @@ snapshots: dependencies: lowercase-keys: 3.0.0 - restore-cursor@3.1.0: + restore-cursor@5.1.0: dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 + onetime: 7.0.0 + signal-exit: 4.1.0 ret@0.5.0: {} - retry@0.12.0: {} - - rettime@0.11.7: {} + rettime@0.11.11: {} reusify@1.1.0: {} @@ -19308,77 +18931,77 @@ snapshots: glob: 7.2.3 optional: true - rolldown@1.0.0-rc.15: + rolldown@1.0.0: dependencies: - '@oxc-project/types': 0.124.0 - '@rolldown/pluginutils': 1.0.0-rc.15 + '@oxc-project/types': 0.129.0 + '@rolldown/pluginutils': 1.0.0 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-x64': 1.0.0-rc.15 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.15 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 - - rolldown@1.0.0-rc.17: - dependencies: - '@oxc-project/types': 0.127.0 - '@rolldown/pluginutils': 1.0.0-rc.17 + '@rolldown/binding-android-arm64': 1.0.0 + '@rolldown/binding-darwin-arm64': 1.0.0 + '@rolldown/binding-darwin-x64': 1.0.0 + '@rolldown/binding-freebsd-x64': 1.0.0 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0 + '@rolldown/binding-linux-arm64-gnu': 1.0.0 + '@rolldown/binding-linux-arm64-musl': 1.0.0 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0 + '@rolldown/binding-linux-s390x-gnu': 1.0.0 + '@rolldown/binding-linux-x64-gnu': 1.0.0 + '@rolldown/binding-linux-x64-musl': 1.0.0 + '@rolldown/binding-openharmony-arm64': 1.0.0 + '@rolldown/binding-wasm32-wasi': 1.0.0 + '@rolldown/binding-win32-arm64-msvc': 1.0.0 + '@rolldown/binding-win32-x64-msvc': 1.0.0 + + rolldown@1.0.0-rc.18: + dependencies: + '@oxc-project/types': 0.128.0 + '@rolldown/pluginutils': 1.0.0-rc.18 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.17 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.17 - '@rolldown/binding-darwin-x64': 1.0.0-rc.17 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.17 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 - - rollup@4.60.2: + '@rolldown/binding-android-arm64': 1.0.0-rc.18 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.18 + '@rolldown/binding-darwin-x64': 1.0.0-rc.18 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.18 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.18 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.18 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.18 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.18 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.18 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.18 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.18 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.18 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.18 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.18 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.18 + + rollup@4.60.3: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.2 - '@rollup/rollup-android-arm64': 4.60.2 - '@rollup/rollup-darwin-arm64': 4.60.2 - '@rollup/rollup-darwin-x64': 4.60.2 - '@rollup/rollup-freebsd-arm64': 4.60.2 - '@rollup/rollup-freebsd-x64': 4.60.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.2 - '@rollup/rollup-linux-arm-musleabihf': 4.60.2 - '@rollup/rollup-linux-arm64-gnu': 4.60.2 - '@rollup/rollup-linux-arm64-musl': 4.60.2 - '@rollup/rollup-linux-loong64-gnu': 4.60.2 - '@rollup/rollup-linux-loong64-musl': 4.60.2 - '@rollup/rollup-linux-ppc64-gnu': 4.60.2 - '@rollup/rollup-linux-ppc64-musl': 4.60.2 - '@rollup/rollup-linux-riscv64-gnu': 4.60.2 - '@rollup/rollup-linux-riscv64-musl': 4.60.2 - '@rollup/rollup-linux-s390x-gnu': 4.60.2 - '@rollup/rollup-linux-x64-gnu': 4.60.2 - '@rollup/rollup-linux-x64-musl': 4.60.2 - '@rollup/rollup-openbsd-x64': 4.60.2 - '@rollup/rollup-openharmony-arm64': 4.60.2 - '@rollup/rollup-win32-arm64-msvc': 4.60.2 - '@rollup/rollup-win32-ia32-msvc': 4.60.2 - '@rollup/rollup-win32-x64-gnu': 4.60.2 - '@rollup/rollup-win32-x64-msvc': 4.60.2 + '@rollup/rollup-android-arm-eabi': 4.60.3 + '@rollup/rollup-android-arm64': 4.60.3 + '@rollup/rollup-darwin-arm64': 4.60.3 + '@rollup/rollup-darwin-x64': 4.60.3 + '@rollup/rollup-freebsd-arm64': 4.60.3 + '@rollup/rollup-freebsd-x64': 4.60.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.3 + '@rollup/rollup-linux-arm-musleabihf': 4.60.3 + '@rollup/rollup-linux-arm64-gnu': 4.60.3 + '@rollup/rollup-linux-arm64-musl': 4.60.3 + '@rollup/rollup-linux-loong64-gnu': 4.60.3 + '@rollup/rollup-linux-loong64-musl': 4.60.3 + '@rollup/rollup-linux-ppc64-gnu': 4.60.3 + '@rollup/rollup-linux-ppc64-musl': 4.60.3 + '@rollup/rollup-linux-riscv64-gnu': 4.60.3 + '@rollup/rollup-linux-riscv64-musl': 4.60.3 + '@rollup/rollup-linux-s390x-gnu': 4.60.3 + '@rollup/rollup-linux-x64-gnu': 4.60.3 + '@rollup/rollup-linux-x64-musl': 4.60.3 + '@rollup/rollup-openbsd-x64': 4.60.3 + '@rollup/rollup-openharmony-arm64': 4.60.3 + '@rollup/rollup-win32-arm64-msvc': 4.60.3 + '@rollup/rollup-win32-ia32-msvc': 4.60.3 + '@rollup/rollup-win32-x64-gnu': 4.60.3 + '@rollup/rollup-win32-x64-msvc': 4.60.3 fsevents: 2.3.3 router@2.2.0: @@ -19406,9 +19029,9 @@ snapshots: dependencies: tslib: 2.8.1 - safe-array-concat@1.1.3: + safe-array-concat@1.1.4: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 has-symbols: 1.1.0 @@ -19429,7 +19052,7 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 - safe-regex2@5.0.0: + safe-regex2@5.1.1: dependencies: ret: 0.5.0 @@ -19444,7 +19067,7 @@ snapshots: htmlparser2: 10.1.0 is-plain-object: 5.0.0 parse-srcset: 1.0.2 - postcss: 8.5.10 + postcss: 8.5.14 sass-embedded-all-unknown@1.99.0: dependencies: @@ -19506,7 +19129,7 @@ snapshots: sass-embedded@1.99.0: dependencies: - '@bufbuild/protobuf': 2.11.0 + '@bufbuild/protobuf': 2.12.0 colorjs.io: 0.5.2 immutable: 5.1.5 rxjs: 7.8.2 @@ -19539,15 +19162,10 @@ snapshots: immutable: 5.1.5 source-map-js: 1.2.1 optionalDependencies: - '@parcel/watcher': 2.5.1 + '@parcel/watcher': 2.5.6 optional: true - sax@1.5.0: {} - - saxes@6.0.0: - dependencies: - xmlchars: 2.2.0 - optional: true + sax@1.6.0: {} scheduler@0.27.0: {} @@ -19563,7 +19181,7 @@ snapshots: semver@7.7.4: {} - send@1.2.0: + send@1.2.1: dependencies: debug: 4.4.3(supports-color@10.2.2) encodeurl: 2.0.0 @@ -19579,18 +19197,18 @@ snapshots: transitivePeerDependencies: - supports-color - serve-static@2.2.0: + serve-static@2.2.1: dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 1.2.0 + send: 1.2.1 transitivePeerDependencies: - supports-color set-blocking@2.0.0: {} - set-cookie-parser@2.7.1: {} + set-cookie-parser@2.7.2: {} set-cookie-parser@3.1.0: {} @@ -19669,7 +19287,7 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 - side-channel-list@1.0.0: + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -19693,7 +19311,7 @@ snapshots: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 - side-channel-list: 1.0.0 + side-channel-list: 1.0.1 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 @@ -19706,7 +19324,7 @@ snapshots: simple-oauth2@5.1.0: dependencies: '@hapi/hoek': 11.0.7 - '@hapi/wreck': 18.1.0 + '@hapi/wreck': 18.1.1 debug: 4.4.3(supports-color@10.2.2) joi: 17.13.3 transitivePeerDependencies: @@ -19725,8 +19343,8 @@ snapshots: '@sinonjs/commons': 3.0.1 '@sinonjs/fake-timers': 11.2.2 '@sinonjs/samsam': 8.0.3 - diff: 5.2.0 - nise: 6.1.1 + diff: 5.2.2 + nise: 6.1.5 supports-color: 7.2.0 slacc-android-arm-eabi@0.1.5: @@ -19786,36 +19404,19 @@ snapshots: slash@3.0.0: {} - slice-ansi@3.0.0: + slice-ansi@7.1.2: dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 - slice-ansi@4.0.0: + slice-ansi@8.0.0: dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 slick@1.12.2: {} - smart-buffer@4.2.0: {} - - socks-proxy-agent@8.0.5: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3(supports-color@10.2.2) - socks: 2.8.7 - transitivePeerDependencies: - - supports-color - - socks@2.8.7: - dependencies: - ip-address: 10.0.1 - smart-buffer: 4.2.0 - - sonic-boom@4.2.0: + sonic-boom@4.2.1: dependencies: atomic-sleep: 1.0.0 @@ -19833,16 +19434,16 @@ snapshots: spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.22 + spdx-license-ids: 3.0.23 spdx-exceptions@2.5.0: {} spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.22 + spdx-license-ids: 3.0.23 - spdx-license-ids@3.0.22: {} + spdx-license-ids@3.0.23: {} split2@4.2.0: {} @@ -19864,10 +19465,6 @@ snapshots: safer-buffer: 2.1.2 tweetnacl: 0.14.5 - ssri@13.0.0: - dependencies: - minipass: 7.1.2 - stackback@0.0.2: {} standard-as-callback@2.1.0: {} @@ -19885,44 +19482,42 @@ snapshots: transitivePeerDependencies: - supports-color - statuses@2.0.1: {} - statuses@2.0.2: {} - std-env@4.0.0: {} + std-env@4.1.0: {} stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 internal-slot: 1.1.0 - storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(97c00992be6c92d700516236c15b3de8): + storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(267bf2f6efbfa841ce5c842b3f261858): dependencies: - '@storybook/blocks': 8.6.18(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/components': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/core-events': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/manager-api': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/preview-api': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/theming': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) - '@storybook/types': 8.6.18(storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6)) + '@storybook/blocks': 8.6.18(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/components': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/core-events': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/manager-api': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/preview-api': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/theming': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) + '@storybook/types': 8.6.18(storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6)) optionalDependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - storybook@10.3.5(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(utf-8-validate@6.0.6): + storybook@10.3.6(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(utf-8-validate@6.0.6): dependencies: '@storybook/global': 5.0.0 - '@storybook/icons': 2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@storybook/icons': 2.0.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@testing-library/jest-dom': 6.9.1 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) '@vitest/expect': 3.2.4 '@vitest/spy': 3.2.4 '@webcontainer/env': 1.1.1 - esbuild: 0.27.4 + esbuild: 0.27.7 open: 10.2.0 recast: 0.23.11 semver: 7.7.4 - use-sync-external-store: 1.6.0(react@19.2.5) + use-sync-external-store: 1.6.0(react@19.2.6) ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) optionalDependencies: prettier: 3.8.3 @@ -19946,11 +19541,11 @@ snapshots: streamsearch@1.1.0: {} - streamx@2.23.0: + streamx@2.25.0: dependencies: events-universal: 1.0.1 fast-fifo: 1.3.2 - text-decoder: 1.2.3 + text-decoder: 1.2.7 transitivePeerDependencies: - bare-abort-controller - react-native-b4a @@ -19971,34 +19566,39 @@ snapshots: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 string-width@7.2.0: dependencies: emoji-regex: 10.6.0 - get-east-asian-width: 1.4.0 - strip-ansi: 7.1.2 + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 + + string-width@8.2.1: + dependencies: + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 string.prototype.trim@1.2.10: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 string.prototype.trimend@1.0.9: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -20023,7 +19623,7 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.2: + strip-ansi@7.2.0: dependencies: ansi-regex: 6.2.2 @@ -20049,10 +19649,10 @@ snapshots: dependencies: '@tokenizer/token': 0.3.0 - stylehacks@7.0.10(postcss@8.5.10): + stylehacks@8.0.0(postcss@8.5.14): dependencies: browserslist: 4.28.2 - postcss: 8.5.10 + postcss: 8.5.14 postcss-selector-parser: 7.1.1 superagent@10.3.0: @@ -20065,7 +19665,7 @@ snapshots: formidable: 3.5.4 methods: 1.1.2 mime: 2.6.0 - qs: 6.14.1 + qs: 6.15.1 transitivePeerDependencies: - supports-color @@ -20102,14 +19702,11 @@ snapshots: dependencies: commander: 11.1.0 css-select: 5.2.2 - css-tree: 3.1.0 + css-tree: 3.2.1 css-what: 6.2.2 csso: 5.0.5 picocolors: 1.1.1 - sax: 1.5.0 - - symbol-tree@3.2.4: - optional: true + sax: 1.6.0 sync-child-process@1.0.2: dependencies: @@ -20117,17 +19714,19 @@ snapshots: sync-message-port@1.2.0: {} - systeminformation@5.31.5: {} + systeminformation@5.31.6: {} tagged-tag@1.0.0: {} - tar-stream@3.1.7: + tar-stream@3.2.0: dependencies: - b4a: 1.7.3 + b4a: 1.8.1 + bare-fs: 4.7.1 fast-fifo: 1.3.2 - streamx: 2.23.0 + streamx: 2.25.0 transitivePeerDependencies: - bare-abort-controller + - bare-buffer - react-native-b4a tar@6.2.1: @@ -20140,11 +19739,11 @@ snapshots: yallist: 4.0.0 optional: true - tar@7.5.13: + tar@7.5.14: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 - minipass: 7.1.2 + minipass: 7.1.3 minizlib: 3.1.0 yallist: 5.0.0 @@ -20152,22 +19751,29 @@ snapshots: dependencies: execa: 6.1.0 - terser@5.46.2: + teex@1.0.1: + dependencies: + streamx: 2.25.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + terser@5.47.1: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 - text-decoder@1.2.3: + text-decoder@1.2.7: dependencies: - b4a: 1.7.3 + b4a: 1.8.1 transitivePeerDependencies: - react-native-b4a textarea-caret@3.1.0: {} - thread-stream@3.1.0: + thread-stream@4.0.0: dependencies: real-require: 0.2.0 @@ -20177,15 +19783,13 @@ snapshots: throttleit@1.0.1: {} - through@2.3.8: {} - tiny-invariant@1.3.3: {} tinybench@2.9.0: {} tinycolor2@1.6.0: {} - tinyexec@1.0.2: {} + tinyexec@1.1.2: {} tinyglobby@0.2.16: dependencies: @@ -20204,15 +19808,15 @@ snapshots: tldts-core@6.1.86: {} - tldts-core@7.0.18: {} + tldts-core@7.0.30: {} tldts@6.1.86: dependencies: tldts-core: 6.1.86 - tldts@7.0.18: + tldts@7.0.30: dependencies: - tldts-core: 7.0.18 + tldts-core: 7.0.30 tmp@0.2.5: {} @@ -20248,15 +19852,10 @@ snapshots: tough-cookie@6.0.1: dependencies: - tldts: 7.0.18 + tldts: 7.0.30 tr46@0.0.3: {} - tr46@6.0.0: - dependencies: - punycode: 2.3.1 - optional: true - tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -20273,17 +19872,17 @@ snapshots: ts-dedent@2.2.0: {} - ts-essentials@10.1.1(typescript@5.9.3): + ts-essentials@10.2.0(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 ts-map@1.0.3: {} - tsc-alias@1.8.16: + tsc-alias@1.8.17: dependencies: chokidar: 5.0.0 commander: 9.5.0 - get-tsconfig: 4.13.0 + get-tsconfig: 4.14.0 globby: 11.1.0 mylas: 2.1.14 normalize-path: 3.0.0 @@ -20318,8 +19917,8 @@ snapshots: tsx@4.21.0: dependencies: - esbuild: 0.27.4 - get-tsconfig: 4.13.0 + esbuild: 0.27.7 + get-tsconfig: 4.14.0 optionalDependencies: fsevents: 2.3.3 @@ -20376,7 +19975,7 @@ snapshots: typed-array-byte-length@1.0.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 @@ -20385,7 +19984,7 @@ snapshots: typed-array-byte-offset@1.0.4: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 @@ -20394,7 +19993,7 @@ snapshots: typed-array-length@1.0.7: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 is-typed-array: 1.1.15 @@ -20409,16 +20008,16 @@ snapshots: ansis: 4.2.0 app-root-path: 3.1.0 buffer: 6.0.3 - dayjs: 1.11.19 + dayjs: 1.11.20 debug: 4.4.3(supports-color@10.2.2) - dedent: 1.7.0 + dedent: 1.7.2 dotenv: 16.6.1 glob: 10.5.0 reflect-metadata: 0.2.2 sha.js: 2.4.12 sql-highlight: 6.1.0 tslib: 2.8.1 - uuid: 11.1.0 + uuid: 11.1.1 yargs: 17.7.2 optionalDependencies: ioredis: 5.10.1 @@ -20429,7 +20028,7 @@ snapshots: typescript@5.9.3: {} - ufo@1.6.3: {} + ufo@1.6.4: {} uid2@0.0.4: {} @@ -20452,7 +20051,7 @@ snapshots: undici-types@7.16.0: {} - undici@6.22.0: {} + undici@6.25.0: {} undici@7.25.0: {} @@ -20468,14 +20067,6 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 - unique-filename@5.0.0: - dependencies: - unique-slug: 6.0.0 - - unique-slug@6.0.0: - dependencies: - imurmurhash: 0.1.4 - unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -20493,7 +20084,7 @@ snapshots: '@types/unist': 3.0.3 unist-util-is: 6.0.1 - unist-util-visit@5.0.0: + unist-util-visit@5.1.0: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 @@ -20527,13 +20118,15 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + uri-js-replace@1.0.1: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 - use-sync-external-store@1.6.0(react@19.2.5): + use-sync-external-store@1.6.0(react@19.2.6): dependencies: - react: 19.2.5 + react: 19.2.6 utf-8-validate@6.0.6: dependencies: @@ -20546,19 +20139,21 @@ snapshots: uuid@11.1.0: {} + uuid@11.1.1: {} + uuid@14.0.0: {} uuid@8.3.2: {} uuid@9.0.1: {} - v-code-diff@1.13.1(vue@3.5.33(typescript@5.9.3)): + v-code-diff@1.13.1(vue@3.5.34(typescript@5.9.3)): dependencies: - diff: 5.2.0 + diff: 5.2.2 diff-match-patch: 1.0.5 highlight.js: 11.11.1 - vue: 3.5.33(typescript@5.9.3) - vue-demi: 0.14.10(vue@3.5.33(typescript@5.9.3)) + vue: 3.5.34(typescript@5.9.3) + vue-demi: 0.14.10(vue@3.5.34(typescript@5.9.3)) valid-data-url@3.0.1: {} @@ -20587,21 +20182,21 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-plugin-glsl@1.6.0(@rollup/pluginutils@5.3.0(rollup@4.60.2))(esbuild@0.28.0)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)): + vite-plugin-glsl@1.6.0(@rollup/pluginutils@5.3.0(rollup@4.60.3))(esbuild@0.28.0)(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)): dependencies: - vite: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) optionalDependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.60.2) + '@rollup/pluginutils': 5.3.0(rollup@4.60.3) esbuild: 0.28.0 vite-plugin-turbosnap@1.0.3: {} - vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0): + vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.10 - rolldown: 1.0.0-rc.17 + postcss: 8.5.14 + rolldown: 1.0.0-rc.18 tinyglobby: 0.2.16 optionalDependencies: '@types/node': 24.12.2 @@ -20609,53 +20204,52 @@ snapshots: fsevents: 2.3.3 sass: 1.99.0 sass-embedded: 1.99.0 - terser: 5.46.2 + terser: 5.47.1 tsx: 4.21.0 vitest-fetch-mock@0.4.5(vitest@4.1.5): dependencies: - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) vitest-mock-extended@4.0.0(typescript@5.9.3)(vitest@4.1.5): dependencies: - ts-essentials: 10.1.1(typescript@5.9.3) + ts-essentials: 10.2.0(typescript@5.9.3) typescript: 5.9.3 - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) vitest-websocket-mock@0.5.0(vitest@4.1.5): dependencies: '@vitest/utils': 3.2.4 mock-socket: 9.3.1 - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) - vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)): + vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)): dependencies: '@vitest/expect': 4.1.5 - '@vitest/mocker': 4.1.5(msw@2.13.6(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)) + '@vitest/mocker': 4.1.5(msw@2.14.3(@types/node@24.12.2)(typescript@5.9.3))(vite@8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0)) '@vitest/pretty-format': 4.1.5 '@vitest/runner': 4.1.5 '@vitest/snapshot': 4.1.5 '@vitest/spy': 4.1.5 '@vitest/utils': 4.1.5 - es-module-lexer: 2.0.0 + es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.4 - std-env: 4.0.0 + std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.0.2 + tinyexec: 1.1.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.11(@types/node@24.12.2)(esbuild@0.28.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.47.1)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 24.12.2 '@vitest/coverage-v8': 4.1.5(vitest@4.1.5) happy-dom: 20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) - jsdom: 27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - msw @@ -20665,7 +20259,7 @@ snapshots: vscode-languageclient@9.0.1: dependencies: - minimatch: 5.1.6 + minimatch: 5.1.9 semver: 7.7.4 vscode-languageserver-protocol: 3.17.5 @@ -20689,69 +20283,64 @@ snapshots: vue-component-type-helpers@2.2.12: {} - vue-component-type-helpers@3.2.7: {} + vue-component-type-helpers@3.2.8: {} - vue-demi@0.14.10(vue@3.5.33(typescript@5.9.3)): + vue-demi@0.14.10(vue@3.5.34(typescript@5.9.3)): dependencies: - vue: 3.5.33(typescript@5.9.3) + vue: 3.5.34(typescript@5.9.3) - vue-docgen-api@4.79.2(vue@3.5.33(typescript@5.9.3)): + vue-docgen-api@4.79.2(vue@3.5.34(typescript@5.9.3)): dependencies: - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 - '@vue/compiler-dom': 3.5.33 - '@vue/compiler-sfc': 3.5.33 + '@vue/compiler-dom': 3.5.34 + '@vue/compiler-sfc': 3.5.34 ast-types: 0.16.1 esm-resolve: 1.0.11 hash-sum: 2.0.0 lru-cache: 8.0.5 - pug: 3.0.3 + pug: 3.0.4 recast: 0.23.11 ts-map: 1.0.3 - vue: 3.5.33(typescript@5.9.3) - vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.5.33(typescript@5.9.3)) + vue: 3.5.34(typescript@5.9.3) + vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.5.34(typescript@5.9.3)) vue-eslint-parser@10.4.0(eslint@9.39.4): dependencies: debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.4 - eslint-scope: 8.4.0 + eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 - espree: 10.4.0 - esquery: 1.6.0 + espree: 11.2.0 + esquery: 1.7.0 semver: 7.7.4 transitivePeerDependencies: - supports-color - vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.5.33(typescript@5.9.3)): + vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.5.34(typescript@5.9.3)): dependencies: - vue: 3.5.33(typescript@5.9.3) + vue: 3.5.34(typescript@5.9.3) - vue-tsc@3.2.7(typescript@5.9.3): + vue-tsc@3.2.8(typescript@5.9.3): dependencies: '@volar/typescript': 2.4.28 - '@vue/language-core': 3.2.7 + '@vue/language-core': 3.2.8 typescript: 5.9.3 - vue@3.5.33(typescript@5.9.3): + vue@3.5.34(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.33 - '@vue/compiler-sfc': 3.5.33 - '@vue/runtime-dom': 3.5.33 - '@vue/server-renderer': 3.5.33(vue@3.5.33(typescript@5.9.3)) - '@vue/shared': 3.5.33 + '@vue/compiler-dom': 3.5.34 + '@vue/compiler-sfc': 3.5.34 + '@vue/runtime-dom': 3.5.34 + '@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@5.9.3)) + '@vue/shared': 3.5.34 optionalDependencies: typescript: 5.9.3 - w3c-xmlserializer@5.0.0: - dependencies: - xml-name-validator: 5.0.0 - optional: true - wait-on@9.0.5(debug@4.4.3): dependencies: - axios: 1.15.0(debug@4.4.3) - joi: 18.1.2 + axios: 1.16.0(debug@4.4.3) + joi: 18.2.1 lodash: 4.18.1 minimist: 1.2.8 rxjs: 7.8.2 @@ -20769,7 +20358,7 @@ snapshots: asn1.js: 5.4.1 http_ece: 1.2.0 https-proxy-agent: 7.0.6(supports-color@10.2.2) - jws: 4.0.0 + jws: 4.0.1 minimist: 1.2.8 transitivePeerDependencies: - supports-color @@ -20786,9 +20375,6 @@ snapshots: webidl-conversions@3.0.1: {} - webidl-conversions@8.0.1: - optional: true - webpack-virtual-modules@0.6.2: {} whatwg-encoding@3.1.1: @@ -20799,15 +20385,6 @@ snapshots: whatwg-mimetype@4.0.0: {} - whatwg-mimetype@5.0.0: - optional: true - - whatwg-url@15.1.0: - dependencies: - tr46: 6.0.0 - webidl-conversions: 8.0.1 - optional: true - whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -20835,7 +20412,7 @@ snapshots: isarray: 2.0.5 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.19 + which-typed-array: 1.1.20 which-collection@1.0.2: dependencies: @@ -20846,10 +20423,10 @@ snapshots: which-module@2.0.1: {} - which-typed-array@1.1.19: + which-typed-array@1.1.20: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 for-each: 0.3.5 get-proto: 1.0.1 @@ -20864,9 +20441,9 @@ snapshots: dependencies: isexe: 2.0.0 - which@6.0.0: + which@6.0.1: dependencies: - isexe: 3.1.1 + isexe: 4.0.0 why-is-node-running@2.3.0: dependencies: @@ -20880,7 +20457,7 @@ snapshots: with@7.0.2: dependencies: - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 assert-never: 1.4.0 babel-walk: 3.0.0-canary-5 @@ -20903,13 +20480,13 @@ snapshots: dependencies: ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 string-width: 7.2.0 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrappy@1.0.2: {} @@ -20920,29 +20497,23 @@ snapshots: wsl-utils@0.1.0: dependencies: - is-wsl: 3.1.0 + is-wsl: 3.1.1 xev@3.0.2: {} xml-js@1.6.11: dependencies: - sax: 1.5.0 + sax: 1.6.0 xml-name-validator@4.0.0: {} - xml-name-validator@5.0.0: - optional: true - xml2js@0.5.0: dependencies: - sax: 1.5.0 + sax: 1.6.0 xmlbuilder: 11.0.1 xmlbuilder@11.0.1: {} - xmlchars@2.2.0: - optional: true - xtend@4.0.2: {} y18n@4.0.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8d1fcbb5080..4d9043f720f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,26 +11,26 @@ packages: - packages/misskey-js/generator - packages/misskey-reversi - packages/misskey-bubble-game -onlyBuiltDependencies: - - '@nestjs/core' - - '@parcel/watcher' - - '@sentry/profiling-node' - - '@sentry-internal/node-cpu-profiler' - - '@tensorflow/tfjs-node' - - bufferutil - - canvas - - core-js - - cypress - - esbuild - - msgpackr-extract - - msw - - nice-napi - - re2 - - sharp - - utf-8-validate - - v-code-diff - - vue-demi -ignorePatchFailures: false +allowBuilds: + '@nestjs/core': true + '@parcel/watcher': true + '@sentry/profiling-node': true + '@sentry-internal/node-cpu-profiler': true + '@tensorflow/tfjs-node': true + bufferutil: true + canvas: true + core-js: true + cypress: true + esbuild: true + msgpackr-extract: true + msw: true + nice-napi: true + re2: true + sharp: true + utf-8-validate: true + v-code-diff: true + vue-demi: true + exifreader: false minimumReleaseAge: 10080 # delay 7days to mitigate supply-chain attack minimumReleaseAgeExclude: - '@misskey-dev/*' @@ -52,3 +52,12 @@ minimumReleaseAgeExclude: - slacc-win32-arm64-msvc - slacc-win32-x64-msvc - '@typescript/native-preview*' + - pnpm + - systeminformation # 脆弱性対応。����消� +overrides: + '@aiscript-dev/aiscript-languageserver': '-' + chokidar: 5.0.0 + lodash: 4.18.1 +engineStrict: true +saveExact: true +shellEmulator: true diff --git a/scripts/changelog-checker/package-lock.json b/scripts/changelog-checker/package-lock.json index c5ed48cba43..7b333237b21 100644 --- a/scripts/changelog-checker/package-lock.json +++ b/scripts/changelog-checker/package-lock.json @@ -16,7 +16,7 @@ "remark-parse": "11.0.0", "typescript": "5.9.3", "unified": "11.0.5", - "vite": "8.0.10", + "vite": "8.0.11", "vite-node": "6.0.0", "vitest": "4.1.5" } @@ -163,9 +163,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.127.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", - "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "version": "0.128.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.128.0.tgz", + "integrity": "sha512-huv1Y/LzBJkBVHt3OlC7u0zHBW9qXf1FdD7sGmc1rXc2P1mTwHssYv7jyGx5KAACSCH+9B3Bhn6Z9luHRvf7pQ==", "dev": true, "license": "MIT", "funding": { @@ -173,9 +173,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.18.tgz", + "integrity": "sha512-lIDyUAfD7U3+BWKzdxMbJcsYHuqXqmGz40aeRqvuAm3y5TkJSYTBW2RDrn65DJFPQqVjUAUqq5uz8urzQ8aBdQ==", "cpu": [ "arm64" ], @@ -190,9 +190,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.18.tgz", + "integrity": "sha512-apJq2ktnGp27nSInMR5Vcj8kY6xJzDAvfdIFlpDcAK/w4cDO58qVoi1YQsES/SKiFNge/6e4CUzgjfHduYqWpQ==", "cpu": [ "arm64" ], @@ -207,9 +207,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.18.tgz", + "integrity": "sha512-5Ofot8xbs+pxRHJqm9/9N/4sTQOvdrwEsmPE9pdLEEoAbdZtG6F2LMDfO1sp6ZAtXJuJV/21ew2srq3W8NXB5g==", "cpu": [ "x64" ], @@ -224,9 +224,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.18.tgz", + "integrity": "sha512-7h8eeOTT1eyqJyx64BFCnWZpNm486hGWt2sqeLLgDxA0xI1oGZ9H7gK1S85uNGmBhkdPwa/6reTxfFFKvIsebw==", "cpu": [ "x64" ], @@ -241,9 +241,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", - "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.18.tgz", + "integrity": "sha512-eRcm/HVt9U/JFu5RKAEKwGQYtDCKWLiaH6wOnsSEp6NMBb/3Os8LgHZlNyzMpFVNmiiMFlfb2zEnebfzJrHFmg==", "cpu": [ "arm" ], @@ -258,9 +258,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-SOrT/cT4ukTmgnrEz/Hg3m7LBnuCLW9psDeMKrimRWY4I8DmnO7Lco8W2vtqPmMkbVu8iJ+g4GFLVLLOVjJ9DQ==", "cpu": [ "arm64" ], @@ -278,9 +278,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.18.tgz", + "integrity": "sha512-QWjdxN1HJCpBTAcZ5N5F7wju3gVPzRzSpmGzx7na0c/1qpN9CFil+xt+l9lV/1M6/gqHSNXCiqPfwhVJPeLnug==", "cpu": [ "arm64" ], @@ -298,9 +298,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-ugCOyj7a4d9h3q9B+wXmf6g3a68UsjGh6dob5DHevHGMwDUbhsYNbSPxJsENcIttJZ9jv7qGM2UesLw5jqIhdg==", "cpu": [ "ppc64" ], @@ -318,9 +318,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-kKWRhbsotpXkGbcd5dllUWg5gEXcDAa8u5YnP9AV5DYNbvJHGzzuwv7dpmhc8NqKMJldl0a+x76IHbspEpEmdA==", "cpu": [ "s390x" ], @@ -338,9 +338,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-uCo8ElcCIAMyYAZyuIZ81oFkhTSIllNvUCHCAlbhlN4ji3uC28h7IIdlXyIvGO7HsuqnV9p3rD/bpH7XhIyhRw==", "cpu": [ "x64" ], @@ -358,9 +358,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.18.tgz", + "integrity": "sha512-XNOQZtuE6yUIvx4rwGemwh8kpL1xvU41FXy/s9K7T/3JVcqGzo3NfKM2HrbrGgfPYGFW42f07Wk++aOC6B9NWA==", "cpu": [ "x64" ], @@ -378,9 +378,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.18.tgz", + "integrity": "sha512-tSn/kzrfa7tNOXr7sEacDBN4YsIqTyLqh45IO0nHDwtpKIDNDJr+VFojt+4klSpChxB29JLyduSsE0MKEwa65A==", "cpu": [ "arm64" ], @@ -395,9 +395,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", - "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.18.tgz", + "integrity": "sha512-+J9YGmc+czgqlhYmwun3S3O0FIZhsH8ep2456xwjAdIOmuJxM7xz4P4PtrxU+Bz17a/5bqPA8o3HAAoX0teUdg==", "cpu": [ "wasm32" ], @@ -414,9 +414,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.18.tgz", + "integrity": "sha512-zsu47DgU0FQzSwi6sU9dZoEdUv7pc1AptSEz/Z8HBg54sV0Pbs3N0+CrIbTsgiu6EyoaNN9CHboqbLaz9lhOyQ==", "cpu": [ "arm64" ], @@ -431,9 +431,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.18.tgz", + "integrity": "sha512-7H+3yqGgmnlDTRRhw/xpYY9J1kf4GC681nVc4GqKhExZTDrVVrV2tsOR9kso0fvgBdcTCcQShx4SLLoHgaLwhg==", "cpu": [ "x64" ], @@ -448,9 +448,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", - "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.18.tgz", + "integrity": "sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==", "dev": true, "license": "MIT" }, @@ -462,9 +462,9 @@ "license": "MIT" }, "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, "license": "MIT", "optional": true, @@ -1861,9 +1861,9 @@ } }, "node_modules/postcss": { - "version": "8.5.13", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.13.tgz", - "integrity": "sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "dev": true, "funding": [ { @@ -1937,14 +1937,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", - "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.18.tgz", + "integrity": "sha512-phmyKBpuBdRYDf4hgyynGAYn/rDDe+iZXKVJ7WX5b1zQzpLkP5oJRPGsfJuHdzPMlyyEO/4sPW6yfSx2gf7lVg==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.127.0", - "@rolldown/pluginutils": "1.0.0-rc.17" + "@oxc-project/types": "=0.128.0", + "@rolldown/pluginutils": "1.0.0-rc.18" }, "bin": { "rolldown": "bin/cli.mjs" @@ -1953,21 +1953,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-x64": "1.0.0-rc.17", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" + "@rolldown/binding-android-arm64": "1.0.0-rc.18", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.18", + "@rolldown/binding-darwin-x64": "1.0.0-rc.18", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.18", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.18", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.18", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.18", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.18", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.18", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.18", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.18" } }, "node_modules/semver": { @@ -2215,16 +2215,16 @@ } }, "node_modules/vite": { - "version": "8.0.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", - "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.11.tgz", + "integrity": "sha512-Jz1mxtUBR5xTT65VOdJZUUeoyLtqljmFkiUXhPTLZka3RDc9vpi/xXkyrnsdRcm2lIi3l3GPMnAidTsEGIj3Ow==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.10", - "rolldown": "1.0.0-rc.17", + "postcss": "^8.5.14", + "rolldown": "1.0.0-rc.18", "tinyglobby": "^0.2.16" }, "bin": { @@ -2241,7 +2241,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.0", + "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", diff --git a/scripts/changelog-checker/package.json b/scripts/changelog-checker/package.json index 3c45f5d42bc..f3a81cf4084 100644 --- a/scripts/changelog-checker/package.json +++ b/scripts/changelog-checker/package.json @@ -17,7 +17,7 @@ "remark-parse": "11.0.0", "typescript": "5.9.3", "unified": "11.0.5", - "vite": "8.0.10", + "vite": "8.0.11", "vite-node": "6.0.0", "vitest": "4.1.5" } From 62b323b58bffe920ae31c590b0698a5f04764bfe Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 15 May 2026 09:39:57 +0900 Subject: [PATCH 105/578] update re2 --- packages/backend/package.json | 2 +- pnpm-workspace.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 3a03407bfb7..625349ad340 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -133,7 +133,7 @@ "qrcode": "1.5.4", "random-seed": "0.3.0", "ratelimiter": "3.4.1", - "re2": "1.24.0", + "re2": "1.24.1", "reflect-metadata": "0.2.2", "rename": "1.0.4", "rss-parser": "3.13.0", diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4d9043f720f..88f9b251b59 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -53,6 +53,8 @@ minimumReleaseAgeExclude: - slacc-win32-x64-msvc - '@typescript/native-preview*' - pnpm + - re2 # ����消� + - nan # ����消� - systeminformation # 脆弱性対応。����消� overrides: '@aiscript-dev/aiscript-languageserver': '-' From 08c6efb04449bcc68be142e09724b2eecfae50ab Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 09:44:57 +0900 Subject: [PATCH 106/578] fix(deps): update dependency sanitize-html to v2.17.4 [security] [ci skip] (#17402) * fix(deps): update dependency sanitize-html to v2.17.4 [security] * fix minimumReleaseAgeExclude --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> --- packages/backend/package.json | 2 +- packages/frontend/package.json | 2 +- pnpm-lock.yaml | 22 +++++++++++++++------- pnpm-workspace.yaml | 2 ++ 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 625349ad340..1a19f02eab5 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -138,7 +138,7 @@ "rename": "1.0.4", "rss-parser": "3.13.0", "rxjs": "7.8.2", - "sanitize-html": "2.17.3", + "sanitize-html": "2.17.4", "secure-json-parse": "4.1.0", "semver": "7.7.4", "sharp": "0.33.5", diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 1392160c5aa..8f4d5cfd529 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -60,7 +60,7 @@ "punycode.js": "2.3.1", "qr-code-styling": "1.9.2", "qr-scanner": "1.4.2", - "sanitize-html": "2.17.3", + "sanitize-html": "2.17.4", "shiki": "4.0.2", "textarea-caret": "3.1.0", "three": "0.184.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d4fb2acfd5..248da08dd29 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -346,8 +346,8 @@ importers: specifier: 7.8.2 version: 7.8.2 sanitize-html: - specifier: 2.17.3 - version: 2.17.3 + specifier: 2.17.4 + version: 2.17.4 secure-json-parse: specifier: 4.1.0 version: 4.1.0 @@ -738,8 +738,8 @@ importers: specifier: 1.4.2 version: 1.4.2 sanitize-html: - specifier: 2.17.3 - version: 2.17.3 + specifier: 2.17.4 + version: 2.17.4 shiki: specifier: 4.0.2 version: 4.0.2 @@ -7207,6 +7207,9 @@ packages: resolution: {integrity: sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==} engines: {node: '>=18'} + launder@1.7.1: + resolution: {integrity: sha512-mU6WRz5EusL9ZZuiZ5SO4Y6C0P9PAUR9iwdb6bzj4KDihm28DiHFw+/yk9DBH4f+Pv1wuzQ4e2jV3oQ7mkIqvw==} + lazy-ass@1.6.0: resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} engines: {node: '> 0.8'} @@ -8901,8 +8904,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sanitize-html@2.17.3: - resolution: {integrity: sha512-Kn4srCAo2+wZyvCNKCSyB2g8RQ8IkX/gQs2uqoSRNu5t9I2qvUyAVvRDiFUVAiX3N3PNuwStY0eNr+ooBHVWEg==} + sanitize-html@2.17.4: + resolution: {integrity: sha512-2HW7v2ol/uAM7sX4hbD8Z59OGWmAPrvjL8E71UWlBcj6m+kcF6ilQBLny+cIgY214QJeJT5tQuxKKqX0SQqjGQ==} sass-embedded-all-unknown@1.99.0: resolution: {integrity: sha512-qPIRG8Uhjo6/OKyAKixTnwMliTz+t9K6Duk0mx5z+K7n0Ts38NSJz2sjDnc7cA/8V9Lb3q09H38dZ1CLwD+ssw==} @@ -17116,6 +17119,10 @@ snapshots: ky@1.14.3: {} + launder@1.7.1: + dependencies: + dayjs: 1.11.20 + lazy-ass@1.6.0: {} lazystream@1.0.1: @@ -19060,12 +19067,13 @@ snapshots: safer-buffer@2.1.2: {} - sanitize-html@2.17.3: + sanitize-html@2.17.4: dependencies: deepmerge: 4.3.1 escape-string-regexp: 4.0.0 htmlparser2: 10.1.0 is-plain-object: 5.0.0 + launder: 1.7.1 parse-srcset: 1.0.2 postcss: 8.5.14 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 88f9b251b59..9e4c609d4dc 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -56,6 +56,8 @@ minimumReleaseAgeExclude: - re2 # ����消� - nan # ����消� - systeminformation # 脆弱性対応。����消� + - sanitize-html # 脆弱性対応。����消� + - launder # 脆弱性対応。����消� overrides: '@aiscript-dev/aiscript-languageserver': '-' chokidar: 5.0.0 From 1684dc9c055df4e6b848a09470e11d9450171050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 15 May 2026 09:47:35 +0900 Subject: [PATCH 107/578] fix(deps): broken lockfile (#17404) --- pnpm-lock.yaml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 248da08dd29..25a753da19b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -331,8 +331,8 @@ importers: specifier: 3.4.1 version: 3.4.1 re2: - specifier: 1.24.0 - version: 1.24.0 + specifier: 1.24.1 + version: 1.24.1 reflect-metadata: specifier: 0.2.2 version: 0.2.2 @@ -7766,8 +7766,8 @@ packages: resolution: {integrity: sha512-BzQguy9W9NJgoVn2mRWzbFrFWWztGCcng2QI9+41frfk+Athwgx3qhqhvStz7ExeUUu7Kzw427sNzHpEZNINog==} engines: {node: '>=16.0.0'} - nan@2.26.2: - resolution: {integrity: sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==} + nan@2.27.0: + resolution: {integrity: sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==} nanoid@3.3.12: resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} @@ -8662,8 +8662,9 @@ packages: resolution: {integrity: sha512-g8OUrgMXAR9ys/ZuJVfBr05sPPoMA7nHIVs8VEvg9QwM5W4GR2qSFEEHjsyHF1eWlBaf8Ev40WNjQFQ+nJTO3w==} engines: {node: '>=18'} - re2@1.24.0: - resolution: {integrity: sha512-pBm6cMaOb0Yb0kg0Sfw/k4LwDMkPScb/NVd7GrEllDwfsPZstsZIo93A6Nn0wZuWJw3h57GdzkrOk81EofKY/g==} + re2@1.24.1: + resolution: {integrity: sha512-uRl9cLDKuobJQp+6lVz7E3AyVszubUJ0fqAMWout4ocUWTIFvdHgpqLwwMh/vuNGGGJGh2p2mJZJIQr9am9M/A==} + engines: {node: '>=22'} react-docgen-typescript@2.4.0: resolution: {integrity: sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==} @@ -17815,7 +17816,7 @@ snapshots: mylas@2.1.14: {} - nan@2.26.2: {} + nan@2.27.0: {} nanoid@3.3.12: {} @@ -18704,10 +18705,10 @@ snapshots: dependencies: setimmediate: 1.0.5 - re2@1.24.0: + re2@1.24.1: dependencies: install-artifact-from-github: 1.6.0 - nan: 2.26.2 + nan: 2.27.0 node-gyp: 12.3.0 react-docgen-typescript@2.4.0(typescript@5.9.3): From 92c1dc06f27ee90b46103b635d2c6568d35feeee Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 15 May 2026 10:11:42 +0900 Subject: [PATCH 108/578] Update CONTRIBUTING.md --- CONTRIBUTING.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 10ae1275e94..de3f4d32085 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -202,6 +202,14 @@ command. - Vite runs behind the backend (the backend will proxy Vite at /vite and /embed_vite except for websocket used for HMR). - You can see Misskey by accessing `http://localhost:3000` (Replace `3000` with the port configured with `port` in .config/default.yml). +#### Cloudflare tunnel +Cloudflare tunnelを使��ローカル�Misskeyサー�ーをインター�ット�公開����。 +HTTPS���動作���機能を検証���時や�スマホ��別�デ�イス�らローカル�Misskeyサー�ーを検証���時�便利��。 + +##### Cloudflare warp�併用�る際�tips + +> cloudflared (Cloudflare Tunnel) � region1.v2.argotunnel.com / region2.v2.argotunnel.com � QUIC/HTTP2 �アウト�ウンド接続�る�����WARP を有効化�る���トラフィック� WARP 経由����ループ/切断���。�れら 2 ホストを WARP �トン�ル除外(split tunnel)�追加�る����cloudflared ��� WARP を�イパス��直接 Cloudflare エッジ�接続��るよ���り��。 + ## Testing You can run non-backend tests by executing following commands: ```sh From e6375fb7562384f02994818d93d7f6438c21c8fa Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 15 May 2026 10:12:17 +0900 Subject: [PATCH 109/578] Update CONTRIBUTING.md --- CONTRIBUTING.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index de3f4d32085..bfb83e6de20 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -189,6 +189,14 @@ pnpm migrate After finishing the migration, you can proceed. +#### Cloudflare tunnel +Cloudflare tunnelを使��ローカル�Misskeyサー�ーをインター�ット�公開����。 +HTTPS���動作���機能を検証���時や�スマホ��別�デ�イス�らローカル�Misskeyサー�ーを検証���時�便利��。 + +##### Cloudflare warp�併用�る際�tips + +> cloudflared (Cloudflare Tunnel) � region1.v2.argotunnel.com / region2.v2.argotunnel.com � QUIC/HTTP2 �アウト�ウンド接続�る�����WARP を有効化�る���トラフィック� WARP 経由����ループ/切断���。�れら 2 ホストを WARP �トン�ル除外(split tunnel)�追加�る����cloudflared ��� WARP を�イパス��直接 Cloudflare エッジ�接続��るよ���り��。 + ### Start developing During development, it is useful to use the ``` @@ -202,14 +210,6 @@ command. - Vite runs behind the backend (the backend will proxy Vite at /vite and /embed_vite except for websocket used for HMR). - You can see Misskey by accessing `http://localhost:3000` (Replace `3000` with the port configured with `port` in .config/default.yml). -#### Cloudflare tunnel -Cloudflare tunnelを使��ローカル�Misskeyサー�ーをインター�ット�公開����。 -HTTPS���動作���機能を検証���時や�スマホ��別�デ�イス�らローカル�Misskeyサー�ーを検証���時�便利��。 - -##### Cloudflare warp�併用�る際�tips - -> cloudflared (Cloudflare Tunnel) � region1.v2.argotunnel.com / region2.v2.argotunnel.com � QUIC/HTTP2 �アウト�ウンド接続�る�����WARP を有効化�る���トラフィック� WARP 経由����ループ/切断���。�れら 2 ホストを WARP �トン�ル除外(split tunnel)�追加�る����cloudflared ��� WARP を�イパス��直接 Cloudflare エッジ�接続��るよ���り��。 - ## Testing You can run non-backend tests by executing following commands: ```sh From baad1c51d8449cb926152fd6edbbf46e8b82734c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 16 May 2026 12:54:19 +0900 Subject: [PATCH 110/578] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 648613809b6..f026e3f689d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ ### General - Enhance: Unicode 17.0 ��録�れ��る絵文字�処�・表示�対応 - Fluent Emojiや端末�イティブ�絵文字を利用���る場���最新�絵文字�対応���ら�正��表示�����能性��り��。絵文字�表示����場���表示�使用�る絵文字をTwemoji�切り替���利用����。 -- 投稿通知設定��ユーザーをリスト�見る�����るよ�� +- Enhance: 投稿通知設定��ユーザーをリスト�見る�����るよ�� +- �存関係�更新 ### Client - Enhance: テーマ�プレビュー時�リロード���も��テーマ�戻�るよ�� From 9410bc51946c9338d7200c3f705b55b2940536dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sun, 17 May 2026 18:51:10 +0900 Subject: [PATCH 111/578] fix: move `users/notify/list` to `following/list` (#17416) * fix: move `users/notify/list` to `following/list` * fix * fix lint * fix test * fix test * fix test title --- .../backend/src/server/api/endpoint-list.ts | 2 +- .../{users/notify => following}/list.ts | 23 +-- packages/backend/test/e2e/note-notify.ts | 58 ++++--- .../src/pages/settings/notifications.vue | 11 +- packages/misskey-js/etc/misskey-js.api.md | 16 +- .../misskey-js/src/autogen/apiClientJSDoc.ts | 22 +-- packages/misskey-js/src/autogen/endpoint.ts | 6 +- packages/misskey-js/src/autogen/entities.ts | 4 +- packages/misskey-js/src/autogen/types.ts | 164 +++++++++--------- 9 files changed, 165 insertions(+), 141 deletions(-) rename packages/backend/src/server/api/endpoints/{users/notify => following}/list.ts (75%) diff --git a/packages/backend/src/server/api/endpoint-list.ts b/packages/backend/src/server/api/endpoint-list.ts index 60a4656214d..feb39e98bb3 100644 --- a/packages/backend/src/server/api/endpoint-list.ts +++ b/packages/backend/src/server/api/endpoint-list.ts @@ -217,6 +217,7 @@ export * as 'flash/search' from './endpoints/flash/search.js'; export * as 'following/create' from './endpoints/following/create.js'; export * as 'following/delete' from './endpoints/following/delete.js'; export * as 'following/invalidate' from './endpoints/following/invalidate.js'; +export * as 'following/list' from './endpoints/following/list.js'; export * as 'following/requests/accept' from './endpoints/following/requests/accept.js'; export * as 'following/requests/cancel' from './endpoints/following/requests/cancel.js'; export * as 'following/requests/list' from './endpoints/following/requests/list.js'; @@ -391,7 +392,6 @@ export * as 'users/featured-notes' from './endpoints/users/featured-notes.js'; export * as 'users/flashs' from './endpoints/users/flashs.js'; export * as 'users/followers' from './endpoints/users/followers.js'; export * as 'users/following' from './endpoints/users/following.js'; -export * as 'users/notify/list' from './endpoints/users/notify/list.js'; export * as 'users/get-following-users-by-birthday' from './endpoints/users/get-following-users-by-birthday.js'; export * as 'users/gallery/posts' from './endpoints/users/gallery/posts.js'; export * as 'users/get-frequently-replied-users' from './endpoints/users/get-frequently-replied-users.js'; diff --git a/packages/backend/src/server/api/endpoints/users/notify/list.ts b/packages/backend/src/server/api/endpoints/following/list.ts similarity index 75% rename from packages/backend/src/server/api/endpoints/users/notify/list.ts rename to packages/backend/src/server/api/endpoints/following/list.ts index 4c7ca48134b..5c48621b7a5 100644 --- a/packages/backend/src/server/api/endpoints/users/notify/list.ts +++ b/packages/backend/src/server/api/endpoints/following/list.ts @@ -4,7 +4,7 @@ */ import { Inject, Injectable } from '@nestjs/common'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { FollowingEntityService } from '@/core/entities/FollowingEntityService.js'; import type { FollowingsRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { QueryService } from '@/core/QueryService.js'; @@ -15,7 +15,7 @@ export const meta = { requireCredential: true, kind: 'read:following', - description: 'List of following users with notification enabled.', + description: 'List of following users', res: { type: 'array', @@ -23,7 +23,7 @@ export const meta = { items: { type: 'object', optional: false, nullable: false, - ref: 'UserDetailed', + ref: 'Following', }, }, } as const; @@ -31,6 +31,7 @@ export const meta = { export const paramDef = { type: 'object', properties: { + notification: { type: 'boolean', default: false }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, sinceDate: { type: 'integer' }, @@ -45,22 +46,24 @@ export default class extends Endpoint { // eslint- @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, - private userEntityService: UserEntityService, + private followingEntityService: FollowingEntityService, private queryService: QueryService, ) { super(meta, paramDef, async (ps, me) => { const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .innerJoinAndSelect('following.followee', 'followee') - .andWhere('following.followerId = :userId', { userId: me.id }) - .andWhere('following.notify IS NOT NULL'); + .andWhere('following.followerId = :userId', { userId: me.id }); + + if (ps.notification) { + query.andWhere('following.notify IS NOT NULL'); + } + + query.innerJoinAndSelect('following.followee', 'followee'); const followings = await query .limit(ps.limit) .getMany(); - const users = followings.map(f => f.followee!); - - return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' }); + return await this.followingEntityService.packMany(followings, me, { populateFollowee: true }); }); } } diff --git a/packages/backend/test/e2e/note-notify.ts b/packages/backend/test/e2e/note-notify.ts index 9835223053b..b3d5d110b9b 100644 --- a/packages/backend/test/e2e/note-notify.ts +++ b/packages/backend/test/e2e/note-notify.ts @@ -9,7 +9,7 @@ import { describe, beforeAll, test } from 'vitest'; import { api, signup } from '../utils.js'; import type * as misskey from 'misskey-js'; -describe('users/notify/list', () => { +describe('following/list', () => { let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; let carol: misskey.entities.SignupResponse; @@ -24,11 +24,19 @@ describe('users/notify/list', () => { // alice � bob を普通�フォロー(通知設定��) await api('following/create', { userId: bob.id }, alice); - const res = await api('users/notify/list', {}, alice); + const res1 = await api('following/list', { notification: true }, alice); + const res2 = await api('following/list', {}, alice); - assert.strictEqual(res.status, 200); - assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.length, 0); + // notification: true �場��通知設定���フォロー�返ら�� + assert.strictEqual(res1.status, 200); + assert.strictEqual(Array.isArray(res1.body), true); + assert.strictEqual(res1.body.length, 0); + + // notification パラメータ���場��通知設定���フォローも返る + assert.strictEqual(res2.status, 200); + assert.strictEqual(Array.isArray(res2.body), true); + assert.strictEqual(res2.body.length, 1); + assert.strictEqual(res2.body[0].followeeId, bob.id); }); test('通知設定�り�フォロー��る場����ユーザー�返る', async () => { @@ -36,34 +44,42 @@ describe('users/notify/list', () => { await api('following/create', { userId: carol.id, withReplies: false }, alice); await api('following/update', { userId: carol.id, notify: 'normal' }, alice); - const res = await api('users/notify/list', {}, alice); + const res = await api('following/list', { notification: true }, alice); assert.strictEqual(res.status, 200); assert.strictEqual(res.body.length, 1); - assert.strictEqual(res.body[0].id, carol.id); + assert.strictEqual(res.body[0].followeeId, carol.id); }); test('複数ユーザー�通知設定�り�場��全員返る', async () => { // bob �も通知設定をON await api('following/update', { userId: bob.id, notify: 'normal' }, alice); - const res = await api('users/notify/list', {}, alice); + const res = await api('following/list', { notification: true }, alice); assert.strictEqual(res.status, 200); assert.strictEqual(res.body.length, 2); - const ids = res.body.map((u: { id: string }) => u.id).sort(); + const ids = res.body.map((u) => u.followeeId).sort(); assert.deepStrictEqual(ids, [bob.id, carol.id].sort()); }); - test('通知設定をOFF(none)��る�一覧�ら外れる', async () => { + test('通知設定をOFF(none)��る� notification: true �一覧�ら外れる', async () => { await api('following/update', { userId: bob.id, notify: 'none' }, alice); - const res = await api('users/notify/list', {}, alice); + const res1 = await api('following/list', { notification: true }, alice); + const res2 = await api('following/list', {}, alice); - assert.strictEqual(res.status, 200); - assert.strictEqual(res.body.length, 1); - assert.strictEqual(res.body[0].id, carol.id); + // notification: true �場�� bob �返ら�� + assert.strictEqual(res1.status, 200); + assert.strictEqual(res1.body.length, 1); + assert.strictEqual(res1.body[0].followeeId, carol.id); + + // notification パラメータ���場�� bob も返る + assert.strictEqual(res2.status, 200); + assert.strictEqual(res2.body.length, 2); + const ids = res2.body.map((u) => u.followeeId).sort(); + assert.deepStrictEqual(ids, [bob.id, carol.id].sort()); }); test('他�ユーザー�通知対象�見���', async () => { @@ -72,14 +88,14 @@ describe('users/notify/list', () => { await api('following/update', { userId: carol.id, notify: 'normal' }, bob); // alice �一覧�� bob �通知設定��映�れ�� - const aliceRes = await api('users/notify/list', {}, alice); - const aliceIds = aliceRes.body.map((u: { id: string }) => u.id); + const aliceRes = await api('following/list', { notification: true }, alice); + const aliceIds = aliceRes.body.map((u) => u.followeeId); assert.strictEqual(aliceIds.includes(bob.id), false); // bob �一覧�� carol �����れる - const bobRes = await api('users/notify/list', {}, bob); + const bobRes = await api('following/list', { notification: true }, bob); assert.strictEqual(bobRes.body.length, 1); - assert.strictEqual(bobRes.body[0].id, carol.id); + assert.strictEqual(bobRes.body[0].followeeId, carol.id); // 後片付�: bob → carol �フォローを解除 await api('following/delete', { userId: carol.id }, bob); @@ -114,18 +130,18 @@ describe('users/notify/list', () => { await api('following/update', { userId: bob.id, notify: 'normal' }, alice); // limit����2件返る��を確� - const allRes = await api('users/notify/list', {}, alice); + const allRes = await api('following/list', { notification: true }, alice); assert.strictEqual(allRes.status, 200); assert.strictEqual(allRes.body.length, 2); // limit:1 �1件�絞られる��を確� - const res = await api('users/notify/list', { limit: 1 }, alice); + const res = await api('following/list', { notification: true, limit: 1 }, alice); assert.strictEqual(res.status, 200); assert.strictEqual(res.body.length, 1); }); test('未�証�場��エラー', async () => { - const res = await api('users/notify/list', {}); + const res = await api('following/list', {}); assert.strictEqual(res.status, 401); }); }); diff --git a/packages/frontend/src/pages/settings/notifications.vue b/packages/frontend/src/pages/settings/notifications.vue index ffd8493cc3f..9ff45fa4c54 100644 --- a/packages/frontend/src/pages/settings/notifications.vue +++ b/packages/frontend/src/pages/settings/notifications.vue @@ -47,10 +47,10 @@ SPDX-License-Identifier: AGPL-3.0-only
- - + + - +
@@ -125,8 +125,11 @@ async function showNotifyMenu(user: Misskey.entities.UserDetailed, ev: PointerEv }], ev.currentTarget ?? ev.target); } -const notifyUserPaginator = markRaw(new Paginator('users/notify/list', { +const notifyUserPaginator = markRaw(new Paginator('following/list', { limit: 10, + params: { + notification: true, + }, })); const nonConfigurableNotificationTypes = ['note', 'roleAssigned', 'followRequestAccepted', 'test', 'exportCompleted'] as const satisfies (typeof notificationTypes[number])[]; diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 852ccbb9b90..7a4d44498f2 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1884,6 +1884,8 @@ declare namespace entities { FollowingDeleteResponse, FollowingInvalidateRequest, FollowingInvalidateResponse, + FollowingListRequest, + FollowingListResponse, FollowingRequestsAcceptRequest, FollowingRequestsCancelRequest, FollowingRequestsCancelResponse, @@ -2162,8 +2164,6 @@ declare namespace entities { UsersListsUpdateMembershipRequest, UsersNotesRequest, UsersNotesResponse, - UsersNotifyListRequest, - UsersNotifyListResponse, UsersPagesRequest, UsersPagesResponse, UsersReactionsRequest, @@ -2403,6 +2403,12 @@ type FollowingInvalidateRequest = operations['following___invalidate']['requestB // @public (undocumented) type FollowingInvalidateResponse = operations['following___invalidate']['responses']['200']['content']['application/json']; +// @public (undocumented) +type FollowingListRequest = operations['following___list']['requestBody']['content']['application/json']; + +// @public (undocumented) +type FollowingListResponse = operations['following___list']['responses']['200']['content']['application/json']; + // @public (undocumented) type FollowingRequestsAcceptRequest = operations['following___requests___accept']['requestBody']['content']['application/json']; @@ -3829,12 +3835,6 @@ type UsersNotesRequest = operations['users___notes']['requestBody']['content'][' // @public (undocumented) type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json']; -// @public (undocumented) -type UsersNotifyListRequest = operations['users___notify___list']['requestBody']['content']['application/json']; - -// @public (undocumented) -type UsersNotifyListResponse = operations['users___notify___list']['responses']['200']['content']['application/json']; - // @public (undocumented) type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index 395156ad938..a10471aa77e 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -2570,6 +2570,17 @@ declare module '../api.js' { credential?: string | null, ): Promise>; + /** + * List of following users + * + * **Credential required**: *Yes* / **Permission**: *read:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + /** * No description provided. * @@ -4697,17 +4708,6 @@ declare module '../api.js' { credential?: string | null, ): Promise>; - /** - * List of following users with notification enabled. - * - * **Credential required**: *Yes* / **Permission**: *read:following* - */ - request( - endpoint: E, - params: P, - credential?: string | null, - ): Promise>; - /** * Show all pages this user created. * diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index dbbc44cb7bb..063691da8df 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -360,6 +360,8 @@ import type { FollowingDeleteResponse, FollowingInvalidateRequest, FollowingInvalidateResponse, + FollowingListRequest, + FollowingListResponse, FollowingRequestsAcceptRequest, FollowingRequestsCancelRequest, FollowingRequestsCancelResponse, @@ -640,8 +642,6 @@ import type { UsersListsUpdateMembershipRequest, UsersNotesRequest, UsersNotesResponse, - UsersNotifyListRequest, - UsersNotifyListResponse, UsersPagesRequest, UsersPagesResponse, UsersReactionsRequest, @@ -896,6 +896,7 @@ export type Endpoints = { 'following/create': { req: FollowingCreateRequest; res: FollowingCreateResponse }; 'following/delete': { req: FollowingDeleteRequest; res: FollowingDeleteResponse }; 'following/invalidate': { req: FollowingInvalidateRequest; res: FollowingInvalidateResponse }; + 'following/list': { req: FollowingListRequest; res: FollowingListResponse }; 'following/requests/accept': { req: FollowingRequestsAcceptRequest; res: EmptyResponse }; 'following/requests/cancel': { req: FollowingRequestsCancelRequest; res: FollowingRequestsCancelResponse }; 'following/requests/list': { req: FollowingRequestsListRequest; res: FollowingRequestsListResponse }; @@ -1086,7 +1087,6 @@ export type Endpoints = { 'users/lists/update': { req: UsersListsUpdateRequest; res: UsersListsUpdateResponse }; 'users/lists/update-membership': { req: UsersListsUpdateMembershipRequest; res: EmptyResponse }; 'users/notes': { req: UsersNotesRequest; res: UsersNotesResponse }; - 'users/notify/list': { req: UsersNotifyListRequest; res: UsersNotifyListResponse }; 'users/pages': { req: UsersPagesRequest; res: UsersPagesResponse }; 'users/reactions': { req: UsersReactionsRequest; res: UsersReactionsResponse }; 'users/recommendation': { req: UsersRecommendationRequest; res: UsersRecommendationResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index c2f845d8ccb..f7cb34a02e1 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -363,6 +363,8 @@ export type FollowingDeleteRequest = operations['following___delete']['requestBo export type FollowingDeleteResponse = operations['following___delete']['responses']['200']['content']['application/json']; export type FollowingInvalidateRequest = operations['following___invalidate']['requestBody']['content']['application/json']; export type FollowingInvalidateResponse = operations['following___invalidate']['responses']['200']['content']['application/json']; +export type FollowingListRequest = operations['following___list']['requestBody']['content']['application/json']; +export type FollowingListResponse = operations['following___list']['responses']['200']['content']['application/json']; export type FollowingRequestsAcceptRequest = operations['following___requests___accept']['requestBody']['content']['application/json']; export type FollowingRequestsCancelRequest = operations['following___requests___cancel']['requestBody']['content']['application/json']; export type FollowingRequestsCancelResponse = operations['following___requests___cancel']['responses']['200']['content']['application/json']; @@ -643,8 +645,6 @@ export type UsersListsUpdateResponse = operations['users___lists___update']['res export type UsersListsUpdateMembershipRequest = operations['users___lists___update-membership']['requestBody']['content']['application/json']; export type UsersNotesRequest = operations['users___notes']['requestBody']['content']['application/json']; export type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json']; -export type UsersNotifyListRequest = operations['users___notify___list']['requestBody']['content']['application/json']; -export type UsersNotifyListResponse = operations['users___notify___list']['responses']['200']['content']['application/json']; export type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json']; export type UsersPagesResponse = operations['users___pages']['responses']['200']['content']['application/json']; export type UsersReactionsRequest = operations['users___reactions']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index ecc64039d71..4b6d26b63f2 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -2105,6 +2105,15 @@ export type paths = { */ post: operations['following___invalidate']; }; + '/following/list': { + /** + * following/list + * @description List of following users + * + * **Credential required**: *Yes* / **Permission**: *read:following* + */ + post: operations['following___list']; + }; '/following/requests/accept': { /** * following/requests/accept @@ -3852,15 +3861,6 @@ export type paths = { */ post: operations['users___notes']; }; - '/users/notify/list': { - /** - * users/notify/list - * @description List of following users with notification enabled. - * - * **Credential required**: *Yes* / **Permission**: *read:following* - */ - post: operations['users___notify___list']; - }; '/users/pages': { /** * users/pages @@ -22521,6 +22521,80 @@ export interface operations { }; }; }; + following___list: { + requestBody: { + content: { + 'application/json': { + /** @default false */ + notification?: boolean; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + sinceDate?: number; + untilDate?: number; + /** @default 10 */ + limit?: number; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Following'][]; + }; + }; + /** @description Client error */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; following___requests___accept: { requestBody: { content: { @@ -36056,78 +36130,6 @@ export interface operations { }; }; }; - users___notify___list: { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - sinceDate?: number; - untilDate?: number; - /** @default 10 */ - limit?: number; - }; - }; - }; - responses: { - /** @description OK (with results) */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - 'application/json': components['schemas']['UserDetailed'][]; - }; - }; - /** @description Client error */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - 'application/json': components['schemas']['Error']; - }; - }; - /** @description Authentication error */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - 'application/json': components['schemas']['Error']; - }; - }; - /** @description Forbidden error */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - 'application/json': components['schemas']['Error']; - }; - }; - /** @description I'm Ai */ - 418: { - headers: { - [name: string]: unknown; - }; - content: { - 'application/json': components['schemas']['Error']; - }; - }; - /** @description Internal server error */ - 500: { - headers: { - [name: string]: unknown; - }; - content: { - 'application/json': components['schemas']['Error']; - }; - }; - }; - }; users___pages: { requestBody: { content: { From 99081be9fd2404d9a91f4a1f58205254cb54e145 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 17 May 2026 09:59:00 +0000 Subject: [PATCH 112/578] Bump version to 2026.5.2-beta.1 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1a32dc48bec..2fbd9ba4cda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2026.5.2-beta.0", + "version": "2026.5.2-beta.1", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 90045fd12a8..12d63dcd9fd 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2026.5.2-beta.0", + "version": "2026.5.2-beta.1", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From fc6c45d175ae37d80fa33709a12b5f033adc7e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Sun, 17 May 2026 19:30:35 +0900 Subject: [PATCH 113/578] =?UTF-8?q?fix:=20add-i18n-key=E3=81=AE=E8=A8=98?= =?UTF-8?q?=E8=BF=B0=E3=81=8C=E9=96=93=E9=81=95=E3=81=A3=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=9F=E3=81=AE=E3=81=A7=E4=BF=AE=E6=AD=A3=20(#17418)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/skills/add-i18n-key/SKILL.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.claude/skills/add-i18n-key/SKILL.md b/.claude/skills/add-i18n-key/SKILL.md index 903cfea217c..899c61826de 100644 --- a/.claude/skills/add-i18n-key/SKILL.md +++ b/.claude/skills/add-i18n-key/SKILL.md @@ -26,7 +26,9 @@ _settings: general: "全般" appearance: "外観" -# パラメータ付� (ICU MessageFormat 互�) +# パラメータ付� (�純�プレースホルダ置�) +# ICU MessageFormat � plural / select / number / date ����対応 +# 使�る�� `{name}` �よ���純�置��� greeting: "�ん����{name}�ん" ``` From 2bc0ccb108bfd59227aa86cb1178665d0505544d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 17 May 2026 22:14:54 +0000 Subject: [PATCH 114/578] Release: 2026.5.2 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2fbd9ba4cda..3c52ec40b87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2026.5.2-beta.1", + "version": "2026.5.2", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 12d63dcd9fd..7fd486067bd 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2026.5.2-beta.1", + "version": "2026.5.2", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From badb243021e17d7464741a53dedb3939c42b0893 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 17 May 2026 22:15:01 +0000 Subject: [PATCH 115/578] [skip ci] Update CHANGELOG.md (prepend template) --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f026e3f689d..bbf9bcbbc63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## Unreleased + +### General +- + +### Client +- + +### Server +- + + ## 2026.5.2 ### Note From 419cdcff368460e536b985bcdc64e29bc970f69c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Mon, 18 May 2026 07:25:03 +0900 Subject: [PATCH 116/578] Update about-misskey.vue --- packages/frontend/src/pages/about-misskey.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index 175402fd8e7..c9ef67c4ea0 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -138,6 +138,7 @@ SPDX-License-Identifier: AGPL-3.0-only -``` - -## 国際化 (i18n) - -- 文字列リテラルを直書����。 -- 引数��: `i18n.ts.` ��照�る (例: `i18n.ts.deleted`)。 -- 引数�り: `i18n.tsx.(...)` �関数呼�出��る (例: `i18n.tsx.takeOverConfirm({ name })`)。 -- 新�キー� **`locales/ja-JP.yml` ��** �追加�る (他言語� Crowdin �自動�信)。 -- `i18n` � `packages/frontend/src/i18n.ts` (���共有モジュール) �ら import �る。 - -## モーダル / 通知 - -- `os.ts` (`packages/frontend/src/os.ts`) 経由�呼�。 -- `os.alert(...)` / `os.confirm(...)` / `os.popup(...)` / `os.success(...)` ��。 -- ブラウザ標準� `window.alert()` / `window.confirm()` を **直接呼���**。 - -## アクセシビリティ (PR レビュー�指摘�れや��点) - -- クリック�ンドラを付�る�ら ` +``` + +- `_button` global class �ボタン�装飾を除去�るリセット (背景/枠線�� + `cursor: pointer` + disabled cursor)。focus ring や ripple �**付���** — ripple 付��ボタン��る�ら `MkButton.vue` コン�ー�ントを使� +- ` +``` + +`aria-label` �値も i18n 経由��る (英語直書���止)。 + +**実情:** �状コードベース�� `aria-label` �使用例自体���� (アイコン� hover ヒント�� `:title="i18n.ts..."` �使�れる��`title` � tooltip ��りスクリーンリーダー��ラベル�代替���ら��)。���� aria-label �確立��慣習���より a11y 上�推奨ベストプラクティス���書���る。新��アイコン���ボタンを足��ら付�る��望���。 + +### `:disabled` � `aria-disabled` �整� + +- 本物� `
@@ -100,6 +100,7 @@ import { hms } from '@/filters/hms.js'; import MkMediaRange from '@/components/MkMediaRange.vue'; import { $i, iAmModerator } from '@/i.js'; import { prefer } from '@/preferences.js'; +import { getFileMenu } from '@/utility/get-file-menu.js'; import { canRevealFile, shouldHideFileByDefault } from '@/utility/sensitive-file.js'; const props = defineProps<{ @@ -208,56 +209,11 @@ function showMenu(ev: MouseEvent) { { type: 'divider', }, - { - text: i18n.ts.hide, - icon: 'ti ti-eye-off', - action: () => { - hide.value = true; - }, - }, ]; - if (iAmModerator) { - menu.push({ - text: props.audio.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive, - icon: props.audio.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation', - danger: true, - action: () => toggleSensitive(props.audio), - }); - } - - const details: MenuItem[] = []; - if ($i?.id === props.audio.userId) { - details.push({ - type: 'link', - text: i18n.ts._fileViewer.title, - icon: 'ti ti-info-circle', - to: `/my/drive/file/${props.audio.id}`, - }); - } - - if (iAmModerator) { - details.push({ - type: 'link', - text: i18n.ts.moderation, - icon: 'ti ti-photo-exclamation', - to: `/admin/file/${props.audio.id}`, - }); - } - - if (details.length > 0) { - menu.push({ type: 'divider' }, ...details); - } - - if (prefer.s.devMode) { - menu.push({ type: 'divider' }, { - icon: 'ti ti-hash', - text: i18n.ts.copyFileId, - action: () => { - copyToClipboard(props.audio.id); - }, - }); - } + menu.push(...getFileMenu(props.audio, (newState) => { + hide.value = newState; + })); menuShowing.value = true; os.popupMenu(menu, ev.currentTarget ?? ev.target, { @@ -268,20 +224,6 @@ function showMenu(ev: MouseEvent) { }); } -async function toggleSensitive(file: Misskey.entities.DriveFile) { - const { canceled } = await os.confirm({ - type: 'warning', - text: file.isSensitive ? i18n.ts.unmarkAsSensitiveConfirm : i18n.ts.markAsSensitiveConfirm, - }); - - if (canceled) return; - - os.apiWithDialog('drive/files/update', { - fileId: file.id, - isSensitive: !file.isSensitive, - }); -} - // MediaControl: Common State const oncePlayed = ref(false); const isReady = ref(false); diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index 4236bd943a9..01f449753bf 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/utility/paginator.ts b/packages/frontend/src/utility/paginator.ts index 45054acfd08..471b7c0d915 100644 --- a/packages/frontend/src/utility/paginator.ts +++ b/packages/frontend/src/utility/paginator.ts @@ -17,6 +17,8 @@ export type MisskeyEntity = { id: string; createdAt: string; _shouldInsertAd_?: boolean; + _shouldAnimateIn_?: boolean; + _shouldAnimateOut_?: boolean; }; type AbsEndpointType = { @@ -107,6 +109,8 @@ export class Paginator< private canFetchDetection: 'safe' | 'limit' | null = null; private aheadQueue: T[] = []; private useShallowRef: SRef; + private itemRemovalDelay: number | false; + private removalTimers = new Map(); // �列内��素を��よ��順��並�る� // newest: 新��も��先頭 (default) @@ -138,6 +142,9 @@ export class Paginator< useShallowRef?: SRef; + // アイテム削除時�アニメーションを待�時間 (ms) + itemRemovalDelay?: number | false; + canSearch?: boolean; searchParamName?: keyof E['req']; }) { @@ -160,6 +167,7 @@ export class Paginator< this.noPaging = props.noPaging ?? false; this.offsetMode = props.offsetMode ?? false; this.canSearch = props.canSearch ?? false; + this.itemRemovalDelay = props.itemRemovalDelay ?? false; this.searchParamName = props.searchParamName ?? 'search'; this.getNewestId = this.getNewestId.bind(this); @@ -191,6 +199,7 @@ export class Paginator< } public async init(): Promise { + this.clearRemovalTimers(); this.items.value = []; this.aheadQueue = []; this.queuedAheadItemsCount.value = 0; @@ -384,6 +393,8 @@ export class Paginator< public prepend(item: T): void { if (this.items.value.some(x => x.id === item.id)) return; + item._shouldAnimateIn_ = true; + item._shouldAnimateOut_ = false; this.items.value.unshift(item); this.trim(false); if (this.useShallowRef) triggerRef(this.items); @@ -399,6 +410,9 @@ export class Paginator< public releaseQueue(): void { if (this.aheadQueue.length === 0) return; // �れやら���余計�re-render�走る + for (const item of this.aheadQueue) { + item._shouldAnimateIn_ = true; + } this.unshiftItems(this.aheadQueue); this.aheadQueue = []; this.queuedAheadItemsCount.value = 0; @@ -407,11 +421,41 @@ export class Paginator< public removeItem(id: string): void { // TODO: queue�らも消� + if (this.itemRemovalDelay === false) { + const index = this.items.value.findIndex(x => x.id === id); + if (index !== -1) { + this.items.value.splice(index, 1); + if (this.useShallowRef) triggerRef(this.items); + } + return; + } + const index = this.items.value.findIndex(x => x.id === id); if (index !== -1) { - this.items.value.splice(index, 1); if (this.useShallowRef) triggerRef(this.items); + + const item = this.items.value[index]!; + item._shouldAnimateOut_ = true; + if (this.useShallowRef) triggerRef(this.items); + + if (this.removalTimers.has(id)) return; + + this.removalTimers.set(id, window.setTimeout(() => { + this.removalTimers.delete(id); + const currentIndex = this.items.value.findIndex(x => x.id === id); + if (currentIndex !== -1) { + this.items.value.splice(currentIndex, 1); + if (this.useShallowRef) triggerRef(this.items); + } + }, this.itemRemovalDelay + 20)); // アニメーション終了�らやや余裕をも��る + } + } + + private clearRemovalTimers(): void { + for (const timer of this.removalTimers.values()) { + window.clearTimeout(timer); } + this.removalTimers.clear(); } public updateItem(id: string, updater: (item: T) => T): void { From 667919581e604140f7caed9be9800ecf46a5c2e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Wed, 15 Jul 2026 13:29:39 +0900 Subject: [PATCH 348/578] =?UTF-8?q?enhance:=20=E6=96=B0=E3=81=97=E3=81=84L?= =?UTF-8?q?ogger=E3=81=AE=E3=82=B3=E3=82=A2=E5=AE=9F=E8=A3=85=20(#17714)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance: impl logger core * fix order --- packages/backend/src/logger.ts | 105 +++++-------- packages/backend/src/logging/LogBackend.ts | 21 +++ packages/backend/src/logging/LogManager.ts | 94 +++++++++++ .../src/logging/PrettyConsoleBackend.ts | 82 ++++++++++ .../backend/src/logging/logging-runtime.ts | 13 ++ packages/backend/src/logging/types.ts | 50 ++++++ .../backend/test/unit/logging/LogManager.ts | 125 +++++++++++++++ packages/backend/test/unit/logging/Logger.ts | 103 ++++++++++++ .../test/unit/logging/PrettyConsoleBackend.ts | 147 ++++++++++++++++++ 9 files changed, 678 insertions(+), 62 deletions(-) create mode 100644 packages/backend/src/logging/LogBackend.ts create mode 100644 packages/backend/src/logging/LogManager.ts create mode 100644 packages/backend/src/logging/PrettyConsoleBackend.ts create mode 100644 packages/backend/src/logging/logging-runtime.ts create mode 100644 packages/backend/src/logging/types.ts create mode 100644 packages/backend/test/unit/logging/LogManager.ts create mode 100644 packages/backend/test/unit/logging/Logger.ts create mode 100644 packages/backend/test/unit/logging/PrettyConsoleBackend.ts diff --git a/packages/backend/src/logger.ts b/packages/backend/src/logger.ts index ce76f8d05e5..c32b462cc03 100644 --- a/packages/backend/src/logger.ts +++ b/packages/backend/src/logger.ts @@ -3,80 +3,59 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import cluster from 'node:cluster'; -import chalk from 'chalk'; -import { default as convertColor } from 'color-convert'; -import { format as dateFormat } from 'date-fns'; import { bindThis } from '@/decorators.js'; -import { envOption } from './env.js'; +import { logManager } from './logging/logging-runtime.js'; +import type { LogLevel, LoggerContext } from './logging/types.js'; import type { Keyword } from 'color-convert'; -type Context = { - name: string; - color?: Keyword; -}; - -type Level = 'error' | 'success' | 'warning' | 'debug' | 'info'; - +/** + * ロガー��階層�従��公開APIを�供�る薄�窓���。 + * 出力�件�判断や整形�LogManager�LogBackend�委譲���。 + */ // eslint-disable-next-line import/no-default-export export default class Logger { - private context: Context; - private parentLogger: Logger | null = null; + private context: readonly LoggerContext[]; + /** 指定����を起点��るLoggerを作����。 */ constructor(context: string, color?: Keyword) { - this.context = { + this.context = [{ name: context, - color: color, - }; + color, + }]; } + /** + * �在�ロガーを親����下����を��Loggerを作����。 + */ @bindThis public createSubLogger(context: string, color?: Keyword): Logger { const logger = new Logger(context, color); - logger.parentLogger = this; + logger.context = [...this.context, ...logger.context]; return logger; } + /** + * 従�API�引数を共通形��変���LogManager�渡���。 + */ @bindThis - private log(level: Level, message: string, data?: Record | null, important = false, subContexts: Context[] = []): void { - if (envOption.quiet) return; - - if (this.parentLogger) { - this.parentLogger.log(level, message, data, important, [this.context].concat(subContexts)); - return; - } - - const time = dateFormat(new Date(), 'HH:mm:ss'); - const worker = cluster.isPrimary ? '*' : cluster.worker!.id; - const l = - level === 'error' ? important ? chalk.bgRed.white('ERR ') : chalk.red('ERR ') : - level === 'warning' ? chalk.yellow('WARN') : - level === 'success' ? important ? chalk.bgGreen.white('DONE') : chalk.green('DONE') : - level === 'debug' ? chalk.gray('VERB') : - level === 'info' ? chalk.blue('INFO') : - null; - const contexts = [this.context].concat(subContexts).map(d => d.color ? chalk.rgb(...convertColor.keyword.rgb(d.color))(d.name) : chalk.white(d.name)); - const m = - level === 'error' ? chalk.red(message) : - level === 'warning' ? chalk.yellow(message) : - level === 'success' ? chalk.green(message) : - level === 'debug' ? chalk.gray(message) : - level === 'info' ? message : - null; - - let log = `${l} ${worker}\t[${contexts.join(' ')}]\t${m}`; - if (envOption.withLogTime) log = chalk.gray(time) + ' ' + log; - - const args: unknown[] = [important ? chalk.bold(log) : log]; - if (data != null) { - args.push(data); - } - console.log(...args); + private log(level: LogLevel, message: string, data?: Record | null, important = false, legacyLevel?: 'success'): void { + logManager.write({ + level, + message, + context: this.context, + compatibility: { + legacyLevel, + important, + data, + }, + }); } + /** 処�を継続����状�を記録���。 */ @bindThis - public error(x: string | Error, data?: Record | null, important = false): void { // 実行を継続����状��使� + public error(x: string | Error, data?: Record | null, important = false): void { if (x instanceof Error) { + // Error本体も第2引数�残��従���りスタック��を確���るよ�����。 data = data ?? {}; data.e = x; this.log('error', x.toString(), data, important); @@ -87,25 +66,27 @@ export default class Logger { } } + /** 処��継続��るも���改善�必��状�を記録���。 */ @bindThis - public warn(message: string, data?: Record | null, important = false): void { // 実行を継続��る�改善���状��使� - this.log('warning', message, data, important); + public warn(message: string, data?: Record | null, important = false): void { + this.log('warn', message, data, important); } + /** 処���功����を�従��DONE表示�記録���。 */ @bindThis - public succ(message: string, data?: Record | null, important = false): void { // 何���功��状��使� - this.log('success', message, data, important); + public succ(message: string, data?: Record | null, important = false): void { + this.log('info', message, data, important, 'success'); } + /** 開発者���調査情報を記録���。 */ @bindThis - public debug(message: string, data?: Record | null, important = false): void { // デ�ッグ用�使�(開発者�必���利用者����情報) - if (process.env.NODE_ENV !== 'production' || envOption.verbose) { - this.log('debug', message, data, important); - } + public debug(message: string, data?: Record | null, important = false): void { + this.log('debug', message, data, important); } + /** 通常�動作状�を記録���。 */ @bindThis - public info(message: string, data?: Record | null, important = false): void { // �れ以外 + public info(message: string, data?: Record | null, important = false): void { this.log('info', message, data, important); } } diff --git a/packages/backend/src/logging/LogBackend.ts b/packages/backend/src/logging/LogBackend.ts new file mode 100644 index 00000000000..36d2a60bb66 --- /dev/null +++ b/packages/backend/src/logging/LogBackend.ts @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { LogRecord } from './types.js'; + +/** + * 整形済��ログを実際�出力先�渡����共通窓���。 + * Loggerを特定�出力形���存����後�ら出力先を追加��るよ�����。 + */ +export interface LogBackend { + /** ログを一件出力���。 */ + write(record: LogRecord): void; + + /** �留中�出力��る場������書�出���。 */ + flush?(): void | Promise; + + /** 出力先���資�を解放���。 */ + close?(): void | Promise; +} diff --git a/packages/backend/src/logging/LogManager.ts b/packages/backend/src/logging/LogManager.ts new file mode 100644 index 00000000000..d31aac5dafe --- /dev/null +++ b/packages/backend/src/logging/LogManager.ts @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import cluster from 'node:cluster'; +import process from 'node:process'; +import { envOption } from '@/env.js'; +import type { LogBackend } from './LogBackend.js'; +import type { LogRecordInput } from './types.js'; + +/** ログを出力��プロセスを識別�る���情報��。 */ +export type LogProcessInfo = { + readonly processId: number; + readonly isPrimary: boolean; + readonly workerId: number | null; +}; + +/** + * 実行環境�ら�得�る値を�����存関係��。 + * テスト��固定値�差�替��時刻やプロセス状態�左��れ��よ�����。 + */ +export type LogManagerDependencies = { + readonly now: () => Date; + readonly getProcessInfo: () => LogProcessInfo; + readonly isQuiet: () => boolean; + readonly isVerbose: () => boolean; + readonly getNodeEnv: () => string | undefined; +}; + +const defaultDependencies: LogManagerDependencies = { + now: () => new Date(), + getProcessInfo: () => ({ + processId: process.pid, + isPrimary: cluster.isPrimary, + workerId: cluster.isPrimary ? null : (cluster.worker?.id ?? null), + }), + isQuiet: () => envOption.quiet, + isVerbose: () => envOption.verbose, + getNodeEnv: () => process.env.NODE_ENV, +}; + +/** + * ログ�出力��を判断������出力先�共通��る情報を付加���。 + * Logger�出力先�間�置�����設定や共通情報�扱�を一�所�集約���。 + */ +export class LogManager { + private backend: LogBackend; + private readonly dependencies: LogManagerDependencies; + + /** + * 出力先�実行環境�ら値を�得�る処�を���り��。 + * 実行環境��得処���必��項目��テスト用�差�替�られ��。 + */ + constructor(backend: LogBackend, dependencies: Partial = {}) { + this.backend = backend; + this.dependencies = { + ...defaultDependencies, + ...dependencies, + }; + } + + /** + * 以後�ログを書�込む出力先を切り替���。 + * 作�済��Logger�も切り替�を�映�る���LogManager�������。 + */ + public setBackend(backend: LogBackend): void { + this.backend = backend; + } + + /** + * 出力�件を確���共通情報を付加��出力先�渡���。 + */ + public write(input: LogRecordInput): void { + // `quiet`�他��件より優先��ログ�付��る情報��得も行���ん。 + if (this.dependencies.isQuiet()) return; + + // 本番環境�デ�ッグログ��明示的�`verbose`�指定�れ�場���出力���。 + if (input.level === 'debug' && this.dependencies.getNodeEnv() === 'production' && !this.dependencies.isVerbose()) return; + + const processInfo = this.dependencies.getProcessInfo(); + // 呼�出����列を共有���親�ら末端���順�を固定���。 + const context = [...input.context]; + this.backend.write({ + ...input, + context, + timestamp: this.dependencies.now().toISOString(), + loggerName: context.map(segment => segment.name).join('.'), + processId: processInfo.processId, + isPrimary: processInfo.isPrimary, + workerId: processInfo.workerId, + }); + } +} diff --git a/packages/backend/src/logging/PrettyConsoleBackend.ts b/packages/backend/src/logging/PrettyConsoleBackend.ts new file mode 100644 index 00000000000..6af60e5efd0 --- /dev/null +++ b/packages/backend/src/logging/PrettyConsoleBackend.ts @@ -0,0 +1,82 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import chalk from 'chalk'; +import { default as convertColor } from 'color-convert'; +import { format as dateFormat } from 'date-fns'; +import { envOption } from '@/env.js'; +import type { LogBackend } from './LogBackend.js'; +import type { LogRecord } from './types.js'; + +/** Pretty形��出力処��外部�ら���る�存関係��。 */ +export type PrettyConsoleBackendDependencies = { + readonly output: (...args: unknown[]) => void; + readonly withLogTime: () => boolean; +}; + +const defaultDependencies: PrettyConsoleBackendDependencies = { + output: (...args) => console.log(...args), + withLogTime: () => envOption.withLogTime, +}; + +/** + * 人�読�や��従�形��整形��コンソール�出力���。 + * 色�ラベル�時刻���見�目��を担当��出力���LogManager�任���。 + */ +export class PrettyConsoleBackend implements LogBackend { + private readonly dependencies: PrettyConsoleBackendDependencies; + + /** + * 出力処��時刻表示�判定処�を���り��。 + * �略時�従���り�標準�コンソール�環境設定を使用���。 + */ + constructor(dependencies: Partial = {}) { + this.dependencies = { + ...defaultDependencies, + ...dependencies, + }; + } + + /** + * 共通�ログを従�形��整形��一件出力���。 + */ + public write(record: LogRecord): void { + const legacyLevel = record.compatibility?.legacyLevel; + // `fatal`��大�エラー���扱��従��`important`���強調表示����。 + const important = record.level === 'fatal' || (record.compatibility?.important ?? false); + const presentationLevel = record.level === 'fatal' ? 'error' : (legacyLevel ?? record.level); + const label = + presentationLevel === 'error' ? important ? chalk.bgRed.white('ERR ') : chalk.red('ERR ') : + presentationLevel === 'warn' ? chalk.yellow('WARN') : + presentationLevel === 'success' ? important ? chalk.bgGreen.white('DONE') : chalk.green('DONE') : + presentationLevel === 'debug' ? chalk.gray('VERB') : + presentationLevel === 'info' ? chalk.blue('INFO') : + null; + const contexts = record.context.map(context => context.color + ? chalk.rgb(...convertColor.keyword.rgb(context.color))(context.name) + : chalk.white(context.name)); + const message = + presentationLevel === 'error' ? chalk.red(record.message) : + presentationLevel === 'warn' ? chalk.yellow(record.message) : + presentationLevel === 'success' ? chalk.green(record.message) : + presentationLevel === 'debug' ? chalk.gray(record.message) : + presentationLevel === 'info' ? record.message : + null; + // 主プロセス�従���り「*���プロセス�ワーカー番��識別���。 + const worker = record.isPrimary ? '*' : record.workerId; + + let log = `${label} ${worker}\t[${contexts.join(' ')}]\t${message}`; + if (this.dependencies.withLogTime()) { + log = chalk.gray(dateFormat(new Date(record.timestamp), 'HH:mm:ss')) + ' ' + log; + } + + // `data`�文字列�埋�込���第2引数���渡�従��挙動を維����。 + const args: unknown[] = [important ? chalk.bold(log) : log]; + if (record.compatibility?.data != null) { + args.push(record.compatibility.data); + } + this.dependencies.output(...args); + } +} diff --git a/packages/backend/src/logging/logging-runtime.ts b/packages/backend/src/logging/logging-runtime.ts new file mode 100644 index 00000000000..79890ad4962 --- /dev/null +++ b/packages/backend/src/logging/logging-runtime.ts @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { LogManager } from './LogManager.js'; +import { PrettyConsoleBackend } from './PrettyConsoleBackend.js'; + +/** + * プロセス内�����Logger�共有�るLogManager��。 + * Logger作�後も��LogManagerを�照�る���出力先�切り替�を一括��映����。 + */ +export const logManager = new LogManager(new PrettyConsoleBackend()); diff --git a/packages/backend/src/logging/types.ts b/packages/backend/src/logging/types.ts new file mode 100644 index 00000000000..e65fd2195eb --- /dev/null +++ b/packages/backend/src/logging/types.ts @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { Keyword } from 'color-convert'; + +/** ログ���度を表���。 */ +export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; + +/** + * ロガー�を構��る一�素��。 + * 色�Pretty形���表示���使��ログ��味��影響����ん。 + */ +export type LoggerContext = { + readonly name: string; + readonly color?: Keyword; +}; + +/** + * 従��コンソール表示を維��る���情報��。 + * 構造化ログ�項目�混����よ��互�用�領域�分離�����。 + */ +export type LogCompatibility = { + readonly legacyLevel?: 'success'; + readonly important?: boolean; + readonly data?: Record | null; +}; + +/** + * 呼�出���らLogManager�渡��時刻��を付加�る��ログ��。 + */ +export type LogRecordInput = { + readonly level: LogLevel; + readonly message: string; + readonly context: readonly LoggerContext[]; + readonly compatibility?: LogCompatibility; +}; + +/** + * 出力先�渡�ログ��。 + * LogManager�時刻やプロセス情報を付加�る���出力形���存��利用����。 + */ +export type LogRecord = LogRecordInput & { + readonly timestamp: string; + readonly loggerName: string; + readonly processId: number; + readonly isPrimary: boolean; + readonly workerId: number | null; +}; diff --git a/packages/backend/test/unit/logging/LogManager.ts b/packages/backend/test/unit/logging/LogManager.ts new file mode 100644 index 00000000000..629be70d5cb --- /dev/null +++ b/packages/backend/test/unit/logging/LogManager.ts @@ -0,0 +1,125 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test, vi } from 'vitest'; +import { LogManager } from '@/logging/LogManager.js'; +import type { LogBackend } from '@/logging/LogBackend.js'; +import type { LogRecordInput } from '@/logging/types.js'; + +/** テスト�使�最�構��ログ入力を作����。 */ +function createInput(level: LogRecordInput['level'] = 'info'): LogRecordInput { + return { + level, + message: 'message', + context: [ + { name: 'queue', color: 'red' }, + { name: 'deliver', color: 'blue' }, + ], + }; +} + +/** 実行環境を固定��LogManager��出力確�用�関数を作����。 */ +function createManager(options: { + quiet?: boolean; + verbose?: boolean; + nodeEnv?: string; + isPrimary?: boolean; + workerId?: number | null; +} = {}) { + const write = vi.fn(); + const manager = new LogManager({ write }, { + now: () => new Date('2025-01-02T03:04:05.678Z'), + getProcessInfo: () => ({ + processId: 1234, + isPrimary: options.isPrimary ?? true, + workerId: options.workerId ?? null, + }), + isQuiet: () => options.quiet ?? false, + isVerbose: () => options.verbose ?? false, + getNodeEnv: () => options.nodeEnv ?? 'development', + }); + + return { manager, write }; +} + +describe('LogManager', () => { + test('adds logger and process metadata while preserving root-to-leaf context order', () => { + const { manager, write } = createManager(); + const input = createInput(); + + manager.write(input); + + expect(write).toHaveBeenCalledOnce(); + expect(write).toHaveBeenCalledWith({ + ...input, + context: [ + { name: 'queue', color: 'red' }, + { name: 'deliver', color: 'blue' }, + ], + timestamp: '2025-01-02T03:04:05.678Z', + loggerName: 'queue.deliver', + processId: 1234, + isPrimary: true, + workerId: null, + }); + expect(write.mock.calls[0][0].context).not.toBe(input.context); + }); + + test('records worker process metadata', () => { + const { manager, write } = createManager({ isPrimary: false, workerId: 7 }); + + manager.write(createInput()); + + expect(write.mock.calls[0][0]).toMatchObject({ + processId: 1234, + isPrimary: false, + workerId: 7, + }); + }); + + test('does not call the backend in quiet mode', () => { + const { manager, write } = createManager({ quiet: true, verbose: true }); + + manager.write(createInput('fatal')); + manager.write(createInput('debug')); + + expect(write).not.toHaveBeenCalled(); + }); + + test('writes debug logs outside production', () => { + const { manager, write } = createManager({ nodeEnv: 'development' }); + + manager.write(createInput('debug')); + + expect(write).toHaveBeenCalledOnce(); + }); + + test('suppresses debug logs in production by default', () => { + const { manager, write } = createManager({ nodeEnv: 'production' }); + + manager.write(createInput('debug')); + + expect(write).not.toHaveBeenCalled(); + }); + + test('writes debug logs in verbose production mode', () => { + const { manager, write } = createManager({ nodeEnv: 'production', verbose: true }); + + manager.write(createInput('debug')); + + expect(write).toHaveBeenCalledOnce(); + }); + + test('uses a replaced backend for subsequent records', () => { + const { manager, write } = createManager(); + const replacementWrite = vi.fn(); + + manager.setBackend({ write: replacementWrite }); + manager.write(createInput()); + + expect(write).not.toHaveBeenCalled(); + expect(replacementWrite).toHaveBeenCalledOnce(); + }); +}); diff --git a/packages/backend/test/unit/logging/Logger.ts b/packages/backend/test/unit/logging/Logger.ts new file mode 100644 index 00000000000..21fa84e5bf6 --- /dev/null +++ b/packages/backend/test/unit/logging/Logger.ts @@ -0,0 +1,103 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { beforeEach, describe, expect, test, vi } from 'vitest'; +import type { LogRecordInput } from '@/logging/types.js'; + +const mocks = vi.hoisted(() => ({ + write: vi.fn<(input: LogRecordInput) => void>(), +})); + +vi.mock('@/logging/logging-runtime.js', () => ({ + logManager: { + write: mocks.write, + }, +})); + +import Logger from '@/logger.js'; + +describe('Logger', () => { + beforeEach(() => { + mocks.write.mockReset(); + }); + + test('passes immutable multi-level root-to-leaf context to the manager', () => { + const root = new Logger('root', 'red'); + const child = root.createSubLogger('child', 'green'); + const leaf = child.createSubLogger('leaf', 'blue'); + + leaf.info('from leaf'); + root.info('from root'); + + expect(mocks.write.mock.calls[0][0]).toMatchObject({ + level: 'info', + message: 'from leaf', + context: [ + { name: 'root', color: 'red' }, + { name: 'child', color: 'green' }, + { name: 'leaf', color: 'blue' }, + ], + }); + expect(mocks.write.mock.calls[1][0].context).toEqual([ + { name: 'root', color: 'red' }, + ]); + }); + + test('maps succ to info with the legacy success presentation', () => { + new Logger('root').succ('completed', { count: 1 }, true); + + expect(mocks.write).toHaveBeenCalledWith({ + level: 'info', + message: 'completed', + context: [{ name: 'root', color: undefined }], + compatibility: { + legacyLevel: 'success', + important: true, + data: { count: 1 }, + }, + }); + }); + + test('uses Error.toString and adds the Error to existing data', () => { + const logger = new Logger('root'); + const error = new TypeError('broken'); + const data: Record = { requestId: 'request' }; + + logger.error(error, data, true); + + expect(data).toEqual({ requestId: 'request', e: error }); + expect(mocks.write).toHaveBeenCalledWith({ + level: 'error', + message: 'TypeError: broken', + context: [{ name: 'root', color: undefined }], + compatibility: { + legacyLevel: undefined, + important: true, + data, + }, + }); + }); + + test('creates data containing the Error when none is supplied', () => { + const error = new Error('broken'); + + new Logger('root').error(error); + + expect(mocks.write.mock.calls[0][0].compatibility?.data).toEqual({ e: error }); + }); + + test('keeps public methods bound when called separately', () => { + const logger = new Logger('root'); + const info = logger.info; + + info('bound'); + + expect(mocks.write).toHaveBeenCalledWith(expect.objectContaining({ + level: 'info', + message: 'bound', + context: [{ name: 'root', color: undefined }], + })); + }); +}); diff --git a/packages/backend/test/unit/logging/PrettyConsoleBackend.ts b/packages/backend/test/unit/logging/PrettyConsoleBackend.ts new file mode 100644 index 00000000000..512facbee09 --- /dev/null +++ b/packages/backend/test/unit/logging/PrettyConsoleBackend.ts @@ -0,0 +1,147 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test, vi } from 'vitest'; +import type { LogRecord } from '@/logging/types.js'; + +type Formatter = ((value: unknown) => string) & { white?: Formatter }; + +const chalkMock = vi.hoisted(() => { + const format = (name: string): Formatter => (value: unknown) => `<${name}>${String(value)}`; + const bgRed = format('bgRed'); + bgRed.white = format('bgRed.white'); + const bgGreen = format('bgGreen'); + bgGreen.white = format('bgGreen.white'); + + return { + red: format('red'), + yellow: format('yellow'), + green: format('green'), + gray: format('gray'), + blue: format('blue'), + white: format('white'), + bold: format('bold'), + bgRed, + bgGreen, + rgb: (red: number, green: number, blue: number) => format(`rgb:${red},${green},${blue}`), + }; +}); + +vi.mock('chalk', () => ({ + default: chalkMock, +})); + +import { PrettyConsoleBackend } from '@/logging/PrettyConsoleBackend.js'; + +/** Pretty形��テスト�使�共通�ログを作����。 */ +function createRecord(overrides: Partial = {}): LogRecord { + return { + level: 'info', + message: 'message', + context: [{ name: 'root' }], + timestamp: '2025-01-02T03:04:05.678Z', + loggerName: 'root', + processId: 1234, + isPrimary: true, + workerId: null, + ...overrides, + }; +} + +describe('PrettyConsoleBackend', () => { + test.each([ + { level: 'error', label: 'ERR ', message: 'message' }, + { level: 'warn', label: 'WARN', message: 'message' }, + { level: 'debug', label: 'VERB', message: 'message' }, + { level: 'info', label: 'INFO', message: 'message' }, + ] as const)('formats the $level label and message', ({ level, label, message }) => { + const output = vi.fn(); + const backend = new PrettyConsoleBackend({ output, withLogTime: () => false }); + + backend.write(createRecord({ level })); + + expect(output).toHaveBeenCalledWith(`${label} *\t[root]\t${message}`); + }); + + test('formats legacy success as DONE while retaining the info severity', () => { + const output = vi.fn(); + const backend = new PrettyConsoleBackend({ output, withLogTime: () => false }); + + backend.write(createRecord({ + level: 'info', + compatibility: { legacyLevel: 'success' }, + })); + + expect(output).toHaveBeenCalledWith('DONE *\t[root]\tmessage'); + }); + + test('formats contexts from root to leaf using their configured colors', () => { + const output = vi.fn(); + const backend = new PrettyConsoleBackend({ output, withLogTime: () => false }); + + backend.write(createRecord({ + context: [ + { name: 'root', color: 'red' }, + { name: 'child' }, + { name: 'leaf', color: 'blue' }, + ], + })); + + expect(output).toHaveBeenCalledWith('INFO *\t[root child leaf]\tmessage'); + }); + + test('prefixes the time derived from the record timestamp when enabled', () => { + const output = vi.fn(); + const backend = new PrettyConsoleBackend({ output, withLogTime: () => true }); + + backend.write(createRecord()); + + expect(output).toHaveBeenCalledWith('03:04:05 INFO *\t[root]\tmessage'); + }); + + test('uses the worker id for a worker process', () => { + const output = vi.fn(); + const backend = new PrettyConsoleBackend({ output, withLogTime: () => false }); + + backend.write(createRecord({ isPrimary: false, workerId: 7 })); + + expect(output).toHaveBeenCalledWith('INFO 7\t[root]\tmessage'); + }); + + test('bolds an important record and passes data as the second output argument', () => { + const output = vi.fn(); + const data = { detail: 'value' }; + const backend = new PrettyConsoleBackend({ output, withLogTime: () => false }); + + backend.write(createRecord({ + level: 'error', + compatibility: { important: true, data }, + })); + + expect(output).toHaveBeenCalledWith( + 'ERR *\t[root]\tmessage', + data, + ); + }); + + test('treats fatal records as important errors', () => { + const output = vi.fn(); + const backend = new PrettyConsoleBackend({ output, withLogTime: () => false }); + + backend.write(createRecord({ level: 'fatal' })); + + expect(output).toHaveBeenCalledWith('ERR *\t[root]\tmessage'); + }); + + test('omits null data from output arguments', () => { + const output = vi.fn(); + const backend = new PrettyConsoleBackend({ output, withLogTime: () => false }); + + backend.write(createRecord({ compatibility: { data: null } })); + + expect(output).toHaveBeenCalledTimes(1); + expect(output.mock.calls[0]).toHaveLength(1); + }); +}); From 1110d334c82827a647bace2441c0f25a9eacb7f0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 Jul 2026 04:36:32 +0000 Subject: [PATCH 349/578] Bump version to 2026.7.0-alpha.5 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 643035b384c..fd2253f431b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2026.7.0-alpha.4", + "version": "2026.7.0-alpha.5", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index af719499c56..eb61b1a81e1 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2026.7.0-alpha.4", + "version": "2026.7.0-alpha.5", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From ed70123ace31bb35a1b4bc33fd0e608d541649f5 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 19:12:33 +0900 Subject: [PATCH 350/578] Create .coderabbit.yaml --- .coderabbit.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 00000000000..be81490b64c --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,4 @@ +reviews: + auto_review: + base_branches: + - "develop" From 0849dc7cdd8286938aad705050f9b64ad187772f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:14:19 +0900 Subject: [PATCH 351/578] =?UTF-8?q?enhance:=20=E6=A7=8B=E9=80=A0=E5=8C=96?= =?UTF-8?q?=E3=83=AD=E3=82=B0API=E3=81=A8=E6=AD=A3=E8=A6=8F=E5=8C=96=20(#1?= =?UTF-8?q?7719)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance: 構造化ログAPI�正�化 * fix changelog * fixed copilot review * fixed coderabbit review --- CHANGELOG.md | 1 + packages/backend/src/logger.ts | 18 +- packages/backend/src/logging/LogManager.ts | 45 +- packages/backend/src/logging/LogNormalizer.ts | 386 ++++++++++++++++++ .../src/logging/PrettyConsoleBackend.ts | 10 +- packages/backend/src/logging/types.ts | 44 +- .../backend/src/server/api/ApiCallService.ts | 18 +- .../backend/test/unit/logging/LogManager.ts | 78 ++++ .../test/unit/logging/LogNormalizer.ts | 136 ++++++ packages/backend/test/unit/logging/Logger.ts | 17 + .../test/unit/logging/PrettyConsoleBackend.ts | 22 +- .../test/unit/server/ApiCallService.ts | 98 +++++ 12 files changed, 846 insertions(+), 27 deletions(-) create mode 100644 packages/backend/src/logging/LogNormalizer.ts create mode 100644 packages/backend/test/unit/logging/LogNormalizer.ts create mode 100644 packages/backend/test/unit/server/ApiCallService.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index bef208dbf69..d2cb4e8e40c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ - Enhance: Node.js 22.23.0以��24.17.0以��26.4.0以�をサ�ート�るよ�� - Enhance: Docker Image � Node.js を 26.4.0 ��Debian を trixie (v13) �更新 - Enhance: URLプレビュー��果を内部�キャッシュ�るよ�� +- Enhance: API内部エラー�ログ�構造化属性�正�化��エラー情報を付与���証情報を自動的�秘匿�るよ��(従�形��表示�維�) - Fix: `/stats` API �レス�ンス型�正�����題を修正 - Fix: �ッシュタグ�関連�るデータを更新�る際�エラー�ンドリングを修正 - Fix: Sentry 使用環境下���Misskey �発行�� SQL クエリ� span ���れ���題を修正 diff --git a/packages/backend/src/logger.ts b/packages/backend/src/logger.ts index c32b462cc03..8d58fd88d2d 100644 --- a/packages/backend/src/logger.ts +++ b/packages/backend/src/logger.ts @@ -5,7 +5,7 @@ import { bindThis } from '@/decorators.js'; import { logManager } from './logging/logging-runtime.js'; -import type { LogLevel, LoggerContext } from './logging/types.js'; +import type { LogLevel, LoggerContext, LogWriteInput } from './logging/types.js'; import type { Keyword } from 'color-convert'; /** @@ -38,11 +38,12 @@ export default class Logger { * 従�API�引数を共通形��変���LogManager�渡���。 */ @bindThis - private log(level: LogLevel, message: string, data?: Record | null, important = false, legacyLevel?: 'success'): void { + private log(level: LogLevel, message: string, data?: unknown, important = false, legacyLevel?: 'success', error?: unknown): void { logManager.write({ level, message, context: this.context, + ...(typeof error !== 'undefined' ? { error } : {}), compatibility: { legacyLevel, important, @@ -51,14 +52,23 @@ export default class Logger { }); } + /** 構造化ログをLogger�context付��LogManager�渡���。 */ + @bindThis + public write(input: LogWriteInput): void { + logManager.write({ + ...input, + context: this.context, + }); + } + /** 処�を継続����状�を記録���。 */ @bindThis public error(x: string | Error, data?: Record | null, important = false): void { if (x instanceof Error) { - // Error本体も第2引数�残��従���りスタック��を確���るよ�����。 + // エラー本体も第2引数�残��従���りスタック��を確���るよ�����。 data = data ?? {}; data.e = x; - this.log('error', x.toString(), data, important); + this.log('error', x.toString(), data, important, undefined, x); } else if (typeof x === 'object') { this.log('error', `${(x as any).message ?? (x as any).name ?? x}`, data, important); } else { diff --git a/packages/backend/src/logging/LogManager.ts b/packages/backend/src/logging/LogManager.ts index d31aac5dafe..6fef23d35f9 100644 --- a/packages/backend/src/logging/LogManager.ts +++ b/packages/backend/src/logging/LogManager.ts @@ -6,8 +6,14 @@ import cluster from 'node:cluster'; import process from 'node:process'; import { envOption } from '@/env.js'; +import { + findLegacyLogError, + normalizeLogAttributes, + serializeLogError, + type LogNormalizationProfile, +} from './LogNormalizer.js'; import type { LogBackend } from './LogBackend.js'; -import type { LogRecordInput } from './types.js'; +import type { LogRecord, LogRecordInput } from './types.js'; /** ログを出力��プロセスを識別�る���情報��。 */ export type LogProcessInfo = { @@ -28,6 +34,11 @@ export type LogManagerDependencies = { readonly getNodeEnv: () => string | undefined; }; +/** ログ管���期化時�指定��る正�化設定��。 */ +export type LogManagerOptions = { + readonly normalizationProfile?: LogNormalizationProfile; +}; + const defaultDependencies: LogManagerDependencies = { now: () => new Date(), getProcessInfo: () => ({ @@ -47,17 +58,23 @@ const defaultDependencies: LogManagerDependencies = { export class LogManager { private backend: LogBackend; private readonly dependencies: LogManagerDependencies; + private normalizationProfile: LogNormalizationProfile; /** * 出力先�実行環境�ら値を�得�る処�を���り��。 * 実行環境��得処���必��項目��テスト用�差�替�られ��。 */ - constructor(backend: LogBackend, dependencies: Partial = {}) { + constructor( + backend: LogBackend, + dependencies: Partial = {}, + options: LogManagerOptions = {}, + ) { this.backend = backend; this.dependencies = { ...defaultDependencies, ...dependencies, }; + this.normalizationProfile = options.normalizationProfile ?? 'standard'; } /** @@ -68,6 +85,11 @@ export class LogManager { this.backend = backend; } + /** 正�化方�を切り替��既�作�済��Logger�も�映���。 */ + public setNormalizationProfile(profile: LogNormalizationProfile): void { + this.normalizationProfile = profile; + } + /** * 出力�件を確���共通情報を付加��出力先�渡���。 */ @@ -81,14 +103,27 @@ export class LogManager { const processInfo = this.dependencies.getProcessInfo(); // 呼�出����列を共有���親�ら末端���順�を固定���。 const context = [...input.context]; - this.backend.write({ - ...input, + // 出力を実際�行�直����正�化����られるdebugログ�コストを抑���。 + const { attributes, error: inputError, ...inputWithoutStructuredValues } = input; + const normalizedAttributes = typeof attributes !== 'undefined' + ? normalizeLogAttributes(attributes, { profile: this.normalizationProfile }) + : undefined; + const error = inputError ?? findLegacyLogError(input.compatibility?.data); + const normalizedError = typeof error !== 'undefined' + ? serializeLogError(error, { profile: this.normalizationProfile }) + : undefined; + const record = { + ...inputWithoutStructuredValues, context, timestamp: this.dependencies.now().toISOString(), loggerName: context.map(segment => segment.name).join('.'), processId: processInfo.processId, isPrimary: processInfo.isPrimary, workerId: processInfo.workerId, - }); + ...(normalizedAttributes ? { attributes: normalizedAttributes } : {}), + ...(normalizedError ? { error: normalizedError } : {}), + } as LogRecord; + + this.backend.write(record); } } diff --git a/packages/backend/src/logging/LogNormalizer.ts b/packages/backend/src/logging/LogNormalizer.ts new file mode 100644 index 00000000000..aa3d1360a7b --- /dev/null +++ b/packages/backend/src/logging/LogNormalizer.ts @@ -0,0 +1,386 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Buffer } from 'node:buffer'; +import type { LogAttributeValue, LogAttributes, SerializedError } from './types.js'; + +/** 正�化�粒度を表���。詳細指定�も秘匿処��常�有効��。 */ +export type LogNormalizationProfile = 'standard' | 'detailed'; + +/** 正�化�使�上�値��。 */ +export type LogNormalizationLimits = { + readonly maxDepth: number; + readonly maxEntries: number; + readonly maxStringBytes: number; + readonly maxBytes: number; +}; + +/** 属性�キーを秘匿����判定�る関数��。 */ +export type LogRedactor = (path: readonly string[], key: string) => boolean; + +/** 正�化処��渡�設定��。 */ +export type LogNormalizationOptions = { + readonly profile?: LogNormalizationProfile; + readonly limits?: Partial; + readonly redactor?: LogRedactor; +}; + +/** 通常�用�ログ�肥大化���よ����上���。 */ +export const STANDARD_LOG_NORMALIZATION_LIMITS: LogNormalizationLimits = { + maxDepth: 6, + maxEntries: 100, + maxStringBytes: 8 * 1024, + maxBytes: 64 * 1024, +}; + +/** 障害調査時�より多��情報を残�上���。 */ +export const DETAILED_LOG_NORMALIZATION_LIMITS: LogNormalizationLimits = { + maxDepth: 10, + maxEntries: 1000, + maxStringBytes: 64 * 1024, + maxBytes: 256 * 1024, +}; + +const REDACTED = '[REDACTED]'; +const CIRCULAR = '[Circular]'; +const TRUNCATED = '[Truncated]'; +const UNSUPPORTED = '[Unsupported]'; +const TRUNCATED_KEY = '[Truncated]'; + +const sensitiveKeyParts = [ + 'password', + 'passwd', + 'passphrase', + 'token', + 'secret', + 'authorization', + 'cookie', + 'apikey', + 'privatekey', + 'credential', + 'hcaptcharesponse', + 'grecaptcharesponse', + 'turnstileresponse', + 'mcaptcharesponse', + 'testcaptcharesponse', +]; + +/** キー�を比較用����区切り文字�よる表記�れを�����。 */ +function normalizeKey(key: string): string { + return key.toLowerCase().replace(/[-_.\s]/g, ''); +} + +/** 既定�秘匿対象を判定���。Misskey API�`i`も�証情報���扱���。 */ +export function defaultLogRedactor(_path: readonly string[], key: string): boolean { + const normalized = normalizeKey(key); + return normalized === 'i' || sensitiveKeyParts.some(part => normalized.includes(part)); +} + +/** �択��方��個別指定を�����実際�上�値を決���。 */ +export function resolveLogNormalizationLimits(options: LogNormalizationOptions = {}): LogNormalizationLimits { + const base = options.profile === 'detailed' + ? DETAILED_LOG_NORMALIZATION_LIMITS + : STANDARD_LOG_NORMALIZATION_LIMITS; + const limits = { + ...base, + ...options.limits, + }; + return { + maxDepth: Math.max(0, limits.maxDepth), + maxEntries: Math.max(0, limits.maxEntries), + maxStringBytes: Math.max(1, limits.maxStringBytes), + maxBytes: Math.max(2, limits.maxBytes), + }; +} + +/** 値�通常�オブジェクト���読�る�判定���。 */ +function isObject(value: unknown): value is Record { + return typeof value === 'object' && value !== null; +} + +/** 外部入力�キーを安全�格��る���prototypeを����属性領域を作����。 */ +function createAttributeMap(): Record { + return Object.create(null) as Record; +} + +/** 値を文字列化��文字列化処�自体�例外もログ処���ら���よ�����。 */ +function stringifySafely(value: unknown): string { + try { + return String(value); + } catch { + return UNSUPPORTED; + } +} + +/** UTF-8��イト数を測り��。ログ�上�を文字数����出力サイズ���る���使���。 */ +function byteLength(value: string): number { + return Buffer.byteLength(value, 'utf8'); +} + +/** 文字列をUTF-8�上�内�切り詰���。 */ +function normalizeString(value: string, maxBytes: number): string { + if (byteLength(value) <= maxBytes) return value; + const suffix = `…${TRUNCATED}`; + if (byteLength(suffix) > maxBytes) { + const end = findMaxPrefixLength(value, '', maxBytes); + return value.slice(0, end); + } + const end = findMaxPrefixLength(value, suffix, maxBytes); + return value.slice(0, end) + suffix; +} + +/** 指定��後置文字列を���上����る接頭辞�長�を二分探索���。 */ +function findMaxPrefixLength(value: string, suffix: string, maxBytes: number): number { + let lower = 0; + let upper = value.length; + while (lower < upper) { + const middle = Math.ceil((lower + upper) / 2); + if (byteLength(value.slice(0, middle) + suffix) <= maxBytes) { + lower = middle; + } else { + upper = middle - 1; + } + } + // UTF-16�サロゲート対を途中�切ら��よ��必��ら1文字戻���。 + if (lower > 0 && lower < value.length) { + const code = value.charCodeAt(lower - 1); + if (code >= 0xd800 && code <= 0xdbff) lower--; + } + return lower; +} + +/** 特殊�値�対��も�エラー判定�例外を発生����よ�����。 */ +function isErrorValue(value: unknown): value is Error { + try { + return value instanceof Error; + } catch { + return false; + } +} + +/** 値�読�出�を安全�行��壊れ�ログ属性�本処�を中断���よ�����。 */ +function readProperty(value: Record, key: string): unknown { + try { + return value[key]; + } catch { + return `${UNSUPPORTED}: property access failed`; + } +} + +/** 属性をJSON�出力��る値�変����。 */ +function normalizeValue( + value: unknown, + path: readonly string[], + depth: number, + seen: WeakSet, + limits: LogNormalizationLimits, + redactor: LogRedactor, +): LogAttributeValue { + if (value === null) return null; + if (typeof value === 'string') return normalizeString(value, limits.maxStringBytes); + if (typeof value === 'boolean') return value; + if (typeof value === 'number') return Number.isFinite(value) ? value : stringifySafely(value); + if (typeof value === 'bigint') return value.toString(10); + if (typeof value === 'undefined') return `${UNSUPPORTED}: undefined`; + if (typeof value === 'function' || typeof value === 'symbol') return `${UNSUPPORTED}: ${typeof value}`; + let isArray = false; + try { + if (value instanceof Date) { + return normalizeString(value.toISOString(), limits.maxStringBytes); + } + isArray = Array.isArray(value); + if (!isArray) { + const prototype = Object.getPrototypeOf(value); + if (prototype !== Object.prototype && prototype !== null) return `${UNSUPPORTED}: object`; + } + } catch { + return `${UNSUPPORTED}: object access failed`; + } + if (seen.has(value)) return CIRCULAR; + if (depth >= limits.maxDepth) return TRUNCATED; + seen.add(value); + + try { + if (isArray) { + const arrayValue = value as readonly unknown[]; + const result: LogAttributeValue[] = []; + const entries = Math.min(arrayValue.length, limits.maxEntries); + for (let i = 0; i < entries; i++) { + result.push(normalizeValue(arrayValue[i], [...path, String(i)], depth + 1, seen, limits, redactor)); + } + if (arrayValue.length > entries) result.push(TRUNCATED); + return result; + } + + // 攻撃者�指定��`__proto__`を通常�属性������る���null prototypeを使���。 + const result = createAttributeMap(); + const keys = Object.keys(value).sort(); + const entries = Math.min(keys.length, limits.maxEntries); + for (let i = 0; i < entries; i++) { + const key = keys[i]; + // 秘匿対象�値を読�出���置����読�出�処�や巨大�値�も触れ��ん。 + result[key] = redactor(path, key) + ? REDACTED + : normalizeValue(readProperty(value as Record, key), [...path, key], depth + 1, seen, limits, redactor); + } + if (keys.length > entries) result[TRUNCATED_KEY] = TRUNCATED; + return result; + } catch { + return `${UNSUPPORTED}: object access failed`; + } finally { + seen.delete(value); + } +} + +/** JSON文字列化��値��イト数を測り��。正�化後�最終上��使���。 */ +function serializedByteLength(value: LogAttributeValue): number { + return byteLength(JSON.stringify(value)); +} + +/** 正�化済��値を上�内��帰的�縮���。 */ +function trimToByteLimit(value: LogAttributeValue, maxBytes: number): LogAttributeValue { + if (serializedByteLength(value) <= maxBytes) return value; + if (typeof value === 'string') return normalizeString(value, maxBytes); + if (Array.isArray(value)) { + const result: LogAttributeValue[] = []; + for (const item of value) { + const trimmedItem = trimToByteLimit(item, maxBytes); + const candidate = [...result, trimmedItem]; + if (serializedByteLength(candidate) > maxBytes) break; + result.push(trimmedItem); + } + if (result.length < value.length && serializedByteLength([...result, TRUNCATED]) <= maxBytes) result.push(TRUNCATED); + return result; + } + if (isObject(value)) { + // 上�調整中も`__proto__`を安全�属性���扱�るよ�����。 + const result = createAttributeMap(); + for (const key of Object.keys(value).sort()) { + const candidate = Object.assign(createAttributeMap(), result, { [key]: trimToByteLimit(value[key], maxBytes) }); + if (serializedByteLength(candidate) > maxBytes) break; + result[key] = candidate[key]; + } + if (Object.keys(result).length < Object.keys(value).length) { + const candidate = Object.assign(createAttributeMap(), result, { [TRUNCATED_KEY]: TRUNCATED }); + if (serializedByteLength(candidate) <= maxBytes) return candidate; + } + return result; + } + return TRUNCATED; +} + +/** エラーら��原因情報�を安全�判定���。特殊�値もログ処�を壊���ん。 */ +function isErrorLike(value: unknown): value is Record { + if (!isObject(value)) return false; + try { + return ['name', 'message', 'stack', 'cause'].some(key => key in value); + } catch { + return false; + } +} + +/** 属性をJSON�出力��るオブジェクト�正�化���。 */ +export function normalizeLogAttributes(value: unknown, options: LogNormalizationOptions = {}): LogAttributes { + const limits = resolveLogNormalizationLimits(options); + const redactor = options.redactor ?? defaultLogRedactor; + const normalized = normalizeValue(value, [], 0, new WeakSet(), limits, redactor); + const root = isObject(normalized) && !Array.isArray(normalized) ? normalized : { value: normalized }; + return trimToByteLimit(root as LogAttributes, limits.maxBytes) as LogAttributes; +} + +/** 旧API�data領域�ら�エラー本体を見���構造化��形�渡���。 */ +export function findLegacyLogError(value: unknown): unknown { + if (isErrorValue(value)) return value; + if (!isObject(value)) return undefined; + for (const key of ['e', 'err', 'error', 'stack']) { + const candidate = readProperty(value, key); + if (isErrorValue(candidate)) return candidate; + } + return undefined; +} + +/** エラー�原因情報を����一定�形�正�化���。 */ +function serializeErrorValue( + value: unknown, + depth: number, + seen: WeakSet, + limits: LogNormalizationLimits, + redactor: LogRedactor, +): SerializedError { + if (!isObject(value)) { + return { + type: value === null ? 'null' : typeof value, + message: normalizeString(stringifySafely(value), limits.maxStringBytes), + }; + } + if (seen.has(value)) return { type: 'CircularError', message: CIRCULAR }; + seen.add(value); + + try { + const name = readProperty(value, 'name'); + const message = readProperty(value, 'message'); + const stack = readProperty(value, 'stack'); + const cause = readProperty(value, 'cause'); + const constructor = readProperty(value, 'constructor'); + const constructorName = typeof constructor === 'function' || isObject(constructor) + ? readProperty(constructor as Record, 'name') + : undefined; + const type = normalizeString( + typeof name === 'string' && name.length > 0 + ? name + : typeof constructorName === 'string' && constructorName.length > 0 ? constructorName : 'Error', + limits.maxStringBytes, + ); + const result: { type: string; message: string; stack?: string; cause?: SerializedError | LogAttributeValue } = { + type, + message: normalizeString(typeof message === 'string' ? message : stringifySafely(value), limits.maxStringBytes), + }; + if (typeof stack === 'string') result.stack = normalizeString(stack, limits.maxStringBytes); + if (typeof cause !== 'undefined') { + result.cause = depth < limits.maxDepth + ? isErrorValue(cause) || isErrorLike(cause) + ? serializeErrorValue(cause, depth + 1, seen, limits, redactor) + : normalizeValue(cause, ['cause'], depth + 1, seen, limits, redactor) + : TRUNCATED; + } + return result; + } finally { + seen.delete(value); + } +} + +/** エラー�必須項目を残�����全体�出力サイズを上�内�縮���。 */ +function trimSerializedError(value: SerializedError, maxBytes: number): SerializedError { + const requiredLimit = Math.max(0, Math.floor((maxBytes - 24) / 2)); + const result: { type: string; message: string; stack?: string; cause?: SerializedError | LogAttributeValue } = { + type: normalizeString(value.type, requiredLimit), + message: normalizeString(value.message, requiredLimit), + }; + if (serializedByteLength(result as unknown as LogAttributeValue) > maxBytes) { + return { type: '', message: '' }; + } + if (value.stack != null) { + const candidate = { ...result, stack: value.stack }; + if (serializedByteLength(candidate as unknown as LogAttributeValue) <= maxBytes) result.stack = value.stack; + } + if (value.cause != null) { + const cause = typeof value.cause === 'object' + ? trimToByteLimit(value.cause as LogAttributeValue, maxBytes) + : value.cause; + const candidate = { ...result, cause }; + if (serializedByteLength(candidate as unknown as LogAttributeValue) <= maxBytes) result.cause = cause as SerializedError | LogAttributeValue; + } + return result; +} + +/** 任��エラー入力を�ログ�安全�埋�込�る形�変����。 */ +export function serializeLogError(value: unknown, options: LogNormalizationOptions = {}): SerializedError | undefined { + if (typeof value === 'undefined' || value === null) return undefined; + const limits = resolveLogNormalizationLimits(options); + // 必須項目を�む最��JSON形�ら��ら��場���上�を超���よ�出力���ん。 + if (limits.maxBytes < 24) return undefined; + const serialized = serializeErrorValue(value, 0, new WeakSet(), limits, options.redactor ?? defaultLogRedactor); + return trimSerializedError(serialized, limits.maxBytes); +} diff --git a/packages/backend/src/logging/PrettyConsoleBackend.ts b/packages/backend/src/logging/PrettyConsoleBackend.ts index 6af60e5efd0..6e9bc313e3f 100644 --- a/packages/backend/src/logging/PrettyConsoleBackend.ts +++ b/packages/backend/src/logging/PrettyConsoleBackend.ts @@ -10,7 +10,7 @@ import { envOption } from '@/env.js'; import type { LogBackend } from './LogBackend.js'; import type { LogRecord } from './types.js'; -/** Pretty形��出力処��外部�ら���る�存関係��。 */ +/** 見や��形��出力処��外部�ら���る�存関係��。 */ export type PrettyConsoleBackendDependencies = { readonly output: (...args: unknown[]) => void; readonly withLogTime: () => boolean; @@ -75,7 +75,15 @@ export class PrettyConsoleBackend implements LogBackend { // `data`�文字列�埋�込���第2引数���渡�従��挙動を維����。 const args: unknown[] = [important ? chalk.bold(log) : log]; if (record.compatibility?.data != null) { + // 旧形��値�����第2引数�渡��既存�表示�調査方法を����。 args.push(record.compatibility.data); + } else if (record.eventName != null || record.attributes != null || record.error != null) { + // 構造化ログ��専用�出力先����も調査情報を確���るよ�����。 + args.push({ + ...(record.eventName != null ? { eventName: record.eventName } : {}), + ...(record.attributes != null ? { attributes: record.attributes } : {}), + ...(record.error != null ? { error: record.error } : {}), + }); } this.dependencies.output(...args); } diff --git a/packages/backend/src/logging/types.ts b/packages/backend/src/logging/types.ts index e65fd2195eb..aa3b63edecd 100644 --- a/packages/backend/src/logging/types.ts +++ b/packages/backend/src/logging/types.ts @@ -8,9 +8,30 @@ import type { Keyword } from 'color-convert'; /** ログ���度を表���。 */ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; +/** 正�化後�ログ属性���扱�るJSON�値��。 */ +export type LogAttributeValue = + | string + | number + | boolean + | null + | readonly LogAttributeValue[] + | { readonly [key: string]: LogAttributeValue }; + +/** 正�化後�ログ属性��。 */ +export type LogAttributes = Readonly>; + +/** ロガー�呼�出���構造化ログ���指定�る入力��。 */ +export type LogWriteInput = { + readonly level: LogLevel; + readonly message: string; + readonly eventName?: string; + readonly attributes?: Readonly>; + readonly error?: unknown; +}; + /** * ロガー�を構��る一�素��。 - * 色�Pretty形���表示���使��ログ��味��影響����ん。 + * 色�見や��形���表示���使��ログ��味��影響����ん。 */ export type LoggerContext = { readonly name: string; @@ -20,31 +41,40 @@ export type LoggerContext = { /** * 従��コンソール表示を維��る���情報��。 * 構造化ログ�項目�混����よ��互�用�領域�分離�����。 + * `data`�従�表示を����正�化���秘匿�必��値�構造化属性�移���。 */ export type LogCompatibility = { readonly legacyLevel?: 'success'; readonly important?: boolean; - readonly data?: Record | null; + readonly data?: unknown; }; /** * 呼�出���らLogManager�渡��時刻��を付加�る��ログ��。 */ -export type LogRecordInput = { - readonly level: LogLevel; - readonly message: string; +export type LogRecordInput = LogWriteInput & { readonly context: readonly LoggerContext[]; readonly compatibility?: LogCompatibility; }; +/** エラーをJSON�出力�る���正�化��形��。 */ +export type SerializedError = { + readonly type: string; + readonly message: string; + readonly stack?: string; + readonly cause?: SerializedError | LogAttributeValue; +}; + /** * 出力先�渡�ログ��。 - * LogManager�時刻やプロセス情報を付加�る���出力形���存��利用����。 + * `compatibility.data`�見や��形����使�従�値��構造化��出力先�属性�エラーを利用���。 */ -export type LogRecord = LogRecordInput & { +export type LogRecord = Omit & { readonly timestamp: string; readonly loggerName: string; readonly processId: number; readonly isPrimary: boolean; readonly workerId: number | null; + readonly attributes?: LogAttributes; + readonly error?: SerializedError; }; diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts index 65b4abee05b..685c8a8ab37 100644 --- a/packages/backend/src/server/api/ApiCallService.ts +++ b/packages/backend/src/server/api/ApiCallService.ts @@ -110,15 +110,16 @@ export class ApiCallService implements OnApplicationShutdown { throw err; } else { const errId = randomUUID(); - this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, { - ep: ep.name, - ps: data, - e: { - message: err.message, - code: err.name, - stack: err.stack, - id: errId, + this.logger.write({ + level: 'error', + eventName: 'api.endpoint.failed', + message: `Internal error occurred in ${ep.name}: ${err.message}`, + attributes: { + 'api.endpoint': ep.name, + 'error.id': errId, + 'api.params': data, }, + error: err, }); this.telemetryService.captureMessage(`Internal error occurred in ${ep.name}: ${err.message}`, { @@ -126,7 +127,6 @@ export class ApiCallService implements OnApplicationShutdown { userId, extra: { ep: ep.name, - ps: data, e: { message: err.message, code: err.name, diff --git a/packages/backend/test/unit/logging/LogManager.ts b/packages/backend/test/unit/logging/LogManager.ts index 629be70d5cb..93290590336 100644 --- a/packages/backend/test/unit/logging/LogManager.ts +++ b/packages/backend/test/unit/logging/LogManager.ts @@ -27,6 +27,7 @@ function createManager(options: { nodeEnv?: string; isPrimary?: boolean; workerId?: number | null; + normalizationProfile?: 'standard' | 'detailed'; } = {}) { const write = vi.fn(); const manager = new LogManager({ write }, { @@ -39,6 +40,8 @@ function createManager(options: { isQuiet: () => options.quiet ?? false, isVerbose: () => options.verbose ?? false, getNodeEnv: () => options.nodeEnv ?? 'development', + }, { + normalizationProfile: options.normalizationProfile, }); return { manager, write }; @@ -122,4 +125,79 @@ describe('LogManager', () => { expect(write).not.toHaveBeenCalled(); expect(replacementWrite).toHaveBeenCalledOnce(); }); + + test('normalizes structured attributes and errors before writing', () => { + const { manager, write } = createManager(); + const error = new TypeError('broken'); + + manager.write({ + ...createInput('error'), + eventName: 'api.endpoint.failed', + attributes: { i: 'secret', safe: 'value' }, + error, + }); + + expect(write.mock.calls[0][0]).toMatchObject({ + eventName: 'api.endpoint.failed', + attributes: { i: '[REDACTED]', safe: 'value' }, + error: { type: 'TypeError', message: 'broken' }, + }); + }); + + test('does not pass raw structured values when normalization omits an error', () => { + const { manager, write } = createManager(); + + manager.write({ + ...createInput('error'), + attributes: { detail: 'value' }, + error: null, + }); + + expect(write.mock.calls[0][0].attributes).toEqual({ detail: 'value' }); + expect(write.mock.calls[0][0]).not.toHaveProperty('error'); + }); + + test('keeps legacy data for the pretty output while serializing its Error separately', () => { + const { manager, write } = createManager(); + const error = new Error('legacy failure'); + const data = { detail: 'legacy', e: error }; + + manager.write({ + ...createInput('error'), + compatibility: { data }, + }); + + expect(write.mock.calls[0][0].compatibility?.data).toBe(data); + expect(write.mock.calls[0][0]).toMatchObject({ + error: { type: 'Error', message: 'legacy failure' }, + }); + expect(write.mock.calls[0][0].attributes).toBeUndefined(); + }); + + test('supports the detailed normalization profile', () => { + const { manager, write } = createManager({ normalizationProfile: 'detailed' }); + + manager.write({ + ...createInput(), + attributes: { nested: { level1: { level2: { level3: { value: 'kept' } } } } }, + }); + + expect(write.mock.calls[0][0].attributes).toEqual({ + nested: { level1: { level2: { level3: { value: 'kept' } } } }, + }); + }); + + test('switches the normalization profile for existing loggers', () => { + const { manager, write } = createManager(); + const nested = { level1: { level2: { level3: { level4: { level5: { level6: { value: 'kept' } } } } } } }; + + manager.write({ ...createInput(), attributes: nested }); + manager.setNormalizationProfile('detailed'); + manager.write({ ...createInput(), attributes: nested }); + + expect(write.mock.calls[0][0].attributes).toMatchObject({ + level1: { level2: { level3: { level4: { level5: { level6: '[Truncated]' } } } } }, + }); + expect(write.mock.calls[1][0].attributes).toEqual(nested); + }); }); diff --git a/packages/backend/test/unit/logging/LogNormalizer.ts b/packages/backend/test/unit/logging/LogNormalizer.ts new file mode 100644 index 00000000000..642887d2251 --- /dev/null +++ b/packages/backend/test/unit/logging/LogNormalizer.ts @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test } from 'vitest'; +import { + findLegacyLogError, + normalizeLogAttributes, + serializeLogError, +} from '@/logging/LogNormalizer.js'; + +describe('LogNormalizer', () => { + test('normalizes common non-JSON values', () => { + expect(normalizeLogAttributes({ + date: new Date('2025-01-02T03:04:05.678Z'), + bigint: 123n, + infinity: Infinity, + undefinedValue: undefined, + })).toEqual({ + bigint: '123', + date: '2025-01-02T03:04:05.678Z', + infinity: 'Infinity', + undefinedValue: '[Unsupported]: undefined', + }); + }); + + test('marks unsupported objects and invalid dates without throwing', () => { + expect(normalizeLogAttributes({ + map: new Map([['key', 'value']]), + invalidDate: new Date('invalid'), + })).toEqual({ + invalidDate: '[Unsupported]: object access failed', + map: '[Unsupported]: object', + }); + }); + + test('preserves __proto__ as a normal attribute key', () => { + const value = JSON.parse('{"__proto__":{"nested":"value"},"large":"' + 'x'.repeat(100) + '"}') as Record; + const normalized = normalizeLogAttributes(value, { limits: { maxBytes: 64 } }); + + expect(Object.keys(normalized)).toContain('__proto__'); + expect(normalized['__proto__']).toEqual({ nested: 'value' }); + expect(Object.getPrototypeOf(normalized)).toBeNull(); + }); + + test('redacts sensitive fields recursively, including the Misskey i token', () => { + expect(normalizeLogAttributes({ + i: 'top-level-token', + request: { + Authorization: 'bearer-token', + password: 'password', + nested: [{ api_key: 'api-key' }], + }, + visible: 'value', + })).toEqual({ + i: '[REDACTED]', + request: { + Authorization: '[REDACTED]', + password: '[REDACTED]', + nested: [{ api_key: '[REDACTED]' }], + }, + visible: 'value', + }); + }); + + test('keeps cycles finite and marks depth and entry truncation', () => { + const cycle: Record = { value: 'ok' }; + cycle.self = cycle; + + expect(normalizeLogAttributes({ + cycle, + deep: { level1: { level2: { level3: 'value' } } }, + }, { + limits: { maxDepth: 2, maxEntries: 10 }, + })).toEqual({ + cycle: { self: '[Circular]', value: 'ok' }, + deep: { level1: '[Truncated]' }, + }); + expect(normalizeLogAttributes({ entries: { a: 1, b: 2, c: 3 } }, { limits: { maxEntries: 2 } })).toEqual({ + entries: { a: 1, b: 2, '[Truncated]': '[Truncated]' }, + }); + }); + + test('uses the detailed profile while retaining the redaction policy', () => { + const value = { level1: { level2: { level3: { level4: 'value' } } }, token: 'secret' }; + + expect(normalizeLogAttributes(value, { limits: { maxDepth: 3 } })).toMatchObject({ level1: { level2: { level3: '[Truncated]' } }, token: '[REDACTED]' }); + expect(normalizeLogAttributes(value, { profile: 'detailed' })).toEqual({ + level1: { level2: { level3: { level4: 'value' } } }, + token: '[REDACTED]', + }); + }); + + test('keeps normalized attributes within the configured byte limit', () => { + const normalized = normalizeLogAttributes({ first: 'a'.repeat(100), second: 'b'.repeat(100) }, { limits: { maxBytes: 32 } }); + + expect(Buffer.byteLength(JSON.stringify(normalized), 'utf8')).toBeLessThanOrEqual(32); + }); + + test('truncates long multibyte strings without splitting characters', () => { + const normalized = normalizeLogAttributes({ value: '😀'.repeat(100) }, { limits: { maxStringBytes: 16, maxBytes: 100 } }); + + expect(Buffer.byteLength(JSON.stringify(normalized.value), 'utf8')).toBeLessThanOrEqual(16); + expect(JSON.stringify(normalized.value)).not.toContain('�'); + }); + + test('serializes Error and its cause consistently', () => { + const cause = new Error('root cause'); + const error = new TypeError('outer error', { cause }); + + expect(serializeLogError(error)).toMatchObject({ + type: 'TypeError', + message: 'outer error', + cause: { + type: 'Error', + message: 'root cause', + }, + }); + }); + + test('keeps serialized Error output within its byte limit', () => { + const serialized = serializeLogError(new Error('a long message'), { limits: { maxBytes: 32 } }); + + expect(serialized).toBeDefined(); + expect(Buffer.byteLength(JSON.stringify(serialized), 'utf8')).toBeLessThanOrEqual(32); + expect(serializeLogError(new Error('message'), { limits: { maxBytes: 20 } })).toBeUndefined(); + }); + + test('finds Error values in legacy data', () => { + const error = new Error('legacy'); + + expect(findLegacyLogError({ e: error })).toBe(error); + expect(findLegacyLogError({ stack: 'not-an-error' })).toBeUndefined(); + }); +}); diff --git a/packages/backend/test/unit/logging/Logger.ts b/packages/backend/test/unit/logging/Logger.ts index 21fa84e5bf6..8cadbca592a 100644 --- a/packages/backend/test/unit/logging/Logger.ts +++ b/packages/backend/test/unit/logging/Logger.ts @@ -60,6 +60,22 @@ describe('Logger', () => { }); }); + test('supports structured log input while preserving the context hierarchy', () => { + new Logger('root').createSubLogger('child').write({ + level: 'error', + eventName: 'example.failed', + message: 'failed', + attributes: { id: 'id' }, + error: new Error('broken'), + }); + + expect(mocks.write).toHaveBeenCalledWith(expect.objectContaining({ + level: 'error', + eventName: 'example.failed', + context: [{ name: 'root', color: undefined }, { name: 'child', color: undefined }], + })); + }); + test('uses Error.toString and adds the Error to existing data', () => { const logger = new Logger('root'); const error = new TypeError('broken'); @@ -72,6 +88,7 @@ describe('Logger', () => { level: 'error', message: 'TypeError: broken', context: [{ name: 'root', color: undefined }], + error, compatibility: { legacyLevel: undefined, important: true, diff --git a/packages/backend/test/unit/logging/PrettyConsoleBackend.ts b/packages/backend/test/unit/logging/PrettyConsoleBackend.ts index 512facbee09..8002b0a3095 100644 --- a/packages/backend/test/unit/logging/PrettyConsoleBackend.ts +++ b/packages/backend/test/unit/logging/PrettyConsoleBackend.ts @@ -35,7 +35,7 @@ vi.mock('chalk', () => ({ import { PrettyConsoleBackend } from '@/logging/PrettyConsoleBackend.js'; -/** Pretty形��テスト�使�共通�ログを作����。 */ +/** 見や��形��テスト�使�共通�ログを作����。 */ function createRecord(overrides: Partial = {}): LogRecord { return { level: 'info', @@ -144,4 +144,24 @@ describe('PrettyConsoleBackend', () => { expect(output).toHaveBeenCalledTimes(1); expect(output.mock.calls[0]).toHaveLength(1); }); + + test('passes structured event details as normalized output data', () => { + const output = vi.fn(); + const backend = new PrettyConsoleBackend({ output, withLogTime: () => false }); + + backend.write(createRecord({ + eventName: 'api.endpoint.failed', + attributes: { 'api.endpoint': 'notes/show' }, + error: { type: 'TypeError', message: 'broken' }, + })); + + expect(output).toHaveBeenCalledWith( + 'INFO *\t[root]\tmessage', + { + eventName: 'api.endpoint.failed', + attributes: { 'api.endpoint': 'notes/show' }, + error: { type: 'TypeError', message: 'broken' }, + }, + ); + }); }); diff --git a/packages/backend/test/unit/server/ApiCallService.ts b/packages/backend/test/unit/server/ApiCallService.ts new file mode 100644 index 00000000000..6c1f5202072 --- /dev/null +++ b/packages/backend/test/unit/server/ApiCallService.ts @@ -0,0 +1,98 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test, vi } from 'vitest'; +import { ApiCallService } from '@/server/api/ApiCallService.js'; +import Logger from '@/logger.js'; +import { envOption } from '@/env.js'; +import { logManager } from '@/logging/logging-runtime.js'; +import { PrettyConsoleBackend } from '@/logging/PrettyConsoleBackend.js'; +import type { LogBackend } from '@/logging/LogBackend.js'; +import type { LogRecord } from '@/logging/types.js'; + +/** API失敗ログを確��る���最�Fastify応答を作����。 */ +function createReply() { + return { + code: vi.fn(), + header: vi.fn(), + send: vi.fn(), + }; +} + +/** APIサービス��存関係を最���仮実装�差�替���。 */ +function createService() { + const authenticateService = { + authenticate: vi.fn().mockResolvedValue([null, null]), + }; + const telemetryService = { + startSpan: vi.fn((_name: string, callback: () => unknown) => callback()), + captureMessage: vi.fn(), + }; + const apiLoggerService = { logger: new Logger('api') }; + + const service = new ApiCallService( + {} as never, + {} as never, + {} as never, + authenticateService as never, + {} as never, + {} as never, + apiLoggerService as never, + telemetryService as never, + ); + return { service, telemetryService }; +} + +describe('ApiCallService structured error logging', () => { + test('redacts API credentials and serializes the endpoint error', async () => { + const write = vi.fn(); + logManager.setBackend({ write }); + const previousQuiet = envOption.quiet; + envOption.quiet = false; + const { service, telemetryService } = createService(); + try { + const reply = createReply(); + const endpoint = { + name: 'notes/show', + meta: {}, + params: {}, + exec: vi.fn().mockRejectedValue(new TypeError('broken endpoint')), + }; + const request = { + method: 'POST', + body: { + i: 'native-token', + password: 'password', + options: { visible: true }, + }, + query: {}, + headers: {}, + ip: '127.0.0.1', + }; + + await service.handleRequest(endpoint as never, request as never, reply as never); + + const record = write.mock.calls[0][0] as LogRecord; + expect(record).toMatchObject({ + eventName: 'api.endpoint.failed', + attributes: { + 'api.endpoint': 'notes/show', + 'api.params': { + i: '[REDACTED]', + password: '[REDACTED]', + options: { visible: true }, + }, + }, + error: { type: 'TypeError', message: 'broken endpoint' }, + }); + expect(record.attributes?.['error.id']).toEqual(expect.any(String)); + expect(telemetryService.captureMessage.mock.calls[0][1].extra).not.toHaveProperty('ps'); + } finally { + service.dispose(); + envOption.quiet = previousQuiet; + logManager.setBackend(new PrettyConsoleBackend({ output: () => undefined })); + } + }); +}); From ce411817b4716755676610e8a60a0a43405b2ec4 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:44:18 +0900 Subject: [PATCH 352/578] Update .coderabbit.yaml --- .coderabbit.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index be81490b64c..ce726dd641e 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -1,4 +1,9 @@ reviews: + profile: "chill" + high_level_summary: false + poem: true auto_review: + enabled: true + drafts: false base_branches: - "develop" From d74a7a515cfaf2236ce9f777cf315e9842ad1894 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:46:42 +0900 Subject: [PATCH 353/578] docs: design generated chunk handling --- ...frontend-bundle-generated-chunks-design.md | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md diff --git a/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md b/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md new file mode 100644 index 00000000000..95e0de006bd --- /dev/null +++ b/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md @@ -0,0 +1,153 @@ +# Frontend bundle report: generated chunk handling + +## Background + +The frontend bundle report compares the Vite manifests produced for the pull request base and head builds. Chunks with a `src` value are currently identified by that source path. Chunks without `src` are identified by Rolldown's generated `name`. + +Generated names are not unique or stable identities. Multiple unrelated shared chunks can all be called `dist`, `esm`, `index`, or a similar path-derived name. The current collection logic stores those chunks in a `Map` under `chunk:`, so later entries overwrite earlier entries. This produces two problems: + +1. unrelated chunks can be compared as if they were the same chunk; and +2. overwritten chunks are omitted from the reported total. + +Individual size changes for these generated shared chunks are not sufficiently actionable to justify heuristic matching. + +## Goals + +- Never compare unrelated generated chunks as the same chunk. +- Keep generated chunks out of the individual chunk-diff rows. +- Preserve the contribution of every physical JavaScript chunk in totals. +- Show the aggregate size change of generated chunks so unexplained bundle growth remains visible. +- Apply the same rules to the full chunk report and the startup chunk report. +- Continue comparing source-backed chunks and intentionally named chunks. + +## Non-goals + +- Inferring chunk identity from module-set similarity. +- Preserving an `updated` relationship for every shared chunk after code splitting changes. +- Changing the frontend's code-splitting strategy or output filenames. +- Suppressing specific names such as `esm` or `dist` with a denylist. + +## Approaches considered + +### Denylist generated-looking names + +Exclude names such as `esm`, `dist`, `lib`, and `index`. + +This is not selected because Rolldown can generate many other names, and a denylist can also hide an intentionally named chunk. It would leave the underlying name collision and total-size bug in place. + +### Compare only stable identities and aggregate the rest + +Classify chunks by whether the report has a stable semantic identity. Source-backed chunks and explicitly supported manual chunk names remain individually comparable. All other generated chunks are retained as physical files but shown only as an aggregate. + +This is the selected approach. It removes false comparisons without introducing matching heuristics, and it keeps all bytes visible. + +### Match shared chunks by their module sets + +Use visualizer metadata to compare exact or similar sets of module IDs. + +This could retain more individual diffs, but splits, merges, dependency-version paths, and small module movements make the matching policy complex and potentially misleading. It can be added later if aggregate data proves insufficient. + +## Design + +### Separate physical chunks from comparable identities + +`collectReport` will no longer use a single map keyed by the comparison identity as its source of truth. It will collect every resolved JavaScript output file exactly once into a physical chunk collection. + +Each physical chunk contains: + +- its resolved relative output path; +- its byte size; +- its manifest key, when present; +- its display name; and +- an optional comparison key. + +The physical output path is used only for de-duplication within one build. It is not used to match changed chunks across builds. + +### Comparison-key classification + +A chunk receives a comparison key only in one of these cases: + +1. `chunk.src` is present: use `src:`. +2. `chunk.name` is in an explicit allowlist of intentionally stable manual chunks: use `named:`. + +The initial stable-name allowlist is: + +- `vue` +- `i18n` + +These names correspond to the explicit `codeSplitting.groups` configuration in `packages/frontend/vite.config.ts`. + +All other manifest chunks without `src`, including generated names such as `esm` and `dist`, receive no comparison key. JavaScript files found in the localized output directory but absent from the manifest also receive no comparison key. + +If a supposedly stable comparison key occurs more than once within one build, the report must not silently overwrite it. Collection will fail with a descriptive error because duplicate `src` or allowlisted manual names violate the assumptions required for a correct comparison. + +### Full chunk report + +The report computes three independent values: + +1. **Total:** the sum of every unique physical JavaScript chunk. +2. **Generated chunk aggregate:** the sum of chunks without a comparison key. +3. **Individual rows:** before/after comparisons for stable comparison keys only. + +The table starts with the existing `(total)` row. When either build contains generated chunks, it then includes one aggregate row such as: + +```text +(other generated chunks) +``` + +This row compares aggregate sizes, not individual chunk identities. Generated chunks do not participate in the updated/added/removed row counts. + +The report includes a short note stating how many generated chunks were grouped on each side. This makes the scope of the aggregate explicit without listing noisy filenames. + +### Startup chunk report + +Startup traversal continues to follow the entry chunk's static `imports`, but it records manifest keys or resolved physical file paths rather than generated comparison keys. This prevents two startup chunks named `dist` from collapsing into one. + +Startup totals include every unique physical startup chunk. Stable startup chunks receive individual rows, while startup chunks without stable identities contribute to the same `(other generated chunks)` aggregate row within the startup table. + +### Displayed filenames + +For an individually comparable chunk, the details should expose both filenames when they differ. A single before-side filename must not imply that the after size belongs to that same file. + +The display can use one filename when unchanged and `before → after` when the content-hashed filename differs. + +The generated aggregate row does not display an arbitrary representative filename. + +## Data flow + +1. Read each build's Vite manifest. +2. Resolve localized output files and collect unique physical chunks. +3. Attach optional stable comparison keys using the classification rules. +4. Traverse startup imports using manifest identities and map them to physical chunks. +5. Calculate full and startup totals from physical chunks. +6. Calculate generated aggregates from chunks without comparison keys. +7. Compare only unique stable keys for individual rows. +8. Render totals, generated aggregates, and stable rows. + +## Error handling + +- A manifest entry whose expected localized JavaScript file is absent remains a fatal report-generation error. +- Duplicate physical output paths are de-duplicated and counted once. +- Duplicate stable comparison keys fail with an error that includes the key and conflicting files. +- Missing or malformed manifest data remains fatal rather than producing a partial report. + +## Testing + +Add focused fixtures or pure-function tests covering: + +- two unrelated `dist` chunks are both counted in total and grouped into the generated aggregate; +- `dist` and `esm` chunks never produce individual comparison rows; +- source-backed chunks with the same `src` are reported as updated; +- source-backed additions and removals remain visible; +- allowlisted `vue` and `i18n` chunks remain individually comparable; +- duplicate stable keys produce a descriptive error instead of overwriting; +- full totals equal the sum of all unique physical chunks; +- startup totals include multiple same-name generated chunks exactly once each; +- generated aggregate changes do not affect the updated/added/removed summary counts; and +- differing before/after filenames are rendered without attributing both sizes to one file. + +Validation should include the focused tests and repository lint. No CHANGELOG entry is required because this changes developer-facing CI reporting rather than Misskey user behavior. + +## Future extension + +If aggregate generated-chunk data is later found insufficient, visualizer module metadata can support a separate opt-in analysis. That extension must preserve the physical-chunk accounting introduced here and must not reintroduce name-based identity. From 9076a4ecf33ad5a8854973d47baa62b1f89db6aa Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:56:56 +0900 Subject: [PATCH 354/578] docs: plan generated chunk reporting fix --- ...-07-15-frontend-bundle-generated-chunks.md | 661 ++++++++++++++++++ 1 file changed, 661 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-15-frontend-bundle-generated-chunks.md diff --git a/docs/superpowers/plans/2026-07-15-frontend-bundle-generated-chunks.md b/docs/superpowers/plans/2026-07-15-frontend-bundle-generated-chunks.md new file mode 100644 index 00000000000..6a58d5e322b --- /dev/null +++ b/docs/superpowers/plans/2026-07-15-frontend-bundle-generated-chunks.md @@ -0,0 +1,661 @@ +# Frontend Bundle Generated Chunks Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Prevent generated `esm`/`dist`-style chunks from being compared individually while retaining every JavaScript output file in full and startup totals. + +**Architecture:** Keep physical chunk accounting separate from stable before/after identities. Source-backed chunks and the explicit `vue`/`i18n` code-splitting groups remain individually comparable; all other generated chunks are grouped into one aggregate row. Exercise the report generator through filesystem fixtures so tests cover manifest parsing, localized file resolution, startup traversal, and Markdown rendering together. + +**Tech Stack:** Node.js 26.4, TypeScript `.mts` scripts with native type stripping, Node test runner, Vite manifest JSON, GitHub Actions. + +## Global Constraints + +- Never compare unrelated generated chunks as the same chunk. +- Keep generated chunks out of the individual chunk-diff rows. +- Preserve the contribution of every physical JavaScript chunk in totals. +- Show the aggregate size change of generated chunks so unexplained bundle growth remains visible. +- Apply the same rules to the full chunk report and the startup chunk report. +- Continue comparing source-backed chunks and intentionally named chunks. +- The only stable generated-name allowlist entries are `vue` and `i18n`. +- Do not infer chunk identity from module-set similarity. +- Do not change the frontend code-splitting strategy or output filenames. +- Do not suppress generated chunks with a name denylist. +- Do not manually edit locale files other than `locales/ja-JP.yml`; this change does not require any locale edit. +- New `.mts` files must include the repository SPDX header. +- This developer-facing report change does not require a `CHANGELOG.md` entry. + +## File Structure + +- Create `.github/scripts/frontend-js-size.test.mts`: end-to-end fixtures for manifest collection and Markdown output. +- Modify `.github/scripts/frontend-js-size.mts`: physical chunk collection, stable identity classification, generated aggregation, startup accounting, duplicate-key validation, and filename rendering. +- Modify `.github/workflows/lint.yml`: run the focused Node test whenever the report script or its utility changes. +- Reference `docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md`: approved behavior and non-goals; no implementation edit is required. + +--- + +### Task 1: Preserve all physical chunks and aggregate generated chunks + +**Files:** +- Create: `.github/scripts/frontend-js-size.test.mts` +- Modify: `.github/scripts/frontend-js-size.mts:39-134` +- Modify: `.github/scripts/frontend-js-size.mts:315-426` + +**Interfaces:** +- Consumes: Vite `manifest.json`, localized JavaScript files under `built/_frontend_vite_/ja-JP`, and the existing five CLI arguments of `frontend-js-size.mts`. +- Produces: `CollectedReport` with `chunks: FileEntry[]`, `comparableChunks: Record`, `chunksByManifestKey: Record`, and `startupFiles: string[]`; Markdown with `(total)` and `(other generated chunks)` rows. + +- [ ] **Step 1: Write the failing end-to-end test** + +Create `.github/scripts/frontend-js-size.test.mts` with this initial content: + +```ts +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import assert from 'node:assert/strict'; +import { promises as fs } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test, { type TestContext } from 'node:test'; +import * as util from './utility.mts'; + +type Manifest = Record; + +const repoDir = path.resolve(import.meta.dirname, '../..'); +const reportScript = path.join(repoDir, '.github/scripts/frontend-js-size.mts'); + +async function writeBuild(repo: string, manifest: Manifest, sizes: Record) { + const outDir = path.join(repo, 'built/_frontend_vite_'); + await fs.mkdir(path.join(outDir, 'ja-JP'), { recursive: true }); + await fs.writeFile(path.join(outDir, 'manifest.json'), JSON.stringify(manifest)); + for (const [file, size] of Object.entries(sizes)) { + const localizedFile = file.replace(/^scripts\//, ''); + const outputFile = path.join(outDir, 'ja-JP', localizedFile); + await fs.mkdir(path.dirname(outputFile), { recursive: true }); + await fs.writeFile(outputFile, Buffer.alloc(size)); + } +} + +async function runReport(t: TestContext, before: { manifest: Manifest; sizes: Record }, after: { manifest: Manifest; sizes: Record }) { + const root = await fs.mkdtemp(path.join(os.tmpdir(), 'frontend-js-size-')); + t.after(() => fs.rm(root, { recursive: true, force: true })); + const beforeDir = path.join(root, 'before'); + const afterDir = path.join(root, 'after'); + const beforeStats = path.join(root, 'before-stats.json'); + const afterStats = path.join(root, 'after-stats.json'); + const reportFile = path.join(root, 'report.md'); + await writeBuild(beforeDir, before.manifest, before.sizes); + await writeBuild(afterDir, after.manifest, after.sizes); + await fs.writeFile(beforeStats, '{}'); + await fs.writeFile(afterStats, '{}'); + await util.run(process.execPath, [reportScript, beforeDir, afterDir, beforeStats, afterStats, reportFile]); + return fs.readFile(reportFile, 'utf8'); +} + +function fixture(suffix: string, generatedName: string, sizes: { entry: number; generatedA: number; generatedB: number; vue: number; i18n: number }) { + const files = { + entry: `scripts/entry-${suffix}.js`, + generatedA: `scripts/generated-a-${suffix}.js`, + generatedB: `scripts/generated-b-${suffix}.js`, + vue: `scripts/vue-${suffix}.js`, + i18n: `scripts/i18n-${suffix}.js`, + }; + return { + manifest: { + 'src/_boot_.ts': { file: files.entry, src: 'src/_boot_.ts', name: 'entry', isEntry: true, imports: ['_generatedA', '_generatedB', '_vue', '_i18n'] }, + _generatedA: { file: files.generatedA, name: generatedName }, + _generatedB: { file: files.generatedB, name: generatedName }, + _vue: { file: files.vue, name: 'vue' }, + _i18n: { file: files.i18n, name: 'i18n' }, + }, + sizes: Object.fromEntries(Object.entries(files).map(([key, file]) => [file, sizes[key as keyof typeof sizes]])), + }; +} + +test('groups generated chunks while preserving full and startup totals', async t => { + const report = await runReport( + t, + fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + ); + + assert.match(report, /\| \(total\) \| 220 B \| 275 B \|/); + assert.equal(report.match(/\| \(other generated chunks\) \| 30 B \| 70 B \|/g)?.length, 2); + assert.equal(report.match(/_2 before \/ 2 after generated chunks are grouped\._/g)?.length, 2); + assert.doesNotMatch(report, /`(?:dist|esm)`<\/summary>/); + assert.match(report, /`src\/_boot_\.ts`<\/summary>/); + assert.match(report, /`vue`<\/summary>/); +}); +``` + +- [ ] **Step 2: Run the test and verify the current implementation fails** + +Run: + +```bash +node --test .github/scripts/frontend-js-size.test.mts +``` + +Expected: FAIL because `(total)` omits one of the duplicate generated-name chunks, no `(other generated chunks)` row exists, and an individual `dist` or `esm` row is rendered. + +- [ ] **Step 3: Replace name-based identity with physical accounting and stable classification** + +In `.github/scripts/frontend-js-size.mts`, replace `FileEntry`, `stableChunkKey`, `collectStartupKeys`, and `collectReport` with these structures and functions while retaining the existing `resolveBuiltFile` function: + +```ts +const stableNamedChunks = new Set(['vue', 'i18n']); + +type FileEntry = { + comparisonKey: string | null; + displayName: string; + file: string; + manifestKeys: string[]; + size: number; +}; + +type CollectedReport = { + manifest: Manifest; + chunks: FileEntry[]; + comparableChunks: Record; + chunksByManifestKey: Record; + startupFiles: string[]; +}; + +function stableChunkKey(chunk: Manifest[string]) { + if (chunk.src != null) return `src:${util.normalizePath(chunk.src)}`; + if (chunk.name != null && stableNamedChunks.has(chunk.name)) return `named:${chunk.name}`; + return null; +} + +function collectStartupManifestKeys(manifest: Manifest) { + const entryKey = findEntryKey(manifest); + const keys = new Set(); + if (entryKey == null) return keys; + + function visit(key: string) { + if (keys.has(key)) return; + const chunk = manifest[key]; + if (!chunk || !chunk.file?.endsWith('.js')) return; + keys.add(key); + for (const importKey of chunk.imports ?? []) visit(importKey); + } + + visit(entryKey); + return keys; +} + +async function collectReport(repoDir: string): Promise { + const outDir = path.join(repoDir, 'built/_frontend_vite_'); + const manifestPath = path.join(outDir, 'manifest.json'); + const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')) as Manifest; + const chunksByFile = new Map(); + const comparableChunks = new Map(); + const chunksByManifestKey = new Map(); + + for (const [manifestKey, chunk] of Object.entries(manifest)) { + if (!chunk.file?.endsWith('.js')) continue; + const builtFile = await resolveBuiltFile(outDir, chunk.file); + const comparisonKey = stableChunkKey(chunk); + let entry = chunksByFile.get(builtFile.relativePath); + if (entry == null) { + entry = { + comparisonKey, + displayName: chunk.src ?? chunk.name ?? manifestKey, + file: builtFile.relativePath, + manifestKeys: [manifestKey], + size: await util.fileSize(builtFile.absolutePath), + }; + chunksByFile.set(entry.file, entry); + } else if (entry.comparisonKey !== comparisonKey) { + throw new Error(`Conflicting identities for ${entry.file}`); + } else { + entry.manifestKeys.push(manifestKey); + } + chunksByManifestKey.set(manifestKey, entry); + if (comparisonKey != null) { + const existing = comparableChunks.get(comparisonKey); + if (existing != null && existing.file !== entry.file) { + throw new Error(`Duplicate stable chunk key "${comparisonKey}": ${existing.file}, ${entry.file}`); + } + comparableChunks.set(comparisonKey, entry); + } + } + + const localeDir = path.join(outDir, locale); + if (await util.fileExists(localeDir)) { + for await (const fullPath of util.traverseDirectory(localeDir)) { + if (!fullPath.endsWith('.js')) continue; + const relativePath = util.normalizePath(path.relative(outDir, fullPath)); + if (chunksByFile.has(relativePath)) continue; + chunksByFile.set(relativePath, { + comparisonKey: null, + displayName: relativePath, + file: relativePath, + manifestKeys: [], + size: await util.fileSize(fullPath), + }); + } + } + + const startupFiles = new Set(); + for (const manifestKey of collectStartupManifestKeys(manifest)) { + const entry = chunksByManifestKey.get(manifestKey); + if (entry != null) startupFiles.add(entry.file); + } + + return { + manifest, + chunks: [...chunksByFile.values()], + comparableChunks: Object.fromEntries(comparableChunks), + chunksByManifestKey: Object.fromEntries(chunksByManifestKey), + startupFiles: [...startupFiles], + }; +} +``` + +- [ ] **Step 4: Update comparison rows and table rendering** + +Change `getChunkComparisonRows` to consume comparable maps and retain both filenames: + +```ts +function getChunkComparisonRows(keys: string[], before: Record, after: Record) { + return keys.map(key => { + const beforeEntry = before[key]; + const afterEntry = after[key]; + const beforeSize = beforeEntry?.size ?? 0; + const afterSize = afterEntry?.size ?? 0; + return { + key, + name: entryDisplayName(beforeEntry ?? afterEntry), + beforeFile: beforeEntry?.file, + afterFile: afterEntry?.file, + beforeSize, + afterSize, + changeType: beforeEntry == null ? 'added' : afterEntry == null ? 'removed' : beforeSize !== afterSize ? 'updated' : 'unchanged', + sortSize: Math.max(beforeSize, afterSize), + }; + }); +} + +type ChunkAggregate = { + beforeSize: number; + afterSize: number; + beforeCount: number; + afterCount: number; +}; + +function sumChunkSizes(chunks: FileEntry[]) { + return chunks.reduce((sum, chunk) => sum + chunk.size, 0); +} + +function generatedAggregate(before: FileEntry[], after: FileEntry[]): ChunkAggregate { + const beforeGenerated = before.filter(chunk => chunk.comparisonKey == null); + const afterGenerated = after.filter(chunk => chunk.comparisonKey == null); + return { + beforeSize: sumChunkSizes(beforeGenerated), + afterSize: sumChunkSizes(afterGenerated), + beforeCount: beforeGenerated.length, + afterCount: afterGenerated.length, + }; +} + +function comparableMap(chunks: FileEntry[]) { + const entries: [string, FileEntry][] = []; + for (const chunk of chunks) { + if (chunk.comparisonKey != null) entries.push([chunk.comparisonKey, chunk]); + } + return Object.fromEntries(entries); +} +``` + +Replace `chunkMarkdownTable` with this version, which adds a third `generated` argument: + +```ts +function chunkMarkdownTable( + rows: ReturnType, + total?: { beforeSize: number; afterSize: number }, + generated?: ChunkAggregate, +) { + if (rows.length === 0 && total == null && generated == null) return '_No data_'; + + const lines = [ + '| Chunk | Before | After | Δ | Δ (%) |', + '| --- | ---: | ---: | ---: | ---: |', + ]; + let hasSummaryRow = false; + if (total != null) { + lines.push(`| (total) | ${util.formatBytes(total.beforeSize)} | ${util.formatBytes(total.afterSize)} | ${util.calcAndFormatDeltaBytes(total.beforeSize, total.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(total.beforeSize, total.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); + hasSummaryRow = true; + } + if (generated != null && (generated.beforeCount > 0 || generated.afterCount > 0)) { + lines.push(`| (other generated chunks) | ${util.formatBytes(generated.beforeSize)} | ${util.formatBytes(generated.afterSize)} | ${util.calcAndFormatDeltaBytes(generated.beforeSize, generated.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(generated.beforeSize, generated.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); + hasSummaryRow = true; + } + if (hasSummaryRow && rows.length > 0) lines.push('| | | | | |'); + + for (const row of rows) { + const chunkFile = row.beforeFile ?? row.afterFile ?? ''; + if (row.changeType === 'added') { + lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); + } else if (row.changeType === 'removed') { + lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{green}{\\text{( - )}}$ |`); + } else { + lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(row.beforeSize, row.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); + } + } + if (generated != null && (generated.beforeCount > 0 || generated.afterCount > 0)) { + lines.push(''); + lines.push(`_${generated.beforeCount} before / ${generated.afterCount} after generated chunks are grouped._`); + } + return lines.join('\n'); +} +``` + +Update `renderFrontendChunkReport` so the full report uses all physical chunks for totals, stable maps for rows, and unidentifiable chunks for the aggregate: + +```ts +const beforeComparable = before.comparableChunks; +const afterComparable = after.comparableChunks; +const allChunkKeys = [...new Set([...Object.keys(beforeComparable), ...Object.keys(afterComparable)])]; +const allComparisonRows = getChunkComparisonRows(allChunkKeys, beforeComparable, afterComparable); +const diffTotal = { + beforeSize: sumChunkSizes(before.chunks), + afterSize: sumChunkSizes(after.chunks), +}; +const diffGenerated = generatedAggregate(before.chunks, after.chunks); +``` + +For startup accounting, filter physical chunks by `startupFiles`, rebuild comparable maps from those filtered arrays, and calculate totals and aggregate from the filtered arrays: + +```ts +const beforeStartupFiles = new Set(before.startupFiles); +const afterStartupFiles = new Set(after.startupFiles); +const beforeStartupChunks = before.chunks.filter(chunk => beforeStartupFiles.has(chunk.file)); +const afterStartupChunks = after.chunks.filter(chunk => afterStartupFiles.has(chunk.file)); +const beforeStartupComparable = comparableMap(beforeStartupChunks); +const afterStartupComparable = comparableMap(afterStartupChunks); +const startupKeys = [...new Set([...Object.keys(beforeStartupComparable), ...Object.keys(afterStartupComparable)])]; +const startupComparisonRows = getChunkComparisonRows(startupKeys, beforeStartupComparable, afterStartupComparable); +const startupTotal = { + beforeSize: sumChunkSizes(beforeStartupChunks), + afterSize: sumChunkSizes(afterStartupChunks), +}; +const startupGenerated = generatedAggregate(beforeStartupChunks, afterStartupChunks); +``` + +Pass the aggregates with these exact calls: + +```ts +chunkMarkdownTable(diffRows, diffTotal, diffGenerated) +chunkMarkdownTable(startupRows, startupTotal, startupGenerated) +``` + +- [ ] **Step 5: Run the focused test and verify it passes** + +Run: + +```bash +node --test .github/scripts/frontend-js-size.test.mts +``` + +Expected: PASS with `1` test and `0` failures. The Markdown contains two aggregate rows because the fixture makes all chunks startup chunks as well as full-report chunks. + +- [ ] **Step 6: Commit the physical-accounting change** + +```bash +git add .github/scripts/frontend-js-size.mts .github/scripts/frontend-js-size.test.mts +git commit -m "fix(dev): aggregate generated frontend chunks" +``` + +--- + +### Task 2: Reject duplicate stable identities and render honest filenames + +**Files:** +- Modify: `.github/scripts/frontend-js-size.test.mts` +- Modify: `.github/scripts/frontend-js-size.mts:315-372` + +**Interfaces:** +- Consumes: the `Duplicate stable chunk key` validation and comparison rows produced in Task 1. +- Produces: a fatal diagnostic for duplicate `src`/allowlisted identities and a file label that renders `before → after` when hashes differ. + +- [ ] **Step 1: Add failing coverage for duplicate stable names and filename changes** + +Append these tests to `.github/scripts/frontend-js-size.test.mts`: + +```ts +test('fails instead of overwriting duplicate stable chunk keys', async t => { + const duplicateVue = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + duplicateVue.manifest._vueDuplicate = { file: 'scripts/vue-duplicate-before.js', name: 'vue' }; + duplicateVue.sizes['scripts/vue-duplicate-before.js'] = 60; + + await assert.rejects( + runReport(t, duplicateVue, fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 })), + /Duplicate stable chunk key "named:vue".*vue-before\.js.*vue-duplicate-before\.js/, + ); +}); + +test('shows both filenames for an updated stable chunk', async t => { + const report = await runReport( + t, + fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + ); + + assert.match(report, /`ja-JP\/entry-before\.js → ja-JP\/entry-after\.js`/); + assert.match(report, /`ja-JP\/vue-before\.js → ja-JP\/vue-after\.js`/); +}); +``` + +- [ ] **Step 2: Run the tests and confirm the filename test fails** + +Run: + +```bash +node --test .github/scripts/frontend-js-size.test.mts +``` + +Expected: the duplicate-key test passes using Task 1 validation, while `shows both filenames for an updated stable chunk` fails because the table still shows only one file. + +- [ ] **Step 3: Render both filenames without changing identity logic** + +Add this helper near `chunkMarkdownTable`: + +```ts +function chunkFileDisplay(row: ReturnType[number]) { + if (row.beforeFile == null) return row.afterFile ?? ''; + if (row.afterFile == null || row.beforeFile === row.afterFile) return row.beforeFile; + return `${row.beforeFile} → ${row.afterFile}`; +} +``` + +At the start of each `for (const row of rows)` iteration, compute: + +```ts +const chunkFile = chunkFileDisplay(row); +``` + +Replace every `${escapeCell(row.chunkFile)}` interpolation in the three row variants with `${escapeCell(chunkFile)}`. Do not display any representative filename on the aggregate row. + +- [ ] **Step 4: Run all focused tests** + +Run: + +```bash +node --test .github/scripts/frontend-js-size.test.mts +``` + +Expected: PASS with `3` tests and `0` failures. + +- [ ] **Step 5: Commit the validation and display behavior** + +```bash +git add .github/scripts/frontend-js-size.mts .github/scripts/frontend-js-size.test.mts +git commit -m "fix(dev): clarify frontend chunk comparisons" +``` + +--- + +### Task 3: Run the report regression test in CI + +**Files:** +- Modify: `.github/workflows/lint.yml:3-33` +- Modify: `.github/workflows/lint.yml:139` + +**Interfaces:** +- Consumes: `.github/scripts/frontend-js-size.test.mts` from Tasks 1 and 2. +- Produces: a `frontend-bundle-report-test` GitHub Actions job using the repository's `.node-version`. + +- [ ] **Step 1: Verify the focused test is not currently referenced by CI** + +Run: + +```bash +rg -n "frontend-js-size.test|frontend-bundle-report-test" .github/workflows +``` + +Expected: no matches. + +- [ ] **Step 2: Add report-script paths to both lint workflow filters** + +Under both `on.push.paths` and `on.pull_request.paths` in `.github/workflows/lint.yml`, add: + +```yaml + - .github/scripts/frontend-js-size*.mts + - .github/scripts/utility.mts +``` + +Keep `.github/workflows/lint.yml` itself in both filters. + +- [ ] **Step 3: Add a focused CI job** + +Append this job under `jobs` at the same level as `check-dts`: + +```yaml + frontend-bundle-report-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6.0.3 + - uses: actions/setup-node@v6.4.0 + with: + node-version-file: '.node-version' + - run: node --test .github/scripts/frontend-js-size.test.mts +``` + +This job intentionally does not depend on `pnpm_install` because the test and report generator use only Node built-ins and the local `utility.mts` module. + +- [ ] **Step 4: Run the exact CI test command locally** + +Run: + +```bash +node --test .github/scripts/frontend-js-size.test.mts +``` + +Expected: PASS with `3` tests and `0` failures. + +- [ ] **Step 5: Confirm CI now references the test exactly once** + +Run: + +```bash +rg -n "node --test \.github/scripts/frontend-js-size\.test\.mts" .github/workflows/lint.yml +``` + +Expected: one match in the `frontend-bundle-report-test` job. + +- [ ] **Step 6: Commit the CI coverage** + +```bash +git add .github/workflows/lint.yml +git commit -m "test(dev): check frontend bundle report" +``` + +--- + +### Task 4: Complete Misskey pre-ship validation + +**Files:** +- Verify: `.github/scripts/frontend-js-size.mts` +- Verify: `.github/scripts/frontend-js-size.test.mts` +- Verify: `.github/workflows/lint.yml` +- Verify: `docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md` + +**Interfaces:** +- Consumes: all implementation and CI changes from Tasks 1-3. +- Produces: fresh evidence that focused behavior, repository lint, SPDX, locale safety, and final diff checks pass. + +- [ ] **Step 1: Run the focused regression tests** + +Run: + +```bash +node --test .github/scripts/frontend-js-size.test.mts +``` + +Expected: PASS with `3` tests and `0` failures. + +- [ ] **Step 2: Run repository lint** + +Run: + +```bash +pnpm lint +``` + +Expected: exit code `0`. If an unrelated pre-existing failure occurs, record its exact command and output rather than claiming lint passed. + +- [ ] **Step 3: Check the new file's SPDX header** + +Run: + +```bash +rg -n "SPDX-FileCopyrightText: syuilo and misskey-project|SPDX-License-Identifier: AGPL-3.0-only" .github/scripts/frontend-js-size.test.mts +``` + +Expected: two matches, one for each required SPDX line. + +- [ ] **Step 4: Verify locale safety and unchanged migration/API surfaces** + +Run: + +```bash +git diff --name-only develop -- locales +git diff --name-only develop -- packages/backend/migration packages/backend/src packages/misskey-js/src/autogen +``` + +Expected: both commands produce no output. Therefore locale generation, migration checking, backend API review, and misskey-js regeneration are not applicable. + +- [ ] **Step 5: Verify the final diff and worktree** + +Run: + +```bash +git diff --check develop...HEAD +git status --short +git log --oneline develop..HEAD +``` + +Expected: `git diff --check` exits `0`, `git status --short` is empty, and the log contains the approved design commit plus the three implementation commits from this plan. + +- [ ] **Step 6: Review the final report behavior against the approved design** + +Confirm all of these from the focused test output and diff: + +```text +[x] Physical chunks are counted once by output path. +[x] Only src-backed, vue, and i18n chunks are individually compared. +[x] Generated chunks are aggregated in full and startup reports. +[x] Duplicate stable keys fail instead of overwriting. +[x] Updated stable rows show before and after filenames. +[x] No locale, migration, backend API, frontend Vue, or user-facing behavior changed. +[x] No CHANGELOG entry is needed. +``` From b6996a2766d0b853bbef7014bc64281855710b96 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:00:39 +0900 Subject: [PATCH 355/578] chore: ignore local worktrees --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index e975691b935..e1fdaa271ae 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,6 @@ vite.config.local-dev.ts.timestamp-* # Affinity *.af~lock~ + +# Local Git worktrees +/.worktrees/ From 945fd405786d8cbed98c69b5c5693e81d97d6795 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:15:17 +0900 Subject: [PATCH 356/578] fix(dev): aggregate generated frontend chunks --- .github/scripts/frontend-js-size.mts | 202 +++++++++++++++------- .github/scripts/frontend-js-size.test.mts | 85 +++++++++ 2 files changed, 226 insertions(+), 61 deletions(-) create mode 100644 .github/scripts/frontend-js-size.test.mts diff --git a/.github/scripts/frontend-js-size.mts b/.github/scripts/frontend-js-size.mts index 4d6dd0a0bc4..b4a61e659a5 100644 --- a/.github/scripts/frontend-js-size.mts +++ b/.github/scripts/frontend-js-size.mts @@ -40,13 +40,24 @@ function escapeCell(value: string) { type Manifest = Record; +const stableNamedChunks = new Set(['vue', 'i18n']); + type FileEntry = { - key: string; + comparisonKey: string | null; displayName: string; file: string; + manifestKeys: string[]; size: number; }; +type CollectedReport = { + manifest: Manifest; + chunks: FileEntry[]; + comparableChunks: Record; + chunksByManifestKey: Record; + startupFiles: string[]; +}; + function entryDisplayName(entry: FileEntry) { if (!entry) return ''; return entry.displayName || entry.file; @@ -60,11 +71,13 @@ function findEntryKey(manifest: Manifest) { ?? null; } -function stableChunkKey(manifestKey: string, chunk: Manifest[string]) { - return chunk.src ?? (chunk.name ? `chunk:${chunk.name}` : manifestKey); +function stableChunkKey(chunk: Manifest[string]) { + if (chunk.src != null) return `src:${util.normalizePath(chunk.src)}`; + if (chunk.name != null && stableNamedChunks.has(chunk.name)) return `named:${chunk.name}`; + return null; } -function collectStartupKeys(manifest: Manifest) { +function collectStartupManifestKeys(manifest: Manifest) { const entryKey = findEntryKey(manifest); const keys = new Set(); if (entryKey == null) return keys; @@ -73,10 +86,8 @@ function collectStartupKeys(manifest: Manifest) { if (keys.has(key)) return; const chunk = manifest[key]; if (!chunk || !chunk.file?.endsWith('.js')) return; - keys.add(stableChunkKey(key, chunk)); - for (const importKey of chunk.imports ?? []) { - visit(importKey); - } + keys.add(key); + for (const importKey of chunk.imports ?? []) visit(importKey); } visit(entryKey); @@ -102,26 +113,41 @@ async function resolveBuiltFile(outDir: string, file: string) { }; } -async function collectReport(repoDir: string) { +async function collectReport(repoDir: string): Promise { const outDir = path.join(repoDir, 'built/_frontend_vite_'); const manifestPath = path.join(outDir, 'manifest.json'); const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')) as Manifest; - const byKey = new Map(); - const byFile = new Set(); + const chunksByFile = new Map(); + const comparableChunks = new Map(); + const chunksByManifestKey = new Map(); - for (const [key, chunk] of Object.entries(manifest)) { + for (const [manifestKey, chunk] of Object.entries(manifest)) { if (!chunk.file?.endsWith('.js')) continue; const builtFile = await resolveBuiltFile(outDir, chunk.file); - const size = await util.fileSize(builtFile.absolutePath); - const stableKey = stableChunkKey(key, chunk); - const displayName = chunk.src ?? chunk.name ?? key; - byKey.set(stableKey, { - key: stableKey, - displayName, - file: builtFile.relativePath, - size, - }); - byFile.add(builtFile.relativePath); + const comparisonKey = stableChunkKey(chunk); + let entry = chunksByFile.get(builtFile.relativePath); + if (entry == null) { + entry = { + comparisonKey, + displayName: chunk.src ?? chunk.name ?? manifestKey, + file: builtFile.relativePath, + manifestKeys: [manifestKey], + size: await util.fileSize(builtFile.absolutePath), + }; + chunksByFile.set(entry.file, entry); + } else if (entry.comparisonKey !== comparisonKey) { + throw new Error(`Conflicting identities for ${entry.file}`); + } else { + entry.manifestKeys.push(manifestKey); + } + chunksByManifestKey.set(manifestKey, entry); + if (comparisonKey != null) { + const existing = comparableChunks.get(comparisonKey); + if (existing != null && existing.file !== entry.file) { + throw new Error(`Duplicate stable chunk key "${comparisonKey}": ${existing.file}, ${entry.file}`); + } + comparableChunks.set(comparisonKey, entry); + } } const localeDir = path.join(outDir, locale); @@ -129,21 +155,29 @@ async function collectReport(repoDir: string) { for await (const fullPath of util.traverseDirectory(localeDir)) { if (!fullPath.endsWith('.js')) continue; const relativePath = util.normalizePath(path.relative(outDir, fullPath)); - if (byFile.has(relativePath)) continue; - const size = await util.fileSize(fullPath); - byKey.set(relativePath, { - key: relativePath, + if (chunksByFile.has(relativePath)) continue; + chunksByFile.set(relativePath, { + comparisonKey: null, displayName: relativePath, file: relativePath, - size, + manifestKeys: [], + size: await util.fileSize(fullPath), }); } } + const startupFiles = new Set(); + for (const manifestKey of collectStartupManifestKeys(manifest)) { + const entry = chunksByManifestKey.get(manifestKey); + if (entry != null) startupFiles.add(entry.file); + } + return { manifest, - chunks: Object.fromEntries(byKey), - startupKeys: [...collectStartupKeys(manifest)], + chunks: [...chunksByFile.values()], + comparableChunks: Object.fromEntries(comparableChunks), + chunksByManifestKey: Object.fromEntries(chunksByManifestKey), + startupFiles: [...startupFiles], }; } @@ -312,16 +346,17 @@ function renderVisualizerSummaryTable(before: ReturnType>, after: Awaited>) { - return keys.map((key) => { - const beforeEntry = before.chunks[key]; - const afterEntry = after.chunks[key]; +function getChunkComparisonRows(keys: string[], before: Record, after: Record) { + return keys.map(key => { + const beforeEntry = before[key]; + const afterEntry = after[key]; const beforeSize = beforeEntry?.size ?? 0; const afterSize = afterEntry?.size ?? 0; return { key, name: entryDisplayName(beforeEntry ?? afterEntry), - chunkFile: beforeEntry?.file ?? afterEntry?.file, + beforeFile: beforeEntry?.file, + afterFile: afterEntry?.file, beforeSize, afterSize, changeType: beforeEntry == null ? 'added' : afterEntry == null ? 'removed' : beforeSize !== afterSize ? 'updated' : 'unchanged', @@ -330,6 +365,36 @@ function getChunkComparisonRows(keys: string[], before: Awaited sum + chunk.size, 0); +} + +function generatedAggregate(before: FileEntry[], after: FileEntry[]): ChunkAggregate { + const beforeGenerated = before.filter(chunk => chunk.comparisonKey == null); + const afterGenerated = after.filter(chunk => chunk.comparisonKey == null); + return { + beforeSize: sumChunkSizes(beforeGenerated), + afterSize: sumChunkSizes(afterGenerated), + beforeCount: beforeGenerated.length, + afterCount: afterGenerated.length, + }; +} + +function comparableMap(chunks: FileEntry[]) { + const entries: [string, FileEntry][] = []; + for (const chunk of chunks) { + if (chunk.comparisonKey != null) entries.push([chunk.comparisonKey, chunk]); + } + return Object.fromEntries(entries); +} + function summarizeChunkChanges(rows: ReturnType) { return { updated: rows.filter((row) => row.changeType === 'updated').length, @@ -349,60 +414,75 @@ function compareChunkComparisonRows(a: ReturnType || a.name.localeCompare(b.name); } -function chunkMarkdownTable(rows: ReturnType, total?: { beforeSize: number; afterSize: number }) { - if (rows.length === 0) return '_No data_'; +function chunkMarkdownTable( + rows: ReturnType, + total?: { beforeSize: number; afterSize: number }, + generated?: ChunkAggregate, +) { + if (rows.length === 0 && total == null && generated == null) return '_No data_'; const lines = [ '| Chunk | Before | After | Δ | Δ (%) |', '| --- | ---: | ---: | ---: | ---: |', ]; + let hasSummaryRow = false; if (total != null) { lines.push(`| (total) | ${util.formatBytes(total.beforeSize)} | ${util.formatBytes(total.afterSize)} | ${util.calcAndFormatDeltaBytes(total.beforeSize, total.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(total.beforeSize, total.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); - lines.push('| | | | | |'); + hasSummaryRow = true; + } + if (generated != null && (generated.beforeCount > 0 || generated.afterCount > 0)) { + lines.push(`| (other generated chunks) | ${util.formatBytes(generated.beforeSize)} | ${util.formatBytes(generated.afterSize)} | ${util.calcAndFormatDeltaBytes(generated.beforeSize, generated.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(generated.beforeSize, generated.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); + hasSummaryRow = true; } + if (hasSummaryRow && rows.length > 0) lines.push('| | | | | |'); + for (const row of rows) { + const chunkFile = row.beforeFile ?? row.afterFile ?? ''; if (row.changeType === 'added') { - lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(row.chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); + lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); } else if (row.changeType === 'removed') { - lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(row.chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{green}{\\text{( - )}}$ |`); + lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{green}{\\text{( - )}}$ |`); } else { - lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(row.chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(row.beforeSize, row.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); + lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(row.beforeSize, row.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); } } + if (generated != null && (generated.beforeCount > 0 || generated.afterCount > 0)) { + lines.push(''); + lines.push(`_${generated.beforeCount} before / ${generated.afterCount} after generated chunks are grouped._`); + } return lines.join('\n'); } function renderFrontendChunkReport(before: Awaited>, after: Awaited>) { - const commonChunkKeys = Object.keys(before.chunks).filter((key) => after.chunks[key] != null); - const addedChunkKeys = Object.keys(after.chunks).filter((key) => before.chunks[key] == null); - const removedChunkKeys = Object.keys(before.chunks).filter((key) => after.chunks[key] == null); - const allChunkKeys = [ - ...commonChunkKeys, - ...addedChunkKeys, - ...removedChunkKeys, - ]; - //const comparisonRows = getChunkComparisonRows(commonChunkKeys, before, after); - const allComparisonRows = getChunkComparisonRows(allChunkKeys, before, after); + const beforeComparable = before.comparableChunks; + const afterComparable = after.comparableChunks; + const allChunkKeys = [...new Set([...Object.keys(beforeComparable), ...Object.keys(afterComparable)])]; + const allComparisonRows = getChunkComparisonRows(allChunkKeys, beforeComparable, afterComparable); const changedRows = allComparisonRows.filter((row) => row.changeType !== 'unchanged'); const diffSummary = summarizeChunkChanges(changedRows); const diffTotal = { - beforeSize: allComparisonRows.reduce((sum, row) => sum + row.beforeSize, 0), - afterSize: allComparisonRows.reduce((sum, row) => sum + row.afterSize, 0), + beforeSize: sumChunkSizes(before.chunks), + afterSize: sumChunkSizes(after.chunks), }; + const diffGenerated = generatedAggregate(before.chunks, after.chunks); const diffRows = changedRows.sort(compareChunkComparisonRows).slice(0, 30); // TODO: 実際�30を超��切り��られ�row����場����旨をmarkdown内�表示�るよ���る - const startupKeys = new Set([ - ...before.startupKeys, - ...after.startupKeys, - ]); - const startupComparisonRows = getChunkComparisonRows([...startupKeys], before, after); + const beforeStartupFiles = new Set(before.startupFiles); + const afterStartupFiles = new Set(after.startupFiles); + const beforeStartupChunks = before.chunks.filter(chunk => beforeStartupFiles.has(chunk.file)); + const afterStartupChunks = after.chunks.filter(chunk => afterStartupFiles.has(chunk.file)); + const beforeStartupComparable = comparableMap(beforeStartupChunks); + const afterStartupComparable = comparableMap(afterStartupChunks); + const startupKeys = [...new Set([...Object.keys(beforeStartupComparable), ...Object.keys(afterStartupComparable)])]; + const startupComparisonRows = getChunkComparisonRows(startupKeys, beforeStartupComparable, afterStartupComparable); const startupRows = startupComparisonRows.sort(compareChunkComparisonRows); const startupSummary = summarizeChunkChanges(startupComparisonRows); const startupTotal = { - beforeSize: startupComparisonRows.reduce((sum, row) => sum + row.beforeSize, 0), - afterSize: startupComparisonRows.reduce((sum, row) => sum + row.afterSize, 0), + beforeSize: sumChunkSizes(beforeStartupChunks), + afterSize: sumChunkSizes(afterStartupChunks), }; + const startupGenerated = generatedAggregate(beforeStartupChunks, afterStartupChunks); //const largeRows = comparisonRows // .sort((a, b) => b.sortSize - a.sortSize || a.name.localeCompare(b.name)) @@ -412,14 +492,14 @@ function renderFrontendChunkReport(before: Awaited', `${formatChunkChangeSummary('Chunk size diff', diffSummary)}`, '', - chunkMarkdownTable(diffRows, diffTotal), + chunkMarkdownTable(diffRows, diffTotal, diffGenerated), '', '', '', '
', `${formatChunkChangeSummary('Startup chunk size', startupSummary)}`, '', - chunkMarkdownTable(startupRows, startupTotal), + chunkMarkdownTable(startupRows, startupTotal, startupGenerated), '', `_Startup chunks are the Vite entry for \`src/_boot_.ts\` and its static imports._`, '', diff --git a/.github/scripts/frontend-js-size.test.mts b/.github/scripts/frontend-js-size.test.mts new file mode 100644 index 00000000000..51b71c075f0 --- /dev/null +++ b/.github/scripts/frontend-js-size.test.mts @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import assert from 'node:assert/strict'; +import { promises as fs } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test, { type TestContext } from 'node:test'; +import * as util from './utility.mts'; + +type Manifest = Record; + +const repoDir = path.resolve(import.meta.dirname, '../..'); +const reportScript = path.join(repoDir, '.github/scripts/frontend-js-size.mts'); + +async function writeBuild(repo: string, manifest: Manifest, sizes: Record) { + const outDir = path.join(repo, 'built/_frontend_vite_/'); + await fs.mkdir(path.join(outDir, 'ja-JP'), { recursive: true }); + await fs.writeFile(path.join(outDir, 'manifest.json'), JSON.stringify(manifest)); + for (const [file, size] of Object.entries(sizes)) { + const localizedFile = file.replace(/^scripts\//, ''); + const outputFile = path.join(outDir, 'ja-JP', localizedFile); + await fs.mkdir(path.dirname(outputFile), { recursive: true }); + await fs.writeFile(outputFile, Buffer.alloc(size)); + } +} + +async function runReport(t: TestContext, before: { manifest: Manifest; sizes: Record }, after: { manifest: Manifest; sizes: Record }) { + const root = await fs.mkdtemp(path.join(os.tmpdir(), 'frontend-js-size-')); + t.after(() => fs.rm(root, { recursive: true, force: true })); + const beforeDir = path.join(root, 'before'); + const afterDir = path.join(root, 'after'); + const beforeStats = path.join(root, 'before-stats.json'); + const afterStats = path.join(root, 'after-stats.json'); + const reportFile = path.join(root, 'report.md'); + await writeBuild(beforeDir, before.manifest, before.sizes); + await writeBuild(afterDir, after.manifest, after.sizes); + await fs.writeFile(beforeStats, '{}'); + await fs.writeFile(afterStats, '{}'); + await util.run(process.execPath, [reportScript, beforeDir, afterDir, beforeStats, afterStats, reportFile]); + return fs.readFile(reportFile, 'utf8'); +} + +function fixture(suffix: string, generatedName: string, sizes: { entry: number; generatedA: number; generatedB: number; vue: number; i18n: number }) { + const files = { + entry: `scripts/entry-${suffix}.js`, + generatedA: `scripts/generated-a-${suffix}.js`, + generatedB: `scripts/generated-b-${suffix}.js`, + vue: `scripts/vue-${suffix}.js`, + i18n: `scripts/i18n-${suffix}.js`, + }; + return { + manifest: { + 'src/_boot_.ts': { file: files.entry, src: 'src/_boot_.ts', name: 'entry', isEntry: true, imports: ['_generatedA', '_generatedB', '_vue', '_i18n'] }, + _generatedA: { file: files.generatedA, name: generatedName }, + _generatedB: { file: files.generatedB, name: generatedName }, + _vue: { file: files.vue, name: 'vue' }, + _i18n: { file: files.i18n, name: 'i18n' }, + }, + sizes: Object.fromEntries(Object.entries(files).map(([key, file]) => [file, sizes[key as keyof typeof sizes]])), + }; +} + +test('groups generated chunks while preserving full and startup totals', async t => { + const report = await runReport( + t, + fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + ); + + assert.match(report, /\| \(total\) \| 220 B \| 275 B \|/); + assert.equal(report.match(/\| \(other generated chunks\) \| 30 B \| 70 B \|/g)?.length, 2); + assert.equal(report.match(/_2 before \/ 2 after generated chunks are grouped\._/g)?.length, 2); + assert.doesNotMatch(report, /`(?:dist|esm)`<\/summary>/); + assert.match(report, /`src\/_boot_\.ts`<\/summary>/); + assert.match(report, /`vue`<\/summary>/); +}); From afca066833c5844e24cfe3b6eb0d1c97d216facf Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:22:28 +0900 Subject: [PATCH 357/578] fix(dev): clarify frontend chunk comparisons --- .github/scripts/frontend-js-size.mts | 8 +++++++- .github/scripts/frontend-js-size.test.mts | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/.github/scripts/frontend-js-size.mts b/.github/scripts/frontend-js-size.mts index b4a61e659a5..38c6fa07e91 100644 --- a/.github/scripts/frontend-js-size.mts +++ b/.github/scripts/frontend-js-size.mts @@ -414,6 +414,12 @@ function compareChunkComparisonRows(a: ReturnType || a.name.localeCompare(b.name); } +function chunkFileDisplay(row: ReturnType[number]) { + if (row.beforeFile == null) return row.afterFile ?? ''; + if (row.afterFile == null || row.beforeFile === row.afterFile) return row.beforeFile; + return `${row.beforeFile} → ${row.afterFile}`; +} + function chunkMarkdownTable( rows: ReturnType, total?: { beforeSize: number; afterSize: number }, @@ -437,7 +443,7 @@ function chunkMarkdownTable( if (hasSummaryRow && rows.length > 0) lines.push('| | | | | |'); for (const row of rows) { - const chunkFile = row.beforeFile ?? row.afterFile ?? ''; + const chunkFile = chunkFileDisplay(row); if (row.changeType === 'added') { lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); } else if (row.changeType === 'removed') { diff --git a/.github/scripts/frontend-js-size.test.mts b/.github/scripts/frontend-js-size.test.mts index 51b71c075f0..3688948e94c 100644 --- a/.github/scripts/frontend-js-size.test.mts +++ b/.github/scripts/frontend-js-size.test.mts @@ -83,3 +83,25 @@ test('groups generated chunks while preserving full and startup totals', async t assert.match(report, /`src\/_boot_\.ts`<\/summary>/); assert.match(report, /`vue`<\/summary>/); }); + +test('fails instead of overwriting duplicate stable chunk keys', async t => { + const duplicateVue = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + duplicateVue.manifest._vueDuplicate = { file: 'scripts/vue-duplicate-before.js', name: 'vue' }; + duplicateVue.sizes['scripts/vue-duplicate-before.js'] = 60; + + await assert.rejects( + runReport(t, duplicateVue, fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 })), + /Duplicate stable chunk key "named:vue".*vue-before\.js.*vue-duplicate-before\.js/, + ); +}); + +test('shows both filenames for an updated stable chunk', async t => { + const report = await runReport( + t, + fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + ); + + assert.match(report, /`ja-JP\/entry-before\.js → ja-JP\/entry-after\.js`/); + assert.match(report, /`ja-JP\/vue-before\.js → ja-JP\/vue-after\.js`/); +}); From 11c6fb1567a31e3eadb81879fb1f735a9465c652 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:29:01 +0900 Subject: [PATCH 358/578] test(dev): capture expected frontend report failures --- .github/scripts/frontend-js-size.test.mts | 26 ++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/scripts/frontend-js-size.test.mts b/.github/scripts/frontend-js-size.test.mts index 3688948e94c..d89fa153ba1 100644 --- a/.github/scripts/frontend-js-size.test.mts +++ b/.github/scripts/frontend-js-size.test.mts @@ -4,6 +4,7 @@ */ import assert from 'node:assert/strict'; +import { execFile } from 'node:child_process'; import { promises as fs } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; @@ -33,7 +34,7 @@ async function writeBuild(repo: string, manifest: Manifest, sizes: Record }, after: { manifest: Manifest; sizes: Record }) { +async function runReport(t: TestContext, before: { manifest: Manifest; sizes: Record }, after: { manifest: Manifest; sizes: Record }, expectFailure = false) { const root = await fs.mkdtemp(path.join(os.tmpdir(), 'frontend-js-size-')); t.after(() => fs.rm(root, { recursive: true, force: true })); const beforeDir = path.join(root, 'before'); @@ -45,7 +46,19 @@ async function runReport(t: TestContext, before: { manifest: Manifest; sizes: Re await writeBuild(afterDir, after.manifest, after.sizes); await fs.writeFile(beforeStats, '{}'); await fs.writeFile(afterStats, '{}'); - await util.run(process.execPath, [reportScript, beforeDir, afterDir, beforeStats, afterStats, reportFile]); + const args = [reportScript, beforeDir, afterDir, beforeStats, afterStats, reportFile]; + if (expectFailure) { + return new Promise((resolve, reject) => { + execFile(process.execPath, args, (error, _stdout, stderr) => { + if (error == null) { + reject(new Error('Expected frontend report script to fail')); + } else { + resolve(stderr); + } + }); + }); + } + await util.run(process.execPath, args); return fs.readFile(reportFile, 'utf8'); } @@ -89,10 +102,13 @@ test('fails instead of overwriting duplicate stable chunk keys', async t => { duplicateVue.manifest._vueDuplicate = { file: 'scripts/vue-duplicate-before.js', name: 'vue' }; duplicateVue.sizes['scripts/vue-duplicate-before.js'] = 60; - await assert.rejects( - runReport(t, duplicateVue, fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 })), - /Duplicate stable chunk key "named:vue".*vue-before\.js.*vue-duplicate-before\.js/, + const diagnostic = await runReport( + t, + duplicateVue, + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + true, ); + assert.match(diagnostic, /Duplicate stable chunk key "named:vue".*vue-before\.js.*vue-duplicate-before\.js/); }); test('shows both filenames for an updated stable chunk', async t => { From 0ad72528da904e48a0da00556bfffead87c66b92 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:34:13 +0900 Subject: [PATCH 359/578] test(dev): check frontend bundle report --- .github/workflows/lint.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 63ae5c7397a..d3c745aea6d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,6 +18,8 @@ on: - packages/misskey-reversi/** - packages/shared/eslint.config.js - scripts/check-dts*.mjs + - .github/scripts/frontend-js-size*.mts + - .github/scripts/utility.mts - .github/workflows/lint.yml - package.json pull_request: @@ -34,6 +36,8 @@ on: - packages/misskey-reversi/** - packages/shared/eslint.config.js - scripts/check-dts*.mjs + - .github/scripts/frontend-js-size*.mts + - .github/scripts/utility.mts - .github/workflows/lint.yml - package.json jobs: @@ -136,3 +140,12 @@ jobs: - run: pnpm i --frozen-lockfile - run: node --test scripts/check-dts.test.mjs - run: pnpm check-dts + + frontend-bundle-report-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6.0.3 + - uses: actions/setup-node@v6.4.0 + with: + node-version-file: '.node-version' + - run: node --test .github/scripts/frontend-js-size.test.mts From ef852e6ab0351f4c9ed0d7e8c33e8cd9098536e2 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:55:12 +0900 Subject: [PATCH 360/578] fix(dev): validate frontend startup manifest --- .github/scripts/frontend-js-size.mts | 11 +- .github/scripts/frontend-js-size.test.mts | 112 ++- .gitignore | 3 - ...-07-15-frontend-bundle-generated-chunks.md | 661 ------------------ 4 files changed, 118 insertions(+), 669 deletions(-) delete mode 100644 docs/superpowers/plans/2026-07-15-frontend-bundle-generated-chunks.md diff --git a/.github/scripts/frontend-js-size.mts b/.github/scripts/frontend-js-size.mts index 38c6fa07e91..04a92679c7d 100644 --- a/.github/scripts/frontend-js-size.mts +++ b/.github/scripts/frontend-js-size.mts @@ -80,14 +80,17 @@ function stableChunkKey(chunk: Manifest[string]) { function collectStartupManifestKeys(manifest: Manifest) { const entryKey = findEntryKey(manifest); const keys = new Set(); - if (entryKey == null) return keys; + if (entryKey == null) throw new Error('Unable to find frontend startup entry in Vite manifest.'); - function visit(key: string) { + function visit(key: string, importedBy?: string) { if (keys.has(key)) return; const chunk = manifest[key]; - if (!chunk || !chunk.file?.endsWith('.js')) return; + const importContext = importedBy == null ? '' : ` imported by "${importedBy}"`; + if (chunk == null) throw new Error(`Startup manifest key "${key}"${importContext} is missing.`); + if (chunk.file == null || chunk.file.length === 0) throw new Error(`Startup manifest key "${key}"${importContext} has no output file.`); + if (!chunk.file.endsWith('.js')) throw new Error(`Startup manifest key "${key}"${importContext} resolves to non-JavaScript output "${chunk.file}".`); keys.add(key); - for (const importKey of chunk.imports ?? []) visit(importKey); + for (const importKey of chunk.imports ?? []) visit(importKey, key); } visit(entryKey); diff --git a/.github/scripts/frontend-js-size.test.mts b/.github/scripts/frontend-js-size.test.mts index d89fa153ba1..347d21548c1 100644 --- a/.github/scripts/frontend-js-size.test.mts +++ b/.github/scripts/frontend-js-size.test.mts @@ -12,7 +12,7 @@ import test, { type TestContext } from 'node:test'; import * as util from './utility.mts'; type Manifest = Record { assert.match(report, /`ja-JP\/entry-before\.js → ja-JP\/entry-after\.js`/); assert.match(report, /`ja-JP\/vue-before\.js → ja-JP\/vue-after\.js`/); }); + +test('fails descriptively when the startup entry is missing', async t => { + const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + delete before.manifest['src/_boot_.ts']; + delete before.sizes['scripts/entry-before.js']; + + const diagnostic = await runReport( + t, + before, + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + true, + ); + assert.match(diagnostic, /Unable to find frontend startup entry in Vite manifest/); +}); + +test('fails descriptively when a static import is missing from the manifest', async t => { + const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + before.manifest['src/_boot_.ts'].imports = ['_missing']; + + const diagnostic = await runReport( + t, + before, + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + true, + ); + assert.match(diagnostic, /Startup manifest key "_missing".*is missing/); +}); + +test('fails descriptively when a static import has no output file', async t => { + const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + before.manifest['src/_boot_.ts'].imports = ['_malformed']; + before.manifest._malformed = { name: 'malformed' }; + + const diagnostic = await runReport( + t, + before, + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + true, + ); + assert.match(diagnostic, /Startup manifest key "_malformed".*has no output file/); +}); + +test('fails descriptively when a static import resolves to a non-JavaScript output', async t => { + const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + before.manifest['src/_boot_.ts'].imports = ['_malformed']; + before.manifest._malformed = { file: 'assets/malformed.css', name: 'malformed' }; + + const diagnostic = await runReport( + t, + before, + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + true, + ); + assert.match(diagnostic, /Startup manifest key "_malformed".*non-JavaScript output "assets\/malformed\.css"/); +}); + +test('keeps source-backed additions and removals as individual rows', async t => { + const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + before.manifest._removed = { file: 'scripts/removed-before.js', src: 'src/removed.ts' }; + before.sizes['scripts/removed-before.js'] = 12; + const after = fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }); + after.manifest._added = { file: 'scripts/added-after.js', src: 'src/added.ts' }; + after.sizes['scripts/added-after.js'] = 13; + + const report = await runReport(t, before, after); + + assert.match(report, /`src\/added\.ts`<\/summary> `ja-JP\/added-after\.js` <\/details> \| 0 B \| 13 B \|/); + assert.match(report, /`src\/removed\.ts`<\/summary> `ja-JP\/removed-before\.js` <\/details> \| 12 B \| 0 B \|/); +}); + +test('counts an unmanifested localized JavaScript file in totals and the generated aggregate', async t => { + const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + before.sizes['scripts/unmanifested-before.js'] = 15; + + const report = await runReport( + t, + before, + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + ); + + assert.match(report, /\| \(total\) \| 235 B \| 275 B \|/); + assert.match(report, /\| \(other generated chunks\) \| 45 B \| 70 B \|/); + assert.match(report, /_3 before \/ 2 after generated chunks are grouped\._/); +}); + +test('counts duplicate manifest entries for one physical output only once', async t => { + const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + before.manifest._generatedAlias = { file: 'scripts/generated-a-before.js', name: 'dist' }; + + const report = await runReport( + t, + before, + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + ); + + assert.match(report, /\| \(total\) \| 220 B \| 275 B \|/); + assert.match(report, /_2 before \/ 2 after generated chunks are grouped\._/); +}); + +test('does not count generated-aggregate-only changes as individual chunk changes', async t => { + const report = await runReport( + t, + fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), + fixture('after', 'esm', { entry: 100, generatedA: 30, generatedB: 40, vue: 40, i18n: 50 }), + ); + + assert.match(report, /Chunk size diff \(0 updated, 0 added, 0 removed\)<\/summary>/); + assert.match(report, /Startup chunk size \(0 updated, 0 added, 0 removed\)<\/summary>/); + assert.equal(report.match(/\| \(other generated chunks\) \| 30 B \| 70 B \|/g)?.length, 2); +}); diff --git a/.gitignore b/.gitignore index e1fdaa271ae..e975691b935 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,3 @@ vite.config.local-dev.ts.timestamp-* # Affinity *.af~lock~ - -# Local Git worktrees -/.worktrees/ diff --git a/docs/superpowers/plans/2026-07-15-frontend-bundle-generated-chunks.md b/docs/superpowers/plans/2026-07-15-frontend-bundle-generated-chunks.md deleted file mode 100644 index 6a58d5e322b..00000000000 --- a/docs/superpowers/plans/2026-07-15-frontend-bundle-generated-chunks.md +++ /dev/null @@ -1,661 +0,0 @@ -# Frontend Bundle Generated Chunks Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Prevent generated `esm`/`dist`-style chunks from being compared individually while retaining every JavaScript output file in full and startup totals. - -**Architecture:** Keep physical chunk accounting separate from stable before/after identities. Source-backed chunks and the explicit `vue`/`i18n` code-splitting groups remain individually comparable; all other generated chunks are grouped into one aggregate row. Exercise the report generator through filesystem fixtures so tests cover manifest parsing, localized file resolution, startup traversal, and Markdown rendering together. - -**Tech Stack:** Node.js 26.4, TypeScript `.mts` scripts with native type stripping, Node test runner, Vite manifest JSON, GitHub Actions. - -## Global Constraints - -- Never compare unrelated generated chunks as the same chunk. -- Keep generated chunks out of the individual chunk-diff rows. -- Preserve the contribution of every physical JavaScript chunk in totals. -- Show the aggregate size change of generated chunks so unexplained bundle growth remains visible. -- Apply the same rules to the full chunk report and the startup chunk report. -- Continue comparing source-backed chunks and intentionally named chunks. -- The only stable generated-name allowlist entries are `vue` and `i18n`. -- Do not infer chunk identity from module-set similarity. -- Do not change the frontend code-splitting strategy or output filenames. -- Do not suppress generated chunks with a name denylist. -- Do not manually edit locale files other than `locales/ja-JP.yml`; this change does not require any locale edit. -- New `.mts` files must include the repository SPDX header. -- This developer-facing report change does not require a `CHANGELOG.md` entry. - -## File Structure - -- Create `.github/scripts/frontend-js-size.test.mts`: end-to-end fixtures for manifest collection and Markdown output. -- Modify `.github/scripts/frontend-js-size.mts`: physical chunk collection, stable identity classification, generated aggregation, startup accounting, duplicate-key validation, and filename rendering. -- Modify `.github/workflows/lint.yml`: run the focused Node test whenever the report script or its utility changes. -- Reference `docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md`: approved behavior and non-goals; no implementation edit is required. - ---- - -### Task 1: Preserve all physical chunks and aggregate generated chunks - -**Files:** -- Create: `.github/scripts/frontend-js-size.test.mts` -- Modify: `.github/scripts/frontend-js-size.mts:39-134` -- Modify: `.github/scripts/frontend-js-size.mts:315-426` - -**Interfaces:** -- Consumes: Vite `manifest.json`, localized JavaScript files under `built/_frontend_vite_/ja-JP`, and the existing five CLI arguments of `frontend-js-size.mts`. -- Produces: `CollectedReport` with `chunks: FileEntry[]`, `comparableChunks: Record`, `chunksByManifestKey: Record`, and `startupFiles: string[]`; Markdown with `(total)` and `(other generated chunks)` rows. - -- [ ] **Step 1: Write the failing end-to-end test** - -Create `.github/scripts/frontend-js-size.test.mts` with this initial content: - -```ts -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import assert from 'node:assert/strict'; -import { promises as fs } from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import test, { type TestContext } from 'node:test'; -import * as util from './utility.mts'; - -type Manifest = Record; - -const repoDir = path.resolve(import.meta.dirname, '../..'); -const reportScript = path.join(repoDir, '.github/scripts/frontend-js-size.mts'); - -async function writeBuild(repo: string, manifest: Manifest, sizes: Record) { - const outDir = path.join(repo, 'built/_frontend_vite_'); - await fs.mkdir(path.join(outDir, 'ja-JP'), { recursive: true }); - await fs.writeFile(path.join(outDir, 'manifest.json'), JSON.stringify(manifest)); - for (const [file, size] of Object.entries(sizes)) { - const localizedFile = file.replace(/^scripts\//, ''); - const outputFile = path.join(outDir, 'ja-JP', localizedFile); - await fs.mkdir(path.dirname(outputFile), { recursive: true }); - await fs.writeFile(outputFile, Buffer.alloc(size)); - } -} - -async function runReport(t: TestContext, before: { manifest: Manifest; sizes: Record }, after: { manifest: Manifest; sizes: Record }) { - const root = await fs.mkdtemp(path.join(os.tmpdir(), 'frontend-js-size-')); - t.after(() => fs.rm(root, { recursive: true, force: true })); - const beforeDir = path.join(root, 'before'); - const afterDir = path.join(root, 'after'); - const beforeStats = path.join(root, 'before-stats.json'); - const afterStats = path.join(root, 'after-stats.json'); - const reportFile = path.join(root, 'report.md'); - await writeBuild(beforeDir, before.manifest, before.sizes); - await writeBuild(afterDir, after.manifest, after.sizes); - await fs.writeFile(beforeStats, '{}'); - await fs.writeFile(afterStats, '{}'); - await util.run(process.execPath, [reportScript, beforeDir, afterDir, beforeStats, afterStats, reportFile]); - return fs.readFile(reportFile, 'utf8'); -} - -function fixture(suffix: string, generatedName: string, sizes: { entry: number; generatedA: number; generatedB: number; vue: number; i18n: number }) { - const files = { - entry: `scripts/entry-${suffix}.js`, - generatedA: `scripts/generated-a-${suffix}.js`, - generatedB: `scripts/generated-b-${suffix}.js`, - vue: `scripts/vue-${suffix}.js`, - i18n: `scripts/i18n-${suffix}.js`, - }; - return { - manifest: { - 'src/_boot_.ts': { file: files.entry, src: 'src/_boot_.ts', name: 'entry', isEntry: true, imports: ['_generatedA', '_generatedB', '_vue', '_i18n'] }, - _generatedA: { file: files.generatedA, name: generatedName }, - _generatedB: { file: files.generatedB, name: generatedName }, - _vue: { file: files.vue, name: 'vue' }, - _i18n: { file: files.i18n, name: 'i18n' }, - }, - sizes: Object.fromEntries(Object.entries(files).map(([key, file]) => [file, sizes[key as keyof typeof sizes]])), - }; -} - -test('groups generated chunks while preserving full and startup totals', async t => { - const report = await runReport( - t, - fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), - ); - - assert.match(report, /\| \(total\) \| 220 B \| 275 B \|/); - assert.equal(report.match(/\| \(other generated chunks\) \| 30 B \| 70 B \|/g)?.length, 2); - assert.equal(report.match(/_2 before \/ 2 after generated chunks are grouped\._/g)?.length, 2); - assert.doesNotMatch(report, /`(?:dist|esm)`<\/summary>/); - assert.match(report, /`src\/_boot_\.ts`<\/summary>/); - assert.match(report, /`vue`<\/summary>/); -}); -``` - -- [ ] **Step 2: Run the test and verify the current implementation fails** - -Run: - -```bash -node --test .github/scripts/frontend-js-size.test.mts -``` - -Expected: FAIL because `(total)` omits one of the duplicate generated-name chunks, no `(other generated chunks)` row exists, and an individual `dist` or `esm` row is rendered. - -- [ ] **Step 3: Replace name-based identity with physical accounting and stable classification** - -In `.github/scripts/frontend-js-size.mts`, replace `FileEntry`, `stableChunkKey`, `collectStartupKeys`, and `collectReport` with these structures and functions while retaining the existing `resolveBuiltFile` function: - -```ts -const stableNamedChunks = new Set(['vue', 'i18n']); - -type FileEntry = { - comparisonKey: string | null; - displayName: string; - file: string; - manifestKeys: string[]; - size: number; -}; - -type CollectedReport = { - manifest: Manifest; - chunks: FileEntry[]; - comparableChunks: Record; - chunksByManifestKey: Record; - startupFiles: string[]; -}; - -function stableChunkKey(chunk: Manifest[string]) { - if (chunk.src != null) return `src:${util.normalizePath(chunk.src)}`; - if (chunk.name != null && stableNamedChunks.has(chunk.name)) return `named:${chunk.name}`; - return null; -} - -function collectStartupManifestKeys(manifest: Manifest) { - const entryKey = findEntryKey(manifest); - const keys = new Set(); - if (entryKey == null) return keys; - - function visit(key: string) { - if (keys.has(key)) return; - const chunk = manifest[key]; - if (!chunk || !chunk.file?.endsWith('.js')) return; - keys.add(key); - for (const importKey of chunk.imports ?? []) visit(importKey); - } - - visit(entryKey); - return keys; -} - -async function collectReport(repoDir: string): Promise { - const outDir = path.join(repoDir, 'built/_frontend_vite_'); - const manifestPath = path.join(outDir, 'manifest.json'); - const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')) as Manifest; - const chunksByFile = new Map(); - const comparableChunks = new Map(); - const chunksByManifestKey = new Map(); - - for (const [manifestKey, chunk] of Object.entries(manifest)) { - if (!chunk.file?.endsWith('.js')) continue; - const builtFile = await resolveBuiltFile(outDir, chunk.file); - const comparisonKey = stableChunkKey(chunk); - let entry = chunksByFile.get(builtFile.relativePath); - if (entry == null) { - entry = { - comparisonKey, - displayName: chunk.src ?? chunk.name ?? manifestKey, - file: builtFile.relativePath, - manifestKeys: [manifestKey], - size: await util.fileSize(builtFile.absolutePath), - }; - chunksByFile.set(entry.file, entry); - } else if (entry.comparisonKey !== comparisonKey) { - throw new Error(`Conflicting identities for ${entry.file}`); - } else { - entry.manifestKeys.push(manifestKey); - } - chunksByManifestKey.set(manifestKey, entry); - if (comparisonKey != null) { - const existing = comparableChunks.get(comparisonKey); - if (existing != null && existing.file !== entry.file) { - throw new Error(`Duplicate stable chunk key "${comparisonKey}": ${existing.file}, ${entry.file}`); - } - comparableChunks.set(comparisonKey, entry); - } - } - - const localeDir = path.join(outDir, locale); - if (await util.fileExists(localeDir)) { - for await (const fullPath of util.traverseDirectory(localeDir)) { - if (!fullPath.endsWith('.js')) continue; - const relativePath = util.normalizePath(path.relative(outDir, fullPath)); - if (chunksByFile.has(relativePath)) continue; - chunksByFile.set(relativePath, { - comparisonKey: null, - displayName: relativePath, - file: relativePath, - manifestKeys: [], - size: await util.fileSize(fullPath), - }); - } - } - - const startupFiles = new Set(); - for (const manifestKey of collectStartupManifestKeys(manifest)) { - const entry = chunksByManifestKey.get(manifestKey); - if (entry != null) startupFiles.add(entry.file); - } - - return { - manifest, - chunks: [...chunksByFile.values()], - comparableChunks: Object.fromEntries(comparableChunks), - chunksByManifestKey: Object.fromEntries(chunksByManifestKey), - startupFiles: [...startupFiles], - }; -} -``` - -- [ ] **Step 4: Update comparison rows and table rendering** - -Change `getChunkComparisonRows` to consume comparable maps and retain both filenames: - -```ts -function getChunkComparisonRows(keys: string[], before: Record, after: Record) { - return keys.map(key => { - const beforeEntry = before[key]; - const afterEntry = after[key]; - const beforeSize = beforeEntry?.size ?? 0; - const afterSize = afterEntry?.size ?? 0; - return { - key, - name: entryDisplayName(beforeEntry ?? afterEntry), - beforeFile: beforeEntry?.file, - afterFile: afterEntry?.file, - beforeSize, - afterSize, - changeType: beforeEntry == null ? 'added' : afterEntry == null ? 'removed' : beforeSize !== afterSize ? 'updated' : 'unchanged', - sortSize: Math.max(beforeSize, afterSize), - }; - }); -} - -type ChunkAggregate = { - beforeSize: number; - afterSize: number; - beforeCount: number; - afterCount: number; -}; - -function sumChunkSizes(chunks: FileEntry[]) { - return chunks.reduce((sum, chunk) => sum + chunk.size, 0); -} - -function generatedAggregate(before: FileEntry[], after: FileEntry[]): ChunkAggregate { - const beforeGenerated = before.filter(chunk => chunk.comparisonKey == null); - const afterGenerated = after.filter(chunk => chunk.comparisonKey == null); - return { - beforeSize: sumChunkSizes(beforeGenerated), - afterSize: sumChunkSizes(afterGenerated), - beforeCount: beforeGenerated.length, - afterCount: afterGenerated.length, - }; -} - -function comparableMap(chunks: FileEntry[]) { - const entries: [string, FileEntry][] = []; - for (const chunk of chunks) { - if (chunk.comparisonKey != null) entries.push([chunk.comparisonKey, chunk]); - } - return Object.fromEntries(entries); -} -``` - -Replace `chunkMarkdownTable` with this version, which adds a third `generated` argument: - -```ts -function chunkMarkdownTable( - rows: ReturnType, - total?: { beforeSize: number; afterSize: number }, - generated?: ChunkAggregate, -) { - if (rows.length === 0 && total == null && generated == null) return '_No data_'; - - const lines = [ - '| Chunk | Before | After | Δ | Δ (%) |', - '| --- | ---: | ---: | ---: | ---: |', - ]; - let hasSummaryRow = false; - if (total != null) { - lines.push(`| (total) | ${util.formatBytes(total.beforeSize)} | ${util.formatBytes(total.afterSize)} | ${util.calcAndFormatDeltaBytes(total.beforeSize, total.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(total.beforeSize, total.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); - hasSummaryRow = true; - } - if (generated != null && (generated.beforeCount > 0 || generated.afterCount > 0)) { - lines.push(`| (other generated chunks) | ${util.formatBytes(generated.beforeSize)} | ${util.formatBytes(generated.afterSize)} | ${util.calcAndFormatDeltaBytes(generated.beforeSize, generated.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(generated.beforeSize, generated.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); - hasSummaryRow = true; - } - if (hasSummaryRow && rows.length > 0) lines.push('| | | | | |'); - - for (const row of rows) { - const chunkFile = row.beforeFile ?? row.afterFile ?? ''; - if (row.changeType === 'added') { - lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); - } else if (row.changeType === 'removed') { - lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{green}{\\text{( - )}}$ |`); - } else { - lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(row.beforeSize, row.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); - } - } - if (generated != null && (generated.beforeCount > 0 || generated.afterCount > 0)) { - lines.push(''); - lines.push(`_${generated.beforeCount} before / ${generated.afterCount} after generated chunks are grouped._`); - } - return lines.join('\n'); -} -``` - -Update `renderFrontendChunkReport` so the full report uses all physical chunks for totals, stable maps for rows, and unidentifiable chunks for the aggregate: - -```ts -const beforeComparable = before.comparableChunks; -const afterComparable = after.comparableChunks; -const allChunkKeys = [...new Set([...Object.keys(beforeComparable), ...Object.keys(afterComparable)])]; -const allComparisonRows = getChunkComparisonRows(allChunkKeys, beforeComparable, afterComparable); -const diffTotal = { - beforeSize: sumChunkSizes(before.chunks), - afterSize: sumChunkSizes(after.chunks), -}; -const diffGenerated = generatedAggregate(before.chunks, after.chunks); -``` - -For startup accounting, filter physical chunks by `startupFiles`, rebuild comparable maps from those filtered arrays, and calculate totals and aggregate from the filtered arrays: - -```ts -const beforeStartupFiles = new Set(before.startupFiles); -const afterStartupFiles = new Set(after.startupFiles); -const beforeStartupChunks = before.chunks.filter(chunk => beforeStartupFiles.has(chunk.file)); -const afterStartupChunks = after.chunks.filter(chunk => afterStartupFiles.has(chunk.file)); -const beforeStartupComparable = comparableMap(beforeStartupChunks); -const afterStartupComparable = comparableMap(afterStartupChunks); -const startupKeys = [...new Set([...Object.keys(beforeStartupComparable), ...Object.keys(afterStartupComparable)])]; -const startupComparisonRows = getChunkComparisonRows(startupKeys, beforeStartupComparable, afterStartupComparable); -const startupTotal = { - beforeSize: sumChunkSizes(beforeStartupChunks), - afterSize: sumChunkSizes(afterStartupChunks), -}; -const startupGenerated = generatedAggregate(beforeStartupChunks, afterStartupChunks); -``` - -Pass the aggregates with these exact calls: - -```ts -chunkMarkdownTable(diffRows, diffTotal, diffGenerated) -chunkMarkdownTable(startupRows, startupTotal, startupGenerated) -``` - -- [ ] **Step 5: Run the focused test and verify it passes** - -Run: - -```bash -node --test .github/scripts/frontend-js-size.test.mts -``` - -Expected: PASS with `1` test and `0` failures. The Markdown contains two aggregate rows because the fixture makes all chunks startup chunks as well as full-report chunks. - -- [ ] **Step 6: Commit the physical-accounting change** - -```bash -git add .github/scripts/frontend-js-size.mts .github/scripts/frontend-js-size.test.mts -git commit -m "fix(dev): aggregate generated frontend chunks" -``` - ---- - -### Task 2: Reject duplicate stable identities and render honest filenames - -**Files:** -- Modify: `.github/scripts/frontend-js-size.test.mts` -- Modify: `.github/scripts/frontend-js-size.mts:315-372` - -**Interfaces:** -- Consumes: the `Duplicate stable chunk key` validation and comparison rows produced in Task 1. -- Produces: a fatal diagnostic for duplicate `src`/allowlisted identities and a file label that renders `before → after` when hashes differ. - -- [ ] **Step 1: Add failing coverage for duplicate stable names and filename changes** - -Append these tests to `.github/scripts/frontend-js-size.test.mts`: - -```ts -test('fails instead of overwriting duplicate stable chunk keys', async t => { - const duplicateVue = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - duplicateVue.manifest._vueDuplicate = { file: 'scripts/vue-duplicate-before.js', name: 'vue' }; - duplicateVue.sizes['scripts/vue-duplicate-before.js'] = 60; - - await assert.rejects( - runReport(t, duplicateVue, fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 })), - /Duplicate stable chunk key "named:vue".*vue-before\.js.*vue-duplicate-before\.js/, - ); -}); - -test('shows both filenames for an updated stable chunk', async t => { - const report = await runReport( - t, - fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), - ); - - assert.match(report, /`ja-JP\/entry-before\.js → ja-JP\/entry-after\.js`/); - assert.match(report, /`ja-JP\/vue-before\.js → ja-JP\/vue-after\.js`/); -}); -``` - -- [ ] **Step 2: Run the tests and confirm the filename test fails** - -Run: - -```bash -node --test .github/scripts/frontend-js-size.test.mts -``` - -Expected: the duplicate-key test passes using Task 1 validation, while `shows both filenames for an updated stable chunk` fails because the table still shows only one file. - -- [ ] **Step 3: Render both filenames without changing identity logic** - -Add this helper near `chunkMarkdownTable`: - -```ts -function chunkFileDisplay(row: ReturnType[number]) { - if (row.beforeFile == null) return row.afterFile ?? ''; - if (row.afterFile == null || row.beforeFile === row.afterFile) return row.beforeFile; - return `${row.beforeFile} → ${row.afterFile}`; -} -``` - -At the start of each `for (const row of rows)` iteration, compute: - -```ts -const chunkFile = chunkFileDisplay(row); -``` - -Replace every `${escapeCell(row.chunkFile)}` interpolation in the three row variants with `${escapeCell(chunkFile)}`. Do not display any representative filename on the aggregate row. - -- [ ] **Step 4: Run all focused tests** - -Run: - -```bash -node --test .github/scripts/frontend-js-size.test.mts -``` - -Expected: PASS with `3` tests and `0` failures. - -- [ ] **Step 5: Commit the validation and display behavior** - -```bash -git add .github/scripts/frontend-js-size.mts .github/scripts/frontend-js-size.test.mts -git commit -m "fix(dev): clarify frontend chunk comparisons" -``` - ---- - -### Task 3: Run the report regression test in CI - -**Files:** -- Modify: `.github/workflows/lint.yml:3-33` -- Modify: `.github/workflows/lint.yml:139` - -**Interfaces:** -- Consumes: `.github/scripts/frontend-js-size.test.mts` from Tasks 1 and 2. -- Produces: a `frontend-bundle-report-test` GitHub Actions job using the repository's `.node-version`. - -- [ ] **Step 1: Verify the focused test is not currently referenced by CI** - -Run: - -```bash -rg -n "frontend-js-size.test|frontend-bundle-report-test" .github/workflows -``` - -Expected: no matches. - -- [ ] **Step 2: Add report-script paths to both lint workflow filters** - -Under both `on.push.paths` and `on.pull_request.paths` in `.github/workflows/lint.yml`, add: - -```yaml - - .github/scripts/frontend-js-size*.mts - - .github/scripts/utility.mts -``` - -Keep `.github/workflows/lint.yml` itself in both filters. - -- [ ] **Step 3: Add a focused CI job** - -Append this job under `jobs` at the same level as `check-dts`: - -```yaml - frontend-bundle-report-test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6.0.3 - - uses: actions/setup-node@v6.4.0 - with: - node-version-file: '.node-version' - - run: node --test .github/scripts/frontend-js-size.test.mts -``` - -This job intentionally does not depend on `pnpm_install` because the test and report generator use only Node built-ins and the local `utility.mts` module. - -- [ ] **Step 4: Run the exact CI test command locally** - -Run: - -```bash -node --test .github/scripts/frontend-js-size.test.mts -``` - -Expected: PASS with `3` tests and `0` failures. - -- [ ] **Step 5: Confirm CI now references the test exactly once** - -Run: - -```bash -rg -n "node --test \.github/scripts/frontend-js-size\.test\.mts" .github/workflows/lint.yml -``` - -Expected: one match in the `frontend-bundle-report-test` job. - -- [ ] **Step 6: Commit the CI coverage** - -```bash -git add .github/workflows/lint.yml -git commit -m "test(dev): check frontend bundle report" -``` - ---- - -### Task 4: Complete Misskey pre-ship validation - -**Files:** -- Verify: `.github/scripts/frontend-js-size.mts` -- Verify: `.github/scripts/frontend-js-size.test.mts` -- Verify: `.github/workflows/lint.yml` -- Verify: `docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md` - -**Interfaces:** -- Consumes: all implementation and CI changes from Tasks 1-3. -- Produces: fresh evidence that focused behavior, repository lint, SPDX, locale safety, and final diff checks pass. - -- [ ] **Step 1: Run the focused regression tests** - -Run: - -```bash -node --test .github/scripts/frontend-js-size.test.mts -``` - -Expected: PASS with `3` tests and `0` failures. - -- [ ] **Step 2: Run repository lint** - -Run: - -```bash -pnpm lint -``` - -Expected: exit code `0`. If an unrelated pre-existing failure occurs, record its exact command and output rather than claiming lint passed. - -- [ ] **Step 3: Check the new file's SPDX header** - -Run: - -```bash -rg -n "SPDX-FileCopyrightText: syuilo and misskey-project|SPDX-License-Identifier: AGPL-3.0-only" .github/scripts/frontend-js-size.test.mts -``` - -Expected: two matches, one for each required SPDX line. - -- [ ] **Step 4: Verify locale safety and unchanged migration/API surfaces** - -Run: - -```bash -git diff --name-only develop -- locales -git diff --name-only develop -- packages/backend/migration packages/backend/src packages/misskey-js/src/autogen -``` - -Expected: both commands produce no output. Therefore locale generation, migration checking, backend API review, and misskey-js regeneration are not applicable. - -- [ ] **Step 5: Verify the final diff and worktree** - -Run: - -```bash -git diff --check develop...HEAD -git status --short -git log --oneline develop..HEAD -``` - -Expected: `git diff --check` exits `0`, `git status --short` is empty, and the log contains the approved design commit plus the three implementation commits from this plan. - -- [ ] **Step 6: Review the final report behavior against the approved design** - -Confirm all of these from the focused test output and diff: - -```text -[x] Physical chunks are counted once by output path. -[x] Only src-backed, vue, and i18n chunks are individually compared. -[x] Generated chunks are aggregated in full and startup reports. -[x] Duplicate stable keys fail instead of overwriting. -[x] Updated stable rows show before and after filenames. -[x] No locale, migration, backend API, frontend Vue, or user-facing behavior changed. -[x] No CHANGELOG entry is needed. -``` From a7fd58e4a59c4ce2fceee7e220dca99f71c90577 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:57:56 +0900 Subject: [PATCH 361/578] docs: define small frontend chunk aggregation --- ...frontend-bundle-generated-chunks-design.md | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md b/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md index 95e0de006bd..1cadf1f3fa7 100644 --- a/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md +++ b/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md @@ -89,7 +89,7 @@ The report computes three independent values: 2. **Generated chunk aggregate:** the sum of chunks without a comparison key. 3. **Individual rows:** before/after comparisons for stable comparison keys only. -The table starts with the existing `(total)` row. When either build contains generated chunks, it then includes one aggregate row such as: +The table starts with the existing `(total)` row. Generated chunks are rendered at the bottom of the table as one aggregate row such as: ```text (other generated chunks) @@ -99,6 +99,24 @@ This row compares aggregate sizes, not individual chunk identities. Generated ch The report includes a short note stating how many generated chunks were grouped on each side. This makes the scope of the aggregate explicit without listing noisy filenames. +### Small-delta aggregation + +Stable comparison rows whose absolute byte delta is at most `5 B` are grouped into an `(other)` aggregate instead of being rendered individually. The threshold is inclusive: deltas from `-5 B` through `+5 B` are grouped, while a `6 B` absolute delta remains an individual row. Small additions and removals are handled by the same rule. + +The `(other)` row reports the sum of the grouped chunks' before sizes and the sum of their after sizes. It does not expose an arbitrary representative filename. In the full chunk report, only changed rows are candidates because unchanged rows are already omitted. In the startup report, all rows currently eligible for display are candidates, so unchanged rows are also grouped instead of being listed individually. + +The updated/added/removed counts are calculated before small-delta rows are grouped. Therefore the summary continues to include every stable changed chunk, including chunks represented only by `(other)`. + +Table rows are ordered as follows: + +1. `(total)`; +2. individual stable comparison rows whose absolute delta is greater than `5 B`; +3. one empty separator row, when at least one aggregate row follows; +4. `(other generated chunks)`, when generated chunks exist; and +5. `(other)`, when small-delta stable chunks exist. + +The existing 30-row limit applies after small-delta rows have been removed from the individual-row candidates. + ### Startup chunk report Startup traversal continues to follow the entry chunk's static `imports`, but it records manifest keys or resolved physical file paths rather than generated comparison keys. This prevents two startup chunks named `dist` from collapsing into one. @@ -143,8 +161,12 @@ Add focused fixtures or pure-function tests covering: - duplicate stable keys produce a descriptive error instead of overwriting; - full totals equal the sum of all unique physical chunks; - startup totals include multiple same-name generated chunks exactly once each; -- generated aggregate changes do not affect the updated/added/removed summary counts; and -- differing before/after filenames are rendered without attributing both sizes to one file. +- generated aggregate changes do not affect the updated/added/removed summary counts; +- differing before/after filenames are rendered without attributing both sizes to one file; +- deltas of exactly `5 B` are grouped into `(other)`, while `6 B` deltas remain individual; +- small updated, added, and removed chunks remain included in the summary counts; +- `(other generated chunks)` and `(other)` appear below individual rows after an empty separator row; and +- the same small-delta and ordering rules apply to the full and startup tables. Validation should include the focused tests and repository lint. No CHANGELOG entry is required because this changes developer-facing CI reporting rather than Misskey user behavior. From 1e4260cfb192a75e36bd91f65d60c4e3999cf9e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:59:31 +0900 Subject: [PATCH 362/578] feat: add Japanese language support and tone instructions (#17720) --- .coderabbit.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index ce726dd641e..b10b0011714 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -1,3 +1,5 @@ +language: "ja-JP" +tone_instructions: "常��寧語(��・��調)を用��敬���る表��応答������。人格や能力��評価�皮肉��圧的・高圧的・命令的�表���������。指摘���題点�影響を明確����由を簡潔�説明������具体的�改善案を�案������。�確実�事項�推測�明示��確�を促������。�大��グやセキュリティ上�懸念���度�根拠を明確��������。" reviews: profile: "chill" high_level_summary: false From 2199f9040d156f173af8fa908a987374283235d0 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:01:17 +0900 Subject: [PATCH 363/578] docs: plan small frontend chunk aggregation --- .gitignore | 3 + ...frontend-bundle-small-delta-aggregation.md | 114 ++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md diff --git a/.gitignore b/.gitignore index e975691b935..748b9f5d18e 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,6 @@ vite.config.local-dev.ts.timestamp-* # Affinity *.af~lock~ + +# Agent worktrees +/.worktrees/ diff --git a/docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md b/docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md new file mode 100644 index 00000000000..8b0ac359f3c --- /dev/null +++ b/docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md @@ -0,0 +1,114 @@ +# Frontend Bundle Small-Delta Aggregation Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Group stable frontend chunks with an absolute size delta of at most `5 B` into a bottom-of-table `(other)` row while preserving complete change counts. + +**Architecture:** Keep comparison and summary calculation unchanged, then partition render candidates into significant and small-delta rows. Render individual rows first and append generated/small-delta aggregates after one empty separator row in both full and startup tables. + +**Tech Stack:** TypeScript, Node.js test runner, Markdown report generation. + +## Global Constraints + +- The threshold is inclusive: `Math.abs(afterSize - beforeSize) <= 5` is grouped. +- Summary updated/added/removed counts use all stable changed rows before grouping. +- Full-report candidates are changed stable rows; startup candidates include every stable startup row, including unchanged rows. +- Aggregate order is `(other generated chunks)` followed by `(other)`. +- A single empty Markdown table row separates individual rows from aggregates. +- The existing individual-row limit is applied after small-delta rows are removed. +- Do not run code review or repository-wide lint, per the user's request. + +--- + +### Task 1: Aggregate and move small-delta rows + +**Files:** +- Modify: `.github/scripts/frontend-js-size.test.mts` +- Modify: `.github/scripts/frontend-js-size.mts:350-520` +- Verify: `docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md` + +**Interfaces:** +- Consumes: stable comparison rows from `getChunkComparisonRows`, physical generated aggregates, and the existing `chunkMarkdownTable` renderer. +- Produces: a `ChunkAggregate` for small-delta rows and Markdown ordered as total, significant rows, separator, generated aggregate, small-delta aggregate. + +- [ ] **Step 1: Write the failing end-to-end test** + +Add a test based on the existing `fixture` helper. Use an entry delta of `+6 B`, a Vue delta of `+5 B`, unchanged i18n, a `5 B` removed source chunk in the before startup imports, and a `5 B` added source chunk in the after startup imports. + +Assert all of the following: + +```ts +assert.match(report, /Chunk size diff \(2 updated, 1 added, 1 removed\)<\/summary>/); +assert.match(report, /Startup chunk size \(2 updated, 1 added, 1 removed\)<\/summary>/); +assert.match(report, /`src\/_boot_\.ts`<\/summary>/); +assert.doesNotMatch(report, /`(?:vue|i18n|src\/added-small\.ts|src\/removed-small\.ts)`<\/summary>/); +assert.match(report, /\| \| \| \| \| \|\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 45 B \| 50 B \|/); +assert.match(report, /\| \| \| \| \| \|\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 95 B \| 100 B \|/); +``` + +- [ ] **Step 2: Run the focused test and verify RED** + +Run: + +```powershell +& 'C:\Program Files\nodejs\node.exe' --test .github/scripts/frontend-js-size.test.mts +``` + +Expected: the new test fails because `(other)` is absent and `(other generated chunks)` is still directly below `(total)`. + +- [ ] **Step 3: Add the small-delta partition and aggregate** + +Add a constant and helpers near `ChunkAggregate`: + +```ts +const smallDeltaThreshold = 5; + +type ChunkComparisonRow = ReturnType[number]; + +function hasSmallDelta(row: ChunkComparisonRow) { + return Math.abs(row.afterSize - row.beforeSize) <= smallDeltaThreshold; +} + +function comparisonRowsAggregate(rows: ChunkComparisonRow[]): ChunkAggregate { + return { + beforeSize: rows.reduce((sum, row) => sum + row.beforeSize, 0), + afterSize: rows.reduce((sum, row) => sum + row.afterSize, 0), + beforeCount: rows.filter(row => row.beforeFile != null).length, + afterCount: rows.filter(row => row.afterFile != null).length, + }; +} +``` + +Calculate summaries before filtering. Partition `changedRows` and `startupComparisonRows`, aggregate small rows, and apply sorting/30-row limiting only to rows for which `hasSmallDelta` is false. + +- [ ] **Step 4: Render aggregate rows at the table bottom** + +Extend `chunkMarkdownTable` with an optional `other?: ChunkAggregate`. Render `(total)`, then individual rows. If either aggregate contains chunks, append one `| | | | | |` separator, followed by `(other generated chunks)` and `(other)` when present. + +Use the existing numeric formatting for both aggregates: + +```ts +`| (other) | ${util.formatBytes(other.beforeSize)} | ${util.formatBytes(other.afterSize)} | ${util.calcAndFormatDeltaBytes(other.beforeSize, other.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(other.beforeSize, other.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |` +``` + +Pass the full and startup small-delta aggregates to their corresponding table calls. + +- [ ] **Step 5: Run the focused suite and verify GREEN** + +Run: + +```powershell +& 'C:\Program Files\nodejs\node.exe' --test .github/scripts/frontend-js-size.test.mts +``` + +Expected: all existing tests plus the new test pass with zero failures and clean output. + +- [ ] **Step 6: Remove this transient implementation plan and commit** + +Delete `docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md`, then run: + +```powershell +git diff --check +git add .github/scripts/frontend-js-size.mts .github/scripts/frontend-js-size.test.mts +git commit -m "fix(dev): group small frontend chunk deltas" +``` From 112263135eb68c85009878c132800e229bcada74 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:04:54 +0900 Subject: [PATCH 364/578] fix(dev): group small frontend chunk deltas --- .github/scripts/frontend-js-size.mts | 52 +++++--- .github/scripts/frontend-js-size.test.mts | 27 ++++- .gitignore | 3 - ...frontend-bundle-small-delta-aggregation.md | 114 ------------------ 4 files changed, 61 insertions(+), 135 deletions(-) delete mode 100644 docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md diff --git a/.github/scripts/frontend-js-size.mts b/.github/scripts/frontend-js-size.mts index 04a92679c7d..370f49c0827 100644 --- a/.github/scripts/frontend-js-size.mts +++ b/.github/scripts/frontend-js-size.mts @@ -368,6 +368,8 @@ function getChunkComparisonRows(keys: string[], before: Record[number]; + type ChunkAggregate = { beforeSize: number; afterSize: number; @@ -375,6 +377,8 @@ type ChunkAggregate = { afterCount: number; }; +const smallDeltaThreshold = 5; + function sumChunkSizes(chunks: FileEntry[]) { return chunks.reduce((sum, chunk) => sum + chunk.size, 0); } @@ -390,6 +394,19 @@ function generatedAggregate(before: FileEntry[], after: FileEntry[]): ChunkAggre }; } +function hasSmallDelta(row: ChunkComparisonRow) { + return Math.abs(row.afterSize - row.beforeSize) <= smallDeltaThreshold; +} + +function comparisonRowsAggregate(rows: ChunkComparisonRow[]): ChunkAggregate { + return { + beforeSize: rows.reduce((sum, row) => sum + row.beforeSize, 0), + afterSize: rows.reduce((sum, row) => sum + row.afterSize, 0), + beforeCount: rows.filter(row => row.beforeFile != null).length, + afterCount: rows.filter(row => row.afterFile != null).length, + }; +} + function comparableMap(chunks: FileEntry[]) { const entries: [string, FileEntry][] = []; for (const chunk of chunks) { @@ -410,14 +427,14 @@ function formatChunkChangeSummary(label: string, summary: ReturnType[number], b: ReturnType[number]) { +function compareChunkComparisonRows(a: ChunkComparisonRow, b: ChunkComparisonRow) { return Math.abs(b.afterSize - b.beforeSize) - Math.abs(a.afterSize - a.beforeSize) || (b.afterSize - b.beforeSize) - (a.afterSize - a.beforeSize) || b.sortSize - a.sortSize || a.name.localeCompare(b.name); } -function chunkFileDisplay(row: ReturnType[number]) { +function chunkFileDisplay(row: ChunkComparisonRow) { if (row.beforeFile == null) return row.afterFile ?? ''; if (row.afterFile == null || row.beforeFile === row.afterFile) return row.beforeFile; return `${row.beforeFile} → ${row.afterFile}`; @@ -427,23 +444,19 @@ function chunkMarkdownTable( rows: ReturnType, total?: { beforeSize: number; afterSize: number }, generated?: ChunkAggregate, + other?: ChunkAggregate, ) { - if (rows.length === 0 && total == null && generated == null) return '_No data_'; + const hasGenerated = generated != null && (generated.beforeCount > 0 || generated.afterCount > 0); + const hasOther = other != null && (other.beforeCount > 0 || other.afterCount > 0); + if (rows.length === 0 && total == null && !hasGenerated && !hasOther) return '_No data_'; const lines = [ '| Chunk | Before | After | Δ | Δ (%) |', '| --- | ---: | ---: | ---: | ---: |', ]; - let hasSummaryRow = false; if (total != null) { lines.push(`| (total) | ${util.formatBytes(total.beforeSize)} | ${util.formatBytes(total.afterSize)} | ${util.calcAndFormatDeltaBytes(total.beforeSize, total.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(total.beforeSize, total.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); - hasSummaryRow = true; - } - if (generated != null && (generated.beforeCount > 0 || generated.afterCount > 0)) { - lines.push(`| (other generated chunks) | ${util.formatBytes(generated.beforeSize)} | ${util.formatBytes(generated.afterSize)} | ${util.calcAndFormatDeltaBytes(generated.beforeSize, generated.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(generated.beforeSize, generated.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); - hasSummaryRow = true; } - if (hasSummaryRow && rows.length > 0) lines.push('| | | | | |'); for (const row of rows) { const chunkFile = chunkFileDisplay(row); @@ -455,7 +468,14 @@ function chunkMarkdownTable( lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(row.beforeSize, row.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); } } - if (generated != null && (generated.beforeCount > 0 || generated.afterCount > 0)) { + if (hasGenerated || hasOther) lines.push('| | | | | |'); + if (hasGenerated) { + lines.push(`| (other generated chunks) | ${util.formatBytes(generated.beforeSize)} | ${util.formatBytes(generated.afterSize)} | ${util.calcAndFormatDeltaBytes(generated.beforeSize, generated.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(generated.beforeSize, generated.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); + } + if (hasOther) { + lines.push(`| (other) | ${util.formatBytes(other.beforeSize)} | ${util.formatBytes(other.afterSize)} | ${util.calcAndFormatDeltaBytes(other.beforeSize, other.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(other.beforeSize, other.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); + } + if (hasGenerated) { lines.push(''); lines.push(`_${generated.beforeCount} before / ${generated.afterCount} after generated chunks are grouped._`); } @@ -475,7 +495,8 @@ function renderFrontendChunkReport(before: Awaited !hasSmallDelta(row)).sort(compareChunkComparisonRows).slice(0, 30); // TODO: 実際�30を超��切り��られ�row����場����旨をmarkdown内�表示�るよ���る const beforeStartupFiles = new Set(before.startupFiles); const afterStartupFiles = new Set(after.startupFiles); @@ -485,8 +506,9 @@ function renderFrontendChunkReport(before: Awaited !hasSmallDelta(row)).sort(compareChunkComparisonRows); const startupTotal = { beforeSize: sumChunkSizes(beforeStartupChunks), afterSize: sumChunkSizes(afterStartupChunks), @@ -501,14 +523,14 @@ function renderFrontendChunkReport(before: Awaited', `${formatChunkChangeSummary('Chunk size diff', diffSummary)}`, '', - chunkMarkdownTable(diffRows, diffTotal, diffGenerated), + chunkMarkdownTable(diffRows, diffTotal, diffGenerated, diffOther), '', '
', '', '
', `${formatChunkChangeSummary('Startup chunk size', startupSummary)}`, '', - chunkMarkdownTable(startupRows, startupTotal, startupGenerated), + chunkMarkdownTable(startupRows, startupTotal, startupGenerated, startupOther), '', `_Startup chunks are the Vite entry for \`src/_boot_.ts\` and its static imports._`, '', diff --git a/.github/scripts/frontend-js-size.test.mts b/.github/scripts/frontend-js-size.test.mts index 347d21548c1..f688ae3270b 100644 --- a/.github/scripts/frontend-js-size.test.mts +++ b/.github/scripts/frontend-js-size.test.mts @@ -86,10 +86,10 @@ test('groups generated chunks while preserving full and startup totals', async t const report = await runReport( t, fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 55, i18n: 50 }), ); - assert.match(report, /\| \(total\) \| 220 B \| 275 B \|/); + assert.match(report, /\| \(total\) \| 220 B \| 285 B \|/); assert.equal(report.match(/\| \(other generated chunks\) \| 30 B \| 70 B \|/g)?.length, 2); assert.equal(report.match(/_2 before \/ 2 after generated chunks are grouped\._/g)?.length, 2); assert.doesNotMatch(report, /`(?:dist|esm)`<\/summary>/); @@ -97,6 +97,27 @@ test('groups generated chunks while preserving full and startup totals', async t assert.match(report, /`vue`<\/summary>/); }); +test('groups small deltas at the bottom while preserving all change counts', async t => { + const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); + before.manifest._removedSmall = { file: 'scripts/removed-small-before.js', src: 'src/removed-small.ts' }; + before.manifest['src/_boot_.ts'].imports?.push('_removedSmall'); + before.sizes['scripts/removed-small-before.js'] = 5; + + const after = fixture('after', 'esm', { entry: 106, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }); + after.manifest._addedSmall = { file: 'scripts/added-small-after.js', src: 'src/added-small.ts' }; + after.manifest['src/_boot_.ts'].imports?.push('_addedSmall'); + after.sizes['scripts/added-small-after.js'] = 5; + + const report = await runReport(t, before, after); + + assert.match(report, /Chunk size diff \(2 updated, 1 added, 1 removed\)<\/summary>/); + assert.match(report, /Startup chunk size \(2 updated, 1 added, 1 removed\)<\/summary>/); + assert.equal(report.match(/`src\/_boot_\.ts`<\/summary>/g)?.length, 2); + assert.doesNotMatch(report, /`(?:vue|i18n|src\/added-small\.ts|src\/removed-small\.ts)`<\/summary>/); + assert.match(report, /\| \(total\) \| 225 B \| 276 B \|[^\n]*\n\|
`src\/_boot_\.ts`<\/summary>[^\n]*\n\| \| \| \| \| \|\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 45 B \| 50 B \|/); + assert.match(report, /\| \(total\) \| 225 B \| 276 B \|[^\n]*\n\|
`src\/_boot_\.ts`<\/summary>[^\n]*\n\| \| \| \| \| \|\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 95 B \| 100 B \|/); +}); + test('fails instead of overwriting duplicate stable chunk keys', async t => { const duplicateVue = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); duplicateVue.manifest._vueDuplicate = { file: 'scripts/vue-duplicate-before.js', name: 'vue' }; @@ -115,7 +136,7 @@ test('shows both filenames for an updated stable chunk', async t => { const report = await runReport( t, fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), + fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 55, i18n: 50 }), ); assert.match(report, /`ja-JP\/entry-before\.js → ja-JP\/entry-after\.js`/); diff --git a/.gitignore b/.gitignore index 748b9f5d18e..e975691b935 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,3 @@ vite.config.local-dev.ts.timestamp-* # Affinity *.af~lock~ - -# Agent worktrees -/.worktrees/ diff --git a/docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md b/docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md deleted file mode 100644 index 8b0ac359f3c..00000000000 --- a/docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md +++ /dev/null @@ -1,114 +0,0 @@ -# Frontend Bundle Small-Delta Aggregation Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Group stable frontend chunks with an absolute size delta of at most `5 B` into a bottom-of-table `(other)` row while preserving complete change counts. - -**Architecture:** Keep comparison and summary calculation unchanged, then partition render candidates into significant and small-delta rows. Render individual rows first and append generated/small-delta aggregates after one empty separator row in both full and startup tables. - -**Tech Stack:** TypeScript, Node.js test runner, Markdown report generation. - -## Global Constraints - -- The threshold is inclusive: `Math.abs(afterSize - beforeSize) <= 5` is grouped. -- Summary updated/added/removed counts use all stable changed rows before grouping. -- Full-report candidates are changed stable rows; startup candidates include every stable startup row, including unchanged rows. -- Aggregate order is `(other generated chunks)` followed by `(other)`. -- A single empty Markdown table row separates individual rows from aggregates. -- The existing individual-row limit is applied after small-delta rows are removed. -- Do not run code review or repository-wide lint, per the user's request. - ---- - -### Task 1: Aggregate and move small-delta rows - -**Files:** -- Modify: `.github/scripts/frontend-js-size.test.mts` -- Modify: `.github/scripts/frontend-js-size.mts:350-520` -- Verify: `docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md` - -**Interfaces:** -- Consumes: stable comparison rows from `getChunkComparisonRows`, physical generated aggregates, and the existing `chunkMarkdownTable` renderer. -- Produces: a `ChunkAggregate` for small-delta rows and Markdown ordered as total, significant rows, separator, generated aggregate, small-delta aggregate. - -- [ ] **Step 1: Write the failing end-to-end test** - -Add a test based on the existing `fixture` helper. Use an entry delta of `+6 B`, a Vue delta of `+5 B`, unchanged i18n, a `5 B` removed source chunk in the before startup imports, and a `5 B` added source chunk in the after startup imports. - -Assert all of the following: - -```ts -assert.match(report, /Chunk size diff \(2 updated, 1 added, 1 removed\)<\/summary>/); -assert.match(report, /Startup chunk size \(2 updated, 1 added, 1 removed\)<\/summary>/); -assert.match(report, /`src\/_boot_\.ts`<\/summary>/); -assert.doesNotMatch(report, /`(?:vue|i18n|src\/added-small\.ts|src\/removed-small\.ts)`<\/summary>/); -assert.match(report, /\| \| \| \| \| \|\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 45 B \| 50 B \|/); -assert.match(report, /\| \| \| \| \| \|\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 95 B \| 100 B \|/); -``` - -- [ ] **Step 2: Run the focused test and verify RED** - -Run: - -```powershell -& 'C:\Program Files\nodejs\node.exe' --test .github/scripts/frontend-js-size.test.mts -``` - -Expected: the new test fails because `(other)` is absent and `(other generated chunks)` is still directly below `(total)`. - -- [ ] **Step 3: Add the small-delta partition and aggregate** - -Add a constant and helpers near `ChunkAggregate`: - -```ts -const smallDeltaThreshold = 5; - -type ChunkComparisonRow = ReturnType[number]; - -function hasSmallDelta(row: ChunkComparisonRow) { - return Math.abs(row.afterSize - row.beforeSize) <= smallDeltaThreshold; -} - -function comparisonRowsAggregate(rows: ChunkComparisonRow[]): ChunkAggregate { - return { - beforeSize: rows.reduce((sum, row) => sum + row.beforeSize, 0), - afterSize: rows.reduce((sum, row) => sum + row.afterSize, 0), - beforeCount: rows.filter(row => row.beforeFile != null).length, - afterCount: rows.filter(row => row.afterFile != null).length, - }; -} -``` - -Calculate summaries before filtering. Partition `changedRows` and `startupComparisonRows`, aggregate small rows, and apply sorting/30-row limiting only to rows for which `hasSmallDelta` is false. - -- [ ] **Step 4: Render aggregate rows at the table bottom** - -Extend `chunkMarkdownTable` with an optional `other?: ChunkAggregate`. Render `(total)`, then individual rows. If either aggregate contains chunks, append one `| | | | | |` separator, followed by `(other generated chunks)` and `(other)` when present. - -Use the existing numeric formatting for both aggregates: - -```ts -`| (other) | ${util.formatBytes(other.beforeSize)} | ${util.formatBytes(other.afterSize)} | ${util.calcAndFormatDeltaBytes(other.beforeSize, other.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(other.beforeSize, other.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |` -``` - -Pass the full and startup small-delta aggregates to their corresponding table calls. - -- [ ] **Step 5: Run the focused suite and verify GREEN** - -Run: - -```powershell -& 'C:\Program Files\nodejs\node.exe' --test .github/scripts/frontend-js-size.test.mts -``` - -Expected: all existing tests plus the new test pass with zero failures and clean output. - -- [ ] **Step 6: Remove this transient implementation plan and commit** - -Delete `docs/superpowers/plans/2026-07-16-frontend-bundle-small-delta-aggregation.md`, then run: - -```powershell -git diff --check -git add .github/scripts/frontend-js-size.mts .github/scripts/frontend-js-size.test.mts -git commit -m "fix(dev): group small frontend chunk deltas" -``` From 0f3210946d6621f5bfaede5c8fa31f251d521a90 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:27:46 +0900 Subject: [PATCH 365/578] fix(dev): refine frontend chunk report layout --- .github/scripts/frontend-js-size.mts | 6 +----- .github/scripts/frontend-js-size.test.mts | 8 +++----- ...07-15-frontend-bundle-generated-chunks-design.md | 13 +++++++------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.github/scripts/frontend-js-size.mts b/.github/scripts/frontend-js-size.mts index 370f49c0827..db134bab791 100644 --- a/.github/scripts/frontend-js-size.mts +++ b/.github/scripts/frontend-js-size.mts @@ -456,6 +456,7 @@ function chunkMarkdownTable( ]; if (total != null) { lines.push(`| (total) | ${util.formatBytes(total.beforeSize)} | ${util.formatBytes(total.afterSize)} | ${util.calcAndFormatDeltaBytes(total.beforeSize, total.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(total.beforeSize, total.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); + lines.push('| | | | | |'); } for (const row of rows) { @@ -468,17 +469,12 @@ function chunkMarkdownTable( lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(row.beforeSize, row.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); } } - if (hasGenerated || hasOther) lines.push('| | | | | |'); if (hasGenerated) { lines.push(`| (other generated chunks) | ${util.formatBytes(generated.beforeSize)} | ${util.formatBytes(generated.afterSize)} | ${util.calcAndFormatDeltaBytes(generated.beforeSize, generated.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(generated.beforeSize, generated.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); } if (hasOther) { lines.push(`| (other) | ${util.formatBytes(other.beforeSize)} | ${util.formatBytes(other.afterSize)} | ${util.calcAndFormatDeltaBytes(other.beforeSize, other.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(other.beforeSize, other.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); } - if (hasGenerated) { - lines.push(''); - lines.push(`_${generated.beforeCount} before / ${generated.afterCount} after generated chunks are grouped._`); - } return lines.join('\n'); } diff --git a/.github/scripts/frontend-js-size.test.mts b/.github/scripts/frontend-js-size.test.mts index f688ae3270b..d3b3db9af66 100644 --- a/.github/scripts/frontend-js-size.test.mts +++ b/.github/scripts/frontend-js-size.test.mts @@ -91,7 +91,7 @@ test('groups generated chunks while preserving full and startup totals', async t assert.match(report, /\| \(total\) \| 220 B \| 285 B \|/); assert.equal(report.match(/\| \(other generated chunks\) \| 30 B \| 70 B \|/g)?.length, 2); - assert.equal(report.match(/_2 before \/ 2 after generated chunks are grouped\._/g)?.length, 2); + assert.doesNotMatch(report, /generated chunks are grouped/); assert.doesNotMatch(report, /`(?:dist|esm)`<\/summary>/); assert.match(report, /`src\/_boot_\.ts`<\/summary>/); assert.match(report, /`vue`<\/summary>/); @@ -114,8 +114,8 @@ test('groups small deltas at the bottom while preserving all change counts', asy assert.match(report, /Startup chunk size \(2 updated, 1 added, 1 removed\)<\/summary>/); assert.equal(report.match(/`src\/_boot_\.ts`<\/summary>/g)?.length, 2); assert.doesNotMatch(report, /`(?:vue|i18n|src\/added-small\.ts|src\/removed-small\.ts)`<\/summary>/); - assert.match(report, /\| \(total\) \| 225 B \| 276 B \|[^\n]*\n\|
`src\/_boot_\.ts`<\/summary>[^\n]*\n\| \| \| \| \| \|\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 45 B \| 50 B \|/); - assert.match(report, /\| \(total\) \| 225 B \| 276 B \|[^\n]*\n\|
`src\/_boot_\.ts`<\/summary>[^\n]*\n\| \| \| \| \| \|\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 95 B \| 100 B \|/); + assert.match(report, /\| \(total\) \| 225 B \| 276 B \|[^\n]*\n\| \| \| \| \| \|\n\|
`src\/_boot_\.ts`<\/summary>[^\n]*\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 45 B \| 50 B \|/); + assert.match(report, /\| \(total\) \| 225 B \| 276 B \|[^\n]*\n\| \| \| \| \| \|\n\|
`src\/_boot_\.ts`<\/summary>[^\n]*\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 95 B \| 100 B \|/); }); test('fails instead of overwriting duplicate stable chunk keys', async t => { @@ -224,7 +224,6 @@ test('counts an unmanifested localized JavaScript file in totals and the generat assert.match(report, /\| \(total\) \| 235 B \| 275 B \|/); assert.match(report, /\| \(other generated chunks\) \| 45 B \| 70 B \|/); - assert.match(report, /_3 before \/ 2 after generated chunks are grouped\._/); }); test('counts duplicate manifest entries for one physical output only once', async t => { @@ -238,7 +237,6 @@ test('counts duplicate manifest entries for one physical output only once', asyn ); assert.match(report, /\| \(total\) \| 220 B \| 275 B \|/); - assert.match(report, /_2 before \/ 2 after generated chunks are grouped\._/); }); test('does not count generated-aggregate-only changes as individual chunk changes', async t => { diff --git a/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md b/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md index 1cadf1f3fa7..3a8c404a3ec 100644 --- a/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md +++ b/docs/superpowers/specs/2026-07-15-frontend-bundle-generated-chunks-design.md @@ -95,9 +95,7 @@ The table starts with the existing `(total)` row. Generated chunks are rendered (other generated chunks) ``` -This row compares aggregate sizes, not individual chunk identities. Generated chunks do not participate in the updated/added/removed row counts. - -The report includes a short note stating how many generated chunks were grouped on each side. This makes the scope of the aggregate explicit without listing noisy filenames. +This row compares aggregate sizes, not individual chunk identities. Generated chunks do not participate in the updated/added/removed row counts. No additional generated-chunk count note is rendered below the table. ### Small-delta aggregation @@ -110,11 +108,13 @@ The updated/added/removed counts are calculated before small-delta rows are grou Table rows are ordered as follows: 1. `(total)`; -2. individual stable comparison rows whose absolute delta is greater than `5 B`; -3. one empty separator row, when at least one aggregate row follows; +2. one empty separator row; +3. individual stable comparison rows whose absolute delta is greater than `5 B`; 4. `(other generated chunks)`, when generated chunks exist; and 5. `(other)`, when small-delta stable chunks exist. +There is no additional separator row before the aggregate rows. If no individual stable row exists, the empty row after `(total)` is therefore immediately followed by the aggregate rows. + The existing 30-row limit applies after small-delta rows have been removed from the individual-row candidates. ### Startup chunk report @@ -165,7 +165,8 @@ Add focused fixtures or pure-function tests covering: - differing before/after filenames are rendered without attributing both sizes to one file; - deltas of exactly `5 B` are grouped into `(other)`, while `6 B` deltas remain individual; - small updated, added, and removed chunks remain included in the summary counts; -- `(other generated chunks)` and `(other)` appear below individual rows after an empty separator row; and +- an empty separator row appears immediately after `(total)`, with no additional separator before `(other generated chunks)` or `(other)`; +- no generated-chunk grouping note is rendered below the table; and - the same small-delta and ordering rules apply to the full and startup tables. Validation should include the focused tests and repository lint. No CHANGELOG entry is required because this changes developer-facing CI reporting rather than Misskey user behavior. From 3c1f01af10f1c10849eb4016c539158ee1c2016c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 10:21:30 +0900 Subject: [PATCH 366/578] feat(dev): frontend browser metrics report (#17630) * wip * Update measure-frontend-browser-comparison.mts * Update frontend-browser-report.mts * Update frontend-browser-report.mts * Update frontend-browser-report.mts * Update frontend-browser-report.mts * Update frontend-browser-report.mts * Update frontend-browser-report.mts * Update frontend-browser-report.mts * refactor * fix * Update chrome.mts * refactor * wip * fix * Update frontend-browser-metrics-report.yml * Update frontend-browser-report.mts * refactor * wip * Update frontend-browser-report.mts * wip * wip * wip * Revert "wip" This reverts commit ce7657081bdd44393315d41a0c979b5527d879dd. * Update frontend-browser-metrics-report.yml * Update frontend-browser-report.mts * Update frontend-browser-report.mts * Update frontend-browser-report.mts * playwright * Update chrome.mts * refactor * wip * Update measure-frontend-browser-comparison.mts * clean up * Update measure-frontend-browser-comparison.mts * fix * Update chrome.mts * refactor * Update frontend-browser-metrics-report.yml --- .github/scripts/chrome.mts | 523 ++++++++++++++++++ .../frontend-browser-detailed-html.mts | 448 +++++++++++++++ .github/scripts/frontend-browser-report.mts | 378 +++++++++++++ .github/scripts/heap-snapshot-util.mts | 320 +++++++++++ .../measure-backend-memory-comparison.mts | 80 +-- .../measure-frontend-browser-comparison.mts | 274 +++++++++ .github/scripts/utility.mts | 94 +++- ...rontend-browser-metrics-report-comment.yml | 44 ++ .../frontend-browser-metrics-report.yml | 200 +++++++ packages/backend/scripts/measure-memory.mts | 246 +------- packages/frontend/test/e2e/basic.spec.ts | 12 +- packages/frontend/test/e2e/router.spec.ts | 7 +- packages/frontend/test/e2e/shared.ts | 135 +++++ packages/frontend/test/e2e/utils.ts | 94 +--- 14 files changed, 2456 insertions(+), 399 deletions(-) create mode 100644 .github/scripts/chrome.mts create mode 100644 .github/scripts/frontend-browser-detailed-html.mts create mode 100644 .github/scripts/frontend-browser-report.mts create mode 100644 .github/scripts/measure-frontend-browser-comparison.mts create mode 100644 .github/workflows/frontend-browser-metrics-report-comment.yml create mode 100644 .github/workflows/frontend-browser-metrics-report.yml create mode 100644 packages/frontend/test/e2e/shared.ts diff --git a/.github/scripts/chrome.mts b/.github/scripts/chrome.mts new file mode 100644 index 00000000000..5d07ac6efec --- /dev/null +++ b/.github/scripts/chrome.mts @@ -0,0 +1,523 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { createRequire } from 'node:module'; +import { writeFile } from 'node:fs/promises'; +import type { Browser, BrowserContext, CDPSession, Page } from 'playwright'; +import type { HeapSnapshotData } from './heap-snapshot-util.mts'; + +export type NetworkRequest = { + requestId: string; + url: string; + method: string; + resourceType: string; + startedAt: number; + documentUrl?: string; + requestHeaders?: Record; + requestBody?: string; + hasRequestBody: boolean; + status?: number; + statusText?: string; + mimeType?: string; + responseHeaders?: Record; + protocol?: string; + remoteIPAddress?: string; + remotePort?: number; + encodedDataLength: number; + decodedBodyLength: number; + fromDiskCache: boolean; + fromServiceWorker: boolean; + finished: boolean; + failed: boolean; + errorText?: string; +}; + +export type WebSocketConnection = { + requestId: string; + url: string; + createdAt: number; + handshakeRequestHeaders?: Record; + handshakeResponseStatus?: number; + handshakeResponseStatusText?: string; + handshakeResponseHeaders?: Record; + closedAt?: number; + sentFrameCount: number; + receivedFrameCount: number; + sentBytes: number; + receivedBytes: number; + errorCount: number; +}; + +export type NetworkSummary = { + requestCount: number; + webSocketConnectionCount: number; + webSocketSentBytes: number; + webSocketReceivedBytes: number; + finishedRequestCount: number; + failedRequestCount: number; + cachedRequestCount: number; + serviceWorkerRequestCount: number; + totalEncodedBytes: number; + totalDecodedBodyBytes: number; + sameOriginEncodedBytes: number; + thirdPartyEncodedBytes: number; + byResourceType: Record; + largestRequests: { + url: string; + method: string; + resourceType: string; + status?: number; + encodedBytes: number; + decodedBodyBytes: number; + }[]; + failedRequests: { + url: string; + method: string; + resourceType: string; + errorText?: string; + status?: number; + }[]; +}; + +export type TabMemory = { + totalBytes: number; +}; + +export type BrowserMeasurement = { + label: string; + timestamp: string; + url: string; + scenario: string; + durationMs: number; + network: NetworkSummary; + performance: { + cdpMetrics: Record; + runtimeHeap?: { + usedSize: number; + totalSize: number; + }; + tabMemory: TabMemory; + webVitals: { + firstPaintMs?: number; + firstContentfulPaintMs?: number; + domContentLoadedEventEndMs?: number; + loadEventEndMs?: number; + longTaskCount: number; + longTaskDurationMs: number; + maxLongTaskDurationMs: number; + resourceEntryCount: number; + domElements: number; + }; + }; + heapSnapshot: HeapSnapshotData; +}; + +type PlaywrightModule = typeof import('playwright'); + +const requireFromFrontend = createRequire(new URL('../../packages/frontend/package.json', import.meta.url)); + +function loadPlaywright(): PlaywrightModule { + return requireFromFrontend('playwright') as PlaywrightModule; +} + +function normalizeHeaders(headers: Record | undefined) { + if (headers == null) return undefined; + const normalized = {} as Record; + for (const [key, value] of Object.entries(headers)) { + normalized[key] = String(value); + } + return normalized; +} + +function webSocketFramePayloadBytes(frame: { opcode?: number; payloadData?: string } | undefined) { + if (frame?.payloadData == null) return 0; + if (frame.opcode === 1) return Buffer.byteLength(frame.payloadData, 'utf8'); + return Buffer.byteLength(frame.payloadData, 'base64'); +} + +type PlaywrightBrowserOptions = { + scenarioTimeoutMs: number; + baseUrl: string; +}; + +export class HeadlessChromeController { + public networkRequests: NetworkRequest[] = []; + public webSocketConnections: WebSocketConnection[] = []; + private readonly browser: Browser; + private readonly context: BrowserContext; + public readonly page: Page; + private readonly cdp: CDPSession; + private pendingNetworkDetailReads: Promise[] = []; + + private constructor( + browser: Browser, + context: BrowserContext, + page: Page, + cdp: CDPSession, + options: PlaywrightBrowserOptions, + ) { + this.browser = browser; + this.context = context; + this.page = page; + this.cdp = cdp; + this.page.setDefaultTimeout(options.scenarioTimeoutMs); + this.page.setDefaultNavigationTimeout(options.scenarioTimeoutMs); + } + + static async create(label: string, options: PlaywrightBrowserOptions): Promise { + process.stderr.write(`[${label}] Launching Playwright Chromium\n`); + const { chromium } = loadPlaywright(); + const browser = await chromium.launch({ + channel: 'chromium', + headless: true, + args: [ + '--disable-gpu', + '--disable-dev-shm-usage', + '--disable-background-networking', + '--disable-default-apps', + '--disable-extensions', + '--disable-sync', + '--metrics-recording-only', + '--no-first-run', + '--no-default-browser-check', + '--no-sandbox', + ], + }); + + try { + const context = await browser.newContext({ + baseURL: options.baseUrl, + locale: 'en-US', + }); + await context.addInitScript(() => { + // @ts-expect-error Test-only runtime hint consumed by Misskey frontend code. + window.isPlaywright = true; + }); + + const page = await context.newPage(); + const cdp = await context.newCDPSession(page); + return new HeadlessChromeController(browser, context, page, cdp, options); + } catch (error) { + await browser.close().catch(() => undefined); + throw error; + } + } + + static async with(label: string, options: PlaywrightBrowserOptions, callback: (browser: HeadlessChromeController) => T | Promise): Promise { + const browser = await HeadlessChromeController.create(label, options); + try { + return await callback(browser); + } finally { + await browser.close(); + } + } + + public async enableNetworkTracking() { + const requests = new Map(); + const webSockets = new Map(); + + const readRequestBody = (row: NetworkRequest) => { + if (!row.hasRequestBody || row.requestBody != null) return; + const pending = this.cdp.send<{ postData: string }>('Network.getRequestPostData', { + requestId: row.requestId, + }).then(result => { + row.requestBody = result.postData; + }).catch(() => { + // Some requests expose hasPostData but no longer have retrievable body data. + }); + this.pendingNetworkDetailReads.push(pending); + }; + + this.cdp.on('Network.requestWillBeSent', params => { + if (params.request?.url == null) return; + const row: NetworkRequest = { + requestId: params.requestId, + url: params.request.url, + method: params.request.method ?? 'GET', + resourceType: params.type ?? 'Other', + startedAt: params.timestamp ?? 0, + documentUrl: params.documentURL, + requestHeaders: normalizeHeaders(params.request.headers), + requestBody: typeof params.request.postData === 'string' ? params.request.postData : undefined, + hasRequestBody: params.request.hasPostData === true || typeof params.request.postData === 'string', + encodedDataLength: 0, + decodedBodyLength: 0, + fromDiskCache: false, + fromServiceWorker: false, + finished: false, + failed: false, + }; + requests.set(params.requestId, row); + this.networkRequests.push(row); + }); + + this.cdp.on('Network.webSocketCreated', params => { + if (params.requestId == null || params.url == null) return; + const row: WebSocketConnection = { + requestId: params.requestId, + url: params.url, + createdAt: params.timestamp ?? 0, + sentFrameCount: 0, + receivedFrameCount: 0, + sentBytes: 0, + receivedBytes: 0, + errorCount: 0, + }; + webSockets.set(params.requestId, row); + this.webSocketConnections.push(row); + }); + + this.cdp.on('Network.webSocketWillSendHandshakeRequest', params => { + const row = webSockets.get(params.requestId); + if (row == null) return; + row.handshakeRequestHeaders = normalizeHeaders(params.request?.headers); + }); + + this.cdp.on('Network.webSocketHandshakeResponseReceived', params => { + const row = webSockets.get(params.requestId); + if (row == null) return; + row.handshakeResponseStatus = params.response?.status; + row.handshakeResponseStatusText = params.response?.statusText; + row.handshakeResponseHeaders = normalizeHeaders(params.response?.headers); + }); + + this.cdp.on('Network.webSocketFrameSent', params => { + const row = webSockets.get(params.requestId); + if (row == null) return; + row.sentFrameCount += 1; + row.sentBytes += webSocketFramePayloadBytes(params.response); + }); + + this.cdp.on('Network.webSocketFrameReceived', params => { + const row = webSockets.get(params.requestId); + if (row == null) return; + row.receivedFrameCount += 1; + row.receivedBytes += webSocketFramePayloadBytes(params.response); + }); + + this.cdp.on('Network.webSocketFrameError', params => { + const row = webSockets.get(params.requestId); + if (row == null) return; + row.errorCount += 1; + }); + + this.cdp.on('Network.webSocketClosed', params => { + const row = webSockets.get(params.requestId); + if (row == null) return; + row.closedAt = params.timestamp ?? 0; + }); + + this.cdp.on('Network.responseReceived', params => { + const row = requests.get(params.requestId); + if (row == null) return; + row.status = params.response?.status; + row.statusText = params.response?.statusText; + row.mimeType = params.response?.mimeType; + row.responseHeaders = normalizeHeaders(params.response?.headers); + row.protocol = params.response?.protocol; + row.remoteIPAddress = params.response?.remoteIPAddress; + row.remotePort = params.response?.remotePort; + row.requestHeaders ??= normalizeHeaders(params.response?.requestHeaders); + row.fromDiskCache = params.response?.fromDiskCache === true; + row.fromServiceWorker = params.response?.fromServiceWorker === true; + }); + + this.cdp.on('Network.dataReceived', params => { + const row = requests.get(params.requestId); + if (row == null) return; + row.decodedBodyLength += params.dataLength ?? 0; + row.encodedDataLength += params.encodedDataLength ?? 0; + }); + + this.cdp.on('Network.loadingFinished', params => { + const row = requests.get(params.requestId); + if (row == null) return; + row.finished = true; + row.encodedDataLength = Math.max(row.encodedDataLength, params.encodedDataLength ?? 0); + readRequestBody(row); + }); + + this.cdp.on('Network.loadingFailed', params => { + const row = requests.get(params.requestId); + if (row == null) return; + row.failed = true; + row.finished = true; + row.errorText = params.errorText; + readRequestBody(row); + }); + + await this.cdp.send('Network.enable'); + await this.cdp.send('Network.setCacheDisabled', { cacheDisabled: true }); + await this.cdp.send('Network.setBypassServiceWorker', { bypass: true }); + await this.cdp.send('Page.enable'); + await this.cdp.send('Runtime.enable'); + await this.cdp.send('Performance.enable'); + } + + public async waitForNetworkDetails() { + let settledCount = 0; + while (settledCount < this.pendingNetworkDetailReads.length) { + const pending = this.pendingNetworkDetailReads.slice(settledCount); + settledCount = this.pendingNetworkDetailReads.length; + await Promise.allSettled(pending); + } + } + + public async evaluate(expression: string, timeoutMs = 30_000): Promise { + return await Promise.race([ + this.page.evaluate(expression), + new Promise((_, reject) => setTimeout(() => reject(new Error(`Playwright evaluate timed out after ${timeoutMs}ms`)), timeoutMs).unref()), + ]) as T; + } + + public async collectPerformance(): Promise { + const cdpMetricsResult = await this.cdp.send<{ metrics: { name: string; value: number }[] }>('Performance.getMetrics'); + const cdpMetrics = Object.fromEntries(cdpMetricsResult.metrics.map(metric => [metric.name, metric.value])); + const runtimeHeap = await this.cdp.send<{ usedSize: number; totalSize: number }>('Runtime.getHeapUsage').catch(() => undefined); + const tabMemory = await this.collectTabMemory(); + const webVitals = await this.evaluate(`(() => { + const navigation = performance.getEntriesByType('navigation')[0]; + const paintEntries = Object.fromEntries(performance.getEntriesByType('paint').map(entry => [entry.name, entry.startTime])); + const longTasks = performance.getEntriesByType('longtask'); + const resourceEntries = performance.getEntriesByType('resource'); + return { + firstPaintMs: paintEntries['first-paint'], + firstContentfulPaintMs: paintEntries['first-contentful-paint'], + domContentLoadedEventEndMs: navigation?.domContentLoadedEventEnd, + loadEventEndMs: navigation?.loadEventEnd, + longTaskCount: longTasks.length, + longTaskDurationMs: longTasks.reduce((sum, entry) => sum + entry.duration, 0), + maxLongTaskDurationMs: longTasks.reduce((max, entry) => Math.max(max, entry.duration), 0), + resourceEntryCount: resourceEntries.length, + domElements: document.getElementsByTagName('*').length, + }; + })()`); + + return { + cdpMetrics, + runtimeHeap, + tabMemory, + webVitals, + }; + } + + public async collectTabMemory(): Promise { + const userAgentSpecificMemory = await this.evaluate<{ bytes?: number }>(`(async () => { + const measureMemory = performance.measureUserAgentSpecificMemory; + if (typeof measureMemory !== 'function') return {}; + const result = await measureMemory.call(performance); + return { bytes: result.bytes }; + })()`, 60_000); + + const userAgentSpecificBytes = userAgentSpecificMemory?.bytes; + if (!Number.isFinite(userAgentSpecificBytes)) { + throw new Error('performance.measureUserAgentSpecificMemory() did not return finite bytes'); + } + + return { + totalBytes: userAgentSpecificBytes as number, + }; + } + + public async takeHeapSnapshot(savePath?: string) { + const chunks: string[] = []; + this.cdp.on('HeapProfiler.addHeapSnapshotChunk', params => { + chunks.push(params.chunk); + }); + + await this.cdp.send('HeapProfiler.enable'); + await this.cdp.send('HeapProfiler.collectGarbage'); + await this.cdp.send('HeapProfiler.takeHeapSnapshot', { reportProgress: false }); + + const content = chunks.join(''); + if (savePath != null) { + await writeFile(savePath, content); + } + + return JSON.parse(content); + } + + public async close() { + await this.cdp.detach().catch(() => undefined); + await this.context.close().catch(() => undefined); + await this.browser.close().catch(() => undefined); + } +} + +function isMeasurableRequest(row: NetworkRequest) { + return !row.url.startsWith('data:') && !row.url.startsWith('blob:') && !row.url.startsWith('devtools:'); +} + +export function summarizeNetwork(requestRows: NetworkRequest[], baseUrl: string, webSocketRows?: WebSocketConnection[]): NetworkSummary { + const origin = new URL(baseUrl).origin; + const rows = requestRows.filter(isMeasurableRequest); + const byResourceType = {} as NetworkSummary['byResourceType']; + + for (const row of rows) { + const summary = byResourceType[row.resourceType] ?? { + requests: 0, + encodedBytes: 0, + decodedBodyBytes: 0, + }; + summary.requests += 1; + summary.encodedBytes += row.encodedDataLength; + summary.decodedBodyBytes += row.decodedBodyLength; + byResourceType[row.resourceType] = summary; + } + + function isSameOrigin(url: string) { + try { + return new URL(url).origin === origin; + } catch { + return false; + } + } + + return { + requestCount: rows.length, + webSocketConnectionCount: webSocketRows == null + ? rows.filter(row => row.resourceType === 'WebSocket').length + : webSocketRows.length, + webSocketSentBytes: webSocketRows?.reduce((sum, row) => sum + row.sentBytes, 0) ?? 0, + webSocketReceivedBytes: webSocketRows?.reduce((sum, row) => sum + row.receivedBytes, 0) ?? 0, + finishedRequestCount: rows.filter(row => row.finished).length, + failedRequestCount: rows.filter(row => row.failed).length, + cachedRequestCount: rows.filter(row => row.fromDiskCache).length, + serviceWorkerRequestCount: rows.filter(row => row.fromServiceWorker).length, + totalEncodedBytes: rows.reduce((sum, row) => sum + row.encodedDataLength, 0), + totalDecodedBodyBytes: rows.reduce((sum, row) => sum + row.decodedBodyLength, 0), + sameOriginEncodedBytes: rows + .filter(row => isSameOrigin(row.url)) + .reduce((sum, row) => sum + row.encodedDataLength, 0), + thirdPartyEncodedBytes: rows + .filter(row => !isSameOrigin(row.url)) + .reduce((sum, row) => sum + row.encodedDataLength, 0), + byResourceType, + largestRequests: rows + .toSorted((a, b) => b.encodedDataLength - a.encodedDataLength) + .slice(0, 15) + .map(row => ({ + url: row.url, + method: row.method, + resourceType: row.resourceType, + status: row.status, + encodedBytes: row.encodedDataLength, + decodedBodyBytes: row.decodedBodyLength, + })), + failedRequests: rows + .filter(row => row.failed) + .map(row => ({ + url: row.url, + method: row.method, + resourceType: row.resourceType, + errorText: row.errorText, + status: row.status, + })), + }; +} diff --git a/.github/scripts/frontend-browser-detailed-html.mts b/.github/scripts/frontend-browser-detailed-html.mts new file mode 100644 index 00000000000..34240eefc65 --- /dev/null +++ b/.github/scripts/frontend-browser-detailed-html.mts @@ -0,0 +1,448 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { readFile, writeFile } from 'node:fs/promises'; +import { pathToFileURL } from 'node:url'; +import * as util from './utility.mts'; +import type { BrowserMeasurementSample, BrowserMetricsReport } from './frontend-browser-report.mts'; +import type { NetworkRequest } from './chrome.mts'; + +type DiffDirection = 'added' | 'removed'; + +type RequestDiff = { + direction: DiffDirection; + round: number; + baseCount: number; + headCount: number; + request: NetworkRequest; +}; + +function escapeHtml(value: unknown) { + return String(value ?? '') + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + +function escapeAttribute(value: unknown) { + return escapeHtml(value); +} + +function isHttpRequest(request: NetworkRequest) { + try { + const { protocol } = new URL(request.url); + return protocol === 'http:' || protocol === 'https:'; + } catch { + return false; + } +} + +function requestKey(request: NetworkRequest) { + return [ + request.method, + request.resourceType, + request.url, + ].join('\u0000'); +} + +function groupRequests(requests: NetworkRequest[] | undefined) { + const grouped = new Map(); + for (const request of requests ?? []) { + if (!isHttpRequest(request)) continue; + const key = requestKey(request); + const rows = grouped.get(key) ?? []; + rows.push(request); + grouped.set(key, rows); + } + return grouped; +} + +function byRound(samples: BrowserMeasurementSample[]) { + return new Map(samples.map(sample => [sample.round, sample])); +} + +function diffRound(round: number, baseSample: BrowserMeasurementSample | undefined, headSample: BrowserMeasurementSample | undefined) { + const baseRequests = groupRequests(baseSample?.networkRequests); + const headRequests = groupRequests(headSample?.networkRequests); + const keys = [...new Set([ + ...baseRequests.keys(), + ...headRequests.keys(), + ])].toSorted(); + const diffs: RequestDiff[] = []; + + for (const key of keys) { + const baseRows = baseRequests.get(key) ?? []; + const headRows = headRequests.get(key) ?? []; + if (headRows.length > baseRows.length) { + for (const request of headRows.slice(baseRows.length)) { + diffs.push({ + direction: 'added', + round, + baseCount: baseRows.length, + headCount: headRows.length, + request, + }); + } + } else if (baseRows.length > headRows.length) { + for (const request of baseRows.slice(headRows.length)) { + diffs.push({ + direction: 'removed', + round, + baseCount: baseRows.length, + headCount: headRows.length, + request, + }); + } + } + } + + return diffs; +} + +function diffReports(base: BrowserMetricsReport, head: BrowserMetricsReport) { + const baseSamples = byRound(base.samples); + const headSamples = byRound(head.samples); + const rounds = [...new Set([ + ...baseSamples.keys(), + ...headSamples.keys(), + ])].toSorted((a, b) => a - b); + return rounds.flatMap(round => diffRound(round, baseSamples.get(round), headSamples.get(round))); +} + +function formatMaybeJson(value: string | undefined) { + if (value == null || value === '') return null; + try { + return JSON.stringify(JSON.parse(value), null, '\t'); + } catch { + return value; + } +} + +function formatHeaders(headers: Record | undefined) { + if (headers == null || Object.keys(headers).length === 0) return null; + return JSON.stringify(headers, null, '\t'); +} + +function countBy(diffs: RequestDiff[], getKey: (diff: RequestDiff) => T) { + const counts = new Map(); + for (const diff of diffs) { + counts.set(getKey(diff), (counts.get(getKey(diff)) ?? 0) + 1); + } + return [...counts].toSorted((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])); +} + +function renderSummary(base: BrowserMetricsReport, head: BrowserMetricsReport, diffs: RequestDiff[]) { + const added = diffs.filter(diff => diff.direction === 'added').length; + const removed = diffs.filter(diff => diff.direction === 'removed').length; + const typeRows = countBy(diffs, diff => diff.request.resourceType).map(([type, count]) => ` + + ${escapeHtml(type)} + ${util.formatNumber(count)} + `).join(''); + + return ` +
+
+ Base samples + ${util.formatNumber(base.sampleCount)} +
+
+ Head samples + ${util.formatNumber(head.sampleCount)} +
+
+ Added in Head + ${util.formatNumber(added)} +
+
+ Removed in Head + ${util.formatNumber(removed)} +
+
+ ${typeRows === '' ? '' : ` +
+

Diffs by Resource Type

+ + + ${typeRows} + +
TypeDiff requests
+
`}`; +} + +function renderDetails(title: string, content: string | null, open = false) { + if (content == null || content === '') return ''; + return ` + + ${escapeHtml(title)} +
${escapeHtml(content)}
+
`; +} + +function renderRequest(diff: RequestDiff) { + const { request } = diff; + const requestBody = formatMaybeJson(request.requestBody); + const requestHeaders = formatHeaders(request.requestHeaders); + const responseHeaders = formatHeaders(request.responseHeaders); + const bodyNote = requestBody == null && request.hasRequestBody === true + ? '

Request body was present but could not be retrieved from CDP.

' + : ''; + + return ` +
+
+ ${diff.direction === 'added' ? 'Added in Head' : 'Removed in Head'} + ${escapeHtml(request.method)} + ${escapeHtml(request.resourceType)} + ${escapeHtml(request.status ?? '-')} +
+ ${escapeHtml(request.url)} +
+
Round
${util.formatNumber(diff.round)}
+
Base count
${util.formatNumber(diff.baseCount)}
+
Head count
${util.formatNumber(diff.headCount)}
+
Encoded
${util.formatBytes(request.encodedDataLength ?? 0)}
+
Decoded body
${util.formatBytes(request.decodedBodyLength ?? 0)}
+
MIME
${escapeHtml(request.mimeType ?? '-')}
+
Protocol
${escapeHtml(request.protocol ?? '-')}
+
Remote
${escapeHtml(request.remoteIPAddress == null ? '-' : `${request.remoteIPAddress}:${request.remotePort ?? ''}`)}
+
Failed
${request.failed ? escapeHtml(request.errorText ?? 'yes') : 'no'}
+
+ ${bodyNote} + ${renderDetails('Request body', requestBody, requestBody != null)} + ${renderDetails('Request headers', requestHeaders)} + ${renderDetails('Response headers', responseHeaders)} +
`; +} + +function renderRound(round: number, diffs: RequestDiff[]) { + const added = diffs.filter(diff => diff.direction === 'added').length; + const removed = diffs.filter(diff => diff.direction === 'removed').length; + return ` +
+

Round ${util.formatNumber(round)}

+

${util.formatNumber(added)} added, ${util.formatNumber(removed)} removed

+
+ ${diffs.map(renderRequest).join('\n')} +
+
`; +} + +function renderHtml(base: BrowserMetricsReport, head: BrowserMetricsReport) { + const diffs = diffReports(base, head); + const rounds = [...new Set(diffs.map(diff => diff.round))].toSorted((a, b) => a - b); + const generatedAt = new Date().toISOString(); + const content = diffs.length === 0 + ? '

No added or removed HTTP(S) requests were found in paired samples.

' + : rounds.map(round => renderRound(round, diffs.filter(diff => diff.round === round))).join('\n'); + + return ` + + + + + Frontend Browser Network Request Diff + + + +
+

Frontend Browser Network Request Diff

+

Generated at ${escapeHtml(generatedAt)}. Requests are compared per paired round by method, resource type, and exact URL. Bodies are shown for added/removed request instances when CDP exposes them.

+ ${renderSummary(base, head, diffs)} + ${content} +
+ + +`; +} + +async function main() { + const [baseFile, headFile, outputFile] = process.argv.slice(2); + if (baseFile == null || headFile == null || outputFile == null) { + throw new Error('Usage: node frontend-browser-detailed-html.mts '); + } + + const base = JSON.parse(await readFile(baseFile, 'utf8')) as BrowserMetricsReport; + const head = JSON.parse(await readFile(headFile, 'utf8')) as BrowserMetricsReport; + await writeFile(outputFile, renderHtml(base, head)); +} + +if (process.argv[1] != null && import.meta.url === pathToFileURL(process.argv[1]).href) { + await main(); +} diff --git a/.github/scripts/frontend-browser-report.mts b/.github/scripts/frontend-browser-report.mts new file mode 100644 index 00000000000..755b29bc884 --- /dev/null +++ b/.github/scripts/frontend-browser-report.mts @@ -0,0 +1,378 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { readFile, writeFile } from 'node:fs/promises'; +import { pathToFileURL } from 'node:url'; +import * as util from './utility.mts'; +import * as heapSnapshotUtil from './heap-snapshot-util.mts'; +import type { HeapSnapshotData, HeapSnapshotReport } from './heap-snapshot-util.mts'; +import type { NetworkRequest } from './chrome.mts'; + +export type BrowserMeasurement = { + label: string; + timestamp: string; + url: string; + scenario: string; + durationMs: number; + network: { + requestCount: number; + webSocketConnectionCount: number; + webSocketSentBytes: number; + webSocketReceivedBytes: number; + finishedRequestCount: number; + failedRequestCount: number; + cachedRequestCount: number; + serviceWorkerRequestCount: number; + totalEncodedBytes: number; + totalDecodedBodyBytes: number; + sameOriginEncodedBytes: number; + thirdPartyEncodedBytes: number; + byResourceType: Record; + largestRequests: { + url: string; + method: string; + resourceType: string; + status?: number; + encodedBytes: number; + decodedBodyBytes: number; + }[]; + failedRequests: { + url: string; + method: string; + resourceType: string; + errorText?: string; + status?: number; + }[]; + }; + performance: { + cdpMetrics: Record; + runtimeHeap?: { + usedSize: number; + totalSize: number; + }; + tabMemory: { + totalBytes: number; + }; + webVitals: { + firstPaintMs?: number; + firstContentfulPaintMs?: number; + domContentLoadedEventEndMs?: number; + loadEventEndMs?: number; + longTaskCount: number; + longTaskDurationMs: number; + maxLongTaskDurationMs: number; + resourceEntryCount: number; + domElements: number; + }; + }; + heapSnapshot: HeapSnapshotData; +}; + +export type BrowserMeasurementSample = BrowserMeasurement & { + round: number; + networkRequests?: NetworkRequest[]; +}; + +export type BrowserMetricsReport = { + label: string; + timestamp: string; + url: string; + scenario: string; + sampleCount: number; + aggregation: 'median'; + summary: BrowserMeasurement; + samples: BrowserMeasurementSample[]; +}; + +function escapeCell(value: string) { + return String(value).replaceAll('|', '\\|').replaceAll('\n', '
'); +} + +function truncate(value: string, maxLength = 140) { + if (value.length <= maxLength) return value; + return `${value.slice(0, maxLength - 3)}...`; +} + +function formatMs(value: number | null | undefined) { + if (value == null || !Number.isFinite(value)) return '-'; + if (value >= 1_000) return `${util.formatNumber(value / 1_000)} s`; + return `${util.formatNumber(value)} ms`; +} + +function formatSecondsAsMs(value: number | null | undefined) { + if (value == null || !Number.isFinite(value)) return '-'; + return formatMs(value * 1_000); +} + +function formatDelta(delta: number, formatter: (value: number) => string, colorThreshold = 0) { + if (delta === 0) return formatter(0); + return util.formatColoredDelta(delta, v => formatter(v), colorThreshold); +} + +function finiteValues(values: (number | null | undefined)[]) { + return values.filter(value => Number.isFinite(value)) as number[]; +} + +function sampleSpread(report: BrowserMetricsReport, getValue: (sample: BrowserMeasurementSample) => number | null | undefined) { + const values = finiteValues(report.samples.map(sample => getValue(sample))); + if (values.length < 2) return null; + + const center = util.median(values); + return util.median(values.map(value => Math.abs(value - center))); +} + +function formatValueWithSpread(report: BrowserMetricsReport, value: number, getSampleValue: (sample: BrowserMeasurementSample) => number | null | undefined, formatter: (value: number) => string) { + const spread = sampleSpread(report, getSampleValue); + if (spread == null) return formatter(value); + return `${formatter(value)}
± ${formatter(spread)}`; +} + +function metricRow( + label: string, + base: BrowserMetricsReport, + head: BrowserMetricsReport, + getSummaryValue: (summary: BrowserMeasurement) => number, + getSampleValue: (sample: BrowserMeasurementSample) => number, + formatter: (value: number) => string, + significantThreshold = 0, + skipIfNotSignificant = true +) { + const baseValue = getSummaryValue(base.summary); + const headValue = getSummaryValue(head.summary); + if (baseValue == null || headValue == null || !Number.isFinite(baseValue) || !Number.isFinite(headValue)) return null; + + const summary = util.pairedDeltaSummary(base.samples, head.samples, sample => getSampleValue(sample)); + // 有��閾値�満���場���も�もrow���出力��� + if (skipIfNotSignificant && (Math.abs(summary.median) < significantThreshold)) return null; + + const percent = baseValue === 0 ? null : summary.median * 100 / baseValue; + //const deltaMedian = `${formatDelta(summary.median, formatter, colorThreshold)}
${percent == null ? '-' : util.formatDeltaPercent(percent, 0.1).replaceAll('\\%', '\\\\%')}`; + const deltaMedian = formatDelta(summary.median, formatter, significantThreshold); + + //return `| **${label}** | ${formatValueWithSpread(base, baseValue, getSampleValue, formatter)} | ${formatValueWithSpread(head, headValue, getSampleValue, formatter)} | ${deltaMedian} | ${summary == null ? '-' : formatter(summary.mad)} | ${summary == null ? '-' : formatDelta(summary.min, formatter)} | ${summary == null ? '-' : formatDelta(summary.max, formatter)} |`; + return `| **${label}** | ${formatter(baseValue)} | ${formatter(headValue)} | ${deltaMedian} | ${summary == null ? '-' : formatter(summary.mad)} | ${summary == null ? '-' : formatDelta(summary.min, formatter, significantThreshold)} | ${summary == null ? '-' : formatDelta(summary.max, formatter, significantThreshold)} |`; +} + +function resourceTypeBytes(report: BrowserMeasurement, resourceTypes: string[]) { + return resourceTypes.reduce((sum, resourceType) => sum + (report.network.byResourceType[resourceType]?.encodedBytes ?? 0), 0); +} + +function resourceTypeSampleBytes(sample: BrowserMeasurementSample, resourceTypes: string[]) { + return resourceTypeBytes(sample, resourceTypes); +} + +function getMetric(report: BrowserMeasurement, key: string) { + return report.performance.cdpMetrics[key]; +} + +function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { + const rows = [ + //metricRow('Scenario duration', base, head, summary => summary.durationMs, sample => sample.durationMs, formatMs), + metricRow('Requests', base, head, summary => summary.network.requestCount, sample => sample.network.requestCount, util.formatNumber, 1, !all), + //metricRow('Failed requests', base, head, summary => summary.network.failedRequestCount, sample => sample.network.failedRequestCount, util.formatNumber), + metricRow('Encoded network', base, head, summary => summary.network.totalEncodedBytes, sample => sample.network.totalEncodedBytes, util.formatBytes, 10000, !all), + metricRow('Decoded body', base, head, summary => summary.network.totalDecodedBodyBytes, sample => sample.network.totalDecodedBodyBytes, util.formatBytes, 10000, !all), + metricRow('Same-origin encoded', base, head, summary => summary.network.sameOriginEncodedBytes, sample => sample.network.sameOriginEncodedBytes, util.formatBytes, 10000, !all), + metricRow('Third-party encoded', base, head, summary => summary.network.thirdPartyEncodedBytes, sample => sample.network.thirdPartyEncodedBytes, util.formatBytes, 10000, !all), + metricRow('Script encoded', base, head, summary => resourceTypeBytes(summary, ['Script']), sample => resourceTypeSampleBytes(sample, ['Script']), util.formatBytes, 10000, !all), + metricRow('Stylesheet encoded', base, head, summary => resourceTypeBytes(summary, ['Stylesheet']), sample => resourceTypeSampleBytes(sample, ['Stylesheet']), util.formatBytes, 10000, !all), + metricRow('Fetch/XHR encoded', base, head, summary => resourceTypeBytes(summary, ['Fetch', 'XHR']), sample => resourceTypeSampleBytes(sample, ['Fetch', 'XHR']), util.formatBytes, 10000, !all), + metricRow('Image encoded', base, head, summary => resourceTypeBytes(summary, ['Image']), sample => resourceTypeSampleBytes(sample, ['Image']), util.formatBytes, 10000, !all), + metricRow('Font encoded', base, head, summary => resourceTypeBytes(summary, ['Font']), sample => resourceTypeSampleBytes(sample, ['Font']), util.formatBytes, 10000, !all), + //metricRow('First contentful paint', base, head, summary => summary.performance.webVitals.firstContentfulPaintMs, sample => sample.performance.webVitals.firstContentfulPaintMs, formatMs), + //metricRow('Load event end', base, head, summary => summary.performance.webVitals.loadEventEndMs, sample => sample.performance.webVitals.loadEventEndMs, formatMs), + //metricRow('Long tasks', base, head, summary => summary.performance.webVitals.longTaskCount, sample => sample.performance.webVitals.longTaskCount, util.formatNumber), + //metricRow('Long task duration', base, head, summary => summary.performance.webVitals.longTaskDurationMs, sample => sample.performance.webVitals.longTaskDurationMs, formatMs), + //metricRow('Max long task', base, head, summary => summary.performance.webVitals.maxLongTaskDurationMs, sample => sample.performance.webVitals.maxLongTaskDurationMs, formatMs), + //metricRow('JS heap used', base, head, summary => summary.performance.runtimeHeap?.usedSize ?? getMetric(summary, 'JSHeapUsedSize'), sample => sample.performance.runtimeHeap?.usedSize ?? getMetric(sample, 'JSHeapUsedSize'), util.formatBytes), + //metricRow('JS heap total', base, head, summary => summary.performance.runtimeHeap?.totalSize ?? getMetric(summary, 'JSHeapTotalSize'), sample => sample.performance.runtimeHeap?.totalSize ?? getMetric(sample, 'JSHeapTotalSize'), util.formatBytes), + //metricRow('V8 heap snapshot total', base, head, summary => summary.heapSnapshot.categories.total, sample => sample.heapSnapshot.categories.total, util.formatBytes, 10000), + //metricRow('DOM elements', base, head, summary => summary.performance.webVitals.domElements, sample => sample.performance.webVitals.domElements, util.formatNumber), + //metricRow('CDP nodes', base, head, summary => getMetric(summary, 'Nodes'), sample => getMetric(sample, 'Nodes'), util.formatNumber), + //metricRow('JS event listeners', base, head, summary => getMetric(summary, 'JSEventListeners'), sample => getMetric(sample, 'JSEventListeners'), util.formatNumber), + //metricRow('Layout count', base, head, summary => getMetric(summary, 'LayoutCount'), sample => getMetric(sample, 'LayoutCount'), util.formatNumber), + //metricRow('Recalc style count', base, head, summary => getMetric(summary, 'RecalcStyleCount'), sample => getMetric(sample, 'RecalcStyleCount'), util.formatNumber), + //metricRow('Script duration', base, head, summary => getMetric(summary, 'ScriptDuration'), sample => getMetric(sample, 'ScriptDuration'), formatSecondsAsMs), + //metricRow('Task duration', base, head, summary => getMetric(summary, 'TaskDuration'), sample => getMetric(sample, 'TaskDuration'), formatSecondsAsMs), + metricRow('WebSocket connections', base, head, summary => summary.network.webSocketConnectionCount, sample => sample.network.webSocketConnectionCount, util.formatNumber, 1, !all), + metricRow('WebSocket sent', base, head, summary => summary.network.webSocketSentBytes, sample => sample.network.webSocketSentBytes, util.formatBytes, 10000, !all), + metricRow('WebSocket received', base, head, summary => summary.network.webSocketReceivedBytes, sample => sample.network.webSocketReceivedBytes, util.formatBytes, 10000, !all), + metricRow('Tab memory', base, head, summary => summary.performance.tabMemory.totalBytes, sample => sample.performance.tabMemory.totalBytes, util.formatBytes, 10000, !all), + ].filter(row => row != null); + + return [ + '| Metric | Base | Head | Δ median | Δ MAD | Δ min | Δ max |', + '| --- | ---: | ---: | ---: | ---: | ---: | ---: |', + ...rows, + ].join('\n'); +} + +function renderResourceTypeTable(base: BrowserMetricsReport, head: BrowserMetricsReport) { + const preferredOrder = ['Document', 'Script', 'Stylesheet', 'Fetch', 'XHR', 'Image', 'Font', 'Media', 'WebSocket', 'EventSource', 'Other']; + const keys = [...new Set([ + ...preferredOrder, + ...Object.keys(base.summary.network.byResourceType), + ...Object.keys(head.summary.network.byResourceType), + ])].filter(key => base.summary.network.byResourceType[key] != null || head.summary.network.byResourceType[key] != null); + + const lines = [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + ]; + + for (const key of keys) { + const baseRow = base.summary.network.byResourceType[key] ?? { requests: 0, encodedBytes: 0 }; + const headRow = head.summary.network.byResourceType[key] ?? { requests: 0, encodedBytes: 0 }; + lines.push(''); + lines.push(``); + lines.push(``); + lines.push(``); + lines.push(``); + lines.push(``); + lines.push(``); + lines.push(``); + lines.push(''); + } + + lines.push(''); + lines.push('
TypeRequestsEncoded bytes
BaseHeadΔBaseHeadΔ
${key}${util.formatNumber(baseRow.requests)}${util.formatNumber(headRow.requests)}${formatDelta(headRow.requests - baseRow.requests, util.formatNumber)}${util.formatBytes(baseRow.encodedBytes)}${util.formatBytes(headRow.encodedBytes)}${formatDelta(headRow.encodedBytes - baseRow.encodedBytes, util.formatBytes)}
'); + + return lines.join('\n'); +} + +function renderLargestRequests(report: BrowserMetricsReport, title: string) { + if (report.summary.network.largestRequests.length === 0) return null; + + const lines = [ + `
${title}`, + '', + '| Resource | Type | Status | Encoded | Decoded |', + '| --- | --- | ---: | ---: | ---: |', + ]; + + for (const request of report.summary.network.largestRequests.slice(0, 10)) { + lines.push(`| \`${escapeCell(truncate(request.url))}\` | ${escapeCell(request.resourceType)} | ${request.status ?? '-'} | ${util.formatBytes(request.encodedBytes)} | ${util.formatBytes(request.decodedBodyBytes)} |`); + } + + lines.push('', '
'); + return lines.join('\n'); +} + +function renderFailedRequests(report: BrowserMetricsReport, title: string) { + if (report.summary.network.failedRequests.length === 0) return null; + + const lines = [ + `
${title}`, + '', + '| Resource | Type | Status | Error |', + '| --- | --- | ---: | --- |', + ]; + + for (const request of report.summary.network.failedRequests.slice(0, 20)) { + lines.push(`| \`${escapeCell(truncate(request.url))}\` | ${escapeCell(request.resourceType)} | ${request.status ?? '-'} | ${escapeCell(request.errorText ?? '')} |`); + } + + lines.push('', '
'); + return lines.join('\n'); +} + +function toHeapSnapshotReport(report: BrowserMetricsReport): HeapSnapshotReport { + return { + summary: report.summary.heapSnapshot, + samples: report.samples.map(sample => ({ + round: sample.round, + data: sample.heapSnapshot, + })), + }; +} + +export function renderFrontendBrowserReport(base: BrowserMetricsReport, head: BrowserMetricsReport, options: { + headHeapSnapshotUrl?: string; + detailedHtmlUrl?: string; +} = {}) { + const headHeapSnapshotUrl = options.headHeapSnapshotUrl; + const detailedHtmlUrl = options.detailedHtmlUrl; + const sampleSummary = base.sampleCount === head.sampleCount + ? `${base.sampleCount} samples per side` + : `${base.sampleCount} base sample(s), ${head.sampleCount} head sample(s)`; + const heapSnapshotTable = heapSnapshotUtil.renderHeapSnapshotTable(toHeapSnapshotReport(base), toHeapSnapshotReport(head)); + const lines = [ + '## 🖥 Frontend Browser Metrics', + '', + 'Only metrics showing significant changes are displayed.', + '', + renderSummaryTable(base, head), + '', + //`> Measured ${sampleSummary} with fresh headless Chrome profiles, browser cache disabled, service workers bypassed, and forced V8 GC before each heap snapshot. Base/Head values are medians; Δ median is the median of paired Head - Base sample deltas; percent uses Δ median / Base median; ± and Δ MAD are median absolute deviations. Scenario: sign up, dismiss the initial account setup dialog, create the first timeline note, then wait until that note is visible.`, + //'', + detailedHtmlUrl == null || detailedHtmlUrl === '' ? null : `[View details](${detailedHtmlUrl})`, + detailedHtmlUrl == null || detailedHtmlUrl === '' ? null : '', + '
', + 'Requests by resource type', + '', + renderResourceTypeTable(base, head), + '', + '
', + '', + '
', + 'V8 heap snapshot statistics', + '', + heapSnapshotTable ?? '_No V8 heap snapshot data._', + '', + heapSnapshotUtil.renderHeapSnapshotSankey(toHeapSnapshotReport(head), 'Head'), + '', + `[Download representative head heap snapshot](${headHeapSnapshotUrl})`, + '
', + '', + ]; + + for (const section of [ + //renderLargestRequests(head, 'Largest representative head requests'), + //renderFailedRequests(base, 'Failed representative base requests'), + //renderFailedRequests(head, 'Failed representative head requests'), + ]) { + if (section == null) continue; + lines.push(section, ''); + } + + return lines.filter(line => line != null).join('\n').trimEnd() + '\n'; +} + +async function main() { + const [baseFile, headFile, outputFile] = process.argv.slice(2); + if (baseFile == null || headFile == null || outputFile == null) { + throw new Error('Usage: node frontend-browser-report.mts '); + } + + const base = JSON.parse(await readFile(baseFile, 'utf8')) as BrowserMetricsReport; + const head = JSON.parse(await readFile(headFile, 'utf8')) as BrowserMetricsReport; + await writeFile(outputFile, renderFrontendBrowserReport(base, head, { + headHeapSnapshotUrl: process.env.FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL, + detailedHtmlUrl: process.env.FRONTEND_BROWSER_DETAILED_HTML_ARTIFACT_URL, + })); +} + +if (process.argv[1] != null && import.meta.url === pathToFileURL(process.argv[1]).href) { + await main(); +} diff --git a/.github/scripts/heap-snapshot-util.mts b/.github/scripts/heap-snapshot-util.mts index c99ce5f4418..92e36188c1f 100644 --- a/.github/scripts/heap-snapshot-util.mts +++ b/.github/scripts/heap-snapshot-util.mts @@ -32,6 +32,326 @@ export type HeapSnapshotReport = { }[]; }; +export const defaultHeapSnapshotBreakdownTopN = 6; + +export function createEmptyHeapSnapshotData(): HeapSnapshotData { + const categories = {} as HeapSnapshotData['categories']; + const nodeCounts = {} as HeapSnapshotData['nodeCounts']; + for (const category of Object.keys(heapSnapshotCategory) as (keyof typeof heapSnapshotCategory)[]) { + categories[category] = 0; + nodeCounts[category] = 0; + } + return { + categories, + nodeCounts, + breakdowns: {} as HeapSnapshotData['breakdowns'], + }; +} + +function sanitizeHeapSnapshotBreakdownLabel(value: unknown, fallback = 'unknown') { + const label = String(value ?? '').replace(/\s+/g, ' ').trim(); + if (label === '') return fallback; + if (label.length <= 80) return label; + return `${label.slice(0, 77)}...`; +} + +function classifyHeapSnapshotBreakdown(category: keyof typeof heapSnapshotCategory, type: string, name: string) { + if (category === 'strings') return type; + + if (category === 'jsArrays') { + if (type === 'array elements') return 'Array elements'; + if (type === 'object' && name === 'Array') return 'Array objects'; + return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`); + } + + if (category === 'typedArrays') { + if (name === 'system / JSArrayBufferData') return 'ArrayBuffer data'; + return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`); + } + + if (category === 'systemObjects') { + if (name.startsWith('system /')) return sanitizeHeapSnapshotBreakdownLabel(name); + if (name.startsWith('(system ')) return sanitizeHeapSnapshotBreakdownLabel(name); + return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`, type); + } + + if (category === 'otherJsObjects') { + if (type === 'object') return sanitizeHeapSnapshotBreakdownLabel(`object: ${name}`, 'object: unknown'); + return type; + } + + if (category === 'otherNonJsObjects') { + if (type === 'extra native bytes') return 'Extra native bytes'; + if (type === 'native') return sanitizeHeapSnapshotBreakdownLabel(`native: ${name}`, 'native: unknown'); + return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`, type); + } + + if (category === 'code') { + const lowerName = name.toLowerCase(); + if (lowerName.includes('bytecode')) return 'bytecode'; + if (lowerName.includes('builtin')) return 'builtins'; + if (lowerName.includes('regexp')) return 'regexp code'; + if (lowerName.includes('stub')) return 'stubs'; + return sanitizeHeapSnapshotBreakdownLabel(`code: ${name}`, 'code: unknown'); + } + + return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`, type); +} + +export function collapseHeapSnapshotBreakdown(breakdown: Record, topN = defaultHeapSnapshotBreakdownTopN) { + const entries = Object.entries(breakdown) + .filter(([, value]) => value > 0) + .toSorted((a, b) => b[1] - a[1]); + + const topEntries = entries.slice(0, topN); + const otherValue = entries + .slice(topN) + .reduce((sum, [, value]) => sum + value, 0); + + const collapsed = Object.fromEntries(topEntries); + if (otherValue > 0) collapsed.Other = otherValue; + return collapsed; +} + +export function collapseHeapSnapshotBreakdowns( + breakdowns: Partial>>, + topN = defaultHeapSnapshotBreakdownTopN, +) { + const collapsed = {} as NonNullable; + for (const category of Object.keys(heapSnapshotCategory) as (keyof typeof heapSnapshotCategory)[]) { + if (category === 'total') continue; + + const categoryBreakdown = breakdowns[category]; + if (categoryBreakdown == null) continue; + + const collapsedCategory = collapseHeapSnapshotBreakdown(categoryBreakdown, topN); + if (Object.keys(collapsedCategory).length > 0) { + collapsed[category] = collapsedCategory; + } + } + + return collapsed; +} + +// Keep these buckets aligned with Chrome DevTools' heap snapshot Statistics view. +export function analyzeHeapSnapshot(snapshot: any, options: { breakdownTopN?: number } = {}): HeapSnapshotData { + const meta = snapshot?.snapshot?.meta; + const nodes = snapshot?.nodes; + const edges = snapshot?.edges; + const strings = snapshot?.strings; + if (meta == null || !Array.isArray(nodes) || !Array.isArray(edges) || !Array.isArray(strings)) { + throw new Error('Invalid heap snapshot format'); + } + + const nodeFields = meta.node_fields; + if (!Array.isArray(nodeFields)) throw new Error('Invalid heap snapshot node fields'); + const edgeFields = meta.edge_fields; + if (!Array.isArray(edgeFields)) throw new Error('Invalid heap snapshot edge fields'); + + const typeOffset = nodeFields.indexOf('type'); + const nameOffset = nodeFields.indexOf('name'); + const selfSizeOffset = nodeFields.indexOf('self_size'); + const edgeCountOffset = nodeFields.indexOf('edge_count'); + if (typeOffset < 0 || nameOffset < 0 || selfSizeOffset < 0 || edgeCountOffset < 0) { + throw new Error('Heap snapshot is missing required node fields'); + } + const edgeTypeOffset = edgeFields.indexOf('type'); + const edgeNameOffset = edgeFields.indexOf('name_or_index'); + const edgeToNodeOffset = edgeFields.indexOf('to_node'); + if (edgeTypeOffset < 0 || edgeNameOffset < 0 || edgeToNodeOffset < 0) { + throw new Error('Heap snapshot is missing required edge fields'); + } + + const nodeTypeNames = meta.node_types?.[typeOffset]; + if (!Array.isArray(nodeTypeNames)) throw new Error('Invalid heap snapshot node types'); + const edgeTypeNames = meta.edge_types?.[edgeTypeOffset]; + if (!Array.isArray(edgeTypeNames)) throw new Error('Invalid heap snapshot edge types'); + + const nodeFieldCount = nodeFields.length; + const edgeFieldCount = edgeFields.length; + const nativeType = nodeTypeNames.indexOf('native'); + const codeType = nodeTypeNames.indexOf('code'); + const hiddenType = nodeTypeNames.indexOf('hidden'); + const stringTypes = new Set([ + nodeTypeNames.indexOf('string'), + nodeTypeNames.indexOf('concatenated string'), + nodeTypeNames.indexOf('sliced string'), + ]); + const internalEdgeType = edgeTypeNames.indexOf('internal'); + const extraNativeBytes = Number.isFinite(snapshot.snapshot.extra_native_bytes) ? snapshot.snapshot.extra_native_bytes : 0; + const { categories, nodeCounts } = createEmptyHeapSnapshotData(); + const breakdowns = {} as Record>; + for (const category of Object.keys(heapSnapshotCategory) as (keyof typeof heapSnapshotCategory)[]) { + if (category !== 'total') breakdowns[category] = {}; + } + + function addValue(map: Record, key: string, value: number) { + map[key] = (map[key] ?? 0) + value; + } + + const edgeStartIndexes = new Map(); + const retainerCounts = new Map(); + let edgeIndex = 0; + for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { + edgeStartIndexes.set(nodeIndex, edgeIndex); + const edgeCount = nodes[nodeIndex + edgeCountOffset] ?? 0; + for (let i = 0; i < edgeCount; i++, edgeIndex += edgeFieldCount) { + const toNodeIndex = edges[edgeIndex + edgeToNodeOffset]; + retainerCounts.set(toNodeIndex, (retainerCounts.get(toNodeIndex) ?? 0) + 1); + } + } + + const jsArrayElementNodeIndexes = new Set(); + + function addCategoryValue(category: keyof typeof heapSnapshotCategory, value: number, type: string, name: string, nodeIndex: number | null = null) { + if (value <= 0) return; + categories[category] += value; + addValue(breakdowns[category], classifyHeapSnapshotBreakdown(category, type, name), value); + if (nodeIndex != null) nodeCounts[category]++; + } + + function addJsArrayElementSize(nodeIndex: number) { + const beginEdgeIndex = edgeStartIndexes.get(nodeIndex) ?? 0; + const edgeCount = nodes[nodeIndex + edgeCountOffset] ?? 0; + for (let i = 0, currentEdgeIndex = beginEdgeIndex; i < edgeCount; i++, currentEdgeIndex += edgeFieldCount) { + const edgeType = edges[currentEdgeIndex + edgeTypeOffset]; + if (edgeType !== internalEdgeType) continue; + + const edgeName = strings[edges[currentEdgeIndex + edgeNameOffset]]; + if (edgeName !== 'elements') continue; + + const elementsNodeIndex = edges[currentEdgeIndex + edgeToNodeOffset]; + if ((retainerCounts.get(elementsNodeIndex) ?? 0) === 1) { + const elementsSize = nodes[elementsNodeIndex + selfSizeOffset] ?? 0; + addCategoryValue('jsArrays', elementsSize, 'array elements', 'Array elements', elementsNodeIndex); + jsArrayElementNodeIndexes.add(elementsNodeIndex); + } + break; + } + } + + if (extraNativeBytes > 0) { + addCategoryValue('otherNonJsObjects', extraNativeBytes, 'extra native bytes', 'extra native bytes'); + } + + for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { + const typeId = nodes[nodeIndex + typeOffset]; + const type = nodeTypeNames[typeId] ?? 'unknown'; + const name = strings[nodes[nodeIndex + nameOffset]] ?? ''; + const selfSize = nodes[nodeIndex + selfSizeOffset] ?? 0; + categories.total += selfSize; + nodeCounts.total++; + + if (typeId === hiddenType) { + addCategoryValue('systemObjects', selfSize, type, name, nodeIndex); + continue; + } + + if (typeId === nativeType) { + if (name === 'system / JSArrayBufferData') { + addCategoryValue('typedArrays', selfSize, type, name, nodeIndex); + } else { + addCategoryValue('otherNonJsObjects', selfSize, type, name, nodeIndex); + } + continue; + } + + if (typeId === codeType) { + addCategoryValue('code', selfSize, type, name, nodeIndex); + continue; + } + + if (stringTypes.has(typeId)) { + addCategoryValue('strings', selfSize, type, name, nodeIndex); + continue; + } + + if (name === 'Array') { + addCategoryValue('jsArrays', selfSize, type, name, nodeIndex); + addJsArrayElementSize(nodeIndex); + continue; + } + } + + categories.total += extraNativeBytes; + + for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { + if (jsArrayElementNodeIndexes.has(nodeIndex)) continue; + + const typeId = nodes[nodeIndex + typeOffset]; + if (typeId === hiddenType || typeId === nativeType || typeId === codeType || stringTypes.has(typeId)) continue; + + const name = strings[nodes[nodeIndex + nameOffset]] ?? ''; + if (name === 'Array') continue; + + const type = nodeTypeNames[typeId] ?? 'unknown'; + const selfSize = nodes[nodeIndex + selfSizeOffset] ?? 0; + addCategoryValue('otherJsObjects', selfSize, type, name, nodeIndex); + } + + return { + categories, + nodeCounts, + breakdowns: collapseHeapSnapshotBreakdowns(breakdowns, options.breakdownTopN), + }; +} + +function finiteMedian(values: (number | null | undefined)[]) { + const finiteValues = values.filter(value => Number.isFinite(value)) as number[]; + if (finiteValues.length === 0) return null; + return util.median(finiteValues); +} + +export function summarizeHeapSnapshotDataSamples( + samples: T[], + getData: (sample: T) => HeapSnapshotData | null | undefined, + options: { breakdownTopN?: number } = {}, +) { + const data = samples.map(getData); + const categories = {} as HeapSnapshotData['categories']; + for (const category of Object.keys(heapSnapshotCategory) as (keyof typeof heapSnapshotCategory)[]) { + const value = finiteMedian(data.map(snapshot => snapshot?.categories?.[category])); + if (value != null) categories[category] = value; + } + + const nodeCounts = {} as HeapSnapshotData['nodeCounts']; + for (const category of Object.keys(heapSnapshotCategory) as (keyof typeof heapSnapshotCategory)[]) { + const value = finiteMedian(data.map(snapshot => snapshot?.nodeCounts?.[category])); + if (value != null) nodeCounts[category] = value; + } + + if (Object.keys(categories).length === 0) return null; + + const breakdowns = {} as NonNullable; + for (const category of Object.keys(heapSnapshotCategory) as (keyof typeof heapSnapshotCategory)[]) { + if (category === 'total') continue; + + const childKeys = new Set(); + for (const snapshot of data) { + for (const childKey of Object.keys(snapshot?.breakdowns?.[category] ?? {})) { + childKeys.add(childKey); + } + } + + const categoryBreakdown = {} as Record; + for (const childKey of childKeys) { + const value = finiteMedian(data.map(snapshot => snapshot?.breakdowns?.[category]?.[childKey])); + if (value != null) categoryBreakdown[childKey] = value; + } + + const collapsed = collapseHeapSnapshotBreakdown(categoryBreakdown, options.breakdownTopN); + if (Object.keys(collapsed).length > 0) { + breakdowns[category] = collapsed; + } + } + + return { + categories, + nodeCounts, + ...(Object.keys(breakdowns).length > 0 ? { breakdowns } : {}), + }; +} + function getHeapSnapshotCategoryValue(report: HeapSnapshotReport, category: keyof typeof heapSnapshotCategory) { return report.summary.categories[category]; } diff --git a/.github/scripts/measure-backend-memory-comparison.mts b/.github/scripts/measure-backend-memory-comparison.mts index 3dce74dc0a9..2e7e67fe5af 100644 --- a/.github/scripts/measure-backend-memory-comparison.mts +++ b/.github/scripts/measure-backend-memory-comparison.mts @@ -38,7 +38,7 @@ export type MemoryReport = { const [baseDirArg, headDirArg, baseOutputArg, headOutputArg] = process.argv.slice(2); -const HEAP_SNAPSHOT_BREAKDOWN_TOP_N = util.readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', 6, 1); +const HEAP_SNAPSHOT_BREAKDOWN_TOP_N = util.readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', heapSnapshotUtil.defaultHeapSnapshotBreakdownTopN, 1); const HEAD_HEAP_SNAPSHOT_WORK_DIR = resolve('head-heap-snapshots'); const HEAD_HEAP_SNAPSHOT_OUTPUT_PATH = resolve('head-heap-snapshot.heapsnapshot'); @@ -70,51 +70,6 @@ async function resetState(repoDir: string) { } } -function summarizeHeapSnapshotBreakdowns(samples: MemoryReport['samples'], phase: typeof phases[number]) { - const breakdowns = {} as Record>; - - for (const category of Object.keys(heapSnapshotUtil.heapSnapshotCategory) as (keyof typeof heapSnapshotUtil.heapSnapshotCategory)[]) { - if (category === 'total') continue; - - const childKeys = new Set(); - for (const sample of samples) { - for (const childKey of Object.keys(sample.phases[phase].heapSnapshot?.breakdowns?.[category] ?? {})) { - childKeys.add(childKey); - } - } - - const categoryBreakdown = {} as Record; - for (const childKey of childKeys) { - const values = samples - .map(sample => sample.phases[phase].heapSnapshot?.breakdowns?.[category]?.[childKey]) - .filter(value => Number.isFinite(value)) as number[]; - - if (values.length > 0) categoryBreakdown[childKey] = util.median(values); - } - - if (Object.keys(categoryBreakdown).length > 0) { - breakdowns[category] = collapseHeapSnapshotBreakdown(categoryBreakdown); - } - } - - return breakdowns; -} - -function collapseHeapSnapshotBreakdown(breakdown: Record) { - const entries = Object.entries(breakdown) - .filter(([, value]) => value > 0) - .toSorted((a, b) => b[1] - a[1]); - - const topEntries = entries.slice(0, HEAP_SNAPSHOT_BREAKDOWN_TOP_N); - const otherValue = entries - .slice(HEAP_SNAPSHOT_BREAKDOWN_TOP_N) - .reduce((sum, [, value]) => sum + value, 0); - - const collapsed = Object.fromEntries(topEntries); - if (otherValue > 0) collapsed.Other = otherValue; - return collapsed; -} - function summarizeSamples(samples: MemoryReport['samples']) { const summary = {} as MemoryReport['summary']; @@ -135,33 +90,12 @@ function summarizeSamples(samples: MemoryReport['samples']) { summary[phase].memoryUsage[key] = util.median(values); } - const heapSnapshotCategoryValues = {} as Record; - for (const category of Object.keys(heapSnapshotUtil.heapSnapshotCategory) as (keyof typeof heapSnapshotUtil.heapSnapshotCategory)[]) { - const values = samples - .map(sample => sample.phases[phase].heapSnapshot?.categories?.[category]) - .filter(value => Number.isFinite(value)) as number[]; - - if (values.length > 0) heapSnapshotCategoryValues[category] = util.median(values); - } - - const heapSnapshotNodeCountValues = {} as Record; - for (const category of Object.keys(heapSnapshotUtil.heapSnapshotCategory) as (keyof typeof heapSnapshotUtil.heapSnapshotCategory)[]) { - const values = samples - .map(sample => sample.phases[phase].heapSnapshot?.nodeCounts?.[category]) - .filter(value => Number.isFinite(value)) as number[]; - - if (values.length > 0) heapSnapshotNodeCountValues[category] = util.median(values); - } - - if (Object.keys(heapSnapshotCategoryValues).length > 0) { - const heapSnapshotBreakdowns = summarizeHeapSnapshotBreakdowns(samples, phase); - - summary[phase].heapSnapshot = { - categories: heapSnapshotCategoryValues, - nodeCounts: heapSnapshotNodeCountValues, - ...(Object.keys(heapSnapshotBreakdowns).length > 0 ? { breakdowns: heapSnapshotBreakdowns } : {}), - }; - } + const heapSnapshot = heapSnapshotUtil.summarizeHeapSnapshotDataSamples( + samples, + sample => sample.phases[phase].heapSnapshot, + { breakdownTopN: HEAP_SNAPSHOT_BREAKDOWN_TOP_N }, + ); + if (heapSnapshot != null) summary[phase].heapSnapshot = heapSnapshot; } return summary; diff --git a/.github/scripts/measure-frontend-browser-comparison.mts b/.github/scripts/measure-frontend-browser-comparison.mts new file mode 100644 index 00000000000..0825133b1df --- /dev/null +++ b/.github/scripts/measure-frontend-browser-comparison.mts @@ -0,0 +1,274 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { copyFile, mkdir, rm, writeFile } from 'node:fs/promises'; +import { join, resolve } from 'node:path'; +import * as util from './utility.mts'; +import * as heapSnapshotUtil from './heap-snapshot-util.mts'; +import { HeadlessChromeController, summarizeNetwork } from './chrome.mts'; +import type { BrowserMeasurement, NetworkRequest, NetworkSummary } from './chrome.mts'; +import { closeUserSetupDialog, postNote, signupThroughUi, visitHome } from '../../packages/frontend/test/e2e/shared.ts'; + +const [baseDirArg, headDirArg, baseOutputArg, headOutputArg, headHeapSnapshotOutputArg] = process.argv.slice(2); + +const baseUrl = process.env.FRONTEND_BROWSER_METRICS_URL ?? 'http://127.0.0.1:61812'; +const sampleCount = util.readIntegerEnv('FRONTEND_BROWSER_METRICS_SAMPLE_COUNT', 5, 1); +const heapSnapshotBreakdownTopN = util.readIntegerEnv('FRONTEND_BROWSER_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', heapSnapshotUtil.defaultHeapSnapshotBreakdownTopN, 1); +const headHeapSnapshotWorkDir = resolve('frontend-browser-head-heap-snapshots'); + +type BrowserMeasurementSample = BrowserMeasurement & { + round: number; + networkRequests: NetworkRequest[]; +}; + +type BrowserMetricsReport = { + label: string; + timestamp: string; + url: string; + scenario: string; + sampleCount: number; + aggregation: 'median'; + summary: BrowserMeasurement; + samples: BrowserMeasurementSample[]; +}; + +async function runSignupAndPostScenario(chrome: HeadlessChromeController) { + const page = chrome.page; + const noteText = `Frontend browser metrics ${Date.now()}`; + + await visitHome(page, baseUrl); + await signupThroughUi(page, { username: 'alice', password: 'password' }); + await closeUserSetupDialog(page); + await postNote(page, noteText, 10_000); + + await util.sleep(1000); +} + +function finiteMedian(values: (number | null | undefined)[], defaultValue = 0) { + const finiteValues = values.filter(value => Number.isFinite(value)) as number[]; + if (finiteValues.length === 0) return defaultValue; + return util.median(finiteValues); +} + +function selectRepresentativeSample(samples: BrowserMeasurementSample[], getValue: (sample: BrowserMeasurementSample) => number) { + const medianValue = finiteMedian(samples.map(getValue)); + let selected: { sample: BrowserMeasurementSample; distance: number } | null = null; + + for (const sample of samples) { + const value = getValue(sample); + if (!Number.isFinite(value)) continue; + const distance = Math.abs(value - medianValue); + if (selected == null || distance < selected.distance || (distance === selected.distance && sample.round < selected.sample.round)) { + selected = { + sample, + distance, + }; + } + } + + return selected?.sample ?? samples[0]; +} + +function summarizeResourceType(samples: BrowserMeasurementSample[], resourceType: string) { + return { + requests: finiteMedian(samples.map(sample => sample.network.byResourceType[resourceType]?.requests)), + encodedBytes: finiteMedian(samples.map(sample => sample.network.byResourceType[resourceType]?.encodedBytes)), + decodedBodyBytes: finiteMedian(samples.map(sample => sample.network.byResourceType[resourceType]?.decodedBodyBytes)), + }; +} + +function summarizeNetworkSamples(samples: BrowserMeasurementSample[]): NetworkSummary { + const resourceTypes = new Set(); + for (const sample of samples) { + for (const resourceType of Object.keys(sample.network.byResourceType)) { + resourceTypes.add(resourceType); + } + } + + const representative = selectRepresentativeSample(samples, sample => sample.network.totalEncodedBytes); + const byResourceType = {} as NetworkSummary['byResourceType']; + for (const resourceType of resourceTypes) { + byResourceType[resourceType] = summarizeResourceType(samples, resourceType); + } + + return { + requestCount: finiteMedian(samples.map(sample => sample.network.requestCount)), + webSocketConnectionCount: finiteMedian(samples.map(sample => sample.network.webSocketConnectionCount)), + webSocketSentBytes: finiteMedian(samples.map(sample => sample.network.webSocketSentBytes)), + webSocketReceivedBytes: finiteMedian(samples.map(sample => sample.network.webSocketReceivedBytes)), + finishedRequestCount: finiteMedian(samples.map(sample => sample.network.finishedRequestCount)), + failedRequestCount: finiteMedian(samples.map(sample => sample.network.failedRequestCount)), + cachedRequestCount: finiteMedian(samples.map(sample => sample.network.cachedRequestCount)), + serviceWorkerRequestCount: finiteMedian(samples.map(sample => sample.network.serviceWorkerRequestCount)), + totalEncodedBytes: finiteMedian(samples.map(sample => sample.network.totalEncodedBytes)), + totalDecodedBodyBytes: finiteMedian(samples.map(sample => sample.network.totalDecodedBodyBytes)), + sameOriginEncodedBytes: finiteMedian(samples.map(sample => sample.network.sameOriginEncodedBytes)), + thirdPartyEncodedBytes: finiteMedian(samples.map(sample => sample.network.thirdPartyEncodedBytes)), + byResourceType, + largestRequests: representative.network.largestRequests, + failedRequests: representative.network.failedRequests, + }; +} + +function summarizePerformanceSamples(samples: BrowserMeasurementSample[]): BrowserMeasurement['performance'] { + const cdpMetricKeys = new Set(); + for (const sample of samples) { + for (const key of Object.keys(sample.performance.cdpMetrics)) { + cdpMetricKeys.add(key); + } + } + + const cdpMetrics = {} as Record; + for (const key of cdpMetricKeys) { + cdpMetrics[key] = finiteMedian(samples.map(sample => sample.performance.cdpMetrics[key])); + } + + const webVitalKeys = [ + 'firstPaintMs', + 'firstContentfulPaintMs', + 'domContentLoadedEventEndMs', + 'loadEventEndMs', + 'longTaskCount', + 'longTaskDurationMs', + 'maxLongTaskDurationMs', + 'resourceEntryCount', + 'domElements', + ] as const satisfies (keyof BrowserMeasurement['performance']['webVitals'])[]; + + const webVitals = {} as BrowserMeasurement['performance']['webVitals']; + for (const key of webVitalKeys) { + webVitals[key] = finiteMedian(samples.map(sample => sample.performance.webVitals[key])); + } + + return { + cdpMetrics, + runtimeHeap: { + usedSize: finiteMedian(samples.map(sample => sample.performance.runtimeHeap?.usedSize)), + totalSize: finiteMedian(samples.map(sample => sample.performance.runtimeHeap?.totalSize)), + }, + tabMemory: { + totalBytes: finiteMedian(samples.map(sample => sample.performance.tabMemory.totalBytes)), + }, + webVitals, + }; +} + +function summarizeHeapSnapshotSamples(samples: BrowserMeasurementSample[]) { + const summary = heapSnapshotUtil.summarizeHeapSnapshotDataSamples( + samples, + sample => sample.heapSnapshot, + { breakdownTopN: heapSnapshotBreakdownTopN }, + ); + if (summary == null) throw new Error('No heap snapshot samples'); + return summary; +} + +function summarizeSamples(label: 'base' | 'head', samples: BrowserMeasurementSample[]): BrowserMetricsReport { + if (samples.length === 0) throw new Error(`No browser metric samples for ${label}`); + const representative = selectRepresentativeSample(samples, sample => sample.network.totalEncodedBytes); + const summary: BrowserMeasurement = { + label, + timestamp: new Date().toISOString(), + url: baseUrl, + scenario: representative.scenario, + durationMs: finiteMedian(samples.map(sample => sample.durationMs)), + network: summarizeNetworkSamples(samples), + performance: summarizePerformanceSamples(samples), + heapSnapshot: summarizeHeapSnapshotSamples(samples), + }; + + return { + label, + timestamp: new Date().toISOString(), + url: baseUrl, + scenario: representative.scenario, + sampleCount: samples.length, + aggregation: 'median', + summary, + samples, + }; +} + +async function measureSample(label: 'base' | 'head', round: number, heapSnapshotSavePath?: string) { + await util.prepareInstance(baseUrl); + + return await HeadlessChromeController.with(label, { scenarioTimeoutMs: 120000, baseUrl }, async chrome => { + await chrome.enableNetworkTracking(); + + const startedAt = Date.now(); + await runSignupAndPostScenario(chrome); + const durationMs = Date.now() - startedAt; + await chrome.waitForNetworkDetails(); + const performance = await chrome.collectPerformance(); + const heapSnapshotRaw = await chrome.takeHeapSnapshot(heapSnapshotSavePath); + const heapSnapshot = heapSnapshotUtil.analyzeHeapSnapshot(heapSnapshotRaw, { breakdownTopN: heapSnapshotBreakdownTopN }); + const measurement: BrowserMeasurementSample = { + label, + round, + timestamp: new Date().toISOString(), + url: baseUrl, + scenario: 'fresh browser signup, first timeline note, after the note becomes visible', + durationMs, + network: summarizeNetwork(chrome.networkRequests, baseUrl, chrome.webSocketConnections), + networkRequests: chrome.networkRequests, + performance, + heapSnapshot, + }; + + return measurement; + }); +} + +function headHeapSnapshotPath(round: number) { + return join(headHeapSnapshotWorkDir, `round-${round}.heapsnapshot`); +} + +async function saveRepresentativeHeadHeapSnapshot(report: BrowserMetricsReport, outputPath: string) { + const representative = selectRepresentativeSample(report.samples, sample => sample.heapSnapshot.categories.total); + await copyFile(headHeapSnapshotPath(representative.round), outputPath); + process.stderr.write(`[head] Selected round ${representative.round} heap snapshot for artifact\n`); + await rm(headHeapSnapshotWorkDir, { recursive: true, force: true }); +} + +async function measureRepo(label: 'base' | 'head', repoDir: string, outputPath: string, heapSnapshotSavePath?: string) { + let server: ReturnType | null = null; + + try { + server = util.startServer(label, repoDir); + await util.waitForServer(baseUrl, server!); + + if (label === 'head' && heapSnapshotSavePath != null) { + await rm(headHeapSnapshotWorkDir, { recursive: true, force: true }); + await mkdir(headHeapSnapshotWorkDir, { recursive: true }); + } + + const samples: BrowserMeasurementSample[] = []; + for (let round = 1; round <= sampleCount; round++) { + process.stderr.write(`[${label}] Measuring browser metrics sample ${round}/${sampleCount}\n`); + samples.push(await measureSample( + label, + round, + label === 'head' && heapSnapshotSavePath != null ? headHeapSnapshotPath(round) : undefined, + )); + } + + const report = summarizeSamples(label, samples); + await writeFile(outputPath, JSON.stringify(report, null, '\t')); + process.stderr.write(`[${label}] Wrote browser metrics report to ${outputPath}\n`); + + if (label === 'head' && heapSnapshotSavePath != null) { + await saveRepresentativeHeadHeapSnapshot(report, heapSnapshotSavePath); + } + } finally { + if (server != null) await util.stopServer(server); + } +} + +async function main() { + await measureRepo('base', resolve(baseDirArg), resolve(baseOutputArg)); + await measureRepo('head', resolve(headDirArg), resolve(headOutputArg), headHeapSnapshotOutputArg == null ? undefined : resolve(headHeapSnapshotOutputArg)); +} + +await main(); diff --git a/.github/scripts/utility.mts b/.github/scripts/utility.mts index fb65d9191dc..caec5555ef6 100644 --- a/.github/scripts/utility.mts +++ b/.github/scripts/utility.mts @@ -5,10 +5,14 @@ // NOTE: ��ファイル�workflow上��ックエンド�らも�照�れる���side effect������ら�� -import { spawn } from 'node:child_process'; +import { spawn, spawnSync, type ChildProcessWithoutNullStreams } from 'node:child_process'; import { promises as fs } from 'node:fs'; import path from 'node:path'; +export function sleep(ms: number) { + return new Promise(resolvePromise => setTimeout(resolvePromise, ms)); +} + export function median(values: number[]) { const sorted = values.toSorted((a, b) => a - b); const center = Math.floor(sorted.length / 2); @@ -202,3 +206,91 @@ export function run(command: string, args: string[], options: { cwd?: string; en }); }); } + +export function startServer(label: string, repoDir: string) { + process.stderr.write(`[${label}] Starting Misskey test server\n`); + const child = spawn(commandName('pnpm'), ['start:test'], { + cwd: repoDir, + env: process.env, + stdio: ['ignore', 'pipe', 'pipe'], + detached: process.platform !== 'win32', + }); + child.stdout.on('data', data => process.stderr.write(`[server:${label}] ${data}`)); + child.stderr.on('data', data => process.stderr.write(`[server:${label}] ${data}`)); + return child; +} + +export async function waitForServer(baseUrl: string, child: ChildProcessWithoutNullStreams) { + const startedAt = Date.now(); + while (Date.now() - startedAt < 120_000) { + if (child.exitCode != null) throw new Error(`Misskey server exited early with code ${child.exitCode}`); + try { + const response = await fetch(`${baseUrl}/`, { redirect: 'manual' }); + if (response.status < 500) return; + } catch { + // retry + } + await sleep(1_000); + } + throw new Error(`Timed out waiting for ${baseUrl}`); +} + +export async function api(baseUrl: string, endpoint: string, body: Record) { + const response = await fetch(`${baseUrl}/api/${endpoint}`, { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify(body), + }); + if (!response.ok) { + throw new Error(`/api/${endpoint} returned ${response.status}: ${await response.text()}`); + } + if (response.status === 204) return null; + return await response.json(); +} + +export async function prepareInstance(baseUrl: string) { + await api(baseUrl, 'reset-db', {}); + await api(baseUrl, 'admin/accounts/create', { + username: 'admin', + password: 'admin1234', + setupPassword: 'example_password_please_change_this_or_you_will_get_hacked', + }); +} + +export async function stopServer(child: ChildProcessWithoutNullStreams) { + if (child.exitCode != null) return; + + if (process.platform === 'win32') { + spawnSync('taskkill', ['/pid', String(child.pid), '/t', '/f'], { stdio: 'ignore' }); + } else if (child.pid != null) { + try { + process.kill(-child.pid, 'SIGTERM'); + } catch { + child.kill('SIGTERM'); + } + } + + await new Promise(resolvePromise => { + if (child.exitCode != null) { + resolvePromise(); + return; + } + child.once('exit', () => resolvePromise()); + setTimeout(() => { + if (child.pid != null) { + try { + if (process.platform === 'win32') { + spawnSync('taskkill', ['/pid', String(child.pid), '/t', '/f'], { stdio: 'ignore' }); + } else { + process.kill(-child.pid, 'SIGKILL'); + } + } catch { + child.kill('SIGKILL'); + } + } + resolvePromise(); + }, 10_000).unref(); + }); +} diff --git a/.github/workflows/frontend-browser-metrics-report-comment.yml b/.github/workflows/frontend-browser-metrics-report-comment.yml new file mode 100644 index 00000000000..0312092a5bd --- /dev/null +++ b/.github/workflows/frontend-browser-metrics-report-comment.yml @@ -0,0 +1,44 @@ +name: frontend-browser-metrics-report-comment + +on: + workflow_run: + workflows: + - frontend-browser-metrics-report + types: + - completed + +permissions: + actions: read + contents: read + issues: write + pull-requests: write + +jobs: + comment: + name: Comment frontend browser metrics report + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + concurrency: + group: frontend-browser-metrics-report-comment-${{ github.event.workflow_run.id }} + cancel-in-progress: true + steps: + - name: Download browser metrics report + uses: actions/download-artifact@v8 + with: + name: frontend-browser-metrics-report + path: ${{ runner.temp }}/frontend-browser-metrics-report + github-token: ${{ github.token }} + repository: ${{ github.repository }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Load PR number + id: load-pr-number + shell: bash + run: echo "pr-number=$(cat "$RUNNER_TEMP/frontend-browser-metrics-report/pr-number.txt")" >> "$GITHUB_OUTPUT" + + - name: Comment on pull request + uses: thollander/actions-comment-pull-request@v3 + with: + pr-number: ${{ steps.load-pr-number.outputs.pr-number }} + comment-tag: frontend_browser_metrics_report + file-path: ${{ runner.temp }}/frontend-browser-metrics-report/frontend-browser-metrics-report.md diff --git a/.github/workflows/frontend-browser-metrics-report.yml b/.github/workflows/frontend-browser-metrics-report.yml new file mode 100644 index 00000000000..863c7bb155c --- /dev/null +++ b/.github/workflows/frontend-browser-metrics-report.yml @@ -0,0 +1,200 @@ +name: frontend-browser-metrics-report + +on: + pull_request: + types: + - opened + - synchronize + - reopened + - ready_for_review + paths: + - packages/frontend/** + - packages/frontend-shared/** + - packages/frontend-builder/** + - packages/backend/** + - packages/i18n/** + - packages/icons-subsetter/** + - packages/misskey-js/** + - packages/misskey-reversi/** + - packages/misskey-bubble-game/** + - package.json + - pnpm-lock.yaml + - pnpm-workspace.yaml + - .node-version + - .github/misskey/test.yml + - .github/scripts/utility.mts + - .github/scripts/frontend-browser-detailed-html.mts + - .github/scripts/frontend-browser-report.mts + - .github/scripts/heap-snapshot-util.mts + - .github/scripts/measure-frontend-browser-comparison.mts + - .github/scripts/chrome.mts + - .github/workflows/frontend-browser-metrics-report.yml + - .github/workflows/frontend-browser-metrics-report-comment.yml + +permissions: + contents: read + pull-requests: read + +concurrency: + group: frontend-browser-metrics-report-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + report: + name: Measure frontend browser metrics + runs-on: ubuntu-latest + timeout-minutes: 90 + + services: + postgres: + image: postgres:18 + ports: + - 54312:5432 + env: + POSTGRES_DB: test-misskey + POSTGRES_HOST_AUTH_METHOD: trust + redis: + image: redis:8 + ports: + - 56312:6379 + + steps: + - name: Checkout base + uses: actions/checkout@v6.0.2 + with: + persist-credentials: false + repository: ${{ github.event.pull_request.base.repo.full_name }} + ref: ${{ github.event.pull_request.base.sha }} + path: before + submodules: true + + - name: Checkout pull request + uses: actions/checkout@v6.0.2 + with: + persist-credentials: false + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.sha }} + path: after + submodules: true + + - name: Setup pnpm + uses: pnpm/action-setup@v6.0.3 + with: + package_json_file: after/package.json + + - name: Setup Node.js + uses: actions/setup-node@v6.4.0 + with: + node-version-file: after/.node-version + cache: pnpm + cache-dependency-path: | + before/pnpm-lock.yaml + after/pnpm-lock.yaml + + - name: Install dependencies for base + working-directory: before + run: pnpm i --frozen-lockfile + + - name: Configure base + working-directory: before + run: cp .github/misskey/test.yml .config + + - name: Build base + working-directory: before + run: pnpm build + + - name: Install dependencies for pull request + working-directory: after + run: pnpm i --frozen-lockfile + + - name: Configure pull request + working-directory: after + run: cp .github/misskey/test.yml .config + + - name: Build pull request + working-directory: after + run: pnpm build + + - name: Install Playwright browsers + working-directory: after/packages/frontend + run: pnpm exec playwright install --with-deps --no-shell chromium + + - name: Measure frontend browser metrics + shell: bash + env: + FRONTEND_BROWSER_METRICS_SAMPLE_COUNT: 5 + MK_ENABLE_CROSS_ORIGIN_ISOLATION: "true" + run: | + REPORT_DIR="$RUNNER_TEMP/frontend-browser-metrics-report" + mkdir -p "$REPORT_DIR" + node after/.github/scripts/measure-frontend-browser-comparison.mts before after "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/head-heap-snapshot.heapsnapshot" + + - name: Upload browser head heap snapshot + id: upload-browser-head-heap-snapshot + uses: actions/upload-artifact@v7 + with: + name: frontend-browser-metrics-head-heap-snapshot + path: ${{ runner.temp }}/frontend-browser-metrics-report/head-heap-snapshot.heapsnapshot + if-no-files-found: error + retention-days: 7 + + - name: Generate browser detailed html + shell: bash + run: | + REPORT_DIR="$RUNNER_TEMP/frontend-browser-metrics-report" + test -s "$REPORT_DIR/before-browser.json" + test -s "$REPORT_DIR/after-browser.json" + node after/.github/scripts/frontend-browser-detailed-html.mts "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/frontend-browser-detailed-html.html" + + - name: Upload browser detailed html + id: upload-browser-detailed-html + uses: actions/upload-artifact@v7 + with: + name: frontend-browser-metrics-detailed-html + path: ${{ runner.temp }}/frontend-browser-metrics-report/frontend-browser-detailed-html.html + if-no-files-found: error + archive: false + retention-days: 7 + + - name: Generate browser metrics report + shell: bash + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + PR_NUMBER: ${{ github.event.pull_request.number }} + FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL: ${{ steps.upload-browser-head-heap-snapshot.outputs.artifact-url }} + FRONTEND_BROWSER_DETAILED_HTML_ARTIFACT_URL: ${{ steps.upload-browser-detailed-html.outputs.artifact-url }} + run: | + REPORT_DIR="$RUNNER_TEMP/frontend-browser-metrics-report" + test -s "$REPORT_DIR/before-browser.json" + test -s "$REPORT_DIR/after-browser.json" + node after/.github/scripts/frontend-browser-report.mts "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/frontend-browser-metrics-report.md" + printf '%s\n' "$PR_NUMBER" > "$REPORT_DIR/pr-number.txt" + printf '%s\n' "$BASE_SHA" > "$REPORT_DIR/base-sha.txt" + printf '%s\n' "$HEAD_SHA" > "$REPORT_DIR/head-sha.txt" + printf '%s\n' "${{ github.event.pull_request.html_url }}" > "$REPORT_DIR/pr-url.txt" + + - name: Check browser metrics report + shell: bash + run: | + REPORT_DIR="$RUNNER_TEMP/frontend-browser-metrics-report" + test -s "$REPORT_DIR/frontend-browser-metrics-report.md" + test -s "$REPORT_DIR/frontend-browser-detailed-html.html" + test -s "$REPORT_DIR/pr-number.txt" + test -s "$REPORT_DIR/head-sha.txt" + cat "$REPORT_DIR/frontend-browser-metrics-report.md" >> "$GITHUB_STEP_SUMMARY" + + - name: Upload browser metrics report + uses: actions/upload-artifact@v7 + with: + name: frontend-browser-metrics-report + path: | + ${{ runner.temp }}/frontend-browser-metrics-report/before-browser.json + ${{ runner.temp }}/frontend-browser-metrics-report/after-browser.json + ${{ runner.temp }}/frontend-browser-metrics-report/frontend-browser-metrics-report.md + ${{ runner.temp }}/frontend-browser-metrics-report/pr-number.txt + ${{ runner.temp }}/frontend-browser-metrics-report/base-sha.txt + ${{ runner.temp }}/frontend-browser-metrics-report/head-sha.txt + ${{ runner.temp }}/frontend-browser-metrics-report/pr-url.txt + if-no-files-found: error + retention-days: 7 diff --git a/packages/backend/scripts/measure-memory.mts b/packages/backend/scripts/measure-memory.mts index 74b84d998ff..eb7a9c037a8 100644 --- a/packages/backend/scripts/measure-memory.mts +++ b/packages/backend/scripts/measure-memory.mts @@ -10,7 +10,7 @@ import { dirname, join } from 'node:path'; import { tmpdir } from 'node:os'; //import * as http from 'node:http'; import * as fs from 'node:fs/promises'; -import { heapSnapshotCategory, type HeapSnapshotData } from '../../../.github/scripts/heap-snapshot-util.mts'; +import { analyzeHeapSnapshot, defaultHeapSnapshotBreakdownTopN, type HeapSnapshotData } from '../../../.github/scripts/heap-snapshot-util.mts'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -40,7 +40,7 @@ const IPC_TIMEOUT = readIntegerEnv('MK_MEMORY_IPC_TIMEOUT_MS', 30000, 1); // Tim const REQUEST_COUNT = readIntegerEnv('MK_MEMORY_REQUEST_COUNT', 10, 0); const HEAP_SNAPSHOT = readBooleanEnv('MK_MEMORY_HEAP_SNAPSHOT', false); const HEAP_SNAPSHOT_TIMEOUT = readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_TIMEOUT_MS', 120000, 1); -const HEAP_SNAPSHOT_BREAKDOWN_TOP_N = readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', 6, 1); +const HEAP_SNAPSHOT_BREAKDOWN_TOP_N = readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', defaultHeapSnapshotBreakdownTopN, 1); const HEAP_SNAPSHOT_SAVE_PATH = process.env.MK_MEMORY_HEAP_SNAPSHOT_SAVE_PATH; const procStatusKeys = ['VmPeak', 'VmSize', 'VmHWM', 'VmRSS', 'VmData', 'VmStk', 'VmExe', 'VmLib', 'VmPTE', 'VmSwap'] as const; @@ -79,246 +79,6 @@ function bytesToKiB(value: number) { return Math.round(value / 1024); } -function sanitizeHeapSnapshotBreakdownLabel(value, fallback = 'unknown') { - const label = String(value ?? '').replace(/\s+/g, ' ').trim(); - if (label === '') return fallback; - if (label.length <= 80) return label; - return `${label.slice(0, 77)}...`; -} - -function classifyHeapSnapshotBreakdown(category: keyof typeof heapSnapshotCategory, type, name) { - if (category === 'strings') return type; - - if (category === 'jsArrays') { - if (type === 'array elements') return 'Array elements'; - if (type === 'object' && name === 'Array') return 'Array objects'; - return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`); - } - - if (category === 'typedArrays') { - if (name === 'system / JSArrayBufferData') return 'ArrayBuffer data'; - return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`); - } - - if (category === 'systemObjects') { - if (name.startsWith('system /')) return sanitizeHeapSnapshotBreakdownLabel(name); - if (name.startsWith('(system ')) return sanitizeHeapSnapshotBreakdownLabel(name); - return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`, type); - } - - if (category === 'otherJsObjects') { - if (type === 'object') return sanitizeHeapSnapshotBreakdownLabel(`object: ${name}`, 'object: unknown'); - return type; - } - - if (category === 'otherNonJsObjects') { - if (type === 'extra native bytes') return 'Extra native bytes'; - if (type === 'native') return sanitizeHeapSnapshotBreakdownLabel(`native: ${name}`, 'native: unknown'); - return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`, type); - } - - if (category === 'code') { - const lowerName = name.toLowerCase(); - if (lowerName.includes('bytecode')) return 'bytecode'; - if (lowerName.includes('builtin')) return 'builtins'; - if (lowerName.includes('regexp')) return 'regexp code'; - if (lowerName.includes('stub')) return 'stubs'; - return sanitizeHeapSnapshotBreakdownLabel(`code: ${name}`, 'code: unknown'); - } - - return sanitizeHeapSnapshotBreakdownLabel(`${type}: ${name}`, type); -} - -function collapseHeapSnapshotBreakdown(breakdowns: Record>) { - const collapsed = {} as Record>; - - for (const [category, children] of Object.entries(breakdowns)) { - const entries = Object.entries(children) - .filter(([, value]) => value > 0) - .toSorted((a, b) => b[1] - a[1]); - - const topEntries = entries.slice(0, HEAP_SNAPSHOT_BREAKDOWN_TOP_N); - const otherValue = entries - .slice(HEAP_SNAPSHOT_BREAKDOWN_TOP_N) - .reduce((sum, [, value]) => sum + value, 0); - - const categoryBreakdown = Object.fromEntries(topEntries); - if (otherValue > 0) categoryBreakdown.Other = otherValue; - if (Object.keys(categoryBreakdown).length > 0) collapsed[category] = categoryBreakdown; - } - - return collapsed; -} - -// Keep these buckets aligned with Chrome DevTools' heap snapshot Statistics view. -function analyzeHeapSnapshot(snapshot) { - const meta = snapshot?.snapshot?.meta; - const nodes = snapshot?.nodes; - const edges = snapshot?.edges; - const strings = snapshot?.strings; - if (meta == null || !Array.isArray(nodes) || !Array.isArray(edges) || !Array.isArray(strings)) { - throw new Error('Invalid heap snapshot format'); - } - - const nodeFields = meta.node_fields; - if (!Array.isArray(nodeFields)) throw new Error('Invalid heap snapshot node fields'); - const edgeFields = meta.edge_fields; - if (!Array.isArray(edgeFields)) throw new Error('Invalid heap snapshot edge fields'); - - const typeOffset = nodeFields.indexOf('type'); - const nameOffset = nodeFields.indexOf('name'); - const selfSizeOffset = nodeFields.indexOf('self_size'); - const edgeCountOffset = nodeFields.indexOf('edge_count'); - if (typeOffset < 0 || nameOffset < 0 || selfSizeOffset < 0 || edgeCountOffset < 0) { - throw new Error('Heap snapshot is missing required node fields'); - } - const edgeTypeOffset = edgeFields.indexOf('type'); - const edgeNameOffset = edgeFields.indexOf('name_or_index'); - const edgeToNodeOffset = edgeFields.indexOf('to_node'); - if (edgeTypeOffset < 0 || edgeNameOffset < 0 || edgeToNodeOffset < 0) { - throw new Error('Heap snapshot is missing required edge fields'); - } - - const nodeTypeNames = meta.node_types?.[typeOffset]; - if (!Array.isArray(nodeTypeNames)) throw new Error('Invalid heap snapshot node types'); - const edgeTypeNames = meta.edge_types?.[edgeTypeOffset]; - if (!Array.isArray(edgeTypeNames)) throw new Error('Invalid heap snapshot edge types'); - - function createEmptyHeapSnapshotCategoryMap() { - return Object.fromEntries(Object.keys(heapSnapshotCategory).map(category => [category, 0])) as Record; - } - - const nodeFieldCount = nodeFields.length; - const edgeFieldCount = edgeFields.length; - const nativeType = nodeTypeNames.indexOf('native'); - const codeType = nodeTypeNames.indexOf('code'); - const hiddenType = nodeTypeNames.indexOf('hidden'); - const stringTypes = new Set([ - nodeTypeNames.indexOf('string'), - nodeTypeNames.indexOf('concatenated string'), - nodeTypeNames.indexOf('sliced string'), - ]); - const internalEdgeType = edgeTypeNames.indexOf('internal'); - const extraNativeBytes = Number.isFinite(snapshot.snapshot.extra_native_bytes) ? snapshot.snapshot.extra_native_bytes : 0; - const categories = createEmptyHeapSnapshotCategoryMap(); - const nodeCounts = createEmptyHeapSnapshotCategoryMap(); - const breakdowns = Object.fromEntries( - (Object.keys(heapSnapshotCategory) as (keyof typeof heapSnapshotCategory)[]) - .filter(category => category !== 'total') - .map(category => [category, {}]), - ); - - function addValue(map: Record, key: string, value: number) { - map[key] = (map[key] ?? 0) + value; - } - - const edgeStartIndexes = new Map(); - const retainerCounts = new Map(); - let edgeIndex = 0; - for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { - edgeStartIndexes.set(nodeIndex, edgeIndex); - const edgeCount = nodes[nodeIndex + edgeCountOffset] ?? 0; - for (let i = 0; i < edgeCount; i++, edgeIndex += edgeFieldCount) { - const toNodeIndex = edges[edgeIndex + edgeToNodeOffset]; - retainerCounts.set(toNodeIndex, (retainerCounts.get(toNodeIndex) ?? 0) + 1); - } - } - - const jsArrayElementNodeIndexes = new Set(); - - function addCategoryValue(category: keyof typeof heapSnapshotCategory, value: number, type: string, name: string, nodeIndex: number | null = null) { - if (value <= 0) return; - categories[category] += value; - addValue(breakdowns[category], classifyHeapSnapshotBreakdown(category, type, name), value); - if (nodeIndex != null) nodeCounts[category]++; - } - - function addJsArrayElementSize(nodeIndex: number) { - const beginEdgeIndex = edgeStartIndexes.get(nodeIndex) ?? 0; - const edgeCount = nodes[nodeIndex + edgeCountOffset] ?? 0; - for (let i = 0, currentEdgeIndex = beginEdgeIndex; i < edgeCount; i++, currentEdgeIndex += edgeFieldCount) { - const edgeType = edges[currentEdgeIndex + edgeTypeOffset]; - if (edgeType !== internalEdgeType) continue; - - const edgeName = strings[edges[currentEdgeIndex + edgeNameOffset]]; - if (edgeName !== 'elements') continue; - - const elementsNodeIndex = edges[currentEdgeIndex + edgeToNodeOffset]; - if ((retainerCounts.get(elementsNodeIndex) ?? 0) === 1) { - const elementsSize = nodes[elementsNodeIndex + selfSizeOffset] ?? 0; - addCategoryValue('jsArrays', elementsSize, 'array elements', 'Array elements', elementsNodeIndex); - jsArrayElementNodeIndexes.add(elementsNodeIndex); - } - break; - } - } - - if (extraNativeBytes > 0) { - addCategoryValue('otherNonJsObjects', extraNativeBytes, 'extra native bytes', 'extra native bytes'); - } - - for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { - const typeId = nodes[nodeIndex + typeOffset]; - const type = nodeTypeNames[typeId] ?? 'unknown'; - const name = strings[nodes[nodeIndex + nameOffset]] ?? ''; - const selfSize = nodes[nodeIndex + selfSizeOffset] ?? 0; - categories.total += selfSize; - nodeCounts.total++; - - if (typeId === hiddenType) { - addCategoryValue('systemObjects', selfSize, type, name, nodeIndex); - continue; - } - - if (typeId === nativeType) { - if (name === 'system / JSArrayBufferData') { - addCategoryValue('typedArrays', selfSize, type, name, nodeIndex); - } else { - addCategoryValue('otherNonJsObjects', selfSize, type, name, nodeIndex); - } - continue; - } - - if (typeId === codeType) { - addCategoryValue('code', selfSize, type, name, nodeIndex); - continue; - } - - if (stringTypes.has(typeId)) { - addCategoryValue('strings', selfSize, type, name, nodeIndex); - continue; - } - - if (name === 'Array') { - addCategoryValue('jsArrays', selfSize, type, name, nodeIndex); - addJsArrayElementSize(nodeIndex); - continue; - } - } - - categories.total += extraNativeBytes; - - for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { - if (jsArrayElementNodeIndexes.has(nodeIndex)) continue; - - const typeId = nodes[nodeIndex + typeOffset]; - if (typeId === hiddenType || typeId === nativeType || typeId === codeType || stringTypes.has(typeId)) continue; - - const name = strings[nodes[nodeIndex + nameOffset]] ?? ''; - if (name === 'Array') continue; - - const type = nodeTypeNames[typeId] ?? 'unknown'; - const selfSize = nodes[nodeIndex + selfSizeOffset] ?? 0; - addCategoryValue('otherJsObjects', selfSize, type, name, nodeIndex); - } - - return { - categories, - nodeCounts, - breakdowns: collapseHeapSnapshotBreakdown(breakdowns), - }; -} - async function getMemoryUsage(pid: number) { const path = `/proc/${pid}/status`; const status = await fs.readFile(path, 'utf-8'); @@ -417,7 +177,7 @@ async function getHeapSnapshotStatistics(serverProcess: ChildProcess): Promise { process.stderr.write(`Failed to delete heap snapshot ${writtenPath}: ${err.message}\n`); diff --git a/packages/frontend/test/e2e/basic.spec.ts b/packages/frontend/test/e2e/basic.spec.ts index ceae8c6c251..d432680e1da 100644 --- a/packages/frontend/test/e2e/basic.spec.ts +++ b/packages/frontend/test/e2e/basic.spec.ts @@ -10,7 +10,7 @@ import { // locator helper locateMkInput, locateMkSwitch, locateMkTextarea, // utils - registerUser, resetState, visitHome, + registerUser, resetState, visitHome, closeUserSetupDialog, postNote, // page utils waitApiResponse, signIn, } from './utils.js'; @@ -194,17 +194,11 @@ test.describe('After user setup', () => { await signIn(page, 'alice', 'alice1234'); // 表示�時間���る��デフォルト秒数��タイムアウト�る - await page.locator('[data-testid="user-setup-dialog"] [data-testid="modal-window-close"]').click({ timeout: 30000 }); - await page.getByTestId('modal-dialog-ok').click(); + await closeUserSetupDialog(page); }); test('note', async ({ page }) => { - await page.getByTestId('open-post-form').waitFor({ state: 'visible' }); - await page.getByTestId('open-post-form').click(); - await page.getByTestId('post-form-text').fill('Hello, Misskey!'); - await page.getByTestId('post-form-submit').click(); - - await page.getByText('Hello, Misskey!').waitFor({ timeout: 15000 }); + await postNote(page, 'Hello, Misskey!'); }); test('open note form with hotkey', async ({ page }) => { diff --git a/packages/frontend/test/e2e/router.spec.ts b/packages/frontend/test/e2e/router.spec.ts index 83754d1fb9b..41c057b510c 100644 --- a/packages/frontend/test/e2e/router.spec.ts +++ b/packages/frontend/test/e2e/router.spec.ts @@ -10,7 +10,7 @@ import { // utils resetState, registerUser, // page utils - signIn, + signIn, closeUserSetupDialogIfVisible, } from './utils.js'; test.describe('Router transition', () => { @@ -26,10 +26,7 @@ test.describe('Router transition', () => { // 表示�時間���る��デフォルト秒数��タイムアウト�る。少�待� await page.waitForTimeout(1000); - if (await page.getByTestId('user-setup-dialog').isVisible()) { - await page.locator('[data-testid="user-setup-dialog"] [data-testid="modal-window-close"]').click(); - await page.getByTestId('modal-dialog-ok').click(); - } + await closeUserSetupDialogIfVisible(page); }); test.describe('Redirect', () => { diff --git a/packages/frontend/test/e2e/shared.ts b/packages/frontend/test/e2e/shared.ts new file mode 100644 index 00000000000..2bff5bf1369 --- /dev/null +++ b/packages/frontend/test/e2e/shared.ts @@ -0,0 +1,135 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { Locator, Page } from 'playwright'; + +export const ADMIN_SETUP_PASSWORD = 'example_password_please_change_this_or_you_will_get_hacked'; +export const DEFAULT_INVITATION_CODE = 'test-invitation-code'; + +export interface RegisteredUser { + id: string; + token: string; +} + +export function assertOk(status: number, route: string): void { + if (status < 200 || status >= 300) { + throw new Error(`${route} failed: status=${status}`); + } +} + +export async function api(baseUrl: string, endpoint: string, body: Record) { + const response = await fetch(`${baseUrl}/api/${endpoint}`, { + method: 'POST', + body: JSON.stringify(body), + headers: { + 'Content-Type': 'application/json', + }, + }); + assertOk(response.status, `/api/${endpoint}`); + if (response.status === 204) return null; + return await response.json(); +} + +export async function resetState(baseUrl: string): Promise { + await api(baseUrl, 'reset-db', {}); +} + +export async function registerUser( + baseUrl: string, + username: string, + password: string, + isAdmin = false, +): Promise { + const route = isAdmin ? 'admin/accounts/create' : 'signup'; + const result = await api(baseUrl, route, { + username, + password, + ...(isAdmin ? { setupPassword: ADMIN_SETUP_PASSWORD } : {}), + }); + return result as RegisteredUser; +} + +export function locateMkInput(page: Page, testId: string): Locator { + return page.locator(`[data-testid="${testId}"] input`); +} + +export function locateMkTextarea(page: Page, testId: string): Locator { + return page.locator(`[data-testid="${testId}"] textarea`); +} + +export function locateMkSwitch(page: Page, testId: string): Locator { + return page.locator(`[data-testid="${testId}"] [data-testid="switch-toggle"]`); +} + +export async function visitHome(page: Page, baseUrl: string): Promise { + await page.goto(`${baseUrl}/`); + await page.locator('button').first().waitFor({ state: 'visible', timeout: 30_000 }); +} + +export async function waitApiResponse(page: Page, path: string, timeout = 30_000): Promise { + await page.waitForResponse((response) => { + return response.url().endsWith(path) && response.request().method() === 'POST'; + }, { timeout }); +} + +export async function signIn(page: Page, baseUrl: string, username: string, password: string): Promise { + await visitHome(page, baseUrl); + await page.getByTestId('signin').click(); + await page.getByTestId('signin-page-input').waitFor({ state: 'visible', timeout: 10_000 }); + await locateMkInput(page, 'signin-username').fill(username); + await page.keyboard.press('Enter'); + await page.getByTestId('signin-page-password').waitFor({ state: 'visible', timeout: 10_000 }); + await locateMkInput(page, 'signin-password').fill(password); + const signinResponse = waitApiResponse(page, '/api/signin-flow'); + await page.keyboard.press('Enter'); + await signinResponse; +} + +export async function acceptSignupRules(page: Page): Promise { + await page.getByTestId('signup-rules-continue').waitFor({ state: 'visible' }); + await locateMkSwitch(page, 'signup-rules-notes-agree').click(); + await page.getByTestId('modal-dialog-ok').click(); + await page.getByTestId('signup-rules-continue').click(); +} + +export async function signupThroughUi( + page: Page, + options: { + username: string; + password: string; + invitationCode?: string; + }, +): Promise { + await page.getByTestId('signup').click(); + await acceptSignupRules(page); + + await locateMkInput(page, 'signup-username').fill(options.username); + await locateMkInput(page, 'signup-password').fill(options.password); + await locateMkInput(page, 'signup-password-retype').fill(options.password); + await locateMkInput(page, 'signup-invitation-code').fill(options.invitationCode ?? DEFAULT_INVITATION_CODE); + + const signupResponse = waitApiResponse(page, '/api/signup'); + await page.getByTestId('signup-submit').click(); + await signupResponse; +} + +export async function closeUserSetupDialog(page: Page, timeout = 30_000): Promise { + await page.locator('[data-testid="user-setup-dialog"] [data-testid="modal-window-close"]').click({ timeout }); + await page.getByTestId('modal-dialog-ok').click(); +} + +export async function closeUserSetupDialogIfVisible(page: Page): Promise { + if (await page.getByTestId('user-setup-dialog').isVisible()) { + await closeUserSetupDialog(page); + } +} + +export async function postNote(page: Page, noteText: string, timeout = 15_000): Promise { + await page.getByTestId('open-post-form').waitFor({ state: 'visible' }); + await page.getByTestId('open-post-form').click(); + await page.getByTestId('post-form-text').fill(noteText); + await page.getByTestId('post-form-submit').click(); + await page.getByText(noteText).waitFor({ timeout }); +} diff --git a/packages/frontend/test/e2e/utils.ts b/packages/frontend/test/e2e/utils.ts index 4a210764643..67bcfd10d1d 100644 --- a/packages/frontend/test/e2e/utils.ts +++ b/packages/frontend/test/e2e/utils.ts @@ -3,92 +3,50 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import type { Locator, Page } from 'playwright'; +import type { Page } from 'playwright'; +import { + registerUser as registerUserWithBaseUrl, + resetState as resetStateWithBaseUrl, + signIn as signInWithBaseUrl, + visitHome as visitHomeWithBaseUrl, +} from './shared.js'; +export type { RegisteredUser } from './shared.js'; +export { + ADMIN_SETUP_PASSWORD, + DEFAULT_INVITATION_CODE, + acceptSignupRules, + assertOk, + closeUserSetupDialog, + closeUserSetupDialogIfVisible, + locateMkInput, + locateMkSwitch, + locateMkTextarea, + postNote, + waitApiResponse, +} from './shared.js'; export const BASE_URL = 'http://localhost:61812'; -export const ADMIN_SETUP_PASSWORD = 'example_password_please_change_this_or_you_will_get_hacked'; - -export interface RegisteredUser { - id: string; - token: string; -} //#region Misc -export function assertOk(status: number, route: string): void { - if (status < 200 || status >= 300) { - throw new Error(`${route} failed: status=${status}`); - } -} - export async function resetState(): Promise { - const response = await fetch(`${BASE_URL}/api/reset-db`, { - method: 'POST', - body: '{}', - headers: { - 'Content-Type': 'application/json', - }, - }); - assertOk(response.status, '/api/reset-db'); + await resetStateWithBaseUrl(BASE_URL); } export async function registerUser( username: string, password: string, isAdmin = false, -): Promise { - const route = isAdmin ? '/api/admin/accounts/create' : '/api/signup'; - const response = await fetch(`${BASE_URL}${route}`, { - method: 'POST', - body: JSON.stringify({ - username, - password, - ...(isAdmin ? { setupPassword: ADMIN_SETUP_PASSWORD } : {}), - }), - headers: { - 'Content-Type': 'application/json', - }, - }); - assertOk(response.status, route); - return await response.json() as RegisteredUser; -} -//#endregion - -//#region Locator Helpers -export function locateMkInput(page: Page, testId: string): Locator { - return page.locator(`[data-testid="${testId}"] input`); -} - -export function locateMkTextarea(page: Page, testId: string): Locator { - return page.locator(`[data-testid="${testId}"] textarea`); -} - -export function locateMkSwitch(page: Page, testId: string): Locator { - return page.locator(`[data-testid="${testId}"] [data-testid="switch-toggle"]`); +): ReturnType { + return registerUserWithBaseUrl(BASE_URL, username, password, isAdmin); } //#endregion //#region Page Helpers export async function visitHome(page: Page): Promise { - await page.goto(`${BASE_URL}/`); - await page.locator('button').first().waitFor({ state: 'visible', timeout: 30_000 }); -} - -export async function waitApiResponse(page: Page, path: string): Promise { - await page.waitForResponse((response) => { - return response.url().endsWith(path) && response.request().method() === 'POST'; - }, { timeout: 30_000 }); + await visitHomeWithBaseUrl(page, BASE_URL); } export async function signIn(page: Page, username: string, password: string): Promise { - await visitHome(page); - await page.getByTestId('signin').click(); - await page.getByTestId('signin-page-input').waitFor({ state: 'visible', timeout: 10_000 }); - await locateMkInput(page, 'signin-username').fill(username); - await page.keyboard.press('Enter'); - await page.getByTestId('signin-page-password').waitFor({ state: 'visible', timeout: 10_000 }); - await locateMkInput(page, 'signin-password').fill(password); - const signinResponse = waitApiResponse(page, '/api/signin-flow'); - await page.keyboard.press('Enter'); - await signinResponse; + await signInWithBaseUrl(page, BASE_URL, username, password); } //#endregion From df063d9386b789f8be9fbc955a92043aaa15fdf6 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:20:34 +0900 Subject: [PATCH 367/578] enhance(dev): tweak get-backend-memory --- .../measure-backend-memory-comparison.mts | 28 +-- .github/scripts/memory-stability-util.mts | 75 ++++++++ .github/workflows/get-backend-memory.yml | 1 + .github/workflows/lint.yml | 2 + packages/backend/scripts/measure-memory.mts | 178 +++++------------- 5 files changed, 131 insertions(+), 153 deletions(-) create mode 100644 .github/scripts/memory-stability-util.mts diff --git a/.github/scripts/measure-backend-memory-comparison.mts b/.github/scripts/measure-backend-memory-comparison.mts index 2e7e67fe5af..ee95c681653 100644 --- a/.github/scripts/measure-backend-memory-comparison.mts +++ b/.github/scripts/measure-backend-memory-comparison.mts @@ -8,30 +8,19 @@ import { copyFile, rm, writeFile } from 'node:fs/promises'; import { join, resolve } from 'node:path'; import * as util from './utility.mts'; import * as heapSnapshotUtil from './heap-snapshot-util.mts'; -import type { MemoryReportRaw } from '../../packages/backend/scripts/measure-memory.mts'; +import type { MemorySample } from '../../packages/backend/scripts/measure-memory.mts'; const phases = ['afterGc'] as const; export type MemoryReport = { timestamp: string; - sampleCount: any; + sampleCount: number; aggregation: string; - measurement: { - startupTimeoutMs: any; - memorySettleTimeMs: any; - ipcTimeoutMs: any; - requestCount: any; - heapSnapshot: { - enabled: any; - timeoutMs: any; - breakdownTopN: any; - }; - }; summary: Record; heapSnapshot?: heapSnapshotUtil.HeapSnapshotData; }>; - samples: (MemoryReportRaw['samples'][number] & { + samples: (MemorySample & { round: number; })[]; }; @@ -41,6 +30,8 @@ const [baseDirArg, headDirArg, baseOutputArg, headOutputArg] = process.argv.slic const HEAP_SNAPSHOT_BREAKDOWN_TOP_N = util.readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', heapSnapshotUtil.defaultHeapSnapshotBreakdownTopN, 1); const HEAD_HEAP_SNAPSHOT_WORK_DIR = resolve('head-heap-snapshots'); const HEAD_HEAP_SNAPSHOT_OUTPUT_PATH = resolve('head-heap-snapshot.heapsnapshot'); +// Use the head checkout's measurement harness for both targets so only the built backend differs. +const MEASURE_MEMORY_SCRIPT = resolve(import.meta.dirname, '../../packages/backend/scripts/measure-memory.mts'); async function resetState(repoDir: string) { const require = createRequire(join(repoDir, 'packages/backend/package.json')); @@ -115,20 +106,17 @@ async function measureRepo(label: string, repoDir: string, round: number, option process.stderr.write(`[${label}] Measuring memory\n`); const measureEnv = { ...process.env, - MK_MEMORY_SAMPLE_COUNT: '1', + MK_MEMORY_BACKEND_DIR: resolve(repoDir, 'packages/backend'), } as NodeJS.ProcessEnv; if (round <= 0) measureEnv.MK_MEMORY_HEAP_SNAPSHOT = '0'; if (options.heapSnapshotSavePath != null) measureEnv.MK_MEMORY_HEAP_SNAPSHOT_SAVE_PATH = options.heapSnapshotSavePath; - const stdout = await util.run('node', ['packages/backend/scripts/measure-memory.mts'], { + const stdout = await util.run('node', [MEASURE_MEMORY_SCRIPT], { cwd: repoDir, env: measureEnv, }); - const report = JSON.parse(stdout) as MemoryReportRaw; - const sample = report.samples[0]; - - return sample; + return JSON.parse(stdout) as MemorySample; } function headHeapSnapshotPath(round: number) { diff --git a/.github/scripts/memory-stability-util.mts b/.github/scripts/memory-stability-util.mts new file mode 100644 index 00000000000..0a9a8d4f525 --- /dev/null +++ b/.github/scripts/memory-stability-util.mts @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { setTimeout } from 'node:timers/promises'; + +type MemoryStabilityTimer = { + now: () => number; + wait: (durationMs: number) => Promise; +}; + +const intervalMs = 2000; +const maxWaitMs = 10000; +const windowSize = 3; +const slopeThresholdKiBPerSecond = 256; +const stabilityMetrics = ['Pss', 'Private_Dirty'] as const; + +const defaultTimer: MemoryStabilityTimer = { + now: () => performance.now(), + wait: durationMs => setTimeout(durationMs), +}; + +function getMaxAbsoluteSlopes>(readings: { elapsedMs: number; memoryUsage: T }[]) { + const result = {} as Record; + + for (const metric of stabilityMetrics) { + let maxAbsoluteSlope = 0; + for (let i = 1; i < readings.length; i++) { + const previous = readings[i - 1]; + const current = readings[i]; + const durationSeconds = (current.elapsedMs - previous.elapsedMs) / 1000; + maxAbsoluteSlope = Math.max(maxAbsoluteSlope, Math.abs(current.memoryUsage[metric] - previous.memoryUsage[metric]) / durationSeconds); + } + result[metric] = maxAbsoluteSlope; + } + + return result; +} + +export async function measureMemoryUntilStable>( + readMemoryUsage: () => Promise, + timer: MemoryStabilityTimer = defaultTimer, +) { + const startedAt = timer.now(); + const readings: { elapsedMs: number; memoryUsage: T }[] = []; + let maxAbsoluteSlopesKiBPerSecond: Record | null = null; + + while (true) { + const memoryUsage = await readMemoryUsage(); + const elapsedMs = timer.now() - startedAt; + readings.push({ elapsedMs, memoryUsage }); + + let converged = false; + if (readings.length >= windowSize) { + const latestSlopes = getMaxAbsoluteSlopes(readings.slice(-windowSize)); + maxAbsoluteSlopesKiBPerSecond = latestSlopes; + converged = stabilityMetrics.every(metric => latestSlopes[metric] <= slopeThresholdKiBPerSecond); + } + + if (converged || elapsedMs >= maxWaitMs) { + return { + memoryUsage, + stability: { + converged, + readingCount: readings.length, + elapsedMs, + maxAbsoluteSlopesKiBPerSecond, + }, + }; + } + + await timer.wait(Math.min(intervalMs, maxWaitMs - elapsedMs)); + } +} diff --git a/.github/workflows/get-backend-memory.yml b/.github/workflows/get-backend-memory.yml index 400a81a7d99..0d0bec33075 100644 --- a/.github/workflows/get-backend-memory.yml +++ b/.github/workflows/get-backend-memory.yml @@ -12,6 +12,7 @@ on: - .github/scripts/utility.mts - .github/scripts/backend-memory-report.mts - .github/scripts/measure-backend-memory-comparison.mts + - .github/scripts/memory-stability-util*.mts - .github/scripts/backend-js-footprint.mjs - .github/scripts/backend-js-footprint-loader.mjs - .github/scripts/backend-js-footprint-require.cjs diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d3c745aea6d..c8e24fb19b9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,6 +19,7 @@ on: - packages/shared/eslint.config.js - scripts/check-dts*.mjs - .github/scripts/frontend-js-size*.mts + - .github/scripts/memory-stability-util*.mts - .github/scripts/utility.mts - .github/workflows/lint.yml - package.json @@ -37,6 +38,7 @@ on: - packages/shared/eslint.config.js - scripts/check-dts*.mjs - .github/scripts/frontend-js-size*.mts + - .github/scripts/memory-stability-util*.mts - .github/scripts/utility.mts - .github/workflows/lint.yml - package.json diff --git a/packages/backend/scripts/measure-memory.mts b/packages/backend/scripts/measure-memory.mts index eb7a9c037a8..55aab61a84c 100644 --- a/packages/backend/scripts/measure-memory.mts +++ b/packages/backend/scripts/measure-memory.mts @@ -4,16 +4,15 @@ */ import { ChildProcess, fork } from 'node:child_process'; -import { setTimeout } from 'node:timers/promises'; -import { fileURLToPath } from 'node:url'; -import { dirname, join } from 'node:path'; +import { dirname, join, resolve } from 'node:path'; import { tmpdir } from 'node:os'; -//import * as http from 'node:http'; import * as fs from 'node:fs/promises'; import { analyzeHeapSnapshot, defaultHeapSnapshotBreakdownTopN, type HeapSnapshotData } from '../../../.github/scripts/heap-snapshot-util.mts'; +import { measureMemoryUntilStable } from '../../../.github/scripts/memory-stability-util.mts'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +const backendDir = process.env.MK_MEMORY_BACKEND_DIR == null || process.env.MK_MEMORY_BACKEND_DIR === '' + ? join(import.meta.dirname, '..') + : resolve(process.env.MK_MEMORY_BACKEND_DIR); function readIntegerEnv(name, defaultValue, min) { const rawValue = process.env[name]; @@ -33,11 +32,8 @@ function readBooleanEnv(name, defaultValue) { throw new Error(`${name} must be one of: 1, 0, true, false`); } -const SAMPLE_COUNT = readIntegerEnv('MK_MEMORY_SAMPLE_COUNT', 3, 1); // Number of samples to measure const STARTUP_TIMEOUT = readIntegerEnv('MK_MEMORY_STARTUP_TIMEOUT_MS', 120000, 1); // Timeout for server startup -const MEMORY_SETTLE_TIME = readIntegerEnv('MK_MEMORY_SETTLE_TIME_MS', 10000, 0); // Wait after startup for memory to settle const IPC_TIMEOUT = readIntegerEnv('MK_MEMORY_IPC_TIMEOUT_MS', 30000, 1); // Timeout for IPC responses -const REQUEST_COUNT = readIntegerEnv('MK_MEMORY_REQUEST_COUNT', 10, 0); const HEAP_SNAPSHOT = readBooleanEnv('MK_MEMORY_HEAP_SNAPSHOT', false); const HEAP_SNAPSHOT_TIMEOUT = readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_TIMEOUT_MS', 120000, 1); const HEAP_SNAPSHOT_BREAKDOWN_TOP_N = readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', defaultHeapSnapshotBreakdownTopN, 1); @@ -187,17 +183,23 @@ async function getHeapSnapshotStatistics(serverProcess: ChildProcess): Promise getSmapsRollupMemoryUsage(pid), + ); + return { - ...await getMemoryUsage(pid), - ...await getSmapsRollupMemoryUsage(pid), - ...await getRuntimeMemoryUsage(serverProcess), + memoryUsage: { + ...await getMemoryUsage(pid), + ...stableSmapsRollup.memoryUsage, + ...await getRuntimeMemoryUsage(serverProcess), + }, + stability: stableSmapsRollup.stability, }; } async function measureMemory() { - // Start the Misskey backend server using fork to enable IPC - const serverProcess = fork(join(__dirname, '../built/entry.js'), [], { - cwd: join(__dirname, '..'), + const serverProcess = fork(join(backendDir, 'built/entry.js'), [], { + cwd: backendDir, env: { ...process.env, NODE_ENV: 'production', @@ -209,16 +211,13 @@ async function measureMemory() { execArgv: [...process.execArgv, '--expose-gc'], }); - let serverReady = false; - - // Listen for the 'ok' message from the server indicating it's ready - serverProcess.on('message', (message) => { - if (message === 'ok') { - serverReady = true; - } - }); + const serverReady = waitForMessage( + serverProcess, + (message): message is 'ok' => message === 'ok', + 'server startup', + STARTUP_TIMEOUT, + ); - // Handle server output serverProcess.stdout?.on('data', (data) => { process.stderr.write(`[server stdout] ${data}`); }); @@ -227,7 +226,6 @@ async function measureMemory() { process.stderr.write(`[server stderr] ${data}`); }); - // Handle server error serverProcess.on('error', (err) => { process.stderr.write(`[server error] ${err}\n`); }); @@ -245,141 +243,55 @@ async function measureMemory() { if (message === 'gc unavailable') { throw new Error('GC is unavailable. Start the process with --expose-gc to enable this feature.'); } - - 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 const startupStartTime = Date.now(); - while (!serverReady) { - if (Date.now() - startupStartTime > STARTUP_TIMEOUT) { - serverProcess.kill('SIGTERM'); - throw new Error('Server startup timeout'); - } - await setTimeout(100); + try { + await serverReady; + } catch (err) { + serverProcess.kill('SIGTERM'); + throw err; } const startupTime = Date.now() - startupStartTime; process.stderr.write(`Server started in ${startupTime}ms\n`); - // Wait for memory to settle - await setTimeout(MEMORY_SETTLE_TIME); - - //const beforeGc = await getAllMemoryUsage(serverProcess); - await triggerGc(); - const memoryUsageAfterGC = await getAllMemoryUsage(serverProcess); - - //// create some http requests to simulate load - //await Promise.all( - // Array.from({ length: REQUEST_COUNT }).map(() => createRequest()), - //); - - //await triggerGc(); - - //const afterRequest = await getAllMemoryUsage(serverProcess); + const afterGc = await getAllMemoryUsage(serverProcess); + process.stderr.write(`Memory ${afterGc.stability.converged ? 'stabilized' : 'did not stabilize'} after ${afterGc.stability.readingCount} readings over ${Math.round(afterGc.stability.elapsedMs)}ms\n`); const heapSnapshotAfterGc = await getHeapSnapshotStatistics(serverProcess); - // Stop the server - serverProcess.kill('SIGTERM'); - - // Wait for process to exit - let exited = false; - await new Promise((resolve) => { - serverProcess.on('exit', () => { - exited = true; - resolve(undefined); - }); - // Force kill after 10 seconds if not exited - setTimeout(10000).then(() => { - if (!exited) { - serverProcess.kill('SIGKILL'); - } - resolve(undefined); + const serverExited = new Promise(resolve => { + const timer = globalThis.setTimeout(() => { + serverProcess.kill('SIGKILL'); + resolve(); + }, 10000); + serverProcess.once('exit', () => { + globalThis.clearTimeout(timer); + resolve(); }); }); + serverProcess.kill('SIGTERM'); + await serverExited; - const result = { + return { timestamp: new Date().toISOString(), phases: { - //beforeGc, afterGc: { - memoryUsage: memoryUsageAfterGC, + memoryUsage: afterGc.memoryUsage, + memoryStability: afterGc.stability, heapSnapshot: heapSnapshotAfterGc, }, - //afterRequest, }, }; - - return result; } -export type MemoryReportRaw = { - timestamp: string; - sampleCount: number; - measurement: { - startupTimeoutMs: number; - memorySettleTimeMs: number; - ipcTimeoutMs: number; - requestCount: number; - heapSnapshot: { - enabled: boolean; - timeoutMs: number; - breakdownTopN: number; - }; - }; - samples: Awaited>[]; -}; +export type MemorySample = Awaited>; async function main() { - const results = []; - for (let i = 0; i < SAMPLE_COUNT; i++) { - process.stderr.write(`Starting sample ${i + 1}/${SAMPLE_COUNT}\n`); - const res = await measureMemory(); - results.push(res); - } - - const result: MemoryReportRaw = { - timestamp: new Date().toISOString(), - sampleCount: SAMPLE_COUNT, - measurement: { - startupTimeoutMs: STARTUP_TIMEOUT, - memorySettleTimeMs: MEMORY_SETTLE_TIME, - ipcTimeoutMs: IPC_TIMEOUT, - requestCount: REQUEST_COUNT, - heapSnapshot: { - enabled: HEAP_SNAPSHOT, - timeoutMs: HEAP_SNAPSHOT_TIMEOUT, - breakdownTopN: HEAP_SNAPSHOT_BREAKDOWN_TOP_N, - }, - }, - samples: results, - }; - - // Output as JSON to stdout - console.log(JSON.stringify(result, null, 2)); + console.log(JSON.stringify(await measureMemory(), null, 2)); } main().catch((err) => { From 22cdc24b04fa1ca8af78de5b6da9b41df410fe91 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 14:10:30 +0900 Subject: [PATCH 368/578] add test --- .../scripts/memory-stability-util.test.mts | 110 ++++++++++++++++++ .github/workflows/lint.yml | 1 + 2 files changed, 111 insertions(+) create mode 100644 .github/scripts/memory-stability-util.test.mts diff --git a/.github/scripts/memory-stability-util.test.mts b/.github/scripts/memory-stability-util.test.mts new file mode 100644 index 00000000000..70bbb3924bf --- /dev/null +++ b/.github/scripts/memory-stability-util.test.mts @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { measureMemoryUntilStable } from './memory-stability-util.mts'; + +function createTimer() { + let elapsedMs = 0; + + return { + now: () => elapsedMs, + wait: async (durationMs: number) => { + elapsedMs += durationMs; + }, + }; +} + +async function measure(readings: Record[]) { + let readCount = 0; + const result = await measureMemoryUntilStable( + async () => readings[readCount++], + createTimer(), + ); + return { result, readCount }; +} + +test('adopts the latest reading once Pss and Private_Dirty slopes converge', async () => { + const readings = [ + { Pss: 1000, Private_Dirty: 500, HeapUsed: 300 }, + { Pss: 1100, Private_Dirty: 520, HeapUsed: 310 }, + { Pss: 1200, Private_Dirty: 540, HeapUsed: 320 }, + ]; + const { result, readCount } = await measure(readings); + + assert.equal(readCount, 3); + assert.deepEqual(result.memoryUsage, readings[2]); + assert.deepEqual(result.stability, { + converged: true, + readingCount: 3, + elapsedMs: 4000, + maxAbsoluteSlopesKiBPerSecond: { + Pss: 50, + Private_Dirty: 10, + }, + }); +}); + +test('uses only the latest readings when determining convergence', async () => { + const readings = [ + { Pss: 1000, Private_Dirty: 500 }, + { Pss: 2000, Private_Dirty: 1000 }, + { Pss: 3000, Private_Dirty: 1500 }, + { Pss: 3040, Private_Dirty: 1520 }, + { Pss: 3080, Private_Dirty: 1540 }, + ]; + const { result, readCount } = await measure(readings); + + assert.equal(readCount, 5); + assert.equal(result.stability.converged, true); + assert.deepEqual(result.stability.maxAbsoluteSlopesKiBPerSecond, { + Pss: 20, + Private_Dirty: 10, + }); +}); + +test('bounds the wait and reports the latest slopes when memory does not converge', async () => { + const readings = [ + { Pss: 1000, Private_Dirty: 500 }, + { Pss: 1600, Private_Dirty: 520 }, + { Pss: 2200, Private_Dirty: 540 }, + { Pss: 2800, Private_Dirty: 560 }, + { Pss: 3400, Private_Dirty: 580 }, + { Pss: 4000, Private_Dirty: 600 }, + ]; + const { result, readCount } = await measure(readings); + + assert.equal(readCount, 6); + assert.deepEqual(result.memoryUsage, readings[5]); + assert.deepEqual(result.stability, { + converged: false, + readingCount: 6, + elapsedMs: 10000, + maxAbsoluteSlopesKiBPerSecond: { + Pss: 300, + Private_Dirty: 10, + }, + }); +}); + +test('does not treat opposing adjacent slopes as convergence', async () => { + const readings = [ + { Pss: 1000, Private_Dirty: 500 }, + { Pss: 1600, Private_Dirty: 500 }, + { Pss: 1000, Private_Dirty: 500 }, + { Pss: 1600, Private_Dirty: 500 }, + { Pss: 1000, Private_Dirty: 500 }, + { Pss: 1600, Private_Dirty: 500 }, + ]; + const { result, readCount } = await measure(readings); + + assert.equal(readCount, 6); + assert.equal(result.stability.converged, false); + assert.deepEqual(result.stability.maxAbsoluteSlopesKiBPerSecond, { + Pss: 300, + Private_Dirty: 0, + }); +}); diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c8e24fb19b9..63f8684c33e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -151,3 +151,4 @@ jobs: with: node-version-file: '.node-version' - run: node --test .github/scripts/frontend-js-size.test.mts + - run: node --test .github/scripts/memory-stability-util.test.mts From 212fcaf254352e8e682758044e4e18f93fb207ad Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 14:44:49 +0900 Subject: [PATCH 369/578] enhance(dev): tweak get-backend-memory --- .github/scripts/backend-memory-report.mts | 46 ++++++++++----------- packages/backend/scripts/measure-memory.mts | 8 ++-- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/.github/scripts/backend-memory-report.mts b/.github/scripts/backend-memory-report.mts index 9aae10d8874..fc64cb6db53 100644 --- a/.github/scripts/backend-memory-report.mts +++ b/.github/scripts/backend-memory-report.mts @@ -47,8 +47,7 @@ const memoryReportPhases = [ const metrics = [ 'HeapUsed', 'Pss', - 'Private_Dirty', - 'VmRSS', + 'USS', 'External', ] as const; @@ -57,16 +56,27 @@ function formatMemoryMb(valueKiB: number | null | undefined) { return `${util.formatNumber(valueKiB / 1000)} MB`; } -function getMemoryValue(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { - return report.summary[phase].memoryUsage[metric]; +function formatMetricName(metric: typeof metrics[number]) { + return metric === 'Pss' ? 'PSS' : metric; } function getMemoryValueFromSample(sample: MemoryReport['samples'][number], phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { - return sample.phases[phase].memoryUsage[metric]; + const memoryUsage = sample.phases[phase].memoryUsage; + if (metric !== 'USS') return memoryUsage[metric]; + return memoryUsage.Private_Clean + memoryUsage.Private_Dirty; +} + +function getSampleValues(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { + return report.samples.map(sample => getMemoryValueFromSample(sample, phase, metric)); +} + +function getMemoryValue(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { + if (metric !== 'USS') return report.summary[phase].memoryUsage[metric]; + return util.median(getSampleValues(report, phase, metric)); } function getSampleSpread(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { - const values = report.samples.map(sample => getMemoryValueFromSample(sample, phase, metric)); + const values = getSampleValues(report, phase, metric); if (values.length < 2) return null; const center = util.median(values); @@ -91,9 +101,9 @@ function renderMainTableForPhase(base: MemoryReport, head: MemoryReport, phase: const headSpread = getSampleSpread(head, phase, metric); const summary = util.pairedDeltaSummary(base.samples, head.samples, (sample) => getMemoryValueFromSample(sample, phase, metric)); const percent = summary.median * 100 / baseValue; - const deltaMedian = summary == null ? '-' : `${formatDeltaMemory(summary.median)}
${util.formatDeltaPercent(percent, 0.1).replaceAll('\\%', '\\\\%')}`; + const deltaMedian = `${formatDeltaMemory(summary.median)}
${util.formatDeltaPercent(percent, 0.1).replaceAll('\\%', '\\\\%')}`; - lines.push(`| **${metric}** | ${formatMemoryMb(baseValue)}
± ${formatMemoryMb(baseSpread)} | ${formatMemoryMb(headValue)}
± ${formatMemoryMb(headSpread)} | ${deltaMedian} | ${summary?.mad == null ? '-' : formatMemoryMb(summary.mad)} | ${summary == null ? '-' : formatDeltaMemory(summary.min)} | ${summary == null ? '-' : formatDeltaMemory(summary.max)} |`); + lines.push(`| **${formatMetricName(metric)}** | ${formatMemoryMb(baseValue)}
± ${formatMemoryMb(baseSpread)} | ${formatMemoryMb(headValue)}
± ${formatMemoryMb(headSpread)} | ${deltaMedian} | ${formatMemoryMb(summary.mad)} | ${formatDeltaMemory(summary.min)} | ${formatDeltaMemory(summary.max)} |`); } return lines.join('\n'); @@ -384,27 +394,15 @@ if (jsFootprintSection != null) { lines.push(''); } -function getWarningMetric(base: MemoryReport, head: MemoryReport) { - for (const metric of ['Pss', 'Private_Dirty', 'VmRSS'] as const) { - if (getMemoryValue(base, 'afterGc', metric) != null && getMemoryValue(head, 'afterGc', metric) != null) { - return metric; - } - } - return null; -} - function getDiffPercent(base: MemoryReport, head: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { const baseValue = getMemoryValue(base, phase, metric); const headValue = getMemoryValue(head, phase, metric); - if (baseValue == null || headValue == null || baseValue <= 0) return null; - return ((headValue - baseValue) * 100) / baseValue; } function isBeyondSampleNoise(base: MemoryReport, head: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { const baseValue = getMemoryValue(base, phase, metric); const headValue = getMemoryValue(head, phase, metric); - if (baseValue == null || headValue == null) return false; const delta = headValue - baseValue; if (delta <= 0) return false; @@ -417,10 +415,10 @@ function isBeyondSampleNoise(base: MemoryReport, head: MemoryReport, phase: type return delta > combinedSpread * 3; } -const warningMetric = getWarningMetric(base, head); -const warningDiffPercent = warningMetric == null ? null : getDiffPercent(base, head, 'afterGc', warningMetric); -if (warningMetric != null && warningDiffPercent != null && warningDiffPercent > 5 && isBeyondSampleNoise(base, head, 'afterGc', warningMetric)) { - lines.push(`⚠� **Warning**: Memory usage (${warningMetric}) has increased by more than 5% and exceeds the observed sample noise. Please verify this is not an unintended change.`); +const warningMetric = 'Pss'; +const warningDiffPercent = getDiffPercent(base, head, 'afterGc', warningMetric); +if (warningDiffPercent > 5 && isBeyondSampleNoise(base, head, 'afterGc', warningMetric)) { + lines.push(`⚠� **Warning**: Memory usage (${formatMetricName(warningMetric)}) has increased by more than 5% and exceeds the observed sample noise. Please verify this is not an unintended change.`); lines.push(''); } diff --git a/packages/backend/scripts/measure-memory.mts b/packages/backend/scripts/measure-memory.mts index 55aab61a84c..a95eb3075c3 100644 --- a/packages/backend/scripts/measure-memory.mts +++ b/packages/backend/scripts/measure-memory.mts @@ -57,14 +57,14 @@ type HeapSnapshotErrorMessage = { }; type HeapSnapshotResponseMessage = HeapSnapshotMessage | HeapSnapshotErrorMessage; -function parseMemoryFile(content: string, keys: KS, path: string, required: boolean): Record { +function parseMemoryFile(content: string, keys: KS, path: string): Record { const result = {} as Record; for (const _key of keys) { const key = _key as KS[number]; const match = content.match(new RegExp(`${key}:\\s+(\\d+)\\s+kB`)); if (match) { result[key] = parseInt(match[1], 10); - } else if (required) { + } else { throw new Error(`Failed to parse ${key} from ${path}`); } } @@ -78,13 +78,13 @@ function bytesToKiB(value: number) { async function getMemoryUsage(pid: number) { const path = `/proc/${pid}/status`; const status = await fs.readFile(path, 'utf-8'); - return parseMemoryFile(status, procStatusKeys, path, true); + return parseMemoryFile(status, procStatusKeys, path); } async function getSmapsRollupMemoryUsage(pid: number) { const path = `/proc/${pid}/smaps_rollup`; const smapsRollup = await fs.readFile(path, 'utf-8'); - return parseMemoryFile(smapsRollup, smapsRollupKeys, path, false); + return parseMemoryFile(smapsRollup, smapsRollupKeys, path); } function isRecord(value: unknown): value is Record { From b5e470b6d4c3635b382b2a6fe6b327b5d4a9f420 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:59:41 +0900 Subject: [PATCH 370/578] enhance(dev): tweak get-backend-memory --- .github/scripts/backend-memory-report.mts | 5 +- .../measure-backend-memory-comparison.mts | 46 +++++++++++-------- .github/workflows/get-backend-memory.yml | 9 +++- .github/workflows/report-backend-memory.yml | 19 +++++--- 4 files changed, 51 insertions(+), 28 deletions(-) diff --git a/.github/scripts/backend-memory-report.mts b/.github/scripts/backend-memory-report.mts index fc64cb6db53..4a701655ecd 100644 --- a/.github/scripts/backend-memory-report.mts +++ b/.github/scripts/backend-memory-report.mts @@ -384,8 +384,9 @@ if (heapSnapshotSection != null) { lines.push(''); } -const artifactUrl = process.env.MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_HEAD!.trim(); -lines.push(`[Download representative V8 heap snapshot (head)](${artifactUrl})`); +const baseHeapSnapshotArtifactUrl = process.env.MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_BASE!.trim(); +const headHeapSnapshotArtifactUrl = process.env.MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_HEAD!.trim(); +lines.push(`Download representative V8 heap snapshot [base](${baseHeapSnapshotArtifactUrl}) / [head](${headHeapSnapshotArtifactUrl})`); lines.push(''); const jsFootprintSection = renderJsFootprintSection(baseJsFootprint, headJsFootprint); diff --git a/.github/scripts/measure-backend-memory-comparison.mts b/.github/scripts/measure-backend-memory-comparison.mts index ee95c681653..a4e93b3ce42 100644 --- a/.github/scripts/measure-backend-memory-comparison.mts +++ b/.github/scripts/measure-backend-memory-comparison.mts @@ -28,8 +28,15 @@ export type MemoryReport = { const [baseDirArg, headDirArg, baseOutputArg, headOutputArg] = process.argv.slice(2); const HEAP_SNAPSHOT_BREAKDOWN_TOP_N = util.readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', heapSnapshotUtil.defaultHeapSnapshotBreakdownTopN, 1); -const HEAD_HEAP_SNAPSHOT_WORK_DIR = resolve('head-heap-snapshots'); -const HEAD_HEAP_SNAPSHOT_OUTPUT_PATH = resolve('head-heap-snapshot.heapsnapshot'); +const heapSnapshotLabels = ['base', 'head'] as const; +const HEAP_SNAPSHOT_WORK_DIRS = { + base: resolve('base-heap-snapshots'), + head: resolve('head-heap-snapshots'), +}; +const HEAP_SNAPSHOT_OUTPUT_PATHS = { + base: resolve('base-heap-snapshot.heapsnapshot'), + head: resolve('head-heap-snapshot.heapsnapshot'), +}; // Use the head checkout's measurement harness for both targets so only the built backend differs. const MEASURE_MEMORY_SCRIPT = resolve(import.meta.dirname, '../../packages/backend/scripts/measure-memory.mts'); @@ -119,11 +126,11 @@ async function measureRepo(label: string, repoDir: string, round: number, option return JSON.parse(stdout) as MemorySample; } -function headHeapSnapshotPath(round: number) { - return join(HEAD_HEAP_SNAPSHOT_WORK_DIR, `round-${round}.heapsnapshot`); +function heapSnapshotPath(label: typeof heapSnapshotLabels[number], round: number) { + return join(HEAP_SNAPSHOT_WORK_DIRS[label], `round-${round}.heapsnapshot`); } -function selectRepresentativeHeadHeapSnapshotRound(samples: MemoryReport['samples'], summary: MemoryReport['summary']) { +function selectRepresentativeHeapSnapshotRound(samples: MemoryReport['samples'], summary: MemoryReport['summary']) { const medianTotal = summary.afterGc.heapSnapshot?.categories?.total; if (medianTotal == null || !Number.isFinite(medianTotal)) return null; @@ -144,13 +151,13 @@ function selectRepresentativeHeadHeapSnapshotRound(samples: MemoryReport['sample return selected?.round ?? null; } -async function saveRepresentativeHeadHeapSnapshot(samples: MemoryReport['samples'], summary: MemoryReport['summary']) { - const round = selectRepresentativeHeadHeapSnapshotRound(samples, summary); +async function saveRepresentativeHeapSnapshot(label: typeof heapSnapshotLabels[number], samples: MemoryReport['samples'], summary: MemoryReport['summary']) { + const round = selectRepresentativeHeapSnapshotRound(samples, summary); if (round == null) return; - await copyFile(headHeapSnapshotPath(round), HEAD_HEAP_SNAPSHOT_OUTPUT_PATH); - process.stderr.write(`Selected head heap snapshot round ${round} for artifact\n`); - await rm(HEAD_HEAP_SNAPSHOT_WORK_DIR, { recursive: true, force: true }); + await copyFile(heapSnapshotPath(label, round), HEAP_SNAPSHOT_OUTPUT_PATHS[label]); + process.stderr.write(`Selected ${label} heap snapshot round ${round} for artifact\n`); + await rm(HEAP_SNAPSHOT_WORK_DIRS[label], { recursive: true, force: true }); } async function main() { @@ -162,8 +169,10 @@ async function main() { const warmupRounds = util.readIntegerEnv('MK_MEMORY_COMPARE_WARMUP_ROUNDS', 1, 0); const startedAt = new Date().toISOString(); - await rm(HEAD_HEAP_SNAPSHOT_WORK_DIR, { recursive: true, force: true }); - await rm(HEAD_HEAP_SNAPSHOT_OUTPUT_PATH, { force: true }); + for (const label of heapSnapshotLabels) { + await rm(HEAP_SNAPSHOT_WORK_DIRS[label], { recursive: true, force: true }); + await rm(HEAP_SNAPSHOT_OUTPUT_PATHS[label], { force: true }); + } const reports = { base: { @@ -178,7 +187,7 @@ async function main() { for (let round = 1; round <= warmupRounds; round++) { process.stderr.write(`Starting warmup round ${round}/${warmupRounds}\n`); - for (const label of ['base', 'head'] as const) { + for (const label of heapSnapshotLabels) { await measureRepo(label, reports[label].dir, -round); } } @@ -188,10 +197,7 @@ async function main() { process.stderr.write(`Starting measurement round ${round}/${rounds}: ${order.join(' -> ')}\n`); for (const label of order) { - const shouldSaveHeadHeapSnapshot = label === 'head'; - const options = shouldSaveHeadHeapSnapshot - ? { heapSnapshotSavePath: headHeapSnapshotPath(round) } - : {}; + const options = { heapSnapshotSavePath: heapSnapshotPath(label, round) }; const sample = await measureRepo(label, reports[label].dir, round, options); reports[label].samples.push({ ...sample, @@ -204,9 +210,11 @@ async function main() { base: summarizeSamples(reports.base.samples), head: summarizeSamples(reports.head.samples), }; - await saveRepresentativeHeadHeapSnapshot(reports.head.samples, summaries.head); + for (const label of heapSnapshotLabels) { + await saveRepresentativeHeapSnapshot(label, reports[label].samples, summaries[label]); + } - for (const label of ['base', 'head'] as const) { + for (const label of heapSnapshotLabels) { const report = { timestamp: new Date().toISOString(), sampleCount: reports[label].samples.length, diff --git a/.github/workflows/get-backend-memory.yml b/.github/workflows/get-backend-memory.yml index 0d0bec33075..03f82789a3b 100644 --- a/.github/workflows/get-backend-memory.yml +++ b/.github/workflows/get-backend-memory.yml @@ -97,11 +97,18 @@ jobs: MK_MEMORY_COMPARE_WARMUP_ROUNDS: 1 MK_MEMORY_HEAP_SNAPSHOT: 1 run: node head/.github/scripts/measure-backend-memory-comparison.mts base head memory-base.json memory-head.json + - name: Upload base heap snapshot + uses: actions/upload-artifact@v7 + with: + path: base-heap-snapshot.heapsnapshot + archive: false + if-no-files-found: error + retention-days: 7 - name: Upload head heap snapshot uses: actions/upload-artifact@v7 with: - name: backend-memory-head-heap-snapshot path: head-heap-snapshot.heapsnapshot + archive: false if-no-files-found: error retention-days: 7 - name: Measure backend loaded JS footprint diff --git a/.github/workflows/report-backend-memory.yml b/.github/workflows/report-backend-memory.yml index 3343ec745e5..a6c0b4afdfa 100644 --- a/.github/workflows/report-backend-memory.yml +++ b/.github/workflows/report-backend-memory.yml @@ -33,8 +33,8 @@ jobs: - name: Load PR Number id: load-pr-num run: echo "pr-number=$(cat artifacts/pr_number)" >> "$GITHUB_OUTPUT" - - name: Find head heap snapshot artifact - id: find-heap-snapshot-artifact + - name: Find heap snapshot artifacts + id: find-heap-snapshot-artifacts uses: actions/github-script@v8 with: script: | @@ -45,14 +45,21 @@ jobs: repo, run_id, }); - const artifact = artifacts.find(artifact => artifact.name === 'backend-memory-head-heap-snapshot'); - if (artifact == null) return; - core.setOutput('url', `https://github.com/${owner}/${repo}/actions/runs/${run_id}/artifacts/${artifact.id}`); + const artifactNames = { + base: 'base-heap-snapshot.heapsnapshot', + head: 'head-heap-snapshot.heapsnapshot', + }; + for (const [label, artifactName] of Object.entries(artifactNames)) { + const artifact = artifacts.find(artifact => artifact.name === artifactName); + if (artifact == null) throw new Error(`Artifact not found: ${artifactName}`); + core.setOutput(`${label}-url`, `https://github.com/${owner}/${repo}/actions/runs/${run_id}/artifacts/${artifact.id}`); + } - id: build-comment name: Build memory comment env: - MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_HEAD: ${{ steps.find-heap-snapshot-artifact.outputs.url }} + MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_BASE: ${{ steps.find-heap-snapshot-artifacts.outputs.base-url }} + MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_HEAD: ${{ steps.find-heap-snapshot-artifacts.outputs.head-url }} run: node .github/scripts/backend-memory-report.mts ./artifacts/memory-base.json ./artifacts/memory-head.json ./output.md ./artifacts/js-footprint-base.json ./artifacts/js-footprint-head.json - uses: thollander/actions-comment-pull-request@v3 with: From ac8e8c48921ad4ae1926ef977c660b72d7953049 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:35:36 +0900 Subject: [PATCH 371/578] chore(dev): tweak get-backend-memory --- .github/workflows/get-backend-memory.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/get-backend-memory.yml b/.github/workflows/get-backend-memory.yml index 03f82789a3b..1f933444bda 100644 --- a/.github/workflows/get-backend-memory.yml +++ b/.github/workflows/get-backend-memory.yml @@ -93,7 +93,7 @@ jobs: run: pnpm build - name: Measure backend memory usage env: - MK_MEMORY_COMPARE_ROUNDS: 5 + MK_MEMORY_COMPARE_ROUNDS: 10 MK_MEMORY_COMPARE_WARMUP_ROUNDS: 1 MK_MEMORY_HEAP_SNAPSHOT: 1 run: node head/.github/scripts/measure-backend-memory-comparison.mts base head memory-base.json memory-head.json From 828a24f6dfc7965d691d9195431fde66a33a6517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Thu, 16 Jul 2026 17:39:28 +0900 Subject: [PATCH 372/578] =?UTF-8?q?enhance:=20=E3=83=97=E3=83=AD=E3=82=BB?= =?UTF-8?q?=E3=82=B9=E8=B5=B7=E5=8B=95=E7=9B=B4=E5=BE=8C=E3=81=AE=E3=83=AD?= =?UTF-8?q?=E3=82=B0=E3=81=8B=E3=82=89=E6=96=B0logger=E9=81=A9=E7=94=A8?= =?UTF-8?q?=EF=BC=8Blogger=E8=A8=AD=E5=AE=9A=E6=A9=9F=E6=A7=8B=E3=81=AE?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=20(#17725)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance: プロセス�ライフサイクル�����logger�期化・終了+logger設定機構�追加 * fix --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- .config/docker_example.yml | 8 ++ .config/example.yml | 8 ++ CHANGELOG.md | 1 + packages/backend/src/boot/entry.ts | 5 +- packages/backend/src/boot/master.ts | 11 +- packages/backend/src/boot/shutdown-handler.ts | 100 +++++++++++++++ packages/backend/src/boot/worker.ts | 21 +++- packages/backend/src/config.ts | 5 + .../src/core/telemetry/telemetry-shutdown.ts | 67 +--------- .../src/logging/BootstrapConsoleBackend.ts | 49 ++++++++ packages/backend/src/logging/LogManager.ts | 116 +++++++++++++++++- .../backend/src/logging/logging-runtime.ts | 15 ++- packages/backend/src/logging/types.ts | 3 + .../test/unit/boot/shutdown-handler.ts | 113 +++++++++++++++++ .../unit/logging/BootstrapConsoleBackend.ts | 54 ++++++++ .../backend/test/unit/logging/LogManager.ts | 90 +++++++++++++- .../backend/test/unit/telemetry-shutdown.ts | 59 --------- 17 files changed, 590 insertions(+), 135 deletions(-) create mode 100644 packages/backend/src/boot/shutdown-handler.ts create mode 100644 packages/backend/src/logging/BootstrapConsoleBackend.ts create mode 100644 packages/backend/test/unit/boot/shutdown-handler.ts create mode 100644 packages/backend/test/unit/logging/BootstrapConsoleBackend.ts delete mode 100644 packages/backend/test/unit/telemetry-shutdown.ts diff --git a/.config/docker_example.yml b/.config/docker_example.yml index 2f4ea329d2c..bc2549d5cf6 100644 --- a/.config/docker_example.yml +++ b/.config/docker_example.yml @@ -241,6 +241,14 @@ proxyBypassHosts: # Log settings # logging: +# # Minimum level for all loggers. Defaults to info in production and debug otherwise. +# level: info +# # The longest matching logger domain takes precedence over the global level. +# domains: +# core.boot: info +# queue: error +# queue.deliver: debug +# db.sql: off # sql: # # Outputs query parameters during SQL execution to the log. # # default: false diff --git a/.config/example.yml b/.config/example.yml index 14808e27955..961417cb30c 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -474,6 +474,14 @@ proxyBypassHosts: # Log settings # logging: +# # Minimum level for all loggers. Defaults to info in production and debug otherwise. +# level: info +# # The longest matching logger domain takes precedence over the global level. +# domains: +# core.boot: info +# queue: error +# queue.deliver: debug +# db.sql: off # sql: # # Outputs query parameters during SQL execution to the log. # # default: false diff --git a/CHANGELOG.md b/CHANGELOG.md index d2cb4e8e40c..1fc991d0a13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ - Enhance: Docker Image � Node.js を 26.4.0 ��Debian を trixie (v13) �更新 - Enhance: URLプレビュー��果を内部�キャッシュ�るよ�� - Enhance: API内部エラー�ログ�構造化属性�正�化��エラー情報を付与���証情報を自動的�秘匿�るよ��(従�形��表示�維�) +- Enhance: ログ全体�既定level�logger domain���出力levelを設定��るよ�� - Fix: `/stats` API �レス�ンス型�正�����題を修正 - Fix: �ッシュタグ�関連�るデータを更新�る際�エラー�ンドリングを修正 - Fix: Sentry 使用環境下���Misskey �発行�� SQL クエリ� span ���れ���題を修正 diff --git a/packages/backend/src/boot/entry.ts b/packages/backend/src/boot/entry.ts index a35bd412721..3c2d56c73c7 100644 --- a/packages/backend/src/boot/entry.ts +++ b/packages/backend/src/boot/entry.ts @@ -13,8 +13,8 @@ import { writeHeapSnapshot } from 'node:v8'; import chalk from 'chalk'; import Xev from 'xev'; import Logger from '@/logger.js'; -import { isTelemetryShutdownInProgress } from '@/core/telemetry/telemetry-shutdown.js'; import { envOption } from '../env.js'; +import { isShutdownInProgress } from './shutdown-handler.js'; import { readyRef } from './ready.js'; import 'reflect-metadata'; @@ -42,7 +42,7 @@ cluster.on('online', worker => { // Listen for dying workers cluster.on('exit', worker => { - if (isTelemetryShutdownInProgress()) { + if (isShutdownInProgress()) { clusterLogger.info(`Process exited during shutdown: [${worker.id}]`); return; } @@ -68,6 +68,7 @@ process.on('uncaughtException', err => { // Dying away... process.on('exit', code => { + if (isShutdownInProgress()) return; logger.info(`The process is going to exit with code ${code}`); }); diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index 59e1351ea10..4f78e602d01 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -11,11 +11,12 @@ import chalkTemplate from 'chalk-template'; import Logger from '@/logger.js'; import { loadConfig } from '@/config.js'; import type { Config } from '@/config.js'; +import { configureLogging, shutdownLogging } from '@/logging/logging-runtime.js'; import { showMachineInfo } from '@/misc/show-machine-info.js'; import { envOption } from '@/env.js'; -import { initTelemetry } from '@/core/telemetry/telemetry-registry.js'; -import { installTelemetrySignalHandlers } from '@/core/telemetry/telemetry-shutdown.js'; +import { initTelemetry, shutdownTelemetry } from '@/core/telemetry/telemetry-registry.js'; import { initExtraThreadPool, jobQueue, server } from './common.js'; +import { installShutdownSignalHandlers } from './shutdown-handler.js'; const logger = new Logger('core', 'cyan'); const bootLogger = logger.createSubLogger('boot', 'magenta'); @@ -74,7 +75,10 @@ export async function masterMain() { bootLogger.error(e instanceof Error ? e : new Error(String(e)), null, true); process.exit(1); } - installTelemetrySignalHandlers(); + installShutdownSignalHandlers({ + shutdownTasks: [shutdownTelemetry, shutdownLogging], + onRegistered: message => bootLogger.info(message), + }); bootLogger.info( `mode: [disableClustering: ${envOption.disableClustering}, onlyServer: ${envOption.onlyServer}, onlyQueue: ${envOption.onlyQueue}]`, @@ -138,6 +142,7 @@ function loadConfigBoot(): Config { try { config = loadConfig(); + configureLogging(config.logging); } catch (exception) { if (typeof exception === 'string') { configLogger.error(exception); diff --git a/packages/backend/src/boot/shutdown-handler.ts b/packages/backend/src/boot/shutdown-handler.ts new file mode 100644 index 00000000000..a0d85d1df69 --- /dev/null +++ b/packages/backend/src/boot/shutdown-handler.ts @@ -0,0 +1,100 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +type ShutdownSignalProcess = { + once(event: 'SIGTERM' | 'SIGINT', listener: () => Promise): unknown; +}; + +const SHUTDOWN_TIMEOUT_MS = 10_000; + +export type ShutdownTask = () => Promise; + +export type ShutdownHandlerOptions = { + /** The process-like object that receives the signal handlers. */ + process?: ShutdownSignalProcess; + /** Shutdown tasks, executed in array order. */ + shutdownTasks: readonly ShutdownTask[]; + /** Process termination function. */ + exit?: (code: number) => void; + /** Optional boot logger hook used after signal handlers are registered. */ + onRegistered?: (message: string) => void; +}; + +let shuttingDown = false; + +/** + * Register the process-level shutdown signals. + * + * Boot owns signal coordination and receives shutdown tasks through callbacks + * so individual domains do not depend on each other. + * + * 注�: ��プロジェクト�� app.enableShutdownHooks() �一切呼�れ������� + * NestJS�OnApplicationShutdown経由�graceful shutdown(GlobalModule.dispose()�よるDB/Redis切断� + * QueueProcessorService.stop()�よるqueue drain�ServerService.dispose()�よるfastify/WebSocket close)� + * SIGTERM/SIGINTを起点��発����。��handler��れらを経由���登録�れ�終了処�を実行���exit�る。 + * 将�enableShutdownHooks()を�線�る場������exit�NestJS��shutdown sequence�競����よ�順�を設計�る��。 + */ +export function installShutdownSignalHandlers(options: ShutdownHandlerOptions): void { + // テスト��process/exitを差�替��本番��実process�SIGTERM/SIGINT handlerを登録�る。 + const processLike = options.process ?? process; + const exit = options.exit ?? ((code: number) => process.exit(code)); + + const handleSignal = async () => { + // �時�複数signal���もflushを二�実行���cluster refork抑止用�状態も���立�る。 + if (shuttingDown) return; + shuttingDown = true; + + let timedOut = false; + let timeout: NodeJS.Timeout | undefined; + try { + // 処�時間上����シャットダウンプロセス + await Promise.race([ + (async () => { + for (const shutdownTask of options.shutdownTasks) { + if (timedOut) return; + try { + await shutdownTask(); + } catch (error) { + // 1��終了処��失敗�後続タスクを妨���よ��stderr�フォール�ック�る。 + try { + console.error('Shutdown task failed:', error); + } catch { + // stderr�出力自体�失敗��も�残り�終了処��exit�継続�る。 + } + } + } + })(), + new Promise(resolve => { + timeout = setTimeout(() => { + timedOut = true; + try { + console.error(`Shutdown tasks timed out after ${SHUTDOWN_TIMEOUT_MS}ms.`); + } catch { + // stderr�出力自体�失敗��もexit�継続�る。 + } + resolve(); + }, SHUTDOWN_TIMEOUT_MS); + }), + ]); + } finally { + if (timeout != null) clearTimeout(timeout); + } + + // 既存挙動�����終了処�後�プロセスを終了�る。 + exit(0); + }; + + // once������signal�handler��入���よ���る。 + processLike.once('SIGTERM', handleSignal); + processLike.once('SIGINT', handleSignal); + + // app.enableShutdownHooks()未�線��状�SIGTERM/SIGINT時��登録済�終了処���を行�。 + options.onRegistered?.('Registered SIGTERM/SIGINT shutdown handler (this process does not perform NestJS graceful shutdown on these signals).'); +} + +export function isShutdownInProgress(): boolean { + // master�cluster exit handler���図��shutdown中�worker終了を�fork�������照�る。 + return shuttingDown; +} diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts index 32bcbe8fb40..ad15296440c 100644 --- a/packages/backend/src/boot/worker.ts +++ b/packages/backend/src/boot/worker.ts @@ -7,9 +7,11 @@ import cluster from 'node:cluster'; import Logger from '@/logger.js'; import { envOption } from '@/env.js'; import { loadConfig } from '@/config.js'; -import { initTelemetry } from '@/core/telemetry/telemetry-registry.js'; -import { installTelemetrySignalHandlers } from '@/core/telemetry/telemetry-shutdown.js'; +import type { Config } from '@/config.js'; +import { configureLogging, shutdownLogging } from '@/logging/logging-runtime.js'; +import { initTelemetry, shutdownTelemetry } from '@/core/telemetry/telemetry-registry.js'; import { initExtraThreadPool, jobQueue, server } from './common.js'; +import { installShutdownSignalHandlers } from './shutdown-handler.js'; const logger = new Logger('core', 'cyan'); const bootLogger = logger.createSubLogger('boot', 'magenta'); @@ -18,7 +20,15 @@ const bootLogger = logger.createSubLogger('boot', 'magenta'); * Init worker process */ export async function workerMain() { - const config = loadConfig(); + let config: Config; + try { + config = loadConfig(); + configureLogging(config.logging); + } catch (e) { + bootLogger.error(e instanceof Error ? e : new Error(String(e)), null, true); + process.exit(1); + return; + } initExtraThreadPool(config); @@ -28,7 +38,10 @@ export async function workerMain() { bootLogger.error(e instanceof Error ? e : new Error(String(e)), null, true); process.exit(1); } - installTelemetrySignalHandlers(); + installShutdownSignalHandlers({ + shutdownTasks: [shutdownTelemetry, shutdownLogging], + onRegistered: message => bootLogger.info(message), + }); if (envOption.onlyServer) { await server(); diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index de67daa31bf..ab46416b356 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -10,6 +10,7 @@ import { type FastifyServerOptions } from 'fastify'; import type * as Sentry from '@sentry/node'; import type * as SentryVue from '@sentry/vue'; import type { RedisOptions } from 'ioredis'; +import type { LogLevelSetting } from './logging/types.js'; type RedisOptionsSource = Partial & { host: string; @@ -132,6 +133,8 @@ type Source = { pidFile: string; logging?: { + level?: LogLevelSetting; + domains?: Record | null; sql?: { disableQueryTruncation?: boolean, enableQueryParamLogging?: boolean, @@ -194,6 +197,8 @@ export type Config = { deliverJobMaxAttempts: number | undefined; inboxJobMaxAttempts: number | undefined; logging?: { + level?: LogLevelSetting; + domains?: Record | null; sql?: { disableQueryTruncation?: boolean, enableQueryParamLogging?: boolean, diff --git a/packages/backend/src/core/telemetry/telemetry-shutdown.ts b/packages/backend/src/core/telemetry/telemetry-shutdown.ts index 07d950f70d6..1ee1b42649b 100644 --- a/packages/backend/src/core/telemetry/telemetry-shutdown.ts +++ b/packages/backend/src/core/telemetry/telemetry-shutdown.ts @@ -3,64 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import Logger from '@/logger.js'; -import { shutdownTelemetry as defaultShutdownTelemetry } from './telemetry-registry.js'; - -const logger = new Logger('telemetry', 'green'); - -type SignalProcess = { - once(event: 'SIGTERM' | 'SIGINT', listener: () => Promise): unknown; -}; - -type InstallTelemetrySignalHandlersOptions = { - process?: SignalProcess; - shutdownTelemetry?: () => Promise; - exit?: (code: number) => void; -}; - -let shuttingDown = false; - -export function installTelemetrySignalHandlers(options: InstallTelemetrySignalHandlersOptions = {}): void { - // テスト��process/exitを差�替��本番��実process�SIGTERM/SIGINT handlerを登録�る。 - // - // 注�: ��プロジェクト�� app.enableShutdownHooks() �一切呼�れ������� - // NestJS�OnApplicationShutdown経由�graceful shutdown(GlobalModule.dispose()�よるDB/Redis切断� - // QueueProcessorService.stop()�よるqueue drain�ServerService.dispose()�よるfastify/WebSocket close)� - // 本PR以��ら実質的�無効(SIGTERM/SIGINTを起点�発��る���無�)���。 - // ��handler�リ�ジトリ����有効��る本番SIGTERM/SIGINT handler��り�telemetry�flush��を行� - // 上記�graceful shutdown処�を経由����exit�る。将�enableShutdownHooks()を�線�る場��� - // ���exit�NestJS��shutdown sequence�競����よ�順�を設計�る��。 - const processLike = options.process ?? process; - const shutdownTelemetry = options.shutdownTelemetry ?? defaultShutdownTelemetry; - const exit = options.exit ?? ((code: number) => process.exit(code)); - - const handleSignal = async () => { - // �時�複数signal���もflushを二�実行���cluster refork抑止用�状態も���立�る。 - if (shuttingDown) return; - shuttingDown = true; - - try { - // 終了直��BatchSpanProcessor/Sentry�bufferをflush�る。 - // (DB/Redis/queue/HTTPサー�ー�graceful close�����行���。上記�注�を�照。) - await shutdownTelemetry(); - } catch { - // telemetry flush�失敗�プロセス終了�止�ら��よ�������り潰�。 - } finally { - // 既存挙動�����telemetry flush後�プロセスを終了�る。 - exit(0); - } - }; - - // once������signal�handler��入���よ���る。 - processLike.once('SIGTERM', handleSignal); - processLike.once('SIGINT', handleSignal); - - // app.enableShutdownHooks()未�線��状�SIGTERM/SIGINT時�処��telemetry flush����る��を - // 起動時�明示��DB/Redis/queue/HTTPサー�ー�graceful close�行�れ��点を�用者�把���るよ���る。 - logger.info('Registered SIGTERM/SIGINT handler for telemetry flush (this process does not perform NestJS graceful shutdown on these signals).'); -} - -export function isTelemetryShutdownInProgress(): boolean { - // master�cluster exit handler���図��shutdown中�worker終了を�fork�������照�る。 - return shuttingDown; -} +/** + * Telemetry-specific shutdown is implemented by telemetry-registry.ts. + * Signal coordination belongs to boot/shutdown-handler.ts so telemetry and + * logging remain independent domains. + */ +export { shutdownTelemetry } from './telemetry-registry.js'; diff --git a/packages/backend/src/logging/BootstrapConsoleBackend.ts b/packages/backend/src/logging/BootstrapConsoleBackend.ts new file mode 100644 index 00000000000..b6b033c8b6c --- /dev/null +++ b/packages/backend/src/logging/BootstrapConsoleBackend.ts @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { LogBackend } from './LogBackend.js'; +import type { LogRecord } from './types.js'; + +/** 設定読込��最�出力処��外部�ら���る�存関係��。 */ +export type BootstrapConsoleBackendDependencies = { + readonly output: (...args: unknown[]) => void; +}; + +const defaultDependencies: BootstrapConsoleBackendDependencies = { + output: (...args) => console.log(...args), +}; + +/** + * 設定読込��も利用��る��存�少��コンソール出力��。 + * 設定ファイル�読�込�失敗を報告�る���Pretty backendやTelemetry���存���ん。 + */ +export class BootstrapConsoleBackend implements LogBackend { + private readonly dependencies: BootstrapConsoleBackendDependencies; + + constructor(dependencies: Partial = {}) { + this.dependencies = { + ...defaultDependencies, + ...dependencies, + }; + } + + public write(record: LogRecord): void { + const worker = record.isPrimary ? '*' : record.workerId ?? '?'; + const line = `${record.timestamp} ${record.level.toUpperCase()} ${worker}\t[${record.loggerName}]\t${record.message}`; + const args: unknown[] = [line]; + + if (record.compatibility?.data != null) { + args.push(record.compatibility.data); + } else if (record.eventName != null || record.attributes != null || record.error != null) { + args.push({ + ...(record.eventName != null ? { eventName: record.eventName } : {}), + ...(record.attributes != null ? { attributes: record.attributes } : {}), + ...(record.error != null ? { error: record.error } : {}), + }); + } + + this.dependencies.output(...args); + } +} diff --git a/packages/backend/src/logging/LogManager.ts b/packages/backend/src/logging/LogManager.ts index 6fef23d35f9..565bc5e0b4c 100644 --- a/packages/backend/src/logging/LogManager.ts +++ b/packages/backend/src/logging/LogManager.ts @@ -13,7 +13,7 @@ import { type LogNormalizationProfile, } from './LogNormalizer.js'; import type { LogBackend } from './LogBackend.js'; -import type { LogRecord, LogRecordInput } from './types.js'; +import type { LogLevel, LogLevelSetting, LogRecord, LogRecordInput } from './types.js'; /** ログを出力��プロセスを識別�る���情報��。 */ export type LogProcessInfo = { @@ -39,6 +39,60 @@ export type LogManagerOptions = { readonly normalizationProfile?: LogNormalizationProfile; }; +/** 起動時��用�るログ出力設定��。 */ +export type LogManagerConfiguration = { + readonly level?: LogLevelSetting; + readonly domains?: Readonly> | null; +}; + +const logLevelOrder: Readonly> = { + debug: 0, + info: 1, + warn: 2, + error: 3, + fatal: 4, +}; + +const validLogLevels = new Set(['debug', 'info', 'warn', 'error', 'fatal', 'off']); + +function validateLogLevel(value: unknown, path: string): LogLevelSetting | undefined { + if (typeof value === 'undefined') return undefined; + if (typeof value !== 'string' || !validLogLevels.has(value as LogLevelSetting)) { + throw new Error(`${path} must be one of debug, info, warn, error, fatal, or off`); + } + return value as LogLevelSetting; +} + +function validateDomainName(domain: string): void { + if (domain.length === 0 || domain.trim() !== domain || domain.split('.').some(segment => segment.length === 0)) { + throw new Error(`logging.domains contains an invalid domain name: ${JSON.stringify(domain)}`); + } +} + +function resolveConfiguration(configuration: LogManagerConfiguration | undefined): { + readonly level: LogLevelSetting | undefined; + readonly domains: readonly (readonly [string, LogLevelSetting])[]; +} { + if (configuration == null) return { level: undefined, domains: [] }; + + const level = validateLogLevel(configuration.level, 'logging.level'); + if (configuration.domains == null) return { level, domains: [] }; + if (typeof configuration.domains !== 'object' || configuration.domains === null || Array.isArray(configuration.domains)) { + throw new Error('logging.domains must be an object'); + } + + const domains = Object.entries(configuration.domains).map(([domain, value]) => { + validateDomainName(domain); + const level = validateLogLevel(value, `logging.domains.${domain}`); + if (typeof level === 'undefined') { + throw new Error(`logging.domains.${domain} must be configured`); + } + return [domain, level] as const; + }).sort((left, right) => right[0].length - left[0].length); + + return { level, domains }; +} + const defaultDependencies: LogManagerDependencies = { now: () => new Date(), getProcessInfo: () => ({ @@ -59,6 +113,9 @@ export class LogManager { private backend: LogBackend; private readonly dependencies: LogManagerDependencies; private normalizationProfile: LogNormalizationProfile; + private configuredLevel: LogLevelSetting | undefined; + private configuredDomains: readonly (readonly [string, LogLevelSetting])[]; + private shutdownPromise: Promise | undefined; /** * 出力先�実行環境�ら値を�得�る処�を���り��。 @@ -75,6 +132,8 @@ export class LogManager { ...dependencies, }; this.normalizationProfile = options.normalizationProfile ?? 'standard'; + this.configuredLevel = undefined; + this.configuredDomains = []; } /** @@ -85,11 +144,60 @@ export class LogManager { this.backend = backend; } + /** 起動時�既定level�domain別levelを�用���。 */ + public configure(configuration?: LogManagerConfiguration): void { + const resolved = resolveConfiguration(configuration); + this.configuredLevel = resolved.level; + this.configuredDomains = resolved.domains; + } + /** 正�化方�を切り替��既�作�済��Logger�も�映���。 */ public setNormalizationProfile(profile: LogNormalizationProfile): void { this.normalizationProfile = profile; } + /** backend�残���るログをflush���ら終了処�を行���。 */ + public shutdown(): Promise { + if (this.shutdownPromise != null) return this.shutdownPromise; + + this.shutdownPromise = (async () => { + try { + await this.backend.flush?.(); + } finally { + await this.backend.close?.(); + } + })(); + + return this.shutdownPromise; + } + + private getDefaultLevel(): LogLevel { + if (this.dependencies.isVerbose()) return 'debug'; + return this.dependencies.getNodeEnv() === 'production' ? 'info' : 'debug'; + } + + private getThreshold(loggerName: string): LogLevelSetting { + let threshold: LogLevelSetting | undefined; + for (const [domain, level] of this.configuredDomains) { + if (loggerName === domain || loggerName.startsWith(`${domain}.`)) { + threshold = level; + break; + } + } + + threshold ??= this.configuredLevel ?? this.getDefaultLevel(); + + // verbose�障害調査用�緊急モード����明示�れ�off以外をdebug��下�る。 + // off��図的�無効化����verbose�も�有効化���。 + return threshold === 'off' || !this.dependencies.isVerbose() ? threshold : 'debug'; + } + + private shouldWrite(input: LogRecordInput, loggerName: string): boolean { + const threshold = this.getThreshold(loggerName); + if (threshold === 'off') return false; + return logLevelOrder[input.level] >= logLevelOrder[threshold]; + } + /** * 出力�件を確���共通情報を付加��出力先�渡���。 */ @@ -97,8 +205,8 @@ export class LogManager { // `quiet`�他��件より優先��ログ�付��る情報��得も行���ん。 if (this.dependencies.isQuiet()) return; - // 本番環境�デ�ッグログ��明示的�`verbose`�指定�れ�場���出力���。 - if (input.level === 'debug' && this.dependencies.getNodeEnv() === 'production' && !this.dependencies.isVerbose()) return; + const loggerName = input.context.map(segment => segment.name).join('.'); + if (!this.shouldWrite(input, loggerName)) return; const processInfo = this.dependencies.getProcessInfo(); // 呼�出����列を共有���親�ら末端���順�を固定���。 @@ -116,7 +224,7 @@ export class LogManager { ...inputWithoutStructuredValues, context, timestamp: this.dependencies.now().toISOString(), - loggerName: context.map(segment => segment.name).join('.'), + loggerName, processId: processInfo.processId, isPrimary: processInfo.isPrimary, workerId: processInfo.workerId, diff --git a/packages/backend/src/logging/logging-runtime.ts b/packages/backend/src/logging/logging-runtime.ts index 79890ad4962..e4f97f56e65 100644 --- a/packages/backend/src/logging/logging-runtime.ts +++ b/packages/backend/src/logging/logging-runtime.ts @@ -4,10 +4,23 @@ */ import { LogManager } from './LogManager.js'; +import { BootstrapConsoleBackend } from './BootstrapConsoleBackend.js'; import { PrettyConsoleBackend } from './PrettyConsoleBackend.js'; +import type { LogManagerConfiguration } from './LogManager.js'; /** * プロセス内�����Logger�共有�るLogManager��。 * Logger作�後も��LogManagerを�照�る���出力先�切り替�を一括��映����。 */ -export const logManager = new LogManager(new PrettyConsoleBackend()); +export const logManager = new LogManager(new BootstrapConsoleBackend()); + +/** 設定読込後�logging設定�Pretty backendを�用���。 */ +export function configureLogging(configuration?: LogManagerConfiguration): void { + logManager.configure(configuration); + logManager.setBackend(new PrettyConsoleBackend()); +} + +/** プロセス終了���在�logging backendをflush��閉���。 */ +export function shutdownLogging(): Promise { + return logManager.shutdown(); +} diff --git a/packages/backend/src/logging/types.ts b/packages/backend/src/logging/types.ts index aa3b63edecd..1993cd18095 100644 --- a/packages/backend/src/logging/types.ts +++ b/packages/backend/src/logging/types.ts @@ -8,6 +8,9 @@ import type { Keyword } from 'color-convert'; /** ログ���度を表���。 */ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; +/** 設定�指定��るログ�閾値��。`off`�ログイベント�level��使用���ん。 */ +export type LogLevelSetting = LogLevel | 'off'; + /** 正�化後�ログ属性���扱�るJSON�値��。 */ export type LogAttributeValue = | string diff --git a/packages/backend/test/unit/boot/shutdown-handler.ts b/packages/backend/test/unit/boot/shutdown-handler.ts new file mode 100644 index 00000000000..399820f08c9 --- /dev/null +++ b/packages/backend/test/unit/boot/shutdown-handler.ts @@ -0,0 +1,113 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test, vi } from 'vitest'; + +describe('shutdown-handler', () => { + test('runs shutdown tasks once and exits on SIGTERM or SIGINT', async () => { + vi.resetModules(); + const { installShutdownSignalHandlers, isShutdownInProgress } = await import('@/boot/shutdown-handler.js'); + const handlers = new Map Promise>(); + const processLike = { + once: vi.fn((event: string, handler: () => Promise) => { + handlers.set(event, handler); + return processLike; + }), + }; + const calls: string[] = []; + const shutdownTelemetry = vi.fn(async () => { + calls.push('telemetry'); + }); + const shutdownLogging = vi.fn(async () => { + calls.push('logging'); + }); + const exit = vi.fn(); + const onRegistered = vi.fn(); + + installShutdownSignalHandlers({ process: processLike, shutdownTasks: [shutdownTelemetry, shutdownLogging], exit, onRegistered }); + + expect(processLike.once).toHaveBeenCalledWith('SIGTERM', expect.any(Function)); + expect(processLike.once).toHaveBeenCalledWith('SIGINT', expect.any(Function)); + expect(onRegistered).toHaveBeenCalledOnce(); + expect(isShutdownInProgress()).toBe(false); + + await handlers.get('SIGTERM')!(); + await handlers.get('SIGINT')!(); + + expect(isShutdownInProgress()).toBe(true); + expect(calls).toEqual(['telemetry', 'logging']); + expect(shutdownTelemetry).toHaveBeenCalledTimes(1); + expect(shutdownLogging).toHaveBeenCalledTimes(1); + expect(exit).toHaveBeenCalledTimes(1); + expect(exit).toHaveBeenCalledWith(0); + }); + + test('continues with later shutdown tasks when an earlier task rejects', async () => { + vi.resetModules(); + const { installShutdownSignalHandlers } = await import('@/boot/shutdown-handler.js'); + const handlers = new Map Promise>(); + const processLike = { + once: vi.fn((event: string, handler: () => Promise) => { + handlers.set(event, handler); + return processLike; + }), + }; + const exit = vi.fn(); + const shutdownLogging = vi.fn().mockResolvedValue(undefined); + const shutdownError = new Error('flush failed'); + const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}); + + try { + installShutdownSignalHandlers({ + process: processLike, + shutdownTasks: [vi.fn().mockRejectedValue(shutdownError), shutdownLogging], + exit, + }); + + await handlers.get('SIGINT')!(); + + expect(exit).toHaveBeenCalledWith(0); + expect(shutdownLogging).toHaveBeenCalledOnce(); + expect(consoleError).toHaveBeenCalledWith('Shutdown task failed:', shutdownError); + } finally { + consoleError.mockRestore(); + } + }); + + test('exits after the shutdown deadline when a task remains pending', async () => { + vi.resetModules(); + vi.useFakeTimers(); + const { installShutdownSignalHandlers } = await import('@/boot/shutdown-handler.js'); + const handlers = new Map Promise>(); + const processLike = { + once: vi.fn((event: string, handler: () => Promise) => { + handlers.set(event, handler); + return processLike; + }), + }; + const exit = vi.fn(); + const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}); + + try { + installShutdownSignalHandlers({ + process: processLike, + shutdownTasks: [() => new Promise(() => {})], + exit, + }); + + const signalPromise = handlers.get('SIGTERM')!(); + expect(exit).not.toHaveBeenCalled(); + + await vi.advanceTimersByTimeAsync(10_000); + await signalPromise; + + expect(consoleError).toHaveBeenCalledWith('Shutdown tasks timed out after 10000ms.'); + expect(exit).toHaveBeenCalledWith(0); + } finally { + consoleError.mockRestore(); + vi.useRealTimers(); + } + }); +}); diff --git a/packages/backend/test/unit/logging/BootstrapConsoleBackend.ts b/packages/backend/test/unit/logging/BootstrapConsoleBackend.ts new file mode 100644 index 00000000000..43545a0693e --- /dev/null +++ b/packages/backend/test/unit/logging/BootstrapConsoleBackend.ts @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test, vi } from 'vitest'; +import type { LogRecord } from '@/logging/types.js'; +import { BootstrapConsoleBackend } from '@/logging/BootstrapConsoleBackend.js'; + +function createRecord(overrides: Partial = {}): LogRecord { + return { + level: 'error', + message: 'configuration failed', + context: [{ name: 'core' }, { name: 'boot' }], + timestamp: '2025-01-02T03:04:05.678Z', + loggerName: 'core.boot', + processId: 1234, + isPrimary: true, + workerId: null, + ...overrides, + }; +} + +describe('BootstrapConsoleBackend', () => { + test('writes a minimal line with legacy data', () => { + const output = vi.fn(); + const backend = new BootstrapConsoleBackend({ output }); + const data = { detail: 'failed' }; + + backend.write(createRecord({ compatibility: { data } })); + + expect(output).toHaveBeenCalledWith('2025-01-02T03:04:05.678Z ERROR *\t[core.boot]\tconfiguration failed', data); + }); + + test('writes structured details without depending on Pretty formatting', () => { + const output = vi.fn(); + const backend = new BootstrapConsoleBackend({ output }); + + backend.write(createRecord({ + eventName: 'config.load.failed', + attributes: { path: '.config/default.yml' }, + error: { type: 'Error', message: 'not found' }, + })); + + expect(output).toHaveBeenCalledWith( + '2025-01-02T03:04:05.678Z ERROR *\t[core.boot]\tconfiguration failed', + { + eventName: 'config.load.failed', + attributes: { path: '.config/default.yml' }, + error: { type: 'Error', message: 'not found' }, + }, + ); + }); +}); diff --git a/packages/backend/test/unit/logging/LogManager.ts b/packages/backend/test/unit/logging/LogManager.ts index 93290590336..eac853afdbb 100644 --- a/packages/backend/test/unit/logging/LogManager.ts +++ b/packages/backend/test/unit/logging/LogManager.ts @@ -4,9 +4,9 @@ */ import { describe, expect, test, vi } from 'vitest'; -import { LogManager } from '@/logging/LogManager.js'; import type { LogBackend } from '@/logging/LogBackend.js'; import type { LogRecordInput } from '@/logging/types.js'; +import { LogManager } from '@/logging/LogManager.js'; /** テスト�使�最�構��ログ入力を作����。 */ function createInput(level: LogRecordInput['level'] = 'info'): LogRecordInput { @@ -28,6 +28,10 @@ function createManager(options: { isPrimary?: boolean; workerId?: number | null; normalizationProfile?: 'standard' | 'detailed'; + configuration?: { + level?: 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'off'; + domains?: Record; + }; } = {}) { const write = vi.fn(); const manager = new LogManager({ write }, { @@ -43,6 +47,7 @@ function createManager(options: { }, { normalizationProfile: options.normalizationProfile, }); + if (options.configuration) manager.configure(options.configuration); return { manager, write }; } @@ -115,6 +120,76 @@ describe('LogManager', () => { expect(write).toHaveBeenCalledOnce(); }); + test('applies the configured global level', () => { + const { manager, write } = createManager({ configuration: { level: 'warn' } }); + + manager.write(createInput('info')); + manager.write(createInput('warn')); + + expect(write).toHaveBeenCalledOnce(); + expect(write.mock.calls[0][0].level).toBe('warn'); + }); + + test('uses the longest matching domain and supports child re-enablement', () => { + const { manager, write } = createManager({ + configuration: { + level: 'info', + domains: { + queue: 'off', + 'queue.deliver': 'debug', + }, + }, + }); + + manager.write({ ...createInput('info'), context: [{ name: 'queue' }, { name: 'inbox' }] }); + manager.write({ ...createInput('debug'), context: [{ name: 'queue' }, { name: 'deliver' }] }); + manager.write({ ...createInput('debug'), context: [{ name: 'queueing' }] }); + + expect(write).toHaveBeenCalledOnce(); + expect(write.mock.calls[0][0].loggerName).toBe('queue.deliver'); + }); + + test('lowers configured levels to debug in verbose mode', () => { + const { manager, write } = createManager({ + nodeEnv: 'production', + verbose: true, + configuration: { level: 'info' }, + }); + + manager.write(createInput('debug')); + + expect(write).toHaveBeenCalledOnce(); + }); + + test('keeps explicit off levels disabled in verbose mode', () => { + const { manager, write } = createManager({ + verbose: true, + configuration: { + level: 'off', + domains: { + queue: 'off', + 'queue.deliver': 'warn', + }, + }, + }); + + manager.write({ ...createInput('fatal'), context: [{ name: 'system' }] }); + manager.write({ ...createInput('debug'), context: [{ name: 'queue' }] }); + manager.write({ ...createInput('debug'), context: [{ name: 'queue' }, { name: 'deliver' }] }); + + expect(write).toHaveBeenCalledOnce(); + expect(write.mock.calls[0][0].loggerName).toBe('queue.deliver'); + }); + + test('rejects invalid logging configuration', () => { + const { manager } = createManager(); + + expect(() => manager.configure({ domains: null })).not.toThrow(); + expect(() => manager.configure({ level: 'notice' as never })).toThrow('logging.level'); + expect(() => manager.configure({ domains: { queue: 'notice' as never } })).toThrow('logging.domains.queue'); + expect(() => manager.configure({ domains: { 'queue.': 'info' } })).toThrow('invalid domain name'); + }); + test('uses a replaced backend for subsequent records', () => { const { manager, write } = createManager(); const replacementWrite = vi.fn(); @@ -126,6 +201,19 @@ describe('LogManager', () => { expect(replacementWrite).toHaveBeenCalledOnce(); }); + test('flushes and closes the backend once during shutdown', async () => { + const write = vi.fn(); + const flush = vi.fn>().mockResolvedValue(undefined); + const close = vi.fn>().mockResolvedValue(undefined); + const manager = new LogManager({ write, flush, close }); + + await Promise.all([manager.shutdown(), manager.shutdown()]); + + expect(flush).toHaveBeenCalledOnce(); + expect(close).toHaveBeenCalledOnce(); + expect(flush.mock.invocationCallOrder[0]).toBeLessThan(close.mock.invocationCallOrder[0]); + }); + test('normalizes structured attributes and errors before writing', () => { const { manager, write } = createManager(); const error = new TypeError('broken'); diff --git a/packages/backend/test/unit/telemetry-shutdown.ts b/packages/backend/test/unit/telemetry-shutdown.ts deleted file mode 100644 index 11c47c4181b..00000000000 --- a/packages/backend/test/unit/telemetry-shutdown.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { describe, expect, test, vi } from 'vitest'; - -describe('telemetry-shutdown', () => { - test('flushes telemetry once and exits on SIGTERM or SIGINT', async () => { - vi.resetModules(); - const { installTelemetrySignalHandlers, isTelemetryShutdownInProgress } = await import('@/core/telemetry/telemetry-shutdown.js'); - const handlers = new Map Promise>(); - const processLike = { - once: vi.fn((event: string, handler: () => Promise) => { - handlers.set(event, handler); - return processLike; - }), - }; - const shutdownTelemetry = vi.fn().mockResolvedValue(undefined); - const exit = vi.fn(); - - installTelemetrySignalHandlers({ process: processLike, shutdownTelemetry, exit }); - - expect(processLike.once).toHaveBeenCalledWith('SIGTERM', expect.any(Function)); - expect(processLike.once).toHaveBeenCalledWith('SIGINT', expect.any(Function)); - expect(isTelemetryShutdownInProgress()).toBe(false); - - await handlers.get('SIGTERM')!(); - await handlers.get('SIGINT')!(); - - expect(isTelemetryShutdownInProgress()).toBe(true); - expect(shutdownTelemetry).toHaveBeenCalledTimes(1); - expect(exit).toHaveBeenCalledTimes(1); - expect(exit).toHaveBeenCalledWith(0); - }); - - test('exits even when telemetry shutdown rejects', async () => { - vi.resetModules(); - const { installTelemetrySignalHandlers } = await import('@/core/telemetry/telemetry-shutdown.js'); - const handlers = new Map Promise>(); - const processLike = { - once: vi.fn((event: string, handler: () => Promise) => { - handlers.set(event, handler); - return processLike; - }), - }; - const exit = vi.fn(); - - installTelemetrySignalHandlers({ - process: processLike, - shutdownTelemetry: vi.fn().mockRejectedValue(new Error('flush failed')), - exit, - }); - - await handlers.get('SIGINT')!(); - - expect(exit).toHaveBeenCalledWith(0); - }); -}); From 875554003e7c4b039ce6ed1a58186e4a1089bb6e Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 19:34:48 +0900 Subject: [PATCH 373/578] feat(dev): report frontend browser diagnostics --- .github/scripts/chrome.mts | 69 +++++++++++++ .github/scripts/frontend-browser-report.mts | 14 ++- .../scripts/frontend-browser-report.test.mts | 98 +++++++++++++++++++ .../measure-frontend-browser-comparison.mts | 4 +- .github/workflows/lint.yml | 1 + 5 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 .github/scripts/frontend-browser-report.test.mts diff --git a/.github/scripts/chrome.mts b/.github/scripts/chrome.mts index 5d07ac6efec..2be10bd261b 100644 --- a/.github/scripts/chrome.mts +++ b/.github/scripts/chrome.mts @@ -7,6 +7,7 @@ import { createRequire } from 'node:module'; import { writeFile } from 'node:fs/promises'; import type { Browser, BrowserContext, CDPSession, Page } from 'playwright'; import type { HeapSnapshotData } from './heap-snapshot-util.mts'; +import * as util from './utility.mts'; export type NetworkRequest = { requestId: string; @@ -89,11 +90,65 @@ export type TabMemory = { totalBytes: number; }; +export type BrowserConsoleMetrics = { + log: number; + warn: number; + error: number; + info: number; +}; + +export type BrowserDiagnostics = { + pageErrorCount: number; + console: BrowserConsoleMetrics; +}; + +export function createBrowserDiagnostics(): BrowserDiagnostics { + return { + pageErrorCount: 0, + console: { + log: 0, + warn: 0, + error: 0, + info: 0, + }, + }; +} + +export function recordPageError(diagnostics: BrowserDiagnostics) { + diagnostics.pageErrorCount += 1; +} + +function isBrowserConsoleMetricKey(value: string): value is keyof BrowserConsoleMetrics { + return value === 'log' || value === 'warn' || value === 'error' || value === 'info'; +} + +export function recordConsoleMessageType(diagnostics: BrowserDiagnostics, messageType: string) { + const metricKey = messageType === 'warning' ? 'warn' : messageType; + if (!isBrowserConsoleMetricKey(metricKey)) return; + diagnostics.console[metricKey] += 1; +} + +export function summarizeBrowserDiagnostics(samples: BrowserDiagnostics[]): BrowserDiagnostics { + if (samples.length === 0) throw new Error('No browser diagnostic samples'); + const median = (select: (sample: BrowserDiagnostics) => number) => util.median(samples.map(select)); + + return { + pageErrorCount: median(sample => sample.pageErrorCount), + console: { + log: median(sample => sample.console.log), + warn: median(sample => sample.console.warn), + error: median(sample => sample.console.error), + info: median(sample => sample.console.info), + }, + }; +} + export type BrowserMeasurement = { label: string; timestamp: string; url: string; scenario: string; + diagnostics: BrowserDiagnostics; durationMs: number; network: NetworkSummary; performance: { @@ -149,6 +204,7 @@ type PlaywrightBrowserOptions = { export class HeadlessChromeController { public networkRequests: NetworkRequest[] = []; public webSocketConnections: WebSocketConnection[] = []; + private readonly diagnostics = createBrowserDiagnostics(); private readonly browser: Browser; private readonly context: BrowserContext; public readonly page: Page; @@ -168,6 +224,12 @@ export class HeadlessChromeController { this.cdp = cdp; this.page.setDefaultTimeout(options.scenarioTimeoutMs); this.page.setDefaultNavigationTimeout(options.scenarioTimeoutMs); + this.page.on('pageerror', () => { + recordPageError(this.diagnostics); + }); + this.page.on('console', message => { + recordConsoleMessageType(this.diagnostics, message.type()); + }); } static async create(label: string, options: PlaywrightBrowserOptions): Promise { @@ -376,6 +438,13 @@ export class HeadlessChromeController { ]) as T; } + public collectDiagnostics(): BrowserDiagnostics { + return { + pageErrorCount: this.diagnostics.pageErrorCount, + console: { ...this.diagnostics.console }, + }; + } + public async collectPerformance(): Promise { const cdpMetricsResult = await this.cdp.send<{ metrics: { name: string; value: number }[] }>('Performance.getMetrics'); const cdpMetrics = Object.fromEntries(cdpMetricsResult.metrics.map(metric => [metric.name, metric.value])); diff --git a/.github/scripts/frontend-browser-report.mts b/.github/scripts/frontend-browser-report.mts index 755b29bc884..829041f1d0a 100644 --- a/.github/scripts/frontend-browser-report.mts +++ b/.github/scripts/frontend-browser-report.mts @@ -8,13 +8,14 @@ import { pathToFileURL } from 'node:url'; import * as util from './utility.mts'; import * as heapSnapshotUtil from './heap-snapshot-util.mts'; import type { HeapSnapshotData, HeapSnapshotReport } from './heap-snapshot-util.mts'; -import type { NetworkRequest } from './chrome.mts'; +import type { BrowserDiagnostics, NetworkRequest } from './chrome.mts'; export type BrowserMeasurement = { label: string; timestamp: string; url: string; scenario: string; + diagnostics: BrowserDiagnostics; durationMs: number; network: { requestCount: number; @@ -171,8 +172,19 @@ function getMetric(report: BrowserMeasurement, key: string) { return report.performance.cdpMetrics[key]; } +export function renderBrowserDiagnosticsRows(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { + return [ + metricRow('Page errors', base, head, summary => summary.diagnostics.pageErrorCount, sample => sample.diagnostics.pageErrorCount, util.formatNumber, 1, !all), + metricRow('Console log', base, head, summary => summary.diagnostics.console.log, sample => sample.diagnostics.console.log, util.formatNumber, 1, !all), + metricRow('Console warnings', base, head, summary => summary.diagnostics.console.warn, sample => sample.diagnostics.console.warn, util.formatNumber, 1, !all), + metricRow('Console errors', base, head, summary => summary.diagnostics.console.error, sample => sample.diagnostics.console.error, util.formatNumber, 1, !all), + metricRow('Console info', base, head, summary => summary.diagnostics.console.info, sample => sample.diagnostics.console.info, util.formatNumber, 1, !all), + ].filter(row => row != null); +} + function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { const rows = [ + ...renderBrowserDiagnosticsRows(base, head, all), //metricRow('Scenario duration', base, head, summary => summary.durationMs, sample => sample.durationMs, formatMs), metricRow('Requests', base, head, summary => summary.network.requestCount, sample => sample.network.requestCount, util.formatNumber, 1, !all), //metricRow('Failed requests', base, head, summary => summary.network.failedRequestCount, sample => sample.network.failedRequestCount, util.formatNumber), diff --git a/.github/scripts/frontend-browser-report.test.mts b/.github/scripts/frontend-browser-report.test.mts new file mode 100644 index 00000000000..4d4f1305043 --- /dev/null +++ b/.github/scripts/frontend-browser-report.test.mts @@ -0,0 +1,98 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { + createBrowserDiagnostics, + recordConsoleMessageType, + recordPageError, + summarizeBrowserDiagnostics, + type BrowserDiagnostics, +} from './chrome.mts'; +import { + renderBrowserDiagnosticsRows, + type BrowserMeasurement, + type BrowserMeasurementSample, + type BrowserMetricsReport, +} from './frontend-browser-report.mts'; + +function diagnostics(pageErrorCount: number, log: number, warn: number, error: number, info: number): BrowserDiagnostics { + return { + pageErrorCount, + console: { log, warn, error, info }, + }; +} + +function browserReport(label: 'base' | 'head', values: BrowserDiagnostics[]): BrowserMetricsReport { + const samples = values.map((value, index) => ({ + round: index + 1, + diagnostics: value, + } as BrowserMeasurementSample)); + + return { + label, + timestamp: '2026-07-16T00:00:00.000Z', + url: 'http://127.0.0.1:61812', + scenario: 'test', + sampleCount: samples.length, + aggregation: 'median', + summary: { + diagnostics: summarizeBrowserDiagnostics(values), + } as BrowserMeasurement, + samples, + }; +} + +test('records page errors and only the requested console message types', () => { + const result = createBrowserDiagnostics(); + recordPageError(result); + recordPageError(result); + for (const type of ['log', 'warning', 'error', 'info', 'debug', 'trace']) { + recordConsoleMessageType(result, type); + } + + assert.deepEqual(result, diagnostics(2, 1, 1, 1, 1)); +}); + +test('summarizes browser diagnostics with a median for every counter', () => { + const result = summarizeBrowserDiagnostics([ + diagnostics(0, 10, 20, 30, 40), + diagnostics(4, 14, 24, 34, 44), + diagnostics(2, 12, 22, 32, 42), + diagnostics(3, 13, 23, 33, 43), + diagnostics(1, 11, 21, 31, 41), + ]); + + assert.deepEqual(result, diagnostics(2, 12, 22, 32, 42)); +}); + +test('renders each changed browser diagnostics metric as a separate row', () => { + const base = browserReport('base', Array.from({ length: 5 }, () => diagnostics(0, 0, 0, 0, 0))); + const head = browserReport('head', Array.from({ length: 5 }, () => diagnostics(1, 1, 1, 1, 1))); + const rows = renderBrowserDiagnosticsRows(base, head).join('\n'); + + for (const label of ['Page errors', 'Console log', 'Console warnings', 'Console errors', 'Console info']) { + assert.match(rows, new RegExp(`\\*\\*${label}\\*\\*`)); + } +}); + +test('renders browser diagnostics deltas from paired rounds instead of summary medians', () => { + const base = browserReport('base', [0, 9, 10, 100, 101].map(value => diagnostics(value, 0, 0, 0, 0))); + const head = browserReport('head', [10, 100, 101, 0, 9].map(value => diagnostics(value, 0, 0, 0, 0))); + const rows = renderBrowserDiagnosticsRows(base, head); + + assert.equal(rows.length, 1); + assert.match(rows[0], /\*\*Page errors\*\*/); + assert.match(rows[0], /\\text\{\+10\}/); +}); + +test('omits browser diagnostics rows whose paired median does not change', () => { + const values = Array.from({ length: 5 }, () => diagnostics(2, 3, 4, 5, 6)); + const base = browserReport('base', values); + const head = browserReport('head', values); + + assert.deepEqual(renderBrowserDiagnosticsRows(base, head), []); +}); diff --git a/.github/scripts/measure-frontend-browser-comparison.mts b/.github/scripts/measure-frontend-browser-comparison.mts index 0825133b1df..3e357c3396e 100644 --- a/.github/scripts/measure-frontend-browser-comparison.mts +++ b/.github/scripts/measure-frontend-browser-comparison.mts @@ -7,7 +7,7 @@ import { copyFile, mkdir, rm, writeFile } from 'node:fs/promises'; import { join, resolve } from 'node:path'; import * as util from './utility.mts'; import * as heapSnapshotUtil from './heap-snapshot-util.mts'; -import { HeadlessChromeController, summarizeNetwork } from './chrome.mts'; +import { HeadlessChromeController, summarizeBrowserDiagnostics, summarizeNetwork } from './chrome.mts'; import type { BrowserMeasurement, NetworkRequest, NetworkSummary } from './chrome.mts'; import { closeUserSetupDialog, postNote, signupThroughUi, visitHome } from '../../packages/frontend/test/e2e/shared.ts'; @@ -173,6 +173,7 @@ function summarizeSamples(label: 'base' | 'head', samples: BrowserMeasurementSam timestamp: new Date().toISOString(), url: baseUrl, scenario: representative.scenario, + diagnostics: summarizeBrowserDiagnostics(samples.map(sample => sample.diagnostics)), durationMs: finiteMedian(samples.map(sample => sample.durationMs)), network: summarizeNetworkSamples(samples), performance: summarizePerformanceSamples(samples), @@ -210,6 +211,7 @@ async function measureSample(label: 'base' | 'head', round: number, heapSnapshot timestamp: new Date().toISOString(), url: baseUrl, scenario: 'fresh browser signup, first timeline note, after the note becomes visible', + diagnostics: chrome.collectDiagnostics(), durationMs, network: summarizeNetwork(chrome.networkRequests, baseUrl, chrome.webSocketConnections), networkRequests: chrome.networkRequests, diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 63f8684c33e..c1a3aeda6e1 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -152,3 +152,4 @@ jobs: node-version-file: '.node-version' - run: node --test .github/scripts/frontend-js-size.test.mts - run: node --test .github/scripts/memory-stability-util.test.mts + - run: node --test .github/scripts/frontend-browser-report.test.mts From 93bbc89c7adfba9d580c433dd07b19ab0235838b Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 19:58:24 +0900 Subject: [PATCH 374/578] chore(dev): tweak frontend browser diagnostics --- .github/scripts/chrome.mts | 58 ++++------- .github/scripts/frontend-browser-report.mts | 18 ++-- .../scripts/frontend-browser-report.test.mts | 98 ------------------- .github/workflows/lint.yml | 1 - 4 files changed, 24 insertions(+), 151 deletions(-) delete mode 100644 .github/scripts/frontend-browser-report.test.mts diff --git a/.github/scripts/chrome.mts b/.github/scripts/chrome.mts index 2be10bd261b..b40c82a263d 100644 --- a/.github/scripts/chrome.mts +++ b/.github/scripts/chrome.mts @@ -90,53 +90,19 @@ export type TabMemory = { totalBytes: number; }; -export type BrowserConsoleMetrics = { - log: number; - warn: number; - error: number; - info: number; -}; - export type BrowserDiagnostics = { pageErrorCount: number; - console: BrowserConsoleMetrics; + console: Record<'log' | 'warning' | 'error' | 'info', number>; }; -export function createBrowserDiagnostics(): BrowserDiagnostics { - return { - pageErrorCount: 0, - console: { - log: 0, - warn: 0, - error: 0, - info: 0, - }, - }; -} - -export function recordPageError(diagnostics: BrowserDiagnostics) { - diagnostics.pageErrorCount += 1; -} - -function isBrowserConsoleMetricKey(value: string): value is keyof BrowserConsoleMetrics { - return value === 'log' || value === 'warn' || value === 'error' || value === 'info'; -} - -export function recordConsoleMessageType(diagnostics: BrowserDiagnostics, messageType: string) { - const metricKey = messageType === 'warning' ? 'warn' : messageType; - if (!isBrowserConsoleMetricKey(metricKey)) return; - diagnostics.console[metricKey] += 1; -} - export function summarizeBrowserDiagnostics(samples: BrowserDiagnostics[]): BrowserDiagnostics { - if (samples.length === 0) throw new Error('No browser diagnostic samples'); const median = (select: (sample: BrowserDiagnostics) => number) => util.median(samples.map(select)); return { pageErrorCount: median(sample => sample.pageErrorCount), console: { log: median(sample => sample.console.log), - warn: median(sample => sample.console.warn), + warning: median(sample => sample.console.warning), error: median(sample => sample.console.error), info: median(sample => sample.console.info), }, @@ -204,7 +170,10 @@ type PlaywrightBrowserOptions = { export class HeadlessChromeController { public networkRequests: NetworkRequest[] = []; public webSocketConnections: WebSocketConnection[] = []; - private readonly diagnostics = createBrowserDiagnostics(); + private readonly diagnostics = { + pageErrorCount: 0, + console: {} as Record, + }; private readonly browser: Browser; private readonly context: BrowserContext; public readonly page: Page; @@ -225,10 +194,14 @@ export class HeadlessChromeController { this.page.setDefaultTimeout(options.scenarioTimeoutMs); this.page.setDefaultNavigationTimeout(options.scenarioTimeoutMs); this.page.on('pageerror', () => { - recordPageError(this.diagnostics); + this.diagnostics.pageErrorCount++; }); this.page.on('console', message => { - recordConsoleMessageType(this.diagnostics, message.type()); + if (this.diagnostics.console[message.type()] == null) { + this.diagnostics.console[message.type()] = 1; + } else { + this.diagnostics.console[message.type()]++; + } }); } @@ -441,7 +414,12 @@ export class HeadlessChromeController { public collectDiagnostics(): BrowserDiagnostics { return { pageErrorCount: this.diagnostics.pageErrorCount, - console: { ...this.diagnostics.console }, + console: { + log: this.diagnostics.console.log ?? 0, + warning: this.diagnostics.console.warning ?? 0, + error: this.diagnostics.console.error ?? 0, + info: this.diagnostics.console.info ?? 0, + }, }; } diff --git a/.github/scripts/frontend-browser-report.mts b/.github/scripts/frontend-browser-report.mts index 829041f1d0a..cfb37ccf3b8 100644 --- a/.github/scripts/frontend-browser-report.mts +++ b/.github/scripts/frontend-browser-report.mts @@ -172,19 +172,8 @@ function getMetric(report: BrowserMeasurement, key: string) { return report.performance.cdpMetrics[key]; } -export function renderBrowserDiagnosticsRows(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { - return [ - metricRow('Page errors', base, head, summary => summary.diagnostics.pageErrorCount, sample => sample.diagnostics.pageErrorCount, util.formatNumber, 1, !all), - metricRow('Console log', base, head, summary => summary.diagnostics.console.log, sample => sample.diagnostics.console.log, util.formatNumber, 1, !all), - metricRow('Console warnings', base, head, summary => summary.diagnostics.console.warn, sample => sample.diagnostics.console.warn, util.formatNumber, 1, !all), - metricRow('Console errors', base, head, summary => summary.diagnostics.console.error, sample => sample.diagnostics.console.error, util.formatNumber, 1, !all), - metricRow('Console info', base, head, summary => summary.diagnostics.console.info, sample => sample.diagnostics.console.info, util.formatNumber, 1, !all), - ].filter(row => row != null); -} - function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { const rows = [ - ...renderBrowserDiagnosticsRows(base, head, all), //metricRow('Scenario duration', base, head, summary => summary.durationMs, sample => sample.durationMs, formatMs), metricRow('Requests', base, head, summary => summary.network.requestCount, sample => sample.network.requestCount, util.formatNumber, 1, !all), //metricRow('Failed requests', base, head, summary => summary.network.failedRequestCount, sample => sample.network.failedRequestCount, util.formatNumber), @@ -215,7 +204,12 @@ function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsRepo metricRow('WebSocket connections', base, head, summary => summary.network.webSocketConnectionCount, sample => sample.network.webSocketConnectionCount, util.formatNumber, 1, !all), metricRow('WebSocket sent', base, head, summary => summary.network.webSocketSentBytes, sample => sample.network.webSocketSentBytes, util.formatBytes, 10000, !all), metricRow('WebSocket received', base, head, summary => summary.network.webSocketReceivedBytes, sample => sample.network.webSocketReceivedBytes, util.formatBytes, 10000, !all), - metricRow('Tab memory', base, head, summary => summary.performance.tabMemory.totalBytes, sample => sample.performance.tabMemory.totalBytes, util.formatBytes, 10000, !all), + metricRow('Page errors', base, head, summary => summary.diagnostics.pageErrorCount, sample => sample.diagnostics.pageErrorCount, util.formatNumber, 1, !all), + metricRow('Console log', base, head, summary => summary.diagnostics.console.log, sample => sample.diagnostics.console.log, util.formatNumber, 1, !all), + metricRow('Console warnings', base, head, summary => summary.diagnostics.console.warn, sample => sample.diagnostics.console.warn, util.formatNumber, 1, !all), + metricRow('Console errors', base, head, summary => summary.diagnostics.console.error, sample => sample.diagnostics.console.error, util.formatNumber, 1, !all), + metricRow('Console info', base, head, summary => summary.diagnostics.console.info, sample => sample.diagnostics.console.info, util.formatNumber, 1, !all), + metricRow('Page-attributed memory', base, head, summary => summary.performance.tabMemory.totalBytes, sample => sample.performance.tabMemory.totalBytes, util.formatBytes, 10000, !all), ].filter(row => row != null); return [ diff --git a/.github/scripts/frontend-browser-report.test.mts b/.github/scripts/frontend-browser-report.test.mts deleted file mode 100644 index 4d4f1305043..00000000000 --- a/.github/scripts/frontend-browser-report.test.mts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import assert from 'node:assert/strict'; -import test from 'node:test'; -import { - createBrowserDiagnostics, - recordConsoleMessageType, - recordPageError, - summarizeBrowserDiagnostics, - type BrowserDiagnostics, -} from './chrome.mts'; -import { - renderBrowserDiagnosticsRows, - type BrowserMeasurement, - type BrowserMeasurementSample, - type BrowserMetricsReport, -} from './frontend-browser-report.mts'; - -function diagnostics(pageErrorCount: number, log: number, warn: number, error: number, info: number): BrowserDiagnostics { - return { - pageErrorCount, - console: { log, warn, error, info }, - }; -} - -function browserReport(label: 'base' | 'head', values: BrowserDiagnostics[]): BrowserMetricsReport { - const samples = values.map((value, index) => ({ - round: index + 1, - diagnostics: value, - } as BrowserMeasurementSample)); - - return { - label, - timestamp: '2026-07-16T00:00:00.000Z', - url: 'http://127.0.0.1:61812', - scenario: 'test', - sampleCount: samples.length, - aggregation: 'median', - summary: { - diagnostics: summarizeBrowserDiagnostics(values), - } as BrowserMeasurement, - samples, - }; -} - -test('records page errors and only the requested console message types', () => { - const result = createBrowserDiagnostics(); - recordPageError(result); - recordPageError(result); - for (const type of ['log', 'warning', 'error', 'info', 'debug', 'trace']) { - recordConsoleMessageType(result, type); - } - - assert.deepEqual(result, diagnostics(2, 1, 1, 1, 1)); -}); - -test('summarizes browser diagnostics with a median for every counter', () => { - const result = summarizeBrowserDiagnostics([ - diagnostics(0, 10, 20, 30, 40), - diagnostics(4, 14, 24, 34, 44), - diagnostics(2, 12, 22, 32, 42), - diagnostics(3, 13, 23, 33, 43), - diagnostics(1, 11, 21, 31, 41), - ]); - - assert.deepEqual(result, diagnostics(2, 12, 22, 32, 42)); -}); - -test('renders each changed browser diagnostics metric as a separate row', () => { - const base = browserReport('base', Array.from({ length: 5 }, () => diagnostics(0, 0, 0, 0, 0))); - const head = browserReport('head', Array.from({ length: 5 }, () => diagnostics(1, 1, 1, 1, 1))); - const rows = renderBrowserDiagnosticsRows(base, head).join('\n'); - - for (const label of ['Page errors', 'Console log', 'Console warnings', 'Console errors', 'Console info']) { - assert.match(rows, new RegExp(`\\*\\*${label}\\*\\*`)); - } -}); - -test('renders browser diagnostics deltas from paired rounds instead of summary medians', () => { - const base = browserReport('base', [0, 9, 10, 100, 101].map(value => diagnostics(value, 0, 0, 0, 0))); - const head = browserReport('head', [10, 100, 101, 0, 9].map(value => diagnostics(value, 0, 0, 0, 0))); - const rows = renderBrowserDiagnosticsRows(base, head); - - assert.equal(rows.length, 1); - assert.match(rows[0], /\*\*Page errors\*\*/); - assert.match(rows[0], /\\text\{\+10\}/); -}); - -test('omits browser diagnostics rows whose paired median does not change', () => { - const values = Array.from({ length: 5 }, () => diagnostics(2, 3, 4, 5, 6)); - const base = browserReport('base', values); - const head = browserReport('head', values); - - assert.deepEqual(renderBrowserDiagnosticsRows(base, head), []); -}); diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c1a3aeda6e1..63f8684c33e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -152,4 +152,3 @@ jobs: node-version-file: '.node-version' - run: node --test .github/scripts/frontend-js-size.test.mts - run: node --test .github/scripts/memory-stability-util.test.mts - - run: node --test .github/scripts/frontend-browser-report.test.mts From 12be1fe5b5002d195e4817c888ee052cbc5a1ea7 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 20:23:01 +0900 Subject: [PATCH 375/578] [skip ci] chore(dev): tweak backend-memory-report --- .github/scripts/backend-memory-report.mts | 277 ++-------------------- 1 file changed, 16 insertions(+), 261 deletions(-) diff --git a/.github/scripts/backend-memory-report.mts b/.github/scripts/backend-memory-report.mts index 4a701655ecd..85630f87b2c 100644 --- a/.github/scripts/backend-memory-report.mts +++ b/.github/scripts/backend-memory-report.mts @@ -8,34 +8,7 @@ import * as util from './utility.mts'; import * as heapSnapshotUtil from './heap-snapshot-util.mts'; import type { MemoryReport } from './measure-backend-memory-comparison.mts'; -const [baseFile, headFile, outputFile, baseJsFootprintFile, headJsFootprintFile] = process.argv.slice(2); - -type RuntimeLoadedJsFootprintReport = { - phases: Record<'afterRequest', { - totals: { - loadedJsModules: number; - loadedJsSourceBytes: number; - loadedJsGzipBytes: number; - astNodeCount: number; - functionCount: number; - classCount: number; - stringLiteralBytes: number; - externalPackageCount: number; - nativeAddonPackageCount: number; - }; - modules: { - path: string; - package: string; - category: string; - sourceBytes: number; - gzipBytes: number; - astNodeCount: number; - functionCount: number; - classCount: number; - stringLiteralBytes: number; - }[]; - }>; -}; +const [baseFile, headFile, outputFile] = process.argv.slice(2); const memoryReportPhases = [ { @@ -44,7 +17,7 @@ const memoryReportPhases = [ }, ] as const; -const metrics = [ +const memoryMetrics = [ 'HeapUsed', 'Pss', 'USS', @@ -56,26 +29,26 @@ function formatMemoryMb(valueKiB: number | null | undefined) { return `${util.formatNumber(valueKiB / 1000)} MB`; } -function formatMetricName(metric: typeof metrics[number]) { +function formatMemoryMetricName(metric: typeof memoryMetrics[number]) { return metric === 'Pss' ? 'PSS' : metric; } -function getMemoryValueFromSample(sample: MemoryReport['samples'][number], phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { +function getMemoryValueFromSample(sample: MemoryReport['samples'][number], phase: typeof memoryReportPhases[number]['key'], metric: typeof memoryMetrics[number]) { const memoryUsage = sample.phases[phase].memoryUsage; if (metric !== 'USS') return memoryUsage[metric]; return memoryUsage.Private_Clean + memoryUsage.Private_Dirty; } -function getSampleValues(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { +function getSampleValues(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof memoryMetrics[number]) { return report.samples.map(sample => getMemoryValueFromSample(sample, phase, metric)); } -function getMemoryValue(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { +function getMemoryValue(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof memoryMetrics[number]) { if (metric !== 'USS') return report.summary[phase].memoryUsage[metric]; return util.median(getSampleValues(report, phase, metric)); } -function getSampleSpread(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { +function getSampleSpread(report: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof memoryMetrics[number]) { const values = getSampleValues(report, phase, metric); if (values.length < 2) return null; @@ -93,7 +66,7 @@ function renderMainTableForPhase(base: MemoryReport, head: MemoryReport, phase: return util.formatColoredDelta(deltaKiB, v => formatMemoryMb(v), 100); // 0.1 MB threshold } - for (const metric of metrics) { + for (const metric of memoryMetrics) { const baseValue = getMemoryValue(base, phase, metric); const headValue = getMemoryValue(head, phase, metric); @@ -103,29 +76,12 @@ function renderMainTableForPhase(base: MemoryReport, head: MemoryReport, phase: const percent = summary.median * 100 / baseValue; const deltaMedian = `${formatDeltaMemory(summary.median)}
${util.formatDeltaPercent(percent, 0.1).replaceAll('\\%', '\\\\%')}`; - lines.push(`| **${formatMetricName(metric)}** | ${formatMemoryMb(baseValue)}
± ${formatMemoryMb(baseSpread)} | ${formatMemoryMb(headValue)}
± ${formatMemoryMb(headSpread)} | ${deltaMedian} | ${formatMemoryMb(summary.mad)} | ${formatDeltaMemory(summary.min)} | ${formatDeltaMemory(summary.max)} |`); + lines.push(`| **${formatMemoryMetricName(metric)}** | ${formatMemoryMb(baseValue)}
± ${formatMemoryMb(baseSpread)} | ${formatMemoryMb(headValue)}
± ${formatMemoryMb(headSpread)} | ${deltaMedian} | ${formatMemoryMb(summary.mad)} | ${formatDeltaMemory(summary.min)} | ${formatDeltaMemory(summary.max)} |`); } return lines.join('\n'); } -/* -function measurementSummary(base, head) { - const baseCount = base?.sampleCount; - const headCount = head?.sampleCount; - const strategy = base?.comparison?.strategy; - if (baseCount == null || headCount == null) return null; - - if (strategy === 'interleaved-pairs') { - const rounds = base?.comparison?.rounds ?? baseCount; - const warmupRounds = base?.comparison?.warmupRounds ?? 0; - return `_Measured as ${rounds} interleaved base/head pairs after ${warmupRounds} warmup pair(s). Values are medians; ± is median absolute deviation._`; - } - - return `_Sample count: base ${baseCount}, head ${headCount}. Values are medians; ± is median absolute deviation._`; -} -*/ - function renderHeapSnapshotSection(base: MemoryReport, head: MemoryReport) { const baseHeapSnapshotReport = { summary: base.summary.afterGc.heapSnapshot!, @@ -165,204 +121,11 @@ function renderHeapSnapshotSection(base: MemoryReport, head: MemoryReport) { return lines.join('\n'); } -function getJsFootprintValue(report: RuntimeLoadedJsFootprintReport, phase: 'afterRequest', key: keyof RuntimeLoadedJsFootprintReport['phases'][typeof phase]['totals']) { - const value = report.phases[phase].totals[key]; - return Number.isFinite(value) ? value : null; -} - -function renderJsFootprintMetricTable(base: RuntimeLoadedJsFootprintReport, head: RuntimeLoadedJsFootprintReport) { - const metricRows = [ - ['Loaded JS modules', 'loadedJsModules', util.formatNumber], - ['Loaded JS source', 'loadedJsSourceBytes', util.formatBytes], - //['Loaded JS gzip estimate', 'loadedJsGzipBytes', util.formatBytes], - //['AST nodes', 'astNodeCount', util.formatNumber], - //['Functions', 'functionCount', util.formatNumber], - //['Classes', 'classCount', util.formatNumber], - //['String literals', 'stringLiteralBytes', util.formatBytes], - ['External packages loaded', 'externalPackageCount', util.formatNumber], - ['Native addon packages', 'nativeAddonPackageCount', util.formatNumber], - ] as const; - - const lines = [ - '| Metric | Base | Head | Δ | Δ (%) |', - '| --- | ---: | ---: | ---: | ---: |', - ]; - - for (const [title, key, formatter] of metricRows) { - const baseValue = getJsFootprintValue(base, 'afterRequest', key); - const headValue = getJsFootprintValue(head, 'afterRequest', key); - if (baseValue == null || headValue == null) continue; - - lines.push(`| **${title}** | ${formatter(baseValue)} | ${formatter(headValue)} | ${util.formatColoredDelta(headValue - baseValue, v => formatter(v))} | ${util.calcAndFormatDeltaPercent(baseValue, headValue).replaceAll('\\%', '\\\\%')} |`); - } - - return lines.join('\n'); -} - -/* -function renderJsFootprintPhaseTable(base, head) { - const lines = [ - '| Phase | Base modules | Head modules | Δ modules | Base source | Head source | Δ source |', - '| --- | ---: | ---: | ---: | ---: | ---: | ---: |', - ]; - - for (const [phase, title] of [['startup', 'Startup'], ['afterRequest', 'After warmup requests']]) { - const baseModules = getJsFootprintValue(base, phase, 'loadedJsModules'); - const headModules = getJsFootprintValue(head, phase, 'loadedJsModules'); - const baseSource = getJsFootprintValue(base, phase, 'loadedJsSourceBytes'); - const headSource = getJsFootprintValue(head, phase, 'loadedJsSourceBytes'); - if (baseModules == null || headModules == null || baseSource == null || headSource == null) continue; - - lines.push(`| ${title} | ${util.formatNumber(baseModules)} | ${util.formatNumber(headModules)} | ${formatPlainDelta(baseModules, headModules)} | ${util.formatBytes(baseSource)} | ${util.formatBytes(headSource)} | ${formatPlainDelta(baseSource, headSource, util.formatBytes)} |`); - } - - return lines.join('\n'); -} -*/ - -function packageMap(report: RuntimeLoadedJsFootprintReport) { - const map = new Map(); - for (const packageSummary of report.phases.afterRequest.packages) { - if (packageSummary?.category !== 'external' || typeof packageSummary.name !== 'string') continue; - map.set(packageSummary.name, packageSummary); - } - return map; -} - -function packageDisplayName(packageSummary: { name: string; version?: string | null }) { - if (packageSummary.version == null) return packageSummary.name; - return `${packageSummary.name} ${packageSummary.version}`; -} - -function renderNewExternalPackages(base: RuntimeLoadedJsFootprintReport, head: RuntimeLoadedJsFootprintReport) { - const basePackages = packageMap(base); - const headPackages = packageMap(head); - const newPackages = [...headPackages.values()] - .filter(packageSummary => !basePackages.has(packageSummary.name)) - .toSorted((a, b) => b.sourceBytes - a.sourceBytes) - .slice(0, 10); - - if (newPackages.length === 0) return null; - - const lines = [ - '#### Newly Loaded External Packages', - '', - '| Package | Loaded JS | Modules | Notes |', - '| --- | ---: | ---: | --- |', - ]; - - for (const packageSummary of newPackages) { - lines.push(`| ${packageDisplayName(packageSummary)} | ${util.formatBytes(packageSummary.sourceBytes)} | ${util.formatNumber(packageSummary.modules)} | ${packageSummary.nativeAddon ? 'native addon' : ''} |`); - } - - return lines.join('\n'); -} - -function renderLargestPackageIncreases(base: RuntimeLoadedJsFootprintReport, head: RuntimeLoadedJsFootprintReport) { - const basePackages = packageMap(base); - const headPackages = packageMap(head); - const increases = [...headPackages.values()] - .map(headPackage => { - const basePackage = basePackages.get(headPackage.name); - const baseSourceBytes = basePackage?.sourceBytes ?? 0; - const baseModules = basePackage?.modules ?? 0; - return { - ...headPackage, - baseSourceBytes, - baseModules, - sourceDiff: headPackage.sourceBytes - baseSourceBytes, - moduleDiff: headPackage.modules - baseModules, - }; - }) - .filter(packageSummary => packageSummary.sourceDiff > 0) - .toSorted((a, b) => b.sourceDiff - a.sourceDiff) - .slice(0, 10); - - if (increases.length === 0) return null; - - const lines = [ - '#### Largest Package Increases', - '', - '| Package | Base | Head | Δ | Modules Δ |', - '| --- | ---: | ---: | ---: | ---: |', - ]; - - for (const packageSummary of increases) { - lines.push(`| ${packageDisplayName(packageSummary)} | ${util.formatBytes(packageSummary.baseSourceBytes)} | ${util.formatBytes(packageSummary.sourceBytes)} | ${util.formatColoredDelta(packageSummary.sourceBytes - packageSummary.baseSourceBytes, v => util.formatBytes(v))} | ${util.formatColoredDelta(packageSummary.modules - packageSummary.baseModules, v => util.formatNumber(v))} |`); - } - - return lines.join('\n'); -} - -function renderNewLoadedModules(base: RuntimeLoadedJsFootprintReport, head: RuntimeLoadedJsFootprintReport) { - function moduleMap(report: RuntimeLoadedJsFootprintReport) { - const map = new Map(); - for (const moduleSummary of report.phases.afterRequest.modules) { - if (typeof moduleSummary.path !== 'string') continue; - map.set(moduleSummary.path, moduleSummary); - } - return map; - } - - const baseModules = moduleMap(base); - const headModules = moduleMap(head); - const newModules = [...headModules.values()] - .filter(moduleSummary => !baseModules.has(moduleSummary.path)) - .toSorted((a, b) => b.sourceBytes - a.sourceBytes) - .slice(0, 10); - - if (newModules.length === 0) return null; - - const lines = [ - '#### Largest Newly Loaded Modules', - '', - '| Module | Package | Loaded JS |', - '| --- | --- | ---: |', - ]; - - for (const moduleSummary of newModules) { - lines.push(`| \`${moduleSummary.path}\` | ${moduleSummary.package} | ${util.formatBytes(moduleSummary.sourceBytes)} |`); - } - - return lines.join('\n'); -} - -function renderJsFootprintSection(base: RuntimeLoadedJsFootprintReport, head: RuntimeLoadedJsFootprintReport) { - const lines = [ - '### Runtime Loaded JS Footprint', - '', - '
Click to show', - '', - renderJsFootprintMetricTable(base, head), - '', - //'#### Load Phase Breakdown', - //'', - //renderJsFootprintPhaseTable(base, head), - //'', - ]; - - for (const block of [ - renderNewExternalPackages(base, head), - renderLargestPackageIncreases(base, head), - renderNewLoadedModules(base, head), - ]) { - if (block == null) continue; - lines.push(block); - lines.push(''); - } - - lines.push('
'); - lines.push(''); - - return lines.join('\n'); -} - const base = JSON.parse(await readFile(baseFile, 'utf8')) as MemoryReport; const head = JSON.parse(await readFile(headFile, 'utf8')) as MemoryReport; -const baseJsFootprint = JSON.parse(await readFile(baseJsFootprintFile, 'utf8')) as RuntimeLoadedJsFootprintReport; -const headJsFootprint = JSON.parse(await readFile(headJsFootprintFile, 'utf8')) as RuntimeLoadedJsFootprintReport; + const lines = [ - '## ⚙� Backend Memory Usage Report', + '## ⚙� Backend Diagnostics Report', '', ]; @@ -373,7 +136,7 @@ const lines = [ //} for (const phase of memoryReportPhases) { - lines.push(`### ${phase.title}`); + lines.push(`### Memory: ${phase.title}`); lines.push(renderMainTableForPhase(base, head, phase.key)); lines.push(''); } @@ -386,22 +149,16 @@ if (heapSnapshotSection != null) { const baseHeapSnapshotArtifactUrl = process.env.MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_BASE!.trim(); const headHeapSnapshotArtifactUrl = process.env.MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_HEAD!.trim(); -lines.push(`Download representative V8 heap snapshot [base](${baseHeapSnapshotArtifactUrl}) / [head](${headHeapSnapshotArtifactUrl})`); +lines.push(`You can download the representative heap snapshot: [base](${baseHeapSnapshotArtifactUrl}) / [head](${headHeapSnapshotArtifactUrl})`); lines.push(''); -const jsFootprintSection = renderJsFootprintSection(baseJsFootprint, headJsFootprint); -if (jsFootprintSection != null) { - lines.push(jsFootprintSection); - lines.push(''); -} - -function getDiffPercent(base: MemoryReport, head: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { +function getDiffPercent(base: MemoryReport, head: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof memoryMetrics[number]) { const baseValue = getMemoryValue(base, phase, metric); const headValue = getMemoryValue(head, phase, metric); return ((headValue - baseValue) * 100) / baseValue; } -function isBeyondSampleNoise(base: MemoryReport, head: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof metrics[number]) { +function isBeyondSampleNoise(base: MemoryReport, head: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof memoryMetrics[number]) { const baseValue = getMemoryValue(base, phase, metric); const headValue = getMemoryValue(head, phase, metric); @@ -419,10 +176,8 @@ function isBeyondSampleNoise(base: MemoryReport, head: MemoryReport, phase: type const warningMetric = 'Pss'; const warningDiffPercent = getDiffPercent(base, head, 'afterGc', warningMetric); if (warningDiffPercent > 5 && isBeyondSampleNoise(base, head, 'afterGc', warningMetric)) { - lines.push(`⚠� **Warning**: Memory usage (${formatMetricName(warningMetric)}) has increased by more than 5% and exceeds the observed sample noise. Please verify this is not an unintended change.`); + lines.push(`⚠� **Warning**: Memory usage (${formatMemoryMetricName(warningMetric)}) has increased by more than 5% and exceeds the observed sample noise. Please verify this is not an unintended change.`); lines.push(''); } -//lines.push(`[See workflow logs for details](https://github.com/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID})`); - await writeFile(outputFile, `${lines.join('\n')}\n`); From 1a04d4c2d91b09324938ea9956d6d26353179e7c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 20:36:55 +0900 Subject: [PATCH 376/578] refacotr(gh): rename some files --- ...ry-report.mts => backend-diagnostics.render-md.mts} | 0 .github/scripts/frontend-browser-report.mts | 2 +- ...kend-memory.yml => backend-diagnostics.inspect.yml} | 10 +++++----- ...ckend-memory.yml => backend-diagnostics.report.yml} | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) rename .github/scripts/{backend-memory-report.mts => backend-diagnostics.render-md.mts} (100%) rename .github/workflows/{get-backend-memory.yml => backend-diagnostics.inspect.yml} (93%) rename .github/workflows/{report-backend-memory.yml => backend-diagnostics.report.yml} (90%) diff --git a/.github/scripts/backend-memory-report.mts b/.github/scripts/backend-diagnostics.render-md.mts similarity index 100% rename from .github/scripts/backend-memory-report.mts rename to .github/scripts/backend-diagnostics.render-md.mts diff --git a/.github/scripts/frontend-browser-report.mts b/.github/scripts/frontend-browser-report.mts index cfb37ccf3b8..1ecfbe14db2 100644 --- a/.github/scripts/frontend-browser-report.mts +++ b/.github/scripts/frontend-browser-report.mts @@ -206,7 +206,7 @@ function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsRepo metricRow('WebSocket received', base, head, summary => summary.network.webSocketReceivedBytes, sample => sample.network.webSocketReceivedBytes, util.formatBytes, 10000, !all), metricRow('Page errors', base, head, summary => summary.diagnostics.pageErrorCount, sample => sample.diagnostics.pageErrorCount, util.formatNumber, 1, !all), metricRow('Console log', base, head, summary => summary.diagnostics.console.log, sample => sample.diagnostics.console.log, util.formatNumber, 1, !all), - metricRow('Console warnings', base, head, summary => summary.diagnostics.console.warn, sample => sample.diagnostics.console.warn, util.formatNumber, 1, !all), + metricRow('Console warnings', base, head, summary => summary.diagnostics.console.warning, sample => sample.diagnostics.console.warning, util.formatNumber, 1, !all), metricRow('Console errors', base, head, summary => summary.diagnostics.console.error, sample => sample.diagnostics.console.error, util.formatNumber, 1, !all), metricRow('Console info', base, head, summary => summary.diagnostics.console.info, sample => sample.diagnostics.console.info, util.formatNumber, 1, !all), metricRow('Page-attributed memory', base, head, summary => summary.performance.tabMemory.totalBytes, sample => sample.performance.tabMemory.totalBytes, util.formatBytes, 10000, !all), diff --git a/.github/workflows/get-backend-memory.yml b/.github/workflows/backend-diagnostics.inspect.yml similarity index 93% rename from .github/workflows/get-backend-memory.yml rename to .github/workflows/backend-diagnostics.inspect.yml index 1f933444bda..65412bafa86 100644 --- a/.github/workflows/get-backend-memory.yml +++ b/.github/workflows/backend-diagnostics.inspect.yml @@ -1,5 +1,5 @@ -# this name is used in report-backend-memory.yml so be careful when change name -name: Get backend memory usage +# this name is used in backend-diagnostics.report.yml so be careful when change name +name: Backend diagnostics (inspect) on: pull_request: @@ -10,14 +10,14 @@ on: - packages/backend/** - packages/misskey-js/** - .github/scripts/utility.mts - - .github/scripts/backend-memory-report.mts + - .github/scripts/backend-diagnostics.render-md.mts - .github/scripts/measure-backend-memory-comparison.mts - .github/scripts/memory-stability-util*.mts - .github/scripts/backend-js-footprint.mjs - .github/scripts/backend-js-footprint-loader.mjs - .github/scripts/backend-js-footprint-require.cjs - - .github/workflows/get-backend-memory.yml - - .github/workflows/report-backend-memory.yml + - .github/workflows/backend-diagnostics.inspect.yml + - .github/workflows/backend-diagnostics.report.yml jobs: get-memory-usage: diff --git a/.github/workflows/report-backend-memory.yml b/.github/workflows/backend-diagnostics.report.yml similarity index 90% rename from .github/workflows/report-backend-memory.yml rename to .github/workflows/backend-diagnostics.report.yml index a6c0b4afdfa..f9fded83d73 100644 --- a/.github/workflows/report-backend-memory.yml +++ b/.github/workflows/backend-diagnostics.report.yml @@ -1,10 +1,10 @@ -name: Report backend memory +name: Backend diagnostics (report) on: workflow_run: types: [completed] workflows: - - Get backend memory usage # get-backend-memory.yml + - Backend diagnostics (inspect) # backend-diagnostics.inspect.yml jobs: compare-memory: @@ -60,7 +60,7 @@ jobs: env: MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_BASE: ${{ steps.find-heap-snapshot-artifacts.outputs.base-url }} MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_HEAD: ${{ steps.find-heap-snapshot-artifacts.outputs.head-url }} - run: node .github/scripts/backend-memory-report.mts ./artifacts/memory-base.json ./artifacts/memory-head.json ./output.md ./artifacts/js-footprint-base.json ./artifacts/js-footprint-head.json + run: node .github/scripts/backend-diagnostics.render-md.mts ./artifacts/memory-base.json ./artifacts/memory-head.json ./output.md ./artifacts/js-footprint-base.json ./artifacts/js-footprint-head.json - uses: thollander/actions-comment-pull-request@v3 with: pr-number: ${{ steps.load-pr-num.outputs.pr-number }} From 77c2f54fa54ab0e4a76fc307b1fc00552664c262 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 20:42:58 +0900 Subject: [PATCH 377/578] refacotr(gh): refactor --- ...on.mts => backend-diagnostics.inspect.mts} | 0 .../scripts/backend-diagnostics.render-md.mts | 2 +- .../scripts/backend-js-footprint-loader.mjs | 46 -- .../scripts/backend-js-footprint-require.cjs | 46 -- .github/scripts/backend-js-footprint.mjs | 473 ------------------ .../workflows/backend-diagnostics.inspect.yml | 13 +- .../workflows/backend-diagnostics.report.yml | 2 +- 7 files changed, 4 insertions(+), 578 deletions(-) rename .github/scripts/{measure-backend-memory-comparison.mts => backend-diagnostics.inspect.mts} (100%) delete mode 100644 .github/scripts/backend-js-footprint-loader.mjs delete mode 100644 .github/scripts/backend-js-footprint-require.cjs delete mode 100644 .github/scripts/backend-js-footprint.mjs diff --git a/.github/scripts/measure-backend-memory-comparison.mts b/.github/scripts/backend-diagnostics.inspect.mts similarity index 100% rename from .github/scripts/measure-backend-memory-comparison.mts rename to .github/scripts/backend-diagnostics.inspect.mts diff --git a/.github/scripts/backend-diagnostics.render-md.mts b/.github/scripts/backend-diagnostics.render-md.mts index 85630f87b2c..e73c22a7222 100644 --- a/.github/scripts/backend-diagnostics.render-md.mts +++ b/.github/scripts/backend-diagnostics.render-md.mts @@ -6,7 +6,7 @@ import { readFile, writeFile } from 'node:fs/promises'; import * as util from './utility.mts'; import * as heapSnapshotUtil from './heap-snapshot-util.mts'; -import type { MemoryReport } from './measure-backend-memory-comparison.mts'; +import type { MemoryReport } from './backend-diagnostics.inspect.mts'; const [baseFile, headFile, outputFile] = process.argv.slice(2); diff --git a/.github/scripts/backend-js-footprint-loader.mjs b/.github/scripts/backend-js-footprint-loader.mjs deleted file mode 100644 index cd2c0af2e63..00000000000 --- a/.github/scripts/backend-js-footprint-loader.mjs +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { appendFileSync, statSync } from 'node:fs'; -import { extname } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const traceFile = process.env.MK_BACKEND_JS_FOOTPRINT_TRACE; -const jsExtensions = new Set(['.js', '.mjs', '.cjs']); - -function recordLoadedFile(kind, url, format) { - if (traceFile == null || !url.startsWith('file:')) return; - - let filePath; - try { - filePath = fileURLToPath(url); - } catch { - return; - } - - const extension = extname(filePath); - if (!jsExtensions.has(extension)) return; - - let size = null; - try { - size = statSync(filePath).size; - } catch { - return; - } - - appendFileSync(traceFile, `${JSON.stringify({ - kind, - format, - path: filePath, - size, - timestamp: Date.now(), - })}\n`); -} - -export async function load(url, context, nextLoad) { - const result = await nextLoad(url, context); - recordLoadedFile('esm', url, result.format ?? context.format ?? null); - return result; -} diff --git a/.github/scripts/backend-js-footprint-require.cjs b/.github/scripts/backend-js-footprint-require.cjs deleted file mode 100644 index 1adab8bc054..00000000000 --- a/.github/scripts/backend-js-footprint-require.cjs +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -'use strict'; - -const { appendFileSync, statSync } = require('node:fs'); -const Module = require('node:module'); -const { extname } = require('node:path'); - -const traceFile = process.env.MK_BACKEND_JS_FOOTPRINT_TRACE; -const jsExtensions = new Set(['.js', '.mjs', '.cjs']); - -function recordLoadedFile(kind, filePath, request) { - if (traceFile == null || typeof filePath !== 'string') return; - - const extension = extname(filePath); - if (!jsExtensions.has(extension) && extension !== '.node') return; - - let size = null; - try { - size = statSync(filePath).size; - } catch { - return; - } - - appendFileSync(traceFile, `${JSON.stringify({ - kind, - format: extension === '.node' ? 'native' : 'commonjs', - path: filePath, - request, - size, - timestamp: Date.now(), - })}\n`); -} - -const originalLoad = Module._load; -const originalResolveFilename = Module._resolveFilename; - -Module._load = function load(request, parent, isMain) { - const resolved = originalResolveFilename.call(this, request, parent, isMain); - const result = originalLoad.apply(this, arguments); - recordLoadedFile('cjs', resolved, request); - return result; -}; diff --git a/.github/scripts/backend-js-footprint.mjs b/.github/scripts/backend-js-footprint.mjs deleted file mode 100644 index 9c98357ad68..00000000000 --- a/.github/scripts/backend-js-footprint.mjs +++ /dev/null @@ -1,473 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { fork, spawn } from 'node:child_process'; -import { createRequire } from 'node:module'; -import { cpus, tmpdir } from 'node:os'; -import { dirname, extname, join, relative, resolve, sep } from 'node:path'; -import { setTimeout } from 'node:timers/promises'; -import { fileURLToPath, pathToFileURL } from 'node:url'; -import { gzipSync } from 'node:zlib'; -import * as fs from 'node:fs/promises'; -import * as fsSync from 'node:fs'; -import * as http from 'node:http'; -import * as util from './utility.mts'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -const [repoDirArg, outputFileArg] = process.argv.slice(2); - -const STARTUP_TIMEOUT = util.readIntegerEnv('MK_JS_FOOTPRINT_STARTUP_TIMEOUT_MS', 120000, 1); -const SETTLE_TIME = util.readIntegerEnv('MK_JS_FOOTPRINT_SETTLE_TIME_MS', 10000, 0); -const REQUEST_COUNT = util.readIntegerEnv('MK_JS_FOOTPRINT_REQUEST_COUNT', 10, 0); - -const repoDir = resolve(repoDirArg); -const outputFile = resolve(outputFileArg); -const backendDir = join(repoDir, 'packages/backend'); -const backendBuiltDir = join(backendDir, 'built'); -const traceFile = join(tmpdir(), `misskey-backend-js-footprint-${process.pid}-${Date.now()}.jsonl`); -const require = createRequire(join(repoDir, 'package.json')); -const ts = require('typescript'); -const jsExtensions = new Set(['.js', '.mjs', '.cjs']); -const fileMetricCache = new Map(); -const packageInfoCache = new Map(); -const nativePackageNames = new Set(); - -function isInside(parent, child) { - const rel = relative(parent, child); - return rel === '' || (!rel.startsWith('..') && !rel.includes(`..${sep}`)); -} - -function bytesToKiB(value) { - return Math.round(value / 1024); -} - -async function resetState() { - const backendRequire = createRequire(join(backendDir, 'package.json')); - const pg = backendRequire('pg'); - const Redis = backendRequire('ioredis'); - - const postgres = new pg.Client({ - host: '127.0.0.1', - port: 54312, - database: 'postgres', - user: 'postgres', - }); - - await postgres.connect(); - try { - await postgres.query('DROP DATABASE IF EXISTS "test-misskey" WITH (FORCE)'); - await postgres.query('CREATE DATABASE "test-misskey"'); - } finally { - await postgres.end(); - } - - const redis = new Redis({ host: '127.0.0.1', port: 56312 }); - try { - await redis.flushall(); - } finally { - redis.disconnect(); - } -} - -function createRequest() { - return new Promise((resolvePromise, reject) => { - const req = http.request({ - host: 'localhost', - port: 61812, - path: '/api/meta', - method: 'POST', - }, res => { - res.on('data', () => { }); - res.on('end', () => resolvePromise()); - }); - req.on('error', reject); - req.end(); - }); -} - -async function waitForServerReady(serverProcess) { - let serverReady = false; - serverProcess.on('message', message => { - if (message === 'ok') serverReady = true; - }); - - const startupStartTime = Date.now(); - while (!serverReady) { - if (Date.now() - startupStartTime > STARTUP_TIMEOUT) { - serverProcess.kill('SIGTERM'); - throw new Error('Server startup timeout'); - } - await setTimeout(100); - } -} - -async function stopServer(serverProcess) { - serverProcess.kill('SIGTERM'); - - let exited = false; - await new Promise(resolvePromise => { - serverProcess.on('exit', () => { - exited = true; - resolvePromise(undefined); - }); - - setTimeout(10000).then(() => { - if (!exited) serverProcess.kill('SIGKILL'); - resolvePromise(undefined); - }); - }); -} - -function getPackageNameFromPath(filePath) { - const normalized = util.normalizePath(filePath); - const marker = '/node_modules/'; - const index = normalized.lastIndexOf(marker); - if (index === -1) return null; - - const rest = normalized.slice(index + marker.length).split('/'); - if (rest[0] === '.pnpm') { - const nestedNodeModulesIndex = rest.indexOf('node_modules'); - if (nestedNodeModulesIndex === -1) return null; - const packageParts = rest.slice(nestedNodeModulesIndex + 1); - if (packageParts.length === 0) return null; - return packageParts[0].startsWith('@') ? packageParts.slice(0, 2).join('/') : packageParts[0]; - } - - return rest[0]?.startsWith('@') ? rest.slice(0, 2).join('/') : rest[0] ?? null; -} - -function findPackageDir(filePath, packageName) { - const normalizedPackageName = packageName.split('/').join(sep); - let current = dirname(filePath); - - while (current !== dirname(current)) { - if (current.endsWith(`${sep}${normalizedPackageName}`) && fsSync.existsSync(join(current, 'package.json'))) { - return current; - } - - const parent = dirname(current); - if (parent === current) break; - current = parent; - } - - return null; -} - -function readPackageInfo(filePath) { - const externalPackageName = getPackageNameFromPath(filePath); - if (externalPackageName != null) { - const packageDir = findPackageDir(filePath, externalPackageName); - const cacheKey = packageDir ?? externalPackageName; - if (packageInfoCache.has(cacheKey)) return packageInfoCache.get(cacheKey); - - let version = null; - if (packageDir != null) { - try { - const packageJson = JSON.parse(fsSync.readFileSync(join(packageDir, 'package.json'), 'utf8')); - version = typeof packageJson.version === 'string' ? packageJson.version : null; - } catch { } - } - - const info = { - category: 'external', - name: externalPackageName, - version, - dir: packageDir, - }; - packageInfoCache.set(cacheKey, info); - return info; - } - - if (isInside(backendBuiltDir, filePath)) { - return { - category: 'internal', - name: 'backend', - version: null, - dir: backendDir, - }; - } - - return { - category: 'internal', - name: 'workspace', - version: null, - dir: repoDir, - }; -} - -function analyzeSource(filePath, source) { - const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS); - const metrics = { - astNodeCount: 0, - functionCount: 0, - classCount: 0, - stringLiteralBytes: 0, - }; - - function visit(node) { - metrics.astNodeCount += 1; - - if ( - ts.isFunctionDeclaration(node) || - ts.isFunctionExpression(node) || - ts.isArrowFunction(node) || - ts.isMethodDeclaration(node) || - ts.isConstructorDeclaration(node) || - ts.isGetAccessorDeclaration(node) || - ts.isSetAccessorDeclaration(node) - ) { - metrics.functionCount += 1; - } else if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) { - metrics.classCount += 1; - } else if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) { - metrics.stringLiteralBytes += Buffer.byteLength(node.text); - } - - ts.forEachChild(node, visit); - } - - visit(sourceFile); - return metrics; -} - -function readFileMetrics(filePath) { - if (fileMetricCache.has(filePath)) return fileMetricCache.get(filePath); - - const source = fsSync.readFileSync(filePath); - const sourceText = source.toString('utf8'); - const astMetrics = analyzeSource(filePath, sourceText); - const packageInfo = readPackageInfo(filePath); - const metric = { - path: filePath, - displayPath: util.normalizePath(relative(repoDir, filePath)), - sourceBytes: source.byteLength, - gzipBytes: gzipSync(source).byteLength, - ...astMetrics, - package: packageInfo, - }; - - fileMetricCache.set(filePath, metric); - return metric; -} - -async function readTraceRecords() { - let content = ''; - try { - content = await fs.readFile(traceFile, 'utf8'); - } catch (err) { - if (err.code === 'ENOENT') return []; - throw err; - } - - const records = []; - for (const line of content.split('\n')) { - if (line.trim() === '') continue; - try { - records.push(JSON.parse(line)); - } catch { } - } - return records; -} - -function emptyTotals() { - return { - loadedJsModules: 0, - loadedJsSourceBytes: 0, - loadedJsGzipBytes: 0, - astNodeCount: 0, - functionCount: 0, - classCount: 0, - stringLiteralBytes: 0, - externalPackageCount: 0, - nativeAddonPackageCount: 0, - }; -} - -function addFileMetrics(target, metric) { - target.loadedJsModules += 1; - target.loadedJsSourceBytes += metric.sourceBytes; - target.loadedJsGzipBytes += metric.gzipBytes; - target.astNodeCount += metric.astNodeCount; - target.functionCount += metric.functionCount; - target.classCount += metric.classCount; - target.stringLiteralBytes += metric.stringLiteralBytes; -} - -function summarizeRecords(records, phase) { - const jsPaths = new Set(); - const nativePaths = new Set(); - - for (const record of records) { - if (typeof record.path !== 'string') continue; - - const extension = extname(record.path); - if (jsExtensions.has(extension)) { - jsPaths.add(resolve(record.path)); - } else if (extension === '.node') { - nativePaths.add(resolve(record.path)); - } - } - - for (const nativePath of nativePaths) { - const packageInfo = readPackageInfo(nativePath); - if (packageInfo.category === 'external') nativePackageNames.add(packageInfo.name); - } - - const totals = emptyTotals(); - const packages = new Map(); - const modules = []; - - for (const filePath of [...jsPaths].toSorted()) { - let metric; - try { - metric = readFileMetrics(filePath); - } catch (err) { - process.stderr.write(`Failed to analyze ${filePath}: ${err.message}\n`); - continue; - } - - addFileMetrics(totals, metric); - - const packageKey = metric.package.name; - if (!packages.has(packageKey)) { - packages.set(packageKey, { - name: metric.package.name, - version: metric.package.version, - category: metric.package.category, - sourceBytes: 0, - gzipBytes: 0, - modules: 0, - astNodeCount: 0, - functionCount: 0, - classCount: 0, - stringLiteralBytes: 0, - nativeAddon: false, - }); - } - - const packageSummary = packages.get(packageKey); - packageSummary.sourceBytes += metric.sourceBytes; - packageSummary.gzipBytes += metric.gzipBytes; - packageSummary.modules += 1; - packageSummary.astNodeCount += metric.astNodeCount; - packageSummary.functionCount += metric.functionCount; - packageSummary.classCount += metric.classCount; - packageSummary.stringLiteralBytes += metric.stringLiteralBytes; - - modules.push({ - path: metric.displayPath, - package: metric.package.name, - category: metric.package.category, - sourceBytes: metric.sourceBytes, - gzipBytes: metric.gzipBytes, - astNodeCount: metric.astNodeCount, - functionCount: metric.functionCount, - classCount: metric.classCount, - stringLiteralBytes: metric.stringLiteralBytes, - }); - } - - for (const packageName of nativePackageNames) { - const packageSummary = packages.get(packageName); - if (packageSummary != null) packageSummary.nativeAddon = true; - } - - const externalPackages = [...packages.values()].filter(packageSummary => packageSummary.category === 'external'); - totals.externalPackageCount = externalPackages.length; - totals.nativeAddonPackageCount = externalPackages.filter(packageSummary => packageSummary.nativeAddon).length; - - return { - totals: { - ...totals, - loadedJsSourceKiB: bytesToKiB(totals.loadedJsSourceBytes), - loadedJsGzipKiB: bytesToKiB(totals.loadedJsGzipBytes), - stringLiteralKiB: bytesToKiB(totals.stringLiteralBytes), - }, - packages: [...packages.values()].toSorted((a, b) => b.sourceBytes - a.sourceBytes), - modules: modules.toSorted((a, b) => b.sourceBytes - a.sourceBytes), - }; -} - -async function measureFootprint() { - await fs.writeFile(traceFile, ''); - - process.stderr.write('Resetting database and Redis\n'); - await resetState(); - - process.stderr.write('Running migrations\n'); - await util.run('pnpm', ['--filter', 'backend', 'migrate'], { - cwd: repoDir, - env: process.env, - logStdout: true, - }); - - const serverProcess = fork(join(backendBuiltDir, 'entry.js'), [], { - cwd: backendDir, - env: { - ...process.env, - NODE_ENV: 'production', - MK_DISABLE_CLUSTERING: '1', - MK_ONLY_SERVER: '1', - MK_NO_DAEMONS: '1', - MK_BACKEND_JS_FOOTPRINT_TRACE: traceFile, - }, - stdio: ['pipe', 'pipe', 'pipe', 'ipc'], - execArgv: [ - '--require', - join(__dirname, 'backend-js-footprint-require.cjs'), - '--experimental-loader', - pathToFileURL(join(__dirname, 'backend-js-footprint-loader.mjs')).href, - ], - }); - - serverProcess.stdout?.on('data', data => { - process.stderr.write(`[server stdout] ${data}`); - }); - - serverProcess.stderr?.on('data', data => { - process.stderr.write(`[server stderr] ${data}`); - }); - - serverProcess.on('error', err => { - process.stderr.write(`[server error] ${err}\n`); - }); - - try { - await waitForServerReady(serverProcess); - await setTimeout(SETTLE_TIME); - - //const startup = summarizeRecords(await readTraceRecords(), 'startup'); - - await Promise.all( - Array.from({ length: REQUEST_COUNT }).map(() => createRequest()), - ); - await setTimeout(1000); - - const afterRequest = summarizeRecords(await readTraceRecords(), 'afterRequest'); - - return { - timestamp: new Date().toISOString(), - measurement: { - strategy: 'runtime-loader-trace', - startupTimeoutMs: STARTUP_TIMEOUT, - settleTimeMs: SETTLE_TIME, - requestCount: REQUEST_COUNT, - cpus: cpus().length, - }, - phases: { - //startup, - afterRequest, - }, - }; - } finally { - await stopServer(serverProcess); - await fs.rm(traceFile, { force: true }); - } -} - -const result = await measureFootprint(); -await fs.writeFile(outputFile, `${JSON.stringify(result, null, 2)}\n`); diff --git a/.github/workflows/backend-diagnostics.inspect.yml b/.github/workflows/backend-diagnostics.inspect.yml index 65412bafa86..1474c78f0cd 100644 --- a/.github/workflows/backend-diagnostics.inspect.yml +++ b/.github/workflows/backend-diagnostics.inspect.yml @@ -11,11 +11,8 @@ on: - packages/misskey-js/** - .github/scripts/utility.mts - .github/scripts/backend-diagnostics.render-md.mts - - .github/scripts/measure-backend-memory-comparison.mts + - .github/scripts/backend-diagnostics.inspect.mts - .github/scripts/memory-stability-util*.mts - - .github/scripts/backend-js-footprint.mjs - - .github/scripts/backend-js-footprint-loader.mjs - - .github/scripts/backend-js-footprint-require.cjs - .github/workflows/backend-diagnostics.inspect.yml - .github/workflows/backend-diagnostics.report.yml @@ -96,7 +93,7 @@ jobs: MK_MEMORY_COMPARE_ROUNDS: 10 MK_MEMORY_COMPARE_WARMUP_ROUNDS: 1 MK_MEMORY_HEAP_SNAPSHOT: 1 - run: node head/.github/scripts/measure-backend-memory-comparison.mts base head memory-base.json memory-head.json + run: node head/.github/scripts/backend-diagnostics.inspect.mts base head memory-base.json memory-head.json - name: Upload base heap snapshot uses: actions/upload-artifact@v7 with: @@ -111,10 +108,6 @@ jobs: archive: false if-no-files-found: error retention-days: 7 - - name: Measure backend loaded JS footprint - run: | - node head/.github/scripts/backend-js-footprint.mjs base js-footprint-base.json - node head/.github/scripts/backend-js-footprint.mjs head js-footprint-head.json - name: Upload Artifact uses: actions/upload-artifact@v7 with: @@ -122,8 +115,6 @@ jobs: path: | memory-base.json memory-head.json - js-footprint-base.json - js-footprint-head.json save-pr-number: runs-on: ubuntu-latest diff --git a/.github/workflows/backend-diagnostics.report.yml b/.github/workflows/backend-diagnostics.report.yml index f9fded83d73..f358216a620 100644 --- a/.github/workflows/backend-diagnostics.report.yml +++ b/.github/workflows/backend-diagnostics.report.yml @@ -60,7 +60,7 @@ jobs: env: MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_BASE: ${{ steps.find-heap-snapshot-artifacts.outputs.base-url }} MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_HEAD: ${{ steps.find-heap-snapshot-artifacts.outputs.head-url }} - run: node .github/scripts/backend-diagnostics.render-md.mts ./artifacts/memory-base.json ./artifacts/memory-head.json ./output.md ./artifacts/js-footprint-base.json ./artifacts/js-footprint-head.json + run: node .github/scripts/backend-diagnostics.render-md.mts ./artifacts/memory-base.json ./artifacts/memory-head.json ./output.md - uses: thollander/actions-comment-pull-request@v3 with: pr-number: ${{ steps.load-pr-num.outputs.pr-number }} From ab92f984729d5a0dbb4f641939e6d4d36ef07ba9 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:02:45 +0900 Subject: [PATCH 378/578] refacotr(gh): rename some files --- ... frontend-browser-diagnostics.inspect.mts} | 0 ...er-diagnostics.render-additional-html.mts} | 5 +- ...rontend-browser-diagnostics.render-md.mts} | 9 ++-- ... frontend-browser-diagnostics.inspect.yml} | 52 +++++++++---------- ...> frontend-browser-diagnostics.report.yml} | 18 +++---- 5 files changed, 39 insertions(+), 45 deletions(-) rename .github/scripts/{measure-frontend-browser-comparison.mts => frontend-browser-diagnostics.inspect.mts} (100%) rename .github/scripts/{frontend-browser-detailed-html.mts => frontend-browser-diagnostics.render-additional-html.mts} (98%) rename .github/scripts/{frontend-browser-report.mts => frontend-browser-diagnostics.render-md.mts} (98%) rename .github/workflows/{frontend-browser-metrics-report.yml => frontend-browser-diagnostics.inspect.yml} (69%) rename .github/workflows/{frontend-browser-metrics-report-comment.yml => frontend-browser-diagnostics.report.yml} (62%) diff --git a/.github/scripts/measure-frontend-browser-comparison.mts b/.github/scripts/frontend-browser-diagnostics.inspect.mts similarity index 100% rename from .github/scripts/measure-frontend-browser-comparison.mts rename to .github/scripts/frontend-browser-diagnostics.inspect.mts diff --git a/.github/scripts/frontend-browser-detailed-html.mts b/.github/scripts/frontend-browser-diagnostics.render-additional-html.mts similarity index 98% rename from .github/scripts/frontend-browser-detailed-html.mts rename to .github/scripts/frontend-browser-diagnostics.render-additional-html.mts index 34240eefc65..86f70e7ebd6 100644 --- a/.github/scripts/frontend-browser-detailed-html.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-additional-html.mts @@ -6,7 +6,7 @@ import { readFile, writeFile } from 'node:fs/promises'; import { pathToFileURL } from 'node:url'; import * as util from './utility.mts'; -import type { BrowserMeasurementSample, BrowserMetricsReport } from './frontend-browser-report.mts'; +import type { BrowserMeasurementSample, BrowserMetricsReport } from './frontend-browser-diagnostics.render-md.mts'; import type { NetworkRequest } from './chrome.mts'; type DiffDirection = 'added' | 'removed'; @@ -434,9 +434,6 @@ function renderHtml(base: BrowserMetricsReport, head: BrowserMetricsReport) { async function main() { const [baseFile, headFile, outputFile] = process.argv.slice(2); - if (baseFile == null || headFile == null || outputFile == null) { - throw new Error('Usage: node frontend-browser-detailed-html.mts '); - } const base = JSON.parse(await readFile(baseFile, 'utf8')) as BrowserMetricsReport; const head = JSON.parse(await readFile(headFile, 'utf8')) as BrowserMetricsReport; diff --git a/.github/scripts/frontend-browser-report.mts b/.github/scripts/frontend-browser-diagnostics.render-md.mts similarity index 98% rename from .github/scripts/frontend-browser-report.mts rename to .github/scripts/frontend-browser-diagnostics.render-md.mts index 1ecfbe14db2..b67a7901025 100644 --- a/.github/scripts/frontend-browser-report.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-md.mts @@ -324,12 +324,12 @@ export function renderFrontendBrowserReport(base: BrowserMetricsReport, head: Br : `${base.sampleCount} base sample(s), ${head.sampleCount} head sample(s)`; const heapSnapshotTable = heapSnapshotUtil.renderHeapSnapshotTable(toHeapSnapshotReport(base), toHeapSnapshotReport(head)); const lines = [ - '## 🖥 Frontend Browser Metrics', - '', - 'Only metrics showing significant changes are displayed.', + '## 🖥 Frontend Browser Diagnostics Report', '', renderSummaryTable(base, head), '', + 'Only metrics showing significant changes are displayed.', + '', //`> Measured ${sampleSummary} with fresh headless Chrome profiles, browser cache disabled, service workers bypassed, and forced V8 GC before each heap snapshot. Base/Head values are medians; Δ median is the median of paired Head - Base sample deltas; percent uses Δ median / Base median; ± and Δ MAD are median absolute deviations. Scenario: sign up, dismiss the initial account setup dialog, create the first timeline note, then wait until that note is visible.`, //'', detailedHtmlUrl == null || detailedHtmlUrl === '' ? null : `[View details](${detailedHtmlUrl})`, @@ -367,9 +367,6 @@ export function renderFrontendBrowserReport(base: BrowserMetricsReport, head: Br async function main() { const [baseFile, headFile, outputFile] = process.argv.slice(2); - if (baseFile == null || headFile == null || outputFile == null) { - throw new Error('Usage: node frontend-browser-report.mts '); - } const base = JSON.parse(await readFile(baseFile, 'utf8')) as BrowserMetricsReport; const head = JSON.parse(await readFile(headFile, 'utf8')) as BrowserMetricsReport; diff --git a/.github/workflows/frontend-browser-metrics-report.yml b/.github/workflows/frontend-browser-diagnostics.inspect.yml similarity index 69% rename from .github/workflows/frontend-browser-metrics-report.yml rename to .github/workflows/frontend-browser-diagnostics.inspect.yml index 863c7bb155c..444c54040ba 100644 --- a/.github/workflows/frontend-browser-metrics-report.yml +++ b/.github/workflows/frontend-browser-diagnostics.inspect.yml @@ -1,4 +1,4 @@ -name: frontend-browser-metrics-report +name: Frontend browser diagnostics (inspect) on: pull_request: @@ -23,20 +23,20 @@ on: - .node-version - .github/misskey/test.yml - .github/scripts/utility.mts - - .github/scripts/frontend-browser-detailed-html.mts - - .github/scripts/frontend-browser-report.mts - .github/scripts/heap-snapshot-util.mts - - .github/scripts/measure-frontend-browser-comparison.mts - .github/scripts/chrome.mts - - .github/workflows/frontend-browser-metrics-report.yml - - .github/workflows/frontend-browser-metrics-report-comment.yml + - .github/scripts/frontend-browser-diagnostics.render-additional-html.mts + - .github/scripts/frontend-browser-diagnostics.render-md.mts + - .github/scripts/frontend-browser-diagnostics.inspect.mts + - .github/workflows/frontend-browser-diagnostics.inspect.yml + - .github/workflows/frontend-browser-diagnostics.report.yml permissions: contents: read pull-requests: read concurrency: - group: frontend-browser-metrics-report-${{ github.event.pull_request.number }} + group: frontend-browser-diagnostics-inspect-${{ github.event.pull_request.number }} cancel-in-progress: true jobs: @@ -125,33 +125,33 @@ jobs: FRONTEND_BROWSER_METRICS_SAMPLE_COUNT: 5 MK_ENABLE_CROSS_ORIGIN_ISOLATION: "true" run: | - REPORT_DIR="$RUNNER_TEMP/frontend-browser-metrics-report" + REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" mkdir -p "$REPORT_DIR" - node after/.github/scripts/measure-frontend-browser-comparison.mts before after "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/head-heap-snapshot.heapsnapshot" + node after/.github/scripts/frontend-browser-diagnostics.inspect.mts before after "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/head-heap-snapshot.heapsnapshot" - name: Upload browser head heap snapshot id: upload-browser-head-heap-snapshot uses: actions/upload-artifact@v7 with: name: frontend-browser-metrics-head-heap-snapshot - path: ${{ runner.temp }}/frontend-browser-metrics-report/head-heap-snapshot.heapsnapshot + path: ${{ runner.temp }}/frontend-browser-diagnostics/head-heap-snapshot.heapsnapshot if-no-files-found: error retention-days: 7 - name: Generate browser detailed html shell: bash run: | - REPORT_DIR="$RUNNER_TEMP/frontend-browser-metrics-report" + REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" test -s "$REPORT_DIR/before-browser.json" test -s "$REPORT_DIR/after-browser.json" - node after/.github/scripts/frontend-browser-detailed-html.mts "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/frontend-browser-detailed-html.html" + node after/.github/scripts/frontend-browser-diagnostics.render-additional-html.mts "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/frontend-browser-detailed-html.html" - name: Upload browser detailed html id: upload-browser-detailed-html uses: actions/upload-artifact@v7 with: name: frontend-browser-metrics-detailed-html - path: ${{ runner.temp }}/frontend-browser-metrics-report/frontend-browser-detailed-html.html + path: ${{ runner.temp }}/frontend-browser-diagnostics/frontend-browser-detailed-html.html if-no-files-found: error archive: false retention-days: 7 @@ -165,10 +165,10 @@ jobs: FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL: ${{ steps.upload-browser-head-heap-snapshot.outputs.artifact-url }} FRONTEND_BROWSER_DETAILED_HTML_ARTIFACT_URL: ${{ steps.upload-browser-detailed-html.outputs.artifact-url }} run: | - REPORT_DIR="$RUNNER_TEMP/frontend-browser-metrics-report" + REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" test -s "$REPORT_DIR/before-browser.json" test -s "$REPORT_DIR/after-browser.json" - node after/.github/scripts/frontend-browser-report.mts "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/frontend-browser-metrics-report.md" + node after/.github/scripts/frontend-browser-diagnostics.render-md.mts "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/frontend-browser-diagnostics.md" printf '%s\n' "$PR_NUMBER" > "$REPORT_DIR/pr-number.txt" printf '%s\n' "$BASE_SHA" > "$REPORT_DIR/base-sha.txt" printf '%s\n' "$HEAD_SHA" > "$REPORT_DIR/head-sha.txt" @@ -177,24 +177,24 @@ jobs: - name: Check browser metrics report shell: bash run: | - REPORT_DIR="$RUNNER_TEMP/frontend-browser-metrics-report" - test -s "$REPORT_DIR/frontend-browser-metrics-report.md" + REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" + test -s "$REPORT_DIR/frontend-browser-diagnostics.md" test -s "$REPORT_DIR/frontend-browser-detailed-html.html" test -s "$REPORT_DIR/pr-number.txt" test -s "$REPORT_DIR/head-sha.txt" - cat "$REPORT_DIR/frontend-browser-metrics-report.md" >> "$GITHUB_STEP_SUMMARY" + cat "$REPORT_DIR/frontend-browser-diagnostics.md" >> "$GITHUB_STEP_SUMMARY" - name: Upload browser metrics report uses: actions/upload-artifact@v7 with: - name: frontend-browser-metrics-report + name: frontend-browser-diagnostics path: | - ${{ runner.temp }}/frontend-browser-metrics-report/before-browser.json - ${{ runner.temp }}/frontend-browser-metrics-report/after-browser.json - ${{ runner.temp }}/frontend-browser-metrics-report/frontend-browser-metrics-report.md - ${{ runner.temp }}/frontend-browser-metrics-report/pr-number.txt - ${{ runner.temp }}/frontend-browser-metrics-report/base-sha.txt - ${{ runner.temp }}/frontend-browser-metrics-report/head-sha.txt - ${{ runner.temp }}/frontend-browser-metrics-report/pr-url.txt + ${{ runner.temp }}/frontend-browser-diagnostics/before-browser.json + ${{ runner.temp }}/frontend-browser-diagnostics/after-browser.json + ${{ runner.temp }}/frontend-browser-diagnostics/frontend-browser-diagnostics.md + ${{ runner.temp }}/frontend-browser-diagnostics/pr-number.txt + ${{ runner.temp }}/frontend-browser-diagnostics/base-sha.txt + ${{ runner.temp }}/frontend-browser-diagnostics/head-sha.txt + ${{ runner.temp }}/frontend-browser-diagnostics/pr-url.txt if-no-files-found: error retention-days: 7 diff --git a/.github/workflows/frontend-browser-metrics-report-comment.yml b/.github/workflows/frontend-browser-diagnostics.report.yml similarity index 62% rename from .github/workflows/frontend-browser-metrics-report-comment.yml rename to .github/workflows/frontend-browser-diagnostics.report.yml index 0312092a5bd..7edc9f36c68 100644 --- a/.github/workflows/frontend-browser-metrics-report-comment.yml +++ b/.github/workflows/frontend-browser-diagnostics.report.yml @@ -1,9 +1,9 @@ -name: frontend-browser-metrics-report-comment +name: Frontend browser diagnostics (report) on: workflow_run: workflows: - - frontend-browser-metrics-report + - Frontend browser diagnostics (inspect) types: - completed @@ -15,18 +15,18 @@ permissions: jobs: comment: - name: Comment frontend browser metrics report + name: Comment frontend browser diagnostics report if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest concurrency: - group: frontend-browser-metrics-report-comment-${{ github.event.workflow_run.id }} + group: frontend-browser-diagnostics-report-${{ github.event.workflow_run.id }} cancel-in-progress: true steps: - name: Download browser metrics report uses: actions/download-artifact@v8 with: - name: frontend-browser-metrics-report - path: ${{ runner.temp }}/frontend-browser-metrics-report + name: frontend-browser-diagnostics + path: ${{ runner.temp }}/frontend-browser-diagnostics github-token: ${{ github.token }} repository: ${{ github.repository }} run-id: ${{ github.event.workflow_run.id }} @@ -34,11 +34,11 @@ jobs: - name: Load PR number id: load-pr-number shell: bash - run: echo "pr-number=$(cat "$RUNNER_TEMP/frontend-browser-metrics-report/pr-number.txt")" >> "$GITHUB_OUTPUT" + run: echo "pr-number=$(cat "$RUNNER_TEMP/frontend-browser-diagnostics/pr-number.txt")" >> "$GITHUB_OUTPUT" - name: Comment on pull request uses: thollander/actions-comment-pull-request@v3 with: pr-number: ${{ steps.load-pr-number.outputs.pr-number }} - comment-tag: frontend_browser_metrics_report - file-path: ${{ runner.temp }}/frontend-browser-metrics-report/frontend-browser-metrics-report.md + comment-tag: frontend_browser_diagnostics + file-path: ${{ runner.temp }}/frontend-browser-diagnostics/frontend-browser-diagnostics.md From 64f98faca93e45ddbe137ca366b623d6a802b6e1 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:11:41 +0900 Subject: [PATCH 379/578] refacotr(gh): refactor --- .github/scripts/backend-diagnostics.inspect.mts | 6 +++--- .github/scripts/frontend-browser-diagnostics.inspect.mts | 6 +++--- .../scripts/frontend-browser-diagnostics.render-md.mts | 9 ++------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/.github/scripts/backend-diagnostics.inspect.mts b/.github/scripts/backend-diagnostics.inspect.mts index a4e93b3ce42..5bf0f3ee99b 100644 --- a/.github/scripts/backend-diagnostics.inspect.mts +++ b/.github/scripts/backend-diagnostics.inspect.mts @@ -99,7 +99,7 @@ function summarizeSamples(samples: MemoryReport['samples']) { return summary; } -async function measureRepo(label: string, repoDir: string, round: number, options: { heapSnapshotSavePath?: string } = {}) { +async function genSample(label: string, repoDir: string, round: number, options: { heapSnapshotSavePath?: string } = {}) { process.stderr.write(`[${label}] Resetting database and Redis\n`); await resetState(repoDir); @@ -188,7 +188,7 @@ async function main() { for (let round = 1; round <= warmupRounds; round++) { process.stderr.write(`Starting warmup round ${round}/${warmupRounds}\n`); for (const label of heapSnapshotLabels) { - await measureRepo(label, reports[label].dir, -round); + await genSample(label, reports[label].dir, -round); } } @@ -198,7 +198,7 @@ async function main() { for (const label of order) { const options = { heapSnapshotSavePath: heapSnapshotPath(label, round) }; - const sample = await measureRepo(label, reports[label].dir, round, options); + const sample = await genSample(label, reports[label].dir, round, options); reports[label].samples.push({ ...sample, round, diff --git a/.github/scripts/frontend-browser-diagnostics.inspect.mts b/.github/scripts/frontend-browser-diagnostics.inspect.mts index 3e357c3396e..545149df24c 100644 --- a/.github/scripts/frontend-browser-diagnostics.inspect.mts +++ b/.github/scripts/frontend-browser-diagnostics.inspect.mts @@ -234,7 +234,7 @@ async function saveRepresentativeHeadHeapSnapshot(report: BrowserMetricsReport, await rm(headHeapSnapshotWorkDir, { recursive: true, force: true }); } -async function measureRepo(label: 'base' | 'head', repoDir: string, outputPath: string, heapSnapshotSavePath?: string) { +async function genReport(label: 'base' | 'head', repoDir: string, outputPath: string, heapSnapshotSavePath?: string) { let server: ReturnType | null = null; try { @@ -269,8 +269,8 @@ async function measureRepo(label: 'base' | 'head', repoDir: string, outputPath: } async function main() { - await measureRepo('base', resolve(baseDirArg), resolve(baseOutputArg)); - await measureRepo('head', resolve(headDirArg), resolve(headOutputArg), headHeapSnapshotOutputArg == null ? undefined : resolve(headHeapSnapshotOutputArg)); + await genReport('base', resolve(baseDirArg), resolve(baseOutputArg)); + await genReport('head', resolve(headDirArg), resolve(headOutputArg), resolve(headHeapSnapshotOutputArg)); } await main(); diff --git a/.github/scripts/frontend-browser-diagnostics.render-md.mts b/.github/scripts/frontend-browser-diagnostics.render-md.mts index b67a7901025..c18ef63f464 100644 --- a/.github/scripts/frontend-browser-diagnostics.render-md.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-md.mts @@ -313,15 +313,12 @@ function toHeapSnapshotReport(report: BrowserMetricsReport): HeapSnapshotReport }; } -export function renderFrontendBrowserReport(base: BrowserMetricsReport, head: BrowserMetricsReport, options: { +function renderMd(base: BrowserMetricsReport, head: BrowserMetricsReport, options: { headHeapSnapshotUrl?: string; detailedHtmlUrl?: string; } = {}) { const headHeapSnapshotUrl = options.headHeapSnapshotUrl; const detailedHtmlUrl = options.detailedHtmlUrl; - const sampleSummary = base.sampleCount === head.sampleCount - ? `${base.sampleCount} samples per side` - : `${base.sampleCount} base sample(s), ${head.sampleCount} head sample(s)`; const heapSnapshotTable = heapSnapshotUtil.renderHeapSnapshotTable(toHeapSnapshotReport(base), toHeapSnapshotReport(head)); const lines = [ '## 🖥 Frontend Browser Diagnostics Report', @@ -330,8 +327,6 @@ export function renderFrontendBrowserReport(base: BrowserMetricsReport, head: Br '', 'Only metrics showing significant changes are displayed.', '', - //`> Measured ${sampleSummary} with fresh headless Chrome profiles, browser cache disabled, service workers bypassed, and forced V8 GC before each heap snapshot. Base/Head values are medians; Δ median is the median of paired Head - Base sample deltas; percent uses Δ median / Base median; ± and Δ MAD are median absolute deviations. Scenario: sign up, dismiss the initial account setup dialog, create the first timeline note, then wait until that note is visible.`, - //'', detailedHtmlUrl == null || detailedHtmlUrl === '' ? null : `[View details](${detailedHtmlUrl})`, detailedHtmlUrl == null || detailedHtmlUrl === '' ? null : '', '
', @@ -370,7 +365,7 @@ async function main() { const base = JSON.parse(await readFile(baseFile, 'utf8')) as BrowserMetricsReport; const head = JSON.parse(await readFile(headFile, 'utf8')) as BrowserMetricsReport; - await writeFile(outputFile, renderFrontendBrowserReport(base, head, { + await writeFile(outputFile, renderMd(base, head, { headHeapSnapshotUrl: process.env.FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL, detailedHtmlUrl: process.env.FRONTEND_BROWSER_DETAILED_HTML_ARTIFACT_URL, })); From fd83c9cb641e5bf82468b3f33fffda99d4562216 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:25:32 +0900 Subject: [PATCH 380/578] enhance(gh): tweak frontend-browser-diagnostics --- .../frontend-browser-diagnostics.inspect.mts | 35 ++++++++++--------- ...frontend-browser-diagnostics.render-md.mts | 11 +++--- .../frontend-browser-diagnostics.inspect.yml | 16 +++++++-- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/.github/scripts/frontend-browser-diagnostics.inspect.mts b/.github/scripts/frontend-browser-diagnostics.inspect.mts index 545149df24c..ec0e08857d8 100644 --- a/.github/scripts/frontend-browser-diagnostics.inspect.mts +++ b/.github/scripts/frontend-browser-diagnostics.inspect.mts @@ -11,12 +11,15 @@ import { HeadlessChromeController, summarizeBrowserDiagnostics, summarizeNetwork import type { BrowserMeasurement, NetworkRequest, NetworkSummary } from './chrome.mts'; import { closeUserSetupDialog, postNote, signupThroughUi, visitHome } from '../../packages/frontend/test/e2e/shared.ts'; -const [baseDirArg, headDirArg, baseOutputArg, headOutputArg, headHeapSnapshotOutputArg] = process.argv.slice(2); +const [baseDirArg, headDirArg, baseOutputArg, headOutputArg, baseHeapSnapshotOutputArg, headHeapSnapshotOutputArg] = process.argv.slice(2); const baseUrl = process.env.FRONTEND_BROWSER_METRICS_URL ?? 'http://127.0.0.1:61812'; const sampleCount = util.readIntegerEnv('FRONTEND_BROWSER_METRICS_SAMPLE_COUNT', 5, 1); const heapSnapshotBreakdownTopN = util.readIntegerEnv('FRONTEND_BROWSER_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', heapSnapshotUtil.defaultHeapSnapshotBreakdownTopN, 1); -const headHeapSnapshotWorkDir = resolve('frontend-browser-head-heap-snapshots'); +const heapSnapshotWorkDirs = { + base: resolve('frontend-browser-base-heap-snapshots'), + head: resolve('frontend-browser-head-heap-snapshots'), +} as const; type BrowserMeasurementSample = BrowserMeasurement & { round: number; @@ -223,28 +226,26 @@ async function measureSample(label: 'base' | 'head', round: number, heapSnapshot }); } -function headHeapSnapshotPath(round: number) { - return join(headHeapSnapshotWorkDir, `round-${round}.heapsnapshot`); +function heapSnapshotPath(label: 'base' | 'head', round: number) { + return join(heapSnapshotWorkDirs[label], `round-${round}.heapsnapshot`); } -async function saveRepresentativeHeadHeapSnapshot(report: BrowserMetricsReport, outputPath: string) { +async function saveRepresentativeHeapSnapshot(label: 'base' | 'head', report: BrowserMetricsReport, outputPath: string) { const representative = selectRepresentativeSample(report.samples, sample => sample.heapSnapshot.categories.total); - await copyFile(headHeapSnapshotPath(representative.round), outputPath); - process.stderr.write(`[head] Selected round ${representative.round} heap snapshot for artifact\n`); - await rm(headHeapSnapshotWorkDir, { recursive: true, force: true }); + await copyFile(heapSnapshotPath(label, representative.round), outputPath); + process.stderr.write(`[${label}] Selected round ${representative.round} heap snapshot for artifact\n`); + await rm(heapSnapshotWorkDirs[label], { recursive: true, force: true }); } -async function genReport(label: 'base' | 'head', repoDir: string, outputPath: string, heapSnapshotSavePath?: string) { +async function genReport(label: 'base' | 'head', repoDir: string, outputPath: string, heapSnapshotSavePath: string) { let server: ReturnType | null = null; try { server = util.startServer(label, repoDir); await util.waitForServer(baseUrl, server!); - if (label === 'head' && heapSnapshotSavePath != null) { - await rm(headHeapSnapshotWorkDir, { recursive: true, force: true }); - await mkdir(headHeapSnapshotWorkDir, { recursive: true }); - } + await rm(heapSnapshotWorkDirs[label], { recursive: true, force: true }); + await mkdir(heapSnapshotWorkDirs[label], { recursive: true }); const samples: BrowserMeasurementSample[] = []; for (let round = 1; round <= sampleCount; round++) { @@ -252,7 +253,7 @@ async function genReport(label: 'base' | 'head', repoDir: string, outputPath: st samples.push(await measureSample( label, round, - label === 'head' && heapSnapshotSavePath != null ? headHeapSnapshotPath(round) : undefined, + heapSnapshotPath(label, round), )); } @@ -260,8 +261,8 @@ async function genReport(label: 'base' | 'head', repoDir: string, outputPath: st await writeFile(outputPath, JSON.stringify(report, null, '\t')); process.stderr.write(`[${label}] Wrote browser metrics report to ${outputPath}\n`); - if (label === 'head' && heapSnapshotSavePath != null) { - await saveRepresentativeHeadHeapSnapshot(report, heapSnapshotSavePath); + if (heapSnapshotSavePath != null) { + await saveRepresentativeHeapSnapshot(label, report, heapSnapshotSavePath); } } finally { if (server != null) await util.stopServer(server); @@ -269,7 +270,7 @@ async function genReport(label: 'base' | 'head', repoDir: string, outputPath: st } async function main() { - await genReport('base', resolve(baseDirArg), resolve(baseOutputArg)); + await genReport('base', resolve(baseDirArg), resolve(baseOutputArg), resolve(baseHeapSnapshotOutputArg)); await genReport('head', resolve(headDirArg), resolve(headOutputArg), resolve(headHeapSnapshotOutputArg)); } diff --git a/.github/scripts/frontend-browser-diagnostics.render-md.mts b/.github/scripts/frontend-browser-diagnostics.render-md.mts index c18ef63f464..f0890e65eff 100644 --- a/.github/scripts/frontend-browser-diagnostics.render-md.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-md.mts @@ -314,10 +314,10 @@ function toHeapSnapshotReport(report: BrowserMetricsReport): HeapSnapshotReport } function renderMd(base: BrowserMetricsReport, head: BrowserMetricsReport, options: { - headHeapSnapshotUrl?: string; + baseHeapSnapshotUrl: string; + headHeapSnapshotUrl: string; detailedHtmlUrl?: string; -} = {}) { - const headHeapSnapshotUrl = options.headHeapSnapshotUrl; +}) { const detailedHtmlUrl = options.detailedHtmlUrl; const heapSnapshotTable = heapSnapshotUtil.renderHeapSnapshotTable(toHeapSnapshotReport(base), toHeapSnapshotReport(head)); const lines = [ @@ -343,7 +343,7 @@ function renderMd(base: BrowserMetricsReport, head: BrowserMetricsReport, option '', heapSnapshotUtil.renderHeapSnapshotSankey(toHeapSnapshotReport(head), 'Head'), '', - `[Download representative head heap snapshot](${headHeapSnapshotUrl})`, + `Download representative heap snapshot: [base](${options.baseHeapSnapshotUrl}) / [head](${options.headHeapSnapshotUrl})`, '
', '', ]; @@ -366,7 +366,8 @@ async function main() { const base = JSON.parse(await readFile(baseFile, 'utf8')) as BrowserMetricsReport; const head = JSON.parse(await readFile(headFile, 'utf8')) as BrowserMetricsReport; await writeFile(outputFile, renderMd(base, head, { - headHeapSnapshotUrl: process.env.FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL, + baseHeapSnapshotUrl: process.env.FRONTEND_BROWSER_BASE_HEAP_SNAPSHOT_ARTIFACT_URL!, + headHeapSnapshotUrl: process.env.FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL!, detailedHtmlUrl: process.env.FRONTEND_BROWSER_DETAILED_HTML_ARTIFACT_URL, })); } diff --git a/.github/workflows/frontend-browser-diagnostics.inspect.yml b/.github/workflows/frontend-browser-diagnostics.inspect.yml index 444c54040ba..76af11bec62 100644 --- a/.github/workflows/frontend-browser-diagnostics.inspect.yml +++ b/.github/workflows/frontend-browser-diagnostics.inspect.yml @@ -127,14 +127,23 @@ jobs: run: | REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" mkdir -p "$REPORT_DIR" - node after/.github/scripts/frontend-browser-diagnostics.inspect.mts before after "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/head-heap-snapshot.heapsnapshot" + node after/.github/scripts/frontend-browser-diagnostics.inspect.mts before after "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/base-heap-snapshot.heapsnapshot" "$REPORT_DIR/head-heap-snapshot.heapsnapshot" + + - name: Upload browser base heap snapshot + id: upload-browser-base-heap-snapshot + uses: actions/upload-artifact@v7 + with: + path: base-heap-snapshot.heapsnapshot + archive: false + if-no-files-found: error + retention-days: 7 - name: Upload browser head heap snapshot id: upload-browser-head-heap-snapshot uses: actions/upload-artifact@v7 with: - name: frontend-browser-metrics-head-heap-snapshot - path: ${{ runner.temp }}/frontend-browser-diagnostics/head-heap-snapshot.heapsnapshot + path: head-heap-snapshot.heapsnapshot + archive: false if-no-files-found: error retention-days: 7 @@ -162,6 +171,7 @@ jobs: BASE_SHA: ${{ github.event.pull_request.base.sha }} HEAD_SHA: ${{ github.event.pull_request.head.sha }} PR_NUMBER: ${{ github.event.pull_request.number }} + FRONTEND_BROWSER_BASE_HEAP_SNAPSHOT_ARTIFACT_URL: ${{ steps.upload-browser-base-heap-snapshot.outputs.artifact-url }} FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL: ${{ steps.upload-browser-head-heap-snapshot.outputs.artifact-url }} FRONTEND_BROWSER_DETAILED_HTML_ARTIFACT_URL: ${{ steps.upload-browser-detailed-html.outputs.artifact-url }} run: | From 153875e1d96a472e05277dbba77c654d21d022f0 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:28:05 +0900 Subject: [PATCH 381/578] [skip ci] refacotr(gh): add note --- .../frontend-browser-diagnostics.render-additional-html.mts | 1 + .github/scripts/frontend-browser-diagnostics.render-md.mts | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/scripts/frontend-browser-diagnostics.render-additional-html.mts b/.github/scripts/frontend-browser-diagnostics.render-additional-html.mts index 86f70e7ebd6..568f4257e2b 100644 --- a/.github/scripts/frontend-browser-diagnostics.render-additional-html.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-additional-html.mts @@ -440,6 +440,7 @@ async function main() { await writeFile(outputFile, renderHtml(base, head)); } +// 直接実行�れ�����呼����判定(テスト�����ファイル内�関数をimport�る�����用) if (process.argv[1] != null && import.meta.url === pathToFileURL(process.argv[1]).href) { await main(); } diff --git a/.github/scripts/frontend-browser-diagnostics.render-md.mts b/.github/scripts/frontend-browser-diagnostics.render-md.mts index f0890e65eff..76ff29b9118 100644 --- a/.github/scripts/frontend-browser-diagnostics.render-md.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-md.mts @@ -372,6 +372,7 @@ async function main() { })); } +// 直接実行�れ�����呼����判定(テスト�����ファイル内�関数をimport�る�����用) if (process.argv[1] != null && import.meta.url === pathToFileURL(process.argv[1]).href) { await main(); } From 8aff44ae2e23f34fabc627dfed4658c03df21bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:37:07 +0900 Subject: [PATCH 382/578] =?UTF-8?q?refactor(misskey-js):=20=E3=83=A2?= =?UTF-8?q?=E3=83=87=E3=83=AC=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=83=AD?= =?UTF-8?q?=E3=82=B0=E3=81=AE=E5=9E=8B=E3=82=92=E6=89=8B=E5=8B=95=E3=81=A7?= =?UTF-8?q?=E6=9B=B8=E3=81=8B=E3=81=9A=E3=81=AB=E3=81=99=E3=82=80=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=20(#17729)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(misskey-js): モデレーションログ�型を手動�書����むよ�� * fix lint --- packages/misskey-js/etc/misskey-js.api.md | 167 +--------------------- packages/misskey-js/src/entities.ts | 164 +-------------------- 2 files changed, 12 insertions(+), 319 deletions(-) diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index a2effe339ae..634ee1f02c2 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2884,6 +2884,8 @@ type MiauthGenTokenRequest = operations['miauth___gen-token']['requestBody']['co // @public (undocumented) type MiauthGenTokenResponse = operations['miauth___gen-token']['responses']['200']['content']['application/json']; +// Warning: (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts +// // @public (undocumented) type ModerationLog = { id: ID; @@ -2891,165 +2893,11 @@ type ModerationLog = { userId: User['id']; user: UserDetailedNotMe; } & ({ - type: 'updateServerSettings'; - info: ModerationLogPayloads['updateServerSettings']; -} | { - type: 'suspend'; - info: ModerationLogPayloads['suspend']; -} | { - type: 'unsuspend'; - info: ModerationLogPayloads['unsuspend']; -} | { - type: 'updateUserNote'; - info: ModerationLogPayloads['updateUserNote']; -} | { - type: 'addCustomEmoji'; - info: ModerationLogPayloads['addCustomEmoji']; -} | { - type: 'updateCustomEmoji'; - info: ModerationLogPayloads['updateCustomEmoji']; -} | { - type: 'deleteCustomEmoji'; - info: ModerationLogPayloads['deleteCustomEmoji']; -} | { - type: 'assignRole'; - info: ModerationLogPayloads['assignRole']; -} | { - type: 'unassignRole'; - info: ModerationLogPayloads['unassignRole']; -} | { - type: 'createRole'; - info: ModerationLogPayloads['createRole']; -} | { - type: 'updateRole'; - info: ModerationLogPayloads['updateRole']; -} | { - type: 'deleteRole'; - info: ModerationLogPayloads['deleteRole']; -} | { - type: 'clearQueue'; - info: ModerationLogPayloads['clearQueue']; -} | { - type: 'promoteQueue'; - info: ModerationLogPayloads['promoteQueue']; -} | { - type: 'deleteDriveFile'; - info: ModerationLogPayloads['deleteDriveFile']; -} | { - type: 'deleteNote'; - info: ModerationLogPayloads['deleteNote']; -} | { - type: 'createGlobalAnnouncement'; - info: ModerationLogPayloads['createGlobalAnnouncement']; -} | { - type: 'createUserAnnouncement'; - info: ModerationLogPayloads['createUserAnnouncement']; -} | { - type: 'updateGlobalAnnouncement'; - info: ModerationLogPayloads['updateGlobalAnnouncement']; -} | { - type: 'updateUserAnnouncement'; - info: ModerationLogPayloads['updateUserAnnouncement']; -} | { - type: 'deleteGlobalAnnouncement'; - info: ModerationLogPayloads['deleteGlobalAnnouncement']; -} | { - type: 'deleteUserAnnouncement'; - info: ModerationLogPayloads['deleteUserAnnouncement']; -} | { - type: 'resetPassword'; - info: ModerationLogPayloads['resetPassword']; -} | { - type: 'suspendRemoteInstance'; - info: ModerationLogPayloads['suspendRemoteInstance']; -} | { - type: 'unsuspendRemoteInstance'; - info: ModerationLogPayloads['unsuspendRemoteInstance']; -} | { - type: 'updateRemoteInstanceNote'; - info: ModerationLogPayloads['updateRemoteInstanceNote']; -} | { - type: 'markSensitiveDriveFile'; - info: ModerationLogPayloads['markSensitiveDriveFile']; -} | { - type: 'unmarkSensitiveDriveFile'; - info: ModerationLogPayloads['unmarkSensitiveDriveFile']; -} | { - type: 'createInvitation'; - info: ModerationLogPayloads['createInvitation']; -} | { - type: 'createAd'; - info: ModerationLogPayloads['createAd']; -} | { - type: 'updateAd'; - info: ModerationLogPayloads['updateAd']; -} | { - type: 'deleteAd'; - info: ModerationLogPayloads['deleteAd']; -} | { - type: 'createAvatarDecoration'; - info: ModerationLogPayloads['createAvatarDecoration']; -} | { - type: 'updateAvatarDecoration'; - info: ModerationLogPayloads['updateAvatarDecoration']; -} | { - type: 'deleteAvatarDecoration'; - info: ModerationLogPayloads['deleteAvatarDecoration']; -} | { - type: 'resolveAbuseReport'; - info: ModerationLogPayloads['resolveAbuseReport']; -} | { - type: 'forwardAbuseReport'; - info: ModerationLogPayloads['forwardAbuseReport']; -} | { - type: 'updateAbuseReportNote'; - info: ModerationLogPayloads['updateAbuseReportNote']; -} | { - type: 'unsetMfa'; - info: ModerationLogPayloads['unsetMfa']; -} | { - type: 'unsetUserAvatar'; - info: ModerationLogPayloads['unsetUserAvatar']; -} | { - type: 'unsetUserBanner'; - info: ModerationLogPayloads['unsetUserBanner']; -} | { - type: 'createSystemWebhook'; - info: ModerationLogPayloads['createSystemWebhook']; -} | { - type: 'updateSystemWebhook'; - info: ModerationLogPayloads['updateSystemWebhook']; -} | { - type: 'deleteSystemWebhook'; - info: ModerationLogPayloads['deleteSystemWebhook']; -} | { - type: 'createAbuseReportNotificationRecipient'; - info: ModerationLogPayloads['createAbuseReportNotificationRecipient']; -} | { - type: 'updateAbuseReportNotificationRecipient'; - info: ModerationLogPayloads['updateAbuseReportNotificationRecipient']; -} | { - type: 'deleteAbuseReportNotificationRecipient'; - info: ModerationLogPayloads['deleteAbuseReportNotificationRecipient']; -} | { - type: 'deleteAccount'; - info: ModerationLogPayloads['deleteAccount']; -} | { - type: 'deletePage'; - info: ModerationLogPayloads['deletePage']; -} | { - type: 'deleteFlash'; - info: ModerationLogPayloads['deleteFlash']; -} | { - type: 'deleteGalleryPost'; - info: ModerationLogPayloads['deleteGalleryPost']; -} | { - type: 'deleteChatRoom'; - info: ModerationLogPayloads['deleteChatRoom']; -} | { - type: 'updateProxyAccountDescription'; - info: ModerationLogPayloads['updateProxyAccountDescription']; -}); + [K in keyof ModerationLogPayloads]: { + type: K; + info: ModerationLogPayloads[K]; + }; +}[keyof ModerationLogPayloads]); // @public (undocumented) export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetMfa", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost", "deleteChatRoom", "updateProxyAccountDescription"]; @@ -3922,7 +3770,6 @@ type VerifyEmailRequest = operations['verify-email']['requestBody']['content'][' // Warnings were encountered during analysis: // -// src/entities.ts:60:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.ts:57:3 - (ae-forgotten-export) The symbol "ReconnectingWebSocket" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:226:4 - (ae-forgotten-export) The symbol "ReversiUpdateKey" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:241:4 - (ae-forgotten-export) The symbol "ReversiUpdateSettings" needs to be exported by the entry point index.d.ts diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 77cec5fe432..4fabe4f096d 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -56,165 +56,11 @@ export type ModerationLog = { userId: User['id']; user: UserDetailedNotMe; } & ({ - type: 'updateServerSettings'; - info: ModerationLogPayloads['updateServerSettings']; -} | { - type: 'suspend'; - info: ModerationLogPayloads['suspend']; -} | { - type: 'unsuspend'; - info: ModerationLogPayloads['unsuspend']; -} | { - type: 'updateUserNote'; - info: ModerationLogPayloads['updateUserNote']; -} | { - type: 'addCustomEmoji'; - info: ModerationLogPayloads['addCustomEmoji']; -} | { - type: 'updateCustomEmoji'; - info: ModerationLogPayloads['updateCustomEmoji']; -} | { - type: 'deleteCustomEmoji'; - info: ModerationLogPayloads['deleteCustomEmoji']; -} | { - type: 'assignRole'; - info: ModerationLogPayloads['assignRole']; -} | { - type: 'unassignRole'; - info: ModerationLogPayloads['unassignRole']; -} | { - type: 'createRole'; - info: ModerationLogPayloads['createRole']; -} | { - type: 'updateRole'; - info: ModerationLogPayloads['updateRole']; -} | { - type: 'deleteRole'; - info: ModerationLogPayloads['deleteRole']; -} | { - type: 'clearQueue'; - info: ModerationLogPayloads['clearQueue']; -} | { - type: 'promoteQueue'; - info: ModerationLogPayloads['promoteQueue']; -} | { - type: 'deleteDriveFile'; - info: ModerationLogPayloads['deleteDriveFile']; -} | { - type: 'deleteNote'; - info: ModerationLogPayloads['deleteNote']; -} | { - type: 'createGlobalAnnouncement'; - info: ModerationLogPayloads['createGlobalAnnouncement']; -} | { - type: 'createUserAnnouncement'; - info: ModerationLogPayloads['createUserAnnouncement']; -} | { - type: 'updateGlobalAnnouncement'; - info: ModerationLogPayloads['updateGlobalAnnouncement']; -} | { - type: 'updateUserAnnouncement'; - info: ModerationLogPayloads['updateUserAnnouncement']; -} | { - type: 'deleteGlobalAnnouncement'; - info: ModerationLogPayloads['deleteGlobalAnnouncement']; -} | { - type: 'deleteUserAnnouncement'; - info: ModerationLogPayloads['deleteUserAnnouncement']; -} | { - type: 'resetPassword'; - info: ModerationLogPayloads['resetPassword']; -} | { - type: 'suspendRemoteInstance'; - info: ModerationLogPayloads['suspendRemoteInstance']; -} | { - type: 'unsuspendRemoteInstance'; - info: ModerationLogPayloads['unsuspendRemoteInstance']; -} | { - type: 'updateRemoteInstanceNote'; - info: ModerationLogPayloads['updateRemoteInstanceNote']; -} | { - type: 'markSensitiveDriveFile'; - info: ModerationLogPayloads['markSensitiveDriveFile']; -} | { - type: 'unmarkSensitiveDriveFile'; - info: ModerationLogPayloads['unmarkSensitiveDriveFile']; -} | { - type: 'createInvitation'; - info: ModerationLogPayloads['createInvitation']; -} | { - type: 'createAd'; - info: ModerationLogPayloads['createAd']; -} | { - type: 'updateAd'; - info: ModerationLogPayloads['updateAd']; -} | { - type: 'deleteAd'; - info: ModerationLogPayloads['deleteAd']; -} | { - type: 'createAvatarDecoration'; - info: ModerationLogPayloads['createAvatarDecoration']; -} | { - type: 'updateAvatarDecoration'; - info: ModerationLogPayloads['updateAvatarDecoration']; -} | { - type: 'deleteAvatarDecoration'; - info: ModerationLogPayloads['deleteAvatarDecoration']; -} | { - type: 'resolveAbuseReport'; - info: ModerationLogPayloads['resolveAbuseReport']; -} | { - type: 'forwardAbuseReport'; - info: ModerationLogPayloads['forwardAbuseReport']; -} | { - type: 'updateAbuseReportNote'; - info: ModerationLogPayloads['updateAbuseReportNote']; -} | { - type: 'unsetMfa'; - info: ModerationLogPayloads['unsetMfa']; -} | { - type: 'unsetUserAvatar'; - info: ModerationLogPayloads['unsetUserAvatar']; -} | { - type: 'unsetUserBanner'; - info: ModerationLogPayloads['unsetUserBanner']; -} | { - type: 'createSystemWebhook'; - info: ModerationLogPayloads['createSystemWebhook']; -} | { - type: 'updateSystemWebhook'; - info: ModerationLogPayloads['updateSystemWebhook']; -} | { - type: 'deleteSystemWebhook'; - info: ModerationLogPayloads['deleteSystemWebhook']; -} | { - type: 'createAbuseReportNotificationRecipient'; - info: ModerationLogPayloads['createAbuseReportNotificationRecipient']; -} | { - type: 'updateAbuseReportNotificationRecipient'; - info: ModerationLogPayloads['updateAbuseReportNotificationRecipient']; -} | { - type: 'deleteAbuseReportNotificationRecipient'; - info: ModerationLogPayloads['deleteAbuseReportNotificationRecipient']; -} | { - type: 'deleteAccount'; - info: ModerationLogPayloads['deleteAccount']; -} | { - type: 'deletePage'; - info: ModerationLogPayloads['deletePage']; -} | { - type: 'deleteFlash'; - info: ModerationLogPayloads['deleteFlash']; -} | { - type: 'deleteGalleryPost'; - info: ModerationLogPayloads['deleteGalleryPost']; -} | { - type: 'deleteChatRoom'; - info: ModerationLogPayloads['deleteChatRoom']; -} | { - type: 'updateProxyAccountDescription'; - info: ModerationLogPayloads['updateProxyAccountDescription']; -}); + [K in keyof ModerationLogPayloads]: { + type: K; + info: ModerationLogPayloads[K]; + }; +}[keyof ModerationLogPayloads]); export type ServerStats = { cpu: number; From 2874a6d5ba903fb752ca7c1dad98c81964aff95e Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:44:55 +0900 Subject: [PATCH 383/578] refacotr(gh): refactor --- ...frontend-bundle-diagnostics.render-md.mts} | 2 +- .github/scripts/frontend-js-size.test.mts | 252 -------------- ...> frontend-bundle-diagnostics.inspect.yml} | 16 +- .../frontend-bundle-diagnostics.report.yml | 179 ++++++++++ .../frontend-bundle-report-comment.yml | 318 ------------------ .github/workflows/lint.yml | 16 - 6 files changed, 188 insertions(+), 595 deletions(-) rename .github/scripts/{frontend-js-size.mts => frontend-bundle-diagnostics.render-md.mts} (99%) delete mode 100644 .github/scripts/frontend-js-size.test.mts rename .github/workflows/{frontend-bundle-report.yml => frontend-bundle-diagnostics.inspect.yml} (89%) create mode 100644 .github/workflows/frontend-bundle-diagnostics.report.yml delete mode 100644 .github/workflows/frontend-bundle-report-comment.yml diff --git a/.github/scripts/frontend-js-size.mts b/.github/scripts/frontend-bundle-diagnostics.render-md.mts similarity index 99% rename from .github/scripts/frontend-js-size.mts rename to .github/scripts/frontend-bundle-diagnostics.render-md.mts index db134bab791..7ec0cfc61d6 100644 --- a/.github/scripts/frontend-js-size.mts +++ b/.github/scripts/frontend-bundle-diagnostics.render-md.mts @@ -7,7 +7,7 @@ import { promises as fs } from 'node:fs'; import path from 'node:path'; import * as util from './utility.mts'; -const marker = ''; +const marker = ''; const locale = process.env.FRONTEND_JS_SIZE_LOCALE ?? 'ja-JP'; diff --git a/.github/scripts/frontend-js-size.test.mts b/.github/scripts/frontend-js-size.test.mts deleted file mode 100644 index d3b3db9af66..00000000000 --- a/.github/scripts/frontend-js-size.test.mts +++ /dev/null @@ -1,252 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import assert from 'node:assert/strict'; -import { execFile } from 'node:child_process'; -import { promises as fs } from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import test, { type TestContext } from 'node:test'; -import * as util from './utility.mts'; - -type Manifest = Record; - -const repoDir = path.resolve(import.meta.dirname, '../..'); -const reportScript = path.join(repoDir, '.github/scripts/frontend-js-size.mts'); - -async function writeBuild(repo: string, manifest: Manifest, sizes: Record) { - const outDir = path.join(repo, 'built/_frontend_vite_/'); - await fs.mkdir(path.join(outDir, 'ja-JP'), { recursive: true }); - await fs.writeFile(path.join(outDir, 'manifest.json'), JSON.stringify(manifest)); - for (const [file, size] of Object.entries(sizes)) { - const localizedFile = file.replace(/^scripts\//, ''); - const outputFile = path.join(outDir, 'ja-JP', localizedFile); - await fs.mkdir(path.dirname(outputFile), { recursive: true }); - await fs.writeFile(outputFile, Buffer.alloc(size)); - } -} - -async function runReport(t: TestContext, before: { manifest: Manifest; sizes: Record }, after: { manifest: Manifest; sizes: Record }, expectFailure = false) { - const root = await fs.mkdtemp(path.join(os.tmpdir(), 'frontend-js-size-')); - t.after(() => fs.rm(root, { recursive: true, force: true })); - const beforeDir = path.join(root, 'before'); - const afterDir = path.join(root, 'after'); - const beforeStats = path.join(root, 'before-stats.json'); - const afterStats = path.join(root, 'after-stats.json'); - const reportFile = path.join(root, 'report.md'); - await writeBuild(beforeDir, before.manifest, before.sizes); - await writeBuild(afterDir, after.manifest, after.sizes); - await fs.writeFile(beforeStats, '{}'); - await fs.writeFile(afterStats, '{}'); - const args = [reportScript, beforeDir, afterDir, beforeStats, afterStats, reportFile]; - if (expectFailure) { - return new Promise((resolve, reject) => { - execFile(process.execPath, args, (error, _stdout, stderr) => { - if (error == null) { - reject(new Error('Expected frontend report script to fail')); - } else { - resolve(stderr); - } - }); - }); - } - await util.run(process.execPath, args); - return fs.readFile(reportFile, 'utf8'); -} - -function fixture(suffix: string, generatedName: string, sizes: { entry: number; generatedA: number; generatedB: number; vue: number; i18n: number }) { - const files = { - entry: `scripts/entry-${suffix}.js`, - generatedA: `scripts/generated-a-${suffix}.js`, - generatedB: `scripts/generated-b-${suffix}.js`, - vue: `scripts/vue-${suffix}.js`, - i18n: `scripts/i18n-${suffix}.js`, - }; - return { - manifest: { - 'src/_boot_.ts': { file: files.entry, src: 'src/_boot_.ts', name: 'entry', isEntry: true, imports: ['_generatedA', '_generatedB', '_vue', '_i18n'] }, - _generatedA: { file: files.generatedA, name: generatedName }, - _generatedB: { file: files.generatedB, name: generatedName }, - _vue: { file: files.vue, name: 'vue' }, - _i18n: { file: files.i18n, name: 'i18n' }, - }, - sizes: Object.fromEntries(Object.entries(files).map(([key, file]) => [file, sizes[key as keyof typeof sizes]])), - }; -} - -test('groups generated chunks while preserving full and startup totals', async t => { - const report = await runReport( - t, - fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 55, i18n: 50 }), - ); - - assert.match(report, /\| \(total\) \| 220 B \| 285 B \|/); - assert.equal(report.match(/\| \(other generated chunks\) \| 30 B \| 70 B \|/g)?.length, 2); - assert.doesNotMatch(report, /generated chunks are grouped/); - assert.doesNotMatch(report, /`(?:dist|esm)`<\/summary>/); - assert.match(report, /`src\/_boot_\.ts`<\/summary>/); - assert.match(report, /`vue`<\/summary>/); -}); - -test('groups small deltas at the bottom while preserving all change counts', async t => { - const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - before.manifest._removedSmall = { file: 'scripts/removed-small-before.js', src: 'src/removed-small.ts' }; - before.manifest['src/_boot_.ts'].imports?.push('_removedSmall'); - before.sizes['scripts/removed-small-before.js'] = 5; - - const after = fixture('after', 'esm', { entry: 106, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }); - after.manifest._addedSmall = { file: 'scripts/added-small-after.js', src: 'src/added-small.ts' }; - after.manifest['src/_boot_.ts'].imports?.push('_addedSmall'); - after.sizes['scripts/added-small-after.js'] = 5; - - const report = await runReport(t, before, after); - - assert.match(report, /Chunk size diff \(2 updated, 1 added, 1 removed\)<\/summary>/); - assert.match(report, /Startup chunk size \(2 updated, 1 added, 1 removed\)<\/summary>/); - assert.equal(report.match(/`src\/_boot_\.ts`<\/summary>/g)?.length, 2); - assert.doesNotMatch(report, /`(?:vue|i18n|src\/added-small\.ts|src\/removed-small\.ts)`<\/summary>/); - assert.match(report, /\| \(total\) \| 225 B \| 276 B \|[^\n]*\n\| \| \| \| \| \|\n\|
`src\/_boot_\.ts`<\/summary>[^\n]*\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 45 B \| 50 B \|/); - assert.match(report, /\| \(total\) \| 225 B \| 276 B \|[^\n]*\n\| \| \| \| \| \|\n\|
`src\/_boot_\.ts`<\/summary>[^\n]*\n\| \(other generated chunks\) \| 30 B \| 70 B \|[^\n]*\n\| \(other\) \| 95 B \| 100 B \|/); -}); - -test('fails instead of overwriting duplicate stable chunk keys', async t => { - const duplicateVue = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - duplicateVue.manifest._vueDuplicate = { file: 'scripts/vue-duplicate-before.js', name: 'vue' }; - duplicateVue.sizes['scripts/vue-duplicate-before.js'] = 60; - - const diagnostic = await runReport( - t, - duplicateVue, - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), - true, - ); - assert.match(diagnostic, /Duplicate stable chunk key "named:vue".*vue-before\.js.*vue-duplicate-before\.js/); -}); - -test('shows both filenames for an updated stable chunk', async t => { - const report = await runReport( - t, - fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 55, i18n: 50 }), - ); - - assert.match(report, /`ja-JP\/entry-before\.js → ja-JP\/entry-after\.js`/); - assert.match(report, /`ja-JP\/vue-before\.js → ja-JP\/vue-after\.js`/); -}); - -test('fails descriptively when the startup entry is missing', async t => { - const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - delete before.manifest['src/_boot_.ts']; - delete before.sizes['scripts/entry-before.js']; - - const diagnostic = await runReport( - t, - before, - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), - true, - ); - assert.match(diagnostic, /Unable to find frontend startup entry in Vite manifest/); -}); - -test('fails descriptively when a static import is missing from the manifest', async t => { - const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - before.manifest['src/_boot_.ts'].imports = ['_missing']; - - const diagnostic = await runReport( - t, - before, - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), - true, - ); - assert.match(diagnostic, /Startup manifest key "_missing".*is missing/); -}); - -test('fails descriptively when a static import has no output file', async t => { - const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - before.manifest['src/_boot_.ts'].imports = ['_malformed']; - before.manifest._malformed = { name: 'malformed' }; - - const diagnostic = await runReport( - t, - before, - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), - true, - ); - assert.match(diagnostic, /Startup manifest key "_malformed".*has no output file/); -}); - -test('fails descriptively when a static import resolves to a non-JavaScript output', async t => { - const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - before.manifest['src/_boot_.ts'].imports = ['_malformed']; - before.manifest._malformed = { file: 'assets/malformed.css', name: 'malformed' }; - - const diagnostic = await runReport( - t, - before, - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), - true, - ); - assert.match(diagnostic, /Startup manifest key "_malformed".*non-JavaScript output "assets\/malformed\.css"/); -}); - -test('keeps source-backed additions and removals as individual rows', async t => { - const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - before.manifest._removed = { file: 'scripts/removed-before.js', src: 'src/removed.ts' }; - before.sizes['scripts/removed-before.js'] = 12; - const after = fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }); - after.manifest._added = { file: 'scripts/added-after.js', src: 'src/added.ts' }; - after.sizes['scripts/added-after.js'] = 13; - - const report = await runReport(t, before, after); - - assert.match(report, /`src\/added\.ts`<\/summary> `ja-JP\/added-after\.js` <\/details> \| 0 B \| 13 B \|/); - assert.match(report, /`src\/removed\.ts`<\/summary> `ja-JP\/removed-before\.js` <\/details> \| 12 B \| 0 B \|/); -}); - -test('counts an unmanifested localized JavaScript file in totals and the generated aggregate', async t => { - const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - before.sizes['scripts/unmanifested-before.js'] = 15; - - const report = await runReport( - t, - before, - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), - ); - - assert.match(report, /\| \(total\) \| 235 B \| 275 B \|/); - assert.match(report, /\| \(other generated chunks\) \| 45 B \| 70 B \|/); -}); - -test('counts duplicate manifest entries for one physical output only once', async t => { - const before = fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }); - before.manifest._generatedAlias = { file: 'scripts/generated-a-before.js', name: 'dist' }; - - const report = await runReport( - t, - before, - fixture('after', 'esm', { entry: 110, generatedA: 30, generatedB: 40, vue: 45, i18n: 50 }), - ); - - assert.match(report, /\| \(total\) \| 220 B \| 275 B \|/); -}); - -test('does not count generated-aggregate-only changes as individual chunk changes', async t => { - const report = await runReport( - t, - fixture('before', 'dist', { entry: 100, generatedA: 10, generatedB: 20, vue: 40, i18n: 50 }), - fixture('after', 'esm', { entry: 100, generatedA: 30, generatedB: 40, vue: 40, i18n: 50 }), - ); - - assert.match(report, /Chunk size diff \(0 updated, 0 added, 0 removed\)<\/summary>/); - assert.match(report, /Startup chunk size \(0 updated, 0 added, 0 removed\)<\/summary>/); - assert.equal(report.match(/\| \(other generated chunks\) \| 30 B \| 70 B \|/g)?.length, 2); -}); diff --git a/.github/workflows/frontend-bundle-report.yml b/.github/workflows/frontend-bundle-diagnostics.inspect.yml similarity index 89% rename from .github/workflows/frontend-bundle-report.yml rename to .github/workflows/frontend-bundle-diagnostics.inspect.yml index b5af3bb0e19..31faaed79bc 100644 --- a/.github/workflows/frontend-bundle-report.yml +++ b/.github/workflows/frontend-bundle-diagnostics.inspect.yml @@ -1,4 +1,4 @@ -name: frontend-bundle-report +name: Frontend bundle diagnostics (inspect) on: pull_request: @@ -21,16 +21,16 @@ on: - pnpm-workspace.yaml - .node-version - .github/scripts/utility.mts - - .github/scripts/frontend-js-size.mts - - .github/workflows/frontend-bundle-report.yml - - .github/workflows/frontend-bundle-report-comment.yml + - .github/scripts/frontend-bundle-diagnostics.render-md.mts + - .github/workflows/frontend-bundle-diagnostics.inspect.yml + - .github/workflows/frontend-bundle-diagnostics.report.yml permissions: contents: read pull-requests: read concurrency: - group: frontend-bundle-report-${{ github.event.pull_request.number }} + group: frontend-bundle-diagnostics-inspect-${{ github.event.pull_request.number }} cancel-in-progress: true jobs: @@ -145,7 +145,7 @@ jobs: FRONTEND_BUNDLE_REPORT_ARTIFACT_URL: ${{ steps.upload-bundle-visualizer.outputs.artifact-url }} run: | REPORT_DIR="$RUNNER_TEMP/frontend-bundle-report" - node after/.github/scripts/frontend-js-size.mts before after "$REPORT_DIR/before-stats.json" "$REPORT_DIR/after-stats.json" "$REPORT_DIR/frontend-js-size-report.md" + node after/.github/scripts/frontend-bundle-diagnostics.render-md.mts before after "$REPORT_DIR/before-stats.json" "$REPORT_DIR/after-stats.json" "$REPORT_DIR/frontend-bundle-diagnostics-report.md" printf '%s\n' "$PR_NUMBER" > "$REPORT_DIR/pr-number.txt" printf '%s\n' "$BASE_SHA" > "$REPORT_DIR/base-sha.txt" printf '%s\n' "$HEAD_SHA" > "$REPORT_DIR/head-sha.txt" @@ -157,8 +157,8 @@ jobs: REPORT_DIR="$RUNNER_TEMP/frontend-bundle-report" test -s "$REPORT_DIR/before-stats.json" test -s "$REPORT_DIR/after-stats.json" - test -s "$REPORT_DIR/frontend-js-size-report.md" - cat "$REPORT_DIR/frontend-js-size-report.md" >> "$GITHUB_STEP_SUMMARY" + test -s "$REPORT_DIR/frontend-bundle-diagnostics-report.md" + cat "$REPORT_DIR/frontend-bundle-diagnostics-report.md" >> "$GITHUB_STEP_SUMMARY" - name: Upload bundle report if: steps.check-base-visualizer.outputs.supported == 'true' diff --git a/.github/workflows/frontend-bundle-diagnostics.report.yml b/.github/workflows/frontend-bundle-diagnostics.report.yml new file mode 100644 index 00000000000..260217ee535 --- /dev/null +++ b/.github/workflows/frontend-bundle-diagnostics.report.yml @@ -0,0 +1,179 @@ +name: frontend-bundle-report-comment + +on: + workflow_run: + workflows: + - frontend-bundle-report + types: + - completed + pull_request_target: + types: + - opened + - synchronize + - reopened + - ready_for_review + paths: + - packages/frontend/** + - packages/frontend-shared/** + - packages/frontend-builder/** + - packages/i18n/** + - packages/icons-subsetter/** + - packages/misskey-js/** + - packages/misskey-reversi/** + - packages/misskey-bubble-game/** + - package.json + - pnpm-lock.yaml + - pnpm-workspace.yaml + - .node-version + - .github/scripts/utility.mts + - .github/scripts/frontend-bundle-diagnostics.render-md.mts + - .github/workflows/frontend-bundle-diagnostics.inspect.yml + - .github/workflows/frontend-bundle-diagnostics.report.yml + +permissions: + actions: read + contents: read + issues: write + pull-requests: write + +jobs: + comment: + name: Comment frontend bundle report + if: github.event_name == 'pull_request_target' || (github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success') + runs-on: ubuntu-latest + concurrency: + group: frontend-bundle-diagnostics-report-${{ github.event.pull_request.number || github.event.workflow_run.id }} + cancel-in-progress: true + steps: + - name: Find bundle report run + if: github.event_name == 'pull_request_target' + id: find-report-run + uses: actions/github-script@v9 + with: + script: | + const workflow_id = 'frontend-bundle-report.yml'; + const artifactName = 'frontend-bundle-report'; + const headSha = context.payload.pull_request.head.sha; + const prNumber = context.payload.pull_request.number; + const pollIntervalMs = 30_000; + const timeoutMs = 90 * 60_000; + const startedAt = Date.now(); + const { owner, repo } = context.repo; + + async function listReportWorkflowRuns() { + const runsForHead = await github.paginate(github.rest.actions.listWorkflowRuns, { + owner, + repo, + workflow_id, + event: 'pull_request', + head_sha: headSha, + per_page: 100, + }); + + if (runsForHead.length > 0) { + return runsForHead; + } + + const recentRuns = await github.paginate(github.rest.actions.listWorkflowRuns, { + owner, + repo, + workflow_id, + event: 'pull_request', + per_page: 100, + }); + return recentRuns.filter((run) => + run.pull_requests?.some((pullRequest) => pullRequest.number === prNumber)); + } + + async function findReportRun() { + const runs = (await listReportWorkflowRuns()) + .sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at)); + + for (const run of runs) { + if (run.status !== 'completed') continue; + if (run.conclusion !== 'success') { + core.warning(`Frontend bundle report run ${run.id} completed with conclusion: ${run.conclusion}`); + return { done: true, run: null }; + } + + const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { + owner, + repo, + run_id: run.id, + per_page: 100, + }); + const report = artifacts.find((artifact) => artifact.name === artifactName && !artifact.expired); + if (report) return { done: true, run }; + + core.info(`Frontend bundle report run ${run.id} did not produce ${artifactName}.`); + return { done: true, run: null }; + } + + return { done: false, run: null }; + } + + while (Date.now() - startedAt < timeoutMs) { + const { done, run } = await findReportRun(); + if (run) { + core.info(`Found frontend bundle report on workflow run ${run.id}.`); + core.setOutput('run-id', String(run.id)); + return; + } + if (done) { + return; + } + + core.info('Waiting for frontend bundle report artifact...'); + await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); + } + + core.warning(`Timed out waiting for ${artifactName} from ${workflow_id} for ${headSha}.`); + + - name: Find bundle report artifact + if: github.event_name == 'workflow_run' + id: find-report-artifact + uses: actions/github-script@v9 + with: + script: | + const artifactName = 'frontend-bundle-report'; + const { owner, repo } = context.repo; + const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { + owner, + repo, + run_id: context.payload.workflow_run.id, + per_page: 100, + }); + const report = artifacts.find((artifact) => artifact.name === artifactName && !artifact.expired); + if (report) { + core.setOutput('exists', 'true'); + } else { + core.info(`Workflow run ${context.payload.workflow_run.id} did not produce ${artifactName}.`); + core.setOutput('exists', 'false'); + } + + - name: Download bundle report from workflow_run + if: github.event_name == 'workflow_run' && steps.find-report-artifact.outputs.exists == 'true' + uses: actions/download-artifact@v8 + with: + name: frontend-bundle-report + path: ${{ runner.temp }}/frontend-bundle-report + github-token: ${{ github.token }} + repository: ${{ github.repository }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Download bundle report from pull_request_target + if: github.event_name == 'pull_request_target' && steps.find-report-run.outputs.run-id != '' + uses: actions/download-artifact@v8 + with: + name: frontend-bundle-report + path: ${{ runner.temp }}/frontend-bundle-report + github-token: ${{ github.token }} + repository: ${{ github.repository }} + run-id: ${{ steps.find-report-run.outputs.run-id }} + + - name: Comment on pull request + uses: thollander/actions-comment-pull-request@v3 + with: + pr-number: ${{ steps.load-pr-number.outputs.pr-number }} + comment-tag: frontend_bundle_diagnostics + file-path: ${{ runner.temp }}/frontend-bundle-report/frontend-bundle-diagnostics-report.md diff --git a/.github/workflows/frontend-bundle-report-comment.yml b/.github/workflows/frontend-bundle-report-comment.yml deleted file mode 100644 index b93f8a320f6..00000000000 --- a/.github/workflows/frontend-bundle-report-comment.yml +++ /dev/null @@ -1,318 +0,0 @@ -name: frontend-bundle-report-comment - -on: - workflow_run: - workflows: - - frontend-bundle-report - types: - - completed - pull_request_target: - types: - - opened - - synchronize - - reopened - - ready_for_review - paths: - - packages/frontend/** - - packages/frontend-shared/** - - packages/frontend-builder/** - - packages/i18n/** - - packages/icons-subsetter/** - - packages/misskey-js/** - - packages/misskey-reversi/** - - packages/misskey-bubble-game/** - - package.json - - pnpm-lock.yaml - - pnpm-workspace.yaml - - .node-version - - .github/scripts/utility.mts - - .github/scripts/frontend-js-size.mts - - .github/workflows/frontend-bundle-report.yml - - .github/workflows/frontend-bundle-report-comment.yml - -permissions: - actions: read - contents: read - issues: write - pull-requests: write - -jobs: - comment: - name: Comment frontend bundle report - if: github.event_name == 'pull_request_target' || (github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success') - runs-on: ubuntu-latest - concurrency: - group: frontend-bundle-report-comment-${{ github.event.pull_request.number || github.event.workflow_run.id }} - cancel-in-progress: true - steps: - - name: Find bundle report run - if: github.event_name == 'pull_request_target' - id: find-report-run - uses: actions/github-script@v9 - with: - script: | - const workflow_id = 'frontend-bundle-report.yml'; - const artifactName = 'frontend-bundle-report'; - const headSha = context.payload.pull_request.head.sha; - const prNumber = context.payload.pull_request.number; - const pollIntervalMs = 30_000; - const timeoutMs = 90 * 60_000; - const startedAt = Date.now(); - const { owner, repo } = context.repo; - - async function listReportWorkflowRuns() { - const runsForHead = await github.paginate(github.rest.actions.listWorkflowRuns, { - owner, - repo, - workflow_id, - event: 'pull_request', - head_sha: headSha, - per_page: 100, - }); - - if (runsForHead.length > 0) { - return runsForHead; - } - - const recentRuns = await github.paginate(github.rest.actions.listWorkflowRuns, { - owner, - repo, - workflow_id, - event: 'pull_request', - per_page: 100, - }); - return recentRuns.filter((run) => - run.pull_requests?.some((pullRequest) => pullRequest.number === prNumber)); - } - - async function findReportRun() { - const runs = (await listReportWorkflowRuns()) - .sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at)); - - for (const run of runs) { - if (run.status !== 'completed') continue; - if (run.conclusion !== 'success') { - core.warning(`Frontend bundle report run ${run.id} completed with conclusion: ${run.conclusion}`); - return { done: true, run: null }; - } - - const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { - owner, - repo, - run_id: run.id, - per_page: 100, - }); - const report = artifacts.find((artifact) => artifact.name === artifactName && !artifact.expired); - if (report) return { done: true, run }; - - core.info(`Frontend bundle report run ${run.id} did not produce ${artifactName}.`); - return { done: true, run: null }; - } - - return { done: false, run: null }; - } - - while (Date.now() - startedAt < timeoutMs) { - const { done, run } = await findReportRun(); - if (run) { - core.info(`Found frontend bundle report on workflow run ${run.id}.`); - core.setOutput('run-id', String(run.id)); - return; - } - if (done) { - return; - } - - core.info('Waiting for frontend bundle report artifact...'); - await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); - } - - core.warning(`Timed out waiting for ${artifactName} from ${workflow_id} for ${headSha}.`); - - - name: Find bundle report artifact - if: github.event_name == 'workflow_run' - id: find-report-artifact - uses: actions/github-script@v9 - with: - script: | - const artifactName = 'frontend-bundle-report'; - const { owner, repo } = context.repo; - const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { - owner, - repo, - run_id: context.payload.workflow_run.id, - per_page: 100, - }); - const report = artifacts.find((artifact) => artifact.name === artifactName && !artifact.expired); - if (report) { - core.setOutput('exists', 'true'); - } else { - core.info(`Workflow run ${context.payload.workflow_run.id} did not produce ${artifactName}.`); - core.setOutput('exists', 'false'); - } - - - name: Download bundle report from workflow_run - if: github.event_name == 'workflow_run' && steps.find-report-artifact.outputs.exists == 'true' - uses: actions/download-artifact@v8 - with: - name: frontend-bundle-report - path: ${{ runner.temp }}/frontend-bundle-report - github-token: ${{ github.token }} - repository: ${{ github.repository }} - run-id: ${{ github.event.workflow_run.id }} - - - name: Download bundle report from pull_request_target - if: github.event_name == 'pull_request_target' && steps.find-report-run.outputs.run-id != '' - uses: actions/download-artifact@v8 - with: - name: frontend-bundle-report - path: ${{ runner.temp }}/frontend-bundle-report - github-token: ${{ github.token }} - repository: ${{ github.repository }} - run-id: ${{ steps.find-report-run.outputs.run-id }} - - - name: Comment on pull request - if: (github.event_name == 'workflow_run' && steps.find-report-artifact.outputs.exists == 'true') || steps.find-report-run.outputs.run-id != '' - uses: actions/github-script@v9 - with: - github-token: ${{ secrets.FRONTEND_BUNDLE_REPORT_COMMENT_TOKEN || secrets.FRONTEND_JS_SIZE_COMMENT_TOKEN || secrets.FRONTEND_BUNDLE_VISUALIZER_COMMENT_TOKEN || github.token }} - script: | - const fs = require('node:fs'); - const path = require('node:path'); - - const jsSizeMarker = ''; - const visualizerMarker = ''; - const reportMarkers = [jsSizeMarker, visualizerMarker]; - const reportDir = path.join(process.env.RUNNER_TEMP, 'frontend-bundle-report'); - const jsSizeReportPath = path.join(reportDir, 'frontend-js-size-report.md'); - const prNumberPath = path.join(reportDir, 'pr-number.txt'); - const headShaPath = path.join(reportDir, 'head-sha.txt'); - const workflowRun = context.payload.workflow_run; - const pullRequest = context.payload.pull_request; - const eventHeadSha = workflowRun?.head_sha ?? pullRequest?.head?.sha ?? null; - const { owner, repo } = context.repo; - - if (!fs.existsSync(jsSizeReportPath)) { - core.setFailed('The frontend bundle report artifact does not contain frontend-js-size-report.md.'); - return; - } - - const artifactHeadSha = fs.existsSync(headShaPath) - ? fs.readFileSync(headShaPath, 'utf8').trim() - : null; - if (eventHeadSha != null && artifactHeadSha != null && artifactHeadSha !== eventHeadSha) { - core.info(`The artifact head SHA (${artifactHeadSha}) differs from the event head SHA (${eventHeadSha}). Using artifact metadata for PR validation.`); - } - const reportHeadSha = artifactHeadSha ?? eventHeadSha; - - const artifactPrNumber = fs.existsSync(prNumberPath) - ? Number(fs.readFileSync(prNumberPath, 'utf8').trim()) - : null; - let issue_number = null; - if (pullRequest != null) { - issue_number = pullRequest.number; - if (Number.isInteger(artifactPrNumber) && artifactPrNumber !== issue_number) { - core.setFailed(`The artifact pull request number (${artifactPrNumber}) does not match the event pull request number (${issue_number}).`); - return; - } - } else if (workflowRun != null) { - const associatedPullRequests = new Map(); - for (const pullRequest of workflowRun.pull_requests ?? []) { - if (Number.isInteger(pullRequest.number)) { - associatedPullRequests.set(pullRequest.number, pullRequest); - } - } - - if (reportHeadSha != null) { - const pullRequestsForCommit = await github.paginate(github.rest.repos.listPullRequestsAssociatedWithCommit, { - owner, - repo, - commit_sha: reportHeadSha, - per_page: 100, - }); - for (const pullRequest of pullRequestsForCommit) { - associatedPullRequests.set(pullRequest.number, pullRequest); - } - } - - if (Number.isInteger(artifactPrNumber) && associatedPullRequests.has(artifactPrNumber)) { - issue_number = artifactPrNumber; - } else if (Number.isInteger(artifactPrNumber) && associatedPullRequests.size === 0) { - issue_number = artifactPrNumber; - } else if (!Number.isInteger(artifactPrNumber) && associatedPullRequests.size === 1) { - issue_number = [...associatedPullRequests.keys()][0]; - } else if (Number.isInteger(artifactPrNumber)) { - core.setFailed(`The artifact pull request number (${artifactPrNumber}) is not associated with ${reportHeadSha}.`); - return; - } else { - core.setFailed(`Could not determine the pull request associated with ${reportHeadSha}.`); - return; - } - } else { - core.setFailed('Could not determine the pull request event for this report.'); - return; - } - - const currentPullRequest = await github.rest.pulls.get({ - owner, - repo, - pull_number: issue_number, - }); - const currentHeadSha = currentPullRequest.data.head?.sha; - if (reportHeadSha != null && currentHeadSha != null && reportHeadSha !== currentHeadSha) { - core.info(`The report head SHA (${reportHeadSha}) is not the current pull request head SHA (${currentHeadSha}). Skipping stale frontend bundle report.`); - return; - } - - const jsSizeReport = fs.readFileSync(jsSizeReportPath, 'utf8').trim(); - if (!jsSizeReport.includes(jsSizeMarker)) { - core.setFailed('The frontend JS size report is missing the expected marker.'); - return; - } - let body = `${jsSizeReport}\n`; - - const maxCommentLength = 65_000; - if (body.length > maxCommentLength) { - const reportLocation = workflowRun?.html_url != null - ? `[workflow run](${workflowRun.html_url})` - : 'workflow artifact'; - const footer = [ - '', - '', - `_Report truncated because it exceeded ${maxCommentLength.toLocaleString('en-US')} characters. See the ${reportLocation} for the full report._`, - ].join('\n'); - body = `${body.slice(0, maxCommentLength - footer.length)}${footer}`; - } - - const comments = await github.paginate(github.rest.issues.listComments, { - owner, - repo, - issue_number, - per_page: 100, - }); - const previousReports = comments.filter((comment) => - comment.user?.type === 'Bot' && reportMarkers.some((reportMarker) => comment.body?.includes(reportMarker))); - - if (previousReports.length > 0) { - const [previous, ...duplicates] = previousReports; - await github.rest.issues.updateComment({ - owner, - repo, - comment_id: previous.id, - body, - }); - for (const duplicate of duplicates) { - await github.rest.issues.deleteComment({ - owner, - repo, - comment_id: duplicate.id, - }); - } - } else { - await github.rest.issues.createComment({ - owner, - repo, - issue_number, - body, - }); - } diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 63f8684c33e..63ae5c7397a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,9 +18,6 @@ on: - packages/misskey-reversi/** - packages/shared/eslint.config.js - scripts/check-dts*.mjs - - .github/scripts/frontend-js-size*.mts - - .github/scripts/memory-stability-util*.mts - - .github/scripts/utility.mts - .github/workflows/lint.yml - package.json pull_request: @@ -37,9 +34,6 @@ on: - packages/misskey-reversi/** - packages/shared/eslint.config.js - scripts/check-dts*.mjs - - .github/scripts/frontend-js-size*.mts - - .github/scripts/memory-stability-util*.mts - - .github/scripts/utility.mts - .github/workflows/lint.yml - package.json jobs: @@ -142,13 +136,3 @@ jobs: - run: pnpm i --frozen-lockfile - run: node --test scripts/check-dts.test.mjs - run: pnpm check-dts - - frontend-bundle-report-test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6.0.3 - - uses: actions/setup-node@v6.4.0 - with: - node-version-file: '.node-version' - - run: node --test .github/scripts/frontend-js-size.test.mts - - run: node --test .github/scripts/memory-stability-util.test.mts From 68193dd38c4ad77473055e26bc735b32337544fc Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:46:59 +0900 Subject: [PATCH 384/578] refacotr(gh): refactor --- .github/workflows/frontend-bundle-diagnostics.report.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/frontend-bundle-diagnostics.report.yml b/.github/workflows/frontend-bundle-diagnostics.report.yml index 260217ee535..be63dd45759 100644 --- a/.github/workflows/frontend-bundle-diagnostics.report.yml +++ b/.github/workflows/frontend-bundle-diagnostics.report.yml @@ -1,9 +1,9 @@ -name: frontend-bundle-report-comment +name: Frontend bundle diagnostics (report) on: workflow_run: workflows: - - frontend-bundle-report + - Frontend bundle diagnostics (inspect) types: - completed pull_request_target: From b028d4ad5bbe132446e03022e66deefd624aa93c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:53:36 +0900 Subject: [PATCH 385/578] refacotr(gh): rename some files --- ...diagnostics.report.yml => backend-diagnostics.comment.yml} | 2 +- .github/workflows/backend-diagnostics.inspect.yml | 4 ++-- ...cs.report.yml => frontend-browser-diagnostics.comment.yml} | 2 +- .github/workflows/frontend-browser-diagnostics.inspect.yml | 2 +- ...ics.report.yml => frontend-bundle-diagnostics.comment.yml} | 4 ++-- .github/workflows/frontend-bundle-diagnostics.inspect.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename .github/workflows/{backend-diagnostics.report.yml => backend-diagnostics.comment.yml} (98%) rename .github/workflows/{frontend-browser-diagnostics.report.yml => frontend-browser-diagnostics.comment.yml} (96%) rename .github/workflows/{frontend-bundle-diagnostics.report.yml => frontend-bundle-diagnostics.comment.yml} (98%) diff --git a/.github/workflows/backend-diagnostics.report.yml b/.github/workflows/backend-diagnostics.comment.yml similarity index 98% rename from .github/workflows/backend-diagnostics.report.yml rename to .github/workflows/backend-diagnostics.comment.yml index f358216a620..4aa7eef68d3 100644 --- a/.github/workflows/backend-diagnostics.report.yml +++ b/.github/workflows/backend-diagnostics.comment.yml @@ -1,4 +1,4 @@ -name: Backend diagnostics (report) +name: Backend diagnostics (comment) on: workflow_run: diff --git a/.github/workflows/backend-diagnostics.inspect.yml b/.github/workflows/backend-diagnostics.inspect.yml index 1474c78f0cd..d5a47b804f0 100644 --- a/.github/workflows/backend-diagnostics.inspect.yml +++ b/.github/workflows/backend-diagnostics.inspect.yml @@ -1,4 +1,4 @@ -# this name is used in backend-diagnostics.report.yml so be careful when change name +# this name is used in backend-diagnostics.comment.yml so be careful when change name name: Backend diagnostics (inspect) on: @@ -14,7 +14,7 @@ on: - .github/scripts/backend-diagnostics.inspect.mts - .github/scripts/memory-stability-util*.mts - .github/workflows/backend-diagnostics.inspect.yml - - .github/workflows/backend-diagnostics.report.yml + - .github/workflows/backend-diagnostics.comment.yml jobs: get-memory-usage: diff --git a/.github/workflows/frontend-browser-diagnostics.report.yml b/.github/workflows/frontend-browser-diagnostics.comment.yml similarity index 96% rename from .github/workflows/frontend-browser-diagnostics.report.yml rename to .github/workflows/frontend-browser-diagnostics.comment.yml index 7edc9f36c68..6b2f2b5a565 100644 --- a/.github/workflows/frontend-browser-diagnostics.report.yml +++ b/.github/workflows/frontend-browser-diagnostics.comment.yml @@ -1,4 +1,4 @@ -name: Frontend browser diagnostics (report) +name: Frontend browser diagnostics (comment) on: workflow_run: diff --git a/.github/workflows/frontend-browser-diagnostics.inspect.yml b/.github/workflows/frontend-browser-diagnostics.inspect.yml index 76af11bec62..63b43a05ae1 100644 --- a/.github/workflows/frontend-browser-diagnostics.inspect.yml +++ b/.github/workflows/frontend-browser-diagnostics.inspect.yml @@ -29,7 +29,7 @@ on: - .github/scripts/frontend-browser-diagnostics.render-md.mts - .github/scripts/frontend-browser-diagnostics.inspect.mts - .github/workflows/frontend-browser-diagnostics.inspect.yml - - .github/workflows/frontend-browser-diagnostics.report.yml + - .github/workflows/frontend-browser-diagnostics.comment.yml permissions: contents: read diff --git a/.github/workflows/frontend-bundle-diagnostics.report.yml b/.github/workflows/frontend-bundle-diagnostics.comment.yml similarity index 98% rename from .github/workflows/frontend-bundle-diagnostics.report.yml rename to .github/workflows/frontend-bundle-diagnostics.comment.yml index be63dd45759..ecc6f1dcfae 100644 --- a/.github/workflows/frontend-bundle-diagnostics.report.yml +++ b/.github/workflows/frontend-bundle-diagnostics.comment.yml @@ -1,4 +1,4 @@ -name: Frontend bundle diagnostics (report) +name: Frontend bundle diagnostics (comment) on: workflow_run: @@ -28,7 +28,7 @@ on: - .github/scripts/utility.mts - .github/scripts/frontend-bundle-diagnostics.render-md.mts - .github/workflows/frontend-bundle-diagnostics.inspect.yml - - .github/workflows/frontend-bundle-diagnostics.report.yml + - .github/workflows/frontend-bundle-diagnostics.comment.yml permissions: actions: read diff --git a/.github/workflows/frontend-bundle-diagnostics.inspect.yml b/.github/workflows/frontend-bundle-diagnostics.inspect.yml index 31faaed79bc..3572f77ea85 100644 --- a/.github/workflows/frontend-bundle-diagnostics.inspect.yml +++ b/.github/workflows/frontend-bundle-diagnostics.inspect.yml @@ -23,7 +23,7 @@ on: - .github/scripts/utility.mts - .github/scripts/frontend-bundle-diagnostics.render-md.mts - .github/workflows/frontend-bundle-diagnostics.inspect.yml - - .github/workflows/frontend-bundle-diagnostics.report.yml + - .github/workflows/frontend-bundle-diagnostics.comment.yml permissions: contents: read From ceb31f16c842646bdaedcee0e5a2648663c54971 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:58:01 +0900 Subject: [PATCH 386/578] refacotr(gh): refactor --- .github/workflows/frontend-browser-diagnostics.comment.yml | 2 +- .github/workflows/frontend-bundle-diagnostics.comment.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/frontend-browser-diagnostics.comment.yml b/.github/workflows/frontend-browser-diagnostics.comment.yml index 6b2f2b5a565..5098e618adc 100644 --- a/.github/workflows/frontend-browser-diagnostics.comment.yml +++ b/.github/workflows/frontend-browser-diagnostics.comment.yml @@ -40,5 +40,5 @@ jobs: uses: thollander/actions-comment-pull-request@v3 with: pr-number: ${{ steps.load-pr-number.outputs.pr-number }} - comment-tag: frontend_browser_diagnostics + comment-tag: frontend-browser-diagnostics file-path: ${{ runner.temp }}/frontend-browser-diagnostics/frontend-browser-diagnostics.md diff --git a/.github/workflows/frontend-bundle-diagnostics.comment.yml b/.github/workflows/frontend-bundle-diagnostics.comment.yml index ecc6f1dcfae..3da6d0dcbc0 100644 --- a/.github/workflows/frontend-bundle-diagnostics.comment.yml +++ b/.github/workflows/frontend-bundle-diagnostics.comment.yml @@ -175,5 +175,5 @@ jobs: uses: thollander/actions-comment-pull-request@v3 with: pr-number: ${{ steps.load-pr-number.outputs.pr-number }} - comment-tag: frontend_bundle_diagnostics + comment-tag: frontend-bundle-diagnostics file-path: ${{ runner.temp }}/frontend-bundle-report/frontend-bundle-diagnostics-report.md From 5d0ecf976d21a96610984abd6dd98ac15a270623 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 22:12:15 +0900 Subject: [PATCH 387/578] refacotr(gh): refactor --- .../frontend-bundle-diagnostics.comment.yml | 149 +----------------- 1 file changed, 7 insertions(+), 142 deletions(-) diff --git a/.github/workflows/frontend-bundle-diagnostics.comment.yml b/.github/workflows/frontend-bundle-diagnostics.comment.yml index 3da6d0dcbc0..709c735e693 100644 --- a/.github/workflows/frontend-bundle-diagnostics.comment.yml +++ b/.github/workflows/frontend-bundle-diagnostics.comment.yml @@ -6,29 +6,6 @@ on: - Frontend bundle diagnostics (inspect) types: - completed - pull_request_target: - types: - - opened - - synchronize - - reopened - - ready_for_review - paths: - - packages/frontend/** - - packages/frontend-shared/** - - packages/frontend-builder/** - - packages/i18n/** - - packages/icons-subsetter/** - - packages/misskey-js/** - - packages/misskey-reversi/** - - packages/misskey-bubble-game/** - - package.json - - pnpm-lock.yaml - - pnpm-workspace.yaml - - .node-version - - .github/scripts/utility.mts - - .github/scripts/frontend-bundle-diagnostics.render-md.mts - - .github/workflows/frontend-bundle-diagnostics.inspect.yml - - .github/workflows/frontend-bundle-diagnostics.comment.yml permissions: actions: read @@ -39,120 +16,13 @@ permissions: jobs: comment: name: Comment frontend bundle report - if: github.event_name == 'pull_request_target' || (github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success') + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest concurrency: - group: frontend-bundle-diagnostics-report-${{ github.event.pull_request.number || github.event.workflow_run.id }} + group: frontend-bundle-diagnostics-report-${{ github.event.workflow_run.id }} cancel-in-progress: true steps: - - name: Find bundle report run - if: github.event_name == 'pull_request_target' - id: find-report-run - uses: actions/github-script@v9 - with: - script: | - const workflow_id = 'frontend-bundle-report.yml'; - const artifactName = 'frontend-bundle-report'; - const headSha = context.payload.pull_request.head.sha; - const prNumber = context.payload.pull_request.number; - const pollIntervalMs = 30_000; - const timeoutMs = 90 * 60_000; - const startedAt = Date.now(); - const { owner, repo } = context.repo; - - async function listReportWorkflowRuns() { - const runsForHead = await github.paginate(github.rest.actions.listWorkflowRuns, { - owner, - repo, - workflow_id, - event: 'pull_request', - head_sha: headSha, - per_page: 100, - }); - - if (runsForHead.length > 0) { - return runsForHead; - } - - const recentRuns = await github.paginate(github.rest.actions.listWorkflowRuns, { - owner, - repo, - workflow_id, - event: 'pull_request', - per_page: 100, - }); - return recentRuns.filter((run) => - run.pull_requests?.some((pullRequest) => pullRequest.number === prNumber)); - } - - async function findReportRun() { - const runs = (await listReportWorkflowRuns()) - .sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at)); - - for (const run of runs) { - if (run.status !== 'completed') continue; - if (run.conclusion !== 'success') { - core.warning(`Frontend bundle report run ${run.id} completed with conclusion: ${run.conclusion}`); - return { done: true, run: null }; - } - - const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { - owner, - repo, - run_id: run.id, - per_page: 100, - }); - const report = artifacts.find((artifact) => artifact.name === artifactName && !artifact.expired); - if (report) return { done: true, run }; - - core.info(`Frontend bundle report run ${run.id} did not produce ${artifactName}.`); - return { done: true, run: null }; - } - - return { done: false, run: null }; - } - - while (Date.now() - startedAt < timeoutMs) { - const { done, run } = await findReportRun(); - if (run) { - core.info(`Found frontend bundle report on workflow run ${run.id}.`); - core.setOutput('run-id', String(run.id)); - return; - } - if (done) { - return; - } - - core.info('Waiting for frontend bundle report artifact...'); - await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); - } - - core.warning(`Timed out waiting for ${artifactName} from ${workflow_id} for ${headSha}.`); - - - name: Find bundle report artifact - if: github.event_name == 'workflow_run' - id: find-report-artifact - uses: actions/github-script@v9 - with: - script: | - const artifactName = 'frontend-bundle-report'; - const { owner, repo } = context.repo; - const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { - owner, - repo, - run_id: context.payload.workflow_run.id, - per_page: 100, - }); - const report = artifacts.find((artifact) => artifact.name === artifactName && !artifact.expired); - if (report) { - core.setOutput('exists', 'true'); - } else { - core.info(`Workflow run ${context.payload.workflow_run.id} did not produce ${artifactName}.`); - core.setOutput('exists', 'false'); - } - - - name: Download bundle report from workflow_run - if: github.event_name == 'workflow_run' && steps.find-report-artifact.outputs.exists == 'true' + - name: Download bundle report uses: actions/download-artifact@v8 with: name: frontend-bundle-report @@ -161,15 +31,10 @@ jobs: repository: ${{ github.repository }} run-id: ${{ github.event.workflow_run.id }} - - name: Download bundle report from pull_request_target - if: github.event_name == 'pull_request_target' && steps.find-report-run.outputs.run-id != '' - uses: actions/download-artifact@v8 - with: - name: frontend-bundle-report - path: ${{ runner.temp }}/frontend-bundle-report - github-token: ${{ github.token }} - repository: ${{ github.repository }} - run-id: ${{ steps.find-report-run.outputs.run-id }} + - name: Load PR number + id: load-pr-number + shell: bash + run: echo "pr-number=$(cat "$RUNNER_TEMP/frontend-bundle-report/pr-number.txt")" >> "$GITHUB_OUTPUT" - name: Comment on pull request uses: thollander/actions-comment-pull-request@v3 From ab21fc725b71f78a96a22e792f6f4af6376a4723 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 22:27:32 +0900 Subject: [PATCH 388/578] refacotr(gh): refactor --- .../scripts/frontend-browser-diagnostics.inspect.mts | 6 ++---- .github/workflows/backend-diagnostics.comment.yml | 2 +- .../workflows/frontend-browser-diagnostics.inspect.yml | 10 +++++----- .github/workflows/lint.yml | 4 ++-- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/scripts/frontend-browser-diagnostics.inspect.mts b/.github/scripts/frontend-browser-diagnostics.inspect.mts index ec0e08857d8..eb3a2288408 100644 --- a/.github/scripts/frontend-browser-diagnostics.inspect.mts +++ b/.github/scripts/frontend-browser-diagnostics.inspect.mts @@ -242,7 +242,7 @@ async function genReport(label: 'base' | 'head', repoDir: string, outputPath: st try { server = util.startServer(label, repoDir); - await util.waitForServer(baseUrl, server!); + await util.waitForServer(baseUrl, server); await rm(heapSnapshotWorkDirs[label], { recursive: true, force: true }); await mkdir(heapSnapshotWorkDirs[label], { recursive: true }); @@ -261,9 +261,7 @@ async function genReport(label: 'base' | 'head', repoDir: string, outputPath: st await writeFile(outputPath, JSON.stringify(report, null, '\t')); process.stderr.write(`[${label}] Wrote browser metrics report to ${outputPath}\n`); - if (heapSnapshotSavePath != null) { - await saveRepresentativeHeapSnapshot(label, report, heapSnapshotSavePath); - } + await saveRepresentativeHeapSnapshot(label, report, heapSnapshotSavePath); } finally { if (server != null) await util.stopServer(server); } diff --git a/.github/workflows/backend-diagnostics.comment.yml b/.github/workflows/backend-diagnostics.comment.yml index 4aa7eef68d3..a19166a3198 100644 --- a/.github/workflows/backend-diagnostics.comment.yml +++ b/.github/workflows/backend-diagnostics.comment.yml @@ -35,7 +35,7 @@ jobs: run: echo "pr-number=$(cat artifacts/pr_number)" >> "$GITHUB_OUTPUT" - name: Find heap snapshot artifacts id: find-heap-snapshot-artifacts - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: script: | const { owner, repo } = context.repo; diff --git a/.github/workflows/frontend-browser-diagnostics.inspect.yml b/.github/workflows/frontend-browser-diagnostics.inspect.yml index 63b43a05ae1..4841cb3822f 100644 --- a/.github/workflows/frontend-browser-diagnostics.inspect.yml +++ b/.github/workflows/frontend-browser-diagnostics.inspect.yml @@ -60,7 +60,7 @@ jobs: steps: - name: Checkout base - uses: actions/checkout@v6.0.2 + uses: actions/checkout@v6.0.3 with: persist-credentials: false repository: ${{ github.event.pull_request.base.repo.full_name }} @@ -69,7 +69,7 @@ jobs: submodules: true - name: Checkout pull request - uses: actions/checkout@v6.0.2 + uses: actions/checkout@v6.0.3 with: persist-credentials: false repository: ${{ github.event.pull_request.head.repo.full_name }} @@ -78,7 +78,7 @@ jobs: submodules: true - name: Setup pnpm - uses: pnpm/action-setup@v6.0.3 + uses: pnpm/action-setup@v6.0.9 with: package_json_file: after/package.json @@ -133,7 +133,7 @@ jobs: id: upload-browser-base-heap-snapshot uses: actions/upload-artifact@v7 with: - path: base-heap-snapshot.heapsnapshot + path: ${{ runner.temp }}/frontend-browser-diagnostics/base-heap-snapshot.heapsnapshot archive: false if-no-files-found: error retention-days: 7 @@ -142,7 +142,7 @@ jobs: id: upload-browser-head-heap-snapshot uses: actions/upload-artifact@v7 with: - path: head-heap-snapshot.heapsnapshot + path: ${{ runner.temp }}/frontend-browser-diagnostics/head-heap-snapshot.heapsnapshot archive: false if-no-files-found: error retention-days: 7 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 63ae5c7397a..0e77f896a22 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -123,12 +123,12 @@ jobs: runs-on: ubuntu-latest continue-on-error: true steps: - - uses: actions/checkout@v6.0.2 + - uses: actions/checkout@v6.0.3 with: fetch-depth: 0 submodules: true - name: Setup pnpm - uses: pnpm/action-setup@v6.0.3 + uses: pnpm/action-setup@v6.0.9 - uses: actions/setup-node@v6.4.0 with: node-version-file: '.node-version' From 0272ee73eba065f4db873c7c602a877fbb720a25 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 22:40:45 +0900 Subject: [PATCH 389/578] refacotr(gh): refactor --- .../frontend-bundle-diagnostics.render-md.mts | 2 +- .../frontend-bundle-diagnostics.inspect.yml | 26 ------------------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/.github/scripts/frontend-bundle-diagnostics.render-md.mts b/.github/scripts/frontend-bundle-diagnostics.render-md.mts index 7ec0cfc61d6..1e8cf37f24f 100644 --- a/.github/scripts/frontend-bundle-diagnostics.render-md.mts +++ b/.github/scripts/frontend-bundle-diagnostics.render-md.mts @@ -9,7 +9,7 @@ import * as util from './utility.mts'; const marker = ''; -const locale = process.env.FRONTEND_JS_SIZE_LOCALE ?? 'ja-JP'; +const locale = 'ja-JP'; //function sharePercent(value, total) { // if (total === 0) return '0%'; diff --git a/.github/workflows/frontend-bundle-diagnostics.inspect.yml b/.github/workflows/frontend-bundle-diagnostics.inspect.yml index 3572f77ea85..6aa4f54fb49 100644 --- a/.github/workflows/frontend-bundle-diagnostics.inspect.yml +++ b/.github/workflows/frontend-bundle-diagnostics.inspect.yml @@ -37,8 +37,6 @@ jobs: report: name: Build frontend bundle report runs-on: ubuntu-latest - env: - FRONTEND_JS_SIZE_LOCALE: ja-JP steps: - name: Checkout base uses: actions/checkout@v6.0.3 @@ -56,25 +54,12 @@ jobs: path: after submodules: true - - name: Check base visualizer support - id: check-base-visualizer - shell: bash - run: | - if grep -q 'FRONTEND_BUNDLE_VISUALIZER' before/packages/frontend/vite.config.ts; then - echo 'supported=true' >> "$GITHUB_OUTPUT" - else - echo 'supported=false' >> "$GITHUB_OUTPUT" - echo 'Base commit does not support frontend bundle visualizer. Skipping frontend bundle report.' >> "$GITHUB_STEP_SUMMARY" - fi - - name: Setup pnpm - if: steps.check-base-visualizer.outputs.supported == 'true' uses: pnpm/action-setup@v6.0.9 with: package_json_file: after/package.json - name: Setup Node.js - if: steps.check-base-visualizer.outputs.supported == 'true' uses: actions/setup-node@v6.4.0 with: node-version-file: after/.node-version @@ -84,21 +69,17 @@ jobs: after/pnpm-lock.yaml - name: Install dependencies for base - if: steps.check-base-visualizer.outputs.supported == 'true' working-directory: before run: pnpm i --frozen-lockfile - name: Build frontend dependencies for base - if: steps.check-base-visualizer.outputs.supported == 'true' working-directory: before run: pnpm --filter "frontend^..." run build - name: Prepare report output - if: steps.check-base-visualizer.outputs.supported == 'true' run: mkdir -p "$RUNNER_TEMP/frontend-bundle-report" - name: Build frontend report for base - if: steps.check-base-visualizer.outputs.supported == 'true' working-directory: before env: FRONTEND_BUNDLE_VISUALIZER: 'true' @@ -106,17 +87,14 @@ jobs: run: pnpm --filter frontend run build - name: Install dependencies for pull request - if: steps.check-base-visualizer.outputs.supported == 'true' working-directory: after run: pnpm i --frozen-lockfile - name: Build frontend dependencies for pull request - if: steps.check-base-visualizer.outputs.supported == 'true' working-directory: after run: pnpm --filter "frontend^..." run build - name: Build frontend report for pull request - if: steps.check-base-visualizer.outputs.supported == 'true' working-directory: after env: FRONTEND_BUNDLE_VISUALIZER: 'true' @@ -125,7 +103,6 @@ jobs: run: pnpm --filter frontend run build - name: Upload bundle visualizer - if: steps.check-base-visualizer.outputs.supported == 'true' id: upload-bundle-visualizer uses: actions/upload-artifact@v7 with: @@ -136,7 +113,6 @@ jobs: retention-days: 7 - name: Generate report markdown - if: steps.check-base-visualizer.outputs.supported == 'true' shell: bash env: BASE_SHA: ${{ github.event.pull_request.base.sha }} @@ -152,7 +128,6 @@ jobs: printf '%s\n' "${{ github.event.pull_request.html_url }}" > "$REPORT_DIR/pr-url.txt" - name: Check report - if: steps.check-base-visualizer.outputs.supported == 'true' run: | REPORT_DIR="$RUNNER_TEMP/frontend-bundle-report" test -s "$REPORT_DIR/before-stats.json" @@ -161,7 +136,6 @@ jobs: cat "$REPORT_DIR/frontend-bundle-diagnostics-report.md" >> "$GITHUB_STEP_SUMMARY" - name: Upload bundle report - if: steps.check-base-visualizer.outputs.supported == 'true' uses: actions/upload-artifact@v7 with: name: frontend-bundle-report From 88c6cd1766b176821cebf996b76085840591ee12 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 16 Jul 2026 23:19:25 +0900 Subject: [PATCH 390/578] refactor(gh): unify heap snapshot output paths --- .../frontend-browser-diagnostics.inspect.mts | 18 +++++++++++------- .../frontend-browser-diagnostics.inspect.yml | 6 +++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/scripts/frontend-browser-diagnostics.inspect.mts b/.github/scripts/frontend-browser-diagnostics.inspect.mts index eb3a2288408..1f0d74875f8 100644 --- a/.github/scripts/frontend-browser-diagnostics.inspect.mts +++ b/.github/scripts/frontend-browser-diagnostics.inspect.mts @@ -11,7 +11,7 @@ import { HeadlessChromeController, summarizeBrowserDiagnostics, summarizeNetwork import type { BrowserMeasurement, NetworkRequest, NetworkSummary } from './chrome.mts'; import { closeUserSetupDialog, postNote, signupThroughUi, visitHome } from '../../packages/frontend/test/e2e/shared.ts'; -const [baseDirArg, headDirArg, baseOutputArg, headOutputArg, baseHeapSnapshotOutputArg, headHeapSnapshotOutputArg] = process.argv.slice(2); +const [baseDirArg, headDirArg, baseOutputArg, headOutputArg] = process.argv.slice(2); const baseUrl = process.env.FRONTEND_BROWSER_METRICS_URL ?? 'http://127.0.0.1:61812'; const sampleCount = util.readIntegerEnv('FRONTEND_BROWSER_METRICS_SAMPLE_COUNT', 5, 1); @@ -20,6 +20,10 @@ const heapSnapshotWorkDirs = { base: resolve('frontend-browser-base-heap-snapshots'), head: resolve('frontend-browser-head-heap-snapshots'), } as const; +const heapSnapshotOutputPaths = { + base: resolve('base-heap-snapshot.heapsnapshot'), + head: resolve('head-heap-snapshot.heapsnapshot'), +} as const; type BrowserMeasurementSample = BrowserMeasurement & { round: number; @@ -230,14 +234,14 @@ function heapSnapshotPath(label: 'base' | 'head', round: number) { return join(heapSnapshotWorkDirs[label], `round-${round}.heapsnapshot`); } -async function saveRepresentativeHeapSnapshot(label: 'base' | 'head', report: BrowserMetricsReport, outputPath: string) { +async function saveRepresentativeHeapSnapshot(label: 'base' | 'head', report: BrowserMetricsReport) { const representative = selectRepresentativeSample(report.samples, sample => sample.heapSnapshot.categories.total); - await copyFile(heapSnapshotPath(label, representative.round), outputPath); + await copyFile(heapSnapshotPath(label, representative.round), heapSnapshotOutputPaths[label]); process.stderr.write(`[${label}] Selected round ${representative.round} heap snapshot for artifact\n`); await rm(heapSnapshotWorkDirs[label], { recursive: true, force: true }); } -async function genReport(label: 'base' | 'head', repoDir: string, outputPath: string, heapSnapshotSavePath: string) { +async function genReport(label: 'base' | 'head', repoDir: string, outputPath: string) { let server: ReturnType | null = null; try { @@ -261,15 +265,15 @@ async function genReport(label: 'base' | 'head', repoDir: string, outputPath: st await writeFile(outputPath, JSON.stringify(report, null, '\t')); process.stderr.write(`[${label}] Wrote browser metrics report to ${outputPath}\n`); - await saveRepresentativeHeapSnapshot(label, report, heapSnapshotSavePath); + await saveRepresentativeHeapSnapshot(label, report); } finally { if (server != null) await util.stopServer(server); } } async function main() { - await genReport('base', resolve(baseDirArg), resolve(baseOutputArg), resolve(baseHeapSnapshotOutputArg)); - await genReport('head', resolve(headDirArg), resolve(headOutputArg), resolve(headHeapSnapshotOutputArg)); + await genReport('base', resolve(baseDirArg), resolve(baseOutputArg)); + await genReport('head', resolve(headDirArg), resolve(headOutputArg)); } await main(); diff --git a/.github/workflows/frontend-browser-diagnostics.inspect.yml b/.github/workflows/frontend-browser-diagnostics.inspect.yml index 4841cb3822f..92f645ab26a 100644 --- a/.github/workflows/frontend-browser-diagnostics.inspect.yml +++ b/.github/workflows/frontend-browser-diagnostics.inspect.yml @@ -127,13 +127,13 @@ jobs: run: | REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" mkdir -p "$REPORT_DIR" - node after/.github/scripts/frontend-browser-diagnostics.inspect.mts before after "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" "$REPORT_DIR/base-heap-snapshot.heapsnapshot" "$REPORT_DIR/head-heap-snapshot.heapsnapshot" + node after/.github/scripts/frontend-browser-diagnostics.inspect.mts before after "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" - name: Upload browser base heap snapshot id: upload-browser-base-heap-snapshot uses: actions/upload-artifact@v7 with: - path: ${{ runner.temp }}/frontend-browser-diagnostics/base-heap-snapshot.heapsnapshot + path: base-heap-snapshot.heapsnapshot archive: false if-no-files-found: error retention-days: 7 @@ -142,7 +142,7 @@ jobs: id: upload-browser-head-heap-snapshot uses: actions/upload-artifact@v7 with: - path: ${{ runner.temp }}/frontend-browser-diagnostics/head-heap-snapshot.heapsnapshot + path: head-heap-snapshot.heapsnapshot archive: false if-no-files-found: error retention-days: 7 From 3760e7a9f85538aeed3015acf0e4f42b4078666e Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 11:05:21 +0900 Subject: [PATCH 391/578] chore(gh): fix workflow name --- .github/workflows/locale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml index 000cfed91d2..d87f18827e7 100644 --- a/.github/workflows/locale.yml +++ b/.github/workflows/locale.yml @@ -1,4 +1,4 @@ -name: Lint +name: Locale on: push: From 3de6b610b54386dbcaec0209648ce3612890be7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:45:26 +0900 Subject: [PATCH 392/578] =?UTF-8?q?enhance:=20JSON=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=E3=81=AE=E6=A7=8B=E9=80=A0=E5=8C=96=E3=83=AD=E3=82=B0=E5=87=BA?= =?UTF-8?q?=E5=8A=9B=E3=81=AB=E5=AF=BE=E5=BF=9C=20(#17728)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance: JSON形��構造化ログ出力�対応 * 起動時ログ�JSON化出��������を調整 --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- .config/docker_example.yml | 2 + .config/example.yml | 2 + CHANGELOG.md | 1 + packages/backend/src/boot/entry.ts | 25 ++---- packages/backend/src/boot/master.ts | 20 ++++- .../backend/src/boot/process-error-handler.ts | 59 ++++++++++++++ packages/backend/src/boot/worker.ts | 1 + packages/backend/src/config.ts | 4 +- .../backend/src/logging/JsonConsoleBackend.ts | 71 +++++++++++++++++ .../backend/src/logging/logging-runtime.ts | 20 ++++- packages/backend/src/logging/types.ts | 3 + .../test/unit/boot/process-error-handler.ts | 72 ++++++++++++++++++ .../test/unit/logging/JsonConsoleBackend.ts | 76 +++++++++++++++++++ .../test/unit/logging/logging-runtime.ts | 40 ++++++++++ 14 files changed, 367 insertions(+), 29 deletions(-) create mode 100644 packages/backend/src/boot/process-error-handler.ts create mode 100644 packages/backend/src/logging/JsonConsoleBackend.ts create mode 100644 packages/backend/test/unit/boot/process-error-handler.ts create mode 100644 packages/backend/test/unit/logging/JsonConsoleBackend.ts create mode 100644 packages/backend/test/unit/logging/logging-runtime.ts diff --git a/.config/docker_example.yml b/.config/docker_example.yml index bc2549d5cf6..4e10f771b02 100644 --- a/.config/docker_example.yml +++ b/.config/docker_example.yml @@ -241,6 +241,8 @@ proxyBypassHosts: # Log settings # logging: +# # ログ�出力形�。「json��1行JSON�未指定時�「pretty���。 +# format: pretty # # Minimum level for all loggers. Defaults to info in production and debug otherwise. # level: info # # The longest matching logger domain takes precedence over the global level. diff --git a/.config/example.yml b/.config/example.yml index 961417cb30c..06a0ed06518 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -474,6 +474,8 @@ proxyBypassHosts: # Log settings # logging: +# # ログ�出力形�。「json��1行JSON�未指定時�「pretty���。 +# format: pretty # # Minimum level for all loggers. Defaults to info in production and debug otherwise. # level: info # # The longest matching logger domain takes precedence over the global level. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fc991d0a13..f7ff08304d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ - Enhance: URLプレビュー��果を内部�キャッシュ�るよ�� - Enhance: API内部エラー�ログ�構造化属性�正�化��エラー情報を付与���証情報を自動的�秘匿�るよ��(従�形��表示�維�) - Enhance: ログ全体�既定level�logger domain���出力levelを設定��るよ�� +- Enhance: �ックエンド�ログを1行JSON形��出力��るよ�� - Fix: `/stats` API �レス�ンス型�正�����題を修正 - Fix: �ッシュタグ�関連�るデータを更新�る際�エラー�ンドリングを修正 - Fix: Sentry 使用環境下���Misskey �発行�� SQL クエリ� span ���れ���題を修正 diff --git a/packages/backend/src/boot/entry.ts b/packages/backend/src/boot/entry.ts index 3c2d56c73c7..03e5c395c36 100644 --- a/packages/backend/src/boot/entry.ts +++ b/packages/backend/src/boot/entry.ts @@ -10,10 +10,10 @@ import cluster from 'node:cluster'; import { EventEmitter } from 'node:events'; import { writeHeapSnapshot } from 'node:v8'; -import chalk from 'chalk'; import Xev from 'xev'; import Logger from '@/logger.js'; import { envOption } from '../env.js'; +import { installProcessErrorHandlers } from './process-error-handler.js'; import { isShutdownInProgress } from './shutdown-handler.js'; import { readyRef } from './ready.js'; @@ -28,6 +28,8 @@ const logger = new Logger('core', 'cyan'); const clusterLogger = logger.createSubLogger('cluster', 'orange'); const ev = new Xev(); +installProcessErrorHandlers({ logger, quiet: envOption.quiet }); + //#region Events // Listen new workers @@ -47,25 +49,11 @@ cluster.on('exit', worker => { return; } - // Replace the dead worker, - // we're not sentimental - clusterLogger.error(chalk.red(`[${worker.id}] died :(`)); + // 終了��ワーカー�従���り�生���表示色�出力処��任���。 + clusterLogger.error(`[${worker.id}] died :(`); cluster.fork(); }); -// Display detail of unhandled promise rejection -if (!envOption.quiet) { - process.on('unhandledRejection', console.dir); -} - -// Display detail of uncaught exception -process.on('uncaughtException', err => { - try { - logger.error(err); - console.trace(err); - } catch { } -}); - // Dying away... process.on('exit', code => { if (isShutdownInProgress()) return; @@ -76,12 +64,10 @@ process.on('exit', code => { if (!envOption.disableClustering) { if (cluster.isPrimary) { - logger.info(`Start main process... pid: ${process.pid}`); const { masterMain } = await import('./master.js'); await masterMain(); ev.mount(); } else if (cluster.isWorker) { - logger.info(`Start worker process... pid: ${process.pid}`); const { workerMain } = await import('./worker.js'); await workerMain(); } else { @@ -89,7 +75,6 @@ if (!envOption.disableClustering) { } } else { // �cluster�場��Master���起動�る���Worker�処��行���(cluster.isWorker === true�状態���ブロック��る�����) - logger.info(`Start main process... pid: ${process.pid}`); const { masterMain } = await import('./master.js'); await masterMain(); ev.mount(); diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index 4f78e602d01..3cb340e9637 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -12,6 +12,7 @@ import Logger from '@/logger.js'; import { loadConfig } from '@/config.js'; import type { Config } from '@/config.js'; import { configureLogging, shutdownLogging } from '@/logging/logging-runtime.js'; +import type { LogFormat } from '@/logging/types.js'; import { showMachineInfo } from '@/misc/show-machine-info.js'; import { envOption } from '@/env.js'; import { initTelemetry, shutdownTelemetry } from '@/core/telemetry/telemetry-registry.js'; @@ -23,7 +24,17 @@ const bootLogger = logger.createSubLogger('boot', 'magenta'); const themeColor = chalk.hex('#86b300'); -function greet(props: { version: string }) { +/** 起動時�案内を��択�れ�ログ形������出力���。 */ +function greet(props: { version: string; format: LogFormat }) { + if (!envOption.quiet && props.format === 'json') { + // JSONモード��生�コンソール出力を����案内を1件��構造化ログ����。 + bootLogger.info('Welcome to Misskey!'); + bootLogger.info(`Misskey v${props.version}`, null, true); + bootLogger.info('Misskey is an open-source decentralized microblogging platform.'); + bootLogger.info('If you like Misskey, please consider donating to support dev. https://misskey-hub.net/docs/donate/'); + return; + } + if (!envOption.quiet) { //#region Misskey logo const v = `v${props.version}`; @@ -54,7 +65,9 @@ export async function masterMain() { // initialize app try { config = loadConfigBoot(); - greet({ version: config.version }); + logger.info(`Start main process... pid: ${process.pid}`); + bootLogger.createSubLogger('config').succ('Loaded'); + greet({ version: config.version, format: config.logging?.format ?? 'pretty' }); showEnvironment(); await showMachineInfo(bootLogger); showNodejsVersion(); @@ -136,6 +149,7 @@ function showNodejsVersion(): void { nodejsLogger.info(`Version ${process.version} detected.`); } +/** 設定を読�込���功時�後続�ログ出力形�を�用���。 */ function loadConfigBoot(): Config { const configLogger = bootLogger.createSubLogger('config'); let config; @@ -154,8 +168,6 @@ function loadConfigBoot(): Config { throw exception; } - configLogger.succ('Loaded'); - return config; } diff --git a/packages/backend/src/boot/process-error-handler.ts b/packages/backend/src/boot/process-error-handler.ts new file mode 100644 index 00000000000..c1224f1923f --- /dev/null +++ b/packages/backend/src/boot/process-error-handler.ts @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { LogWriteInput } from '@/logging/types.js'; + +/** プロセス例外をロガー�渡����必��最��処�対象��。 */ +export type ProcessErrorHandlerProcess = { + on(event: 'unhandledRejection', listener: (reason: unknown) => void): unknown; + on(event: 'uncaughtException', listener: (error: Error) => void): unknown; +}; + +/** 例外記録�必��ロガー�最�インターフェース��。 */ +export type ProcessErrorHandlerLogger = { + write(input: LogWriteInput): void; +}; + +/** プロセス例外�ンドラー�登録�使��存関係��。 */ +export type ProcessErrorHandlerOptions = { + readonly process?: ProcessErrorHandlerProcess; + readonly logger: ProcessErrorHandlerLogger; + readonly quiet: boolean; +}; + +/** ログ記録�失敗�別�例外を起����よ��プロセス異常を安全�記録���。 */ +function writeProcessError( + logger: ProcessErrorHandlerLogger, + eventName: 'process.unhandled_rejection' | 'process.uncaught_exception', + message: string, + error: unknown, +): void { + try { + // 元�値をerror�渡��JSON形��出力処��安全�形�正�化���。 + logger.write({ + level: 'error', + eventName, + message, + error, + }); + } catch { + // 例外処�中�ログ失敗���ら�プロセスを�安定����よ��り�����。 + } +} + +/** 未処��Promise拒��未��例外を構造化ログ�接続���。 */ +export function installProcessErrorHandlers(options: ProcessErrorHandlerOptions): void { + const processLike: ProcessErrorHandlerProcess = options.process ?? (process as unknown as ProcessErrorHandlerProcess); + + if (!options.quiet) { + processLike.on('unhandledRejection', reason => { + writeProcessError(options.logger, 'process.unhandled_rejection', 'Unhandled promise rejection', reason); + }); + } + + processLike.on('uncaughtException', error => { + writeProcessError(options.logger, 'process.uncaught_exception', 'Uncaught exception', error); + }); +} diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts index ad15296440c..71857f9a527 100644 --- a/packages/backend/src/boot/worker.ts +++ b/packages/backend/src/boot/worker.ts @@ -24,6 +24,7 @@ export async function workerMain() { try { config = loadConfig(); configureLogging(config.logging); + logger.info(`Start worker process... pid: ${process.pid}`); } catch (e) { bootLogger.error(e instanceof Error ? e : new Error(String(e)), null, true); process.exit(1); diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index ab46416b356..9b49a48dd33 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -10,7 +10,7 @@ import { type FastifyServerOptions } from 'fastify'; import type * as Sentry from '@sentry/node'; import type * as SentryVue from '@sentry/vue'; import type { RedisOptions } from 'ioredis'; -import type { LogLevelSetting } from './logging/types.js'; +import type { LogFormat, LogLevelSetting } from './logging/types.js'; type RedisOptionsSource = Partial & { host: string; @@ -133,6 +133,7 @@ type Source = { pidFile: string; logging?: { + format?: LogFormat; level?: LogLevelSetting; domains?: Record | null; sql?: { @@ -197,6 +198,7 @@ export type Config = { deliverJobMaxAttempts: number | undefined; inboxJobMaxAttempts: number | undefined; logging?: { + format?: LogFormat; level?: LogLevelSetting; domains?: Record | null; sql?: { diff --git a/packages/backend/src/logging/JsonConsoleBackend.ts b/packages/backend/src/logging/JsonConsoleBackend.ts new file mode 100644 index 00000000000..a13f6c262e7 --- /dev/null +++ b/packages/backend/src/logging/JsonConsoleBackend.ts @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { LogBackend } from './LogBackend.js'; +import type { LogRecord } from './types.js'; + +/** JSON形��ログを1行�出力�る処��外部�ら���る�存関係��。 */ +export type JsonConsoleBackendDependencies = { + readonly output: (line: string) => void; +}; + +/** JSON形��出力�る項目を��用上安定��形���定義���。 */ +type JsonLogRecord = { + readonly timestamp: string; + readonly level: LogRecord['level']; + readonly message: string; + readonly loggerName: string; + readonly eventName?: string; + readonly attributes?: LogRecord['attributes']; + readonly error?: LogRecord['error']; + readonly processId: number; + readonly isPrimary: boolean; + readonly workerId: number | null; +}; + +const defaultDependencies: JsonConsoleBackendDependencies = { + output: line => console.log(line), +}; + +/** LogRecord�らJSON�出�項目��を���内部情報を誤������よ�����。 */ +function createJsonLogRecord(record: LogRecord): JsonLogRecord { + // 色や旧API�生データ�表示専用�情報����機械��形�����込���ん。 + return { + timestamp: record.timestamp, + level: record.level, + message: record.message, + loggerName: record.loggerName, + // 任�項目�値��る場������空�項目を増や���よ�����。 + ...(record.eventName != null ? { eventName: record.eventName } : {}), + ...(record.attributes != null ? { attributes: record.attributes } : {}), + ...(record.error != null ? { error: record.error } : {}), + // 実行主体�情報�常�出��ログを横断��検索��る形を����。 + processId: record.processId, + isPrimary: record.isPrimary, + workerId: record.workerId, + }; +} + +/** + * LogRecordを1行�JSON�変���ログ�集基盤�扱�る標準出力�渡���。 + * LoggerやLogManager�ら出力形�を切り離��Pretty形����記録を共有���。 + */ +export class JsonConsoleBackend implements LogBackend { + private readonly dependencies: JsonConsoleBackendDependencies; + + /** 出力処�を���り�テストや起動環境���出力先を差�替���。 */ + constructor(dependencies: Partial = {}) { + this.dependencies = { + ...defaultDependencies, + ...dependencies, + }; + } + + /** 1件�ログをJSON文字列�変���改行を����1回�出力���渡���。 */ + public write(record: LogRecord): void { + // JSON.stringify�改行��をエスケープ�る���1ログ1行�契約を����。 + this.dependencies.output(JSON.stringify(createJsonLogRecord(record))); + } +} diff --git a/packages/backend/src/logging/logging-runtime.ts b/packages/backend/src/logging/logging-runtime.ts index e4f97f56e65..3d842b31c79 100644 --- a/packages/backend/src/logging/logging-runtime.ts +++ b/packages/backend/src/logging/logging-runtime.ts @@ -5,8 +5,11 @@ import { LogManager } from './LogManager.js'; import { BootstrapConsoleBackend } from './BootstrapConsoleBackend.js'; +import { JsonConsoleBackend } from './JsonConsoleBackend.js'; import { PrettyConsoleBackend } from './PrettyConsoleBackend.js'; import type { LogManagerConfiguration } from './LogManager.js'; +import type { LogBackend } from './LogBackend.js'; +import type { LogFormat } from './types.js'; /** * プロセス内�����Logger�共有�るLogManager��。 @@ -14,13 +17,22 @@ import type { LogManagerConfiguration } from './LogManager.js'; */ export const logManager = new LogManager(new BootstrapConsoleBackend()); -/** 設定読込後�logging設定�Pretty backendを�用���。 */ -export function configureLogging(configuration?: LogManagerConfiguration): void { +/** ログ形�を検証��指定�れ�形��対応�る出力処�を作����。 */ +function createLoggingBackend(format: unknown): LogBackend { + if (format == null || format === 'pretty') return new PrettyConsoleBackend(); + if (format === 'json') return new JsonConsoleBackend(); + throw new Error('logging.format must be either pretty or json'); +} + +/** 起動時�ログ設定を�用���択��出力処��切り替���。 */ +export function configureLogging(configuration?: LogManagerConfiguration & { readonly format?: LogFormat }): void { + // 出力処�を先�検証��設定値��正�場���在�出力処�を壊���よ�����。 + const backend = createLoggingBackend(configuration?.format); logManager.configure(configuration); - logManager.setBackend(new PrettyConsoleBackend()); + logManager.setBackend(backend); } -/** プロセス終了���在�logging backendをflush��閉���。 */ +/** プロセス終了���在�ログ出力処�を�留分��書�出��閉���。 */ export function shutdownLogging(): Promise { return logManager.shutdown(); } diff --git a/packages/backend/src/logging/types.ts b/packages/backend/src/logging/types.ts index 1993cd18095..18616818407 100644 --- a/packages/backend/src/logging/types.ts +++ b/packages/backend/src/logging/types.ts @@ -11,6 +11,9 @@ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; /** 設定�指定��るログ�閾値��。`off`�ログイベント�level��使用���ん。 */ export type LogLevelSetting = LogLevel | 'off'; +/** コンソール�出�ログ形���。未指定時�見や��形�を使用���。 */ +export type LogFormat = 'pretty' | 'json'; + /** 正�化後�ログ属性���扱�るJSON�値��。 */ export type LogAttributeValue = | string diff --git a/packages/backend/test/unit/boot/process-error-handler.ts b/packages/backend/test/unit/boot/process-error-handler.ts new file mode 100644 index 00000000000..32e341cc488 --- /dev/null +++ b/packages/backend/test/unit/boot/process-error-handler.ts @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test, vi } from 'vitest'; +import type { LogWriteInput } from '@/logging/types.js'; +import { installProcessErrorHandlers } from '@/boot/process-error-handler.js'; + +type ProcessListener = (...args: unknown[]) => void; + +/** テスト用��登録�れ�プロセスイベントを呼�出�る処�対象を作����。 */ +function createProcessLike(): { + readonly process: { on: (event: string, listener: ProcessListener) => void }; + readonly listeners: Map; +} { + const listeners = new Map(); + return { + process: { + on: (event, listener) => listeners.set(event, listener), + }, + listeners, + }; +} + +describe('installProcessErrorHandlers', () => { + test('records unhandled rejections and uncaught exceptions as structured errors', () => { + const { process, listeners } = createProcessLike(); + const write = vi.fn<(input: LogWriteInput) => void>(); + const rejection = new Error('rejected'); + const exception = new TypeError('uncaught'); + + installProcessErrorHandlers({ process: process as never, logger: { write }, quiet: false }); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + listeners.get('unhandledRejection')!(rejection); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + listeners.get('uncaughtException')!(exception); + + expect(write).toHaveBeenNthCalledWith(1, { + level: 'error', + eventName: 'process.unhandled_rejection', + message: 'Unhandled promise rejection', + error: rejection, + }); + expect(write).toHaveBeenNthCalledWith(2, { + level: 'error', + eventName: 'process.uncaught_exception', + message: 'Uncaught exception', + error: exception, + }); + }); + + test('does not register the unhandled rejection handler in quiet mode', () => { + const { process, listeners } = createProcessLike(); + + installProcessErrorHandlers({ process: process as never, logger: { write: vi.fn() }, quiet: true }); + + expect([...listeners.keys()]).toEqual(['uncaughtException']); + }); + + test('does not rethrow when the logger fails', () => { + const { process, listeners } = createProcessLike(); + const write = vi.fn(() => { + throw new Error('logger failed'); + }); + + installProcessErrorHandlers({ process: process as never, logger: { write }, quiet: false }); + + expect(() => listeners.get('unhandledRejection')!(new Error('rejected'))).not.toThrow(); + expect(() => listeners.get('uncaughtException')!(new Error('uncaught'))).not.toThrow(); + }); +}); diff --git a/packages/backend/test/unit/logging/JsonConsoleBackend.ts b/packages/backend/test/unit/logging/JsonConsoleBackend.ts new file mode 100644 index 00000000000..b7204bdd643 --- /dev/null +++ b/packages/backend/test/unit/logging/JsonConsoleBackend.ts @@ -0,0 +1,76 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test, vi } from 'vitest'; +import type { LogRecord } from '@/logging/types.js'; +import { JsonConsoleBackend } from '@/logging/JsonConsoleBackend.js'; + +/** JSON形��テスト�使�共通�ログを作����。 */ +function createRecord(overrides: Partial = {}): LogRecord { + return { + level: 'error', + message: 'delivery failed', + context: [{ name: 'queue' }, { name: 'deliver' }], + timestamp: '2025-01-02T03:04:05.678Z', + loggerName: 'queue.deliver', + processId: 1234, + isPrimary: false, + workerId: 7, + ...overrides, + }; +} + +describe('JsonConsoleBackend', () => { + test('writes a stable one-line JSON record', () => { + const output = vi.fn<(line: string) => void>(); + const backend = new JsonConsoleBackend({ output }); + + backend.write(createRecord({ + eventName: 'queue.job.failed', + attributes: { jobId: '123', attempt: 2 }, + error: { type: 'TypeError', message: 'broken', stack: 'stack' }, + })); + + expect(output).toHaveBeenCalledOnce(); + expect(output.mock.calls[0][0]).toMatchInlineSnapshot(`"{\"timestamp\":\"2025-01-02T03:04:05.678Z\",\"level\":\"error\",\"message\":\"delivery failed\",\"loggerName\":\"queue.deliver\",\"eventName\":\"queue.job.failed\",\"attributes\":{\"jobId\":\"123\",\"attempt\":2},\"error\":{\"type\":\"TypeError\",\"message\":\"broken\",\"stack\":\"stack\"},\"processId\":1234,\"isPrimary\":false,\"workerId\":7}"`); + }); + + test('omits pretty-only compatibility data and context colors', () => { + const output = vi.fn<(line: string) => void>(); + const backend = new JsonConsoleBackend({ output }); + const record = createRecord({ + context: [{ name: 'queue', color: 'red' }], + compatibility: { + legacyLevel: 'success', + important: true, + data: { secret: 'must not be written' }, + }, + }); + + backend.write(record); + + expect(JSON.parse(output.mock.calls[0][0])).toEqual({ + timestamp: '2025-01-02T03:04:05.678Z', + level: 'error', + message: 'delivery failed', + loggerName: 'queue.deliver', + processId: 1234, + isPrimary: false, + workerId: 7, + }); + }); + + test('escapes newlines so each record remains one physical line', () => { + const output = vi.fn<(line: string) => void>(); + const backend = new JsonConsoleBackend({ output }); + const message = 'first line\nsecond line "quoted"'; + + backend.write(createRecord({ message })); + + const line = output.mock.calls[0][0]; + expect(line).not.toContain('\n'); + expect(JSON.parse(line).message).toBe(message); + }); +}); diff --git a/packages/backend/test/unit/logging/logging-runtime.ts b/packages/backend/test/unit/logging/logging-runtime.ts new file mode 100644 index 00000000000..9e8b2c2903a --- /dev/null +++ b/packages/backend/test/unit/logging/logging-runtime.ts @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { afterEach, describe, expect, test, vi } from 'vitest'; +import { JsonConsoleBackend } from '@/logging/JsonConsoleBackend.js'; +import { logManager, configureLogging } from '@/logging/logging-runtime.js'; +import { PrettyConsoleBackend } from '@/logging/PrettyConsoleBackend.js'; + +describe('logging-runtime', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + test('uses Pretty backend when the format is omitted', () => { + const setBackend = vi.spyOn(logManager, 'setBackend'); + + configureLogging(); + + expect(setBackend).toHaveBeenCalledWith(expect.any(PrettyConsoleBackend)); + }); + + test('uses JSON backend when the format is json', () => { + const setBackend = vi.spyOn(logManager, 'setBackend'); + + configureLogging({ format: 'json' }); + + expect(setBackend).toHaveBeenCalledWith(expect.any(JsonConsoleBackend)); + }); + + test('rejects an unknown format before changing logging configuration', () => { + const setBackend = vi.spyOn(logManager, 'setBackend'); + const configure = vi.spyOn(logManager, 'configure'); + + expect(() => configureLogging({ format: 'xml' as never })).toThrow('logging.format'); + expect(setBackend).not.toHaveBeenCalled(); + expect(configure).not.toHaveBeenCalled(); + }); +}); From 5a6b9439b6621c593ed2f8bce738d5fced225b17 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 17 Jul 2026 03:49:06 +0000 Subject: [PATCH 393/578] Bump version to 2026.7.0-alpha.6 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fd2253f431b..5a01454ad2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2026.7.0-alpha.5", + "version": "2026.7.0-alpha.6", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index eb61b1a81e1..0f63710f3bb 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2026.7.0-alpha.5", + "version": "2026.7.0-alpha.6", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From b5f0e96bf1def6889f7fc05f8693f2a94064f829 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 13:56:18 +0900 Subject: [PATCH 394/578] New Crowdin updates (#17717) * New translations ja-jp.yml (Spanish) [ci skip] * New translations ja-jp.yml (Indonesian) [ci skip] * New translations ja-jp.yml (Tagalog) [ci skip] --- locales/es-ES.yml | 4 ++-- locales/id-ID.yml | 3 +++ locales/tl-PH.yml | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 locales/tl-PH.yml diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 82879fdff70..043cc2fc897 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -584,7 +584,7 @@ showFixedPostForm: "Mostrar formulario de publicación sobre la línea de tiempo showFixedPostFormInChannel: "Mostrar el formulario de publicación por encima de la cronología (Canales)" withRepliesByDefaultForNewlyFollowed: "Incluir por defecto respuestas de usuarios recién seguidos en la línea de tiempo" newNoteRecived: "Tienes una nota nueva" -newNote: "Nueva nota" +newNote: "Nuevas notas" sounds: "Sonidos" sound: "Sonidos" notificationSoundSettings: "Configuración del sonido de las notificaciones" @@ -1219,7 +1219,7 @@ keepScreenOn: "Mantener pantalla encendida" verifiedLink: "Propiedad del enlace verificada" notifyNotes: "Notificar nuevas notas" unnotifyNotes: "Dejar de notificar nuevas notas" -notifyUsers: "Usuarios que han activado las notificaciones de publicaciones" +notifyUsers: "Cuentas con notificaciones activadas" authentication: "Autenticación" authenticationRequiredToContinue: "Por favor, autentifícate para continuar" dateAndTime: "Fecha y hora" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 24127b6a840..1b3e0575836 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -1358,6 +1358,7 @@ _chat: invitations: "Undang" history: "Riwayat obrolan" noHistory: "Tidak ada riwayat" + join: "Gabung" members: "Anggota" home: "Beranda" send: "Kirim" @@ -2555,6 +2556,8 @@ _deck: useSimpleUiForNonRootPages: "Gunakan antarmuka sederhana ke halaman yang dituju" usedAsMinWidthWhenFlexible: "Lebar minimum akan digunakan untuk ini ketika opsi \"Atur-otomatis lebar\" dinyalakan" flexible: "Atur-otomatis lebar" + _howToUse: + settings_title: "Pengaturan UI" _columns: main: "Utama" widgets: "Widget" diff --git a/locales/tl-PH.yml b/locales/tl-PH.yml new file mode 100644 index 00000000000..ed97d539c09 --- /dev/null +++ b/locales/tl-PH.yml @@ -0,0 +1 @@ +--- From 8691babd56c9fde7fd27d52ca9783f49362126db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:44:03 +0900 Subject: [PATCH 395/578] fix(frontend): Update MkLightbox.item.vue --- packages/frontend/src/components/MkLightbox.item.vue | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/MkLightbox.item.vue b/packages/frontend/src/components/MkLightbox.item.vue index 14ee8d00d98..eb7f5810190 100644 --- a/packages/frontend/src/components/MkLightbox.item.vue +++ b/packages/frontend/src/components/MkLightbox.item.vue @@ -795,8 +795,11 @@ function openMenu(ev: PointerEvent) { }); if (props.content.file != null) { - menu.push({ type: 'divider' }); - menu.push(...getFileMenu(props.content.file)); + const fileMenu = getFileMenu(props.content.file); + if (fileMenu.length > 0) { + menu.push({ type: 'divider' }); + menu.push(...fileMenu); + } } os.popupMenu(menu, (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined); From 0be4d352ec213b1f23977b4169f50a1149d104f2 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:52:05 +0900 Subject: [PATCH 396/578] New Crowdin updates (#17732) * New translations ja-jp.yml (Spanish) [ci skip] * New translations ja-jp.yml (Catalan) [ci skip] * New translations ja-jp.yml (German) [ci skip] * New translations ja-jp.yml (Italian) [ci skip] * New translations ja-jp.yml (Korean) [ci skip] * New translations ja-jp.yml (Portuguese) [ci skip] * New translations ja-jp.yml (Turkish) [ci skip] * New translations ja-jp.yml (Ukrainian) [ci skip] * New translations ja-jp.yml (Chinese Simplified) [ci skip] * New translations ja-jp.yml (Chinese Traditional) [ci skip] * New translations ja-jp.yml (English) [ci skip] * New translations ja-jp.yml (Vietnamese) [ci skip] * New translations ja-jp.yml (Thai) [ci skip] * New translations ja-jp.yml (Japanese, Kansai) [ci skip] --- locales/ca-ES.yml | 3 --- locales/de-DE.yml | 3 --- locales/en-US.yml | 3 --- locales/es-ES.yml | 3 --- locales/it-IT.yml | 3 --- locales/ja-KS.yml | 3 --- locales/ko-KR.yml | 3 --- locales/pt-PT.yml | 3 --- locales/th-TH.yml | 3 --- locales/tr-TR.yml | 3 --- locales/uk-UA.yml | 3 --- locales/vi-VN.yml | 2 -- locales/zh-CN.yml | 3 --- locales/zh-TW.yml | 3 --- 14 files changed, 41 deletions(-) diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index be6ece175e8..ec49f966aa1 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -1361,14 +1361,11 @@ information: "Informació" chat: "Xat" directMessage: "Xateja amb aquest usuari" directMessage_short: "Missatge" -migrateOldSettings: "Migrar la configuració anterior" -migrateOldSettings_description: "Normalment això es fa automàticament, però si la transició no es fa, el procés es pot iniciar manualment. S'esborrarà la configuració actual." compress: "Comprimir " right: "Dreta" bottom: "A baix " top: "A dalt " embed: "Incrustar" -settingsMigrating: "Estem migrant la teva configuració. Si us plau espera un moment... (També pots fer la migració més tard, manualment, anant a Preferències → Altres → Migrar configuració antiga)" readonly: "Només lectura" goToDeck: "Tornar al tauler" federationJobs: "Treballs de federació" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index a53634aa589..17b1a8c7e73 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -1358,14 +1358,11 @@ information: "Über" chat: "Chat" directMessage: "Mit dem Benutzer chatten" directMessage_short: "Nachrichten" -migrateOldSettings: "Alte Client-Einstellungen migrieren" -migrateOldSettings_description: "Dies sollte normalerweise automatisch geschehen, aber wenn die Migration aus irgendeinem Grund nicht erfolgreich war, kannst du den Migrationsprozess selbst manuell auslösen. Die aktuellen Konfigurationsinformationen werden dabei überschrieben." compress: "Komprimieren" right: "Rechts" bottom: "Unten" top: "Oben" embed: "Einbetten" -settingsMigrating: "Deine Einstellungen werden gerade migriert. Bitte warte einen Moment... (Du kannst die Einstellungen später auch manuell migrieren, indem du zu Einstellungen → Anderes → Alte Einstellungen migrieren gehst)" readonly: "Nur Lesezugriff" goToDeck: "Zurück zum Deck" federationJobs: "Föderation Jobs" diff --git a/locales/en-US.yml b/locales/en-US.yml index d1627feb14b..e998937dfb8 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1361,14 +1361,11 @@ information: "About" chat: "Chat" directMessage: "Chat with user" directMessage_short: "Message" -migrateOldSettings: "Migrate old client settings" -migrateOldSettings_description: "This should be done automatically but if for some reason the migration was not successful, you can trigger the migration process yourself manually. The current configuration information will be overwritten." compress: "Compress" right: "Right" bottom: "Bottom" top: "Top" embed: "Embed" -settingsMigrating: "Settings are being migrated, please wait a moment... (You can also migrate manually later by going to Settings→Others→Migrate old settings)" readonly: "Read only" goToDeck: "Return to Deck" federationJobs: "Federation Jobs" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 043cc2fc897..6d0508f9896 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -1361,14 +1361,11 @@ information: "Información" chat: "Chat" directMessage: "Chatear" directMessage_short: "Mensajes" -migrateOldSettings: "Migrar la configuración anterior" -migrateOldSettings_description: "Esto debería hacerse automáticamente, pero si por alguna razón la migración no ha tenido éxito, puede activar usted mismo el proceso de migración manualmente. Se sobrescribirá la información de configuración actual." compress: "Compresión de la imagen" right: "Derecha" bottom: "Abajo" top: "Arriba" embed: "Insertar" -settingsMigrating: "La configuración está siendo migrada, por favor espera un momento... (También puedes migrar manualmente más tarde yendo a Ajustes otros migrar configuración antigua" readonly: "Solo Lectura" goToDeck: "Volver al Deck" federationJobs: "Trabajos de Federación" diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 06880a4ea20..a7712ae5cae 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -1361,14 +1361,11 @@ information: "Informazioni" chat: "Chat" directMessage: "Chattare insieme" directMessage_short: "Messaggio" -migrateOldSettings: "Migrare le vecchie impostazioni" -migrateOldSettings_description: "Di solito, viene fatto automaticamente. Se per qualche motivo non fossero migrate con successo, è possibile avviare il processo di migrazione manualmente, sovrascrivendo le configurazioni attuali." compress: "Compressione" right: "Destra" bottom: "Sotto" top: "Sopra" embed: "Incorporare" -settingsMigrating: "Migrazione delle impostazioni. Attendere prego ... (Puoi anche migrare manualmente in un secondo momento, nel menu: Impostazioni → Altro → Migrazione delle impostazioni)" readonly: "Sola lettura" goToDeck: "Torna al Deck" federationJobs: "Coda di federazione" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 75f9b8224d6..802695ea0e5 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -1332,9 +1332,6 @@ preferenceSyncConflictChoiceCancel: "�期�有効化�や����" postForm: "投稿フォーム" information: "情報" directMessage: "�ャット�よ�" -migrateOldSettings: "旧設定情報を�引�越�" -migrateOldSettings_description: "通常�れ�自動�行�れる���んや����ん���由�上手�移行���ん������手動�移行処�を������る�。今�設定情報�上書��れる�。" -settingsMigrating: "設定を移行��る�。�ょ��待�����... (後��設定→��他→旧設定情報を移行 �手動�移行�る��も��る�)" driveAboutTip: "ドライブ���今��アップロード��ファイル��らー��表示�れる�。
\nノート�ファイルをも�������り����投稿�るファイルを��辺�置�����も��る�ん。
\nファイルを���������ファイルを����全部�場所(ノート�ページ�ア�ター��ナー等)�らも見�ん��る�ら気�����。
\nフォルダを作��整��る��も��る�。" turnItOn: "オン����" turnItOff: "オフ����" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 5b21341ae9d..06c7b27c1e0 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1361,14 +1361,11 @@ information: "정보" chat: "채팅" directMessage: "채팅하기" directMessage_short: "메시지" -migrateOldSettings: "기존 설정 정보를 �전" -migrateOldSettings_description: "보통� ��으로 �루어지지만, 어떤 �유로 �해 성공�으로 �전� �루어지지 않는 경우 수�으로 �전� 실행할 수 있습니다. 현재 설정 정보는 �어쓰게 �니다." compress: "압축" right: "오른쪽" bottom: "아래" top: "위" embed: "임베드" -settingsMigrating: "설정� �전하는 중입니다. 잠시 기다려주십시오... (나중� '환경설정 → 기타 → 기존 설정 정보를 �전'�서 수�으로 �전할 수� 있습니다)" readonly: "�기 전용" goToDeck: "�으로 �아가기" federationJobs: "연합 작업" diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index 436692db3d7..cadbc1e603c 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -1347,14 +1347,11 @@ information: "Sobre" chat: "Conversas" directMessage: "Conversar com usuário" directMessage_short: "Mensagem" -migrateOldSettings: "Migrar configurações antigas de cliente" -migrateOldSettings_description: "Isso deve ser feito automaticamente. Caso o processo de migração tenha falhado, você pode acioná-lo manualmente. As informações atuais de migração serão substituídas." compress: "Comprimir" right: "Direita" bottom: "Inferior" top: "Superior" embed: "Embed" -settingsMigrating: "Configurações estão sendo migradas, aguarde... (Você pode migrar manualmente em Configurações→Outros→Migrar configurações antigas de cliente)" readonly: "Ler apenas" goToDeck: "Voltar ao Deck" federationJobs: "Tarefas de Federação" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 69b8d697885..da1e8659af4 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -1358,14 +1358,11 @@ information: "เ�ี่ยว�ับ" chat: "�ชต" directMessage: "�ชตเลย" directMessage_short: "ข้อความ" -migrateOldSettings: "ย้ายข้อมูล�ารตั้งค่าเ�่า" -migrateOldSettings_description: "โดยป�ติจะทำโดยอัตโนมัติ �ต่หา�ด้วยเหตุผลบางประ�ารที่ไม่สามารถย้ายได้สำเร็จ สามารถสั่งย้ายด้วยตนเองได้ �ารตั้งค่าปัจจุบันจะถู�เขียนทับ" compress: "บีบอัด" right: "ขวา" bottom: "ล่าง" top: "บน" embed: "�ัง" -settingsMigrating: "�ำลังย้าย�ารตั้งค่า �รุณารอสั�ครู่... (สามารถย้ายด้วยตนเองภายหลังได้ที่ �ารตั้งค่า → อื่นๆ → ย้ายข้อมูล�ารตั้งค่าเ�่า)" readonly: "อ่านได้อย่างเดียว" goToDeck: "�ลับไปยังเด็ค" federationJobs: "งานสหพันธ์" diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml index f98d684556e..83a49d3850f 100644 --- a/locales/tr-TR.yml +++ b/locales/tr-TR.yml @@ -1358,14 +1358,11 @@ information: "Hakkında" chat: "Sohbet" directMessage: "Kullanıcıyla sohbet et" directMessage_short: "Mesaj" -migrateOldSettings: "Eski istemci ayarlarını taşıma" -migrateOldSettings_description: "Bu işlem otomatik olarak yapılmalıdır, ancak herhangi bir nedenle geçiş başarısız olursa, geçiş işlemini manuel olarak kendin başlatabilirsin. Mevcut yapılandırma bilgileri üzerine yazılacaktır." compress: "Sıkıştır" right: "Sağ" bottom: "Alt" top: "Üst" embed: "Göm" -settingsMigrating: "Ayarlar taşınıyor, lütfen bir dakika bekle... (Daha sonra Ayarlar→Diğerler→Eski ayarları taşı seçeneğine giderek manuel olarak da taşıyabilirsin)" readonly: "Sadece okuma" goToDeck: "Güverteye Dön" federationJobs: "Federasyon İşleri" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 1cf4b29cd46..ca64191ab6b 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -1314,14 +1314,11 @@ information: "Інформаці�" chat: "Чат" directMessage: "Чат із кори�тувачем" directMessage_short: "Повідомленн�" -migrateOldSettings: "Перене�ти минулі налаштуванн� клієнта" -migrateOldSettings_description: "Це має відбути�� автоматично, але �кщо з �кої�ь причини перене�енн� не вдало��, ви можете запу�тити його вручну. Поточні дані конфігурації буде перезапи�ано." compress: "Сти�нути" right: "Праворуч" bottom: "Зверху" top: "Знизу" embed: "Вбудувати" -settingsMigrating: "�алаштуванн� перено��ть��, зачекайте трохи... (Ви також можете перене�ти їх вручну пізніше: �алаштуванн� → Інше → Перене�ти �тарі налаштуванн�)" readonly: "Лише дл� читанн�" goToDeck: "Повернути�� до Деки" federationJobs: "Завданн� федерації" diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index a9d07a30205..6436fd4c0ad 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -1219,8 +1219,6 @@ paste: "dán" postForm: "Mẫu đăng" information: "Giới thiệu" chat: "Trò chuyện" -migrateOldSettings: "Di chuyển cài đặt cũ" -migrateOldSettings_description: "Thông thư�ng, quá trình này diễn ra tự động, nhưng nếu vì lý do nào đó mà quá trình di chuyển không thành công, bạn có thể kích hoạt thủ công quy trình di chuyển, quá trình này sẽ ghi đè lên thông tin cấu hình hiện tại của bạn." driveAboutTip: "Trong Drive, danh sách các tệp bạn đã tải lên trước đây sẽ được hiển thị.
\nBạn có thể sử dụng lại chúng khi đính kèm vào ghi chú, hoặc tải lên trước các tệp để đăng sau.
\nLưu ý rằng nếu bạn xóa một tệp, tệp đó cũng sẽ biến mất kh�i tất cả những nơi đã sử dụng tệp đó (ghi chú, trang, ảnh đại diện, biểu ngữ, v.v.).
\nBạn cũng có thể tạo các thư mục để sắp xếp chúng." inMinutes: "phút" inDays: "ngày" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index acae660cfbf..f826b716c7b 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1361,14 +1361,11 @@ information: "关于" chat: "�天" directMessage: "�信" directMessage_short: "消�" -migrateOldSettings: "�移旧设置信�" -migrateOldSettings_description: "通常设置信�将自动�移。但如果由于��原因�移��功,则�以手动触��移过程。当�的�置信�将被覆盖。" compress: "压缩" right: "�" bottom: "下" top: "上" embed: "嵌入" -settingsMigrating: "正在�移设置,请�候。(之�也�以在设置 → 其它 → �移旧设置�手动�移)" readonly: "�读" goToDeck: "返回至 Deck" federationJobs: "�邦作业" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 4b99e32f389..59f04cd83c1 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1361,14 +1361,11 @@ information: "關於" chat: "�天" directMessage: "直接訊�" directMessage_short: "訊�" -migrateOldSettings: "�移舊設定資訊" -migrateOldSettings_description: "通常情�下,這會自動進行,但若因�些原因未能順利�移,您�以手動觸發�移處�。請注�,當�的設定資訊將會被覆寫。" compress: "壓縮" right: "�" bottom: "下" top: "上" embed: "嵌入" -settingsMigrating: "正在移轉設定。請�候……(之後也�以到「設定 → 其他 → 舊設定資訊移轉�中手動進行移轉)" readonly: "唯讀" goToDeck: "回到多欄模�" federationJobs: "�邦通訊作業" From 1812f7c11c8244fe8dd6b4cb8c1ebe3f135b3086 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:21:42 +0900 Subject: [PATCH 397/578] chore(gh): tweak workflow --- .github/scripts/frontend-bundle-diagnostics.render-md.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/frontend-bundle-diagnostics.render-md.mts b/.github/scripts/frontend-bundle-diagnostics.render-md.mts index 1e8cf37f24f..efb0a10c85d 100644 --- a/.github/scripts/frontend-bundle-diagnostics.render-md.mts +++ b/.github/scripts/frontend-bundle-diagnostics.render-md.mts @@ -516,7 +516,7 @@ function renderFrontendChunkReport(before: Awaited', + '
', `${formatChunkChangeSummary('Chunk size diff', diffSummary)}`, '', chunkMarkdownTable(diffRows, diffTotal, diffGenerated, diffOther), From 71a50f3d346fe5ecd2482be1fb0d0eafaa18d200 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:21:46 +0900 Subject: [PATCH 398/578] chore(gh): tweak workflow --- .github/scripts/backend-diagnostics.render-md.mts | 4 ++-- .github/scripts/frontend-browser-diagnostics.render-md.mts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/scripts/backend-diagnostics.render-md.mts b/.github/scripts/backend-diagnostics.render-md.mts index e73c22a7222..5a748584e12 100644 --- a/.github/scripts/backend-diagnostics.render-md.mts +++ b/.github/scripts/backend-diagnostics.render-md.mts @@ -111,7 +111,7 @@ function renderHeapSnapshotSection(base: MemoryReport, head: MemoryReport) { for (const graph of [ //heapSnapshotUtil.renderHeapSnapshotSankey(baseHeapSnapshotReport, 'Base'), - heapSnapshotUtil.renderHeapSnapshotSankey(headHeapSnapshotReport, 'Head'), + //heapSnapshotUtil.renderHeapSnapshotSankey(headHeapSnapshotReport, 'Head'), ]) { if (graph == null) continue; lines.push(graph); @@ -149,7 +149,7 @@ if (heapSnapshotSection != null) { const baseHeapSnapshotArtifactUrl = process.env.MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_BASE!.trim(); const headHeapSnapshotArtifactUrl = process.env.MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_HEAD!.trim(); -lines.push(`You can download the representative heap snapshot: [base](${baseHeapSnapshotArtifactUrl}) / [head](${headHeapSnapshotArtifactUrl})`); +lines.push(`Download representative heap snapshot: [base](${baseHeapSnapshotArtifactUrl}) / [head](${headHeapSnapshotArtifactUrl})`); lines.push(''); function getDiffPercent(base: MemoryReport, head: MemoryReport, phase: typeof memoryReportPhases[number]['key'], metric: typeof memoryMetrics[number]) { diff --git a/.github/scripts/frontend-browser-diagnostics.render-md.mts b/.github/scripts/frontend-browser-diagnostics.render-md.mts index 76ff29b9118..c25f3b9a6ef 100644 --- a/.github/scripts/frontend-browser-diagnostics.render-md.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-md.mts @@ -341,8 +341,8 @@ function renderMd(base: BrowserMetricsReport, head: BrowserMetricsReport, option '', heapSnapshotTable ?? '_No V8 heap snapshot data._', '', - heapSnapshotUtil.renderHeapSnapshotSankey(toHeapSnapshotReport(head), 'Head'), - '', + //heapSnapshotUtil.renderHeapSnapshotSankey(toHeapSnapshotReport(head), 'Head'), + //'', `Download representative heap snapshot: [base](${options.baseHeapSnapshotUrl}) / [head](${options.headHeapSnapshotUrl})`, '
', '', From 227268fa1b67f45c7d0c22b44231fb2cf25b2ff7 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:29:47 +0900 Subject: [PATCH 399/578] chore(gh): tweak workflow --- .github/scripts/frontend-bundle-diagnostics.render-md.mts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/scripts/frontend-bundle-diagnostics.render-md.mts b/.github/scripts/frontend-bundle-diagnostics.render-md.mts index efb0a10c85d..a198b46b5c6 100644 --- a/.github/scripts/frontend-bundle-diagnostics.render-md.mts +++ b/.github/scripts/frontend-bundle-diagnostics.render-md.mts @@ -7,8 +7,6 @@ import { promises as fs } from 'node:fs'; import path from 'node:path'; import * as util from './utility.mts'; -const marker = ''; - const locale = 'ja-JP'; //function sharePercent(value, total) { @@ -594,8 +592,6 @@ const afterVisualizerReport = collectVisualizerReport(afterStats); const visualizerArtifactLink = `[Open treemap HTML](${process.env.FRONTEND_BUNDLE_REPORT_ARTIFACT_URL})`; const body = [ - marker, - '', `## 📦 Frontend Bundle Report`, '', renderFrontendChunkReport(before, after), From 65bcca04bea0eb2ae85e9a4a3409baad3d504649 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:58:09 +0900 Subject: [PATCH 400/578] refactor(gh): tweak workflow --- .../scripts/frontend-browser-diagnostics.render-md.mts | 8 ++------ .../scripts/frontend-bundle-diagnostics.render-md.mts | 10 +++------- .github/scripts/utility.mts | 4 ++++ 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/.github/scripts/frontend-browser-diagnostics.render-md.mts b/.github/scripts/frontend-browser-diagnostics.render-md.mts index c25f3b9a6ef..9c3af1a79dc 100644 --- a/.github/scripts/frontend-browser-diagnostics.render-md.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-md.mts @@ -91,10 +91,6 @@ export type BrowserMetricsReport = { samples: BrowserMeasurementSample[]; }; -function escapeCell(value: string) { - return String(value).replaceAll('|', '\\|').replaceAll('\n', '
'); -} - function truncate(value: string, maxLength = 140) { if (value.length <= maxLength) return value; return `${value.slice(0, maxLength - 3)}...`; @@ -278,7 +274,7 @@ function renderLargestRequests(report: BrowserMetricsReport, title: string) { ]; for (const request of report.summary.network.largestRequests.slice(0, 10)) { - lines.push(`| \`${escapeCell(truncate(request.url))}\` | ${escapeCell(request.resourceType)} | ${request.status ?? '-'} | ${util.formatBytes(request.encodedBytes)} | ${util.formatBytes(request.decodedBodyBytes)} |`); + lines.push(`| \`${util.escapeMdTableCell(truncate(request.url))}\` | ${util.escapeMdTableCell(request.resourceType)} | ${request.status ?? '-'} | ${util.formatBytes(request.encodedBytes)} | ${util.formatBytes(request.decodedBodyBytes)} |`); } lines.push('', '
'); @@ -296,7 +292,7 @@ function renderFailedRequests(report: BrowserMetricsReport, title: string) { ]; for (const request of report.summary.network.failedRequests.slice(0, 20)) { - lines.push(`| \`${escapeCell(truncate(request.url))}\` | ${escapeCell(request.resourceType)} | ${request.status ?? '-'} | ${escapeCell(request.errorText ?? '')} |`); + lines.push(`| \`${util.escapeMdTableCell(truncate(request.url))}\` | ${util.escapeMdTableCell(request.resourceType)} | ${request.status ?? '-'} | ${util.escapeMdTableCell(request.errorText ?? '')} |`); } lines.push('', '
'); diff --git a/.github/scripts/frontend-bundle-diagnostics.render-md.mts b/.github/scripts/frontend-bundle-diagnostics.render-md.mts index a198b46b5c6..e6932d450a7 100644 --- a/.github/scripts/frontend-bundle-diagnostics.render-md.mts +++ b/.github/scripts/frontend-bundle-diagnostics.render-md.mts @@ -14,10 +14,6 @@ const locale = 'ja-JP'; // return Math.round((value / total) * 100) + '%'; //} -function escapeCell(value: string) { - return String(value).replaceAll('|', '\\|').replaceAll('\n', '
'); -} - //function tableCell(value) { // return String(value).replaceAll('|', '\\|').replaceAll('\r', ' ').replaceAll('\n', ' '); //} @@ -460,11 +456,11 @@ function chunkMarkdownTable( for (const row of rows) { const chunkFile = chunkFileDisplay(row); if (row.changeType === 'added') { - lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); + lines.push(`|
\`${util.escapeMdTableCell(row.name)}\` \`${util.escapeMdTableCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); } else if (row.changeType === 'removed') { - lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{green}{\\text{( - )}}$ |`); + lines.push(`|
\`${util.escapeMdTableCell(row.name)}\` \`${util.escapeMdTableCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{green}{\\text{( - )}}$ |`); } else { - lines.push(`|
\`${escapeCell(row.name)}\` \`${escapeCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(row.beforeSize, row.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); + lines.push(`|
\`${util.escapeMdTableCell(row.name)}\` \`${util.escapeMdTableCell(chunkFile)}\`
| ${util.formatBytes(row.beforeSize)} | ${util.formatBytes(row.afterSize)} | ${util.calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${util.calcAndFormatDeltaPercent(row.beforeSize, row.afterSize, 0.1).replaceAll('\\%', '\\\\%')} |`); } } if (hasGenerated) { diff --git a/.github/scripts/utility.mts b/.github/scripts/utility.mts index caec5555ef6..e5797d25228 100644 --- a/.github/scripts/utility.mts +++ b/.github/scripts/utility.mts @@ -98,6 +98,10 @@ export function escapeLatex(text: string) { .replaceAll('%', '\\%'); } +export function escapeMdTableCell(value: string) { + return String(value).replaceAll('|', '\\|').replaceAll('\n', '
'); +} + export function formatColoredDelta(delta: number, text: (value: number) => string, colorThreshold = 0) { if (delta === 0) return text(0); const sign = delta > 0 ? '+' : '-'; From 37b4a7a8c44a06696da3fed26d23f78a9e7587df Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 18:06:00 +0900 Subject: [PATCH 401/578] refactor(gh): tweak workflow --- ...frontend-browser-diagnostics.render-md.mts | 83 +++---------------- .../frontend-bundle-diagnostics.render-md.mts | 77 +---------------- .github/scripts/utility.mts | 11 +++ 3 files changed, 23 insertions(+), 148 deletions(-) diff --git a/.github/scripts/frontend-browser-diagnostics.render-md.mts b/.github/scripts/frontend-browser-diagnostics.render-md.mts index 9c3af1a79dc..859caa940ea 100644 --- a/.github/scripts/frontend-browser-diagnostics.render-md.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-md.mts @@ -91,32 +91,16 @@ export type BrowserMetricsReport = { samples: BrowserMeasurementSample[]; }; -function truncate(value: string, maxLength = 140) { - if (value.length <= maxLength) return value; - return `${value.slice(0, maxLength - 3)}...`; -} - -function formatMs(value: number | null | undefined) { - if (value == null || !Number.isFinite(value)) return '-'; - if (value >= 1_000) return `${util.formatNumber(value / 1_000)} s`; - return `${util.formatNumber(value)} ms`; -} - -function formatSecondsAsMs(value: number | null | undefined) { - if (value == null || !Number.isFinite(value)) return '-'; - return formatMs(value * 1_000); -} - function formatDelta(delta: number, formatter: (value: number) => string, colorThreshold = 0) { if (delta === 0) return formatter(0); return util.formatColoredDelta(delta, v => formatter(v), colorThreshold); } -function finiteValues(values: (number | null | undefined)[]) { - return values.filter(value => Number.isFinite(value)) as number[]; -} - function sampleSpread(report: BrowserMetricsReport, getValue: (sample: BrowserMeasurementSample) => number | null | undefined) { + function finiteValues(values: (number | null | undefined)[]) { + return values.filter(value => Number.isFinite(value)) as number[]; + } + const values = finiteValues(report.samples.map(sample => getValue(sample))); if (values.length < 2) return null; @@ -170,7 +154,7 @@ function getMetric(report: BrowserMeasurement, key: string) { function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { const rows = [ - //metricRow('Scenario duration', base, head, summary => summary.durationMs, sample => sample.durationMs, formatMs), + //metricRow('Scenario duration', base, head, summary => summary.durationMs, sample => sample.durationMs, util.formatMs), metricRow('Requests', base, head, summary => summary.network.requestCount, sample => sample.network.requestCount, util.formatNumber, 1, !all), //metricRow('Failed requests', base, head, summary => summary.network.failedRequestCount, sample => sample.network.failedRequestCount, util.formatNumber), metricRow('Encoded network', base, head, summary => summary.network.totalEncodedBytes, sample => sample.network.totalEncodedBytes, util.formatBytes, 10000, !all), @@ -182,11 +166,11 @@ function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsRepo metricRow('Fetch/XHR encoded', base, head, summary => resourceTypeBytes(summary, ['Fetch', 'XHR']), sample => resourceTypeSampleBytes(sample, ['Fetch', 'XHR']), util.formatBytes, 10000, !all), metricRow('Image encoded', base, head, summary => resourceTypeBytes(summary, ['Image']), sample => resourceTypeSampleBytes(sample, ['Image']), util.formatBytes, 10000, !all), metricRow('Font encoded', base, head, summary => resourceTypeBytes(summary, ['Font']), sample => resourceTypeSampleBytes(sample, ['Font']), util.formatBytes, 10000, !all), - //metricRow('First contentful paint', base, head, summary => summary.performance.webVitals.firstContentfulPaintMs, sample => sample.performance.webVitals.firstContentfulPaintMs, formatMs), - //metricRow('Load event end', base, head, summary => summary.performance.webVitals.loadEventEndMs, sample => sample.performance.webVitals.loadEventEndMs, formatMs), + //metricRow('First contentful paint', base, head, summary => summary.performance.webVitals.firstContentfulPaintMs, sample => sample.performance.webVitals.firstContentfulPaintMs, util.formatMs), + //metricRow('Load event end', base, head, summary => summary.performance.webVitals.loadEventEndMs, sample => sample.performance.webVitals.loadEventEndMs, util.formatMs), //metricRow('Long tasks', base, head, summary => summary.performance.webVitals.longTaskCount, sample => sample.performance.webVitals.longTaskCount, util.formatNumber), - //metricRow('Long task duration', base, head, summary => summary.performance.webVitals.longTaskDurationMs, sample => sample.performance.webVitals.longTaskDurationMs, formatMs), - //metricRow('Max long task', base, head, summary => summary.performance.webVitals.maxLongTaskDurationMs, sample => sample.performance.webVitals.maxLongTaskDurationMs, formatMs), + //metricRow('Long task duration', base, head, summary => summary.performance.webVitals.longTaskDurationMs, sample => sample.performance.webVitals.longTaskDurationMs, util.formatMs), + //metricRow('Max long task', base, head, summary => summary.performance.webVitals.maxLongTaskDurationMs, sample => sample.performance.webVitals.maxLongTaskDurationMs, util.formatMs), //metricRow('JS heap used', base, head, summary => summary.performance.runtimeHeap?.usedSize ?? getMetric(summary, 'JSHeapUsedSize'), sample => sample.performance.runtimeHeap?.usedSize ?? getMetric(sample, 'JSHeapUsedSize'), util.formatBytes), //metricRow('JS heap total', base, head, summary => summary.performance.runtimeHeap?.totalSize ?? getMetric(summary, 'JSHeapTotalSize'), sample => sample.performance.runtimeHeap?.totalSize ?? getMetric(sample, 'JSHeapTotalSize'), util.formatBytes), //metricRow('V8 heap snapshot total', base, head, summary => summary.heapSnapshot.categories.total, sample => sample.heapSnapshot.categories.total, util.formatBytes, 10000), @@ -195,8 +179,8 @@ function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsRepo //metricRow('JS event listeners', base, head, summary => getMetric(summary, 'JSEventListeners'), sample => getMetric(sample, 'JSEventListeners'), util.formatNumber), //metricRow('Layout count', base, head, summary => getMetric(summary, 'LayoutCount'), sample => getMetric(sample, 'LayoutCount'), util.formatNumber), //metricRow('Recalc style count', base, head, summary => getMetric(summary, 'RecalcStyleCount'), sample => getMetric(sample, 'RecalcStyleCount'), util.formatNumber), - //metricRow('Script duration', base, head, summary => getMetric(summary, 'ScriptDuration'), sample => getMetric(sample, 'ScriptDuration'), formatSecondsAsMs), - //metricRow('Task duration', base, head, summary => getMetric(summary, 'TaskDuration'), sample => getMetric(sample, 'TaskDuration'), formatSecondsAsMs), + //metricRow('Script duration', base, head, summary => getMetric(summary, 'ScriptDuration'), sample => getMetric(sample, 'ScriptDuration'), util.formatSecondsAsMs), + //metricRow('Task duration', base, head, summary => getMetric(summary, 'TaskDuration'), sample => getMetric(sample, 'TaskDuration'), util.formatSecondsAsMs), metricRow('WebSocket connections', base, head, summary => summary.network.webSocketConnectionCount, sample => sample.network.webSocketConnectionCount, util.formatNumber, 1, !all), metricRow('WebSocket sent', base, head, summary => summary.network.webSocketSentBytes, sample => sample.network.webSocketSentBytes, util.formatBytes, 10000, !all), metricRow('WebSocket received', base, head, summary => summary.network.webSocketReceivedBytes, sample => sample.network.webSocketReceivedBytes, util.formatBytes, 10000, !all), @@ -263,42 +247,6 @@ function renderResourceTypeTable(base: BrowserMetricsReport, head: BrowserMetric return lines.join('\n'); } -function renderLargestRequests(report: BrowserMetricsReport, title: string) { - if (report.summary.network.largestRequests.length === 0) return null; - - const lines = [ - `
${title}`, - '', - '| Resource | Type | Status | Encoded | Decoded |', - '| --- | --- | ---: | ---: | ---: |', - ]; - - for (const request of report.summary.network.largestRequests.slice(0, 10)) { - lines.push(`| \`${util.escapeMdTableCell(truncate(request.url))}\` | ${util.escapeMdTableCell(request.resourceType)} | ${request.status ?? '-'} | ${util.formatBytes(request.encodedBytes)} | ${util.formatBytes(request.decodedBodyBytes)} |`); - } - - lines.push('', '
'); - return lines.join('\n'); -} - -function renderFailedRequests(report: BrowserMetricsReport, title: string) { - if (report.summary.network.failedRequests.length === 0) return null; - - const lines = [ - `
${title}`, - '', - '| Resource | Type | Status | Error |', - '| --- | --- | ---: | --- |', - ]; - - for (const request of report.summary.network.failedRequests.slice(0, 20)) { - lines.push(`| \`${util.escapeMdTableCell(truncate(request.url))}\` | ${util.escapeMdTableCell(request.resourceType)} | ${request.status ?? '-'} | ${util.escapeMdTableCell(request.errorText ?? '')} |`); - } - - lines.push('', '
'); - return lines.join('\n'); -} - function toHeapSnapshotReport(report: BrowserMetricsReport): HeapSnapshotReport { return { summary: report.summary.heapSnapshot, @@ -344,15 +292,6 @@ function renderMd(base: BrowserMetricsReport, head: BrowserMetricsReport, option '', ]; - for (const section of [ - //renderLargestRequests(head, 'Largest representative head requests'), - //renderFailedRequests(base, 'Failed representative base requests'), - //renderFailedRequests(head, 'Failed representative head requests'), - ]) { - if (section == null) continue; - lines.push(section, ''); - } - return lines.filter(line => line != null).join('\n').trimEnd() + '\n'; } diff --git a/.github/scripts/frontend-bundle-diagnostics.render-md.mts b/.github/scripts/frontend-bundle-diagnostics.render-md.mts index e6932d450a7..7e524c82e7b 100644 --- a/.github/scripts/frontend-bundle-diagnostics.render-md.mts +++ b/.github/scripts/frontend-bundle-diagnostics.render-md.mts @@ -9,29 +9,6 @@ import * as util from './utility.mts'; const locale = 'ja-JP'; -//function sharePercent(value, total) { -// if (total === 0) return '0%'; -// return Math.round((value / total) * 100) + '%'; -//} - -//function tableCell(value) { -// return String(value).replaceAll('|', '\\|').replaceAll('\r', ' ').replaceAll('\n', ' '); -//} - -//function code(value) { -// const sanitized = String(value).replaceAll('\r', ' ').replaceAll('\n', ' '); -// const backtickRuns = sanitized.match(/`+/g) ?? []; -// const fenceLength = Math.max(1, ...backtickRuns.map((run) => run.length + 1)); -// const fence = '`'.repeat(fenceLength); -// const padding = sanitized.startsWith('`') || sanitized.endsWith('`') ? ' ' : ''; -// -// return `${fence}${padding}${sanitized}${padding}${fence}`; -//} - -//function tableCode(value) { -// return tableCell(code(value)); -//} - type Manifest = Record; const stableNamedChunks = new Set(['vue', 'i18n']); @@ -505,10 +482,6 @@ function renderFrontendChunkReport(before: Awaited b.sortSize - a.sortSize || a.name.localeCompare(b.name)) - // .slice(0, 30); - return [ '
', `${formatChunkChangeSummary('Chunk size diff', diffSummary)}`, @@ -526,57 +499,9 @@ function renderFrontendChunkReport(before: Awaited', '', - //'
', - //`Largest`, - //'', - //markdownTable(largeRows), - //'', - //'
', - //'', ].join('\n'); } -function renderFrontendBundleReport(before: ReturnType, after: ReturnType) { - const lines = [ - ...renderVisualizerSummaryTable(before, after), - '', - //'
', - //'Top 10', - //'', - ]; - - /* - for (const row of after.hotModules.slice(0, 10)) { - lines.push(`- ${code(row.id)}: ${sharePercent(row.renderedLength, after.metrics.renderedLength)} (${formatBytes(row.renderedLength)})`); - } - - lines.push( - '', - '
', - ); - - lines.push( - '', - '
', - 'Hot Modules (Self Size)', - '', - '| Module | Bundles | Rendered | Share | Gzip | Brotli | Imports | Imported By |', - '|---|---:|---:|---:|---:|---:|---:|---:|', - ); - - for (const row of after.hotModules.slice(0, 15)) { - lines.push(`| ${tableCode(row.id)} | ${row.bundles} | ${formatBytes(row.renderedLength)} | ${sharePercent(row.renderedLength, after.metrics.renderedLength)} | ${formatBytes(row.gzipLength)} | ${formatBytes(row.brotliLength)} | ${row.importedCount} | ${row.importedByCount} |`); - } - - lines.push( - '', - '
', - ); - */ - - return lines.join('\n'); -} - const args = process.argv.slice(2); const [beforeDir, afterDir, beforeStatsFile, afterStatsFile, outFile] = args; const before = await collectReport(beforeDir); @@ -594,7 +519,7 @@ const body = [ '', '## Bundle Stats', '', - renderFrontendBundleReport(beforeVisualizerReport, afterVisualizerReport), + renderVisualizerSummaryTable(beforeVisualizerReport, afterVisualizerReport), '', visualizerArtifactLink, ].join('\n'); diff --git a/.github/scripts/utility.mts b/.github/scripts/utility.mts index e5797d25228..c8d7d2914c1 100644 --- a/.github/scripts/utility.mts +++ b/.github/scripts/utility.mts @@ -102,6 +102,17 @@ export function escapeMdTableCell(value: string) { return String(value).replaceAll('|', '\\|').replaceAll('\n', '
'); } +export function formatMs(value: number | null | undefined) { + if (value == null || !Number.isFinite(value)) return '-'; + if (value >= 1_000) return `${formatNumber(value / 1_000)} s`; + return `${formatNumber(value)} ms`; +} + +export function formatSecondsAsMs(value: number | null | undefined) { + if (value == null || !Number.isFinite(value)) return '-'; + return formatMs(value * 1_000); +} + export function formatColoredDelta(delta: number, text: (value: number) => string, colorThreshold = 0) { if (delta === 0) return text(0); const sign = delta > 0 ? '+' : '-'; From b674da1bc81599771002fecfd1eefe3cdb3a273c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 18:16:44 +0900 Subject: [PATCH 402/578] refactor(gh): tweak workflow --- ...frontend-browser-diagnostics.render-md.mts | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/.github/scripts/frontend-browser-diagnostics.render-md.mts b/.github/scripts/frontend-browser-diagnostics.render-md.mts index 859caa940ea..2cccbd9527b 100644 --- a/.github/scripts/frontend-browser-diagnostics.render-md.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-md.mts @@ -96,20 +96,9 @@ function formatDelta(delta: number, formatter: (value: number) => string, colorT return util.formatColoredDelta(delta, v => formatter(v), colorThreshold); } -function sampleSpread(report: BrowserMetricsReport, getValue: (sample: BrowserMeasurementSample) => number | null | undefined) { - function finiteValues(values: (number | null | undefined)[]) { - return values.filter(value => Number.isFinite(value)) as number[]; - } - - const values = finiteValues(report.samples.map(sample => getValue(sample))); - if (values.length < 2) return null; - - const center = util.median(values); - return util.median(values.map(value => Math.abs(value - center))); -} - function formatValueWithSpread(report: BrowserMetricsReport, value: number, getSampleValue: (sample: BrowserMeasurementSample) => number | null | undefined, formatter: (value: number) => string) { - const spread = sampleSpread(report, getSampleValue); + const values = report.samples.map(sample => getSampleValue(sample)).filter(v => Number.isFinite(v)) as number[]; + const spread = values.length < 2 ? null : util.median(values.map(value => Math.abs(value - util.median(values)))); if (spread == null) return formatter(value); return `${formatter(value)}
± ${formatter(spread)}`; } @@ -148,11 +137,11 @@ function resourceTypeSampleBytes(sample: BrowserMeasurementSample, resourceTypes return resourceTypeBytes(sample, resourceTypes); } -function getMetric(report: BrowserMeasurement, key: string) { - return report.performance.cdpMetrics[key]; -} - function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { + //function getMetric(report: BrowserMeasurement, key: string) { + // return report.performance.cdpMetrics[key]; + //} + const rows = [ //metricRow('Scenario duration', base, head, summary => summary.durationMs, sample => sample.durationMs, util.formatMs), metricRow('Requests', base, head, summary => summary.network.requestCount, sample => sample.network.requestCount, util.formatNumber, 1, !all), From fca7859c89a214a574f3cb9842ea86588c25fe43 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 17 Jul 2026 18:19:41 +0900 Subject: [PATCH 403/578] refactor(gh): tweak workflow --- ...frontend-browser-diagnostics.render-md.mts | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/.github/scripts/frontend-browser-diagnostics.render-md.mts b/.github/scripts/frontend-browser-diagnostics.render-md.mts index 2cccbd9527b..d90c3d32c14 100644 --- a/.github/scripts/frontend-browser-diagnostics.render-md.mts +++ b/.github/scripts/frontend-browser-diagnostics.render-md.mts @@ -91,11 +91,6 @@ export type BrowserMetricsReport = { samples: BrowserMeasurementSample[]; }; -function formatDelta(delta: number, formatter: (value: number) => string, colorThreshold = 0) { - if (delta === 0) return formatter(0); - return util.formatColoredDelta(delta, v => formatter(v), colorThreshold); -} - function formatValueWithSpread(report: BrowserMetricsReport, value: number, getSampleValue: (sample: BrowserMeasurementSample) => number | null | undefined, formatter: (value: number) => string) { const values = report.samples.map(sample => getSampleValue(sample)).filter(v => Number.isFinite(v)) as number[]; const spread = values.length < 2 ? null : util.median(values.map(value => Math.abs(value - util.median(values)))); @@ -103,7 +98,7 @@ function formatValueWithSpread(report: BrowserMetricsReport, value: number, getS return `${formatter(value)}
± ${formatter(spread)}`; } -function metricRow( +function renderMetricRow( label: string, base: BrowserMetricsReport, head: BrowserMetricsReport, @@ -122,11 +117,11 @@ function metricRow( if (skipIfNotSignificant && (Math.abs(summary.median) < significantThreshold)) return null; const percent = baseValue === 0 ? null : summary.median * 100 / baseValue; - //const deltaMedian = `${formatDelta(summary.median, formatter, colorThreshold)}
${percent == null ? '-' : util.formatDeltaPercent(percent, 0.1).replaceAll('\\%', '\\\\%')}`; - const deltaMedian = formatDelta(summary.median, formatter, significantThreshold); + //const deltaMedian = `${util.formatColoredDelta(summary.median, formatter, colorThreshold)}
${percent == null ? '-' : util.formatDeltaPercent(percent, 0.1).replaceAll('\\%', '\\\\%')}`; + const deltaMedian = util.formatColoredDelta(summary.median, formatter, significantThreshold); - //return `| **${label}** | ${formatValueWithSpread(base, baseValue, getSampleValue, formatter)} | ${formatValueWithSpread(head, headValue, getSampleValue, formatter)} | ${deltaMedian} | ${summary == null ? '-' : formatter(summary.mad)} | ${summary == null ? '-' : formatDelta(summary.min, formatter)} | ${summary == null ? '-' : formatDelta(summary.max, formatter)} |`; - return `| **${label}** | ${formatter(baseValue)} | ${formatter(headValue)} | ${deltaMedian} | ${summary == null ? '-' : formatter(summary.mad)} | ${summary == null ? '-' : formatDelta(summary.min, formatter, significantThreshold)} | ${summary == null ? '-' : formatDelta(summary.max, formatter, significantThreshold)} |`; + //return `| **${label}** | ${formatValueWithSpread(base, baseValue, getSampleValue, formatter)} | ${formatValueWithSpread(head, headValue, getSampleValue, formatter)} | ${deltaMedian} | ${summary == null ? '-' : formatter(summary.mad)} | ${summary == null ? '-' : util.formatColoredDelta(summary.min, formatter)} | ${summary == null ? '-' : util.formatColoredDelta(summary.max, formatter)} |`; + return `| **${label}** | ${formatter(baseValue)} | ${formatter(headValue)} | ${deltaMedian} | ${summary == null ? '-' : formatter(summary.mad)} | ${summary == null ? '-' : util.formatColoredDelta(summary.min, formatter, significantThreshold)} | ${summary == null ? '-' : util.formatColoredDelta(summary.max, formatter, significantThreshold)} |`; } function resourceTypeBytes(report: BrowserMeasurement, resourceTypes: string[]) { @@ -144,17 +139,17 @@ function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsRepo const rows = [ //metricRow('Scenario duration', base, head, summary => summary.durationMs, sample => sample.durationMs, util.formatMs), - metricRow('Requests', base, head, summary => summary.network.requestCount, sample => sample.network.requestCount, util.formatNumber, 1, !all), + renderMetricRow('Requests', base, head, summary => summary.network.requestCount, sample => sample.network.requestCount, util.formatNumber, 1, !all), //metricRow('Failed requests', base, head, summary => summary.network.failedRequestCount, sample => sample.network.failedRequestCount, util.formatNumber), - metricRow('Encoded network', base, head, summary => summary.network.totalEncodedBytes, sample => sample.network.totalEncodedBytes, util.formatBytes, 10000, !all), - metricRow('Decoded body', base, head, summary => summary.network.totalDecodedBodyBytes, sample => sample.network.totalDecodedBodyBytes, util.formatBytes, 10000, !all), - metricRow('Same-origin encoded', base, head, summary => summary.network.sameOriginEncodedBytes, sample => sample.network.sameOriginEncodedBytes, util.formatBytes, 10000, !all), - metricRow('Third-party encoded', base, head, summary => summary.network.thirdPartyEncodedBytes, sample => sample.network.thirdPartyEncodedBytes, util.formatBytes, 10000, !all), - metricRow('Script encoded', base, head, summary => resourceTypeBytes(summary, ['Script']), sample => resourceTypeSampleBytes(sample, ['Script']), util.formatBytes, 10000, !all), - metricRow('Stylesheet encoded', base, head, summary => resourceTypeBytes(summary, ['Stylesheet']), sample => resourceTypeSampleBytes(sample, ['Stylesheet']), util.formatBytes, 10000, !all), - metricRow('Fetch/XHR encoded', base, head, summary => resourceTypeBytes(summary, ['Fetch', 'XHR']), sample => resourceTypeSampleBytes(sample, ['Fetch', 'XHR']), util.formatBytes, 10000, !all), - metricRow('Image encoded', base, head, summary => resourceTypeBytes(summary, ['Image']), sample => resourceTypeSampleBytes(sample, ['Image']), util.formatBytes, 10000, !all), - metricRow('Font encoded', base, head, summary => resourceTypeBytes(summary, ['Font']), sample => resourceTypeSampleBytes(sample, ['Font']), util.formatBytes, 10000, !all), + renderMetricRow('Encoded network', base, head, summary => summary.network.totalEncodedBytes, sample => sample.network.totalEncodedBytes, util.formatBytes, 10000, !all), + renderMetricRow('Decoded body', base, head, summary => summary.network.totalDecodedBodyBytes, sample => sample.network.totalDecodedBodyBytes, util.formatBytes, 10000, !all), + renderMetricRow('Same-origin encoded', base, head, summary => summary.network.sameOriginEncodedBytes, sample => sample.network.sameOriginEncodedBytes, util.formatBytes, 10000, !all), + renderMetricRow('Third-party encoded', base, head, summary => summary.network.thirdPartyEncodedBytes, sample => sample.network.thirdPartyEncodedBytes, util.formatBytes, 10000, !all), + renderMetricRow('Script encoded', base, head, summary => resourceTypeBytes(summary, ['Script']), sample => resourceTypeSampleBytes(sample, ['Script']), util.formatBytes, 10000, !all), + renderMetricRow('Stylesheet encoded', base, head, summary => resourceTypeBytes(summary, ['Stylesheet']), sample => resourceTypeSampleBytes(sample, ['Stylesheet']), util.formatBytes, 10000, !all), + renderMetricRow('Fetch/XHR encoded', base, head, summary => resourceTypeBytes(summary, ['Fetch', 'XHR']), sample => resourceTypeSampleBytes(sample, ['Fetch', 'XHR']), util.formatBytes, 10000, !all), + renderMetricRow('Image encoded', base, head, summary => resourceTypeBytes(summary, ['Image']), sample => resourceTypeSampleBytes(sample, ['Image']), util.formatBytes, 10000, !all), + renderMetricRow('Font encoded', base, head, summary => resourceTypeBytes(summary, ['Font']), sample => resourceTypeSampleBytes(sample, ['Font']), util.formatBytes, 10000, !all), //metricRow('First contentful paint', base, head, summary => summary.performance.webVitals.firstContentfulPaintMs, sample => sample.performance.webVitals.firstContentfulPaintMs, util.formatMs), //metricRow('Load event end', base, head, summary => summary.performance.webVitals.loadEventEndMs, sample => sample.performance.webVitals.loadEventEndMs, util.formatMs), //metricRow('Long tasks', base, head, summary => summary.performance.webVitals.longTaskCount, sample => sample.performance.webVitals.longTaskCount, util.formatNumber), @@ -170,15 +165,15 @@ function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsRepo //metricRow('Recalc style count', base, head, summary => getMetric(summary, 'RecalcStyleCount'), sample => getMetric(sample, 'RecalcStyleCount'), util.formatNumber), //metricRow('Script duration', base, head, summary => getMetric(summary, 'ScriptDuration'), sample => getMetric(sample, 'ScriptDuration'), util.formatSecondsAsMs), //metricRow('Task duration', base, head, summary => getMetric(summary, 'TaskDuration'), sample => getMetric(sample, 'TaskDuration'), util.formatSecondsAsMs), - metricRow('WebSocket connections', base, head, summary => summary.network.webSocketConnectionCount, sample => sample.network.webSocketConnectionCount, util.formatNumber, 1, !all), - metricRow('WebSocket sent', base, head, summary => summary.network.webSocketSentBytes, sample => sample.network.webSocketSentBytes, util.formatBytes, 10000, !all), - metricRow('WebSocket received', base, head, summary => summary.network.webSocketReceivedBytes, sample => sample.network.webSocketReceivedBytes, util.formatBytes, 10000, !all), - metricRow('Page errors', base, head, summary => summary.diagnostics.pageErrorCount, sample => sample.diagnostics.pageErrorCount, util.formatNumber, 1, !all), - metricRow('Console log', base, head, summary => summary.diagnostics.console.log, sample => sample.diagnostics.console.log, util.formatNumber, 1, !all), - metricRow('Console warnings', base, head, summary => summary.diagnostics.console.warning, sample => sample.diagnostics.console.warning, util.formatNumber, 1, !all), - metricRow('Console errors', base, head, summary => summary.diagnostics.console.error, sample => sample.diagnostics.console.error, util.formatNumber, 1, !all), - metricRow('Console info', base, head, summary => summary.diagnostics.console.info, sample => sample.diagnostics.console.info, util.formatNumber, 1, !all), - metricRow('Page-attributed memory', base, head, summary => summary.performance.tabMemory.totalBytes, sample => sample.performance.tabMemory.totalBytes, util.formatBytes, 10000, !all), + renderMetricRow('WebSocket connections', base, head, summary => summary.network.webSocketConnectionCount, sample => sample.network.webSocketConnectionCount, util.formatNumber, 1, !all), + renderMetricRow('WebSocket sent', base, head, summary => summary.network.webSocketSentBytes, sample => sample.network.webSocketSentBytes, util.formatBytes, 10000, !all), + renderMetricRow('WebSocket received', base, head, summary => summary.network.webSocketReceivedBytes, sample => sample.network.webSocketReceivedBytes, util.formatBytes, 10000, !all), + renderMetricRow('Page errors', base, head, summary => summary.diagnostics.pageErrorCount, sample => sample.diagnostics.pageErrorCount, util.formatNumber, 1, !all), + renderMetricRow('Console log', base, head, summary => summary.diagnostics.console.log, sample => sample.diagnostics.console.log, util.formatNumber, 1, !all), + renderMetricRow('Console warnings', base, head, summary => summary.diagnostics.console.warning, sample => sample.diagnostics.console.warning, util.formatNumber, 1, !all), + renderMetricRow('Console errors', base, head, summary => summary.diagnostics.console.error, sample => sample.diagnostics.console.error, util.formatNumber, 1, !all), + renderMetricRow('Console info', base, head, summary => summary.diagnostics.console.info, sample => sample.diagnostics.console.info, util.formatNumber, 1, !all), + renderMetricRow('Page-attributed memory', base, head, summary => summary.performance.tabMemory.totalBytes, sample => sample.performance.tabMemory.totalBytes, util.formatBytes, 10000, !all), ].filter(row => row != null); return [ @@ -223,10 +218,10 @@ function renderResourceTypeTable(base: BrowserMetricsReport, head: BrowserMetric lines.push(`${key}`); lines.push(`${util.formatNumber(baseRow.requests)}`); lines.push(`${util.formatNumber(headRow.requests)}`); - lines.push(`${formatDelta(headRow.requests - baseRow.requests, util.formatNumber)}`); + lines.push(`${util.formatColoredDelta(headRow.requests - baseRow.requests, util.formatNumber)}`); lines.push(`${util.formatBytes(baseRow.encodedBytes)}`); lines.push(`${util.formatBytes(headRow.encodedBytes)}`); - lines.push(`${formatDelta(headRow.encodedBytes - baseRow.encodedBytes, util.formatBytes)}`); + lines.push(`${util.formatColoredDelta(headRow.encodedBytes - baseRow.encodedBytes, util.formatBytes)}`); lines.push(''); } From bdf1547a42360830c833bfadef3937de3897c1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 18 Jul 2026 23:04:21 +0900 Subject: [PATCH 404/578] =?UTF-8?q?refactor(frontend):=20=E3=83=A1?= =?UTF-8?q?=E3=83=87=E3=82=A3=E3=82=A2=E3=83=A1=E3=83=8B=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E3=81=AE=E3=83=A1=E3=83=8B=E3=83=A5=E3=83=BC=E3=83=9C=E3=82=BF?= =?UTF-8?q?=E3=83=B3=E3=81=AE=E3=82=B9=E3=82=BF=E3=82=A4=E3=83=AB=E3=82=92?= =?UTF-8?q?=E7=B5=B1=E4=B8=80=20(#17742)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix * fix * refactor --- .../frontend/src/components/MkMediaImage.vue | 32 +++++++------------ .../frontend/src/components/MkMediaVideo.vue | 24 +++++--------- 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index 01f449753bf..dee6db5e261 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -61,8 +61,8 @@ SPDX-License-Identifier: AGPL-3.0-only
ALT
- - + + @@ -174,23 +174,6 @@ function onContextmenu(ev: PointerEvent) { cursor: pointer; } -.hide { - display: block; - position: absolute; - background-color: rgba(0, 0, 0, 0.3); - -webkit-backdrop-filter: var(--MI-blur, blur(15px)); - backdrop-filter: var(--MI-blur, blur(15px)); - border-radius: 0 0 0 9px; - color: #fff; - font-size: 12px; - opacity: .5; - padding: 5px 8px; - text-align: center; - cursor: pointer; - top: 0; - right: 0; -} - .hiddenTextWrapper { display: table-cell; text-align: center; @@ -221,16 +204,25 @@ html[data-color-scheme=light] .visible { background-color: rgba(0, 0, 0, 0.3); -webkit-backdrop-filter: var(--MI-blur, blur(15px)); backdrop-filter: var(--MI-blur, blur(15px)); - border-radius: 9px 0 0 0; color: #fff; font-size: 0.8em; width: 28px; height: 28px; text-align: center; +} + +.menuBottom { + border-radius: 8px 0 8px 0; bottom: 0; right: 0; } +.menuTop { + border-radius: 0 8px 0 8px; + top: 0; + right: 0; +} + .imageContainer { display: block; overflow: hidden; diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue index a03b58d4794..d9d02b0afea 100644 --- a/packages/frontend/src/components/MkMediaVideo.vue +++ b/packages/frontend/src/components/MkMediaVideo.vue @@ -42,8 +42,8 @@ SPDX-License-Identifier: AGPL-3.0-only - - + + @@ -184,29 +184,21 @@ function onContextmenu(ev: PointerEvent) { background-color: rgba(0, 0, 0, 0.3); -webkit-backdrop-filter: var(--MI-blur, blur(15px)); backdrop-filter: var(--MI-blur, blur(15px)); - border-radius: 9px 0 0 0; color: #fff; font-size: 0.8em; width: 28px; height: 28px; text-align: center; +} + +.menuBottom { + border-radius: 8px 0 8px 0; bottom: 0; right: 0; } -.hide { - display: block; - position: absolute; - background-color: rgba(0, 0, 0, 0.3); - -webkit-backdrop-filter: var(--MI-blur, blur(15px)); - backdrop-filter: var(--MI-blur, blur(15px)); - border-radius: 0 0 0 9px; - color: #fff; - font-size: 12px; - opacity: .5; - padding: 5px 8px; - text-align: center; - cursor: pointer; +.menuTop { + border-radius: 0 8px 0 8px; top: 0; right: 0; } From 95de10ee653f2ea7b51ea5c365e1249322821ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 20 Jul 2026 08:19:18 +0900 Subject: [PATCH 405/578] fix(backend): fix dev mode --- packages/backend/rolldown.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/rolldown.config.ts b/packages/backend/rolldown.config.ts index e6a9888a097..768c3afc037 100644 --- a/packages/backend/rolldown.config.ts +++ b/packages/backend/rolldown.config.ts @@ -160,7 +160,7 @@ export default defineConfig((args) => { clearScreen: false, }, // ビルド�高速化�����watchモード����外部モジュール�全��ンドル���よ���る - external: isWatchMode ? /^(?!@\/)[^.\/](?!:[\/\\])/ : externalModules, + external: isWatchMode ? /^(?!@\/|\0)[^.\/](?!:[\/\\])/ : externalModules, }; } }); From 9eca9b6f0d719c5cec9aa4294985ae63dffbda2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:58:07 +0900 Subject: [PATCH 406/578] =?UTF-8?q?fix(frontend):=20MkLightbox=E3=82=92?= =?UTF-8?q?=E4=B8=8A=E4=B8=8B=E6=96=B9=E5=90=91=E3=81=AB=E3=82=B9=E3=83=AF?= =?UTF-8?q?=E3=82=A4=E3=83=97=E3=81=97=E3=81=A6=E9=96=89=E3=81=98=E3=82=8B?= =?UTF-8?q?=E3=81=93=E3=81=A8=E3=81=8C=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=81=93=E3=81=A8=E3=81=8C=E3=81=82=E3=82=8B=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#17740)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(frontend): MkLightboxを上下方��スワイプ��閉�る�����������る�題を修正 * fix * fix * fix * fix * fix * fix * fix * review fixes --- .../src/components/MkLightbox.item.vue | 127 ++++++++++++++---- .../frontend/src/components/MkLightbox.vue | 12 +- .../frontend/src/components/MkMediaImage.vue | 6 +- .../frontend/src/components/MkMediaVideo.vue | 7 +- 4 files changed, 115 insertions(+), 37 deletions(-) diff --git a/packages/frontend/src/components/MkLightbox.item.vue b/packages/frontend/src/components/MkLightbox.item.vue index eb7f5810190..5870652d25c 100644 --- a/packages/frontend/src/components/MkLightbox.item.vue +++ b/packages/frontend/src/components/MkLightbox.item.vue @@ -127,7 +127,6 @@ SPDX-License-Identifier: AGPL-3.0-only '; + + const html = renderHtml(base, head); + + expect(html).not.toContain(''); + expect(html).toContain('<script>alert(1)</script>'); +}); diff --git a/packages-private/diagnostics-frontend-browser/tsconfig.json b/packages-private/diagnostics-frontend-browser/tsconfig.json new file mode 100644 index 00000000000..6672c40acb3 --- /dev/null +++ b/packages-private/diagnostics-frontend-browser/tsconfig.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "esModuleInterop": true, + "skipLibCheck": true, + "noEmit": true, + "types": ["node"] + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ], + "exclude": [] +} diff --git a/packages-private/diagnostics-frontend-bundle/eslint.config.js b/packages-private/diagnostics-frontend-bundle/eslint.config.js new file mode 100644 index 00000000000..11bc648243d --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/eslint.config.js @@ -0,0 +1,25 @@ +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../../packages/shared/eslint.config.js'; + +// eslint-disable-next-line import/no-default-export +export default [ + ...sharedConfig, + { + ignores: [ + '**/node_modules', + '**/__snapshots__', + 'test/fixtures', + ], + }, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]; diff --git a/packages-private/diagnostics-frontend-bundle/package.json b/packages-private/diagnostics-frontend-bundle/package.json new file mode 100644 index 00000000000..b0271a81015 --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/package.json @@ -0,0 +1,22 @@ +{ + "name": "diagnostics-frontend-bundle", + "private": true, + "type": "module", + "scripts": { + "eslint": "eslint './**/*.{js,jsx,ts,tsx}'", + "lint": "pnpm typecheck && pnpm eslint", + "render-md": "tsx src/render-md.ts", + "test": "vitest run", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "diagnostics-shared": "workspace:*" + }, + "devDependencies": { + "@types/node": "26.1.1", + "tsx": "4.23.1", + "typescript": "5.9.3", + "vite": "8.1.4", + "vitest": "4.1.10" + } +} diff --git a/packages-private/diagnostics-frontend-bundle/src/chunk-report.ts b/packages-private/diagnostics-frontend-bundle/src/chunk-report.ts new file mode 100644 index 00000000000..2b2492377c0 --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/src/chunk-report.ts @@ -0,0 +1,217 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { + calcAndFormatDeltaBytes, + calcAndFormatDeltaPercentInMdTable, + escapeMdTableCell, + formatBytes, +} from 'diagnostics-shared/format'; +import type { CollectedReport, FileEntry } from './manifest'; + +/** + * ��差分以下��ャンク�個別�出�� `(other)` ����る。 + * �ッシュ文字列��れ等�サイズ�数�イト動����行�ノイズ��る��。 + */ +const smallDeltaThreshold = 5; + +/** diff表�個別行���出�上�。�れを超��分� `(other)` �集約�る */ +const diffRowLimit = 30; + +function entryDisplayName(entry: FileEntry | undefined) { + if (entry == null) return ''; + return entry.displayName || entry.file; +} + +export function getChunkComparisonRows(keys: string[], before: Partial>, after: Partial>) { + return keys.map(key => { + const beforeEntry = before[key]; + const afterEntry = after[key]; + const beforeSize = beforeEntry?.size ?? 0; + const afterSize = afterEntry?.size ?? 0; + return { + key, + name: entryDisplayName(beforeEntry ?? afterEntry), + beforeFile: beforeEntry?.file, + afterFile: afterEntry?.file, + beforeSize, + afterSize, + changeType: beforeEntry == null ? 'added' : afterEntry == null ? 'removed' : beforeSize !== afterSize ? 'updated' : 'unchanged', + sortSize: Math.max(beforeSize, afterSize), + }; + }); +} + +export type ChunkComparisonRow = ReturnType[number]; + +export type ChunkAggregate = { + beforeSize: number; + afterSize: number; + beforeCount: number; + afterCount: number; +}; + +export function sumChunkSizes(chunks: FileEntry[]) { + return chunks.reduce((sum, chunk) => sum + chunk.size, 0); +} + +/** + * 比較キーを���� (= before/after �対応付�����) �ャンク��計。 + */ +export function generatedAggregate(before: FileEntry[], after: FileEntry[]): ChunkAggregate { + const beforeGenerated = before.filter(chunk => chunk.comparisonKey == null); + const afterGenerated = after.filter(chunk => chunk.comparisonKey == null); + return { + beforeSize: sumChunkSizes(beforeGenerated), + afterSize: sumChunkSizes(afterGenerated), + beforeCount: beforeGenerated.length, + afterCount: afterGenerated.length, + }; +} + +export function hasSmallDelta(row: ChunkComparisonRow) { + return Math.abs(row.afterSize - row.beforeSize) <= smallDeltaThreshold; +} + +export function comparisonRowsAggregate(rows: ChunkComparisonRow[]): ChunkAggregate { + return { + beforeSize: rows.reduce((sum, row) => sum + row.beforeSize, 0), + afterSize: rows.reduce((sum, row) => sum + row.afterSize, 0), + beforeCount: rows.filter(row => row.beforeFile != null).length, + afterCount: rows.filter(row => row.afterFile != null).length, + }; +} + +export function comparableMap(chunks: FileEntry[]) { + const entries: [string, FileEntry][] = []; + for (const chunk of chunks) { + if (chunk.comparisonKey != null) entries.push([chunk.comparisonKey, chunk]); + } + return Object.fromEntries(entries); +} + +export function summarizeChunkChanges(rows: ChunkComparisonRow[]) { + return { + updated: rows.filter((row) => row.changeType === 'updated').length, + added: rows.filter((row) => row.changeType === 'added').length, + removed: rows.filter((row) => row.changeType === 'removed').length, + }; +} + +export function formatChunkChangeSummary(label: string, summary: ReturnType) { + return `${label} (${summary.updated} updated, ${summary.added} added, ${summary.removed} removed)`; +} + +/** + * 差分�絶対値�大��順。���増加�・元サイズ・���順�決定的�並�る。 + */ +export function compareChunkComparisonRows(a: ChunkComparisonRow, b: ChunkComparisonRow) { + return Math.abs(b.afterSize - b.beforeSize) - Math.abs(a.afterSize - a.beforeSize) + || (b.afterSize - b.beforeSize) - (a.afterSize - a.beforeSize) + || b.sortSize - a.sortSize + || a.name.localeCompare(b.name); +} + +export function chunkFileDisplay(row: ChunkComparisonRow) { + if (row.beforeFile == null) return row.afterFile ?? ''; + if (row.afterFile == null || row.beforeFile === row.afterFile) return row.beforeFile; + return `${row.beforeFile} → ${row.afterFile}`; +} + +export function chunkMarkdownTable( + rows: ChunkComparisonRow[], + total?: { beforeSize: number; afterSize: number }, + generated?: ChunkAggregate, + other?: ChunkAggregate, +) { + const hasGenerated = generated != null && (generated.beforeCount > 0 || generated.afterCount > 0); + const hasOther = other != null && (other.beforeCount > 0 || other.afterCount > 0); + if (rows.length === 0 && total == null && !hasGenerated && !hasOther) return '_No data_'; + + const lines = [ + '| Chunk | Before | After | Δ | Δ (%) |', + '| --- | ---: | ---: | ---: | ---: |', + ]; + if (total != null) { + lines.push(`| (total) | ${formatBytes(total.beforeSize)} | ${formatBytes(total.afterSize)} | ${calcAndFormatDeltaBytes(total.beforeSize, total.afterSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(total.beforeSize, total.afterSize, 0.1)} |`); + lines.push('| | | | | |'); + } + + for (const row of rows) { + const chunkFile = chunkFileDisplay(row); + if (row.changeType === 'added') { + lines.push(`|
\`${escapeMdTableCell(row.name)}\` \`${escapeMdTableCell(chunkFile)}\`
| ${formatBytes(row.beforeSize)} | ${formatBytes(row.afterSize)} | ${calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); + } else if (row.changeType === 'removed') { + lines.push(`|
\`${escapeMdTableCell(row.name)}\` \`${escapeMdTableCell(chunkFile)}\`
| ${formatBytes(row.beforeSize)} | ${formatBytes(row.afterSize)} | ${calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{green}{\\text{( - )}}$ |`); + } else { + lines.push(`|
\`${escapeMdTableCell(row.name)}\` \`${escapeMdTableCell(chunkFile)}\`
| ${formatBytes(row.beforeSize)} | ${formatBytes(row.afterSize)} | ${calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(row.beforeSize, row.afterSize, 0.1)} |`); + } + } + if (hasGenerated) { + lines.push(`| (other generated chunks) | ${formatBytes(generated.beforeSize)} | ${formatBytes(generated.afterSize)} | ${calcAndFormatDeltaBytes(generated.beforeSize, generated.afterSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(generated.beforeSize, generated.afterSize, 0.1)} |`); + } + if (hasOther) { + lines.push(`| (other) | ${formatBytes(other.beforeSize)} | ${formatBytes(other.afterSize)} | ${calcAndFormatDeltaBytes(other.beforeSize, other.afterSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(other.beforeSize, other.afterSize, 0.1)} |`); + } + return lines.join('\n'); +} + +export function renderFrontendChunkReport(before: CollectedReport, after: CollectedReport) { + const beforeComparable = before.comparableChunks; + const afterComparable = after.comparableChunks; + const allChunkKeys = [...new Set([...Object.keys(beforeComparable), ...Object.keys(afterComparable)])]; + const allComparisonRows = getChunkComparisonRows(allChunkKeys, beforeComparable, afterComparable); + + const changedRows = allComparisonRows.filter((row) => row.changeType !== 'unchanged'); + const diffSummary = summarizeChunkChanges(changedRows); + const diffTotal = { + beforeSize: sumChunkSizes(before.chunks), + afterSize: sumChunkSizes(after.chunks), + }; + const diffGenerated = generatedAggregate(before.chunks, after.chunks); + const largeDeltaRows = changedRows.filter(row => !hasSmallDelta(row)).sort(compareChunkComparisonRows); + const diffRows = largeDeltaRows.slice(0, diffRowLimit); + // 表示上��切り���行も `(other)` ���る。�����計�実際�変化�������る + const diffOther = comparisonRowsAggregate([ + ...changedRows.filter(hasSmallDelta), + ...largeDeltaRows.slice(diffRowLimit), + ]); + + const beforeStartupFiles = new Set(before.startupFiles); + const afterStartupFiles = new Set(after.startupFiles); + const beforeStartupChunks = before.chunks.filter(chunk => beforeStartupFiles.has(chunk.file)); + const afterStartupChunks = after.chunks.filter(chunk => afterStartupFiles.has(chunk.file)); + const beforeStartupComparable = comparableMap(beforeStartupChunks); + const afterStartupComparable = comparableMap(afterStartupChunks); + const startupKeys = [...new Set([...Object.keys(beforeStartupComparable), ...Object.keys(afterStartupComparable)])]; + const startupComparisonRows = getChunkComparisonRows(startupKeys, beforeStartupComparable, afterStartupComparable); + const startupSummary = summarizeChunkChanges(startupComparisonRows); + const startupOther = comparisonRowsAggregate(startupComparisonRows.filter(hasSmallDelta)); + const startupRows = startupComparisonRows.filter(row => !hasSmallDelta(row)).sort(compareChunkComparisonRows); + const startupTotal = { + beforeSize: sumChunkSizes(beforeStartupChunks), + afterSize: sumChunkSizes(afterStartupChunks), + }; + const startupGenerated = generatedAggregate(beforeStartupChunks, afterStartupChunks); + + return [ + '
', + `${formatChunkChangeSummary('Chunk size diff', diffSummary)}`, + '', + chunkMarkdownTable(diffRows, diffTotal, diffGenerated, diffOther), + '', + '
', + '', + '
', + `${formatChunkChangeSummary('Startup chunk size', startupSummary)}`, + '', + chunkMarkdownTable(startupRows, startupTotal, startupGenerated, startupOther), + '', + '_Startup chunks are the Vite entry for \`src/_boot_.ts\` and its static imports._', + '', + '
', + '', + ].join('\n'); +} diff --git a/packages-private/diagnostics-frontend-bundle/src/fs-utils.ts b/packages-private/diagnostics-frontend-bundle/src/fs-utils.ts new file mode 100644 index 00000000000..74ed757b53f --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/src/fs-utils.ts @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { promises as fs } from 'node:fs'; +import path from 'node:path'; + +/** + * Windows � `\` 区切りを `/` ���る。manifest ��キー�常� `/` 区切り���� + * 実ファイルパス������る��正�化�る必���る。 + */ +export function normalizePath(filePath: string) { + return filePath.split(path.sep).join('/'); +} + +export async function fileExists(filePath: string) { + try { + await fs.access(filePath); + return true; + } catch { + return false; + } +} + +export async function fileSize(filePath: string) { + const stat = await fs.stat(filePath); + return stat.size; +} + +export async function* traverseDirectory(dir: string): AsyncGenerator { + for (const entry of await fs.readdir(dir, { withFileTypes: true })) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + yield* traverseDirectory(fullPath); + } else if (entry.isFile()) { + yield fullPath; + } + } +} diff --git a/packages-private/diagnostics-frontend-bundle/src/manifest.ts b/packages-private/diagnostics-frontend-bundle/src/manifest.ts new file mode 100644 index 00000000000..d35a5cfbfb3 --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/src/manifest.ts @@ -0,0 +1,171 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { promises as fs } from 'node:fs'; +import path from 'node:path'; +import { fileExists, fileSize, normalizePath, traverseDirectory } from './fs-utils'; +import type { Manifest, ManifestChunk } from 'vite'; + +/** + * 比較対象��るロケール。ロケール別�ャンク�全ロケール分��数�多��る��� + * 代表��� ja-JP ��を見る。 + */ +const locale = 'ja-JP'; + +/** + * `src` を�����ャンク�������ビルド間�安定����比較�能�も�。 + */ +const stableNamedChunks = new Set(['vue', 'i18n']); + +export type FileEntry = { + comparisonKey: string | null; + displayName: string; + file: string; + manifestKeys: string[]; + size: number; +}; + +export type CollectedReport = { + manifest: Manifest; + chunks: FileEntry[]; + comparableChunks: Record; + chunksByManifestKey: Record; + startupFiles: string[]; +}; + +export function findEntryKey(manifest: Manifest) { + const entries = Object.entries(manifest); + return entries.find(([key, chunk]) => key === 'src/_boot_.ts' || chunk.src === 'src/_boot_.ts')?.[0] + ?? entries.find(([, chunk]) => chunk.name === 'entry' && chunk.isEntry)?.[0] + ?? entries.find(([, chunk]) => chunk.isEntry)?.[0] + ?? null; +} + +/** + * ビルド間�安定�る�ャンク識別�。出力ファイル���ッシュ付��毎回変�る��� + * �れ��れ���ャンク� before/after �対応付������。 + */ +export function stableChunkKey(chunk: ManifestChunk) { + if (chunk.src != null) return `src:${normalizePath(chunk.src)}`; + if (chunk.name != null && stableNamedChunks.has(chunk.name)) return `named:${chunk.name}`; + return null; +} + +/** + * 起動時�必�読�込�れる�ャンク (entry ����的 import) � manifest キーを集�る。 + */ +export function collectStartupManifestKeys(manifest: Manifest) { + const entryKey = findEntryKey(manifest); + const keys = new Set(); + if (entryKey == null) throw new Error('Unable to find frontend startup entry in Vite manifest.'); + + function visit(key: string, importedBy?: string) { + if (keys.has(key)) return; + const chunk = manifest[key]; + const importContext = importedBy == null ? '' : ` imported by "${importedBy}"`; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (chunk == null) throw new Error(`Startup manifest key "${key}"${importContext} is missing.`); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (chunk.file == null || chunk.file.length === 0) throw new Error(`Startup manifest key "${key}"${importContext} has no output file.`); + if (!chunk.file.endsWith('.js')) throw new Error(`Startup manifest key "${key}"${importContext} resolves to non-JavaScript output "${chunk.file}".`); + keys.add(key); + for (const importKey of chunk.imports ?? []) visit(importKey, key); + } + + visit(entryKey); + return keys; +} + +/** + * manifest 上�出力パスを実ファイル�解決�る。`scripts/` �下�ロケール別� + * 複製�れ�出力�れる���代表ロケール�も��読�替�る。 + */ +export async function resolveBuiltFile(outDir: string, file: string) { + if (file.startsWith('scripts/')) { + const localizedFile = file.slice('scripts/'.length); + const localizedPath = path.join(outDir, locale, localizedFile); + if (await fileExists(localizedPath)) { + return { + absolutePath: localizedPath, + relativePath: `${locale}/${localizedFile}`, + }; + } + + throw new Error(`Expected ${locale} localized chunk for ${file}, but ${localizedPath} was not found.`); + } + return { + absolutePath: path.join(outDir, file), + relativePath: file, + }; +} + +export async function collectReport(repoDir: string): Promise { + const outDir = path.join(repoDir, 'built/_frontend_vite_'); + const manifestPath = path.join(outDir, 'manifest.json'); + const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')) as Manifest; + const chunksByFile = new Map(); + const comparableChunks = new Map(); + const chunksByManifestKey = new Map(); + + for (const [manifestKey, chunk] of Object.entries(manifest)) { + if (!chunk.file.endsWith('.js')) continue; + const builtFile = await resolveBuiltFile(outDir, chunk.file); + const comparisonKey = stableChunkKey(chunk); + let entry = chunksByFile.get(builtFile.relativePath); + if (entry == null) { + entry = { + comparisonKey, + displayName: chunk.src ?? chunk.name ?? manifestKey, + file: builtFile.relativePath, + manifestKeys: [manifestKey], + size: await fileSize(builtFile.absolutePath), + }; + chunksByFile.set(entry.file, entry); + } else if (entry.comparisonKey !== comparisonKey) { + throw new Error(`Conflicting identities for ${entry.file}`); + } else { + entry.manifestKeys.push(manifestKey); + } + chunksByManifestKey.set(manifestKey, entry); + if (comparisonKey != null) { + const existing = comparableChunks.get(comparisonKey); + if (existing != null && existing.file !== entry.file) { + throw new Error(`Duplicate stable chunk key "${comparisonKey}": ${existing.file}, ${entry.file}`); + } + comparableChunks.set(comparisonKey, entry); + } + } + + // manifest �載ら��ロケール別�ャンクも�計サイズ��������拾���� + const localeDir = path.join(outDir, locale); + if (await fileExists(localeDir)) { + for await (const fullPath of traverseDirectory(localeDir)) { + if (!fullPath.endsWith('.js')) continue; + const relativePath = normalizePath(path.relative(outDir, fullPath)); + if (chunksByFile.has(relativePath)) continue; + chunksByFile.set(relativePath, { + comparisonKey: null, + displayName: relativePath, + file: relativePath, + manifestKeys: [], + size: await fileSize(fullPath), + }); + } + } + + const startupFiles = new Set(); + for (const manifestKey of collectStartupManifestKeys(manifest)) { + const entry = chunksByManifestKey.get(manifestKey); + if (entry != null) startupFiles.add(entry.file); + } + + return { + manifest, + chunks: [...chunksByFile.values()], + comparableChunks: Object.fromEntries(comparableChunks), + chunksByManifestKey: Object.fromEntries(chunksByManifestKey), + startupFiles: [...startupFiles], + }; +} diff --git a/packages-private/diagnostics-frontend-bundle/src/render-md.ts b/packages-private/diagnostics-frontend-bundle/src/render-md.ts new file mode 100644 index 00000000000..d8fe0997dd5 --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/src/render-md.ts @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { promises as fs } from 'node:fs'; +import path from 'node:path'; +import { readRequiredEnv } from 'diagnostics-shared/env'; +import { collectReport } from './manifest'; +import { renderBundleReportMarkdown } from './report'; +import type { VisualizerReport } from './visualizer'; + +async function main() { + const [beforeDir, afterDir, beforeStatsFile, afterStatsFile, outFile] = process.argv.slice(2).map(arg => path.resolve(arg)); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (outFile == null) throw new Error('Usage: render-md '); + + // 未設定��� `undefined` ���文字列をコメント�埋�込���よ�������� + const visualizerArtifactUrl = readRequiredEnv('FRONTEND_BUNDLE_REPORT_ARTIFACT_URL'); + + const before = await collectReport(beforeDir); + const after = await collectReport(afterDir); + const beforeStats = JSON.parse(await fs.readFile(beforeStatsFile, 'utf8')) as VisualizerReport; + const afterStats = JSON.parse(await fs.readFile(afterStatsFile, 'utf8')) as VisualizerReport; + + await fs.writeFile(outFile, renderBundleReportMarkdown(before, after, beforeStats, afterStats, { visualizerArtifactUrl })); +} + +await main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/packages-private/diagnostics-frontend-bundle/src/report.ts b/packages-private/diagnostics-frontend-bundle/src/report.ts new file mode 100644 index 00000000000..db2e1cf6e3f --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/src/report.ts @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { renderFrontendChunkReport } from './chunk-report'; +import { collectVisualizerReport, renderVisualizerSummaryTable, type VisualizerReport } from './visualizer'; +import type { CollectedReport } from './manifest'; + +export type RenderBundleReportOptions = { + /** rollup-plugin-visualizer �出力��treemap HTML�artifact URL */ + visualizerArtifactUrl: string; +}; + +export function renderBundleReportMarkdown( + before: CollectedReport, + after: CollectedReport, + beforeStats: VisualizerReport, + afterStats: VisualizerReport, + options: RenderBundleReportOptions, +) { + return [ + '## 📦 Frontend Bundle Report', + '', + renderFrontendChunkReport(before, after), + '', + '## Bundle Stats', + '', + renderVisualizerSummaryTable(collectVisualizerReport(beforeStats), collectVisualizerReport(afterStats)), + '', + `[Open treemap HTML](${options.visualizerArtifactUrl})`, + ].join('\n'); +} diff --git a/packages-private/diagnostics-frontend-bundle/src/visualizer.ts b/packages-private/diagnostics-frontend-bundle/src/visualizer.ts new file mode 100644 index 00000000000..17e4f190b68 --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/src/visualizer.ts @@ -0,0 +1,204 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { + calcAndFormatDeltaBytes, + calcAndFormatDeltaNumber, + calcAndFormatDeltaPercent, + formatBytes, + formatNumber, +} from 'diagnostics-shared/format'; + +/** + * rollup-plugin-visualizer �出力�る `stats.json` �������使�部分���型。 + */ +export type VisualizerReport = { + nodeParts?: Record; + nodeMetas?: Record; + renderedLength: number; + gzipLength: number; + brotliLength: number; + }>; + options?: Record; +}; + +type ModuleRow = { + id: string; + bundles: number; + renderedLength: number; + gzipLength: number; + brotliLength: number; + importedByCount: number; + importedCount: number; +}; + +type BundleRow = { + id: string; + modules: number; + renderedLength: number; + gzipLength: number; + brotliLength: number; +}; + +export function collectVisualizerReport(data: VisualizerReport) { + const nodeParts = data.nodeParts ?? {}; + const nodeMetas = Object.values(data.nodeMetas ?? {}); + const moduleRows: ModuleRow[] = []; + const bundleMap = new Map(); + + for (const meta of nodeMetas) { + const row: ModuleRow = { + id: meta.id, + bundles: 0, + renderedLength: 0, + gzipLength: 0, + brotliLength: 0, + importedByCount: meta.importedBy?.length ?? 0, + importedCount: meta.imported?.length ?? 0, + }; + + for (const [bundleId, partUid] of Object.entries(meta.moduleParts ?? {})) { + const part = nodeParts[partUid]; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (part == null) continue; + + row.bundles += 1; + row.renderedLength += part.renderedLength; + row.gzipLength += part.gzipLength; + row.brotliLength += part.brotliLength; + + const bundle = bundleMap.get(bundleId) ?? { + id: bundleId, + modules: 0, + renderedLength: 0, + gzipLength: 0, + brotliLength: 0, + }; + bundle.modules += 1; + bundle.renderedLength += part.renderedLength; + bundle.gzipLength += part.gzipLength; + bundle.brotliLength += part.brotliLength; + bundleMap.set(bundleId, bundle); + } + + // ���ンドル�も��れ��モジュール (tree-shake 済�等) �集計対象外 + if (row.bundles > 0) { + moduleRows.push(row); + } + } + + let staticImports = 0; + let dynamicImports = 0; + for (const meta of nodeMetas) { + for (const imported of meta.imported ?? []) { + if (imported.dynamic) { + dynamicImports += 1; + } else { + staticImports += 1; + } + } + } + + const bundleRows = [...bundleMap.values()].sort((a, b) => b.renderedLength - a.renderedLength); + const hotModules = [...moduleRows].sort((a, b) => b.renderedLength - a.renderedLength); + const totalRendered = moduleRows.reduce((sum, row) => sum + row.renderedLength, 0); + const totalGzip = moduleRows.reduce((sum, row) => sum + row.gzipLength, 0); + const totalBrotli = moduleRows.reduce((sum, row) => sum + row.brotliLength, 0); + + return { + options: data.options ?? {}, + summary: { + bundles: bundleRows.length, + modules: moduleRows.length, + entries: nodeMetas.filter((meta) => meta.isEntry).length, + externals: nodeMetas.filter((meta) => meta.isExternal).length, + staticImports, + dynamicImports, + }, + metrics: { + renderedLength: totalRendered, + gzipLength: totalGzip, + brotliLength: totalBrotli, + }, + hotModules, + }; +} + +/** + * NOTE: 以����関数� `string[]` を返���り�呼�出��� `[...].join('\n')` � + * �素����列���埋�込�れ������テーブル�カンマ区切り�1行�潰れ���。 + * 呼�出����識����済むよ�����文字列���返�。 + */ +export function renderVisualizerSummaryTable(before: ReturnType, after: ReturnType) { + const summary = [ + 'bundles', + 'modules', + 'entries', + //'externals', + 'staticImports', + 'dynamicImports', + ] as const; + + const metrics = [ + 'renderedLength', + 'gzipLength', + 'brotliLength', + ] as const; + + return [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + ...summary.map((key) => ``), + ...metrics.map((key) => ``), + '', + '', + '', + ...summary.map((key) => ``), + ...metrics.map((key) => ``), + '', + '', + '', + '', + ...summary.map((key) => ``), + ...metrics.map((key) => ``), + '', + '', + '', + ...summary.map((key) => ``), + ...metrics.map((key) => ``), + '', + '', + '
BundlesModulesEntriesImportsSize
StaticDynamicRenderedGzipBrotli
Before${formatNumber(before.summary[key])}${formatBytes(before.metrics[key])}
After${formatNumber(after.summary[key])}${formatBytes(after.metrics[key])}
Δ${calcAndFormatDeltaNumber(before.summary[key], after.summary[key], 0)}${calcAndFormatDeltaBytes(before.metrics[key], after.metrics[key], 1000)}
Δ (%)${calcAndFormatDeltaPercent(before.summary[key], after.summary[key], 0.1)}${calcAndFormatDeltaPercent(before.metrics[key], after.metrics[key], 0.1)}
', + ].join('\n'); +} diff --git a/packages-private/diagnostics-frontend-bundle/test/__snapshots__/render-md.md b/packages-private/diagnostics-frontend-bundle/test/__snapshots__/render-md.md new file mode 100644 index 00000000000..867cbf3b758 --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/test/__snapshots__/render-md.md @@ -0,0 +1,100 @@ +## 📦 Frontend Bundle Report + +
+Chunk size diff (2 updated, 0 added, 0 removed) + +| Chunk | Before | After | Δ | Δ (%) | +| --- | ---: | ---: | ---: | ---: | +| (total) | 120 KB | 127 KB | $\color{orange}{\text{+6.3 KB}}$ | $\color{orange}{\text{+5.2\\%}}$ | +| | | | | | +|
`vue` `assets/vue-b2.js`
| 90 KB | 96 KB | $\color{orange}{\text{+6 KB}}$ | $\color{orange}{\text{+6.7\\%}}$ | +| (other generated chunks) | 1.2 KB | 1.5 KB | $\text{+300 B}$ | $\color{orange}{\text{+25\\%}}$ | +| (other) | 20 KB | 20 KB | $\text{+3 B}$ | $\text{+0\\%}$ | + +
+ +
+Startup chunk size (2 updated, 0 added, 0 removed) + +| Chunk | Before | After | Δ | Δ (%) | +| --- | ---: | ---: | ---: | ---: | +| (total) | 114 KB | 120 KB | $\color{orange}{\text{+6 KB}}$ | $\color{orange}{\text{+5.3\\%}}$ | +| | | | | | +|
`vue` `assets/vue-b2.js`
| 90 KB | 96 KB | $\color{orange}{\text{+6 KB}}$ | $\color{orange}{\text{+6.7\\%}}$ | +| (other) | 24 KB | 24 KB | $\text{+3 B}$ | $\text{+0\\%}$ | + +_Startup chunks are the Vite entry for `src/_boot_.ts` and its static imports._ + +
+ + +## Bundle Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BundlesModulesEntriesImportsSize
StaticDynamicRenderedGzipBrotli
Before2612321 KB6.3 KB5.3 KB
After2713331 KB8.4 KB7 KB
Δ0$\color{orange}{\text{+1}}$0$\color{orange}{\text{+1}}$0$\color{orange}{\text{+9.8 KB}}$$\color{orange}{\text{+2.1 KB}}$$\color{orange}{\text{+1.8 KB}}$
Δ (%)0%$\color{orange}{\text{+16.7\%}}$0%$\color{orange}{\text{+50\%}}$0%$\color{orange}{\text{+46.7\%}}$$\color{orange}{\text{+33.3\%}}$$\color{orange}{\text{+33.3\%}}$
+ +[Open treemap HTML](https://example.invalid/treemap) \ No newline at end of file diff --git a/packages-private/diagnostics-frontend-bundle/test/fixtures/after-stats.json b/packages-private/diagnostics-frontend-bundle/test/fixtures/after-stats.json new file mode 100644 index 00000000000..b69e3f4ceaa --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/test/fixtures/after-stats.json @@ -0,0 +1 @@ +{"nodeParts": {"p0": {"renderedLength": 1100.0, "gzipLength": 300, "brotliLength": 250}, "p1": {"renderedLength": 2200.0, "gzipLength": 600, "brotliLength": 500}, "p2": {"renderedLength": 3300.0000000000005, "gzipLength": 900, "brotliLength": 750}, "p3": {"renderedLength": 4400.0, "gzipLength": 1200, "brotliLength": 1000}, "p4": {"renderedLength": 5500.0, "gzipLength": 1500, "brotliLength": 1250}, "p5": {"renderedLength": 6600.000000000001, "gzipLength": 1800, "brotliLength": 1500}, "p6": {"renderedLength": 7700.000000000001, "gzipLength": 2100, "brotliLength": 1750}}, "nodeMetas": {"m0": {"id": "/src/mod0.ts", "isEntry": true, "importedBy": [], "imported": [{"id": "m1", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p0"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m1": {"id": "/src/mod1.ts", "isEntry": false, "importedBy": ["m0"], "imported": [{"id": "m2", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p1"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m2": {"id": "/src/mod2.ts", "isEntry": false, "importedBy": ["m1"], "imported": [{"id": "m3", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p2"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m3": {"id": "/src/mod3.ts", "isEntry": false, "importedBy": ["m2"], "imported": [{"id": "m4", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p3"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m4": {"id": "/src/mod4.ts", "isEntry": false, "importedBy": ["m3"], "imported": [{"id": "m5", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p4"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m5": {"id": "/src/mod5.ts", "isEntry": false, "importedBy": ["m4"], "imported": [{"id": "m6", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p5"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m6": {"id": "/src/mod6.ts", "isEntry": false, "importedBy": ["m5"], "imported": [], "moduleParts": {"assets/boot-a1.js": "p6"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}}, "options": {}} \ No newline at end of file diff --git a/packages-private/diagnostics-frontend-bundle/test/fixtures/before-stats.json b/packages-private/diagnostics-frontend-bundle/test/fixtures/before-stats.json new file mode 100644 index 00000000000..0a54b931484 --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/test/fixtures/before-stats.json @@ -0,0 +1 @@ +{"nodeParts": {"p0": {"renderedLength": 1000, "gzipLength": 300, "brotliLength": 250}, "p1": {"renderedLength": 2000, "gzipLength": 600, "brotliLength": 500}, "p2": {"renderedLength": 3000, "gzipLength": 900, "brotliLength": 750}, "p3": {"renderedLength": 4000, "gzipLength": 1200, "brotliLength": 1000}, "p4": {"renderedLength": 5000, "gzipLength": 1500, "brotliLength": 1250}, "p5": {"renderedLength": 6000, "gzipLength": 1800, "brotliLength": 1500}}, "nodeMetas": {"m0": {"id": "/src/mod0.ts", "isEntry": true, "importedBy": [], "imported": [{"id": "m1", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p0"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m1": {"id": "/src/mod1.ts", "isEntry": false, "importedBy": ["m0"], "imported": [{"id": "m2", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p1"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m2": {"id": "/src/mod2.ts", "isEntry": false, "importedBy": ["m1"], "imported": [{"id": "m3", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p2"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m3": {"id": "/src/mod3.ts", "isEntry": false, "importedBy": ["m2"], "imported": [{"id": "m4", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p3"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m4": {"id": "/src/mod4.ts", "isEntry": false, "importedBy": ["m3"], "imported": [{"id": "m5", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p4"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m5": {"id": "/src/mod5.ts", "isEntry": false, "importedBy": ["m4"], "imported": [], "moduleParts": {"assets/vue-b2.js": "p5"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}}, "options": {}} \ No newline at end of file diff --git a/packages-private/diagnostics-frontend-bundle/test/render-md.test.ts b/packages-private/diagnostics-frontend-bundle/test/render-md.test.ts new file mode 100644 index 00000000000..17adcef8836 --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/test/render-md.test.ts @@ -0,0 +1,105 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { collectReport } from '../src/manifest'; +import { renderBundleReportMarkdown } from '../src/report'; +import type { VisualizerReport } from '../src/visualizer'; + +const fixturesDir = join(import.meta.dirname, 'fixtures'); + +/** + * ビルド�果物�fixture。 + * + * `collectReport` �ファイル�中身を見�サイズ��使������実体�指定�イト数� + * 詰�物�よ�。ディレクトリ�� `built` ��る��リ�ジトリ��コミット��� + * (ルート� .gitignore �ビルド�果物���除外�る)�テスト実行時�組�立���る。 + */ +const manifest = { + 'src/_boot_.ts': { file: 'assets/boot-a1.js', src: 'src/_boot_.ts', name: 'boot', isEntry: true, imports: ['_vue.js', '_i18n.js'] }, + '_vue.js': { file: 'assets/vue-b2.js', name: 'vue' }, + // `scripts/` �下�ロケール別�出力�れる�� ja-JP/ �解決�れる + '_i18n.js': { file: 'scripts/i18n-c3.js', name: 'i18n' }, + 'src/pages/foo.vue': { file: 'assets/foo-d4.js', src: 'src/pages/foo.vue', name: 'foo' }, + // .js 以外��ャンク���数��� + 'src/pages/style.css': { file: 'assets/style-e5.css', src: 'src/pages/style.css' }, +}; + +const fileSizes = { + before: { + 'assets/boot-a1.js': 20_000, + 'assets/vue-b2.js': 90_000, + 'assets/foo-d4.js': 5_000, + 'assets/style-e5.css': 100, + 'ja-JP/i18n-c3.js': 4_000, + 'ja-JP/orphan.js': 1_200, + }, + after: { + // 差�����る (閾値5�イト以下) ��「(other)��集約�れる + 'assets/boot-a1.js': 20_003, + // 明確�増�る�� diff表�行���出る + 'assets/vue-b2.js': 96_000, + 'assets/foo-d4.js': 5_000, + 'assets/style-e5.css': 100, + 'ja-JP/i18n-c3.js': 4_000, + // manifest�載ら��出力���「(other generated chunks)��集約�れる + 'ja-JP/orphan.js': 1_500, + }, +} as const satisfies Record<'before' | 'after', Record>; + +let repoDirs: { before: string; after: string }; +let workDir: string; + +beforeAll(async () => { + workDir = await mkdtemp(join(tmpdir(), 'diagnostics-frontend-bundle-')); + + for (const label of ['before', 'after'] as const) { + const outDir = join(workDir, label, 'built/_frontend_vite_'); + await mkdir(outDir, { recursive: true }); + await writeFile(join(outDir, 'manifest.json'), JSON.stringify(manifest)); + + for (const [file, size] of Object.entries(fileSizes[label])) { + const path = join(outDir, file); + await mkdir(dirname(path), { recursive: true }); + await writeFile(path, 'x'.repeat(size)); + } + } + + repoDirs = { + before: join(workDir, 'before'), + after: join(workDir, 'after'), + }; +}); + +afterAll(async () => { + await rm(workDir, { recursive: true, force: true }); +}); + +async function loadStats(name: string) { + return JSON.parse(await readFile(join(fixturesDir, `${name}-stats.json`), 'utf8')) as VisualizerReport; +} + +/** + * 出力をゴールデンファイル�固定�る。 + * �図的�変更����� `vitest -u` �更新��__snapshots__ �差分もレビュー�る��。 + */ +test('renders the frontend bundle report', async () => { + const markdown = renderBundleReportMarkdown( + await collectReport(repoDirs.before), + await collectReport(repoDirs.after), + await loadStats('before'), + await loadStats('after'), + { visualizerArtifactUrl: 'https://example.invalid/treemap' }, + ); + + await expect(markdown).toMatchFileSnapshot('./__snapshots__/render-md.md'); +}); + +test('fails loudly when the built output is missing', async () => { + await expect(collectReport(join(workDir, 'nonexistent'))).rejects.toThrow(); +}); diff --git a/packages-private/diagnostics-frontend-bundle/tsconfig.json b/packages-private/diagnostics-frontend-bundle/tsconfig.json new file mode 100644 index 00000000000..6672c40acb3 --- /dev/null +++ b/packages-private/diagnostics-frontend-bundle/tsconfig.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "esModuleInterop": true, + "skipLibCheck": true, + "noEmit": true, + "types": ["node"] + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ], + "exclude": [] +} diff --git a/packages-private/diagnostics-shared/eslint.config.js b/packages-private/diagnostics-shared/eslint.config.js new file mode 100644 index 00000000000..11bc648243d --- /dev/null +++ b/packages-private/diagnostics-shared/eslint.config.js @@ -0,0 +1,25 @@ +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../../packages/shared/eslint.config.js'; + +// eslint-disable-next-line import/no-default-export +export default [ + ...sharedConfig, + { + ignores: [ + '**/node_modules', + '**/__snapshots__', + 'test/fixtures', + ], + }, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]; diff --git a/packages-private/diagnostics-shared/package.json b/packages-private/diagnostics-shared/package.json new file mode 100644 index 00000000000..1fd0a146820 --- /dev/null +++ b/packages-private/diagnostics-shared/package.json @@ -0,0 +1,23 @@ +{ + "name": "diagnostics-shared", + "private": true, + "type": "module", + "exports": { + "./env": "./src/env.ts", + "./format": "./src/format.ts", + "./html": "./src/html.ts", + "./stats": "./src/stats.ts", + "./heap-snapshot": "./src/heap-snapshot/index.ts" + }, + "scripts": { + "eslint": "eslint './**/*.{js,jsx,ts,tsx}'", + "lint": "pnpm typecheck && pnpm eslint", + "test": "vitest run", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/node": "26.1.1", + "typescript": "5.9.3", + "vitest": "4.1.10" + } +} diff --git a/packages-private/diagnostics-shared/src/env.ts b/packages-private/diagnostics-shared/src/env.ts new file mode 100644 index 00000000000..0875cb23739 --- /dev/null +++ b/packages-private/diagnostics-shared/src/env.ts @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export function readIntegerEnv(name: string, defaultValue: number, min: number) { + const rawValue = process.env[name]; + if (rawValue == null || rawValue === '') return defaultValue; + if (!/^\d+$/.test(rawValue)) throw new Error(`${name} must be an integer`); + + const value = Number(rawValue); + if (!Number.isSafeInteger(value) || value < min) throw new Error(`${name} must be >= ${min}`); + return value; +} + +export function readBooleanEnv(name: string, defaultValue: boolean) { + const rawValue = process.env[name]; + if (rawValue == null || rawValue === '') return defaultValue; + if (rawValue === '1' || rawValue === 'true') return true; + if (rawValue === '0' || rawValue === 'false') return false; + throw new Error(`${name} must be one of: 1, 0, true, false`); +} + +/** + * 必須�環境変数を読む。未設定・空文字�らエラー��る。 + */ +export function readRequiredEnv(name: string) { + const rawValue = process.env[name]?.trim(); + if (rawValue == null || rawValue === '') throw new Error(`${name} must be set`); + return rawValue; +} + +/** + * 任��環境変数を読む。未設定・空文字�ら null を返�。 + */ +export function readOptionalEnv(name: string) { + const rawValue = process.env[name]?.trim(); + if (rawValue == null || rawValue === '') return null; + return rawValue; +} diff --git a/packages-private/diagnostics-shared/src/format.ts b/packages-private/diagnostics-shared/src/format.ts new file mode 100644 index 00000000000..75dc835e7bf --- /dev/null +++ b/packages-private/diagnostics-shared/src/format.ts @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +const numberFormatter = new Intl.NumberFormat('en-US', { + maximumFractionDigits: 1, +}); + +export function escapeLatex(text: string) { + return text + .replaceAll('\\', '\\\\') + .replaceAll('{', '\\{') + .replaceAll('}', '\\}') + .replaceAll('%', '\\%'); +} + +export function escapeMdTableCell(value: string) { + return String(value).replaceAll('|', '\\|').replaceAll('\n', '
'); +} + +export function escapeHtml(value: unknown) { + return String(value ?? '') + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll('\'', '''); +} + +export function formatNumber(value: number) { + return numberFormatter.format(value); +} + +export function formatBytes(value: number) { + if (value === 0) return '0 B'; + const units = ['B', 'KB', 'MB', 'GB']; + let unitIndex = 0; + let size = value; + while (size >= 1000 && unitIndex < units.length - 1) { + size /= 1000; + unitIndex += 1; + } + + const maximumFractionDigits = size >= 10 || unitIndex === 0 ? 0 : 1; + return `${numberFormatter.format(Number(size.toFixed(maximumFractionDigits)))} ${units[unitIndex]}`; +} + +/** + * KiB���値をMB表記��る。/proc 由��値�表示�使�。 + */ +export function formatKiBAsMb(valueKiB: number | null | undefined) { + if (valueKiB == null || !Number.isFinite(valueKiB)) return '-'; + return `${formatNumber(valueKiB / 1000)} MB`; +} + +export function formatPercent(value: number) { + return `${formatNumber(value)}%`; +} + +export function formatMs(value: number | null | undefined) { + if (value == null || !Number.isFinite(value)) return '-'; + if (value >= 1_000) return `${formatNumber(value / 1_000)} s`; + return `${formatNumber(value)} ms`; +} + +export function formatSecondsAsMs(value: number | null | undefined) { + if (value == null || !Number.isFinite(value)) return '-'; + return formatMs(value * 1_000); +} + +/** + * 差分値を符�付��整形�る。`colorThreshold` 以上�変化��る����色を付�る。 + */ +export function formatColoredDelta(delta: number, text: (value: number) => string, colorThreshold = 0) { + if (delta === 0) return text(0); + const sign = delta > 0 ? '+' : '-'; + if (Math.abs(delta) < colorThreshold) return `$\\text{${sign}${escapeLatex(text(Math.abs(delta)))}}$`; + const color = delta > 0 ? 'orange' : 'green'; + return `$\\color{${color}}{\\text{${sign}${escapeLatex(text(Math.abs(delta)))}}}$`; +} + +export function formatDeltaBytes(deltaBytes: number, colorThreshold = 0) { + return formatColoredDelta(deltaBytes, formatBytes, colorThreshold); +} + +export function formatDeltaPercent(deltaPercent: number, colorThreshold = 0) { + return formatColoredDelta(deltaPercent, formatPercent, colorThreshold); +} + +/** + * Markdown�テーブルセル内�置�差分パーセント。 + * LaTeX由�� `\%` �Markdown�エスケープ�食�れる��二�エスケープ�る。 + */ +export function formatDeltaPercentInMdTable(deltaPercent: number, colorThreshold = 0) { + return formatDeltaPercent(deltaPercent, colorThreshold).replaceAll('\\%', '\\\\%'); +} + +export function calcAndFormatDeltaNumber(before: number | null | undefined, after: number | null | undefined, colorThreshold = 0) { + if (before == null || after == null) return '-'; + return formatColoredDelta(after - before, formatNumber, colorThreshold); +} + +export function calcAndFormatDeltaBytes(before: number | null | undefined, after: number | null | undefined, colorThreshold = 0) { + if (before == null || after == null) return '-'; + return formatDeltaBytes(after - before, colorThreshold); +} + +export function calcAndFormatDeltaPercent(before: number | null | undefined, after: number | null | undefined, colorThreshold = 0) { + if (before == null || before === 0 || after == null) return '-'; + return formatDeltaPercent((after - before) / before * 100, colorThreshold); +} + +export function calcAndFormatDeltaPercentInMdTable(before: number | null | undefined, after: number | null | undefined, colorThreshold = 0) { + return calcAndFormatDeltaPercent(before, after, colorThreshold).replaceAll('\\%', '\\\\%'); +} diff --git a/packages-private/diagnostics-shared/src/heap-snapshot/analyze.ts b/packages-private/diagnostics-shared/src/heap-snapshot/analyze.ts new file mode 100644 index 00000000000..b3443e1889c --- /dev/null +++ b/packages-private/diagnostics-shared/src/heap-snapshot/analyze.ts @@ -0,0 +1,198 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { classifyHeapSnapshotBreakdown, collapseHeapSnapshotBreakdowns } from './breakdown'; +import { + createEmptyHeapSnapshotData, + heapSnapshotBreakdownCategories, + type HeapSnapshotCategory, + type HeapSnapshotData, +} from './categories'; + +/** + * `.heapsnapshot` �JSONを�フィールドオフセットを解決��状態�扱����ビュー。 + */ +type HeapSnapshotView = { + nodes: number[]; + edges: number[]; + strings: string[]; + nodeFieldCount: number; + edgeFieldCount: number; + nodeTypeNames: string[]; + edgeTypeNames: string[]; + typeOffset: number; + nameOffset: number; + selfSizeOffset: number; + edgeCountOffset: number; + edgeTypeOffset: number; + edgeNameOffset: number; + edgeToNodeOffset: number; + extraNativeBytes: number; +}; + +function requireOffsets(fields: string[], names: string[], what: string) { + const offsets = names.map(name => fields.indexOf(name)); + if (offsets.some(offset => offset < 0)) throw new Error(`Heap snapshot is missing required ${what} fields`); + return offsets; +} + +function parseHeapSnapshot(snapshot: any): HeapSnapshotView { + const meta = snapshot?.snapshot?.meta; + const { nodes, edges, strings } = snapshot ?? {}; + if (meta == null || !Array.isArray(nodes) || !Array.isArray(edges) || !Array.isArray(strings)) { + throw new Error('Invalid heap snapshot format'); + } + + const nodeFields = meta.node_fields; + if (!Array.isArray(nodeFields)) throw new Error('Invalid heap snapshot node fields'); + const edgeFields = meta.edge_fields; + if (!Array.isArray(edgeFields)) throw new Error('Invalid heap snapshot edge fields'); + + const [typeOffset, nameOffset, selfSizeOffset, edgeCountOffset] = requireOffsets(nodeFields, ['type', 'name', 'self_size', 'edge_count'], 'node'); + const [edgeTypeOffset, edgeNameOffset, edgeToNodeOffset] = requireOffsets(edgeFields, ['type', 'name_or_index', 'to_node'], 'edge'); + + const nodeTypeNames = meta.node_types?.[typeOffset]; + if (!Array.isArray(nodeTypeNames)) throw new Error('Invalid heap snapshot node types'); + const edgeTypeNames = meta.edge_types?.[edgeTypeOffset]; + if (!Array.isArray(edgeTypeNames)) throw new Error('Invalid heap snapshot edge types'); + + return { + nodes, + edges, + strings, + nodeFieldCount: nodeFields.length, + edgeFieldCount: edgeFields.length, + nodeTypeNames, + edgeTypeNames, + typeOffset, + nameOffset, + selfSizeOffset, + edgeCountOffset, + edgeTypeOffset, + edgeNameOffset, + edgeToNodeOffset, + extraNativeBytes: Number.isFinite(snapshot.snapshot.extra_native_bytes) ? snapshot.snapshot.extra_native_bytes : 0, + }; +} + +/** + * ノード���edge開始�置���ノード�何本�edge�ら�照�れ��る�を求�る。 + * JS�列�elementsストア�専有�れ��る�判定�る���使�。 + */ +function indexEdges(view: HeapSnapshotView) { + const edgeStartIndexes = new Map(); + const retainerCounts = new Map(); + let edgeIndex = 0; + + for (let nodeIndex = 0; nodeIndex < view.nodes.length; nodeIndex += view.nodeFieldCount) { + edgeStartIndexes.set(nodeIndex, edgeIndex); + const edgeCount = view.nodes[nodeIndex + view.edgeCountOffset] ?? 0; + for (let i = 0; i < edgeCount; i++, edgeIndex += view.edgeFieldCount) { + const toNodeIndex = view.edges[edgeIndex + view.edgeToNodeOffset]; + retainerCounts.set(toNodeIndex, (retainerCounts.get(toNodeIndex) ?? 0) + 1); + } + } + + return { edgeStartIndexes, retainerCounts }; +} + +export function analyzeHeapSnapshot(snapshot: any, options: { breakdownTopN?: number } = {}): HeapSnapshotData { + const view = parseHeapSnapshot(snapshot); + const { nodes, edges, strings, nodeFieldCount, edgeFieldCount, nodeTypeNames, edgeTypeNames } = view; + + const nativeType = nodeTypeNames.indexOf('native'); + const codeType = nodeTypeNames.indexOf('code'); + const hiddenType = nodeTypeNames.indexOf('hidden'); + const stringTypes = new Set([ + nodeTypeNames.indexOf('string'), + nodeTypeNames.indexOf('concatenated string'), + nodeTypeNames.indexOf('sliced string'), + ]); + const internalEdgeType = edgeTypeNames.indexOf('internal'); + + const { categories, nodeCounts } = createEmptyHeapSnapshotData(); + const breakdowns = {} as Record>; + for (const category of heapSnapshotBreakdownCategories) { + breakdowns[category] = {}; + } + + const { edgeStartIndexes, retainerCounts } = indexEdges(view); + const jsArrayElementNodeIndexes = new Set(); + + function addCategoryValue(category: HeapSnapshotCategory, value: number, type: string, name: string, counted = true) { + if (value <= 0) return; + categories[category] += value; + const label = classifyHeapSnapshotBreakdown(category, type, name); + breakdowns[category][label] = (breakdowns[category][label] ?? 0) + value; + if (counted) nodeCounts[category]++; + } + + /** + * �列オブジェクト自身�self_size���素ストア���れ����� + * ���列����照���るelementsノード�分を JS arrays �加算�る。 + */ + function addJsArrayElementSize(nodeIndex: number) { + const beginEdgeIndex = edgeStartIndexes.get(nodeIndex) ?? 0; + const edgeCount = nodes[nodeIndex + view.edgeCountOffset] ?? 0; + for (let i = 0, currentEdgeIndex = beginEdgeIndex; i < edgeCount; i++, currentEdgeIndex += edgeFieldCount) { + if (edges[currentEdgeIndex + view.edgeTypeOffset] !== internalEdgeType) continue; + if (strings[edges[currentEdgeIndex + view.edgeNameOffset]] !== 'elements') continue; + + const elementsNodeIndex = edges[currentEdgeIndex + view.edgeToNodeOffset]; + if ((retainerCounts.get(elementsNodeIndex) ?? 0) === 1) { + addCategoryValue('jsArrays', nodes[elementsNodeIndex + view.selfSizeOffset] ?? 0, 'array elements', 'Array elements'); + jsArrayElementNodeIndexes.add(elementsNodeIndex); + } + break; + } + } + + if (view.extraNativeBytes > 0) { + addCategoryValue('otherNonJsObjects', view.extraNativeBytes, 'extra native bytes', 'extra native bytes', false); + } + + for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { + const typeId = nodes[nodeIndex + view.typeOffset]; + const type = nodeTypeNames[typeId] ?? 'unknown'; + const name = strings[nodes[nodeIndex + view.nameOffset]] ?? ''; + const selfSize = nodes[nodeIndex + view.selfSizeOffset] ?? 0; + categories.total += selfSize; + nodeCounts.total++; + + if (typeId === hiddenType) { + addCategoryValue('systemObjects', selfSize, type, name); + } else if (typeId === nativeType) { + addCategoryValue(name === 'system / JSArrayBufferData' ? 'typedArrays' : 'otherNonJsObjects', selfSize, type, name); + } else if (typeId === codeType) { + addCategoryValue('code', selfSize, type, name); + } else if (stringTypes.has(typeId)) { + addCategoryValue('strings', selfSize, type, name); + } else if (name === 'Array') { + addCategoryValue('jsArrays', selfSize, type, name); + addJsArrayElementSize(nodeIndex); + } + } + + categories.total += view.extraNativeBytes; + + // 上�ループ� JS arrays �計上��elementsノード�確定���ら�残りを Other JS objects �振り分�る + for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { + if (jsArrayElementNodeIndexes.has(nodeIndex)) continue; + + const typeId = nodes[nodeIndex + view.typeOffset]; + if (typeId === hiddenType || typeId === nativeType || typeId === codeType || stringTypes.has(typeId)) continue; + + const name = strings[nodes[nodeIndex + view.nameOffset]] ?? ''; + if (name === 'Array') continue; + + addCategoryValue('otherJsObjects', nodes[nodeIndex + view.selfSizeOffset] ?? 0, nodeTypeNames[typeId] ?? 'unknown', name); + } + + return { + categories, + nodeCounts, + breakdowns: collapseHeapSnapshotBreakdowns(breakdowns, options.breakdownTopN), + }; +} diff --git a/packages-private/diagnostics-shared/src/heap-snapshot/breakdown.ts b/packages-private/diagnostics-shared/src/heap-snapshot/breakdown.ts new file mode 100644 index 00000000000..0dd5ffe324f --- /dev/null +++ b/packages-private/diagnostics-shared/src/heap-snapshot/breakdown.ts @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { + defaultHeapSnapshotBreakdownTopN, + heapSnapshotBreakdownCategories, + type HeapSnapshotCategory, + type HeapSnapshotData, +} from './categories'; + +function sanitizeLabel(value: unknown, fallback = 'unknown') { + const label = String(value ?? '').replace(/\s+/g, ' ').trim(); + if (label === '') return fallback; + if (label.length <= 80) return label; + return `${label.slice(0, 77)}...`; +} + +/** + * ノード� type / name �ら�内訳テーブル�出�粒度�ラベルを決�る。 + */ +export function classifyHeapSnapshotBreakdown(category: HeapSnapshotCategory, type: string, name: string) { + switch (category) { + case 'strings': + return type; + + case 'jsArrays': + if (type === 'array elements') return 'Array elements'; + if (type === 'object' && name === 'Array') return 'Array objects'; + return sanitizeLabel(`${type}: ${name}`); + + case 'typedArrays': + if (name === 'system / JSArrayBufferData') return 'ArrayBuffer data'; + return sanitizeLabel(`${type}: ${name}`); + + case 'systemObjects': + if (name.startsWith('system /') || name.startsWith('(system ')) return sanitizeLabel(name); + return sanitizeLabel(`${type}: ${name}`, type); + + case 'otherJsObjects': + if (type === 'object') return sanitizeLabel(`object: ${name}`, 'object: unknown'); + return type; + + case 'otherNonJsObjects': + if (type === 'extra native bytes') return 'Extra native bytes'; + if (type === 'native') return sanitizeLabel(`native: ${name}`, 'native: unknown'); + return sanitizeLabel(`${type}: ${name}`, type); + + case 'code': { + const lowerName = name.toLowerCase(); + if (lowerName.includes('bytecode')) return 'bytecode'; + if (lowerName.includes('builtin')) return 'builtins'; + if (lowerName.includes('regexp')) return 'regexp code'; + if (lowerName.includes('stub')) return 'stubs'; + return sanitizeLabel(`code: ${name}`, 'code: unknown'); + } + + default: + return sanitizeLabel(`${type}: ${name}`, type); + } +} + +/** + * 内訳を上�N件�丸��残りを `Other` ����る。 + */ +export function collapseHeapSnapshotBreakdown(breakdown: Record, topN = defaultHeapSnapshotBreakdownTopN) { + const entries = Object.entries(breakdown) + .filter(([, value]) => value > 0) + .toSorted((a, b) => b[1] - a[1]); + + const collapsed = Object.fromEntries(entries.slice(0, topN)); + const otherValue = entries.slice(topN).reduce((sum, [, value]) => sum + value, 0); + if (otherValue > 0) collapsed.Other = otherValue; + return collapsed; +} + +export function collapseHeapSnapshotBreakdowns( + breakdowns: Partial>>, + topN = defaultHeapSnapshotBreakdownTopN, +) { + const collapsed: NonNullable = {}; + for (const category of heapSnapshotBreakdownCategories) { + const categoryBreakdown = breakdowns[category]; + if (categoryBreakdown == null) continue; + + const collapsedCategory = collapseHeapSnapshotBreakdown(categoryBreakdown, topN); + if (Object.keys(collapsedCategory).length > 0) { + collapsed[category] = collapsedCategory; + } + } + + return collapsed; +} diff --git a/packages-private/diagnostics-shared/src/heap-snapshot/categories.ts b/packages-private/diagnostics-shared/src/heap-snapshot/categories.ts new file mode 100644 index 00000000000..4e7caed6d85 --- /dev/null +++ b/packages-private/diagnostics-shared/src/heap-snapshot/categories.ts @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +// Chrome DevTools � heap snapshot Statistics ビュー���分類��るよ������。 +export const heapSnapshotCategory = { + total: { label: 'Total', color: 'gray', colorHex: '#888888' }, + code: { label: 'Code', color: 'orange', colorHex: '#f28e2c' }, + strings: { label: 'Strings', color: 'red', colorHex: '#e15759' }, + jsArrays: { label: 'JS arrays', color: 'cyan', colorHex: '#76b7b2' }, + typedArrays: { label: 'Typed arrays', color: 'green', colorHex: '#59a14f' }, + systemObjects: { label: 'System objects', color: 'yellow', colorHex: '#edc949' }, + otherJsObjects: { label: 'Other JS objs', color: 'violet', colorHex: '#af7aa1' }, + otherNonJsObjects: { label: 'Other non-JS objs', color: 'pink', colorHex: '#ff9da7' }, +} as const satisfies Record; + +export type HeapSnapshotCategory = keyof typeof heapSnapshotCategory; + +export const heapSnapshotCategories = Object.keys(heapSnapshotCategory) as HeapSnapshotCategory[]; + +/** `total` �他カテゴリ��算����全体�����内訳を扱����除外�る */ +export const heapSnapshotBreakdownCategories = heapSnapshotCategories.filter(category => category !== 'total'); + +export type HeapSnapshotData = { + categories: Record; + nodeCounts: Record; + /** 内訳�空���カテゴリ���入る (`total` �内訳を����) */ + breakdowns?: Partial>>; +}; + +export type HeapSnapshotReport = { + summary: HeapSnapshotData; + samples: { + round: number; + data: HeapSnapshotData; + }[]; +}; + +export const defaultHeapSnapshotBreakdownTopN = 6; + +export function createEmptyHeapSnapshotData(): HeapSnapshotData { + const categories = {} as HeapSnapshotData['categories']; + const nodeCounts = {} as HeapSnapshotData['nodeCounts']; + for (const category of heapSnapshotCategories) { + categories[category] = 0; + nodeCounts[category] = 0; + } + return { + categories, + nodeCounts, + breakdowns: {}, + }; +} diff --git a/packages-private/diagnostics-shared/src/heap-snapshot/index.ts b/packages-private/diagnostics-shared/src/heap-snapshot/index.ts new file mode 100644 index 00000000000..0634efac878 --- /dev/null +++ b/packages-private/diagnostics-shared/src/heap-snapshot/index.ts @@ -0,0 +1,10 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export * from './analyze'; +export * from './breakdown'; +export * from './categories'; +export * from './render'; +export * from './summarize'; diff --git a/packages-private/diagnostics-shared/src/heap-snapshot/render.ts b/packages-private/diagnostics-shared/src/heap-snapshot/render.ts new file mode 100644 index 00000000000..7690c834c5a --- /dev/null +++ b/packages-private/diagnostics-shared/src/heap-snapshot/render.ts @@ -0,0 +1,177 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { + formatBytes, + formatDeltaBytes, + formatDeltaPercentInMdTable, + formatPercent, +} from '../format'; +import { mad, pairedDeltaSummary } from '../stats'; +import { + heapSnapshotCategories, + heapSnapshotCategory, + type HeapSnapshotCategory, + type HeapSnapshotReport, +} from './categories'; + +/** �れ未満��イト差分��色を付��� (0.1 MB) */ +const byteColorThreshold = 100_000; + +function categoryValue(report: HeapSnapshotReport, category: HeapSnapshotCategory) { + return report.summary.categories[category]; +} + +function categorySampleSpread(report: HeapSnapshotReport, category: HeapSnapshotCategory) { + const values = report.samples + .map(sample => sample.data.categories[category]) + .filter(value => Number.isFinite(value)); + if (values.length < 2) throw new Error(`Not enough samples for category ${category}`); + + return mad(values); +} + +function swatch(category: HeapSnapshotCategory) { + return `$\\color{${heapSnapshotCategory[category].color}}{\\rule{8pt}{8pt}}$ **${heapSnapshotCategory[category].label}**`; +} + +/** + * base / head �heap snapshotをカテゴリ別�比較�るMarkdownテーブルを�画�る。 + */ +export function renderHeapSnapshotTable(base: HeapSnapshotReport, head: HeapSnapshotReport) { + const lines = [ + '| Metric | Base | Head | Δ median | Δ MAD | Δ min | Δ max |', + '| --- | ---: | ---: | ---: | ---: | ---: | ---: |', + ]; + const baseTotal = categoryValue(base, 'total'); + const headTotal = categoryValue(head, 'total'); + + for (const category of heapSnapshotCategories) { + const baseValue = categoryValue(base, category); + const headValue = categoryValue(head, category); + const summary = pairedDeltaSummary(base.samples, head.samples, sample => sample.data.categories[category]); + const deltaColumns = `${formatBytes(summary.mad)} | ${formatDeltaBytes(summary.min, byteColorThreshold)} | ${formatDeltaBytes(summary.max, byteColorThreshold)}`; + + if (category === 'total') { + // Total����ら���変化率も併記�る + const percent = summary.median * 100 / baseValue; + const deltaMedian = `${formatDeltaBytes(summary.median, byteColorThreshold)}
${formatDeltaPercentInMdTable(percent, 0.1)}`; + const baseText = `${formatBytes(baseValue)}
± ${formatBytes(categorySampleSpread(base, category))}`; + const headText = `${formatBytes(headValue)}
± ${formatBytes(categorySampleSpread(head, category))}`; + lines.push(`| ${swatch(category)} | ${baseText} | ${headText} | ${deltaMedian} | ${deltaColumns} |`); + lines.push('| | | | | | | |'); + } else { + // �カテゴリ�Total���る割��推移をdetails�見�る + const basePercent = formatPercent((baseValue * 100) / baseTotal); + const headPercent = formatPercent((headValue * 100) / headTotal); + const metricText = `
${swatch(category)}${basePercent} → ${headPercent}
`; + lines.push(`| ${metricText} | ${formatBytes(baseValue)} | ${formatBytes(headValue)} | ${formatDeltaBytes(summary.median, byteColorThreshold)} | ${deltaColumns} |`); + } + } + + if (lines.length === 2) return null; + return lines.join('\n'); +} + +const sankeyChildMinRatio = 0.3; +const sankeyParentMinPercent = 10; + +function escapeCsvValue(value: string) { + return `"${String(value).replaceAll('"', '""')}"`; +} + +function formatSankeyPercentValue(value: number) { + const rounded = Math.round(value * 100) / 100; + if (rounded === 0 && value > 0) return '0.01'; + if (Number.isInteger(rounded)) return String(rounded); + return rounded.toFixed(2).replace(/0+$/, '').replace(/\.$/, ''); +} + +/** + * heap snapshot�構�比をmermaid�sankey図����画�る。 + * 全体���る割�����カテゴリ・内訳� `Other` ����る。 + */ +export function renderHeapSnapshotSankey(report: HeapSnapshotReport, title: string) { + const total = categoryValue(report, 'total'); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (total == null || total <= 0) return null; + + const categories = heapSnapshotCategories + .filter(category => category !== 'total') + .map(category => { + const value = categoryValue(report, category); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (value == null || value <= 0) return null; + + const breakdownEntries = Object.entries(report.summary.breakdowns?.[category] ?? {}) + .filter(([, childValue]) => Number.isFinite(childValue) && childValue > 0) + .toSorted((a, b) => b[1] - a[1]); + const breakdownTotal = breakdownEntries.reduce((sum, [, childValue]) => sum + childValue, 0); + const percent = (value * 100) / total; + const childEntries: [string, number][] = []; + let otherPercent = 0; + + if (breakdownTotal > 0 && percent > sankeyParentMinPercent) { + for (const [childName, childValue] of breakdownEntries) { + const childRatio = childValue / breakdownTotal; + if (childRatio >= sankeyChildMinRatio) { + childEntries.push([childName.replace(/^[^:]+:\s*/, ''), percent * childRatio]); + } else { + otherPercent += percent * childRatio; + } + } + + if (childEntries.length > 0 && otherPercent > 0) { + childEntries.push(['Other', otherPercent]); + } + } + + return { category, percent, childEntries }; + }) + .filter(value => value != null); + + if (categories.length === 0) return null; + + const nodeColors: Record = { + [title]: heapSnapshotCategory.total.colorHex, + Other: '#888888', + }; + for (const { category, childEntries } of categories) { + nodeColors[category] = heapSnapshotCategory[category].colorHex; + for (const [childName] of childEntries) { + nodeColors[childName] = heapSnapshotCategory[category].colorHex; + } + } + + const lines = [ + `
${title} heap snapshot composition`, + '', + '```mermaid', + `%%{init: ${JSON.stringify({ + sankey: { + showValues: false, + linkColor: 'target', + labelStyle: 'outlined', + nodeAlignment: 'center', + nodePadding: 10, + nodeColors, + }, + })}}%%`, + 'sankey-beta', + ]; + + for (const { category, percent, childEntries } of categories) { + const categoryLabel = heapSnapshotCategory[category].label; + lines.push(`${escapeCsvValue(title)},${escapeCsvValue(categoryLabel)},${formatSankeyPercentValue(percent)}`); + + for (const [childName, childPercent] of childEntries) { + lines.push(`${escapeCsvValue(categoryLabel)},${escapeCsvValue(childName)},${formatSankeyPercentValue(childPercent)}`); + } + } + + lines.push('```', '', '
'); + + return lines.join('\n'); +} diff --git a/packages-private/diagnostics-shared/src/heap-snapshot/summarize.ts b/packages-private/diagnostics-shared/src/heap-snapshot/summarize.ts new file mode 100644 index 00000000000..bbc2a6d203a --- /dev/null +++ b/packages-private/diagnostics-shared/src/heap-snapshot/summarize.ts @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { finiteMedian } from '../stats'; +import { collapseHeapSnapshotBreakdown } from './breakdown'; +import { + heapSnapshotBreakdownCategories, + heapSnapshotCategories, + type HeapSnapshotCategory, + type HeapSnapshotData, +} from './categories'; + +function isComplete(values: Partial>): values is Record { + return heapSnapshotCategories.every(category => values[category] != null); +} + +/** + * 複数ラウンド分�heap snapshotを�カテゴリ・内訳���中央値����る。 + * 全カテゴリ分�値�����れ� null を返�。 + */ +export function summarizeHeapSnapshotDataSamples( + samples: T[], + getData: (sample: T) => HeapSnapshotData | null | undefined, + options: { breakdownTopN?: number } = {}, +) { + const data = samples.map(getData); + + const categories: Partial = {}; + const nodeCounts: Partial = {}; + for (const category of heapSnapshotCategories) { + const categoryValue = finiteMedian(data.map(snapshot => snapshot?.categories?.[category])); + if (categoryValue != null) categories[category] = categoryValue; + + const nodeCountValue = finiteMedian(data.map(snapshot => snapshot?.nodeCounts?.[category])); + if (nodeCountValue != null) nodeCounts[category] = nodeCountValue; + } + + // 一部�カテゴリ��欠��状態�返���呼�出���完全�値���扱�� + // undefined を�画�����。全カテゴリ������れ�サマリ自体を無���る + if (!isComplete(categories) || !isComplete(nodeCounts)) return null; + + const breakdowns: NonNullable = {}; + for (const category of heapSnapshotBreakdownCategories) { + const childKeys = new Set(data.flatMap(snapshot => Object.keys(snapshot?.breakdowns?.[category] ?? {}))); + + const categoryBreakdown = {} as Record; + for (const childKey of childKeys) { + const value = finiteMedian(data.map(snapshot => snapshot?.breakdowns?.[category]?.[childKey])); + if (value != null) categoryBreakdown[childKey] = value; + } + + const collapsed = collapseHeapSnapshotBreakdown(categoryBreakdown, options.breakdownTopN); + if (Object.keys(collapsed).length > 0) breakdowns[category] = collapsed; + } + + return { + categories, + nodeCounts, + ...(Object.keys(breakdowns).length > 0 ? { breakdowns } : {}), + } satisfies HeapSnapshotData; +} diff --git a/packages-private/diagnostics-shared/src/html.ts b/packages-private/diagnostics-shared/src/html.ts new file mode 100644 index 00000000000..907c089656e --- /dev/null +++ b/packages-private/diagnostics-shared/src/html.ts @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { escapeHtml } from './format'; + +/** + * エスケープ済���る���図的�エスケープ���生�HTML断片。 + * + * ���文字列�型�区別�る�����存在�����`html` �実行時� + * 「��値�も�エスケープ����よ���判定�る���マーカー�も�る。 + * 型���ブランド��る�実行時�判定�����局エスケープ�れを防���。 + */ +export class Raw { + constructor(private readonly value: string) {} + + toString() { + return this.value; + } +} + +/** + * 文字列をエスケープ������埋�込む。 + * 呼�出��差分�残る���レビュー�「��生�入れ�よ����を確���る。 + */ +export function raw(value: string) { + return new Raw(value); +} + +function interpolate(value: unknown): string { + if (value instanceof Raw) return value.toString(); + // �列を����文字列化�る�カンマ区切り�潰れる����素���処��る + if (Array.isArray(value)) return value.map(interpolate).join(''); + if (value == null) return ''; + return escapeHtml(value); +} + +/** + * HTMLを組�立�るタグ付�テンプレート。補間値�既定�エスケープ�れる。 + * エスケープ�����場�� `raw()` �包む必���る��� + * 「���り生���埋�込む����起���。 + */ +export function html(strings: TemplateStringsArray, ...values: unknown[]) { + let result = strings[0]; + for (let i = 0; i < values.length; i++) { + result += interpolate(values[i]) + strings[i + 1]; + } + return new Raw(result); +} + +/** + * 断片を指定�区切り文字�連��る。 + * `html` ��列補間�区切り無��繋����改行��を挟��������らを使�。 + */ +export function joinHtml(parts: readonly Raw[], separator: string) { + return new Raw(parts.map(part => part.toString()).join(separator)); +} diff --git a/packages-private/diagnostics-shared/src/stats.ts b/packages-private/diagnostics-shared/src/stats.ts new file mode 100644 index 00000000000..7516242c320 --- /dev/null +++ b/packages-private/diagnostics-shared/src/stats.ts @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export function median(values: number[]) { + const sorted = values.toSorted((a, b) => a - b); + const center = Math.floor(sorted.length / 2); + if (sorted.length % 2 === 1) return sorted[center]; + return Math.round((sorted[center - 1] + sorted[center]) / 2); +} + +export function mad(values: number[]) { + if (values.length < 2) throw new Error('Not enough samples to calculate MAD'); + + const center = median(values); + return median(values.map(value => Math.abs(value - center))); +} + +/** + * 有�値��を対象�中央値を求�る。有�値�1�も無�場�� `defaultValue` を返�。 + */ +export function finiteMedian(values: (number | null | undefined)[]): number | null; +export function finiteMedian(values: (number | null | undefined)[], defaultValue: number): number; +export function finiteMedian(values: (number | null | undefined)[], defaultValue: number | null = null) { + const finiteValues = values.filter(value => Number.isFinite(value)) as number[]; + if (finiteValues.length === 0) return defaultValue; + return median(finiteValues); +} + +/** + * サンプル��ら�� (MAD) を求�る。サンプル�2�未満�求�られ��場�� null を返�。 + */ +export function sampleSpread(values: (number | null | undefined)[]) { + const finiteValues = values.filter(value => Number.isFinite(value)) as number[]; + if (finiteValues.length < 2) return null; + return mad(finiteValues); +} + +type RoundedSample = { round: number }; + +function indexByRound(samples: T[]) { + const samplesByRound = new Map(); + for (const sample of samples) { + // 負�round�warmupを表���対象外 + if (sample.round <= 0) continue; + samplesByRound.set(sample.round, sample); + } + return samplesByRound; +} + +/** + * base / head を��round������������差分�分布を�約�る。 + * 実行順�よる�ら��影響を抑�る����純�集計値����引�算����ペア差分を使�。 + */ +export function pairedDeltaSummary(baseSamples: T[], headSamples: T[], getValue: (sample: T) => number | null | undefined) { + const baseSamplesByRound = indexByRound(baseSamples); + const headSamplesByRound = indexByRound(headSamples); + const values: number[] = []; + + for (const [round, baseSample] of baseSamplesByRound) { + const headSample = headSamplesByRound.get(round); + if (headSample == null) continue; + + const baseValue = getValue(baseSample); + const headValue = getValue(headSample); + if (baseValue == null || headValue == null) continue; + + values.push(headValue - baseValue); + } + + // 対応�るround�1�も無��中央値も最�/最大も定義����。 + // ���NaNやInfinityをレ�ート�載�るより�比較��立������分�る形���� + if (values.length === 0) throw new Error('No paired samples to compare: base and head have no rounds in common'); + + return { + median: median(values), + // 1サンプル��中央値�ら��差�常�0��る (mad() �統計���無�味���拒��る) + mad: values.length < 2 ? 0 : mad(values), + min: Math.min(...values), + max: Math.max(...values), + samples: values.length, + }; +} diff --git a/packages-private/diagnostics-shared/test/format.test.ts b/packages-private/diagnostics-shared/test/format.test.ts new file mode 100644 index 00000000000..e391d862836 --- /dev/null +++ b/packages-private/diagnostics-shared/test/format.test.ts @@ -0,0 +1,102 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test } from 'vitest'; +import { + calcAndFormatDeltaPercent, + calcAndFormatDeltaPercentInMdTable, + escapeHtml, + escapeLatex, + escapeMdTableCell, + formatBytes, + formatColoredDelta, + formatKiBAsMb, + formatMs, + formatNumber, +} from '../src/format'; + +describe('formatBytes', () => { + // 1024����1000区切り。���2�以上�ら�数を��� + test.each([ + [0, '0 B'], + [999, '999 B'], + [1_000, '1 KB'], + [1_500, '1.5 KB'], + [15_000, '15 KB'], + [1_234_567, '1.2 MB'], + [12_345_678, '12 MB'], + [1_500_000_000, '1.5 GB'], + [1_500_000_000_000, '1,500 GB'], + ])('formats %i as %s', (input, expected) => { + expect(formatBytes(input)).toBe(expected); + }); +}); + +describe('formatColoredDelta', () => { + test('leaves zero uncoloured and unsigned', () => { + expect(formatColoredDelta(0, formatNumber)).toBe('0'); + }); + + test('colours growth orange and shrinkage green', () => { + expect(formatColoredDelta(5, formatNumber)).toBe('$\\color{orange}{\\text{+5}}$'); + expect(formatColoredDelta(-5, formatNumber)).toBe('$\\color{green}{\\text{-5}}$'); + }); + + test('omits colour below the threshold but keeps the sign', () => { + expect(formatColoredDelta(5, formatNumber, 10)).toBe('$\\text{+5}$'); + }); +}); + +describe('escaping', () => { + test('escapeHtml covers the five metacharacters', () => { + expect(escapeHtml(`&<>"'`)).toBe('&<>"''); + }); + + test('escapeHtml maps nullish to an empty string', () => { + expect(escapeHtml(null)).toBe(''); + expect(escapeHtml(undefined)).toBe(''); + }); + + test('escapeLatex escapes braces and percent', () => { + expect(escapeLatex('100% {x}')).toBe('100\\% \\{x\\}'); + }); + + test('escapeMdTableCell keeps pipes and newlines from breaking the table', () => { + expect(escapeMdTableCell('a|b\nc')).toBe('a\\|b
c'); + }); +}); + +describe('percent helpers', () => { + // before �0��変化率��も��定義���� + test('returns a placeholder when the baseline is zero or missing', () => { + expect(calcAndFormatDeltaPercent(0, 10)).toBe('-'); + expect(calcAndFormatDeltaPercent(null, 10)).toBe('-'); + expect(calcAndFormatDeltaPercent(10, null)).toBe('-'); + }); + + // 0������「消������有効��果����隠�� -100% ���出� + test('formats a drop to zero as -100%', () => { + expect(calcAndFormatDeltaPercent(10, 0)).toBe('$\\color{green}{\\text{-100\\%}}$'); + }); + + // Markdown�テーブルセル内��LaTeX� \% ��ら�食�れる��二���る + test('doubles the percent escape for markdown table cells', () => { + expect(calcAndFormatDeltaPercentInMdTable(100, 110)).toContain('\\\\%'); + expect(calcAndFormatDeltaPercent(100, 110)).not.toContain('\\\\%'); + }); +}); + +describe('nullish handling', () => { + test('formatKiBAsMb and formatMs render a dash for missing values', () => { + expect(formatKiBAsMb(null)).toBe('-'); + expect(formatKiBAsMb(Number.NaN)).toBe('-'); + expect(formatMs(undefined)).toBe('-'); + }); + + test('formatMs switches to seconds past 1000ms', () => { + expect(formatMs(999)).toBe('999 ms'); + expect(formatMs(1_500)).toBe('1.5 s'); + }); +}); diff --git a/packages-private/diagnostics-shared/test/html.test.ts b/packages-private/diagnostics-shared/test/html.test.ts new file mode 100644 index 00000000000..6e9dbc48b0b --- /dev/null +++ b/packages-private/diagnostics-shared/test/html.test.ts @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test } from 'vitest'; +import { html, joinHtml, raw, Raw } from '../src/html'; + +describe('html', () => { + test('escapes interpolated values by default', () => { + const value = ''; + expect(String(html`

${value}

`)).toBe('

<script>alert(1)</script>

'); + }); + + test('escapes values used in attribute position', () => { + const url = 'x">'; + expect(String(html``)).toBe(''); + }); + + test('leaves the static parts of the template untouched', () => { + expect(String(html`

x

`)).toBe('

x

'); + }); + + test('renders nullish values as an empty string', () => { + expect(String(html`

${null}${undefined}

`)).toBe('

'); + }); + + test('does not double-escape nested fragments', () => { + const inner = html`${'a&b'}`; + expect(String(html`

${inner}

`)).toBe('

a&b

'); + }); + + // �列を����文字列化�る�カンマ区切り�潰れる。実際��去�れ�表�壊れ� + test('joins arrays without separators instead of stringifying them', () => { + const items = [html`
  • 1
  • `, html`
  • 2
  • `]; + expect(String(html`
      ${items}
    `)).toBe('
    • 1
    • 2
    '); + }); + + test('escapes array elements that are not fragments', () => { + expect(String(html`

    ${['', '']}

    `)).toBe('

    <a><b>

    '); + }); +}); + +describe('raw', () => { + test('embeds trusted markup without escaping', () => { + expect(String(html``)).toBe(''); + }); + + test('produces a Raw fragment', () => { + expect(raw('x')).toBeInstanceOf(Raw); + expect(html`x`).toBeInstanceOf(Raw); + }); +}); + +describe('joinHtml', () => { + test('joins fragments with the given separator', () => { + expect(String(joinHtml([html`
  • 1
  • `, html`
  • 2
  • `], '\n'))).toBe('
  • 1
  • \n
  • 2
  • '); + }); + + test('returns an empty fragment for an empty list', () => { + expect(String(joinHtml([], '\n'))).toBe(''); + }); +}); diff --git a/packages-private/diagnostics-shared/test/stats.test.ts b/packages-private/diagnostics-shared/test/stats.test.ts new file mode 100644 index 00000000000..1d57f0d67d4 --- /dev/null +++ b/packages-private/diagnostics-shared/test/stats.test.ts @@ -0,0 +1,109 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test } from 'vitest'; +import { finiteMedian, mad, median, pairedDeltaSummary, sampleSpread } from '../src/stats'; + +describe('median', () => { + test('takes the middle value of an odd-length sample', () => { + expect(median([3, 1, 2])).toBe(2); + }); + + // å�¶æ•°é•·ã�§ã�¯å¹³å�‡ã‚’æ•´æ•°ã�«ä¸¸ã‚�る。KiBå�˜ä½�ã�®æ•´æ•°å€¤ã‚’扱ã�†å‰�æ��ã�®ã�Ÿã‚� + test('rounds the average of an even-length sample', () => { + expect(median([1, 2])).toBe(2); + expect(median([1, 4])).toBe(3); + }); +}); + +describe('mad', () => { + test('measures the median absolute deviation', () => { + expect(mad([1, 1, 1])).toBe(0); + expect(mad([1, 2, 3])).toBe(1); + }); + + test('refuses to compute from a single sample', () => { + expect(() => mad([1])).toThrow(); + }); +}); + +describe('finiteMedian', () => { + test('ignores non-finite entries', () => { + expect(finiteMedian([1, null, undefined, Number.NaN, 3])).toBe(2); + }); + + test('returns null by default when nothing is finite', () => { + expect(finiteMedian([null, undefined])).toBeNull(); + }); + + test('returns the supplied default when nothing is finite', () => { + expect(finiteMedian([null, undefined], 0)).toBe(0); + }); +}); + +describe('sampleSpread', () => { + test('needs at least two finite samples', () => { + expect(sampleSpread([1])).toBeNull(); + expect(sampleSpread([1, null])).toBeNull(); + expect(sampleSpread([1, 3])).toBe(1); + }); +}); + +describe('pairedDeltaSummary', () => { + const base = [ + { round: 1, value: 100 }, + { round: 2, value: 200 }, + { round: 3, value: 300 }, + ]; + + test('compares base and head within the same round', () => { + const head = [ + { round: 1, value: 110 }, + { round: 2, value: 230 }, + { round: 3, value: 320 }, + ]; + + expect(pairedDeltaSummary(base, head, sample => sample.value)).toStrictEqual({ + median: 20, + mad: 10, + min: 10, + max: 30, + samples: 3, + }); + }); + + test('drops rounds that only one side has', () => { + const head = [ + { round: 1, value: 110 }, + { round: 2, value: 230 }, + { round: 9, value: 999 }, + ]; + + expect(pairedDeltaSummary(base, head, sample => sample.value).samples).toBe(2); + }); + + // 1サンプルã�§ã‚‚中央値・最å°�・最大ã�¯å®šã�¾ã‚‹ (å��å·®ã�¯å¸¸ã�«0) + test('summarizes a single paired round without treating MAD as an error', () => { + expect(pairedDeltaSummary([base[0]], [{ round: 1, value: 130 }], sample => sample.value)).toStrictEqual({ + median: 30, + mad: 0, + min: 30, + max: 30, + samples: 1, + }); + }); + + test('fails loudly when no round is shared', () => { + expect(() => pairedDeltaSummary(base, [{ round: 9, value: 1 }], sample => sample.value)).toThrow(/no rounds in common/); + }); + + // è² ã�®roundã�¯warmupを表ã�™ã�®ã�§é›†è¨ˆã�«æ··ã�œã�ªã�„ + test('ignores warmup rounds', () => { + const warmupBase = [{ round: -1, value: 0 }, ...base]; + const warmupHead = [{ round: -1, value: 9999 }, { round: 1, value: 110 }, { round: 2, value: 230 }, { round: 3, value: 320 }]; + + expect(pairedDeltaSummary(warmupBase, warmupHead, sample => sample.value).samples).toBe(3); + }); +}); diff --git a/packages-private/diagnostics-shared/tsconfig.json b/packages-private/diagnostics-shared/tsconfig.json new file mode 100644 index 00000000000..6672c40acb3 --- /dev/null +++ b/packages-private/diagnostics-shared/tsconfig.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "esModuleInterop": true, + "skipLibCheck": true, + "noEmit": true, + "types": ["node"] + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ], + "exclude": [] +} diff --git a/packages/backend/scripts/measure-memory.mts b/packages/backend/scripts/measure-memory.mts deleted file mode 100644 index a95eb3075c3..00000000000 --- a/packages/backend/scripts/measure-memory.mts +++ /dev/null @@ -1,303 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { ChildProcess, fork } from 'node:child_process'; -import { dirname, join, resolve } from 'node:path'; -import { tmpdir } from 'node:os'; -import * as fs from 'node:fs/promises'; -import { analyzeHeapSnapshot, defaultHeapSnapshotBreakdownTopN, type HeapSnapshotData } from '../../../.github/scripts/heap-snapshot-util.mts'; -import { measureMemoryUntilStable } from '../../../.github/scripts/memory-stability-util.mts'; - -const backendDir = process.env.MK_MEMORY_BACKEND_DIR == null || process.env.MK_MEMORY_BACKEND_DIR === '' - ? join(import.meta.dirname, '..') - : resolve(process.env.MK_MEMORY_BACKEND_DIR); - -function readIntegerEnv(name, defaultValue, min) { - const rawValue = process.env[name]; - if (rawValue == null || rawValue === '') return defaultValue; - if (!/^\d+$/.test(rawValue)) throw new Error(`${name} must be an integer`); - - const value = Number(rawValue); - if (!Number.isSafeInteger(value) || value < min) throw new Error(`${name} must be >= ${min}`); - return value; -} - -function readBooleanEnv(name, defaultValue) { - const rawValue = process.env[name]; - if (rawValue == null || rawValue === '') return defaultValue; - if (rawValue === '1' || rawValue === 'true') return true; - if (rawValue === '0' || rawValue === 'false') return false; - throw new Error(`${name} must be one of: 1, 0, true, false`); -} - -const STARTUP_TIMEOUT = readIntegerEnv('MK_MEMORY_STARTUP_TIMEOUT_MS', 120000, 1); // Timeout for server startup -const IPC_TIMEOUT = readIntegerEnv('MK_MEMORY_IPC_TIMEOUT_MS', 30000, 1); // Timeout for IPC responses -const HEAP_SNAPSHOT = readBooleanEnv('MK_MEMORY_HEAP_SNAPSHOT', false); -const HEAP_SNAPSHOT_TIMEOUT = readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_TIMEOUT_MS', 120000, 1); -const HEAP_SNAPSHOT_BREAKDOWN_TOP_N = readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_BREAKDOWN_TOP_N', defaultHeapSnapshotBreakdownTopN, 1); -const HEAP_SNAPSHOT_SAVE_PATH = process.env.MK_MEMORY_HEAP_SNAPSHOT_SAVE_PATH; - -const procStatusKeys = ['VmPeak', 'VmSize', 'VmHWM', 'VmRSS', 'VmData', 'VmStk', 'VmExe', 'VmLib', 'VmPTE', 'VmSwap'] as const; -const smapsRollupKeys = ['Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean', 'Private_Dirty', 'Swap', 'SwapPss'] as const; - -type GcMessage = 'gc ok' | 'gc unavailable'; -type RuntimeMemoryUsageMessage = { - type: 'memory usage'; - value: NodeJS.MemoryUsage; -}; -type HeapSnapshotMessage = { - type: 'heap snapshot'; - path?: string; -}; -type HeapSnapshotErrorMessage = { - type: 'heap snapshot error'; - message: string; -}; -type HeapSnapshotResponseMessage = HeapSnapshotMessage | HeapSnapshotErrorMessage; - -function parseMemoryFile(content: string, keys: KS, path: string): Record { - const result = {} as Record; - for (const _key of keys) { - const key = _key as KS[number]; - const match = content.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 ${path}`); - } - } - return result; -} - -function bytesToKiB(value: number) { - return Math.round(value / 1024); -} - -async function getMemoryUsage(pid: number) { - const path = `/proc/${pid}/status`; - const status = await fs.readFile(path, 'utf-8'); - return parseMemoryFile(status, procStatusKeys, path); -} - -async function getSmapsRollupMemoryUsage(pid: number) { - const path = `/proc/${pid}/smaps_rollup`; - const smapsRollup = await fs.readFile(path, 'utf-8'); - return parseMemoryFile(smapsRollup, smapsRollupKeys, path); -} - -function isRecord(value: unknown): value is Record { - return value != null && typeof value === 'object'; -} - -function isGcMessage(message: unknown): message is GcMessage { - return message === 'gc ok' || message === 'gc unavailable'; -} - -function isRuntimeMemoryUsageMessage(message: unknown): message is RuntimeMemoryUsageMessage { - return isRecord(message) && message.type === 'memory usage' && isRecord(message.value); -} - -function isHeapSnapshotResponseMessage(message: unknown): message is HeapSnapshotResponseMessage { - if (!isRecord(message)) return false; - if (message.type === 'heap snapshot') return true; - return message.type === 'heap snapshot error' && typeof message.message === 'string'; -} - -function waitForMessage(serverProcess: ChildProcess, predicate: (message: unknown) => message is T, description: string, timeout = IPC_TIMEOUT) { - return new Promise((resolve, reject) => { - const timer = globalThis.setTimeout(() => { - serverProcess.off('message', onMessage); - reject(new Error(`Timed out waiting for ${description}`)); - }, timeout); - - const onMessage = (message: unknown) => { - if (!predicate(message)) return; - globalThis.clearTimeout(timer); - serverProcess.off('message', onMessage); - resolve(message); - }; - - serverProcess.on('message', onMessage); - }); -} - -async function getRuntimeMemoryUsage(serverProcess: ChildProcess) { - const response = waitForMessage( - serverProcess, - isRuntimeMemoryUsageMessage, - 'memory usage', - ); - - serverProcess.send('memory usage'); - - const message = await response; - const memoryUsage = message.value; - - return { - HeapTotal: bytesToKiB(memoryUsage.heapTotal), - HeapUsed: bytesToKiB(memoryUsage.heapUsed), - External: bytesToKiB(memoryUsage.external), - ArrayBuffers: bytesToKiB(memoryUsage.arrayBuffers), - }; -} - -async function getHeapSnapshotStatistics(serverProcess: ChildProcess): Promise { - if (!HEAP_SNAPSHOT) return null; - - const snapshotPath = join(tmpdir(), `misskey-backend-heap-${process.pid}-${serverProcess.pid}-${Date.now()}.heapsnapshot`); - const response = waitForMessage( - serverProcess, - isHeapSnapshotResponseMessage, - 'heap snapshot', - HEAP_SNAPSHOT_TIMEOUT, - ); - - serverProcess.send({ - type: 'heap snapshot', - path: snapshotPath, - }); - - const message = await response; - if (message.type === 'heap snapshot error') { - throw new Error(`Failed to write heap snapshot: ${message.message}`); - } - - const writtenPath = typeof message.path === 'string' ? message.path : snapshotPath; - - try { - if (HEAP_SNAPSHOT_SAVE_PATH != null && HEAP_SNAPSHOT_SAVE_PATH !== '') { - await fs.mkdir(dirname(HEAP_SNAPSHOT_SAVE_PATH), { recursive: true }); - await fs.copyFile(writtenPath, HEAP_SNAPSHOT_SAVE_PATH); - } - - const snapshot = JSON.parse(await fs.readFile(writtenPath, 'utf-8')); - return analyzeHeapSnapshot(snapshot, { breakdownTopN: HEAP_SNAPSHOT_BREAKDOWN_TOP_N }); - } finally { - await fs.unlink(writtenPath).catch(err => { - process.stderr.write(`Failed to delete heap snapshot ${writtenPath}: ${err.message}\n`); - }); - } -} - -async function getAllMemoryUsage(serverProcess: ChildProcess) { - const pid = serverProcess.pid!; - const stableSmapsRollup = await measureMemoryUntilStable( - () => getSmapsRollupMemoryUsage(pid), - ); - - return { - memoryUsage: { - ...await getMemoryUsage(pid), - ...stableSmapsRollup.memoryUsage, - ...await getRuntimeMemoryUsage(serverProcess), - }, - stability: stableSmapsRollup.stability, - }; -} - -async function measureMemory() { - const serverProcess = fork(join(backendDir, 'built/entry.js'), [], { - cwd: backendDir, - env: { - ...process.env, - NODE_ENV: 'production', - MK_DISABLE_CLUSTERING: '1', - MK_ONLY_SERVER: '1', - MK_NO_DAEMONS: '1', - }, - stdio: ['pipe', 'pipe', 'pipe', 'ipc'], - execArgv: [...process.execArgv, '--expose-gc'], - }); - - const serverReady = waitForMessage( - serverProcess, - (message): message is 'ok' => message === 'ok', - 'server startup', - STARTUP_TIMEOUT, - ); - - serverProcess.stdout?.on('data', (data) => { - process.stderr.write(`[server stdout] ${data}`); - }); - - serverProcess.stderr?.on('data', (data) => { - process.stderr.write(`[server stderr] ${data}`); - }); - - serverProcess.on('error', (err) => { - process.stderr.write(`[server error] ${err}\n`); - }); - - async function triggerGc() { - const ok = waitForMessage( - serverProcess, - isGcMessage, - 'GC completion', - ); - - serverProcess.send('gc'); - - const message = await ok; - if (message === 'gc unavailable') { - throw new Error('GC is unavailable. Start the process with --expose-gc to enable this feature.'); - } - } - - const startupStartTime = Date.now(); - try { - await serverReady; - } catch (err) { - serverProcess.kill('SIGTERM'); - throw err; - } - - const startupTime = Date.now() - startupStartTime; - process.stderr.write(`Server started in ${startupTime}ms\n`); - - await triggerGc(); - - const afterGc = await getAllMemoryUsage(serverProcess); - process.stderr.write(`Memory ${afterGc.stability.converged ? 'stabilized' : 'did not stabilize'} after ${afterGc.stability.readingCount} readings over ${Math.round(afterGc.stability.elapsedMs)}ms\n`); - - const heapSnapshotAfterGc = await getHeapSnapshotStatistics(serverProcess); - - const serverExited = new Promise(resolve => { - const timer = globalThis.setTimeout(() => { - serverProcess.kill('SIGKILL'); - resolve(); - }, 10000); - serverProcess.once('exit', () => { - globalThis.clearTimeout(timer); - resolve(); - }); - }); - serverProcess.kill('SIGTERM'); - await serverExited; - - return { - timestamp: new Date().toISOString(), - phases: { - afterGc: { - memoryUsage: afterGc.memoryUsage, - memoryStability: afterGc.stability, - heapSnapshot: heapSnapshotAfterGc, - }, - }, - }; -} - -export type MemorySample = Awaited>; - -async function main() { - console.log(JSON.stringify(await measureMemory(), null, 2)); -} - -main().catch((err) => { - console.error(JSON.stringify({ - error: err.message, - timestamp: new Date().toISOString(), - })); - process.exit(1); -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f82d6b63f3..53a344d0e5b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -70,6 +70,126 @@ importers: specifier: npm:@typescript/typescript6@6.0.2 version: '@typescript/typescript6@6.0.2' + packages-private/changelog-checker: + devDependencies: + '@types/mdast': + specifier: 4.0.4 + version: 4.0.4 + '@types/node': + specifier: 26.1.1 + version: 26.1.1 + '@vitest/coverage-v8': + specifier: 4.1.10 + version: 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) + mdast-util-to-string: + specifier: 4.0.0 + version: 4.0.0 + remark: + specifier: 15.0.1 + version: 15.0.1 + remark-parse: + specifier: 11.0.0 + version: 11.0.0 + tsx: + specifier: 4.23.1 + version: 4.23.1 + unified: + specifier: 11.0.5 + version: 11.0.5 + vitest: + specifier: 4.1.10 + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + + packages-private/diagnostics-backend: + dependencies: + diagnostics-shared: + specifier: workspace:* + version: link:../diagnostics-shared + execa: + specifier: 9.6.1 + version: 9.6.1 + devDependencies: + '@types/node': + specifier: 26.1.1 + version: 26.1.1 + '@types/pg': + specifier: 8.20.0 + version: 8.20.0 + ioredis: + specifier: 5.11.1 + version: 5.11.1 + pg: + specifier: 8.22.0 + version: 8.22.0 + tsx: + specifier: 4.23.1 + version: 4.23.1 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 4.1.10 + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + + packages-private/diagnostics-frontend-browser: + dependencies: + diagnostics-shared: + specifier: workspace:* + version: link:../diagnostics-shared + devDependencies: + '@types/node': + specifier: 26.1.1 + version: 26.1.1 + frontend: + specifier: workspace:* + version: link:../../packages/frontend + playwright: + specifier: 1.61.1 + version: 1.61.1 + tsx: + specifier: 4.23.1 + version: 4.23.1 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 4.1.10 + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + + packages-private/diagnostics-frontend-bundle: + dependencies: + diagnostics-shared: + specifier: workspace:* + version: link:../diagnostics-shared + devDependencies: + '@types/node': + specifier: 26.1.1 + version: 26.1.1 + tsx: + specifier: 4.23.1 + version: 4.23.1 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: 8.1.4 + version: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) + vitest: + specifier: 4.1.10 + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + + packages-private/diagnostics-shared: + devDependencies: + '@types/node': + specifier: 26.1.1 + version: 26.1.1 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 4.1.10 + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + packages/backend: dependencies: '@aws-sdk/client-s3': @@ -504,10 +624,10 @@ importers: version: 5.1.0 vite: specifier: 8.1.4 - version: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0) + version: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) vitest: specifier: 4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) vitest-mock-extended: specifier: 4.0.0 version: 4.0.0(@typescript/typescript6@6.0.2)(vitest@4.1.10) @@ -944,7 +1064,7 @@ importers: version: 1.1.5 vite: specifier: 8.1.4 - version: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0) + version: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) devDependencies: '@types/estree': specifier: 1.0.9 @@ -1263,7 +1383,7 @@ importers: version: 0.33.0 vitest: specifier: 4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) vitest-websocket-mock: specifier: 0.7.0 version: 0.7.0(vitest@4.1.10) @@ -7772,6 +7892,9 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + remark@15.0.1: + resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} + rename@1.0.4: resolution: {integrity: sha512-YMM6Fn3lrFOCjhORKjj+z/yizj8WSzv3F3YUlpJA20fteWCb0HbJU19nvuRBPUM5dWgxJcHP+kix3M+5NowJyA==} @@ -8674,6 +8797,11 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tsx@4.23.1: + resolution: {integrity: sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==} + engines: {node: '>=18.0.0'} + hasBin: true + tsyringe@4.10.0: resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} engines: {node: '>= 6.0.0'} @@ -12239,13 +12367,27 @@ snapshots: vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0) vue: 3.5.39(typescript@6.0.2) - '@vitest/browser-playwright@4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(playwright@1.61.1)(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0))(vitest@4.1.10)': + '@vitest/browser-playwright@4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(playwright@1.61.1)(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10)': + dependencies: + '@vitest/browser': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10) + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + playwright: 1.61.1 + tinyrainbow: 3.1.0 + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + optional: true + + '@vitest/browser-playwright@4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(playwright@1.61.1)(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10)': dependencies: - '@vitest/browser': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0))(vitest@4.1.10) - '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + '@vitest/browser': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10) + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) playwright: 1.61.1 tinyrainbow: 3.1.0 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) transitivePeerDependencies: - bufferutil - msw @@ -12266,16 +12408,48 @@ snapshots: - utf-8-validate - vite - '@vitest/browser@4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0))(vitest@4.1.10)': + '@vitest/browser-playwright@4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(playwright@1.61.1)(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10)': + dependencies: + '@vitest/browser': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10) + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + playwright: 1.61.1 + tinyrainbow: 3.1.0 + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + optional: true + + '@vitest/browser@4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10)': + dependencies: + '@blazediff/core': 1.9.1 + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + '@vitest/utils': 4.1.10 + magic-string: 0.30.21 + pngjs: 7.0.0 + sirv: 3.0.2 + tinyrainbow: 3.1.0 + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + optional: true + + '@vitest/browser@4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10)': dependencies: '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) '@vitest/utils': 4.1.10 magic-string: 0.30.21 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - bufferutil @@ -12301,6 +12475,24 @@ snapshots: - utf-8-validate - vite + '@vitest/browser@4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10)': + dependencies: + '@blazediff/core': 1.9.1 + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + '@vitest/utils': 4.1.10 + magic-string: 0.30.21 + pngjs: 7.0.0 + sirv: 3.0.2 + tinyrainbow: 3.1.0 + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + optional: true + '@vitest/coverage-v8@4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10)': dependencies: '@bcoe/v8-coverage': 1.0.2 @@ -12313,9 +12505,9 @@ snapshots: obug: 2.1.1 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) optionalDependencies: - '@vitest/browser': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0))(vitest@4.1.10) + '@vitest/browser': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10) '@vitest/expect@2.0.5': dependencies: @@ -12341,14 +12533,23 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0))': + '@vitest/mocker@4.1.10(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2) - vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0) + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) + + '@vitest/mocker@4.1.10(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))': + dependencies: + '@vitest/spy': 4.1.10 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + msw: 2.15.0(@types/node@26.1.1)(typescript@5.9.3) + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) '@vitest/mocker@4.1.10(msw@2.15.0(@types/node@26.1.1)(typescript@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0))': dependencies: @@ -12359,6 +12560,15 @@ snapshots: msw: 2.15.0(@types/node@26.1.1)(typescript@6.0.2) vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0) + '@vitest/mocker@4.1.10(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))': + dependencies: + '@vitest/spy': 4.1.10 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + msw: 2.15.0(@types/node@26.1.1)(typescript@7.0.2) + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) + '@vitest/pretty-format@2.0.5': dependencies: tinyrainbow: 1.2.0 @@ -15563,6 +15773,32 @@ snapshots: - '@types/node' optional: true + msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3): + dependencies: + '@inquirer/confirm': 6.0.12(@types/node@26.1.1) + '@mswjs/interceptors': 0.41.8 + '@open-draft/deferred-promise': 3.0.0 + '@types/statuses': 2.0.6 + cookie: 1.1.1 + graphql: 16.14.0 + headers-polyfill: 5.0.1 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.11.11 + statuses: 2.0.2 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.1 + type-fest: 5.6.0 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + optional: true + msw@2.15.0(@types/node@26.1.1)(typescript@6.0.2): dependencies: '@inquirer/confirm': 6.0.12(@types/node@26.1.1) @@ -15588,6 +15824,32 @@ snapshots: transitivePeerDependencies: - '@types/node' + msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2): + dependencies: + '@inquirer/confirm': 6.0.12(@types/node@26.1.1) + '@mswjs/interceptors': 0.41.8 + '@open-draft/deferred-promise': 3.0.0 + '@types/statuses': 2.0.6 + cookie: 1.1.1 + graphql: 16.14.0 + headers-polyfill: 5.0.1 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.11.11 + statuses: 2.0.2 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.1 + type-fest: 5.6.0 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 7.0.2 + transitivePeerDependencies: + - '@types/node' + optional: true + muggle-string@0.4.1: {} multer@2.2.0: @@ -16494,6 +16756,15 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 + remark@15.0.1: + dependencies: + '@types/mdast': 4.0.4 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + rename@1.0.4: dependencies: debug: 2.6.9 @@ -17482,6 +17753,12 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tsx@4.23.1: + dependencies: + esbuild: 0.28.1 + optionalDependencies: + fsevents: 2.3.3 + tsyringe@4.10.0: dependencies: tslib: 1.14.1 @@ -17773,6 +18050,22 @@ snapshots: terser: 5.48.0 tsx: 4.23.0 + vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.5 + postcss: 8.5.18 + rolldown: 1.1.5 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 26.1.1 + esbuild: 0.28.1 + fsevents: 2.3.3 + sass: 1.100.0 + sass-embedded: 1.100.0 + terser: 5.48.0 + tsx: 4.23.1 + vitest-fetch-mock@0.4.5(vitest@4.1.10): dependencies: vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) @@ -17781,17 +18074,17 @@ snapshots: dependencies: ts-essentials: 10.2.0(@typescript/typescript6@6.0.2) typescript: '@typescript/typescript6@6.0.2' - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) vitest-websocket-mock@0.7.0(vitest@4.1.10): dependencies: mock-socket: 9.3.1 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) - vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)): + vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0)) + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -17808,12 +18101,43 @@ snapshots: tinyexec: 1.1.2 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0) + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@types/node': 26.1.1 + '@vitest/browser-playwright': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(playwright@1.61.1)(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10) + '@vitest/coverage-v8': 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) + happy-dom: 20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - msw + + vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)): + dependencies: + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.5 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.1.2 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 26.1.1 - '@vitest/browser-playwright': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(@typescript/typescript6@6.0.2))(playwright@1.61.1)(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.0))(vitest@4.1.10) + '@vitest/browser-playwright': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(playwright@1.61.1)(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10) '@vitest/coverage-v8': 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) happy-dom: 20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: @@ -17850,6 +18174,37 @@ snapshots: transitivePeerDependencies: - msw + vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)): + dependencies: + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.5 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.1.2 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@types/node': 26.1.1 + '@vitest/browser-playwright': 4.1.10(bufferutil@4.1.0)(msw@2.15.0(@types/node@26.1.1)(typescript@7.0.2))(playwright@1.61.1)(utf-8-validate@6.0.6)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1))(vitest@4.1.10) + '@vitest/coverage-v8': 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) + happy-dom: 20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - msw + void-elements@3.1.0: {} vscode-jsonrpc@8.2.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b6b2b67cf57..c280df00f27 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,6 +11,7 @@ packages: - packages/misskey-js/generator - packages/misskey-reversi - packages/misskey-bubble-game + - packages-private/* allowBuilds: '@nestjs/core': true '@parcel/watcher': true diff --git a/scripts/changelog-checker/.gitignore b/scripts/changelog-checker/.gitignore deleted file mode 100644 index 882936f9bdd..00000000000 --- a/scripts/changelog-checker/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -coverage -.idea \ No newline at end of file diff --git a/scripts/changelog-checker/package-lock.json b/scripts/changelog-checker/package-lock.json deleted file mode 100644 index f2f48d92f7b..00000000000 --- a/scripts/changelog-checker/package-lock.json +++ /dev/null @@ -1,2773 +0,0 @@ -{ - "name": "changelog-checker", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "changelog-checker", - "version": "1.0.0", - "devDependencies": { - "@types/mdast": "4.0.4", - "@types/node": "26.1.1", - "@vitest/coverage-v8": "4.1.10", - "mdast-util-to-string": "4.0.0", - "remark": "15.0.1", - "remark-parse": "11.0.0", - "typescript": "7.0.2", - "unified": "11.0.5", - "vite": "8.1.4", - "vite-node": "6.0.0", - "vitest": "4.1.10" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.139.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", - "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", - "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", - "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", - "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", - "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", - "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", - "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", - "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", - "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", - "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", - "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", - "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", - "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", - "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.11.1", - "@emnapi/runtime": "1.11.1", - "@napi-rs/wasm-runtime": "^1.1.6" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", - "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", - "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dev": true, - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", - "dev": true - }, - "node_modules/@types/node": { - "version": "26.1.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", - "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~8.3.0" - } - }, - "node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", - "dev": true - }, - "node_modules/@typescript/typescript-aix-ppc64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", - "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-darwin-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", - "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-darwin-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", - "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-freebsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", - "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-freebsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", - "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-arm": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", - "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", - "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-loong64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", - "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-mips64el": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", - "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-ppc64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", - "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-riscv64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", - "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-s390x": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", - "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", - "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-netbsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", - "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-netbsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", - "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-openbsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", - "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-openbsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", - "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-sunos-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", - "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-win32-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", - "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-win32-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", - "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@vitest/coverage-v8": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.10.tgz", - "integrity": "sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.10", - "ast-v8-to-istanbul": "^1.0.0", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-reports": "^3.2.0", - "magicast": "^0.5.2", - "obug": "^2.1.1", - "std-env": "^4.0.0-rc.1", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "4.1.10", - "vitest": "4.1.10" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.1.10", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.10", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/ast-v8-to-istanbul": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", - "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^10.0.0" - } - }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/cac": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz", - "integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", - "dev": true, - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "dev": true, - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "dev": true, - "license": "MIT" - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/expect-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", - "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/js-tokens": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/magicast": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", - "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "source-map-js": "^1.2.1" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", - "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", - "dev": true, - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz", - "integrity": "sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==", - "dev": true, - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", - "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", - "dev": true, - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dev": true, - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", - "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", - "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", - "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT" - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.5.20", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.20.tgz", - "integrity": "sha512-lW616l85ucIQL+FocMmL7pQFPqBmwejrCMg+iPxyImlrANNJG9NHq/RkyCZopDhd8C3LA03PHRJDjkbGu8vvug==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.16", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/remark": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", - "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", - "dev": true, - "dependencies": { - "@types/mdast": "^4.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "dev": true, - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-stringify": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", - "dev": true, - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-to-markdown": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rolldown": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", - "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.139.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.1.5", - "@rolldown/binding-darwin-arm64": "1.1.5", - "@rolldown/binding-darwin-x64": "1.1.5", - "@rolldown/binding-freebsd-x64": "1.1.5", - "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", - "@rolldown/binding-linux-arm64-gnu": "1.1.5", - "@rolldown/binding-linux-arm64-musl": "1.1.5", - "@rolldown/binding-linux-ppc64-gnu": "1.1.5", - "@rolldown/binding-linux-s390x-gnu": "1.1.5", - "@rolldown/binding-linux-x64-gnu": "1.1.5", - "@rolldown/binding-linux-x64-musl": "1.1.5", - "@rolldown/binding-openharmony-arm64": "1.1.5", - "@rolldown/binding-wasm32-wasi": "1.1.5", - "@rolldown/binding-win32-arm64-msvc": "1.1.5", - "@rolldown/binding-win32-x64-msvc": "1.1.5" - } - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", - "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", - "dev": true, - "license": "MIT" - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/trough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true - }, - "node_modules/typescript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", - "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc" - }, - "engines": { - "node": ">=16.20.0" - }, - "optionalDependencies": { - "@typescript/typescript-aix-ppc64": "7.0.2", - "@typescript/typescript-darwin-arm64": "7.0.2", - "@typescript/typescript-darwin-x64": "7.0.2", - "@typescript/typescript-freebsd-arm64": "7.0.2", - "@typescript/typescript-freebsd-x64": "7.0.2", - "@typescript/typescript-linux-arm": "7.0.2", - "@typescript/typescript-linux-arm64": "7.0.2", - "@typescript/typescript-linux-loong64": "7.0.2", - "@typescript/typescript-linux-mips64el": "7.0.2", - "@typescript/typescript-linux-ppc64": "7.0.2", - "@typescript/typescript-linux-riscv64": "7.0.2", - "@typescript/typescript-linux-s390x": "7.0.2", - "@typescript/typescript-linux-x64": "7.0.2", - "@typescript/typescript-netbsd-arm64": "7.0.2", - "@typescript/typescript-netbsd-x64": "7.0.2", - "@typescript/typescript-openbsd-arm64": "7.0.2", - "@typescript/typescript-openbsd-x64": "7.0.2", - "@typescript/typescript-sunos-x64": "7.0.2", - "@typescript/typescript-win32-arm64": "7.0.2", - "@typescript/typescript-win32-x64": "7.0.2" - } - }, - "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unified": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", - "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vite": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.4.tgz", - "integrity": "sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.5", - "postcss": "^8.5.16", - "rolldown": "~1.1.4", - "tinyglobby": "^0.2.17" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.3.0", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-6.0.0.tgz", - "integrity": "sha512-oj4PVrT+pDh6GYf5wfUXkcZyekYS8kKPfLPXVl8qe324Ec6l4K2DUKNadRbZ3LQl0qGcDz+PyOo7ZAh00Y+JjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^7.0.0", - "es-module-lexer": "^2.0.0", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "vite": "^8.0.0" - }, - "bin": { - "vite-node": "dist/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://opencollective.com/antfu" - } - }, - "node_modules/vitest": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", - "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.1.10", - "@vitest/mocker": "4.1.10", - "@vitest/pretty-format": "4.1.10", - "@vitest/runner": "4.1.10", - "@vitest/snapshot": "4.1.10", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.10", - "@vitest/browser-preview": "4.1.10", - "@vitest/browser-webdriverio": "4.1.10", - "@vitest/coverage-istanbul": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "@vitest/ui": "4.1.10", - "happy-dom": "*", - "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/coverage-istanbul": { - "optional": true - }, - "@vitest/coverage-v8": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "vite": { - "optional": false - } - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - } - } -} diff --git a/scripts/changelog-checker/package.json b/scripts/changelog-checker/package.json deleted file mode 100644 index f557a8c072e..00000000000 --- a/scripts/changelog-checker/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "changelog-checker", - "version": "1.0.0", - "description": "", - "type": "module", - "scripts": { - "run": "vite-node src/index.ts", - "test": "vitest run", - "test:coverage": "vitest run --coverage" - }, - "devDependencies": { - "@types/mdast": "4.0.4", - "@types/node": "26.1.1", - "@vitest/coverage-v8": "4.1.10", - "mdast-util-to-string": "4.0.0", - "remark": "15.0.1", - "remark-parse": "11.0.0", - "typescript": "7.0.2", - "unified": "11.0.5", - "vite": "8.1.4", - "vite-node": "6.0.0", - "vitest": "4.1.10" - } -} diff --git a/scripts/changelog-checker/vite.config.ts b/scripts/changelog-checker/vite.config.ts deleted file mode 100644 index 46db02c8067..00000000000 --- a/scripts/changelog-checker/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {defineConfig} from 'vite'; - - -const config = defineConfig({}); - -export default config; From b2d07ca6e3bb3977c04b95e74016321de9f09137 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:01:21 +0900 Subject: [PATCH 421/578] Update .coderabbit.yaml --- .coderabbit.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 415c9ddcae6..e7d070843c0 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -15,3 +15,9 @@ reviews: - "dependabot[bot]" - "renovate[bot]" - "github-actions[bot]" + path_instructions: + - path: "**/*" + instructions: | + ã€�レビュー対象外】 + - フォーマットé�•å��ã€�型エラーã€�SPDXヘッダーã�®è¨˜è¼‰æ¼�れ等ã€�é�™çš„è§£æž�ã�§æ¤œå‡ºå�¯èƒ½ã�ªå•�題ã�«ã�¤ã�„ã�¦ã�¯ã€�別Workflow(CI/CD)ã�§ãƒ�ェックã�•れるã�Ÿã‚�ã€�レビュー対象外ã�¨ã�—ã�¦ç„¡è¦–ã�—ã�¦ã��ã� ã�•ã�„。 + - ã�“れらã�®å•�題ã�«ã�¤ã�„ã�¦ã�®æŒ‡æ‘˜ã‚„コメントã�¯è¡Œã‚�ã�ªã�„ã�§ã��ã� ã�•ã�„。 From ccd04fbcd9c686f7ac644a89e0e92143e6a1b70c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:03:23 +0900 Subject: [PATCH 422/578] Update .coderabbit.yaml --- .coderabbit.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index e7d070843c0..007c507c7eb 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -20,4 +20,5 @@ reviews: instructions: | ã€�レビュー対象外】 - フォーマットé�•å��ã€�型エラーã€�SPDXヘッダーã�®è¨˜è¼‰æ¼�れ等ã€�é�™çš„è§£æž�ã�§æ¤œå‡ºå�¯èƒ½ã�ªå•�題ã�«ã�¤ã�„ã�¦ã�¯ã€�別Workflow(CI/CD)ã�§ãƒ�ェックã�•れるã�Ÿã‚�ã€�レビュー対象外ã�¨ã�—ã�¦ç„¡è¦–ã�—ã�¦ã��ã� ã�•ã�„。 + - CHANGELOGã�«é–¢ã�™ã‚‹å•�題も無視ã�—ã�¦ã��ã� ã�•ã�„。 - ã�“れらã�®å•�題ã�«ã�¤ã�„ã�¦ã�®æŒ‡æ‘˜ã‚„コメントã�¯è¡Œã‚�ã�ªã�„ã�§ã��ã� ã�•ã�„。 From 1dcd6c287cb55609f448764ea287c48e787e7876 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:06:26 +0900 Subject: [PATCH 423/578] Update .coderabbit.yaml --- .coderabbit.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 007c507c7eb..033f614715d 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -22,3 +22,6 @@ reviews: - フォーマットé�•å��ã€�型エラーã€�SPDXヘッダーã�®è¨˜è¼‰æ¼�れ等ã€�é�™çš„è§£æž�ã�§æ¤œå‡ºå�¯èƒ½ã�ªå•�題ã�«ã�¤ã�„ã�¦ã�¯ã€�別Workflow(CI/CD)ã�§ãƒ�ェックã�•れるã�Ÿã‚�ã€�レビュー対象外ã�¨ã�—ã�¦ç„¡è¦–ã�—ã�¦ã��ã� ã�•ã�„。 - CHANGELOGã�«é–¢ã�™ã‚‹å•�題も無視ã�—ã�¦ã��ã� ã�•ã�„。 - ã�“れらã�®å•�題ã�«ã�¤ã�„ã�¦ã�®æŒ‡æ‘˜ã‚„コメントã�¯è¡Œã‚�ã�ªã�„ã�§ã��ã� ã�•ã�„。 + + ã€�注力ã�—ã�¦ã�»ã�—ã�„観点】 + - ビジãƒ�スロジックã�®ä¸�å‚™ã€�セキュリティã€�パフォーマンスã€�設計パターンã�®é�©åˆ‡æ€§ã�ªã�©ã�«ç„¦ç‚¹ã‚’当ã�¦ã�¦ãƒ¬ãƒ“ューã�—ã�¦ã��ã� ã�•ã�„。 From f138a48419605af5b445cc353d0f234eed7866ef Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:09:21 +0900 Subject: [PATCH 424/578] Update .coderabbit.yaml --- .coderabbit.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 033f614715d..b5a669a5c31 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -20,8 +20,8 @@ reviews: instructions: | ã€�レビュー対象外】 - フォーマットé�•å��ã€�型エラーã€�SPDXヘッダーã�®è¨˜è¼‰æ¼�れ等ã€�é�™çš„è§£æž�ã�§æ¤œå‡ºå�¯èƒ½ã�ªå•�題ã�«ã�¤ã�„ã�¦ã�¯ã€�別Workflow(CI/CD)ã�§ãƒ�ェックã�•れるã�Ÿã‚�ã€�レビュー対象外ã�¨ã�—ã�¦ç„¡è¦–ã�—ã�¦ã��ã� ã�•ã�„。 - - CHANGELOGã�«é–¢ã�™ã‚‹å•�題も無視ã�—ã�¦ã��ã� ã�•ã�„。 - - ã�“れらã�®å•�題ã�«ã�¤ã�„ã�¦ã�®æŒ‡æ‘˜ã‚„コメントã�¯è¡Œã‚�ã�ªã�„ã�§ã��ã� ã�•ã�„。 ã€�注力ã�—ã�¦ã�»ã�—ã�„観点】 - ビジãƒ�スロジックã�®ä¸�å‚™ã€�セキュリティã€�パフォーマンスã€�設計パターンã�®é�©åˆ‡æ€§ã�ªã�©ã�«ç„¦ç‚¹ã‚’当ã�¦ã�¦ãƒ¬ãƒ“ューã�—ã�¦ã��ã� ã�•ã�„。 + path_filters: + - "!CHANGELOG.md" From 159b1a4484f56d5087ec29280a7ce5cc863a3e4d Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:30:46 +0900 Subject: [PATCH 425/578] Update .coderabbit.yaml --- .coderabbit.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index b5a669a5c31..379e3f2607f 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -25,3 +25,4 @@ reviews: - ビジãƒ�スロジックã�®ä¸�å‚™ã€�セキュリティã€�パフォーマンスã€�設計パターンã�®é�©åˆ‡æ€§ã�ªã�©ã�«ç„¦ç‚¹ã‚’当ã�¦ã�¦ãƒ¬ãƒ“ューã�—ã�¦ã��ã� ã�•ã�„。 path_filters: - "!CHANGELOG.md" + - "!**/__snapshots__/**" From b51d5ba0a085f1b72aa206ef64d1acc890185ec5 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 21 Jul 2026 11:26:53 +0900 Subject: [PATCH 426/578] =?UTF-8?q?frontend=20bundle=20diagnostics=20?= =?UTF-8?q?=E3=81=A8=20frontend=20browser=20diagnostics=20=E3=82=92?= =?UTF-8?q?=E7=B5=B1=E5=90=88=20(#17757)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(gh): unify frontend diagnostics * refactor(gh): unify frontend diagnostics markdown rendering * docs(gh): restore frontend diagnostics comments * wip * fix * refactor: 呼称をbase/headã�«çµ±ä¸€ * tweak * Update types.ts * fix --- .../frontend-browser-diagnostics.comment.yml | 44 ------ .../frontend-bundle-diagnostics.comment.yml | 44 ------ .../frontend-bundle-diagnostics.inspect.yml | 148 ------------------ .../frontend-diagnostics.comment.yml | 75 +++++++++ ...t.yml => frontend-diagnostics.inspect.yml} | 145 ++++++++++------- .github/workflows/packages-private.yml | 3 +- packages-private/README.md | 12 +- .../src/render-md.ts | 31 ---- .../test/render.test.ts | 69 -------- .../eslint.config.js | 25 --- .../diagnostics-frontend-bundle/package.json | 22 --- .../src/render-md.ts | 32 ---- .../diagnostics-frontend-bundle/src/report.ts | 33 ---- .../test/__snapshots__/render-md.md | 100 ------------ .../diagnostics-frontend-bundle/tsconfig.json | 20 --- .../eslint.config.js | 0 .../package.json | 6 +- .../src/browser/controller.ts | 4 +- .../src/browser/diagnostics.ts | 2 +- .../src/browser/network.ts | 2 +- .../src/browser}/report/html-styles.ts | 0 .../src/browser}/report/html.ts | 2 +- .../src/browser}/scenario.ts | 4 +- .../src/browser}/server.ts | 11 +- .../src/browser}/summarize.ts | 2 +- .../src/browser}/types.ts | 5 + .../src/bundle}/chunk-report.ts | 128 +++++++-------- .../src/bundle}/fs-utils.ts | 5 +- .../src/bundle}/manifest.ts | 27 ++-- .../src/bundle}/visualizer.ts | 22 +-- .../src/inspect-browser.ts} | 10 +- .../src/render-browser-html.ts} | 8 +- .../diagnostics-frontend/src/render-md.ts | 62 ++++++++ .../src/report.ts} | 56 +++++-- .../test/__snapshots__/report.md} | 101 +++++++++++- .../browser}/__snapshots__/render-html.html | 0 .../test/browser}/fixtures/base.json | 0 .../test/browser}/fixtures/head.json | 0 .../test/browser/render.test.ts | 44 ++++++ .../test/browser/server.test.ts | 47 ++++++ .../test/bundle/fixtures/base-stats.json} | 2 +- .../test/bundle/fixtures/head-stats.json} | 2 +- .../test/bundle/fs-utils.test.ts | 29 ++++ .../test/bundle/manifest.test.ts | 24 +++ .../test/report.test.ts} | 75 +++++---- .../tsconfig.json | 0 pnpm-lock.yaml | 24 +-- 47 files changed, 695 insertions(+), 812 deletions(-) delete mode 100644 .github/workflows/frontend-browser-diagnostics.comment.yml delete mode 100644 .github/workflows/frontend-bundle-diagnostics.comment.yml delete mode 100644 .github/workflows/frontend-bundle-diagnostics.inspect.yml create mode 100644 .github/workflows/frontend-diagnostics.comment.yml rename .github/workflows/{frontend-browser-diagnostics.inspect.yml => frontend-diagnostics.inspect.yml} (51%) delete mode 100644 packages-private/diagnostics-frontend-browser/src/render-md.ts delete mode 100644 packages-private/diagnostics-frontend-browser/test/render.test.ts delete mode 100644 packages-private/diagnostics-frontend-bundle/eslint.config.js delete mode 100644 packages-private/diagnostics-frontend-bundle/package.json delete mode 100644 packages-private/diagnostics-frontend-bundle/src/render-md.ts delete mode 100644 packages-private/diagnostics-frontend-bundle/src/report.ts delete mode 100644 packages-private/diagnostics-frontend-bundle/test/__snapshots__/render-md.md delete mode 100644 packages-private/diagnostics-frontend-bundle/tsconfig.json rename packages-private/{diagnostics-frontend-browser => diagnostics-frontend}/eslint.config.js (100%) rename packages-private/{diagnostics-frontend-browser => diagnostics-frontend}/package.json (76%) rename packages-private/{diagnostics-frontend-browser => diagnostics-frontend}/src/browser/controller.ts (99%) rename packages-private/{diagnostics-frontend-browser => diagnostics-frontend}/src/browser/diagnostics.ts (92%) rename packages-private/{diagnostics-frontend-browser => diagnostics-frontend}/src/browser/network.ts (99%) rename packages-private/{diagnostics-frontend-browser/src => diagnostics-frontend/src/browser}/report/html-styles.ts (100%) rename packages-private/{diagnostics-frontend-browser/src => diagnostics-frontend/src/browser}/report/html.ts (98%) rename packages-private/{diagnostics-frontend-browser/src => diagnostics-frontend/src/browser}/scenario.ts (87%) rename packages-private/{diagnostics-frontend-browser/src => diagnostics-frontend/src/browser}/server.ts (90%) rename packages-private/{diagnostics-frontend-browser/src => diagnostics-frontend/src/browser}/summarize.ts (98%) rename packages-private/{diagnostics-frontend-browser/src => diagnostics-frontend/src/browser}/types.ts (87%) rename packages-private/{diagnostics-frontend-bundle/src => diagnostics-frontend/src/bundle}/chunk-report.ts (50%) rename packages-private/{diagnostics-frontend-bundle/src => diagnostics-frontend/src/bundle}/fs-utils.ts (90%) rename packages-private/{diagnostics-frontend-bundle/src => diagnostics-frontend/src/bundle}/manifest.ts (90%) rename packages-private/{diagnostics-frontend-bundle/src => diagnostics-frontend/src/bundle}/visualizer.ts (83%) rename packages-private/{diagnostics-frontend-browser/src/inspect.ts => diagnostics-frontend/src/inspect-browser.ts} (95%) rename packages-private/{diagnostics-frontend-browser/src/render-html.ts => diagnostics-frontend/src/render-browser-html.ts} (68%) create mode 100644 packages-private/diagnostics-frontend/src/render-md.ts rename packages-private/{diagnostics-frontend-browser/src/report/markdown.ts => diagnostics-frontend/src/report.ts} (86%) rename packages-private/{diagnostics-frontend-browser/test/__snapshots__/render-md.md => diagnostics-frontend/test/__snapshots__/report.md} (62%) rename packages-private/{diagnostics-frontend-browser/test => diagnostics-frontend/test/browser}/__snapshots__/render-html.html (100%) rename packages-private/{diagnostics-frontend-browser/test => diagnostics-frontend/test/browser}/fixtures/base.json (100%) rename packages-private/{diagnostics-frontend-browser/test => diagnostics-frontend/test/browser}/fixtures/head.json (100%) create mode 100644 packages-private/diagnostics-frontend/test/browser/render.test.ts create mode 100644 packages-private/diagnostics-frontend/test/browser/server.test.ts rename packages-private/{diagnostics-frontend-bundle/test/fixtures/before-stats.json => diagnostics-frontend/test/bundle/fixtures/base-stats.json} (99%) rename packages-private/{diagnostics-frontend-bundle/test/fixtures/after-stats.json => diagnostics-frontend/test/bundle/fixtures/head-stats.json} (98%) create mode 100644 packages-private/diagnostics-frontend/test/bundle/fs-utils.test.ts create mode 100644 packages-private/diagnostics-frontend/test/bundle/manifest.test.ts rename packages-private/{diagnostics-frontend-bundle/test/render-md.test.ts => diagnostics-frontend/test/report.test.ts} (53%) rename packages-private/{diagnostics-frontend-browser => diagnostics-frontend}/tsconfig.json (100%) diff --git a/.github/workflows/frontend-browser-diagnostics.comment.yml b/.github/workflows/frontend-browser-diagnostics.comment.yml deleted file mode 100644 index 5098e618adc..00000000000 --- a/.github/workflows/frontend-browser-diagnostics.comment.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Frontend browser diagnostics (comment) - -on: - workflow_run: - workflows: - - Frontend browser diagnostics (inspect) - types: - - completed - -permissions: - actions: read - contents: read - issues: write - pull-requests: write - -jobs: - comment: - name: Comment frontend browser diagnostics report - if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' - runs-on: ubuntu-latest - concurrency: - group: frontend-browser-diagnostics-report-${{ github.event.workflow_run.id }} - cancel-in-progress: true - steps: - - name: Download browser metrics report - uses: actions/download-artifact@v8 - with: - name: frontend-browser-diagnostics - path: ${{ runner.temp }}/frontend-browser-diagnostics - github-token: ${{ github.token }} - repository: ${{ github.repository }} - run-id: ${{ github.event.workflow_run.id }} - - - name: Load PR number - id: load-pr-number - shell: bash - run: echo "pr-number=$(cat "$RUNNER_TEMP/frontend-browser-diagnostics/pr-number.txt")" >> "$GITHUB_OUTPUT" - - - name: Comment on pull request - uses: thollander/actions-comment-pull-request@v3 - with: - pr-number: ${{ steps.load-pr-number.outputs.pr-number }} - comment-tag: frontend-browser-diagnostics - file-path: ${{ runner.temp }}/frontend-browser-diagnostics/frontend-browser-diagnostics.md diff --git a/.github/workflows/frontend-bundle-diagnostics.comment.yml b/.github/workflows/frontend-bundle-diagnostics.comment.yml deleted file mode 100644 index 709c735e693..00000000000 --- a/.github/workflows/frontend-bundle-diagnostics.comment.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Frontend bundle diagnostics (comment) - -on: - workflow_run: - workflows: - - Frontend bundle diagnostics (inspect) - types: - - completed - -permissions: - actions: read - contents: read - issues: write - pull-requests: write - -jobs: - comment: - name: Comment frontend bundle report - if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' - runs-on: ubuntu-latest - concurrency: - group: frontend-bundle-diagnostics-report-${{ github.event.workflow_run.id }} - cancel-in-progress: true - steps: - - name: Download bundle report - uses: actions/download-artifact@v8 - with: - name: frontend-bundle-report - path: ${{ runner.temp }}/frontend-bundle-report - github-token: ${{ github.token }} - repository: ${{ github.repository }} - run-id: ${{ github.event.workflow_run.id }} - - - name: Load PR number - id: load-pr-number - shell: bash - run: echo "pr-number=$(cat "$RUNNER_TEMP/frontend-bundle-report/pr-number.txt")" >> "$GITHUB_OUTPUT" - - - name: Comment on pull request - uses: thollander/actions-comment-pull-request@v3 - with: - pr-number: ${{ steps.load-pr-number.outputs.pr-number }} - comment-tag: frontend-bundle-diagnostics - file-path: ${{ runner.temp }}/frontend-bundle-report/frontend-bundle-diagnostics-report.md diff --git a/.github/workflows/frontend-bundle-diagnostics.inspect.yml b/.github/workflows/frontend-bundle-diagnostics.inspect.yml deleted file mode 100644 index 0332ea6a3e9..00000000000 --- a/.github/workflows/frontend-bundle-diagnostics.inspect.yml +++ /dev/null @@ -1,148 +0,0 @@ -name: Frontend bundle diagnostics (inspect) - -on: - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review - paths: - - packages/frontend/** - - packages/frontend-shared/** - - packages/frontend-builder/** - - packages/i18n/** - - packages/icons-subsetter/** - - packages/misskey-js/** - - packages/misskey-reversi/** - - packages/misskey-bubble-game/** - - package.json - - pnpm-lock.yaml - - pnpm-workspace.yaml - - .node-version - - packages-private/diagnostics-shared/** - - packages-private/diagnostics-frontend-bundle/** - - .github/workflows/frontend-bundle-diagnostics.inspect.yml - - .github/workflows/frontend-bundle-diagnostics.comment.yml - -permissions: - contents: read - pull-requests: read - -concurrency: - group: frontend-bundle-diagnostics-inspect-${{ github.event.pull_request.number }} - cancel-in-progress: true - -jobs: - report: - name: Build frontend bundle report - runs-on: ubuntu-latest - steps: - - name: Checkout base - uses: actions/checkout@v6.0.3 - with: - repository: ${{ github.event.pull_request.base.repo.full_name }} - ref: ${{ github.event.pull_request.base.sha }} - path: before - submodules: true - - - name: Checkout pull request - uses: actions/checkout@v6.0.3 - with: - repository: ${{ github.event.pull_request.head.repo.full_name }} - ref: ${{ github.event.pull_request.head.sha }} - path: after - submodules: true - - - name: Setup pnpm - uses: pnpm/action-setup@v6.0.9 - with: - package_json_file: after/package.json - - - name: Setup Node.js - uses: actions/setup-node@v6.4.0 - with: - node-version-file: after/.node-version - cache: pnpm - cache-dependency-path: | - before/pnpm-lock.yaml - after/pnpm-lock.yaml - - - name: Install dependencies for base - working-directory: before - run: pnpm i --frozen-lockfile - - - name: Build frontend dependencies for base - working-directory: before - run: pnpm --filter "frontend^..." run build - - - name: Prepare report output - run: mkdir -p "$RUNNER_TEMP/frontend-bundle-report" - - - name: Build frontend report for base - working-directory: before - env: - FRONTEND_BUNDLE_VISUALIZER: 'true' - FRONTEND_BUNDLE_VISUALIZER_FILE: ${{ runner.temp }}/frontend-bundle-report/before-stats.json - run: pnpm --filter frontend run build - - - name: Install dependencies for pull request - working-directory: after - run: pnpm i --frozen-lockfile - - - name: Build frontend dependencies for pull request - working-directory: after - run: pnpm --filter "frontend^..." run build - - - name: Build frontend report for pull request - working-directory: after - env: - FRONTEND_BUNDLE_VISUALIZER: 'true' - FRONTEND_BUNDLE_VISUALIZER_FILE: ${{ runner.temp }}/frontend-bundle-report/after-stats.json - FRONTEND_BUNDLE_VISUALIZER_HTML_FILE: ${{ runner.temp }}/frontend-bundle-report/frontend-bundle-visualizer.html - run: pnpm --filter frontend run build - - - name: Upload bundle visualizer - id: upload-bundle-visualizer - uses: actions/upload-artifact@v7 - with: - name: frontend-bundle-visualizer - path: ${{ runner.temp }}/frontend-bundle-report/frontend-bundle-visualizer.html - if-no-files-found: error - archive: false - retention-days: 7 - - - name: Generate report markdown - shell: bash - working-directory: after - env: - BASE_SHA: ${{ github.event.pull_request.base.sha }} - HEAD_SHA: ${{ github.event.pull_request.head.sha }} - PR_NUMBER: ${{ github.event.pull_request.number }} - FRONTEND_BUNDLE_REPORT_ARTIFACT_URL: ${{ steps.upload-bundle-visualizer.outputs.artifact-url }} - run: | - REPORT_DIR="$RUNNER_TEMP/frontend-bundle-report" - pnpm --filter diagnostics-frontend-bundle run render-md \ - "$GITHUB_WORKSPACE/before" "$GITHUB_WORKSPACE/after" \ - "$REPORT_DIR/before-stats.json" "$REPORT_DIR/after-stats.json" \ - "$REPORT_DIR/frontend-bundle-diagnostics-report.md" - printf '%s\n' "$PR_NUMBER" > "$REPORT_DIR/pr-number.txt" - printf '%s\n' "$BASE_SHA" > "$REPORT_DIR/base-sha.txt" - printf '%s\n' "$HEAD_SHA" > "$REPORT_DIR/head-sha.txt" - printf '%s\n' "${{ github.event.pull_request.html_url }}" > "$REPORT_DIR/pr-url.txt" - - - name: Check report - run: | - REPORT_DIR="$RUNNER_TEMP/frontend-bundle-report" - test -s "$REPORT_DIR/before-stats.json" - test -s "$REPORT_DIR/after-stats.json" - test -s "$REPORT_DIR/frontend-bundle-diagnostics-report.md" - cat "$REPORT_DIR/frontend-bundle-diagnostics-report.md" >> "$GITHUB_STEP_SUMMARY" - - - name: Upload bundle report - uses: actions/upload-artifact@v7 - with: - name: frontend-bundle-report - path: ${{ runner.temp }}/frontend-bundle-report/ - if-no-files-found: error - retention-days: 7 diff --git a/.github/workflows/frontend-diagnostics.comment.yml b/.github/workflows/frontend-diagnostics.comment.yml new file mode 100644 index 00000000000..96deddcc583 --- /dev/null +++ b/.github/workflows/frontend-diagnostics.comment.yml @@ -0,0 +1,75 @@ +name: Frontend diagnostics (comment) + +on: + workflow_run: + workflows: + - Frontend diagnostics (inspect) + types: + - completed + +permissions: + actions: read + contents: read + issues: write + pull-requests: write + +jobs: + comment: + name: Comment frontend diagnostics report + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + concurrency: + group: frontend-diagnostics-report-${{ github.event.workflow_run.id }} + cancel-in-progress: true + steps: + - name: Download frontend diagnostics report + uses: actions/download-artifact@v8 + with: + name: frontend-diagnostics + path: ${{ runner.temp }}/frontend-diagnostics + github-token: ${{ github.token }} + repository: ${{ github.repository }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Resolve current pull request + id: resolve-pr + uses: actions/github-script@v9 + env: + PR_NUMBER_FILE: ${{ runner.temp }}/frontend-diagnostics/pr-number.txt + with: + script: | + const fs = require('fs/promises'); + const { owner, repo } = context.repo; + const workflowRun = context.payload.workflow_run; + const pullRequestNumberText = (await fs.readFile(process.env.PR_NUMBER_FILE, 'utf8')).trim(); + if (!/^[1-9]\d*$/.test(pullRequestNumberText)) { + throw new Error('Invalid pull request number in frontend diagnostics artifact.'); + } + + const pullRequestNumber = Number(pullRequestNumberText); + if (!Number.isSafeInteger(pullRequestNumber)) { + throw new Error('Pull request number in frontend diagnostics artifact is not a safe integer.'); + } + + const { data: currentPullRequest } = await github.rest.pulls.get({ + owner, + repo, + pull_number: pullRequestNumber, + }); + + if (currentPullRequest.state !== 'open' || currentPullRequest.head.sha !== workflowRun.head_sha) { + core.notice(`Skipping stale frontend diagnostics report for pull request #${pullRequestNumber}.`); + core.setOutput('is-current', 'false'); + return; + } + + core.setOutput('is-current', 'true'); + core.setOutput('pr-number', String(pullRequestNumber)); + + - name: Comment on pull request + if: steps.resolve-pr.outputs.is-current == 'true' + uses: thollander/actions-comment-pull-request@v3 + with: + pr-number: ${{ steps.resolve-pr.outputs.pr-number }} + comment-tag: frontend-diagnostics + file-path: ${{ runner.temp }}/frontend-diagnostics/frontend-diagnostics.md diff --git a/.github/workflows/frontend-browser-diagnostics.inspect.yml b/.github/workflows/frontend-diagnostics.inspect.yml similarity index 51% rename from .github/workflows/frontend-browser-diagnostics.inspect.yml rename to .github/workflows/frontend-diagnostics.inspect.yml index 7b6238c81d6..ecf06c30925 100644 --- a/.github/workflows/frontend-browser-diagnostics.inspect.yml +++ b/.github/workflows/frontend-diagnostics.inspect.yml @@ -1,4 +1,4 @@ -name: Frontend browser diagnostics (inspect) +name: Frontend diagnostics (inspect) on: pull_request: @@ -23,21 +23,21 @@ on: - .node-version - .github/misskey/test.yml - packages-private/diagnostics-shared/** - - packages-private/diagnostics-frontend-browser/** - - .github/workflows/frontend-browser-diagnostics.inspect.yml - - .github/workflows/frontend-browser-diagnostics.comment.yml + - packages-private/diagnostics-frontend/** + - .github/workflows/frontend-diagnostics.inspect.yml + - .github/workflows/frontend-diagnostics.comment.yml permissions: contents: read pull-requests: read concurrency: - group: frontend-browser-diagnostics-inspect-${{ github.event.pull_request.number }} + group: frontend-diagnostics-inspect-${{ github.event.pull_request.number }} cancel-in-progress: true jobs: report: - name: Measure frontend browser metrics + name: Measure frontend diagnostics runs-on: ubuntu-latest timeout-minutes: 90 @@ -61,79 +61,100 @@ jobs: persist-credentials: false repository: ${{ github.event.pull_request.base.repo.full_name }} ref: ${{ github.event.pull_request.base.sha }} - path: before + path: base submodules: true - - name: Checkout pull request + - name: Checkout head uses: actions/checkout@v6.0.3 with: persist-credentials: false repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.sha }} - path: after + path: head submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 with: - package_json_file: after/package.json + package_json_file: head/package.json - name: Setup Node.js uses: actions/setup-node@v6.4.0 with: - node-version-file: after/.node-version + node-version-file: head/.node-version cache: pnpm cache-dependency-path: | - before/pnpm-lock.yaml - after/pnpm-lock.yaml + base/pnpm-lock.yaml + head/pnpm-lock.yaml + + - name: Prepare report output + shell: bash + run: mkdir -p "$RUNNER_TEMP/frontend-diagnostics" - name: Install dependencies for base - working-directory: before + working-directory: base run: pnpm i --frozen-lockfile - name: Configure base - working-directory: before + working-directory: base run: cp .github/misskey/test.yml .config - name: Build base - working-directory: before + working-directory: base + env: + FRONTEND_BUNDLE_VISUALIZER: 'true' + FRONTEND_BUNDLE_VISUALIZER_FILE: ${{ runner.temp }}/frontend-diagnostics/base-bundle-stats.json run: pnpm build - - name: Install dependencies for pull request - working-directory: after + - name: Install dependencies for head + working-directory: head run: pnpm i --frozen-lockfile - - name: Configure pull request - working-directory: after + - name: Configure head + working-directory: head run: cp .github/misskey/test.yml .config - - name: Build pull request - working-directory: after + - name: Build head + working-directory: head + env: + FRONTEND_BUNDLE_VISUALIZER: 'true' + FRONTEND_BUNDLE_VISUALIZER_FILE: ${{ runner.temp }}/frontend-diagnostics/head-bundle-stats.json + FRONTEND_BUNDLE_VISUALIZER_HTML_FILE: ${{ runner.temp }}/frontend-diagnostics/frontend-bundle-visualizer.html run: pnpm build + - name: Upload bundle visualizer + id: upload-bundle-visualizer + uses: actions/upload-artifact@v7 + with: + name: frontend-bundle-visualizer + path: ${{ runner.temp }}/frontend-diagnostics/frontend-bundle-visualizer.html + if-no-files-found: error + archive: false + retention-days: 7 + - name: Install Playwright browsers - working-directory: after/packages-private/diagnostics-frontend-browser + working-directory: head/packages-private/diagnostics-frontend run: pnpm exec playwright install --with-deps --no-shell chromium - name: Measure frontend browser metrics shell: bash - working-directory: after + working-directory: head env: FRONTEND_BROWSER_METRICS_SAMPLE_COUNT: 5 MK_ENABLE_CROSS_ORIGIN_ISOLATION: "true" - # 計測ãƒ�ーãƒ�スã�¯afterå�´ã�®ã‚‚ã�®ã‚’両方ã�«ä½¿ã�†ã�Œã€�æˆ�果物ã�¯runnerã�®workspace直下ã�«å‡ºã�™ + # 計測ãƒ�ーãƒ�スã�¯headå�´ã�®ã‚‚ã�®ã‚’両方ã�«ä½¿ã�†ã�Œã€�æˆ�果物ã�¯runnerã�®workspace直下ã�«å‡ºã�™ FRONTEND_BROWSER_HEAP_SNAPSHOT_OUTPUT_DIR: ${{ github.workspace }} run: | - REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" - mkdir -p "$REPORT_DIR" - pnpm --filter diagnostics-frontend-browser run inspect \ - "$GITHUB_WORKSPACE/before" "$GITHUB_WORKSPACE/after" \ - "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" + REPORT_DIR="$RUNNER_TEMP/frontend-diagnostics" + pnpm --filter diagnostics-frontend run inspect-browser \ + "$GITHUB_WORKSPACE/base" "$GITHUB_WORKSPACE/head" \ + "$REPORT_DIR/base-browser.json" "$REPORT_DIR/head-browser.json" - name: Upload browser base heap snapshot id: upload-browser-base-heap-snapshot uses: actions/upload-artifact@v7 with: + name: frontend-browser-base-heap-snapshot path: base-heap-snapshot.heapsnapshot archive: false if-no-files-found: error @@ -143,6 +164,7 @@ jobs: id: upload-browser-head-heap-snapshot uses: actions/upload-artifact@v7 with: + name: frontend-browser-head-heap-snapshot path: head-heap-snapshot.heapsnapshot archive: false if-no-files-found: error @@ -150,13 +172,13 @@ jobs: - name: Generate browser detailed html shell: bash - working-directory: after + working-directory: head run: | - REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" - test -s "$REPORT_DIR/before-browser.json" - test -s "$REPORT_DIR/after-browser.json" - pnpm --filter diagnostics-frontend-browser run render-html \ - "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" \ + REPORT_DIR="$RUNNER_TEMP/frontend-diagnostics" + test -s "$REPORT_DIR/base-browser.json" + test -s "$REPORT_DIR/head-browser.json" + pnpm --filter diagnostics-frontend run render-browser-html \ + "$REPORT_DIR/base-browser.json" "$REPORT_DIR/head-browser.json" \ "$REPORT_DIR/frontend-browser-detailed-html.html" - name: Upload browser detailed html @@ -164,54 +186,61 @@ jobs: uses: actions/upload-artifact@v7 with: name: frontend-browser-metrics-detailed-html - path: ${{ runner.temp }}/frontend-browser-diagnostics/frontend-browser-detailed-html.html + path: ${{ runner.temp }}/frontend-diagnostics/frontend-browser-detailed-html.html if-no-files-found: error archive: false retention-days: 7 - - name: Generate browser metrics report + - name: Generate frontend diagnostics report shell: bash - working-directory: after + working-directory: head env: BASE_SHA: ${{ github.event.pull_request.base.sha }} HEAD_SHA: ${{ github.event.pull_request.head.sha }} PR_NUMBER: ${{ github.event.pull_request.number }} + FRONTEND_BUNDLE_REPORT_ARTIFACT_URL: ${{ steps.upload-bundle-visualizer.outputs.artifact-url }} FRONTEND_BROWSER_BASE_HEAP_SNAPSHOT_ARTIFACT_URL: ${{ steps.upload-browser-base-heap-snapshot.outputs.artifact-url }} FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL: ${{ steps.upload-browser-head-heap-snapshot.outputs.artifact-url }} FRONTEND_BROWSER_DETAILED_HTML_ARTIFACT_URL: ${{ steps.upload-browser-detailed-html.outputs.artifact-url }} run: | - REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" - test -s "$REPORT_DIR/before-browser.json" - test -s "$REPORT_DIR/after-browser.json" - pnpm --filter diagnostics-frontend-browser run render-md \ - "$REPORT_DIR/before-browser.json" "$REPORT_DIR/after-browser.json" \ - "$REPORT_DIR/frontend-browser-diagnostics.md" + REPORT_DIR="$RUNNER_TEMP/frontend-diagnostics" + test -s "$REPORT_DIR/base-bundle-stats.json" + test -s "$REPORT_DIR/head-bundle-stats.json" + test -s "$REPORT_DIR/base-browser.json" + test -s "$REPORT_DIR/head-browser.json" + pnpm --filter diagnostics-frontend run render-md \ + "$GITHUB_WORKSPACE/base" "$GITHUB_WORKSPACE/head" \ + "$REPORT_DIR/base-bundle-stats.json" "$REPORT_DIR/head-bundle-stats.json" \ + "$REPORT_DIR/base-browser.json" "$REPORT_DIR/head-browser.json" \ + "$REPORT_DIR/frontend-diagnostics.md" printf '%s\n' "$PR_NUMBER" > "$REPORT_DIR/pr-number.txt" printf '%s\n' "$BASE_SHA" > "$REPORT_DIR/base-sha.txt" printf '%s\n' "$HEAD_SHA" > "$REPORT_DIR/head-sha.txt" printf '%s\n' "${{ github.event.pull_request.html_url }}" > "$REPORT_DIR/pr-url.txt" - - name: Check browser metrics report + - name: Check frontend diagnostics report shell: bash run: | - REPORT_DIR="$RUNNER_TEMP/frontend-browser-diagnostics" - test -s "$REPORT_DIR/frontend-browser-diagnostics.md" + REPORT_DIR="$RUNNER_TEMP/frontend-diagnostics" + test -s "$REPORT_DIR/frontend-diagnostics.md" test -s "$REPORT_DIR/frontend-browser-detailed-html.html" test -s "$REPORT_DIR/pr-number.txt" test -s "$REPORT_DIR/head-sha.txt" - cat "$REPORT_DIR/frontend-browser-diagnostics.md" >> "$GITHUB_STEP_SUMMARY" + cat "$REPORT_DIR/frontend-diagnostics.md" >> "$GITHUB_STEP_SUMMARY" - - name: Upload browser metrics report + - name: Upload frontend diagnostics report uses: actions/upload-artifact@v7 with: - name: frontend-browser-diagnostics + name: frontend-diagnostics path: | - ${{ runner.temp }}/frontend-browser-diagnostics/before-browser.json - ${{ runner.temp }}/frontend-browser-diagnostics/after-browser.json - ${{ runner.temp }}/frontend-browser-diagnostics/frontend-browser-diagnostics.md - ${{ runner.temp }}/frontend-browser-diagnostics/pr-number.txt - ${{ runner.temp }}/frontend-browser-diagnostics/base-sha.txt - ${{ runner.temp }}/frontend-browser-diagnostics/head-sha.txt - ${{ runner.temp }}/frontend-browser-diagnostics/pr-url.txt + ${{ runner.temp }}/frontend-diagnostics/base-bundle-stats.json + ${{ runner.temp }}/frontend-diagnostics/head-bundle-stats.json + ${{ runner.temp }}/frontend-diagnostics/base-browser.json + ${{ runner.temp }}/frontend-diagnostics/head-browser.json + ${{ runner.temp }}/frontend-diagnostics/frontend-diagnostics.md + ${{ runner.temp }}/frontend-diagnostics/pr-number.txt + ${{ runner.temp }}/frontend-diagnostics/base-sha.txt + ${{ runner.temp }}/frontend-diagnostics/head-sha.txt + ${{ runner.temp }}/frontend-diagnostics/pr-url.txt if-no-files-found: error retention-days: 7 diff --git a/.github/workflows/packages-private.yml b/.github/workflows/packages-private.yml index e6a72b68c95..cf7e50670ab 100644 --- a/.github/workflows/packages-private.yml +++ b/.github/workflows/packages-private.yml @@ -33,8 +33,7 @@ jobs: workspace: - diagnostics-shared - diagnostics-backend - - diagnostics-frontend-browser - - diagnostics-frontend-bundle + - diagnostics-frontend - changelog-checker steps: - uses: actions/checkout@v6.0.3 diff --git a/packages-private/README.md b/packages-private/README.md index faba8fa046d..0c14dffdf5e 100644 --- a/packages-private/README.md +++ b/packages-private/README.md @@ -8,8 +8,7 @@ | --- | --- | | [`diagnostics-shared`](./diagnostics-shared) | 計測系パッケージã�Œå…±æœ‰ã�™ã‚‹çµ±è¨ˆãƒ»æ›¸å¼�整形・V8 heap snapshotè§£æž�ã�®ãƒ¦ãƒ¼ãƒ†ã‚£ãƒªãƒ†ã‚£ | | [`diagnostics-backend`](./diagnostics-backend) | ãƒ�ックエンドã�®ãƒ¡ãƒ¢ãƒªä½¿ç”¨é‡�ã‚’base/headã�§æ¯”較ã�—ã€�PRコメント用ã�®Markdownを生æˆ�ã�™ã‚‹ | -| [`diagnostics-frontend-browser`](./diagnostics-frontend-browser) | ヘッドレスChromeã�§ãƒ•ロントエンドをæ“�作ã�—ã€�メモリ・ãƒ�ットワーク等ã�®æŒ‡æ¨™ã‚’base/headã�§æ¯”較ã�™ã‚‹ | -| [`diagnostics-frontend-bundle`](./diagnostics-frontend-bundle) | フロントエンドã�®ãƒ“ルドæˆ�果物ã�®chunkサイズをbase/headã�§æ¯”較ã�™ã‚‹ | +| [`diagnostics-frontend`](./diagnostics-frontend) | フロントエンドをブラウザã�§èµ·å‹•ã�—ã�Ÿéš›ã�®ãƒ¡ãƒˆãƒªã‚¯ã‚¹ã�¨ç”Ÿæˆ�ã�•れã�Ÿchunk情報等をbase/headã�§æ¯”較ã�™ã‚‹ | | [`changelog-checker`](./changelog-checker) | `CHANGELOG.md` ã�®è¿½è¨˜å†…容を検証ã�™ã‚‹ | ## GitHub Actionsã�‹ã‚‰ã�®å‘¼ã�³å‡ºã�—æ–¹ @@ -20,11 +19,12 @@ CLIã�«æ¸¡ã�™ãƒ‘スã�¯ã�™ã�¹ã�¦å‘¼ã�³å‡ºã�—å�´ã�®ã‚«ãƒ¬ãƒ³ãƒˆãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ```yaml - name: Generate report - working-directory: after + working-directory: head run: >- - pnpm --filter diagnostics-frontend-bundle run render-md - "$GITHUB_WORKSPACE/before" "$GITHUB_WORKSPACE/after" - "$REPORT_DIR/before-stats.json" "$REPORT_DIR/after-stats.json" + pnpm --filter diagnostics-frontend run render-md + "$GITHUB_WORKSPACE/base" "$GITHUB_WORKSPACE/head" + "$REPORT_DIR/base-bundle-stats.json" "$REPORT_DIR/head-bundle-stats.json" + "$REPORT_DIR/base-browser.json" "$REPORT_DIR/head-browser.json" "$REPORT_DIR/report.md" ``` diff --git a/packages-private/diagnostics-frontend-browser/src/render-md.ts b/packages-private/diagnostics-frontend-browser/src/render-md.ts deleted file mode 100644 index 15c4924808f..00000000000 --- a/packages-private/diagnostics-frontend-browser/src/render-md.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { readFile, writeFile } from 'node:fs/promises'; -import { resolve } from 'node:path'; -import { readOptionalEnv, readRequiredEnv } from 'diagnostics-shared/env'; -import { renderMarkdown } from './report/markdown'; -import type { BrowserMetricsReport } from './types'; - -async function main() { - const [baseFileArg, headFileArg, outputFileArg] = process.argv.slice(2); - if (baseFileArg == null || headFileArg == null || outputFileArg == null) { - throw new Error('Usage: render-md '); - } - - const base = JSON.parse(await readFile(resolve(baseFileArg), 'utf8')) as BrowserMetricsReport; - const head = JSON.parse(await readFile(resolve(headFileArg), 'utf8')) as BrowserMetricsReport; - - await writeFile(resolve(outputFileArg), renderMarkdown(base, head, { - baseHeapSnapshotUrl: readRequiredEnv('FRONTEND_BROWSER_BASE_HEAP_SNAPSHOT_ARTIFACT_URL'), - headHeapSnapshotUrl: readRequiredEnv('FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL'), - detailedHtmlUrl: readOptionalEnv('FRONTEND_BROWSER_DETAILED_HTML_ARTIFACT_URL'), - })); -} - -await main().catch(err => { - console.error(err); - process.exit(1); -}); diff --git a/packages-private/diagnostics-frontend-browser/test/render.test.ts b/packages-private/diagnostics-frontend-browser/test/render.test.ts deleted file mode 100644 index 29e38f7b3e8..00000000000 --- a/packages-private/diagnostics-frontend-browser/test/render.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { readFile } from 'node:fs/promises'; -import { join } from 'node:path'; -import { afterEach, beforeEach, expect, test, vi } from 'vitest'; -import { renderHtml } from '../src/report/html'; -import { renderMarkdown } from '../src/report/markdown'; -import type { BrowserMetricsReport } from '../src/types'; - -const fixturesDir = join(import.meta.dirname, 'fixtures'); - -async function loadFixture(name: string) { - return JSON.parse(await readFile(join(fixturesDir, `${name}.json`), 'utf8')) as BrowserMetricsReport; -} - -beforeEach(() => { - // renderHtml() ã�Œç”Ÿæˆ�時刻を埋ã‚�込むã�®ã�§ã€�スナップショットã�Œæ�ºã‚Œã�ªã�„よã�†æ™‚刻を固定ã�™ã‚‹ - vi.useFakeTimers(); - vi.setSystemTime(new Date('2026-07-18T00:00:00.000Z')); -}); - -afterEach(() => { - vi.useRealTimers(); -}); - -/** - * 出力をゴールデンファイルã�§å›ºå®šã�™ã‚‹ã€‚ - * æ„�図的ã�«å¤‰æ›´ã�—ã�Ÿã�¨ã��ã�¯ `vitest -u` ã�§æ›´æ–°ã�—ã€�__snapshots__ ã�®å·®åˆ†ã‚‚レビューã�™ã‚‹ã�“ã�¨ã€‚ - */ -test('renders the browser diagnostics markdown report', async () => { - const markdown = renderMarkdown(await loadFixture('base'), await loadFixture('head'), { - baseHeapSnapshotUrl: 'https://example.invalid/base', - headHeapSnapshotUrl: 'https://example.invalid/head', - detailedHtmlUrl: 'https://example.invalid/html', - }); - - await expect(markdown).toMatchFileSnapshot('./__snapshots__/render-md.md'); -}); - -test('omits the details link when no detailed html artifact was uploaded', async () => { - const markdown = renderMarkdown(await loadFixture('base'), await loadFixture('head'), { - baseHeapSnapshotUrl: 'https://example.invalid/base', - headHeapSnapshotUrl: 'https://example.invalid/head', - detailedHtmlUrl: null, - }); - - expect(markdown).not.toContain('View details'); -}); - -test('renders the network request diff html report', async () => { - const html = renderHtml(await loadFixture('base'), await loadFixture('head')); - - await expect(html).toMatchFileSnapshot('./__snapshots__/render-html.html'); -}); - -test('escapes html metacharacters coming from the browser session', async () => { - const base = await loadFixture('base'); - const head = await loadFixture('head'); - // CDPç”±æ�¥ã�®å€¤ã�¯åŽŸç�†çš„ã�«ã�¯ä»»æ„�ã�®æ–‡å­—列ã�«ã�ªã‚Šã�†ã‚‹ã�®ã�§ã€�生HTMLã�¨ã�—ã�¦å‡ºã�ªã�„ã�“ã�¨ã‚’確ã�‹ã‚�ã‚‹ - head.samples[0].networkRequests[0].url = 'http://127.0.0.1:61812/">'; - - const html = renderHtml(base, head); - - expect(html).not.toContain(''); - expect(html).toContain('<script>alert(1)</script>'); -}); diff --git a/packages-private/diagnostics-frontend-bundle/eslint.config.js b/packages-private/diagnostics-frontend-bundle/eslint.config.js deleted file mode 100644 index 11bc648243d..00000000000 --- a/packages-private/diagnostics-frontend-bundle/eslint.config.js +++ /dev/null @@ -1,25 +0,0 @@ -import tsParser from '@typescript-eslint/parser'; -import sharedConfig from '../../packages/shared/eslint.config.js'; - -// eslint-disable-next-line import/no-default-export -export default [ - ...sharedConfig, - { - ignores: [ - '**/node_modules', - '**/__snapshots__', - 'test/fixtures', - ], - }, - { - files: ['**/*.ts', '**/*.tsx'], - languageOptions: { - parserOptions: { - parser: tsParser, - project: ['./tsconfig.json'], - sourceType: 'module', - tsconfigRootDir: import.meta.dirname, - }, - }, - }, -]; diff --git a/packages-private/diagnostics-frontend-bundle/package.json b/packages-private/diagnostics-frontend-bundle/package.json deleted file mode 100644 index b0271a81015..00000000000 --- a/packages-private/diagnostics-frontend-bundle/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "diagnostics-frontend-bundle", - "private": true, - "type": "module", - "scripts": { - "eslint": "eslint './**/*.{js,jsx,ts,tsx}'", - "lint": "pnpm typecheck && pnpm eslint", - "render-md": "tsx src/render-md.ts", - "test": "vitest run", - "typecheck": "tsc --noEmit" - }, - "dependencies": { - "diagnostics-shared": "workspace:*" - }, - "devDependencies": { - "@types/node": "26.1.1", - "tsx": "4.23.1", - "typescript": "5.9.3", - "vite": "8.1.4", - "vitest": "4.1.10" - } -} diff --git a/packages-private/diagnostics-frontend-bundle/src/render-md.ts b/packages-private/diagnostics-frontend-bundle/src/render-md.ts deleted file mode 100644 index d8fe0997dd5..00000000000 --- a/packages-private/diagnostics-frontend-bundle/src/render-md.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { promises as fs } from 'node:fs'; -import path from 'node:path'; -import { readRequiredEnv } from 'diagnostics-shared/env'; -import { collectReport } from './manifest'; -import { renderBundleReportMarkdown } from './report'; -import type { VisualizerReport } from './visualizer'; - -async function main() { - const [beforeDir, afterDir, beforeStatsFile, afterStatsFile, outFile] = process.argv.slice(2).map(arg => path.resolve(arg)); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (outFile == null) throw new Error('Usage: render-md '); - - // 未設定ã�®ã�¾ã�¾ `undefined` ã�¨ã�„ã�†æ–‡å­—列をコメントã�«åŸ‹ã‚�è¾¼ã�¾ã�ªã�„よã�†ã€�ã�“ã�“ã�§è�½ã�¨ã�™ - const visualizerArtifactUrl = readRequiredEnv('FRONTEND_BUNDLE_REPORT_ARTIFACT_URL'); - - const before = await collectReport(beforeDir); - const after = await collectReport(afterDir); - const beforeStats = JSON.parse(await fs.readFile(beforeStatsFile, 'utf8')) as VisualizerReport; - const afterStats = JSON.parse(await fs.readFile(afterStatsFile, 'utf8')) as VisualizerReport; - - await fs.writeFile(outFile, renderBundleReportMarkdown(before, after, beforeStats, afterStats, { visualizerArtifactUrl })); -} - -await main().catch(err => { - console.error(err); - process.exit(1); -}); diff --git a/packages-private/diagnostics-frontend-bundle/src/report.ts b/packages-private/diagnostics-frontend-bundle/src/report.ts deleted file mode 100644 index db2e1cf6e3f..00000000000 --- a/packages-private/diagnostics-frontend-bundle/src/report.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { renderFrontendChunkReport } from './chunk-report'; -import { collectVisualizerReport, renderVisualizerSummaryTable, type VisualizerReport } from './visualizer'; -import type { CollectedReport } from './manifest'; - -export type RenderBundleReportOptions = { - /** rollup-plugin-visualizer ã�Œå‡ºåŠ›ã�—ã�Ÿtreemap HTMLã�®artifact URL */ - visualizerArtifactUrl: string; -}; - -export function renderBundleReportMarkdown( - before: CollectedReport, - after: CollectedReport, - beforeStats: VisualizerReport, - afterStats: VisualizerReport, - options: RenderBundleReportOptions, -) { - return [ - '## 📦 Frontend Bundle Report', - '', - renderFrontendChunkReport(before, after), - '', - '## Bundle Stats', - '', - renderVisualizerSummaryTable(collectVisualizerReport(beforeStats), collectVisualizerReport(afterStats)), - '', - `[Open treemap HTML](${options.visualizerArtifactUrl})`, - ].join('\n'); -} diff --git a/packages-private/diagnostics-frontend-bundle/test/__snapshots__/render-md.md b/packages-private/diagnostics-frontend-bundle/test/__snapshots__/render-md.md deleted file mode 100644 index 867cbf3b758..00000000000 --- a/packages-private/diagnostics-frontend-bundle/test/__snapshots__/render-md.md +++ /dev/null @@ -1,100 +0,0 @@ -## 📦 Frontend Bundle Report - -
    -Chunk size diff (2 updated, 0 added, 0 removed) - -| Chunk | Before | After | Δ | Δ (%) | -| --- | ---: | ---: | ---: | ---: | -| (total) | 120 KB | 127 KB | $\color{orange}{\text{+6.3 KB}}$ | $\color{orange}{\text{+5.2\\%}}$ | -| | | | | | -|
    `vue` `assets/vue-b2.js`
    | 90 KB | 96 KB | $\color{orange}{\text{+6 KB}}$ | $\color{orange}{\text{+6.7\\%}}$ | -| (other generated chunks) | 1.2 KB | 1.5 KB | $\text{+300 B}$ | $\color{orange}{\text{+25\\%}}$ | -| (other) | 20 KB | 20 KB | $\text{+3 B}$ | $\text{+0\\%}$ | - -
    - -
    -Startup chunk size (2 updated, 0 added, 0 removed) - -| Chunk | Before | After | Δ | Δ (%) | -| --- | ---: | ---: | ---: | ---: | -| (total) | 114 KB | 120 KB | $\color{orange}{\text{+6 KB}}$ | $\color{orange}{\text{+5.3\\%}}$ | -| | | | | | -|
    `vue` `assets/vue-b2.js`
    | 90 KB | 96 KB | $\color{orange}{\text{+6 KB}}$ | $\color{orange}{\text{+6.7\\%}}$ | -| (other) | 24 KB | 24 KB | $\text{+3 B}$ | $\text{+0\\%}$ | - -_Startup chunks are the Vite entry for `src/_boot_.ts` and its static imports._ - -
    - - -## Bundle Stats - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    BundlesModulesEntriesImportsSize
    StaticDynamicRenderedGzipBrotli
    Before2612321 KB6.3 KB5.3 KB
    After2713331 KB8.4 KB7 KB
    Δ0$\color{orange}{\text{+1}}$0$\color{orange}{\text{+1}}$0$\color{orange}{\text{+9.8 KB}}$$\color{orange}{\text{+2.1 KB}}$$\color{orange}{\text{+1.8 KB}}$
    Δ (%)0%$\color{orange}{\text{+16.7\%}}$0%$\color{orange}{\text{+50\%}}$0%$\color{orange}{\text{+46.7\%}}$$\color{orange}{\text{+33.3\%}}$$\color{orange}{\text{+33.3\%}}$
    - -[Open treemap HTML](https://example.invalid/treemap) \ No newline at end of file diff --git a/packages-private/diagnostics-frontend-bundle/tsconfig.json b/packages-private/diagnostics-frontend-bundle/tsconfig.json deleted file mode 100644 index 6672c40acb3..00000000000 --- a/packages-private/diagnostics-frontend-bundle/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "strict": true, - "strictFunctionTypes": true, - "strictNullChecks": true, - "esModuleInterop": true, - "skipLibCheck": true, - "noEmit": true, - "types": ["node"] - }, - "include": [ - "src/**/*.ts", - "test/**/*.ts" - ], - "exclude": [] -} diff --git a/packages-private/diagnostics-frontend-browser/eslint.config.js b/packages-private/diagnostics-frontend/eslint.config.js similarity index 100% rename from packages-private/diagnostics-frontend-browser/eslint.config.js rename to packages-private/diagnostics-frontend/eslint.config.js diff --git a/packages-private/diagnostics-frontend-browser/package.json b/packages-private/diagnostics-frontend/package.json similarity index 76% rename from packages-private/diagnostics-frontend-browser/package.json rename to packages-private/diagnostics-frontend/package.json index 9264dc49f94..8d3d2d248c0 100644 --- a/packages-private/diagnostics-frontend-browser/package.json +++ b/packages-private/diagnostics-frontend/package.json @@ -1,12 +1,12 @@ { - "name": "diagnostics-frontend-browser", + "name": "diagnostics-frontend", "private": true, "type": "module", "scripts": { "eslint": "eslint './**/*.{js,jsx,ts,tsx}'", - "inspect": "tsx src/inspect.ts", + "inspect-browser": "tsx src/inspect-browser.ts", "lint": "pnpm typecheck && pnpm eslint", - "render-html": "tsx src/render-html.ts", + "render-browser-html": "tsx src/render-browser-html.ts", "render-md": "tsx src/render-md.ts", "test": "vitest run", "typecheck": "tsc --noEmit" diff --git a/packages-private/diagnostics-frontend-browser/src/browser/controller.ts b/packages-private/diagnostics-frontend/src/browser/controller.ts similarity index 99% rename from packages-private/diagnostics-frontend-browser/src/browser/controller.ts rename to packages-private/diagnostics-frontend/src/browser/controller.ts index 756245c636e..dd17be2a62c 100644 --- a/packages-private/diagnostics-frontend-browser/src/browser/controller.ts +++ b/packages-private/diagnostics-frontend/src/browser/controller.ts @@ -5,9 +5,9 @@ import { writeFile } from 'node:fs/promises'; import { chromium } from 'playwright'; -import type { Browser, BrowserContext, CDPSession, Page } from 'playwright'; import { enableNetworkTracking, type NetworkTracker } from './network'; -import type { BrowserDiagnostics, BrowserMeasurement, NetworkRequest, TabMemory, WebSocketConnection } from '../types'; +import type { Browser, BrowserContext, CDPSession, Page } from 'playwright'; +import type { BrowserDiagnostics, BrowserMeasurement, NetworkRequest, TabMemory, WebSocketConnection } from './types'; export type HeadlessChromeOptions = { scenarioTimeoutMs: number; diff --git a/packages-private/diagnostics-frontend-browser/src/browser/diagnostics.ts b/packages-private/diagnostics-frontend/src/browser/diagnostics.ts similarity index 92% rename from packages-private/diagnostics-frontend-browser/src/browser/diagnostics.ts rename to packages-private/diagnostics-frontend/src/browser/diagnostics.ts index 8365038bb22..a4c95bf842c 100644 --- a/packages-private/diagnostics-frontend-browser/src/browser/diagnostics.ts +++ b/packages-private/diagnostics-frontend/src/browser/diagnostics.ts @@ -4,7 +4,7 @@ */ import { median } from 'diagnostics-shared/stats'; -import type { BrowserDiagnostics } from '../types'; +import type { BrowserDiagnostics } from './types'; export function summarizeBrowserDiagnostics(samples: BrowserDiagnostics[]): BrowserDiagnostics { const medianOf = (select: (sample: BrowserDiagnostics) => number) => median(samples.map(select)); diff --git a/packages-private/diagnostics-frontend-browser/src/browser/network.ts b/packages-private/diagnostics-frontend/src/browser/network.ts similarity index 99% rename from packages-private/diagnostics-frontend-browser/src/browser/network.ts rename to packages-private/diagnostics-frontend/src/browser/network.ts index 538294ec3d4..77095ca6890 100644 --- a/packages-private/diagnostics-frontend-browser/src/browser/network.ts +++ b/packages-private/diagnostics-frontend/src/browser/network.ts @@ -4,7 +4,7 @@ */ import type { CDPSession } from 'playwright'; -import type { NetworkRequest, NetworkSummary, WebSocketConnection } from '../types'; +import type { NetworkRequest, NetworkSummary, WebSocketConnection } from './types'; function normalizeHeaders(headers: Record | undefined) { if (headers == null) return undefined; diff --git a/packages-private/diagnostics-frontend-browser/src/report/html-styles.ts b/packages-private/diagnostics-frontend/src/browser/report/html-styles.ts similarity index 100% rename from packages-private/diagnostics-frontend-browser/src/report/html-styles.ts rename to packages-private/diagnostics-frontend/src/browser/report/html-styles.ts diff --git a/packages-private/diagnostics-frontend-browser/src/report/html.ts b/packages-private/diagnostics-frontend/src/browser/report/html.ts similarity index 98% rename from packages-private/diagnostics-frontend-browser/src/report/html.ts rename to packages-private/diagnostics-frontend/src/browser/report/html.ts index 7627f997298..ff1ca478393 100644 --- a/packages-private/diagnostics-frontend-browser/src/report/html.ts +++ b/packages-private/diagnostics-frontend/src/browser/report/html.ts @@ -224,7 +224,7 @@ function renderRound(round: number, diffs: RequestDiff[]): Raw { `; } -export function renderHtml(base: BrowserMetricsReport, head: BrowserMetricsReport) { +export function renderBrowserDiagnosticsHtml(base: BrowserMetricsReport, head: BrowserMetricsReport) { const diffs = diffReports(base, head); const rounds = [...new Set(diffs.map(diff => diff.round))].toSorted((a, b) => a - b); const generatedAt = new Date().toISOString(); diff --git a/packages-private/diagnostics-frontend-browser/src/scenario.ts b/packages-private/diagnostics-frontend/src/browser/scenario.ts similarity index 87% rename from packages-private/diagnostics-frontend-browser/src/scenario.ts rename to packages-private/diagnostics-frontend/src/browser/scenario.ts index 1ad513e93ee..80df8532ecd 100644 --- a/packages-private/diagnostics-frontend-browser/src/scenario.ts +++ b/packages-private/diagnostics-frontend/src/browser/scenario.ts @@ -3,9 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { closeUserSetupDialog, postNote, registerUser, resetState, signupThroughUi, visitHome } from '../../../packages/frontend/test/e2e/shared'; +import { closeUserSetupDialog, postNote, registerUser, resetState, signupThroughUi, visitHome } from '../../../../packages/frontend/test/e2e/shared'; import { sleep } from './server'; -import type { HeadlessChromeController } from './browser/controller'; +import type { HeadlessChromeController } from './controller'; export const scenarioDescription = 'fresh browser signup, first timeline note, after the note becomes visible'; diff --git a/packages-private/diagnostics-frontend-browser/src/server.ts b/packages-private/diagnostics-frontend/src/browser/server.ts similarity index 90% rename from packages-private/diagnostics-frontend-browser/src/server.ts rename to packages-private/diagnostics-frontend/src/browser/server.ts index c2690c57771..72f7a6f79ea 100644 --- a/packages-private/diagnostics-frontend-browser/src/server.ts +++ b/packages-private/diagnostics-frontend/src/browser/server.ts @@ -34,10 +34,15 @@ export function startServer(label: string, repoDir: string) { const serverStartupTimeoutMs = 120_000; +function hasExited(child: ChildProcess) { + return child.exitCode != null || child.signalCode != null; +} + export async function waitForServer(baseUrl: string, child: ChildProcess) { const startedAt = Date.now(); while (Date.now() - startedAt < serverStartupTimeoutMs) { if (child.exitCode != null) throw new Error(`Misskey server exited early with code ${child.exitCode}`); + if (child.signalCode != null) throw new Error(`Misskey server exited early with signal ${child.signalCode}`); try { // 応答�返ら������fetch�待�続��外��120秒�上�を超����� const remainingMs = serverStartupTimeoutMs - (Date.now() - startedAt); @@ -55,7 +60,7 @@ export async function waitForServer(baseUrl: string, child: ChildProcess) { } export async function stopServer(child: ChildProcess) { - if (child.exitCode != null) return; + if (hasExited(child)) return; if (process.platform === 'win32') { spawnSync('taskkill', ['/pid', String(child.pid), '/t', '/f'], { stdio: 'ignore' }); @@ -69,14 +74,14 @@ export async function stopServer(child: ChildProcess) { } await new Promise(resolvePromise => { - if (child.exitCode != null) { + if (hasExited(child)) { resolvePromise(); return; } const forceKillTimer = setTimeout(() => { // 猶予�間�終了���れ��PID��利用�れ�無関係�プロセスを撃��れ��る - if (child.exitCode == null && child.pid != null) { + if (!hasExited(child) && child.pid != null) { try { if (process.platform === 'win32') { spawnSync('taskkill', ['/pid', String(child.pid), '/t', '/f'], { stdio: 'ignore' }); diff --git a/packages-private/diagnostics-frontend-browser/src/summarize.ts b/packages-private/diagnostics-frontend/src/browser/summarize.ts similarity index 98% rename from packages-private/diagnostics-frontend-browser/src/summarize.ts rename to packages-private/diagnostics-frontend/src/browser/summarize.ts index 825ae188f5e..1b880022085 100644 --- a/packages-private/diagnostics-frontend-browser/src/summarize.ts +++ b/packages-private/diagnostics-frontend/src/browser/summarize.ts @@ -5,7 +5,7 @@ import { finiteMedian } from 'diagnostics-shared/stats'; import { summarizeHeapSnapshotDataSamples } from 'diagnostics-shared/heap-snapshot'; -import { summarizeBrowserDiagnostics } from './browser/diagnostics'; +import { summarizeBrowserDiagnostics } from './diagnostics'; import type { BrowserMeasurement, BrowserMeasurementSample, BrowserMetricsReport, NetworkSummary } from './types'; export type SummarizeOptions = { diff --git a/packages-private/diagnostics-frontend-browser/src/types.ts b/packages-private/diagnostics-frontend/src/browser/types.ts similarity index 87% rename from packages-private/diagnostics-frontend-browser/src/types.ts rename to packages-private/diagnostics-frontend/src/browser/types.ts index df91071c13c..78e31b76f40 100644 --- a/packages-private/diagnostics-frontend-browser/src/types.ts +++ b/packages-private/diagnostics-frontend/src/browser/types.ts @@ -5,6 +5,11 @@ import type { HeapSnapshotData } from 'diagnostics-shared/heap-snapshot'; +// NOTE: (AI��) +// NetworkRequest �リクエスト本文��求・応答ヘッダを����APIキーやパスワード�Cookie����証情報も��れ得る�� +// workflow上�作られるMisskeyアカウント�テスト用アカウント��り�誰��実際�使用�るプライベート�アカウント������� +// �れら�情報�第三者�ら閲覧���も何��題も���脆弱性����。 + export type NetworkRequest = { requestId: string; url: string; diff --git a/packages-private/diagnostics-frontend-bundle/src/chunk-report.ts b/packages-private/diagnostics-frontend/src/bundle/chunk-report.ts similarity index 50% rename from packages-private/diagnostics-frontend-bundle/src/chunk-report.ts rename to packages-private/diagnostics-frontend/src/bundle/chunk-report.ts index 2b2492377c0..55857305c53 100644 --- a/packages-private/diagnostics-frontend-bundle/src/chunk-report.ts +++ b/packages-private/diagnostics-frontend/src/bundle/chunk-report.ts @@ -9,7 +9,7 @@ import { escapeMdTableCell, formatBytes, } from 'diagnostics-shared/format'; -import type { CollectedReport, FileEntry } from './manifest'; +import type { CollectedBundleReport, FileEntry } from './manifest'; /** * ��差分以下��ャンク�個別�出�� `(other)` ����る。 @@ -25,21 +25,21 @@ function entryDisplayName(entry: FileEntry | undefined) { return entry.displayName || entry.file; } -export function getChunkComparisonRows(keys: string[], before: Partial>, after: Partial>) { +export function getChunkComparisonRows(keys: string[], base: Partial>, head: Partial>) { return keys.map(key => { - const beforeEntry = before[key]; - const afterEntry = after[key]; - const beforeSize = beforeEntry?.size ?? 0; - const afterSize = afterEntry?.size ?? 0; + const baseEntry = base[key]; + const headEntry = head[key]; + const baseSize = baseEntry?.size ?? 0; + const headSize = headEntry?.size ?? 0; return { key, - name: entryDisplayName(beforeEntry ?? afterEntry), - beforeFile: beforeEntry?.file, - afterFile: afterEntry?.file, - beforeSize, - afterSize, - changeType: beforeEntry == null ? 'added' : afterEntry == null ? 'removed' : beforeSize !== afterSize ? 'updated' : 'unchanged', - sortSize: Math.max(beforeSize, afterSize), + name: entryDisplayName(baseEntry ?? headEntry), + baseFile: baseEntry?.file, + headFile: headEntry?.file, + baseSize, + headSize, + changeType: baseEntry == null ? 'added' : headEntry == null ? 'removed' : baseSize !== headSize ? 'updated' : 'unchanged', + sortSize: Math.max(baseSize, headSize), }; }); } @@ -47,10 +47,10 @@ export function getChunkComparisonRows(keys: string[], before: Partial[number]; export type ChunkAggregate = { - beforeSize: number; - afterSize: number; - beforeCount: number; - afterCount: number; + baseSize: number; + headSize: number; + baseCount: number; + headCount: number; }; export function sumChunkSizes(chunks: FileEntry[]) { @@ -58,29 +58,29 @@ export function sumChunkSizes(chunks: FileEntry[]) { } /** - * 比較キーを���� (= before/after �対応付�����) �ャンク��計。 + * 比較キーを���� (= base/head �対応付�����) �ャンク��計。 */ -export function generatedAggregate(before: FileEntry[], after: FileEntry[]): ChunkAggregate { - const beforeGenerated = before.filter(chunk => chunk.comparisonKey == null); - const afterGenerated = after.filter(chunk => chunk.comparisonKey == null); +export function generatedAggregate(base: FileEntry[], head: FileEntry[]): ChunkAggregate { + const baseGenerated = base.filter(chunk => chunk.comparisonKey == null); + const headGenerated = head.filter(chunk => chunk.comparisonKey == null); return { - beforeSize: sumChunkSizes(beforeGenerated), - afterSize: sumChunkSizes(afterGenerated), - beforeCount: beforeGenerated.length, - afterCount: afterGenerated.length, + baseSize: sumChunkSizes(baseGenerated), + headSize: sumChunkSizes(headGenerated), + baseCount: baseGenerated.length, + headCount: headGenerated.length, }; } export function hasSmallDelta(row: ChunkComparisonRow) { - return Math.abs(row.afterSize - row.beforeSize) <= smallDeltaThreshold; + return Math.abs(row.headSize - row.baseSize) <= smallDeltaThreshold; } export function comparisonRowsAggregate(rows: ChunkComparisonRow[]): ChunkAggregate { return { - beforeSize: rows.reduce((sum, row) => sum + row.beforeSize, 0), - afterSize: rows.reduce((sum, row) => sum + row.afterSize, 0), - beforeCount: rows.filter(row => row.beforeFile != null).length, - afterCount: rows.filter(row => row.afterFile != null).length, + baseSize: rows.reduce((sum, row) => sum + row.baseSize, 0), + headSize: rows.reduce((sum, row) => sum + row.headSize, 0), + baseCount: rows.filter(row => row.baseFile != null).length, + headCount: rows.filter(row => row.headFile != null).length, }; } @@ -108,69 +108,69 @@ export function formatChunkChangeSummary(label: string, summary: ReturnType 0 || generated.afterCount > 0); - const hasOther = other != null && (other.beforeCount > 0 || other.afterCount > 0); + const hasGenerated = generated != null && (generated.baseCount > 0 || generated.headCount > 0); + const hasOther = other != null && (other.baseCount > 0 || other.headCount > 0); if (rows.length === 0 && total == null && !hasGenerated && !hasOther) return '_No data_'; const lines = [ - '| Chunk | Before | After | Δ | Δ (%) |', + '| Chunk | Base | Head | Δ | Δ (%) |', '| --- | ---: | ---: | ---: | ---: |', ]; if (total != null) { - lines.push(`| (total) | ${formatBytes(total.beforeSize)} | ${formatBytes(total.afterSize)} | ${calcAndFormatDeltaBytes(total.beforeSize, total.afterSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(total.beforeSize, total.afterSize, 0.1)} |`); + lines.push(`| (total) | ${formatBytes(total.baseSize)} | ${formatBytes(total.headSize)} | ${calcAndFormatDeltaBytes(total.baseSize, total.headSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(total.baseSize, total.headSize, 0.1)} |`); lines.push('| | | | | |'); } for (const row of rows) { const chunkFile = chunkFileDisplay(row); if (row.changeType === 'added') { - lines.push(`|
    \`${escapeMdTableCell(row.name)}\` \`${escapeMdTableCell(chunkFile)}\`
    | ${formatBytes(row.beforeSize)} | ${formatBytes(row.afterSize)} | ${calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); + lines.push(`|
    \`${escapeMdTableCell(row.name)}\` \`${escapeMdTableCell(chunkFile)}\`
    | ${formatBytes(row.baseSize)} | ${formatBytes(row.headSize)} | ${calcAndFormatDeltaBytes(row.baseSize, row.headSize, 1000)} | $\\color{orange}{\\text{( + )}}$ |`); } else if (row.changeType === 'removed') { - lines.push(`|
    \`${escapeMdTableCell(row.name)}\` \`${escapeMdTableCell(chunkFile)}\`
    | ${formatBytes(row.beforeSize)} | ${formatBytes(row.afterSize)} | ${calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | $\\color{green}{\\text{( - )}}$ |`); + lines.push(`|
    \`${escapeMdTableCell(row.name)}\` \`${escapeMdTableCell(chunkFile)}\`
    | ${formatBytes(row.baseSize)} | ${formatBytes(row.headSize)} | ${calcAndFormatDeltaBytes(row.baseSize, row.headSize, 1000)} | $\\color{green}{\\text{( - )}}$ |`); } else { - lines.push(`|
    \`${escapeMdTableCell(row.name)}\` \`${escapeMdTableCell(chunkFile)}\`
    | ${formatBytes(row.beforeSize)} | ${formatBytes(row.afterSize)} | ${calcAndFormatDeltaBytes(row.beforeSize, row.afterSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(row.beforeSize, row.afterSize, 0.1)} |`); + lines.push(`|
    \`${escapeMdTableCell(row.name)}\` \`${escapeMdTableCell(chunkFile)}\`
    | ${formatBytes(row.baseSize)} | ${formatBytes(row.headSize)} | ${calcAndFormatDeltaBytes(row.baseSize, row.headSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(row.baseSize, row.headSize, 0.1)} |`); } } if (hasGenerated) { - lines.push(`| (other generated chunks) | ${formatBytes(generated.beforeSize)} | ${formatBytes(generated.afterSize)} | ${calcAndFormatDeltaBytes(generated.beforeSize, generated.afterSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(generated.beforeSize, generated.afterSize, 0.1)} |`); + lines.push(`| (other generated chunks) | ${formatBytes(generated.baseSize)} | ${formatBytes(generated.headSize)} | ${calcAndFormatDeltaBytes(generated.baseSize, generated.headSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(generated.baseSize, generated.headSize, 0.1)} |`); } if (hasOther) { - lines.push(`| (other) | ${formatBytes(other.beforeSize)} | ${formatBytes(other.afterSize)} | ${calcAndFormatDeltaBytes(other.beforeSize, other.afterSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(other.beforeSize, other.afterSize, 0.1)} |`); + lines.push(`| (other) | ${formatBytes(other.baseSize)} | ${formatBytes(other.headSize)} | ${calcAndFormatDeltaBytes(other.baseSize, other.headSize, 1000)} | ${calcAndFormatDeltaPercentInMdTable(other.baseSize, other.headSize, 0.1)} |`); } return lines.join('\n'); } -export function renderFrontendChunkReport(before: CollectedReport, after: CollectedReport) { - const beforeComparable = before.comparableChunks; - const afterComparable = after.comparableChunks; - const allChunkKeys = [...new Set([...Object.keys(beforeComparable), ...Object.keys(afterComparable)])]; - const allComparisonRows = getChunkComparisonRows(allChunkKeys, beforeComparable, afterComparable); +export function renderFrontendChunkReport(base: CollectedBundleReport, head: CollectedBundleReport) { + const baseComparable = base.comparableChunks; + const headComparable = head.comparableChunks; + const allChunkKeys = [...new Set([...Object.keys(baseComparable), ...Object.keys(headComparable)])]; + const allComparisonRows = getChunkComparisonRows(allChunkKeys, baseComparable, headComparable); const changedRows = allComparisonRows.filter((row) => row.changeType !== 'unchanged'); const diffSummary = summarizeChunkChanges(changedRows); const diffTotal = { - beforeSize: sumChunkSizes(before.chunks), - afterSize: sumChunkSizes(after.chunks), + baseSize: sumChunkSizes(base.chunks), + headSize: sumChunkSizes(head.chunks), }; - const diffGenerated = generatedAggregate(before.chunks, after.chunks); + const diffGenerated = generatedAggregate(base.chunks, head.chunks); const largeDeltaRows = changedRows.filter(row => !hasSmallDelta(row)).sort(compareChunkComparisonRows); const diffRows = largeDeltaRows.slice(0, diffRowLimit); // 表示上��切り���行も `(other)` ���る。�����計�実際�変化�������る @@ -179,22 +179,22 @@ export function renderFrontendChunkReport(before: CollectedReport, after: Collec ...largeDeltaRows.slice(diffRowLimit), ]); - const beforeStartupFiles = new Set(before.startupFiles); - const afterStartupFiles = new Set(after.startupFiles); - const beforeStartupChunks = before.chunks.filter(chunk => beforeStartupFiles.has(chunk.file)); - const afterStartupChunks = after.chunks.filter(chunk => afterStartupFiles.has(chunk.file)); - const beforeStartupComparable = comparableMap(beforeStartupChunks); - const afterStartupComparable = comparableMap(afterStartupChunks); - const startupKeys = [...new Set([...Object.keys(beforeStartupComparable), ...Object.keys(afterStartupComparable)])]; - const startupComparisonRows = getChunkComparisonRows(startupKeys, beforeStartupComparable, afterStartupComparable); + const baseStartupFiles = new Set(base.startupFiles); + const headStartupFiles = new Set(head.startupFiles); + const baseStartupChunks = base.chunks.filter(chunk => baseStartupFiles.has(chunk.file)); + const headStartupChunks = head.chunks.filter(chunk => headStartupFiles.has(chunk.file)); + const baseStartupComparable = comparableMap(baseStartupChunks); + const headStartupComparable = comparableMap(headStartupChunks); + const startupKeys = [...new Set([...Object.keys(baseStartupComparable), ...Object.keys(headStartupComparable)])]; + const startupComparisonRows = getChunkComparisonRows(startupKeys, baseStartupComparable, headStartupComparable); const startupSummary = summarizeChunkChanges(startupComparisonRows); const startupOther = comparisonRowsAggregate(startupComparisonRows.filter(hasSmallDelta)); const startupRows = startupComparisonRows.filter(row => !hasSmallDelta(row)).sort(compareChunkComparisonRows); const startupTotal = { - beforeSize: sumChunkSizes(beforeStartupChunks), - afterSize: sumChunkSizes(afterStartupChunks), + baseSize: sumChunkSizes(baseStartupChunks), + headSize: sumChunkSizes(headStartupChunks), }; - const startupGenerated = generatedAggregate(beforeStartupChunks, afterStartupChunks); + const startupGenerated = generatedAggregate(baseStartupChunks, headStartupChunks); return [ '
    ', diff --git a/packages-private/diagnostics-frontend-bundle/src/fs-utils.ts b/packages-private/diagnostics-frontend/src/bundle/fs-utils.ts similarity index 90% rename from packages-private/diagnostics-frontend-bundle/src/fs-utils.ts rename to packages-private/diagnostics-frontend/src/bundle/fs-utils.ts index 74ed757b53f..c6b1d3d2e69 100644 --- a/packages-private/diagnostics-frontend-bundle/src/fs-utils.ts +++ b/packages-private/diagnostics-frontend/src/bundle/fs-utils.ts @@ -18,8 +18,9 @@ export async function fileExists(filePath: string) { try { await fs.access(filePath); return true; - } catch { - return false; + } catch (error) { + if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false; + throw error; } } diff --git a/packages-private/diagnostics-frontend-bundle/src/manifest.ts b/packages-private/diagnostics-frontend/src/bundle/manifest.ts similarity index 90% rename from packages-private/diagnostics-frontend-bundle/src/manifest.ts rename to packages-private/diagnostics-frontend/src/bundle/manifest.ts index d35a5cfbfb3..05b00c2a090 100644 --- a/packages-private/diagnostics-frontend-bundle/src/manifest.ts +++ b/packages-private/diagnostics-frontend/src/bundle/manifest.ts @@ -6,7 +6,16 @@ import { promises as fs } from 'node:fs'; import path from 'node:path'; import { fileExists, fileSize, normalizePath, traverseDirectory } from './fs-utils'; -import type { Manifest, ManifestChunk } from 'vite'; + +export type BundleManifestChunk = { + file: string; + src?: string; + name?: string; + isEntry?: boolean; + imports?: string[]; +}; + +export type BundleManifest = Record; /** * 比較対象��るロケール。ロケール別�ャンク�全ロケール分��数�多��る��� @@ -27,15 +36,15 @@ export type FileEntry = { size: number; }; -export type CollectedReport = { - manifest: Manifest; +export type CollectedBundleReport = { + manifest: BundleManifest; chunks: FileEntry[]; comparableChunks: Record; chunksByManifestKey: Record; startupFiles: string[]; }; -export function findEntryKey(manifest: Manifest) { +export function findEntryKey(manifest: BundleManifest) { const entries = Object.entries(manifest); return entries.find(([key, chunk]) => key === 'src/_boot_.ts' || chunk.src === 'src/_boot_.ts')?.[0] ?? entries.find(([, chunk]) => chunk.name === 'entry' && chunk.isEntry)?.[0] @@ -45,9 +54,9 @@ export function findEntryKey(manifest: Manifest) { /** * ビルド間�安定�る�ャンク識別�。出力ファイル���ッシュ付��毎回変�る��� - * �れ��れ���ャンク� before/after �対応付������。 + * �れ��れ���ャンク� base/head �対応付������。 */ -export function stableChunkKey(chunk: ManifestChunk) { +export function stableChunkKey(chunk: BundleManifestChunk) { if (chunk.src != null) return `src:${normalizePath(chunk.src)}`; if (chunk.name != null && stableNamedChunks.has(chunk.name)) return `named:${chunk.name}`; return null; @@ -56,7 +65,7 @@ export function stableChunkKey(chunk: ManifestChunk) { /** * 起動時�必�読�込�れる�ャンク (entry ����的 import) � manifest キーを集�る。 */ -export function collectStartupManifestKeys(manifest: Manifest) { +export function collectStartupManifestKeys(manifest: BundleManifest) { const entryKey = findEntryKey(manifest); const keys = new Set(); if (entryKey == null) throw new Error('Unable to find frontend startup entry in Vite manifest.'); @@ -101,10 +110,10 @@ export async function resolveBuiltFile(outDir: string, file: string) { }; } -export async function collectReport(repoDir: string): Promise { +export async function collectBundleReport(repoDir: string): Promise { const outDir = path.join(repoDir, 'built/_frontend_vite_'); const manifestPath = path.join(outDir, 'manifest.json'); - const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')) as Manifest; + const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')) as BundleManifest; const chunksByFile = new Map(); const comparableChunks = new Map(); const chunksByManifestKey = new Map(); diff --git a/packages-private/diagnostics-frontend-bundle/src/visualizer.ts b/packages-private/diagnostics-frontend/src/bundle/visualizer.ts similarity index 83% rename from packages-private/diagnostics-frontend-bundle/src/visualizer.ts rename to packages-private/diagnostics-frontend/src/bundle/visualizer.ts index 17e4f190b68..199accf2d7f 100644 --- a/packages-private/diagnostics-frontend-bundle/src/visualizer.ts +++ b/packages-private/diagnostics-frontend/src/bundle/visualizer.ts @@ -141,7 +141,7 @@ export function collectVisualizerReport(data: VisualizerReport) { * �素����列���埋�込�れ������テーブル�カンマ区切り�1行�潰れ���。 * 呼�出����識����済むよ�����文字列���返�。 */ -export function renderVisualizerSummaryTable(before: ReturnType, after: ReturnType) { +export function renderVisualizerSummaryTable(base: ReturnType, head: ReturnType) { const summary = [ 'bundles', 'modules', @@ -178,25 +178,25 @@ export function renderVisualizerSummaryTable(before: ReturnType', '', '', - 'Before', - ...summary.map((key) => `${formatNumber(before.summary[key])}`), - ...metrics.map((key) => `${formatBytes(before.metrics[key])}`), + 'Base', + ...summary.map((key) => `${formatNumber(base.summary[key])}`), + ...metrics.map((key) => `${formatBytes(base.metrics[key])}`), '', '', - 'After', - ...summary.map((key) => `${formatNumber(after.summary[key])}`), - ...metrics.map((key) => `${formatBytes(after.metrics[key])}`), + 'Head', + ...summary.map((key) => `${formatNumber(head.summary[key])}`), + ...metrics.map((key) => `${formatBytes(head.metrics[key])}`), '', '', '', 'Δ', - ...summary.map((key) => `${calcAndFormatDeltaNumber(before.summary[key], after.summary[key], 0)}`), - ...metrics.map((key) => `${calcAndFormatDeltaBytes(before.metrics[key], after.metrics[key], 1000)}`), + ...summary.map((key) => `${calcAndFormatDeltaNumber(base.summary[key], head.summary[key], 0)}`), + ...metrics.map((key) => `${calcAndFormatDeltaBytes(base.metrics[key], head.metrics[key], 1000)}`), '', '', 'Δ (%)', - ...summary.map((key) => `${calcAndFormatDeltaPercent(before.summary[key], after.summary[key], 0.1)}`), - ...metrics.map((key) => `${calcAndFormatDeltaPercent(before.metrics[key], after.metrics[key], 0.1)}`), + ...summary.map((key) => `${calcAndFormatDeltaPercent(base.summary[key], head.summary[key], 0.1)}`), + ...metrics.map((key) => `${calcAndFormatDeltaPercent(base.metrics[key], head.metrics[key], 0.1)}`), '', '', '', diff --git a/packages-private/diagnostics-frontend-browser/src/inspect.ts b/packages-private/diagnostics-frontend/src/inspect-browser.ts similarity index 95% rename from packages-private/diagnostics-frontend-browser/src/inspect.ts rename to packages-private/diagnostics-frontend/src/inspect-browser.ts index 9cf08664e96..25d2703e994 100644 --- a/packages-private/diagnostics-frontend-browser/src/inspect.ts +++ b/packages-private/diagnostics-frontend/src/inspect-browser.ts @@ -9,10 +9,10 @@ import { readIntegerEnv, readOptionalEnv } from 'diagnostics-shared/env'; import { analyzeHeapSnapshot, defaultHeapSnapshotBreakdownTopN } from 'diagnostics-shared/heap-snapshot'; import { HeadlessChromeController } from './browser/controller'; import { summarizeNetwork } from './browser/network'; -import { prepareInstance, runSignupAndPostScenario, scenarioDescription } from './scenario'; -import { startServer, stopServer, waitForServer } from './server'; -import { selectRepresentativeSample, summarizeSamples } from './summarize'; -import type { BrowserMeasurementSample, BrowserMetricsReport } from './types'; +import { prepareInstance, runSignupAndPostScenario, scenarioDescription } from './browser/scenario'; +import { startServer, stopServer, waitForServer } from './browser/server'; +import { selectRepresentativeSample, summarizeSamples } from './browser/summarize'; +import type { BrowserMeasurementSample, BrowserMetricsReport } from './browser/types'; type Label = 'base' | 'head'; @@ -110,7 +110,7 @@ async function genReport(label: Label, repoDir: string, outputPath: string) { async function main() { const [baseDirArg, headDirArg, baseOutputArg, headOutputArg] = process.argv.slice(2); if (baseDirArg == null || headDirArg == null || baseOutputArg == null || headOutputArg == null) { - throw new Error('Usage: inspect '); + throw new Error('Usage: inspect-browser '); } for (const label of labels) { diff --git a/packages-private/diagnostics-frontend-browser/src/render-html.ts b/packages-private/diagnostics-frontend/src/render-browser-html.ts similarity index 68% rename from packages-private/diagnostics-frontend-browser/src/render-html.ts rename to packages-private/diagnostics-frontend/src/render-browser-html.ts index d3ed90927a7..c6567e088ed 100644 --- a/packages-private/diagnostics-frontend-browser/src/render-html.ts +++ b/packages-private/diagnostics-frontend/src/render-browser-html.ts @@ -5,19 +5,19 @@ import { readFile, writeFile } from 'node:fs/promises'; import { resolve } from 'node:path'; -import { renderHtml } from './report/html'; -import type { BrowserMetricsReport } from './types'; +import { renderBrowserDiagnosticsHtml } from './browser/report/html'; +import type { BrowserMetricsReport } from './browser/types'; async function main() { const [baseFileArg, headFileArg, outputFileArg] = process.argv.slice(2); if (baseFileArg == null || headFileArg == null || outputFileArg == null) { - throw new Error('Usage: render-html '); + throw new Error('Usage: render-browser-html '); } const base = JSON.parse(await readFile(resolve(baseFileArg), 'utf8')) as BrowserMetricsReport; const head = JSON.parse(await readFile(resolve(headFileArg), 'utf8')) as BrowserMetricsReport; - await writeFile(resolve(outputFileArg), renderHtml(base, head)); + await writeFile(resolve(outputFileArg), renderBrowserDiagnosticsHtml(base, head)); } await main().catch(err => { diff --git a/packages-private/diagnostics-frontend/src/render-md.ts b/packages-private/diagnostics-frontend/src/render-md.ts new file mode 100644 index 00000000000..a9cfbc1cd1f --- /dev/null +++ b/packages-private/diagnostics-frontend/src/render-md.ts @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { readFile, writeFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { readOptionalEnv, readRequiredEnv } from 'diagnostics-shared/env'; +import { collectBundleReport } from './bundle/manifest'; +import { renderFrontendDiagnosticsMarkdown } from './report'; +import type { BrowserMetricsReport } from './browser/types'; +import type { VisualizerReport } from './bundle/visualizer'; + +const args = process.argv.slice(2); +if (args.length !== 7) { + throw new Error('Usage: render-md '); +} +const [ + baseDirArg, + headDirArg, + baseBundleStatsFileArg, + headBundleStatsFileArg, + baseBrowserFileArg, + headBrowserFileArg, + outputFileArg, +] = args as [string, string, string, string, string, string, string]; + +const [ + baseBundle, + headBundle, + baseBundleStatsJson, + headBundleStatsJson, + baseBrowserJson, + headBrowserJson, +] = await Promise.all([ + collectBundleReport(resolve(baseDirArg)), + collectBundleReport(resolve(headDirArg)), + readFile(resolve(baseBundleStatsFileArg), 'utf8'), + readFile(resolve(headBundleStatsFileArg), 'utf8'), + readFile(resolve(baseBrowserFileArg), 'utf8'), + readFile(resolve(headBrowserFileArg), 'utf8'), +]); + +await writeFile( + resolve(outputFileArg), + renderFrontendDiagnosticsMarkdown({ + bundle: { + base: baseBundle, + head: headBundle, + baseStats: JSON.parse(baseBundleStatsJson) as VisualizerReport, + headStats: JSON.parse(headBundleStatsJson) as VisualizerReport, + visualizerArtifactUrl: readRequiredEnv('FRONTEND_BUNDLE_REPORT_ARTIFACT_URL'), + }, + browser: { + base: JSON.parse(baseBrowserJson) as BrowserMetricsReport, + head: JSON.parse(headBrowserJson) as BrowserMetricsReport, + baseHeapSnapshotUrl: readRequiredEnv('FRONTEND_BROWSER_BASE_HEAP_SNAPSHOT_ARTIFACT_URL'), + headHeapSnapshotUrl: readRequiredEnv('FRONTEND_BROWSER_HEAD_HEAP_SNAPSHOT_ARTIFACT_URL'), + detailedHtmlUrl: readOptionalEnv('FRONTEND_BROWSER_DETAILED_HTML_ARTIFACT_URL'), + }, + }), +); diff --git a/packages-private/diagnostics-frontend-browser/src/report/markdown.ts b/packages-private/diagnostics-frontend/src/report.ts similarity index 86% rename from packages-private/diagnostics-frontend-browser/src/report/markdown.ts rename to packages-private/diagnostics-frontend/src/report.ts index 370cb86892c..e605b0f9314 100644 --- a/packages-private/diagnostics-frontend-browser/src/report/markdown.ts +++ b/packages-private/diagnostics-frontend/src/report.ts @@ -4,14 +4,29 @@ */ import { formatBytes, formatColoredDelta, formatNumber } from 'diagnostics-shared/format'; -import { pairedDeltaSummary, sampleSpread } from 'diagnostics-shared/stats'; import { renderHeapSnapshotTable, type HeapSnapshotReport } from 'diagnostics-shared/heap-snapshot'; -import type { BrowserMeasurement, BrowserMeasurementSample, BrowserMetricsReport } from '../types'; - -export type RenderMarkdownOptions = { - baseHeapSnapshotUrl: string; - headHeapSnapshotUrl: string; - detailedHtmlUrl?: string | null; +import { pairedDeltaSummary } from 'diagnostics-shared/stats'; +import { renderFrontendChunkReport } from './bundle/chunk-report'; +import { collectVisualizerReport, renderVisualizerSummaryTable, type VisualizerReport } from './bundle/visualizer'; +import type { CollectedBundleReport } from './bundle/manifest'; +import type { BrowserMeasurement, BrowserMeasurementSample, BrowserMetricsReport } from './browser/types'; + +export type FrontendDiagnosticsMarkdownInput = { + bundle: { + base: CollectedBundleReport; + head: CollectedBundleReport; + baseStats: VisualizerReport; + headStats: VisualizerReport; + /** rollup-plugin-visualizer �出力��treemap HTML�artifact URL */ + visualizerArtifactUrl: string; + }; + browser: { + base: BrowserMetricsReport; + head: BrowserMetricsReport; + baseHeapSnapshotUrl: string; + headHeapSnapshotUrl: string; + detailedHtmlUrl?: string | null; + }; }; function renderMetricRow( @@ -45,7 +60,7 @@ function resourceTypeSampleBytes(sample: BrowserMeasurementSample, resourceTypes return resourceTypeBytes(sample, resourceTypes); } -function renderSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { +function renderBrowserSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { //function getMetric(report: BrowserMeasurement, key: string) { // return report.performance.cdpMetrics[key]; //} @@ -154,13 +169,14 @@ function toHeapSnapshotReport(report: BrowserMetricsReport): HeapSnapshotReport }; } -export function renderMarkdown(base: BrowserMetricsReport, head: BrowserMetricsReport, options: RenderMarkdownOptions) { - const detailedHtmlUrl = options.detailedHtmlUrl; - const heapSnapshotTable = renderHeapSnapshotTable(toHeapSnapshotReport(base), toHeapSnapshotReport(head)); +export function renderFrontendDiagnosticsMarkdown(input: FrontendDiagnosticsMarkdownInput) { + const { bundle, browser } = input; + const detailedHtmlUrl = browser.detailedHtmlUrl; + const heapSnapshotTable = renderHeapSnapshotTable(toHeapSnapshotReport(browser.base), toHeapSnapshotReport(browser.head)); const lines = [ - '## 🖥 Frontend Browser Diagnostics Report', + '## 🖥 Frontend Diagnostics Report', '', - renderSummaryTable(base, head), + renderBrowserSummaryTable(browser.base, browser.head), '', 'Only metrics showing significant changes are displayed.', '', @@ -169,7 +185,7 @@ export function renderMarkdown(base: BrowserMetricsReport, head: BrowserMetricsR '
    ', 'Requests by resource type', '', - renderResourceTypeTable(base, head), + renderResourceTypeTable(browser.base, browser.head), '', '
    ', '', @@ -178,11 +194,19 @@ export function renderMarkdown(base: BrowserMetricsReport, head: BrowserMetricsR '', heapSnapshotTable ?? '_No V8 heap snapshot data._', '', - //renderHeapSnapshotSankey(toHeapSnapshotReport(head), 'Head'), + //renderHeapSnapshotSankey(toHeapSnapshotReport(browser.head), 'Head'), //'', - `Download representative heap snapshot: [base](${options.baseHeapSnapshotUrl}) / [head](${options.headHeapSnapshotUrl})`, + `Download representative heap snapshot: [base](${browser.baseHeapSnapshotUrl}) / [head](${browser.headHeapSnapshotUrl})`, '
    ', '', + '### 📦 Bundle Stats', + '', + renderFrontendChunkReport(bundle.base, bundle.head), + '', + renderVisualizerSummaryTable(collectVisualizerReport(bundle.baseStats), collectVisualizerReport(bundle.headStats)), + '', + `[Open treemap HTML](${bundle.visualizerArtifactUrl})`, + '', ]; return lines.filter(line => line != null).join('\n').trimEnd() + '\n'; diff --git a/packages-private/diagnostics-frontend-browser/test/__snapshots__/render-md.md b/packages-private/diagnostics-frontend/test/__snapshots__/report.md similarity index 62% rename from packages-private/diagnostics-frontend-browser/test/__snapshots__/render-md.md rename to packages-private/diagnostics-frontend/test/__snapshots__/report.md index 0f791057c2e..41d3aae7279 100644 --- a/packages-private/diagnostics-frontend-browser/test/__snapshots__/render-md.md +++ b/packages-private/diagnostics-frontend/test/__snapshots__/report.md @@ -1,4 +1,4 @@ -## 🖥 Frontend Browser Diagnostics Report +## 🖥 Frontend Diagnostics Report | Metric | Base | Head | Δ median | Δ MAD | Δ min | Δ max | | --- | ---: | ---: | ---: | ---: | ---: | ---: | @@ -81,3 +81,102 @@ Download representative heap snapshot: [base](https://example.invalid/base) / [head](https://example.invalid/head)
    + +### 📦 Bundle Stats + +
    +Chunk size diff (2 updated, 0 added, 0 removed) + +| Chunk | Base | Head | Δ | Δ (%) | +| --- | ---: | ---: | ---: | ---: | +| (total) | 120 KB | 127 KB | $\color{orange}{\text{+6.3 KB}}$ | $\color{orange}{\text{+5.2\\%}}$ | +| | | | | | +|
    `vue` `assets/vue-b2.js`
    | 90 KB | 96 KB | $\color{orange}{\text{+6 KB}}$ | $\color{orange}{\text{+6.7\\%}}$ | +| (other generated chunks) | 1.2 KB | 1.5 KB | $\text{+300 B}$ | $\color{orange}{\text{+25\\%}}$ | +| (other) | 20 KB | 20 KB | $\text{+3 B}$ | $\text{+0\\%}$ | + +
    + +
    +Startup chunk size (2 updated, 0 added, 0 removed) + +| Chunk | Base | Head | Δ | Δ (%) | +| --- | ---: | ---: | ---: | ---: | +| (total) | 114 KB | 120 KB | $\color{orange}{\text{+6 KB}}$ | $\color{orange}{\text{+5.3\\%}}$ | +| | | | | | +|
    `vue` `assets/vue-b2.js`
    | 90 KB | 96 KB | $\color{orange}{\text{+6 KB}}$ | $\color{orange}{\text{+6.7\\%}}$ | +| (other) | 24 KB | 24 KB | $\text{+3 B}$ | $\text{+0\\%}$ | + +_Startup chunks are the Vite entry for `src/_boot_.ts` and its static imports._ + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    BundlesModulesEntriesImportsSize
    StaticDynamicRenderedGzipBrotli
    Base2612321 KB6.3 KB5.3 KB
    Head2713331 KB8.4 KB7 KB
    Δ0$\color{orange}{\text{+1}}$0$\color{orange}{\text{+1}}$0$\color{orange}{\text{+9.8 KB}}$$\color{orange}{\text{+2.1 KB}}$$\color{orange}{\text{+1.8 KB}}$
    Δ (%)0%$\color{orange}{\text{+16.7\%}}$0%$\color{orange}{\text{+50\%}}$0%$\color{orange}{\text{+46.7\%}}$$\color{orange}{\text{+33.3\%}}$$\color{orange}{\text{+33.3\%}}$
    + +[Open treemap HTML](https://example.invalid/treemap) diff --git a/packages-private/diagnostics-frontend-browser/test/__snapshots__/render-html.html b/packages-private/diagnostics-frontend/test/browser/__snapshots__/render-html.html similarity index 100% rename from packages-private/diagnostics-frontend-browser/test/__snapshots__/render-html.html rename to packages-private/diagnostics-frontend/test/browser/__snapshots__/render-html.html diff --git a/packages-private/diagnostics-frontend-browser/test/fixtures/base.json b/packages-private/diagnostics-frontend/test/browser/fixtures/base.json similarity index 100% rename from packages-private/diagnostics-frontend-browser/test/fixtures/base.json rename to packages-private/diagnostics-frontend/test/browser/fixtures/base.json diff --git a/packages-private/diagnostics-frontend-browser/test/fixtures/head.json b/packages-private/diagnostics-frontend/test/browser/fixtures/head.json similarity index 100% rename from packages-private/diagnostics-frontend-browser/test/fixtures/head.json rename to packages-private/diagnostics-frontend/test/browser/fixtures/head.json diff --git a/packages-private/diagnostics-frontend/test/browser/render.test.ts b/packages-private/diagnostics-frontend/test/browser/render.test.ts new file mode 100644 index 00000000000..9def362ff69 --- /dev/null +++ b/packages-private/diagnostics-frontend/test/browser/render.test.ts @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { afterEach, beforeEach, expect, test, vi } from 'vitest'; +import { renderBrowserDiagnosticsHtml } from '../../src/browser/report/html'; +import type { BrowserMetricsReport } from '../../src/browser/types'; + +const fixturesDir = join(import.meta.dirname, 'fixtures'); + +async function loadFixture(name: string) { + return JSON.parse(await readFile(join(fixturesDir, `${name}.json`), 'utf8')) as BrowserMetricsReport; +} + +beforeEach(() => { + // renderBrowserDiagnosticsHtml() �生�時刻を埋�込む���スナップショット��れ��よ�時刻を固定�る + vi.useFakeTimers(); + vi.setSystemTime(new Date('2026-07-18T00:00:00.000Z')); +}); + +afterEach(() => { + vi.useRealTimers(); +}); + +test('renders the network request diff html report', async () => { + const html = renderBrowserDiagnosticsHtml(await loadFixture('base'), await loadFixture('head')); + + await expect(html).toMatchFileSnapshot('./__snapshots__/render-html.html'); +}); + +test('escapes html metacharacters coming from the browser session', async () => { + const base = await loadFixture('base'); + const head = await loadFixture('head'); + // CDP由��値�原�的��任��文字列��り�る���生HTML���出����を確��る + head.samples[0].networkRequests[0].url = 'http://127.0.0.1:61812/">'; + + const html = renderBrowserDiagnosticsHtml(base, head); + + expect(html).not.toContain(''); + expect(html).toContain('<script>alert(1)</script>'); +}); diff --git a/packages-private/diagnostics-frontend/test/browser/server.test.ts b/packages-private/diagnostics-frontend/test/browser/server.test.ts new file mode 100644 index 00000000000..24f3e624449 --- /dev/null +++ b/packages-private/diagnostics-frontend/test/browser/server.test.ts @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { EventEmitter } from 'node:events'; +import { afterEach, expect, test, vi } from 'vitest'; +import { stopServer, waitForServer } from '../../src/browser/server'; +import type { ChildProcess } from 'node:child_process'; + +vi.mock('node:child_process', async () => { + const actual = await vi.importActual('node:child_process'); + return { + ...actual, + spawnSync: vi.fn(), + }; +}); + +function signaledChild() { + return Object.assign(new EventEmitter(), { + exitCode: null, + signalCode: 'SIGTERM' as NodeJS.Signals, + pid: undefined, + kill: vi.fn(), + }) as unknown as ChildProcess; +} + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +test('waitForServer fails immediately when the server exited by signal', async () => { + const fetchMock = vi.fn().mockResolvedValue({ status: 200 }); + vi.stubGlobal('fetch', fetchMock); + + await expect(waitForServer('http://127.0.0.1:61812', signaledChild())) + .rejects.toThrow('Misskey server exited early with signal SIGTERM'); + expect(fetchMock).not.toHaveBeenCalled(); +}); + +test('stopServer returns immediately when the server already exited by signal', async () => { + const child = signaledChild(); + const stopPromise = stopServer(child); + + expect(child.listenerCount('exit')).toBe(0); + await stopPromise; +}); diff --git a/packages-private/diagnostics-frontend-bundle/test/fixtures/before-stats.json b/packages-private/diagnostics-frontend/test/bundle/fixtures/base-stats.json similarity index 99% rename from packages-private/diagnostics-frontend-bundle/test/fixtures/before-stats.json rename to packages-private/diagnostics-frontend/test/bundle/fixtures/base-stats.json index 0a54b931484..27f6b2d6b41 100644 --- a/packages-private/diagnostics-frontend-bundle/test/fixtures/before-stats.json +++ b/packages-private/diagnostics-frontend/test/bundle/fixtures/base-stats.json @@ -1 +1 @@ -{"nodeParts": {"p0": {"renderedLength": 1000, "gzipLength": 300, "brotliLength": 250}, "p1": {"renderedLength": 2000, "gzipLength": 600, "brotliLength": 500}, "p2": {"renderedLength": 3000, "gzipLength": 900, "brotliLength": 750}, "p3": {"renderedLength": 4000, "gzipLength": 1200, "brotliLength": 1000}, "p4": {"renderedLength": 5000, "gzipLength": 1500, "brotliLength": 1250}, "p5": {"renderedLength": 6000, "gzipLength": 1800, "brotliLength": 1500}}, "nodeMetas": {"m0": {"id": "/src/mod0.ts", "isEntry": true, "importedBy": [], "imported": [{"id": "m1", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p0"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m1": {"id": "/src/mod1.ts", "isEntry": false, "importedBy": ["m0"], "imported": [{"id": "m2", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p1"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m2": {"id": "/src/mod2.ts", "isEntry": false, "importedBy": ["m1"], "imported": [{"id": "m3", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p2"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m3": {"id": "/src/mod3.ts", "isEntry": false, "importedBy": ["m2"], "imported": [{"id": "m4", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p3"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m4": {"id": "/src/mod4.ts", "isEntry": false, "importedBy": ["m3"], "imported": [{"id": "m5", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p4"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m5": {"id": "/src/mod5.ts", "isEntry": false, "importedBy": ["m4"], "imported": [], "moduleParts": {"assets/vue-b2.js": "p5"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}}, "options": {}} \ No newline at end of file +{"nodeParts": {"p0": {"renderedLength": 1000, "gzipLength": 300, "brotliLength": 250}, "p1": {"renderedLength": 2000, "gzipLength": 600, "brotliLength": 500}, "p2": {"renderedLength": 3000, "gzipLength": 900, "brotliLength": 750}, "p3": {"renderedLength": 4000, "gzipLength": 1200, "brotliLength": 1000}, "p4": {"renderedLength": 5000, "gzipLength": 1500, "brotliLength": 1250}, "p5": {"renderedLength": 6000, "gzipLength": 1800, "brotliLength": 1500}}, "nodeMetas": {"m0": {"id": "/src/mod0.ts", "isEntry": true, "importedBy": [], "imported": [{"id": "m1", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p0"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m1": {"id": "/src/mod1.ts", "isEntry": false, "importedBy": ["m0"], "imported": [{"id": "m2", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p1"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m2": {"id": "/src/mod2.ts", "isEntry": false, "importedBy": ["m1"], "imported": [{"id": "m3", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p2"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m3": {"id": "/src/mod3.ts", "isEntry": false, "importedBy": ["m2"], "imported": [{"id": "m4", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p3"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m4": {"id": "/src/mod4.ts", "isEntry": false, "importedBy": ["m3"], "imported": [{"id": "m5", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p4"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m5": {"id": "/src/mod5.ts", "isEntry": false, "importedBy": ["m4"], "imported": [], "moduleParts": {"assets/vue-b2.js": "p5"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}}, "options": {}} diff --git a/packages-private/diagnostics-frontend-bundle/test/fixtures/after-stats.json b/packages-private/diagnostics-frontend/test/bundle/fixtures/head-stats.json similarity index 98% rename from packages-private/diagnostics-frontend-bundle/test/fixtures/after-stats.json rename to packages-private/diagnostics-frontend/test/bundle/fixtures/head-stats.json index b69e3f4ceaa..ecddcae8128 100644 --- a/packages-private/diagnostics-frontend-bundle/test/fixtures/after-stats.json +++ b/packages-private/diagnostics-frontend/test/bundle/fixtures/head-stats.json @@ -1 +1 @@ -{"nodeParts": {"p0": {"renderedLength": 1100.0, "gzipLength": 300, "brotliLength": 250}, "p1": {"renderedLength": 2200.0, "gzipLength": 600, "brotliLength": 500}, "p2": {"renderedLength": 3300.0000000000005, "gzipLength": 900, "brotliLength": 750}, "p3": {"renderedLength": 4400.0, "gzipLength": 1200, "brotliLength": 1000}, "p4": {"renderedLength": 5500.0, "gzipLength": 1500, "brotliLength": 1250}, "p5": {"renderedLength": 6600.000000000001, "gzipLength": 1800, "brotliLength": 1500}, "p6": {"renderedLength": 7700.000000000001, "gzipLength": 2100, "brotliLength": 1750}}, "nodeMetas": {"m0": {"id": "/src/mod0.ts", "isEntry": true, "importedBy": [], "imported": [{"id": "m1", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p0"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m1": {"id": "/src/mod1.ts", "isEntry": false, "importedBy": ["m0"], "imported": [{"id": "m2", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p1"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m2": {"id": "/src/mod2.ts", "isEntry": false, "importedBy": ["m1"], "imported": [{"id": "m3", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p2"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m3": {"id": "/src/mod3.ts", "isEntry": false, "importedBy": ["m2"], "imported": [{"id": "m4", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p3"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m4": {"id": "/src/mod4.ts", "isEntry": false, "importedBy": ["m3"], "imported": [{"id": "m5", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p4"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m5": {"id": "/src/mod5.ts", "isEntry": false, "importedBy": ["m4"], "imported": [{"id": "m6", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p5"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m6": {"id": "/src/mod6.ts", "isEntry": false, "importedBy": ["m5"], "imported": [], "moduleParts": {"assets/boot-a1.js": "p6"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}}, "options": {}} \ No newline at end of file +{"nodeParts": {"p0": {"renderedLength": 1100.0, "gzipLength": 300, "brotliLength": 250}, "p1": {"renderedLength": 2200.0, "gzipLength": 600, "brotliLength": 500}, "p2": {"renderedLength": 3300.0000000000005, "gzipLength": 900, "brotliLength": 750}, "p3": {"renderedLength": 4400.0, "gzipLength": 1200, "brotliLength": 1000}, "p4": {"renderedLength": 5500.0, "gzipLength": 1500, "brotliLength": 1250}, "p5": {"renderedLength": 6600.000000000001, "gzipLength": 1800, "brotliLength": 1500}, "p6": {"renderedLength": 7700.000000000001, "gzipLength": 2100, "brotliLength": 1750}}, "nodeMetas": {"m0": {"id": "/src/mod0.ts", "isEntry": true, "importedBy": [], "imported": [{"id": "m1", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p0"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m1": {"id": "/src/mod1.ts", "isEntry": false, "importedBy": ["m0"], "imported": [{"id": "m2", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p1"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m2": {"id": "/src/mod2.ts", "isEntry": false, "importedBy": ["m1"], "imported": [{"id": "m3", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p2"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m3": {"id": "/src/mod3.ts", "isEntry": false, "importedBy": ["m2"], "imported": [{"id": "m4", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p3"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m4": {"id": "/src/mod4.ts", "isEntry": false, "importedBy": ["m3"], "imported": [{"id": "m5", "dynamic": true}], "moduleParts": {"assets/boot-a1.js": "p4"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m5": {"id": "/src/mod5.ts", "isEntry": false, "importedBy": ["m4"], "imported": [{"id": "m6", "dynamic": false}], "moduleParts": {"assets/vue-b2.js": "p5"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}, "m6": {"id": "/src/mod6.ts", "isEntry": false, "importedBy": ["m5"], "imported": [], "moduleParts": {"assets/boot-a1.js": "p6"}, "renderedLength": 0, "gzipLength": 0, "brotliLength": 0}}, "options": {}} diff --git a/packages-private/diagnostics-frontend/test/bundle/fs-utils.test.ts b/packages-private/diagnostics-frontend/test/bundle/fs-utils.test.ts new file mode 100644 index 00000000000..12ec8d7bb11 --- /dev/null +++ b/packages-private/diagnostics-frontend/test/bundle/fs-utils.test.ts @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { promises as fs } from 'node:fs'; +import { afterEach, expect, test, vi } from 'vitest'; +import { fileExists } from '../../src/bundle/fs-utils'; + +function fsError(code: string) { + return Object.assign(new Error(`fs error: ${code}`), { code }) as NodeJS.ErrnoException; +} + +afterEach(() => { + vi.restoreAllMocks(); +}); + +test('fileExists returns false for ENOENT', async () => { + vi.spyOn(fs, 'access').mockRejectedValueOnce(fsError('ENOENT')); + + await expect(fileExists('missing')).resolves.toBe(false); +}); + +test('fileExists rethrows errors other than ENOENT', async () => { + const error = fsError('EACCES'); + vi.spyOn(fs, 'access').mockRejectedValueOnce(error); + + await expect(fileExists('restricted')).rejects.toBe(error); +}); diff --git a/packages-private/diagnostics-frontend/test/bundle/manifest.test.ts b/packages-private/diagnostics-frontend/test/bundle/manifest.test.ts new file mode 100644 index 00000000000..ed91120f5f8 --- /dev/null +++ b/packages-private/diagnostics-frontend/test/bundle/manifest.test.ts @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { mkdtemp, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { collectBundleReport } from '../../src/bundle/manifest'; + +let workDir: string; + +beforeAll(async () => { + workDir = await mkdtemp(join(tmpdir(), 'diagnostics-frontend-test-')); +}); + +afterAll(async () => { + await rm(workDir, { recursive: true, force: true }); +}); + +test('fails loudly when the built output is missing', async () => { + await expect(collectBundleReport(join(workDir, 'nonexistent'))).rejects.toThrow(); +}); diff --git a/packages-private/diagnostics-frontend-bundle/test/render-md.test.ts b/packages-private/diagnostics-frontend/test/report.test.ts similarity index 53% rename from packages-private/diagnostics-frontend-bundle/test/render-md.test.ts rename to packages-private/diagnostics-frontend/test/report.test.ts index 17adcef8836..c45961ccb9d 100644 --- a/packages-private/diagnostics-frontend-bundle/test/render-md.test.ts +++ b/packages-private/diagnostics-frontend/test/report.test.ts @@ -7,16 +7,18 @@ import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { dirname, join } from 'node:path'; import { afterAll, beforeAll, expect, test } from 'vitest'; -import { collectReport } from '../src/manifest'; -import { renderBundleReportMarkdown } from '../src/report'; -import type { VisualizerReport } from '../src/visualizer'; +import { collectBundleReport } from '../src/bundle/manifest'; +import { renderFrontendDiagnosticsMarkdown } from '../src/report'; +import type { BrowserMetricsReport } from '../src/browser/types'; +import type { VisualizerReport } from '../src/bundle/visualizer'; -const fixturesDir = join(import.meta.dirname, 'fixtures'); +const bundleFixturesDir = join(import.meta.dirname, 'bundle/fixtures'); +const browserFixturesDir = join(import.meta.dirname, 'browser/fixtures'); /** * ビルド�果物�fixture。 * - * `collectReport` �ファイル�中身を見�サイズ��使������実体�指定�イト数� + * `collectBundleReport` �ファイル�中身を見�サイズ��使������実体�指定�イト数� * 詰�物�よ�。ディレクトリ�� `built` ��る��リ�ジトリ��コミット��� * (ルート� .gitignore �ビルド�果物���除外�る)�テスト実行時�組�立���る。 */ @@ -31,7 +33,7 @@ const manifest = { }; const fileSizes = { - before: { + base: { 'assets/boot-a1.js': 20_000, 'assets/vue-b2.js': 90_000, 'assets/foo-d4.js': 5_000, @@ -39,7 +41,7 @@ const fileSizes = { 'ja-JP/i18n-c3.js': 4_000, 'ja-JP/orphan.js': 1_200, }, - after: { + head: { // 差�����る (閾値5�イト以下) ��「(other)��集約�れる 'assets/boot-a1.js': 20_003, // 明確�増�る�� diff表�行���出る @@ -50,15 +52,15 @@ const fileSizes = { // manifest�載ら��出力���「(other generated chunks)��集約�れる 'ja-JP/orphan.js': 1_500, }, -} as const satisfies Record<'before' | 'after', Record>; +} as const satisfies Record<'base' | 'head', Record>; -let repoDirs: { before: string; after: string }; +let repoDirs: { base: string; head: string }; let workDir: string; beforeAll(async () => { - workDir = await mkdtemp(join(tmpdir(), 'diagnostics-frontend-bundle-')); + workDir = await mkdtemp(join(tmpdir(), 'diagnostics-frontend-report-test-')); - for (const label of ['before', 'after'] as const) { + for (const label of ['base', 'head'] as const) { const outDir = join(workDir, label, 'built/_frontend_vite_'); await mkdir(outDir, { recursive: true }); await writeFile(join(outDir, 'manifest.json'), JSON.stringify(manifest)); @@ -71,8 +73,8 @@ beforeAll(async () => { } repoDirs = { - before: join(workDir, 'before'), - after: join(workDir, 'after'), + base: join(workDir, 'base'), + head: join(workDir, 'head'), }; }); @@ -80,26 +82,45 @@ afterAll(async () => { await rm(workDir, { recursive: true, force: true }); }); -async function loadStats(name: string) { - return JSON.parse(await readFile(join(fixturesDir, `${name}-stats.json`), 'utf8')) as VisualizerReport; +async function loadBundleStats(name: 'base' | 'head') { + return JSON.parse(await readFile(join(bundleFixturesDir, `${name}-stats.json`), 'utf8')) as VisualizerReport; +} + +async function loadBrowserReport(name: 'base' | 'head') { + return JSON.parse(await readFile(join(browserFixturesDir, `${name}.json`), 'utf8')) as BrowserMetricsReport; +} + +async function renderReport(detailedHtmlUrl: string | null) { + return renderFrontendDiagnosticsMarkdown({ + bundle: { + base: await collectBundleReport(repoDirs.base), + head: await collectBundleReport(repoDirs.head), + baseStats: await loadBundleStats('base'), + headStats: await loadBundleStats('head'), + visualizerArtifactUrl: 'https://example.invalid/treemap', + }, + browser: { + base: await loadBrowserReport('base'), + head: await loadBrowserReport('head'), + baseHeapSnapshotUrl: 'https://example.invalid/base', + headHeapSnapshotUrl: 'https://example.invalid/head', + detailedHtmlUrl, + }, + }); } /** * 出力をゴールデンファイル�固定�る。 * �図的�変更����� `vitest -u` �更新��__snapshots__ �差分もレビュー�る��。 */ -test('renders the frontend bundle report', async () => { - const markdown = renderBundleReportMarkdown( - await collectReport(repoDirs.before), - await collectReport(repoDirs.after), - await loadStats('before'), - await loadStats('after'), - { visualizerArtifactUrl: 'https://example.invalid/treemap' }, - ); - - await expect(markdown).toMatchFileSnapshot('./__snapshots__/render-md.md'); +test('renders one frontend diagnostics markdown report from bundle and browser data', async () => { + const markdown = await renderReport('https://example.invalid/html'); + + await expect(markdown).toMatchFileSnapshot('./__snapshots__/report.md'); }); -test('fails loudly when the built output is missing', async () => { - await expect(collectReport(join(workDir, 'nonexistent'))).rejects.toThrow(); +test('omits the browser details link when no detailed html artifact was uploaded', async () => { + const markdown = await renderReport(null); + + expect(markdown).not.toContain('View details'); }); diff --git a/packages-private/diagnostics-frontend-browser/tsconfig.json b/packages-private/diagnostics-frontend/tsconfig.json similarity index 100% rename from packages-private/diagnostics-frontend-browser/tsconfig.json rename to packages-private/diagnostics-frontend/tsconfig.json diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53a344d0e5b..02293b46906 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,7 +131,7 @@ importers: specifier: 4.1.10 version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) - packages-private/diagnostics-frontend-browser: + packages-private/diagnostics-frontend: dependencies: diagnostics-shared: specifier: workspace:* @@ -156,28 +156,6 @@ importers: specifier: 4.1.10 version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) - packages-private/diagnostics-frontend-bundle: - dependencies: - diagnostics-shared: - specifier: workspace:* - version: link:../diagnostics-shared - devDependencies: - '@types/node': - specifier: 26.1.1 - version: 26.1.1 - tsx: - specifier: 4.23.1 - version: 4.23.1 - typescript: - specifier: 5.9.3 - version: 5.9.3 - vite: - specifier: 8.1.4 - version: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1) - vitest: - specifier: 4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(happy-dom@20.10.6(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.15.0(@types/node@26.1.1)(typescript@5.9.3))(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(tsx@4.23.1)) - packages-private/diagnostics-shared: devDependencies: '@types/node': From 41e730a763513b27aad055ca5c676bb7f0a756ee Mon Sep 17 00:00:00 2001 From: Soli Date: Tue, 21 Jul 2026 18:48:58 +0900 Subject: [PATCH 427/578] =?UTF-8?q?fix(backend):=20=E6=9C=AC=E7=95=AA?= =?UTF-8?q?=E3=83=93=E3=83=AB=E3=83=89=E3=81=A7=20@opentelemetry/instrumen?= =?UTF-8?q?tation=20=E3=81=8C=E8=A7=A3=E6=B1=BA=E3=81=A7=E3=81=8D=E3=81=AA?= =?UTF-8?q?=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1775?= =?UTF-8?q?6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Soli0222 --- packages/backend/package.json | 1 + pnpm-lock.yaml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/backend/package.json b/packages/backend/package.json index 26a43fb13ca..ef142fb158f 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -71,6 +71,7 @@ "@opentelemetry/api": "1.9.1", "@opentelemetry/core": "2.9.0", "@opentelemetry/exporter-trace-otlp-proto": "0.220.0", + "@opentelemetry/instrumentation": "0.219.0", "@opentelemetry/instrumentation-pg": "0.72.0", "@opentelemetry/resources": "2.9.0", "@opentelemetry/sdk-trace-base": "2.9.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 02293b46906..b4c5db1eaea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -230,6 +230,9 @@ importers: '@opentelemetry/exporter-trace-otlp-proto': specifier: 0.220.0 version: 0.220.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': + specifier: 0.219.0 + version: 0.219.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-pg': specifier: 0.72.0 version: 0.72.0(@opentelemetry/api@1.9.1) From 98ae62c432e22a006b8feea4f1e1a6841d950d53 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:43:22 +0900 Subject: [PATCH 428/578] =?UTF-8?q?enhance(gh):=20=E8=A4=87=E6=95=B0?= =?UTF-8?q?=E3=82=B5=E3=83=B3=E3=83=97=E3=83=AB=E3=81=AE=E5=80=A4=E3=81=AE?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=82=92=E6=94=B9=E5=96=84=E3=81=99=E3=82=8B?= =?UTF-8?q?=E3=81=AA=E3=81=A9=20(#17759)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: design backend diagnostics memory noise handling * chore(gh): tweak workflow * docs: clarify shared heap snapshot reporting * docs: plan backend diagnostics memory noise handling * chore: ignore local worktrees * feat(diagnostics): add independent delta summary * feat(diagnostics): make heap snapshot deltas noise-aware * docs: correct heap snapshot threshold plan * fix(diagnostics): suppress backend memory noise * ci: refine backend diagnostics sampling * test(diagnostics): address final review * wip * Update heap-snapshot-sampling.ts * wip * wip * docs: design frontend metric noise reporting * docs: plan frontend metric noise reporting * fix(diagnostics): suppress frontend metric noise * docs: remove temporary frontend metric plans * test(diagnostics): cover frontend metric thresholds * docs: design shared diagnostics metric table * docs: plan shared diagnostics metric table * refactor(diagnostics): simplify independent delta statistics * feat(diagnostics): add shared metric table renderer * refactor(diagnostics): use shared heap snapshot table * refactor(diagnostics): use shared backend metric table * refactor(diagnostics): use shared frontend metric table * docs: remove temporary metric table plans * tweak * docs: design metric table no-data output * fix(diagnostics): show marker for empty metric tables * chore: remove temporary diagnostics design --- .../workflows/backend-diagnostics.inspect.yml | 3 +- .../diagnostics-backend/src/compare.ts | 58 ++--- .../src/heap-snapshot-sampling.ts | 37 ++++ .../src/report/markdown.ts | 140 ++++++------ .../diagnostics-backend/src/types.ts | 1 + .../test/__snapshots__/render-md.md | 36 +-- .../test/heap-snapshot-sampling.test.ts | 42 ++++ .../test/render-md.test.ts | 107 +++++++++ .../diagnostics-frontend/src/report.ts | 206 +++++++++++------- .../test/__snapshots__/report.md | 38 ++-- .../diagnostics-frontend/test/report.test.ts | 191 +++++++++++++++- .../diagnostics-shared/package.json | 1 + .../src/heap-snapshot/render.ts | 63 ++---- .../diagnostics-shared/src/metric-table.ts | 80 +++++++ .../diagnostics-shared/src/stats.ts | 43 ++++ .../test/heap-snapshot-render.test.ts | 103 +++++++++ .../test/metric-table.test.ts | 145 ++++++++++++ .../diagnostics-shared/test/stats.test.ts | 87 +++++++- 18 files changed, 1108 insertions(+), 273 deletions(-) create mode 100644 packages-private/diagnostics-backend/src/heap-snapshot-sampling.ts create mode 100644 packages-private/diagnostics-backend/test/heap-snapshot-sampling.test.ts create mode 100644 packages-private/diagnostics-shared/src/metric-table.ts create mode 100644 packages-private/diagnostics-shared/test/heap-snapshot-render.test.ts create mode 100644 packages-private/diagnostics-shared/test/metric-table.test.ts diff --git a/.github/workflows/backend-diagnostics.inspect.yml b/.github/workflows/backend-diagnostics.inspect.yml index 74469ded63c..8040b13307a 100644 --- a/.github/workflows/backend-diagnostics.inspect.yml +++ b/.github/workflows/backend-diagnostics.inspect.yml @@ -89,9 +89,10 @@ jobs: - name: Measure backend memory usage working-directory: head env: - MK_MEMORY_COMPARE_ROUNDS: 10 + MK_MEMORY_COMPARE_ROUNDS: 15 MK_MEMORY_COMPARE_WARMUP_ROUNDS: 1 MK_MEMORY_HEAP_SNAPSHOT: 1 + MK_MEMORY_HEAP_SNAPSHOT_ROUNDS: 3 # 計測�ー�ス�head��も�を両方�使����果物�runner�workspace直下�出� MK_MEMORY_HEAP_SNAPSHOT_OUTPUT_DIR: ${{ github.workspace }} run: >- diff --git a/packages-private/diagnostics-backend/src/compare.ts b/packages-private/diagnostics-backend/src/compare.ts index 8847b44d4a2..2ae1694f827 100644 --- a/packages-private/diagnostics-backend/src/compare.ts +++ b/packages-private/diagnostics-backend/src/compare.ts @@ -6,10 +6,15 @@ import { copyFile, rm, writeFile } from 'node:fs/promises'; import { join, resolve } from 'node:path'; import { execa } from 'execa'; -import { readIntegerEnv, readOptionalEnv } from 'diagnostics-shared/env'; +import { readBooleanEnv, readIntegerEnv, readOptionalEnv } from 'diagnostics-shared/env'; import { median } from 'diagnostics-shared/stats'; import { summarizeHeapSnapshotDataSamples, defaultHeapSnapshotBreakdownTopN } from 'diagnostics-shared/heap-snapshot'; import { resetState } from './db'; +import { + clampHeapSnapshotRounds, + selectRepresentativeHeapSnapshotRound, + shouldCollectHeapSnapshot, +} from './heap-snapshot-sampling'; import { measureBackendMemory } from './measure'; import { memoryPhases, type MemoryReport } from './types'; @@ -67,7 +72,12 @@ export function summarizeSamples(samples: MemoryReport['samples']) { return summary; } -async function genSample(label: string, repoDir: string, round: number, options: { heapSnapshotSavePath?: string } = {}) { +type GenSampleOptions = { + collectHeapSnapshot?: boolean; + heapSnapshotSavePath?: string; +}; + +async function genSample(label: string, repoDir: string, round: number, options: GenSampleOptions = {}) { process.stderr.write(`[${label}] Resetting database and Redis\n`); await resetState(); @@ -82,7 +92,7 @@ async function genSample(label: string, repoDir: string, round: number, options: process.stderr.write(`[${label}] Measuring memory\n`); return await measureBackendMemory(resolve(repoDir, 'packages/backend'), { // warmupラウンド (round <= 0) ���る�����heap snapshot��ら�� - ...(round <= 0 ? { heapSnapshot: false } : {}), + ...(round <= 0 || options.collectHeapSnapshot === false ? { heapSnapshot: false } : {}), heapSnapshotSavePath: options.heapSnapshotSavePath ?? null, }); } @@ -91,32 +101,12 @@ function heapSnapshotPath(label: HeapSnapshotLabel, round: number) { return join(HEAP_SNAPSHOT_WORK_DIRS[label], `round-${round}.heapsnapshot`); } -/** - * 中央値�最も近�ラウンドを代表�����。外れ値�スナップショットを�果物������。 - */ -function selectRepresentativeHeapSnapshotRound(samples: MemoryReport['samples'], summary: MemoryReport['summary']) { - const medianTotal = summary.afterGc.heapSnapshot?.categories.total; - if (medianTotal == null || !Number.isFinite(medianTotal)) return null; - - let selected: { round: number; distance: number } | null = null; - for (const sample of samples) { - const total = sample.phases.afterGc.heapSnapshot?.categories.total; - if (total == null || !Number.isFinite(total)) continue; - - const distance = Math.abs(total - medianTotal); - if (selected == null || distance < selected.distance || (distance === selected.distance && sample.round < selected.round)) { - selected = { - round: sample.round, - distance, - }; - } - } - - return selected?.round ?? null; -} - async function saveRepresentativeHeapSnapshot(label: HeapSnapshotLabel, samples: MemoryReport['samples'], summary: MemoryReport['summary']) { - const round = selectRepresentativeHeapSnapshotRound(samples, summary); + const round = selectRepresentativeHeapSnapshotRound( + samples, + summary.afterGc.heapSnapshot?.categories.total, + sample => sample.phases.afterGc.heapSnapshot?.categories.total, + ); if (round == null) return; await copyFile(heapSnapshotPath(label, round), HEAP_SNAPSHOT_OUTPUT_PATHS[label]); @@ -131,6 +121,11 @@ async function saveRepresentativeHeapSnapshot(label: HeapSnapshotLabel, samples: export async function compareBackendMemory(options: CompareOptions) { const rounds = readIntegerEnv('MK_MEMORY_COMPARE_ROUNDS', 5, 1); const warmupRounds = readIntegerEnv('MK_MEMORY_COMPARE_WARMUP_ROUNDS', 1, 0); + const heapSnapshotsEnabled = readBooleanEnv('MK_MEMORY_HEAP_SNAPSHOT', false); + const requestedHeapSnapshotRounds = heapSnapshotsEnabled + ? readIntegerEnv('MK_MEMORY_HEAP_SNAPSHOT_ROUNDS', rounds, 1) + : 0; + const heapSnapshotRounds = clampHeapSnapshotRounds(rounds, requestedHeapSnapshotRounds); const startedAt = new Date().toISOString(); for (const label of heapSnapshotLabels) { @@ -161,7 +156,11 @@ export async function compareBackendMemory(options: CompareOptions) { process.stderr.write(`Starting measurement round ${round}/${rounds}: ${order.join(' -> ')}\n`); for (const label of order) { - const sample = await genSample(label, reports[label].dir, round, { heapSnapshotSavePath: heapSnapshotPath(label, round) }); + const collectHeapSnapshot = shouldCollectHeapSnapshot(round, rounds, heapSnapshotRounds); + const sample = await genSample(label, reports[label].dir, round, { + collectHeapSnapshot, + ...(collectHeapSnapshot ? { heapSnapshotSavePath: heapSnapshotPath(label, round) } : {}), + }); reports[label].samples.push({ ...sample, round, @@ -186,6 +185,7 @@ export async function compareBackendMemory(options: CompareOptions) { strategy: 'interleaved-pairs', rounds, warmupRounds, + heapSnapshotRounds, startedAt, }, summary: summaries[label], diff --git a/packages-private/diagnostics-backend/src/heap-snapshot-sampling.ts b/packages-private/diagnostics-backend/src/heap-snapshot-sampling.ts new file mode 100644 index 00000000000..791840f9bd9 --- /dev/null +++ b/packages-private/diagnostics-backend/src/heap-snapshot-sampling.ts @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export function clampHeapSnapshotRounds(totalRounds: number, requestedRounds: number) { + return Math.min(totalRounds, requestedRounds); +} + +export function shouldCollectHeapSnapshot(round: number, totalRounds: number, requestedRounds: number) { + const snapshotRounds = clampHeapSnapshotRounds(totalRounds, requestedRounds); + return round > totalRounds - snapshotRounds; +} + +/** + * 中央値�最も近�ラウンドを代表�����。外れ値�スナップショットを�果物������。 + */ +export function selectRepresentativeHeapSnapshotRound( + samples: T[], + medianTotal: number | null | undefined, + getTotal: (sample: T) => number | null | undefined, +) { + if (medianTotal == null || !Number.isFinite(medianTotal)) return null; + + let selected: { round: number; distance: number } | null = null; + for (const sample of samples) { + const total = getTotal(sample); + if (total == null || !Number.isFinite(total)) continue; + + const distance = Math.abs(total - medianTotal); + if (selected == null || distance < selected.distance || (distance === selected.distance && sample.round < selected.round)) { + selected = { round: sample.round, distance }; + } + } + + return selected?.round ?? null; +} diff --git a/packages-private/diagnostics-backend/src/report/markdown.ts b/packages-private/diagnostics-backend/src/report/markdown.ts index bd4655dbe23..0fe16bf62f4 100644 --- a/packages-private/diagnostics-backend/src/report/markdown.ts +++ b/packages-private/diagnostics-backend/src/report/markdown.ts @@ -3,9 +3,14 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { formatColoredDelta, formatDeltaPercentInMdTable, formatKiBAsMb } from 'diagnostics-shared/format'; -import { median, pairedDeltaSummary, sampleSpread } from 'diagnostics-shared/stats'; -import { renderHeapSnapshotTable } from 'diagnostics-shared/heap-snapshot'; +import { formatKiBAsMb } from 'diagnostics-shared/format'; +import { renderHeapSnapshotTable, type HeapSnapshotReport } from 'diagnostics-shared/heap-snapshot'; +import { renderMetricComparisonTable } from 'diagnostics-shared/metric-table'; +import { + independentDeltaSummary, + isOutsideObservedNoise, + type IndependentDeltaSummary, +} from 'diagnostics-shared/stats'; import type { MemoryPhase, MemoryReport } from '../types'; export type RenderMemoryReportOptions = { @@ -29,6 +34,8 @@ const memoryMetrics = [ type MemoryMetric = typeof memoryMetrics[number]; +const memoryColorThresholdKiB = 100; + function formatMemoryMetricName(metric: MemoryMetric) { return metric === 'Pss' ? 'PSS' : metric; } @@ -40,64 +47,51 @@ function getMemoryValueFromSample(sample: MemoryReport['samples'][number], phase return memoryUsage.Private_Clean + memoryUsage.Private_Dirty; } -function getSampleValues(report: MemoryReport, phase: MemoryPhase, metric: MemoryMetric) { - return report.samples.map(sample => getMemoryValueFromSample(sample, phase, metric)); -} - -function getMemoryValue(report: MemoryReport, phase: MemoryPhase, metric: MemoryMetric) { - if (metric !== 'USS') return report.summary[phase].memoryUsage[metric]; - return median(getSampleValues(report, phase, metric)); +function summarizeMemoryMetric(base: MemoryReport, head: MemoryReport, phase: MemoryPhase, metric: MemoryMetric) { + return independentDeltaSummary( + base.samples, + head.samples, + sample => getMemoryValueFromSample(sample, phase, metric), + ); } -function getSampleSpread(report: MemoryReport, phase: MemoryPhase, metric: MemoryMetric) { - return sampleSpread(getSampleValues(report, phase, metric)); +function getDeltaPercent(summary: IndependentDeltaSummary) { + if (summary.baseMedian === 0) return null; + return summary.delta * 100 / summary.baseMedian; } function renderMainTableForPhase(base: MemoryReport, head: MemoryReport, phase: MemoryPhase) { - const lines = [ - '| Metric | Base | Head | Δ median | Δ MAD | Δ min | Δ max |', - '| --- | ---: | ---: | ---: | ---: | ---: | ---: |', - ]; - - function formatDeltaMemory(deltaKiB: number) { - return formatColoredDelta(deltaKiB, v => formatKiBAsMb(v), 100); // 0.1 MB threshold - } - - for (const metric of memoryMetrics) { - const baseValue = getMemoryValue(base, phase, metric); - const headValue = getMemoryValue(head, phase, metric); - - const baseSpread = getSampleSpread(base, phase, metric); - const headSpread = getSampleSpread(head, phase, metric); - const summary = pairedDeltaSummary(base.samples, head.samples, (sample) => getMemoryValueFromSample(sample, phase, metric)); - const percent = summary.median * 100 / baseValue; - const deltaMedian = `${formatDeltaMemory(summary.median)}
    ${formatDeltaPercentInMdTable(percent, 0.1)}`; + return renderMetricComparisonTable( + base.samples, + head.samples, + memoryMetrics.map(metric => ({ + label: `**${formatMemoryMetricName(metric)}**`, + getValue: sample => getMemoryValueFromSample(sample, phase, metric), + formatValue: formatKiBAsMb, + absoluteThreshold: memoryColorThresholdKiB, + })), + ); +} - lines.push(`| **${formatMemoryMetricName(metric)}** | ${formatKiBAsMb(baseValue)}
    ± ${formatKiBAsMb(baseSpread)} | ${formatKiBAsMb(headValue)}
    ± ${formatKiBAsMb(headSpread)} | ${deltaMedian} | ${formatKiBAsMb(summary.mad)} | ${formatDeltaMemory(summary.min)} | ${formatDeltaMemory(summary.max)} |`); - } +function toHeapSnapshotReport(report: MemoryReport): HeapSnapshotReport | null { + const summary = report.summary.afterGc.heapSnapshot; + if (summary == null) return null; - return lines.join('\n'); + return { + summary, + samples: report.samples.flatMap(sample => { + const data = sample.phases.afterGc.heapSnapshot; + return data == null ? [] : [{ round: sample.round, data }]; + }), + }; } function renderHeapSnapshotSection(base: MemoryReport, head: MemoryReport) { - const baseHeapSnapshotReport = { - summary: base.summary.afterGc.heapSnapshot!, - samples: base.samples.map(sample => ({ - round: sample.round, - data: sample.phases.afterGc.heapSnapshot!, - })), - }; - - const headHeapSnapshotReport = { - summary: head.summary.afterGc.heapSnapshot!, - samples: head.samples.map(sample => ({ - round: sample.round, - data: sample.phases.afterGc.heapSnapshot!, - })), - }; + const baseHeapSnapshotReport = toHeapSnapshotReport(base); + const headHeapSnapshotReport = toHeapSnapshotReport(head); + if (baseHeapSnapshotReport == null || headHeapSnapshotReport == null) return null; const table = renderHeapSnapshotTable(baseHeapSnapshotReport, headHeapSnapshotReport); - if (table == null) return null; const lines = [ '### V8 Heap Snapshot Statistics', @@ -119,29 +113,11 @@ function renderHeapSnapshotSection(base: MemoryReport, head: MemoryReport) { return lines.join('\n'); } -function getDiffPercent(base: MemoryReport, head: MemoryReport, phase: MemoryPhase, metric: MemoryMetric) { - const baseValue = getMemoryValue(base, phase, metric); - const headValue = getMemoryValue(head, phase, metric); - return ((headValue - baseValue) * 100) / baseValue; -} - -/** - * 増加分�サンプル��ら��を明確�超���る�を見る。 - * 測定ノイズ�警告�出続�る�を��る������ら���3�を閾値��る。 - */ -function isBeyondSampleNoise(base: MemoryReport, head: MemoryReport, phase: MemoryPhase, metric: MemoryMetric) { - const baseValue = getMemoryValue(base, phase, metric); - const headValue = getMemoryValue(head, phase, metric); - - const delta = headValue - baseValue; - if (delta <= 0) return false; - - const baseSpread = getSampleSpread(base, phase, metric); - const headSpread = getSampleSpread(head, phase, metric); - if (baseSpread == null || headSpread == null) return true; - - const combinedSpread = Math.hypot(baseSpread, headSpread); - return delta > combinedSpread * 3; +function countNonConvergedMemorySamples(base: MemoryReport, head: MemoryReport) { + return [base, head] + .flatMap(report => report.samples) + .filter(sample => memoryReportPhases.some(phase => !sample.phases[phase.key].memoryStability.converged)) + .length; } export function renderMemoryReportMarkdown(base: MemoryReport, head: MemoryReport, options: RenderMemoryReportOptions) { @@ -162,6 +138,16 @@ export function renderMemoryReportMarkdown(base: MemoryReport, head: MemoryRepor lines.push(''); } + lines.push(`_Values are median ± MAD (${base.samples.length} base / ${head.samples.length} head samples). Delta is Head - Base. Deltas are highlighted when their absolute value reaches the metric threshold and exceeds 3 × MAD._`); + lines.push(''); + + const nonConvergedSamples = countNonConvergedMemorySamples(base, head); + if (nonConvergedSamples > 0) { + const noun = nonConvergedSamples === 1 ? 'sample' : 'samples'; + lines.push(`⚠� **Measurement warning**: ${nonConvergedSamples} memory ${noun} did not converge.`); + lines.push(''); + } + const heapSnapshotSection = renderHeapSnapshotSection(base, head); if (heapSnapshotSection != null) { lines.push(heapSnapshotSection); @@ -172,8 +158,14 @@ export function renderMemoryReportMarkdown(base: MemoryReport, head: MemoryRepor lines.push(''); const warningMetric = 'Pss'; - const warningDiffPercent = getDiffPercent(base, head, 'afterGc', warningMetric); - if (warningDiffPercent > 5 && isBeyondSampleNoise(base, head, 'afterGc', warningMetric)) { + const warningSummary = summarizeMemoryMetric(base, head, 'afterGc', warningMetric); + const warningDiffPercent = getDeltaPercent(warningSummary); + if ( + warningSummary.delta > 0 && + warningDiffPercent != null && + warningDiffPercent > 5 && + isOutsideObservedNoise(warningSummary) + ) { lines.push(`⚠� **Warning**: Memory usage (${formatMemoryMetricName(warningMetric)}) has increased by more than 5% and exceeds the observed sample noise. Please verify this is not an unintended change.`); lines.push(''); } diff --git a/packages-private/diagnostics-backend/src/types.ts b/packages-private/diagnostics-backend/src/types.ts index 2dff718a5cd..e095572f293 100644 --- a/packages-private/diagnostics-backend/src/types.ts +++ b/packages-private/diagnostics-backend/src/types.ts @@ -37,6 +37,7 @@ export type MemoryReport = { strategy: string; rounds: number; warmupRounds: number; + heapSnapshotRounds?: number; startedAt: string; }; summary: Record ± 1 MB | 168 MB
    ± 1 MB | $\color{orange}{\text{+16 MB}}$
    $\color{orange}{\text{+10.5\\%}}$ | 0 MB | $\color{orange}{\text{+16 MB}}$ | $\color{orange}{\text{+16 MB}}$ | -| **PSS** | 202 MB
    ± 1 MB | 218 MB
    ± 1 MB | $\color{orange}{\text{+16 MB}}$
    $\color{orange}{\text{+7.9\\%}}$ | 0 MB | $\color{orange}{\text{+16 MB}}$ | $\color{orange}{\text{+16 MB}}$ | -| **USS** | 184 MB
    ± 1 MB | 200 MB
    ± 1 MB | $\color{orange}{\text{+16 MB}}$
    $\color{orange}{\text{+8.7\\%}}$ | 0 MB | $\color{orange}{\text{+16 MB}}$ | $\color{orange}{\text{+16 MB}}$ | -| **External** | 8.2 MB
    ± 0.1 MB | 8.2 MB
    ± 0.1 MB | 0 MB
    0% | 0 MB | 0 MB | 0 MB | +| Metric | @ Base | @ Head | Δ | MAD | +| --- | ---: | ---: | ---: | ---: | +| **HeapUsed** | 152 MB
    ± 1 MB | 168 MB
    ± 1 MB | $\color{orange}{\text{+16 MB}}$
    $\color{orange}{\text{+10.5\\%}}$ | 1.4 MB | +| **PSS** | 202 MB
    ± 1 MB | 218 MB
    ± 1 MB | $\color{orange}{\text{+16 MB}}$
    $\color{orange}{\text{+7.9\\%}}$ | 1.4 MB | +| **USS** | 184 MB
    ± 1 MB | 200 MB
    ± 1 MB | $\color{orange}{\text{+16 MB}}$
    $\color{orange}{\text{+8.7\\%}}$ | 1.4 MB | +| **External** | 8.2 MB
    ± 0.1 MB | 8.2 MB
    ± 0.1 MB | 0 MB
    0% | 0.1 MB | + +_Values are median ± MAD (3 base / 3 head samples). Delta is Head - Base. Deltas are highlighted when their absolute value reaches the metric threshold and exceeds 3 × MAD._ ### V8 Heap Snapshot Statistics -| Metric | Base | Head | Δ median | Δ MAD | Δ min | Δ max | -| --- | ---: | ---: | ---: | ---: | ---: | ---: | -| $\color{gray}{\rule{8pt}{8pt}}$ **Total** | 40 MB
    ± 200 KB | 44 MB
    ± 200 KB | $\color{orange}{\text{+3.2 MB}}$
    $\color{orange}{\text{+7.9\\%}}$ | 0 B | $\color{orange}{\text{+3.2 MB}}$ | $\color{orange}{\text{+3.2 MB}}$ | -| | | | | | | | -|
    $\color{orange}{\rule{8pt}{8pt}}$ **Code**11.8% → 11.8%
    | 4.7 MB | 5.1 MB | $\color{orange}{\text{+376 KB}}$ | 0 B | $\color{orange}{\text{+376 KB}}$ | $\color{orange}{\text{+376 KB}}$ | -|
    $\color{red}{\rule{8pt}{8pt}}$ **Strings**11% → 11%
    | 4.4 MB | 4.8 MB | $\color{orange}{\text{+352 KB}}$ | 0 B | $\color{orange}{\text{+352 KB}}$ | $\color{orange}{\text{+352 KB}}$ | -|
    $\color{cyan}{\rule{8pt}{8pt}}$ **JS arrays**10.3% → 10.3%
    | 4.1 MB | 4.5 MB | $\color{orange}{\text{+328 KB}}$ | 0 B | $\color{orange}{\text{+328 KB}}$ | $\color{orange}{\text{+328 KB}}$ | -|
    $\color{green}{\rule{8pt}{8pt}}$ **Typed arrays**9.5% → 9.5%
    | 3.8 MB | 4.1 MB | $\color{orange}{\text{+304 KB}}$ | 0 B | $\color{orange}{\text{+304 KB}}$ | $\color{orange}{\text{+304 KB}}$ | -|
    $\color{yellow}{\rule{8pt}{8pt}}$ **System objects**8.8% → 8.8%
    | 3.5 MB | 3.8 MB | $\color{orange}{\text{+280 KB}}$ | 0 B | $\color{orange}{\text{+280 KB}}$ | $\color{orange}{\text{+280 KB}}$ | -|
    $\color{violet}{\rule{8pt}{8pt}}$ **Other JS objs**8% → 8%
    | 3.2 MB | 3.5 MB | $\color{orange}{\text{+256 KB}}$ | 0 B | $\color{orange}{\text{+256 KB}}$ | $\color{orange}{\text{+256 KB}}$ | -|
    $\color{pink}{\rule{8pt}{8pt}}$ **Other non-JS objs**7.3% → 7.3%
    | 2.9 MB | 3.2 MB | $\color{orange}{\text{+232 KB}}$ | 0 B | $\color{orange}{\text{+232 KB}}$ | $\color{orange}{\text{+232 KB}}$ | +| Metric | @ Base | @ Head | Δ | MAD | +| --- | ---: | ---: | ---: | ---: | +| $\color{gray}{\rule{8pt}{8pt}}$ **Total** | 40 MB
    ± 200 KB | 44 MB
    ± 200 KB | $\color{orange}{\text{+3.2 MB}}$
    $\color{orange}{\text{+7.9\\%}}$ | 283 KB | +| | | | | | +| $\color{orange}{\rule{8pt}{8pt}}$ **Code** | 4.7 MB | 5.1 MB | $\color{orange}{\text{+376 KB}}$ | 33 KB | +| $\color{red}{\rule{8pt}{8pt}}$ **Strings** | 4.4 MB | 4.8 MB | $\color{orange}{\text{+352 KB}}$ | 31 KB | +| $\color{cyan}{\rule{8pt}{8pt}}$ **JS arrays** | 4.1 MB | 4.5 MB | $\color{orange}{\text{+328 KB}}$ | 29 KB | +| $\color{green}{\rule{8pt}{8pt}}$ **Typed arrays** | 3.8 MB | 4.1 MB | $\color{orange}{\text{+304 KB}}$ | 27 KB | +| $\color{yellow}{\rule{8pt}{8pt}}$ **System objects** | 3.5 MB | 3.8 MB | $\color{orange}{\text{+280 KB}}$ | 25 KB | +| $\color{violet}{\rule{8pt}{8pt}}$ **Other JS objs** | 3.2 MB | 3.5 MB | $\color{orange}{\text{+256 KB}}$ | 23 KB | +| $\color{pink}{\rule{8pt}{8pt}}$ **Other non-JS objs** | 2.9 MB | 3.2 MB | $\color{orange}{\text{+232 KB}}$ | 21 KB | Download representative heap snapshot: [base](https://example.invalid/base) / [head](https://example.invalid/head) diff --git a/packages-private/diagnostics-backend/test/heap-snapshot-sampling.test.ts b/packages-private/diagnostics-backend/test/heap-snapshot-sampling.test.ts new file mode 100644 index 00000000000..8409fe166ba --- /dev/null +++ b/packages-private/diagnostics-backend/test/heap-snapshot-sampling.test.ts @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test } from 'vitest'; +import { + clampHeapSnapshotRounds, + selectRepresentativeHeapSnapshotRound, + shouldCollectHeapSnapshot, +} from '../src/heap-snapshot-sampling'; + +describe('heap snapshot sampling', () => { + test('collects only the final requested rounds', () => { + const selected = Array.from({ length: 15 }, (_, index) => index + 1) + .filter(round => shouldCollectHeapSnapshot(round, 15, 3)); + expect(selected).toStrictEqual([13, 14, 15]); + }); + + test('clamps the requested count to the measured round count', () => { + expect(clampHeapSnapshotRounds(5, 20)).toBe(5); + expect(Array.from({ length: 5 }, (_, index) => index + 1) + .filter(round => shouldCollectHeapSnapshot(round, 5, 20))) + .toStrictEqual([1, 2, 3, 4, 5]); + }); + + test('collects no snapshots when the effective count is zero', () => { + expect(Array.from({ length: 5 }, (_, index) => index + 1) + .filter(round => shouldCollectHeapSnapshot(round, 5, 0))) + .toStrictEqual([]); + }); + + test('selects the snapshot nearest the median and ignores missing rounds', () => { + const samples = [ + { round: 12, total: null }, + { round: 13, total: 100 }, + { round: 14, total: 110 }, + { round: 15, total: 130 }, + ]; + expect(selectRepresentativeHeapSnapshotRound(samples, 110, sample => sample.total)).toBe(14); + }); +}); diff --git a/packages-private/diagnostics-backend/test/render-md.test.ts b/packages-private/diagnostics-backend/test/render-md.test.ts index 468822014fa..6dcf1979ca0 100644 --- a/packages-private/diagnostics-backend/test/render-md.test.ts +++ b/packages-private/diagnostics-backend/test/render-md.test.ts @@ -6,6 +6,7 @@ import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; import { expect, test } from 'vitest'; +import { pairedDeltaSummary } from 'diagnostics-shared/stats'; import { renderMemoryReportMarkdown } from '../src/report/markdown'; import type { MemoryReport } from '../src/types'; @@ -15,6 +16,26 @@ async function loadFixture(name: string) { return JSON.parse(await readFile(join(fixturesDir, `${name}.json`), 'utf8')) as MemoryReport; } +function replacePssSamples(report: MemoryReport, values: number[]) { + const templates = structuredClone(report.samples); + report.samples = values.map((Pss, index) => { + const sample = structuredClone(templates[index % templates.length]); + sample.round = index + 1; + sample.phases.afterGc.memoryUsage.Pss = Pss; + const privateClean = sample.phases.afterGc.memoryUsage.Private_Clean; + sample.phases.afterGc.memoryUsage.Private_Dirty = Pss - privateClean; + return sample; + }); + report.sampleCount = report.samples.length; + return report; +} + +function findMetricRow(markdown: string, metric: string) { + const row = markdown.split('\n').find(line => line.startsWith(`| **${metric}**`)); + if (row === undefined) throw new Error(`expected memory report to contain a ${metric} row`); + return row; +} + /** * 出力をゴールデンファイル�固定�る。 * �図的�変更����� `vitest -u` �更新��__snapshots__ �差分もレビュー�る��。 @@ -27,3 +48,89 @@ test('renders the backend memory report', async () => { await expect(markdown).toMatchFileSnapshot('./__snapshots__/render-md.md'); }); + +test('throws when filtering leaves fewer than two heap snapshots per side', async () => { + const base = await loadFixture('base'); + const head = await loadFixture('head'); + for (const report of [base, head]) { + for (const sample of report.samples.slice(0, -1)) { + sample.phases.afterGc.heapSnapshot = null; + } + } + + expect(() => renderMemoryReportMarkdown(base, head, { + baseHeapSnapshotUrl: 'https://example.invalid/base', + headHeapSnapshotUrl: 'https://example.invalid/head', + })).toThrow('At least two samples per side are required'); +}); + +test('reports the difference of medians and leaves a paired-looking PSS delta uncoloured', async () => { + const base = replacePssSamples(await loadFixture('base'), [290_000, 292_900, 295_800, 298_700, 301_600]); + const head = replacePssSamples(await loadFixture('head'), [292_900, 296_300, 298_700, 301_600, 290_000]); + + expect(pairedDeltaSummary( + base.samples, + head.samples, + sample => sample.phases.afterGc.memoryUsage.Pss, + ).median).toBe(2_900); + + const markdown = renderMemoryReportMarkdown(base, head, { + baseHeapSnapshotUrl: 'https://example.invalid/base', + headHeapSnapshotUrl: 'https://example.invalid/head', + }); + const row = findMetricRow(markdown, 'PSS'); + + expect(row).toContain('295.8 MB
    ± 2.9 MB'); + expect(row).toContain('296.3 MB
    ± 3.4 MB'); + expect(row).toContain('$\\text{+0.5 MB}$'); + expect(row).toContain('4.5 MB'); + expect(row.split('|')).toHaveLength(7); + expect(row).not.toMatch(/within noise|increase|decrease|inconclusive/); + expect(row).not.toContain('\\color{orange}'); + expect(findMetricRow(markdown, 'USS')).not.toContain('\\color{orange}'); +}); + +test('keeps the convergence warning without suppressing table colour or the PSS warning', async () => { + const base = await loadFixture('base'); + const head = await loadFixture('head'); + base.samples[0].phases.afterGc.memoryStability.converged = false; + + const markdown = renderMemoryReportMarkdown(base, head, { + baseHeapSnapshotUrl: 'https://example.invalid/base', + headHeapSnapshotUrl: 'https://example.invalid/head', + }); + const memorySection = markdown.slice(0, markdown.indexOf('### V8 Heap Snapshot Statistics')); + + expect(memorySection).not.toContain('inconclusive'); + expect(findMetricRow(markdown, 'PSS')).toContain('\\color{orange}'); + expect(markdown).toContain('⚠� **Measurement warning**: 1 memory sample did not converge.'); + expect(markdown).not.toContain('results are marked inconclusive'); + expect(markdown).toContain('⚠� **Warning**: Memory usage (PSS)'); +}); + +test('throws for an undersampled memory comparison', async () => { + const base = await loadFixture('base'); + const head = await loadFixture('head'); + base.samples = base.samples.slice(0, 1); + head.samples = head.samples.slice(0, 1); + + expect(() => renderMemoryReportMarkdown(base, head, { + baseHeapSnapshotUrl: 'https://example.invalid/base', + headHeapSnapshotUrl: 'https://example.invalid/head', + })).toThrow('At least two samples per side are required'); +}); + +test('renders an unavailable percentage when the base median is zero', async () => { + const base = await loadFixture('base'); + const head = await loadFixture('head'); + for (const sample of base.samples) sample.phases.afterGc.memoryUsage.External = 0; + + const markdown = renderMemoryReportMarkdown(base, head, { + baseHeapSnapshotUrl: 'https://example.invalid/base', + headHeapSnapshotUrl: 'https://example.invalid/head', + }); + + expect(findMetricRow(markdown, 'External')).toContain('
    -'); + expect(markdown).toContain('| Metric | @ Base | @ Head | Δ | MAD |'); + expect(markdown).not.toContain('| Metric | @ Base | @ Head | Δ | MAD | Result |'); +}); diff --git a/packages-private/diagnostics-frontend/src/report.ts b/packages-private/diagnostics-frontend/src/report.ts index e605b0f9314..ab85c625f8d 100644 --- a/packages-private/diagnostics-frontend/src/report.ts +++ b/packages-private/diagnostics-frontend/src/report.ts @@ -5,11 +5,11 @@ import { formatBytes, formatColoredDelta, formatNumber } from 'diagnostics-shared/format'; import { renderHeapSnapshotTable, type HeapSnapshotReport } from 'diagnostics-shared/heap-snapshot'; -import { pairedDeltaSummary } from 'diagnostics-shared/stats'; +import { renderMetricComparisonTable } from 'diagnostics-shared/metric-table'; import { renderFrontendChunkReport } from './bundle/chunk-report'; import { collectVisualizerReport, renderVisualizerSummaryTable, type VisualizerReport } from './bundle/visualizer'; import type { CollectedBundleReport } from './bundle/manifest'; -import type { BrowserMeasurement, BrowserMeasurementSample, BrowserMetricsReport } from './browser/types'; +import type { BrowserMeasurementSample, BrowserMetricsReport } from './browser/types'; export type FrontendDiagnosticsMarkdownInput = { bundle: { @@ -29,86 +29,132 @@ export type FrontendDiagnosticsMarkdownInput = { }; }; -function renderMetricRow( - label: string, - base: BrowserMetricsReport, - head: BrowserMetricsReport, - getSummaryValue: (summary: BrowserMeasurement) => number, - getSampleValue: (sample: BrowserMeasurementSample) => number, - formatter: (value: number) => string, - significantThreshold = 0, - skipIfNotSignificant = true, -) { - const baseValue = getSummaryValue(base.summary); - const headValue = getSummaryValue(head.summary); - if (baseValue == null || headValue == null || !Number.isFinite(baseValue) || !Number.isFinite(headValue)) return null; - - const summary = pairedDeltaSummary(base.samples, head.samples, sample => getSampleValue(sample)); - // 有��閾値�満���場���も�もrow���出力��� - if (skipIfNotSignificant && (Math.abs(summary.median) < significantThreshold)) return null; - - const deltaMedian = formatColoredDelta(summary.median, formatter, significantThreshold); - - return `| **${label}** | ${formatter(baseValue)} | ${formatter(headValue)} | ${deltaMedian} | ${formatter(summary.mad)} | ${formatColoredDelta(summary.min, formatter, significantThreshold)} | ${formatColoredDelta(summary.max, formatter, significantThreshold)} |`; -} - -function resourceTypeBytes(report: BrowserMeasurement, resourceTypes: string[]) { - return resourceTypes.reduce((sum, resourceType) => sum + (report.network.byResourceType[resourceType]?.encodedBytes ?? 0), 0); -} - function resourceTypeSampleBytes(sample: BrowserMeasurementSample, resourceTypes: string[]) { - return resourceTypeBytes(sample, resourceTypes); + return resourceTypes.reduce((sum, resourceType) => sum + (sample.network.byResourceType[resourceType]?.encodedBytes ?? 0), 0); } -function renderBrowserSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsReport, all = false) { - //function getMetric(report: BrowserMeasurement, key: string) { - // return report.performance.cdpMetrics[key]; - //} - - const rows = [ - //renderMetricRow('Scenario duration', base, head, summary => summary.durationMs, sample => sample.durationMs, formatMs), - renderMetricRow('Requests', base, head, summary => summary.network.requestCount, sample => sample.network.requestCount, formatNumber, 1, !all), - //renderMetricRow('Failed requests', base, head, summary => summary.network.failedRequestCount, sample => sample.network.failedRequestCount, formatNumber), - renderMetricRow('Encoded network', base, head, summary => summary.network.totalEncodedBytes, sample => sample.network.totalEncodedBytes, formatBytes, 10000, !all), - renderMetricRow('Decoded body', base, head, summary => summary.network.totalDecodedBodyBytes, sample => sample.network.totalDecodedBodyBytes, formatBytes, 10000, !all), - renderMetricRow('Same-origin encoded', base, head, summary => summary.network.sameOriginEncodedBytes, sample => sample.network.sameOriginEncodedBytes, formatBytes, 10000, !all), - renderMetricRow('Third-party encoded', base, head, summary => summary.network.thirdPartyEncodedBytes, sample => sample.network.thirdPartyEncodedBytes, formatBytes, 10000, !all), - renderMetricRow('Script encoded', base, head, summary => resourceTypeBytes(summary, ['Script']), sample => resourceTypeSampleBytes(sample, ['Script']), formatBytes, 10000, !all), - renderMetricRow('Stylesheet encoded', base, head, summary => resourceTypeBytes(summary, ['Stylesheet']), sample => resourceTypeSampleBytes(sample, ['Stylesheet']), formatBytes, 10000, !all), - renderMetricRow('Fetch/XHR encoded', base, head, summary => resourceTypeBytes(summary, ['Fetch', 'XHR']), sample => resourceTypeSampleBytes(sample, ['Fetch', 'XHR']), formatBytes, 10000, !all), - renderMetricRow('Image encoded', base, head, summary => resourceTypeBytes(summary, ['Image']), sample => resourceTypeSampleBytes(sample, ['Image']), formatBytes, 10000, !all), - renderMetricRow('Font encoded', base, head, summary => resourceTypeBytes(summary, ['Font']), sample => resourceTypeSampleBytes(sample, ['Font']), formatBytes, 10000, !all), - //renderMetricRow('First contentful paint', base, head, summary => summary.performance.webVitals.firstContentfulPaintMs, sample => sample.performance.webVitals.firstContentfulPaintMs, formatMs), - //renderMetricRow('Load event end', base, head, summary => summary.performance.webVitals.loadEventEndMs, sample => sample.performance.webVitals.loadEventEndMs, formatMs), - //renderMetricRow('Long tasks', base, head, summary => summary.performance.webVitals.longTaskCount, sample => sample.performance.webVitals.longTaskCount, formatNumber), - //renderMetricRow('Long task duration', base, head, summary => summary.performance.webVitals.longTaskDurationMs, sample => sample.performance.webVitals.longTaskDurationMs, formatMs), - //renderMetricRow('Max long task', base, head, summary => summary.performance.webVitals.maxLongTaskDurationMs, sample => sample.performance.webVitals.maxLongTaskDurationMs, formatMs), - //renderMetricRow('JS heap used', base, head, summary => summary.performance.runtimeHeap?.usedSize ?? getMetric(summary, 'JSHeapUsedSize'), sample => sample.performance.runtimeHeap?.usedSize ?? getMetric(sample, 'JSHeapUsedSize'), formatBytes), - //renderMetricRow('JS heap total', base, head, summary => summary.performance.runtimeHeap?.totalSize ?? getMetric(summary, 'JSHeapTotalSize'), sample => sample.performance.runtimeHeap?.totalSize ?? getMetric(sample, 'JSHeapTotalSize'), formatBytes), - //renderMetricRow('V8 heap snapshot total', base, head, summary => summary.heapSnapshot.categories.total, sample => sample.heapSnapshot.categories.total, formatBytes, 10000), - //renderMetricRow('DOM elements', base, head, summary => summary.performance.webVitals.domElements, sample => sample.performance.webVitals.domElements, formatNumber), - //renderMetricRow('CDP nodes', base, head, summary => getMetric(summary, 'Nodes'), sample => getMetric(sample, 'Nodes'), formatNumber), - //renderMetricRow('JS event listeners', base, head, summary => getMetric(summary, 'JSEventListeners'), sample => getMetric(sample, 'JSEventListeners'), formatNumber), - //renderMetricRow('Layout count', base, head, summary => getMetric(summary, 'LayoutCount'), sample => getMetric(sample, 'LayoutCount'), formatNumber), - //renderMetricRow('Recalc style count', base, head, summary => getMetric(summary, 'RecalcStyleCount'), sample => getMetric(sample, 'RecalcStyleCount'), formatNumber), - //renderMetricRow('Script duration', base, head, summary => getMetric(summary, 'ScriptDuration'), sample => getMetric(sample, 'ScriptDuration'), formatSecondsAsMs), - //renderMetricRow('Task duration', base, head, summary => getMetric(summary, 'TaskDuration'), sample => getMetric(sample, 'TaskDuration'), formatSecondsAsMs), - renderMetricRow('WebSocket connections', base, head, summary => summary.network.webSocketConnectionCount, sample => sample.network.webSocketConnectionCount, formatNumber, 1, !all), - renderMetricRow('WebSocket sent', base, head, summary => summary.network.webSocketSentBytes, sample => sample.network.webSocketSentBytes, formatBytes, 10000, !all), - renderMetricRow('WebSocket received', base, head, summary => summary.network.webSocketReceivedBytes, sample => sample.network.webSocketReceivedBytes, formatBytes, 10000, !all), - renderMetricRow('Page errors', base, head, summary => summary.diagnostics.pageErrorCount, sample => sample.diagnostics.pageErrorCount, formatNumber, 1, !all), - renderMetricRow('Console log', base, head, summary => summary.diagnostics.console.log, sample => sample.diagnostics.console.log, formatNumber, 1, !all), - renderMetricRow('Console warnings', base, head, summary => summary.diagnostics.console.warning, sample => sample.diagnostics.console.warning, formatNumber, 1, !all), - renderMetricRow('Console errors', base, head, summary => summary.diagnostics.console.error, sample => sample.diagnostics.console.error, formatNumber, 1, !all), - renderMetricRow('Console info', base, head, summary => summary.diagnostics.console.info, sample => sample.diagnostics.console.info, formatNumber, 1, !all), - renderMetricRow('Page-attributed memory', base, head, summary => summary.performance.tabMemory.totalBytes, sample => sample.performance.tabMemory.totalBytes, formatBytes, 10000, !all), - ].filter(row => row != null); - - return [ - '| Metric | Base | Head | Δ median | Δ MAD | Δ min | Δ max |', - '| --- | ---: | ---: | ---: | ---: | ---: | ---: |', - ...rows, - ].join('\n'); +function renderBrowserSummaryTable(base: BrowserMetricsReport, head: BrowserMetricsReport) { + return renderMetricComparisonTable( + base.samples, + head.samples, + [ + { + label: '**Requests**', + getValue: sample => sample.network.requestCount, + formatValue: formatNumber, + absoluteThreshold: 1, + }, + { + label: '**Encoded network**', + getValue: sample => sample.network.totalEncodedBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**Decoded body**', + getValue: sample => sample.network.totalDecodedBodyBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**Same-origin encoded**', + getValue: sample => sample.network.sameOriginEncodedBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**Third-party encoded**', + getValue: sample => sample.network.thirdPartyEncodedBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**Script encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Script']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**Stylesheet encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Stylesheet']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**Fetch/XHR encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Fetch', 'XHR']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**Image encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Image']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**Font encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Font']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**WebSocket connections**', + getValue: sample => sample.network.webSocketConnectionCount, + formatValue: formatNumber, + absoluteThreshold: 1, + }, + { + label: '**WebSocket sent**', + getValue: sample => sample.network.webSocketSentBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**WebSocket received**', + getValue: sample => sample.network.webSocketReceivedBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + { + label: '**Page errors**', + getValue: sample => sample.diagnostics.pageErrorCount, + formatValue: formatNumber, + absoluteThreshold: 1, + }, + { + label: '**Console log**', + getValue: sample => sample.diagnostics.console.log, + formatValue: formatNumber, + absoluteThreshold: 1, + }, + { + label: '**Console warnings**', + getValue: sample => sample.diagnostics.console.warning, + formatValue: formatNumber, + absoluteThreshold: 1, + }, + { + label: '**Console errors**', + getValue: sample => sample.diagnostics.console.error, + formatValue: formatNumber, + absoluteThreshold: 1, + }, + { + label: '**Console info**', + getValue: sample => sample.diagnostics.console.info, + formatValue: formatNumber, + absoluteThreshold: 1, + }, + { + label: '**Page-attributed memory**', + getValue: sample => sample.performance.tabMemory.totalBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, + ], + { onlySignificantChanges: true }, + ); } function renderResourceTypeTable(base: BrowserMetricsReport, head: BrowserMetricsReport) { @@ -199,7 +245,7 @@ export function renderFrontendDiagnosticsMarkdown(input: FrontendDiagnosticsMark `Download representative heap snapshot: [base](${browser.baseHeapSnapshotUrl}) / [head](${browser.headHeapSnapshotUrl})`, '
    ', '', - '### 📦 Bundle Stats', + '## 📦 Bundle Stats', '', renderFrontendChunkReport(bundle.base, bundle.head), '', diff --git a/packages-private/diagnostics-frontend/test/__snapshots__/report.md b/packages-private/diagnostics-frontend/test/__snapshots__/report.md index 41d3aae7279..144ff183055 100644 --- a/packages-private/diagnostics-frontend/test/__snapshots__/report.md +++ b/packages-private/diagnostics-frontend/test/__snapshots__/report.md @@ -1,12 +1,12 @@ ## 🖥 Frontend Diagnostics Report -| Metric | Base | Head | Δ median | Δ MAD | Δ min | Δ max | -| --- | ---: | ---: | ---: | ---: | ---: | ---: | -| **Encoded network** | 1 MB | 1.1 MB | $\color{orange}{\text{+83 KB}}$ | 816 B | $\color{orange}{\text{+82 KB}}$ | $\color{orange}{\text{+84 KB}}$ | -| **Decoded body** | 3.5 MB | 3.7 MB | $\color{orange}{\text{+277 KB}}$ | 2.7 KB | $\color{orange}{\text{+274 KB}}$ | $\color{orange}{\text{+279 KB}}$ | -| **Same-origin encoded** | 1 MB | 1.1 MB | $\color{orange}{\text{+82 KB}}$ | 800 B | $\color{orange}{\text{+81 KB}}$ | $\color{orange}{\text{+82 KB}}$ | -| **Script encoded** | 918 KB | 991 KB | $\color{orange}{\text{+73 KB}}$ | 720 B | $\color{orange}{\text{+73 KB}}$ | $\color{orange}{\text{+74 KB}}$ | -| **Page-attributed memory** | 92 MB | 99 MB | $\color{orange}{\text{+7.3 MB}}$ | 72 KB | $\color{orange}{\text{+7.3 MB}}$ | $\color{orange}{\text{+7.4 MB}}$ | +| Metric | @ Base | @ Head | Δ | MAD | +| --- | ---: | ---: | ---: | ---: | +| **Encoded network** | 1 MB
    ± 10 KB | 1.1 MB
    ± 11 KB | $\color{orange}{\text{+83 KB}}$
    $\color{orange}{\text{+8\\%}}$ | 15 KB | +| **Decoded body** | 3.5 MB
    ± 34 KB | 3.7 MB
    ± 37 KB | $\color{orange}{\text{+277 KB}}$
    $\color{orange}{\text{+8\\%}}$ | 50 KB | +| **Same-origin encoded** | 1 MB
    ± 10 KB | 1.1 MB
    ± 11 KB | $\color{orange}{\text{+82 KB}}$
    $\color{orange}{\text{+8\\%}}$ | 15 KB | +| **Script encoded** | 918 KB
    ± 9 KB | 991 KB
    ± 9.7 KB | $\color{orange}{\text{+73 KB}}$
    $\color{orange}{\text{+8\\%}}$ | 13 KB | +| **Page-attributed memory** | 92 MB
    ± 900 KB | 99 MB
    ± 972 KB | $\color{orange}{\text{+7.3 MB}}$
    $\color{orange}{\text{+8\\%}}$ | 1.3 MB | Only metrics showing significant changes are displayed. @@ -67,22 +67,22 @@
    V8 heap snapshot statistics -| Metric | Base | Head | Δ median | Δ MAD | Δ min | Δ max | -| --- | ---: | ---: | ---: | ---: | ---: | ---: | -| $\color{gray}{\rule{8pt}{8pt}}$ **Total** | 1 MB
    ± 10 KB | 1.1 MB
    ± 11 KB | $\text{+82 KB}$
    $\color{orange}{\text{+8\\%}}$ | 800 B | $\text{+81 KB}$ | $\text{+82 KB}$ | -| | | | | | | | -|
    $\color{orange}{\rule{8pt}{8pt}}$ **Code**200% → 200%
    | 2 MB | 2.2 MB | $\color{orange}{\text{+163 KB}}$ | 1.6 KB | $\color{orange}{\text{+162 KB}}$ | $\color{orange}{\text{+165 KB}}$ | -|
    $\color{red}{\rule{8pt}{8pt}}$ **Strings**300% → 300%
    | 3.1 MB | 3.3 MB | $\color{orange}{\text{+245 KB}}$ | 2.4 KB | $\color{orange}{\text{+242 KB}}$ | $\color{orange}{\text{+247 KB}}$ | -|
    $\color{cyan}{\rule{8pt}{8pt}}$ **JS arrays**400% → 400%
    | 4.1 MB | 4.4 MB | $\color{orange}{\text{+326 KB}}$ | 3.2 KB | $\color{orange}{\text{+323 KB}}$ | $\color{orange}{\text{+330 KB}}$ | -|
    $\color{green}{\rule{8pt}{8pt}}$ **Typed arrays**500% → 500%
    | 5.1 MB | 5.5 MB | $\color{orange}{\text{+408 KB}}$ | 4 KB | $\color{orange}{\text{+404 KB}}$ | $\color{orange}{\text{+412 KB}}$ | -|
    $\color{yellow}{\rule{8pt}{8pt}}$ **System objects**600% → 600%
    | 6.1 MB | 6.6 MB | $\color{orange}{\text{+490 KB}}$ | 4.8 KB | $\color{orange}{\text{+485 KB}}$ | $\color{orange}{\text{+494 KB}}$ | -|
    $\color{violet}{\rule{8pt}{8pt}}$ **Other JS objs**700% → 700%
    | 7.1 MB | 7.7 MB | $\color{orange}{\text{+571 KB}}$ | 5.6 KB | $\color{orange}{\text{+566 KB}}$ | $\color{orange}{\text{+577 KB}}$ | -|
    $\color{pink}{\rule{8pt}{8pt}}$ **Other non-JS objs**800% → 800%
    | 8.2 MB | 8.8 MB | $\color{orange}{\text{+653 KB}}$ | 6.4 KB | $\color{orange}{\text{+646 KB}}$ | $\color{orange}{\text{+659 KB}}$ | +| Metric | @ Base | @ Head | Δ | MAD | +| --- | ---: | ---: | ---: | ---: | +| $\color{gray}{\rule{8pt}{8pt}}$ **Total** | 1 MB
    ± 10 KB | 1.1 MB
    ± 11 KB | $\text{+82 KB}$
    $\text{+8\\%}$ | 15 KB | +| | | | | | +| $\color{orange}{\rule{8pt}{8pt}}$ **Code** | 2 MB | 2.2 MB | $\color{orange}{\text{+163 KB}}$ | 29 KB | +| $\color{red}{\rule{8pt}{8pt}}$ **Strings** | 3.1 MB | 3.3 MB | $\color{orange}{\text{+245 KB}}$ | 44 KB | +| $\color{cyan}{\rule{8pt}{8pt}}$ **JS arrays** | 4.1 MB | 4.4 MB | $\color{orange}{\text{+326 KB}}$ | 59 KB | +| $\color{green}{\rule{8pt}{8pt}}$ **Typed arrays** | 5.1 MB | 5.5 MB | $\color{orange}{\text{+408 KB}}$ | 74 KB | +| $\color{yellow}{\rule{8pt}{8pt}}$ **System objects** | 6.1 MB | 6.6 MB | $\color{orange}{\text{+490 KB}}$ | 88 KB | +| $\color{violet}{\rule{8pt}{8pt}}$ **Other JS objs** | 7.1 MB | 7.7 MB | $\color{orange}{\text{+571 KB}}$ | 103 KB | +| $\color{pink}{\rule{8pt}{8pt}}$ **Other non-JS objs** | 8.2 MB | 8.8 MB | $\color{orange}{\text{+653 KB}}$ | 118 KB | Download representative heap snapshot: [base](https://example.invalid/base) / [head](https://example.invalid/head)
    -### 📦 Bundle Stats +## 📦 Bundle Stats
    Chunk size diff (2 updated, 0 added, 0 removed) diff --git a/packages-private/diagnostics-frontend/test/report.test.ts b/packages-private/diagnostics-frontend/test/report.test.ts index c45961ccb9d..463374aeec8 100644 --- a/packages-private/diagnostics-frontend/test/report.test.ts +++ b/packages-private/diagnostics-frontend/test/report.test.ts @@ -9,7 +9,7 @@ import { dirname, join } from 'node:path'; import { afterAll, beforeAll, expect, test } from 'vitest'; import { collectBundleReport } from '../src/bundle/manifest'; import { renderFrontendDiagnosticsMarkdown } from '../src/report'; -import type { BrowserMetricsReport } from '../src/browser/types'; +import type { BrowserMeasurementSample, BrowserMetricsReport } from '../src/browser/types'; import type { VisualizerReport } from '../src/bundle/visualizer'; const bundleFixturesDir = join(import.meta.dirname, 'bundle/fixtures'); @@ -90,7 +90,15 @@ async function loadBrowserReport(name: 'base' | 'head') { return JSON.parse(await readFile(join(browserFixturesDir, `${name}.json`), 'utf8')) as BrowserMetricsReport; } -async function renderReport(detailedHtmlUrl: string | null) { +type BrowserReports = { + base: BrowserMetricsReport; + head: BrowserMetricsReport; +}; + +async function renderReport(detailedHtmlUrl: string | null, reports?: BrowserReports) { + const base = reports?.base ?? await loadBrowserReport('base'); + const head = reports?.head ?? await loadBrowserReport('head'); + return renderFrontendDiagnosticsMarkdown({ bundle: { base: await collectBundleReport(repoDirs.base), @@ -100,8 +108,8 @@ async function renderReport(detailedHtmlUrl: string | null) { visualizerArtifactUrl: 'https://example.invalid/treemap', }, browser: { - base: await loadBrowserReport('base'), - head: await loadBrowserReport('head'), + base, + head, baseHeapSnapshotUrl: 'https://example.invalid/base', headHeapSnapshotUrl: 'https://example.invalid/head', detailedHtmlUrl, @@ -109,6 +117,32 @@ async function renderReport(detailedHtmlUrl: string | null) { }); } +function withMetricSamples( + report: BrowserMetricsReport, + values: number[], + setValue: (sample: BrowserMeasurementSample, value: number) => void, +): BrowserMetricsReport { + const cloned = structuredClone(report); + const samples = values.map((value, index) => { + const sample = structuredClone(cloned.samples[index % cloned.samples.length]); + sample.round = index + 1; + setValue(sample, value); + return sample; + }); + + return { + ...cloned, + sampleCount: samples.length, + samples, + }; +} + +function requireMetricRow(markdown: string, label: string) { + const row = markdown.split('\n').find(line => line.startsWith(`| **${label}** |`)); + if (row == null) throw new Error(`Metric row not found: ${label}`); + return row; +} + /** * 出力をゴールデンファイル�固定�る。 * �図的�変更����� `vitest -u` �更新��__snapshots__ �差分もレビュー�る��。 @@ -117,6 +151,10 @@ test('renders one frontend diagnostics markdown report from bundle and browser d const markdown = await renderReport('https://example.invalid/html'); await expect(markdown).toMatchFileSnapshot('./__snapshots__/report.md'); + expect(markdown).toContain('| Metric | @ Base | @ Head | Δ | MAD |'); + expect(markdown).not.toContain('| Metric | @ Base | @ Head | Δ | MAD | Result |'); + expect(markdown).toContain('Requests by resource type'); + expect(markdown).toContain('## 📦 Bundle Stats'); }); test('omits the browser details link when no detailed html artifact was uploaded', async () => { @@ -124,3 +162,148 @@ test('omits the browser details link when no detailed html artifact was uploaded expect(markdown).not.toContain('View details'); }); + +test('renders the difference of independent medians instead of the paired median delta', async () => { + const base = withMetricSamples( + await loadBrowserReport('base'), + [100, 100, 100, 1_000, 1_000], + (sample, value) => { sample.network.requestCount = value; }, + ); + const head = withMetricSamples( + await loadBrowserReport('head'), + [0, 0, 200, 200, 200], + (sample, value) => { sample.network.requestCount = value; }, + ); + + const row = requireMetricRow(await renderReport(null, { base, head }), 'Requests'); + + expect(row).toContain('100
    ± 0'); + expect(row).toContain('200
    ± 0'); + expect(row).toContain('$\\color{orange}{\\text{+100}}$
    $\\color{orange}{\\text{+100\\\\%}}$'); + expect(row).toContain('| 0 |'); + expect(row.split('|')).toHaveLength(7); + expect(row).not.toMatch(/increase|decrease|within noise|inconclusive/); + expect(row).not.toContain('\\color{green}'); +}); + +test('hides a threshold-sized change that remains within observed noise', async () => { + const base = withMetricSamples( + await loadBrowserReport('base'), + [100, 110, 120], + (sample, value) => { sample.network.requestCount = value; }, + ); + const head = withMetricSamples( + await loadBrowserReport('head'), + [110, 120, 130], + (sample, value) => { sample.network.requestCount = value; }, + ); + + const markdown = await renderReport(null, { base, head }); + + expect(markdown).not.toContain('| **Requests** |'); +}); + +test('renders a directional request count delta at the absolute threshold', async () => { + const base = withMetricSamples( + await loadBrowserReport('base'), + [100, 100, 100], + (sample, value) => { sample.network.requestCount = value; }, + ); + const head = withMetricSamples( + await loadBrowserReport('head'), + [101, 101, 101], + (sample, value) => { sample.network.requestCount = value; }, + ); + + const row = requireMetricRow(await renderReport(null, { base, head }), 'Requests'); + + expect(row).toContain('$\\color{orange}{\\text{+1}}$'); +}); + +test('hides a directional byte change below the existing absolute threshold', async () => { + const base = withMetricSamples( + await loadBrowserReport('base'), + [1_000_000, 1_000_000, 1_000_000], + (sample, value) => { sample.network.totalEncodedBytes = value; }, + ); + const head = withMetricSamples( + await loadBrowserReport('head'), + [1_005_000, 1_005_000, 1_005_000], + (sample, value) => { sample.network.totalEncodedBytes = value; }, + ); + + const markdown = await renderReport(null, { base, head }); + + expect(markdown).not.toContain('| **Encoded network** |'); +}); + +test('renders a directional encoded byte delta at the absolute threshold', async () => { + const base = withMetricSamples( + await loadBrowserReport('base'), + [1_000_000, 1_000_000, 1_000_000], + (sample, value) => { sample.network.totalEncodedBytes = value; }, + ); + const head = withMetricSamples( + await loadBrowserReport('head'), + [1_010_000, 1_010_000, 1_010_000], + (sample, value) => { sample.network.totalEncodedBytes = value; }, + ); + + const row = requireMetricRow(await renderReport(null, { base, head }), 'Encoded network'); + + expect(row).toContain('$\\color{orange}{\\text{+10 KB}}$'); +}); + +test('colours absolute and relative deltas together when the row is significant', async () => { + const base = withMetricSamples( + await loadBrowserReport('base'), + [100_000_000, 100_000_000, 100_000_000], + (sample, value) => { sample.network.totalEncodedBytes = value; }, + ); + const head = withMetricSamples( + await loadBrowserReport('head'), + [100_020_000, 100_020_000, 100_020_000], + (sample, value) => { sample.network.totalEncodedBytes = value; }, + ); + + const row = requireMetricRow(await renderReport(null, { base, head }), 'Encoded network'); + + expect(row).toContain('100 MB
    ± 0 B'); + expect(row).toContain('$\\color{orange}{\\text{+20 KB}}$
    $\\color{orange}{\\text{+0\\\\%}}$'); + expect(row).toContain('| 0 B |'); + expect(row.split('|')).toHaveLength(7); +}); + +test('renders an unavailable relative delta when the base median is zero', async () => { + const base = withMetricSamples( + await loadBrowserReport('base'), + [0, 0, 0], + (sample, value) => { sample.network.requestCount = value; }, + ); + const head = withMetricSamples( + await loadBrowserReport('head'), + [2, 2, 2], + (sample, value) => { sample.network.requestCount = value; }, + ); + + const row = requireMetricRow(await renderReport(null, { base, head }), 'Requests'); + + expect(row).toContain('$\\color{orange}{\\text{+2}}$
    -'); + expect(row).not.toContain('increase'); +}); + +test('throws for a metric with fewer than two samples on one side', async () => { + const base = withMetricSamples( + await loadBrowserReport('base'), + [100], + (sample, value) => { sample.network.requestCount = value; }, + ); + const head = withMetricSamples( + await loadBrowserReport('head'), + [102, 102], + (sample, value) => { sample.network.requestCount = value; }, + ); + + await expect(renderReport(null, { base, head })) + .rejects.toThrow('At least two samples per side are required'); +}); diff --git a/packages-private/diagnostics-shared/package.json b/packages-private/diagnostics-shared/package.json index 1fd0a146820..7a0268b2dff 100644 --- a/packages-private/diagnostics-shared/package.json +++ b/packages-private/diagnostics-shared/package.json @@ -7,6 +7,7 @@ "./format": "./src/format.ts", "./html": "./src/html.ts", "./stats": "./src/stats.ts", + "./metric-table": "./src/metric-table.ts", "./heap-snapshot": "./src/heap-snapshot/index.ts" }, "scripts": { diff --git a/packages-private/diagnostics-shared/src/heap-snapshot/render.ts b/packages-private/diagnostics-shared/src/heap-snapshot/render.ts index 7690c834c5a..1f8631ff8b0 100644 --- a/packages-private/diagnostics-shared/src/heap-snapshot/render.ts +++ b/packages-private/diagnostics-shared/src/heap-snapshot/render.ts @@ -3,13 +3,8 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { - formatBytes, - formatDeltaBytes, - formatDeltaPercentInMdTable, - formatPercent, -} from '../format'; -import { mad, pairedDeltaSummary } from '../stats'; +import { formatBytes } from '../format'; +import { renderMetricComparisonTable } from '../metric-table'; import { heapSnapshotCategories, heapSnapshotCategory, @@ -24,15 +19,6 @@ function categoryValue(report: HeapSnapshotReport, category: HeapSnapshotCategor return report.summary.categories[category]; } -function categorySampleSpread(report: HeapSnapshotReport, category: HeapSnapshotCategory) { - const values = report.samples - .map(sample => sample.data.categories[category]) - .filter(value => Number.isFinite(value)); - if (values.length < 2) throw new Error(`Not enough samples for category ${category}`); - - return mad(values); -} - function swatch(category: HeapSnapshotCategory) { return `$\\color{${heapSnapshotCategory[category].color}}{\\rule{8pt}{8pt}}$ **${heapSnapshotCategory[category].label}**`; } @@ -41,38 +27,19 @@ function swatch(category: HeapSnapshotCategory) { * base / head �heap snapshotをカテゴリ別�比較�るMarkdownテーブルを�画�る。 */ export function renderHeapSnapshotTable(base: HeapSnapshotReport, head: HeapSnapshotReport) { - const lines = [ - '| Metric | Base | Head | Δ median | Δ MAD | Δ min | Δ max |', - '| --- | ---: | ---: | ---: | ---: | ---: | ---: |', - ]; - const baseTotal = categoryValue(base, 'total'); - const headTotal = categoryValue(head, 'total'); - - for (const category of heapSnapshotCategories) { - const baseValue = categoryValue(base, category); - const headValue = categoryValue(head, category); - const summary = pairedDeltaSummary(base.samples, head.samples, sample => sample.data.categories[category]); - const deltaColumns = `${formatBytes(summary.mad)} | ${formatDeltaBytes(summary.min, byteColorThreshold)} | ${formatDeltaBytes(summary.max, byteColorThreshold)}`; - - if (category === 'total') { - // Total����ら���変化率も併記�る - const percent = summary.median * 100 / baseValue; - const deltaMedian = `${formatDeltaBytes(summary.median, byteColorThreshold)}
    ${formatDeltaPercentInMdTable(percent, 0.1)}`; - const baseText = `${formatBytes(baseValue)}
    ± ${formatBytes(categorySampleSpread(base, category))}`; - const headText = `${formatBytes(headValue)}
    ± ${formatBytes(categorySampleSpread(head, category))}`; - lines.push(`| ${swatch(category)} | ${baseText} | ${headText} | ${deltaMedian} | ${deltaColumns} |`); - lines.push('| | | | | | | |'); - } else { - // �カテゴリ�Total���る割��推移をdetails�見�る - const basePercent = formatPercent((baseValue * 100) / baseTotal); - const headPercent = formatPercent((headValue * 100) / headTotal); - const metricText = `
    ${swatch(category)}${basePercent} → ${headPercent}
    `; - lines.push(`| ${metricText} | ${formatBytes(baseValue)} | ${formatBytes(headValue)} | ${formatDeltaBytes(summary.median, byteColorThreshold)} | ${deltaColumns} |`); - } - } - - if (lines.length === 2) return null; - return lines.join('\n'); + return renderMetricComparisonTable( + base.samples, + head.samples, + heapSnapshotCategories.map(category => ({ + label: swatch(category), + getValue: sample => sample.data.categories[category], + formatValue: formatBytes, + absoluteThreshold: byteColorThreshold, + showMedianMad: category === 'total', + showDeltaPercentage: category === 'total', + separatorAfter: category === 'total', + })), + ); } const sankeyChildMinRatio = 0.3; diff --git a/packages-private/diagnostics-shared/src/metric-table.ts b/packages-private/diagnostics-shared/src/metric-table.ts new file mode 100644 index 00000000000..62f57aa4836 --- /dev/null +++ b/packages-private/diagnostics-shared/src/metric-table.ts @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { formatColoredDelta, formatDeltaPercentInMdTable } from './format'; +import { + independentDeltaSummary, + isOutsideObservedNoise, + type IndependentDeltaSummary, +} from './stats'; + +export type MetricComparisonRow = { + label: string; + getValue: (sample: T) => number; + formatValue: (value: number) => string; + absoluteThreshold: number; + showMedianMad?: boolean; + showDeltaPercentage?: boolean; + separatorAfter?: boolean; +}; + +export type MetricComparisonTableOptions = { + onlySignificantChanges?: boolean; +}; + +function isSignificant(summary: IndependentDeltaSummary, absoluteThreshold: number) { + return isOutsideObservedNoise(summary) && Math.abs(summary.delta) >= absoluteThreshold; +} + +function formatMedian( + value: number, + spread: number, + row: MetricComparisonRow, +) { + const formatted = row.formatValue(value); + if (row.showMedianMad === false) return formatted; + return `${formatted}
    ± ${row.formatValue(spread)}`; +} + +function formatDelta( + summary: IndependentDeltaSummary, + row: MetricComparisonRow, + significant: boolean, +) { + const colorThreshold = significant ? 0 : Number.POSITIVE_INFINITY; + const absolute = formatColoredDelta(summary.delta, row.formatValue, colorThreshold); + if (row.showDeltaPercentage === false) return absolute; + + const percentage = summary.baseMedian === 0 + ? '-' + : formatDeltaPercentInMdTable(summary.delta * 100 / summary.baseMedian, colorThreshold); + return `${absolute}
    ${percentage}`; +} + +export function renderMetricComparisonTable( + baseSamples: T[], + headSamples: T[], + rows: MetricComparisonRow[], + options: MetricComparisonTableOptions = {}, +): string { + const lines: string[] = []; + + for (const row of rows) { + const summary = independentDeltaSummary(baseSamples, headSamples, row.getValue); + const significant = isSignificant(summary, row.absoluteThreshold); + if (options.onlySignificantChanges === true && !significant) continue; + + lines.push(`| ${row.label} | ${formatMedian(summary.baseMedian, summary.baseMad, row)} | ${formatMedian(summary.headMedian, summary.headMad, row)} | ${formatDelta(summary, row, significant)} | ${row.formatValue(summary.combinedMad)} |`); + if (row.separatorAfter === true) lines.push('| | | | | |'); + } + + if (lines.length === 0) return '**(No data)**'; + + return [ + '| Metric | @ Base | @ Head | Δ | MAD |', + '| --- | ---: | ---: | ---: | ---: |', + ...lines, + ].join('\n'); +} diff --git a/packages-private/diagnostics-shared/src/stats.ts b/packages-private/diagnostics-shared/src/stats.ts index 7516242c320..20fd7b13472 100644 --- a/packages-private/diagnostics-shared/src/stats.ts +++ b/packages-private/diagnostics-shared/src/stats.ts @@ -37,6 +37,49 @@ export function sampleSpread(values: (number | null | undefined)[]) { return mad(finiteValues); } +export type IndependentDeltaSummary = { + baseMedian: number; + headMedian: number; + delta: number; + baseMad: number; + headMad: number; + combinedMad: number; + baseSamples: number; + headSamples: number; +}; + +export function independentDeltaSummary( + baseSamples: T[], + headSamples: T[], + getValue: (sample: T) => number, +): IndependentDeltaSummary { + const baseValues = baseSamples.map(getValue); + const headValues = headSamples.map(getValue); + if (baseValues.length < 2 || headValues.length < 2) { + throw new Error('At least two samples per side are required'); + } + + const baseMedian = median(baseValues); + const headMedian = median(headValues); + const baseMad = mad(baseValues); + const headMad = mad(headValues); + + return { + baseMedian, + headMedian, + delta: headMedian - baseMedian, + baseMad, + headMad, + combinedMad: Math.hypot(baseMad, headMad), + baseSamples: baseValues.length, + headSamples: headValues.length, + }; +} + +export function isOutsideObservedNoise(summary: IndependentDeltaSummary) { + return Math.abs(summary.delta) > summary.combinedMad * 3; +} + type RoundedSample = { round: number }; function indexByRound(samples: T[]) { diff --git a/packages-private/diagnostics-shared/test/heap-snapshot-render.test.ts b/packages-private/diagnostics-shared/test/heap-snapshot-render.test.ts new file mode 100644 index 00000000000..ba56dbb6590 --- /dev/null +++ b/packages-private/diagnostics-shared/test/heap-snapshot-render.test.ts @@ -0,0 +1,103 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test } from 'vitest'; +import { + createEmptyHeapSnapshotData, + renderHeapSnapshotTable, + summarizeHeapSnapshotDataSamples, + type HeapSnapshotData, + type HeapSnapshotReport, +} from '../src/heap-snapshot'; + +function snapshot(total: number): HeapSnapshotData { + const data = createEmptyHeapSnapshotData(); + data.categories.total = total; + return data; +} + +function report(totals: number[]): HeapSnapshotReport { + const samples = totals.map((total, index) => ({ + round: index + 1, + data: snapshot(total), + })); + const summary = summarizeHeapSnapshotDataSamples(samples, sample => sample.data); + if (summary == null) throw new Error('expected heap snapshot samples to produce a summary'); + + return { + summary, + samples, + }; +} + +function totalRow(markdown: string) { + const row = markdown.split('\n').find(line => line.includes('**Total**')); + if (row === undefined) throw new Error('expected heap snapshot table to contain a Total row'); + return row; +} + +describe('renderHeapSnapshotTable', () => { + test('leaves a threshold-sized delta uncoloured when it is within observed noise', () => { + const row = totalRow(renderHeapSnapshotTable( + report([1_000_000, 1_100_000, 1_200_000]), + report([1_100_000, 1_200_000, 1_300_000]), + )); + + expect(row).toContain('$\\text{+100 KB}$'); + expect(row).not.toContain('within noise'); + expect(row).not.toContain('\\color{orange}'); + }); + + test('colours both delta lines for a clear increase at or above the absolute threshold', () => { + const row = totalRow(renderHeapSnapshotTable( + report([1_000_000, 1_000_000, 1_000_000]), + report([1_200_000, 1_200_000, 1_200_000]), + )); + + expect(row).toContain('$\\color{orange}{\\text{+200 KB}}$'); + expect(row).toContain('$\\color{orange}{\\text{+20\\\\%}}$'); + expect(row).not.toContain('increase'); + }); + + test('leaves both delta lines uncoloured below the absolute threshold', () => { + const row = totalRow(renderHeapSnapshotTable( + report([1_000_000, 1_000_000, 1_000_000]), + report([1_050_000, 1_050_000, 1_050_000]), + )); + + expect(row).toContain('$\\text{+50 KB}$
    $\\text{+5\\\\%}$'); + expect(row.split('|')[4]).not.toContain('\\color{'); + }); + + test('throws when only one snapshot per side reaches the renderer', () => { + expect(() => renderHeapSnapshotTable( + report([1_000_000]), + report([1_200_000]), + )).toThrow('At least two samples per side are required'); + }); + + test('uses two-line formatting only for Total and puts a five-column separator after it', () => { + const table = renderHeapSnapshotTable( + report([1_000_000, 1_000_000, 1_000_000]), + report([1_200_000, 1_200_000, 1_200_000]), + ); + const lines = table.split('\n'); + const totalIndex = lines.findIndex(line => line.includes('**Total**')); + const categoryRow = lines.find(line => line.includes('**Code**')); + + expect(lines.slice(0, 2)).toStrictEqual([ + '| Metric | @ Base | @ Head | Δ | MAD |', + '| --- | ---: | ---: | ---: | ---: |', + ]); + expect(table).not.toContain('Result'); + expect(totalIndex).toBeGreaterThan(1); + expect(lines[totalIndex].match(/
    /g)).toHaveLength(3); + expect(lines[totalIndex + 1]).toBe('| | | | | |'); + expect(categoryRow).toBeDefined(); + expect(categoryRow).not.toContain('
    '); + expect(categoryRow).not.toContain('
    '); + expect(categoryRow).not.toContain('→'); + }); +}); diff --git a/packages-private/diagnostics-shared/test/metric-table.test.ts b/packages-private/diagnostics-shared/test/metric-table.test.ts new file mode 100644 index 00000000000..fb638acf48e --- /dev/null +++ b/packages-private/diagnostics-shared/test/metric-table.test.ts @@ -0,0 +1,145 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { describe, expect, test } from 'vitest'; +import { + renderMetricComparisonTable, + type MetricComparisonRow, +} from '../src/metric-table'; + +type Sample = { value: number }; + +const defaultRow: MetricComparisonRow = { + label: 'Metric', + getValue: sample => sample.value, + formatValue: value => `${value} units`, + absoluteThreshold: 10, +}; + +function samples(...values: number[]): Sample[] { + return values.map(value => ({ value })); +} + +describe('renderMetricComparisonTable', () => { + test('renders the fixed five-column layout, raw label, MAD, and percentage by default', () => { + const table = renderMetricComparisonTable( + samples(100, 100, 100), + samples(120, 120, 120), + [defaultRow], + ); + + expect(table.split('\n')).toStrictEqual([ + '| Metric | @ Base | @ Head | Δ | MAD |', + '| --- | ---: | ---: | ---: | ---: |', + '| Metric | 100 units
    ± 0 units | 120 units
    ± 0 units | $\\color{orange}{\\text{+20 units}}$
    $\\color{orange}{\\text{+20\\\\%}}$ | 0 units |', + ]); + }); + + test('can hide second lines and insert a five-column separator row', () => { + const table = renderMetricComparisonTable( + samples(100, 100, 100), + samples(120, 120, 120), + [{ + ...defaultRow, + showMedianMad: false, + showDeltaPercentage: false, + separatorAfter: true, + }], + ); + + expect(table.split('\n')).toStrictEqual([ + '| Metric | @ Base | @ Head | Δ | MAD |', + '| --- | ---: | ---: | ---: | ---: |', + '| Metric | 100 units | 120 units | $\\color{orange}{\\text{+20 units}}$ | 0 units |', + '| | | | | |', + ]); + }); + + test('leaves both delta lines uncolored below the absolute threshold and can filter the row', () => { + const base = samples(100, 100, 100); + const head = samples(109, 109, 109); + const table = renderMetricComparisonTable(base, head, [defaultRow]); + + expect(table).toContain('$\\text{+9 units}$
    $\\text{+9\\\\%}$'); + expect(table).not.toContain('\\color{'); + expect(renderMetricComparisonTable(base, head, [defaultRow], { + onlySignificantChanges: true, + })).toBe('**(No data)**'); + }); + + test('renders a no-data marker when no rows are configured', () => { + expect(renderMetricComparisonTable( + samples(100, 100, 100), + samples(120, 120, 120), + [], + )).toBe('**(No data)**'); + }); + + test('treats the absolute threshold itself as significant', () => { + const table = renderMetricComparisonTable( + samples(100, 100, 100), + samples(110, 110, 110), + [defaultRow], + { onlySignificantChanges: true }, + ); + + expect(table).toContain('$\\color{orange}{\\text{+10 units}}$'); + expect(table).toContain('$\\color{orange}{\\text{+10\\\\%}}$'); + }); + + test('requires the delta to be strictly outside three combined MADs', () => { + const inside = renderMetricComparisonTable( + samples(100, 110, 120), + samples(109, 119, 129), + [{ ...defaultRow, absoluteThreshold: 1 }], + ); + const boundary = renderMetricComparisonTable( + samples(100, 100, 100), + samples(120, 130, 140), + [defaultRow], + ); + const outside = renderMetricComparisonTable( + samples(100, 100, 100), + samples(121, 131, 141), + [defaultRow], + ); + + expect(inside).toContain('$\\text{+9 units}$'); + expect(inside).not.toContain('\\color{'); + expect(boundary).toContain('$\\text{+30 units}$'); + expect(boundary).not.toContain('\\color{'); + expect(outside).toContain('$\\color{orange}{\\text{+31 units}}$'); + expect(outside).toContain('$\\color{orange}{\\text{+31\\\\%}}$'); + }); + + test('colours a significant decrease green on both delta lines', () => { + const table = renderMetricComparisonTable( + samples(120, 120, 120), + samples(100, 100, 100), + [defaultRow], + ); + + expect(table).toContain('$\\color{green}{\\text{-20 units}}$'); + expect(table).toContain('$\\color{green}{\\text{-16.7\\\\%}}$'); + }); + + test('shows a dash for percentage when the base median is zero', () => { + const table = renderMetricComparisonTable( + samples(0, 0, 0), + samples(20, 20, 20), + [defaultRow], + ); + + expect(table).toContain('$\\color{orange}{\\text{+20 units}}$
    -'); + }); + + test('propagates the minimum sample contract', () => { + expect(() => renderMetricComparisonTable( + samples(100), + samples(120, 120), + [defaultRow], + )).toThrow('At least two samples per side are required'); + }); +}); diff --git a/packages-private/diagnostics-shared/test/stats.test.ts b/packages-private/diagnostics-shared/test/stats.test.ts index 1d57f0d67d4..22da6a65317 100644 --- a/packages-private/diagnostics-shared/test/stats.test.ts +++ b/packages-private/diagnostics-shared/test/stats.test.ts @@ -4,7 +4,16 @@ */ import { describe, expect, test } from 'vitest'; -import { finiteMedian, mad, median, pairedDeltaSummary, sampleSpread } from '../src/stats'; +import { + finiteMedian, + independentDeltaSummary, + isOutsideObservedNoise, + mad, + median, + pairedDeltaSummary, + sampleSpread, + type IndependentDeltaSummary, +} from '../src/stats'; describe('median', () => { test('takes the middle value of an odd-length sample', () => { @@ -107,3 +116,79 @@ describe('pairedDeltaSummary', () => { expect(pairedDeltaSummary(warmupBase, warmupHead, sample => sample.value).samples).toBe(3); }); }); + +describe('independentDeltaSummary', () => { + const base = [290_000, 292_900, 295_800, 298_700, 301_600] + .map((value, index) => ({ round: index + 1, value })); + const head = [292_900, 296_300, 298_700, 301_600, 290_000] + .map((value, index) => ({ round: index + 1, value })); + + test('uses the difference of independent medians instead of the paired median', () => { + expect(pairedDeltaSummary(base, head, sample => sample.value).median).toBe(2_900); + + const summary = independentDeltaSummary(base, head, sample => sample.value); + expect(summary).toMatchObject({ + baseMedian: 295_800, + headMedian: 296_300, + delta: 500, + baseMad: 2_900, + headMad: 3_400, + baseSamples: 5, + headSamples: 5, + }); + expect(summary.combinedMad).toBeCloseTo(Math.hypot(2_900, 3_400)); + }); + + test('allows unequal sample counts', () => { + const summary = independentDeltaSummary( + [{ value: 10 }, { value: 20 }], + [{ value: 20 }, { value: 30 }, { value: 40 }], + sample => sample.value, + ); + + expect(summary).toStrictEqual({ + baseMedian: 15, + headMedian: 30, + delta: 15, + baseMad: 5, + headMad: 10, + combinedMad: Math.hypot(5, 10), + baseSamples: 2, + headSamples: 3, + }); + }); + + test('throws when either side has fewer than two samples', () => { + expect(() => independentDeltaSummary( + [{ value: 10 }], + [{ value: 20 }, { value: 20 }], + sample => sample.value, + )).toThrow('At least two samples per side are required'); + + expect(() => independentDeltaSummary( + [{ value: 10 }, { value: 10 }], + [{ value: 20 }], + sample => sample.value, + )).toThrow('At least two samples per side are required'); + }); + + test('treats exactly three combined MADs as noise and only larger deltas as outside noise', () => { + function summary(delta: number, combinedMad: number): IndependentDeltaSummary { + return { + baseMedian: 100, + headMedian: 100 + delta, + delta, + baseMad: 0, + headMad: combinedMad, + combinedMad, + baseSamples: 3, + headSamples: 3, + }; + } + + expect(isOutsideObservedNoise(summary(29, 10))).toBe(false); + expect(isOutsideObservedNoise(summary(30, 10))).toBe(false); + expect(isOutsideObservedNoise(summary(31, 10))).toBe(true); + expect(isOutsideObservedNoise(summary(-31, 10))).toBe(true); + }); +}); From 5e3977973f6e9b16957eba2572c3cde2e7b52ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 22 Jul 2026 09:35:45 +0900 Subject: [PATCH 429/578] docs: update changelog (#17754) Update CHANGELOG.md --- CHANGELOG.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4787ea4efd6..d667cde4770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,15 +49,16 @@ - 全���信HTTPリクエスト - 全���信HTTPリクエスト - ジョブキュー(エンキュー元�トレースを�む) +- Feat: ログ基盤�刷新(部分的�導入中) + - API内部エラー�ログ�構造化属性�正�化��エラー情報を付与���証情報を自動的�秘匿�るよ��(従�形��表示�維�) + - ログ全体�既定出力レベル�ドメイン���出力レベルを設定��るよ�� + - �ックエンド�ログを1行JSON形��出力��るよ�� + - OpenTelemetry�Trace ContextをJSON形��ログ�関連付�られるよ�� - Enhance: Sentry �ックエンド�自動計装を `sentryForBackend.disabledIntegrations` �個別�無効化��るよ�� - Enhance: センシティブメディア�判定を外部サービス ([sensitive-detector](https://github.com/misskey-dev/sensitive-detector)) �分離��`nsfwjs` / `@tensorflow/tfjs(-node)` ��梱� NSFW 判定モデルを廃止 (#16804) - Enhance: Node.js 22.22.2以��24.17.0以��26.4.0以�をサ�ート�るよ�� - Enhance: Docker Image � Node.js を 26.4.0 ��Debian を trixie (v13) �更新 - Enhance: URLプレビュー��果を内部�キャッシュ�るよ�� -- Enhance: API内部エラー�ログ�構造化属性�正�化��エラー情報を付与���証情報を自動的�秘匿�るよ��(従�形��表示�維�) -- Enhance: ログ全体�既定level�logger domain���出力levelを設定��るよ�� -- Enhance: �ックエンド�ログを1行JSON形��出力��るよ�� -- Enhance: OpenTelemetry�Trace Contextを構造化ログ�関連付�られるよ�� - Fix: `/stats` API �レス�ンス型�正�����題を修正 - Fix: �ッシュタグ�関連�るデータを更新�る際�エラー�ンドリングを修正 - Fix: Sentry 使用環境下���Misskey �発行�� SQL クエリ� span ���れ���題を修正 From 4c3f40a87debff1e7ea81afbd731ec553935180c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:12:34 +0900 Subject: [PATCH 430/578] fix(deps): update dependency typeorm to v1.1.0 [security] (#17767) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/backend/package.json | 2 +- pnpm-lock.yaml | 29 +++++++++++++++++------------ pnpm-workspace.yaml | 2 ++ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index ef142fb158f..a13ce02e8ad 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -148,7 +148,7 @@ "tinycolor2": "1.6.0", "tmp": "0.2.7", "tsc-alias": "1.9.0", - "typeorm": "1.0.0", + "typeorm": "1.1.0", "ulid": "3.0.2", "vary": "1.1.2", "web-push": "3.6.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4c5db1eaea..a39081096a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -462,8 +462,8 @@ importers: specifier: 1.9.0 version: 1.9.0 typeorm: - specifier: 1.0.0 - version: 1.0.0(ioredis@5.11.1)(pg@8.22.0) + specifier: 1.1.0 + version: 1.1.0(ioredis@5.11.1)(pg@8.22.0) ulid: specifier: 3.0.2 version: 3.0.2 @@ -4566,8 +4566,8 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + ansis@4.3.1: + resolution: {integrity: sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==} engines: {node: '>=14'} append-field@1.0.0: @@ -5212,6 +5212,9 @@ packages: dayjs@1.11.20: resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + dayjs@1.11.21: + resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -8856,8 +8859,8 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typeorm@1.0.0: - resolution: {integrity: sha512-2mSKNqucP8vo+xQLP59xlHUcqLvG6qajxA7q7tnhJgeZjTrA6lK/Ar7LRyiAxdXhyXmGbIPsArPmcUB9Xg+M7w==} + typeorm@1.1.0: + resolution: {integrity: sha512-iX/kvsV42/htCNAQUyElGW87E4Z12neZc6YUFBTEu0BnLiREYDNT5Wfw3wRqZw9vyOEC36zUBAY6Qvywoig06Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=24.11.0} hasBin: true peerDependencies: @@ -8868,11 +8871,11 @@ packages: mongodb: ^7.0.0 mssql: ^12.0.0 mysql2: ^3.15.3 - oracledb: ^6.3.0 + oracledb: ^6.3.0 || ^7.0.0 pg: ^8.5.1 pg-native: ^3.0.0 pg-query-stream: ^4.0.0 - redis: ^5.0.0 + redis: ^5.0.0 || ^6.0.0 sql.js: ^1.4.0 ts-node: ^10.9.2 typeorm-aurora-data-api-driver: ^3.0.0 @@ -12817,7 +12820,7 @@ snapshots: ansi-styles@6.2.3: {} - ansis@4.2.0: {} + ansis@4.3.1: {} append-field@1.0.0: {} @@ -13470,6 +13473,8 @@ snapshots: dayjs@1.11.20: {} + dayjs@1.11.21: {} + debug@2.6.9: dependencies: ms: 2.0.0 @@ -17816,11 +17821,11 @@ snapshots: typedarray@0.0.6: {} - typeorm@1.0.0(ioredis@5.11.1)(pg@8.22.0): + typeorm@1.1.0(ioredis@5.11.1)(pg@8.22.0): dependencies: '@sqltools/formatter': 1.2.5 - ansis: 4.2.0 - dayjs: 1.11.20 + ansis: 4.3.1 + dayjs: 1.11.21 debug: 4.4.3 dedent: 1.7.2 reflect-metadata: 0.2.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c280df00f27..4d3caf525ae 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -56,6 +56,8 @@ minimumReleaseAgeExclude: - vite # ����消� # Renovate security update: @opentelemetry/core@2.8.0 - "@opentelemetry/core@2.8.0" + # Renovate security update: typeorm@1.1.0 + - typeorm@1.1.0 overrides: '@aiscript-dev/aiscript-languageserver': '-' 'bullmq>ioredis': 5.11.1 From 7725110e1c8fab9ba0b7011c16dc435e39e2a3ab Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:15:19 +0900 Subject: [PATCH 431/578] chore(gh): tweak workflow --- .../src/report/markdown.ts | 2 +- .../test/__snapshots__/render-md.md | 4 +- .../diagnostics-frontend/src/report.ts | 214 ++++++++---------- .../test/__snapshots__/report.md | 2 +- .../diagnostics-shared/src/metric-table.ts | 9 +- .../test/metric-table.test.ts | 4 +- 6 files changed, 109 insertions(+), 126 deletions(-) diff --git a/packages-private/diagnostics-backend/src/report/markdown.ts b/packages-private/diagnostics-backend/src/report/markdown.ts index 0fe16bf62f4..cf4acefae59 100644 --- a/packages-private/diagnostics-backend/src/report/markdown.ts +++ b/packages-private/diagnostics-backend/src/report/markdown.ts @@ -70,6 +70,7 @@ function renderMainTableForPhase(base: MemoryReport, head: MemoryReport, phase: formatValue: formatKiBAsMb, absoluteThreshold: memoryColorThresholdKiB, })), + { onlySignificantChanges: true }, ); } @@ -138,7 +139,6 @@ export function renderMemoryReportMarkdown(base: MemoryReport, head: MemoryRepor lines.push(''); } - lines.push(`_Values are median ± MAD (${base.samples.length} base / ${head.samples.length} head samples). Delta is Head - Base. Deltas are highlighted when their absolute value reaches the metric threshold and exceeds 3 × MAD._`); lines.push(''); const nonConvergedSamples = countNonConvergedMemorySamples(base, head); diff --git a/packages-private/diagnostics-backend/test/__snapshots__/render-md.md b/packages-private/diagnostics-backend/test/__snapshots__/render-md.md index 683e25b6a75..890eb2ba92c 100644 --- a/packages-private/diagnostics-backend/test/__snapshots__/render-md.md +++ b/packages-private/diagnostics-backend/test/__snapshots__/render-md.md @@ -6,9 +6,9 @@ | **HeapUsed** | 152 MB
    ± 1 MB | 168 MB
    ± 1 MB | $\color{orange}{\text{+16 MB}}$
    $\color{orange}{\text{+10.5\\%}}$ | 1.4 MB | | **PSS** | 202 MB
    ± 1 MB | 218 MB
    ± 1 MB | $\color{orange}{\text{+16 MB}}$
    $\color{orange}{\text{+7.9\\%}}$ | 1.4 MB | | **USS** | 184 MB
    ± 1 MB | 200 MB
    ± 1 MB | $\color{orange}{\text{+16 MB}}$
    $\color{orange}{\text{+8.7\\%}}$ | 1.4 MB | -| **External** | 8.2 MB
    ± 0.1 MB | 8.2 MB
    ± 0.1 MB | 0 MB
    0% | 0.1 MB | -_Values are median ± MAD (3 base / 3 head samples). Delta is Head - Base. Deltas are highlighted when their absolute value reaches the metric threshold and exceeds 3 × MAD._ +Only metrics showing significant changes are displayed. + ### V8 Heap Snapshot Statistics diff --git a/packages-private/diagnostics-frontend/src/report.ts b/packages-private/diagnostics-frontend/src/report.ts index ab85c625f8d..c61985f4054 100644 --- a/packages-private/diagnostics-frontend/src/report.ts +++ b/packages-private/diagnostics-frontend/src/report.ts @@ -37,122 +37,102 @@ function renderBrowserSummaryTable(base: BrowserMetricsReport, head: BrowserMetr return renderMetricComparisonTable( base.samples, head.samples, - [ - { - label: '**Requests**', - getValue: sample => sample.network.requestCount, - formatValue: formatNumber, - absoluteThreshold: 1, - }, - { - label: '**Encoded network**', - getValue: sample => sample.network.totalEncodedBytes, - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**Decoded body**', - getValue: sample => sample.network.totalDecodedBodyBytes, - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**Same-origin encoded**', - getValue: sample => sample.network.sameOriginEncodedBytes, - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**Third-party encoded**', - getValue: sample => sample.network.thirdPartyEncodedBytes, - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**Script encoded**', - getValue: sample => resourceTypeSampleBytes(sample, ['Script']), - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**Stylesheet encoded**', - getValue: sample => resourceTypeSampleBytes(sample, ['Stylesheet']), - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**Fetch/XHR encoded**', - getValue: sample => resourceTypeSampleBytes(sample, ['Fetch', 'XHR']), - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**Image encoded**', - getValue: sample => resourceTypeSampleBytes(sample, ['Image']), - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**Font encoded**', - getValue: sample => resourceTypeSampleBytes(sample, ['Font']), - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**WebSocket connections**', - getValue: sample => sample.network.webSocketConnectionCount, - formatValue: formatNumber, - absoluteThreshold: 1, - }, - { - label: '**WebSocket sent**', - getValue: sample => sample.network.webSocketSentBytes, - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**WebSocket received**', - getValue: sample => sample.network.webSocketReceivedBytes, - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - { - label: '**Page errors**', - getValue: sample => sample.diagnostics.pageErrorCount, - formatValue: formatNumber, - absoluteThreshold: 1, - }, - { - label: '**Console log**', - getValue: sample => sample.diagnostics.console.log, - formatValue: formatNumber, - absoluteThreshold: 1, - }, - { - label: '**Console warnings**', - getValue: sample => sample.diagnostics.console.warning, - formatValue: formatNumber, - absoluteThreshold: 1, - }, - { - label: '**Console errors**', - getValue: sample => sample.diagnostics.console.error, - formatValue: formatNumber, - absoluteThreshold: 1, - }, - { - label: '**Console info**', - getValue: sample => sample.diagnostics.console.info, - formatValue: formatNumber, - absoluteThreshold: 1, - }, - { - label: '**Page-attributed memory**', - getValue: sample => sample.performance.tabMemory.totalBytes, - formatValue: formatBytes, - absoluteThreshold: 10_000, - }, - ], + [{ + label: '**Requests**', + getValue: sample => sample.network.requestCount, + formatValue: formatNumber, + absoluteThreshold: 1, + }, { + label: '**Encoded network**', + getValue: sample => sample.network.totalEncodedBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**Decoded body**', + getValue: sample => sample.network.totalDecodedBodyBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**Same-origin encoded**', + getValue: sample => sample.network.sameOriginEncodedBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**Third-party encoded**', + getValue: sample => sample.network.thirdPartyEncodedBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**Script encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Script']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**Stylesheet encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Stylesheet']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**Fetch/XHR encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Fetch', 'XHR']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**Image encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Image']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**Font encoded**', + getValue: sample => resourceTypeSampleBytes(sample, ['Font']), + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**WebSocket connections**', + getValue: sample => sample.network.webSocketConnectionCount, + formatValue: formatNumber, + absoluteThreshold: 1, + }, { + label: '**WebSocket sent**', + getValue: sample => sample.network.webSocketSentBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**WebSocket received**', + getValue: sample => sample.network.webSocketReceivedBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }, { + label: '**Page errors**', + getValue: sample => sample.diagnostics.pageErrorCount, + formatValue: formatNumber, + absoluteThreshold: 1, + }, { + label: '**Console log**', + getValue: sample => sample.diagnostics.console.log, + formatValue: formatNumber, + absoluteThreshold: 1, + }, { + label: '**Console warnings**', + getValue: sample => sample.diagnostics.console.warning, + formatValue: formatNumber, + absoluteThreshold: 1, + }, { + label: '**Console errors**', + getValue: sample => sample.diagnostics.console.error, + formatValue: formatNumber, + absoluteThreshold: 1, + }, { + label: '**Console info**', + getValue: sample => sample.diagnostics.console.info, + formatValue: formatNumber, + absoluteThreshold: 1, + }, { + label: '**Page-attributed memory**', + getValue: sample => sample.performance.tabMemory.totalBytes, + formatValue: formatBytes, + absoluteThreshold: 10_000, + }], { onlySignificantChanges: true }, ); } @@ -224,8 +204,6 @@ export function renderFrontendDiagnosticsMarkdown(input: FrontendDiagnosticsMark '', renderBrowserSummaryTable(browser.base, browser.head), '', - 'Only metrics showing significant changes are displayed.', - '', detailedHtmlUrl == null || detailedHtmlUrl === '' ? null : `[View details](${detailedHtmlUrl})`, detailedHtmlUrl == null || detailedHtmlUrl === '' ? null : '', '
    ', diff --git a/packages-private/diagnostics-frontend/test/__snapshots__/report.md b/packages-private/diagnostics-frontend/test/__snapshots__/report.md index 144ff183055..922c3608074 100644 --- a/packages-private/diagnostics-frontend/test/__snapshots__/report.md +++ b/packages-private/diagnostics-frontend/test/__snapshots__/report.md @@ -8,7 +8,7 @@ | **Script encoded** | 918 KB
    ± 9 KB | 991 KB
    ± 9.7 KB | $\color{orange}{\text{+73 KB}}$
    $\color{orange}{\text{+8\\%}}$ | 13 KB | | **Page-attributed memory** | 92 MB
    ± 900 KB | 99 MB
    ± 972 KB | $\color{orange}{\text{+7.3 MB}}$
    $\color{orange}{\text{+8\\%}}$ | 1.3 MB | -Only metrics showing significant changes are displayed. +Only metrics showing significant changes are displayed. [View details](https://example.invalid/html) diff --git a/packages-private/diagnostics-shared/src/metric-table.ts b/packages-private/diagnostics-shared/src/metric-table.ts index 62f57aa4836..00008fb61d7 100644 --- a/packages-private/diagnostics-shared/src/metric-table.ts +++ b/packages-private/diagnostics-shared/src/metric-table.ts @@ -60,21 +60,26 @@ export function renderMetricComparisonTable( options: MetricComparisonTableOptions = {}, ): string { const lines: string[] = []; + let omitted = false; for (const row of rows) { const summary = independentDeltaSummary(baseSamples, headSamples, row.getValue); const significant = isSignificant(summary, row.absoluteThreshold); - if (options.onlySignificantChanges === true && !significant) continue; + if (options.onlySignificantChanges === true && !significant) { + omitted = true; + continue; + } lines.push(`| ${row.label} | ${formatMedian(summary.baseMedian, summary.baseMad, row)} | ${formatMedian(summary.headMedian, summary.headMad, row)} | ${formatDelta(summary, row, significant)} | ${row.formatValue(summary.combinedMad)} |`); if (row.separatorAfter === true) lines.push('| | | | | |'); } - if (lines.length === 0) return '**(No data)**'; + if (lines.length === 0) return '**(No significant changes)**'; return [ '| Metric | @ Base | @ Head | Δ | MAD |', '| --- | ---: | ---: | ---: | ---: |', ...lines, + ...(omitted ? ['', 'Only metrics showing significant changes are displayed.'] : []), ].join('\n'); } diff --git a/packages-private/diagnostics-shared/test/metric-table.test.ts b/packages-private/diagnostics-shared/test/metric-table.test.ts index fb638acf48e..f1dcafb092f 100644 --- a/packages-private/diagnostics-shared/test/metric-table.test.ts +++ b/packages-private/diagnostics-shared/test/metric-table.test.ts @@ -66,7 +66,7 @@ describe('renderMetricComparisonTable', () => { expect(table).not.toContain('\\color{'); expect(renderMetricComparisonTable(base, head, [defaultRow], { onlySignificantChanges: true, - })).toBe('**(No data)**'); + })).toBe('**(No significant changes)**'); }); test('renders a no-data marker when no rows are configured', () => { @@ -74,7 +74,7 @@ describe('renderMetricComparisonTable', () => { samples(100, 100, 100), samples(120, 120, 120), [], - )).toBe('**(No data)**'); + )).toBe('**(No significant changes)**'); }); test('treats the absolute threshold itself as significant', () => { From 2d2aa779ad01899b8e8a55c74799f3ab0dfda1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:16:15 +0900 Subject: [PATCH 432/578] =?UTF-8?q?fix(frontend):=20=E3=83=81=E3=83=A3?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=82=B3=E3=83=B3=E3=83=9D=E3=83=BC=E3=83=8D?= =?UTF-8?q?=E3=83=B3=E3=83=88=E3=81=AE=E3=83=9E=E3=82=A6=E3=83=B3=E3=83=88?= =?UTF-8?q?=E8=A7=A3=E9=99=A4=E6=99=82=E3=81=ABChart=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E3=82=B9=E3=82=BF=E3=83=B3=E3=82=B9=E3=81=8C=E7=A0=B4=E6=A3=84?= =?UTF-8?q?=E3=81=95=E3=82=8C=E3=81=A6=E3=81=84=E3=81=AA=E3=81=84=E5=95=8F?= =?UTF-8?q?=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#17763)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(frontend): Chart�マウント解除時�Chartインスタンス�破棄�れ�����題を修正 * Update Changelog * fix --- CHANGELOG.md | 1 + packages/frontend/src/components/MkChart.vue | 5 ++++- .../frontend/src/components/MkHeatmap.vue | 8 ++++++-- .../src/components/MkInstanceStats.vue | 19 ++++++++++++++++--- .../src/components/MkRetentionHeatmap.vue | 8 ++++++-- .../src/components/MkRetentionLineChart.vue | 6 +++++- .../MkVisitorDashboard.ActiveUsersChart.vue | 8 ++++++-- .../federation-job-queue.chart.chart.vue | 6 +++++- .../src/pages/admin/job-queue.chart.vue | 6 +++++- .../src/pages/admin/overview.active-users.vue | 12 ++++++++++-- .../src/pages/admin/overview.ap-requests.vue | 18 +++++++++++++++--- .../frontend/src/pages/admin/overview.pie.vue | 6 +++++- .../src/pages/admin/overview.queue.chart.vue | 6 +++++- .../src/pages/user/activity.following.vue | 12 ++++++++++-- .../src/pages/user/activity.notes.vue | 12 ++++++++++-- .../frontend/src/pages/user/activity.pv.vue | 12 ++++++++++-- 16 files changed, 119 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d667cde4770..edcf197752d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ - Fix: �����イベントリスナー�正��解除�れ���題を修正(メモリ使用��改善) - Fix: �ログイン時トップページをスクロール�作��������る�題を修正 - Fix: ローカルユーザー��ホスト付�メンション�本文���れる指�ノート�作�時�投稿フォーム���当該ユーザー�宛先���れ���も正���識�れ���題を修正 +- Fix: �ャート��画終了後�リソース�解放�れ���題を修正 - Fix: ドライブ�「��ファイル�らノートを作��やギャラリー�「ノート�共有��誕生日ウィジェット�ら�ノート作������通常投稿�下書��表示�れる�題を修正 ### Server diff --git a/packages/frontend/src/components/MkChart.vue b/packages/frontend/src/components/MkChart.vue index e418e729ca9..2d96cb7572a 100644 --- a/packages/frontend/src/components/MkChart.vue +++ b/packages/frontend/src/components/MkChart.vue @@ -46,7 +46,7 @@ export type ChartSrc = diff --git a/packages/frontend/src/utility/paginator.ts b/packages/frontend/src/utility/paginator.ts index bd2e8ff80da..45054acfd08 100644 --- a/packages/frontend/src/utility/paginator.ts +++ b/packages/frontend/src/utility/paginator.ts @@ -17,8 +17,6 @@ export type MisskeyEntity = { id: string; createdAt: string; _shouldInsertAd_?: boolean; - _shouldAnimateIn_?: boolean; - _shouldAnimateOut_?: boolean; }; type AbsEndpointType = { @@ -109,8 +107,6 @@ export class Paginator< private canFetchDetection: 'safe' | 'limit' | null = null; private aheadQueue: T[] = []; private useShallowRef: SRef; - private itemRemovalDelay: number | false; - private removalTimers = new Map(); // �列内��素を��よ��順��並�る� // newest: 新��も��先頭 (default) @@ -142,9 +138,6 @@ export class Paginator< useShallowRef?: SRef; - // アイテム削除時�アニメーションを待�時間 (ms) - itemRemovalDelay?: number | false; - canSearch?: boolean; searchParamName?: keyof E['req']; }) { @@ -167,7 +160,6 @@ export class Paginator< this.noPaging = props.noPaging ?? false; this.offsetMode = props.offsetMode ?? false; this.canSearch = props.canSearch ?? false; - this.itemRemovalDelay = props.itemRemovalDelay ?? false; this.searchParamName = props.searchParamName ?? 'search'; this.getNewestId = this.getNewestId.bind(this); @@ -199,7 +191,6 @@ export class Paginator< } public async init(): Promise { - this.clearRemovalTimers(); this.items.value = []; this.aheadQueue = []; this.queuedAheadItemsCount.value = 0; @@ -393,8 +384,6 @@ export class Paginator< public prepend(item: T): void { if (this.items.value.some(x => x.id === item.id)) return; - item._shouldAnimateIn_ = true; - item._shouldAnimateOut_ = false; this.items.value.unshift(item); this.trim(false); if (this.useShallowRef) triggerRef(this.items); @@ -410,10 +399,6 @@ export class Paginator< public releaseQueue(): void { if (this.aheadQueue.length === 0) return; // �れやら���余計�re-render�走る - for (const item of this.aheadQueue) { - item._shouldAnimateIn_ = false; // 一気�入る���挿入アニメーション���� - item._shouldAnimateOut_ = false; - } this.unshiftItems(this.aheadQueue); this.aheadQueue = []; this.queuedAheadItemsCount.value = 0; @@ -422,41 +407,11 @@ export class Paginator< public removeItem(id: string): void { // TODO: queue�らも消� - if (this.itemRemovalDelay === false) { - const index = this.items.value.findIndex(x => x.id === id); - if (index !== -1) { - this.items.value.splice(index, 1); - if (this.useShallowRef) triggerRef(this.items); - } - return; - } - const index = this.items.value.findIndex(x => x.id === id); if (index !== -1) { + this.items.value.splice(index, 1); if (this.useShallowRef) triggerRef(this.items); - - const item = this.items.value[index]!; - item._shouldAnimateOut_ = true; - if (this.useShallowRef) triggerRef(this.items); - - if (this.removalTimers.has(id)) return; - - this.removalTimers.set(id, window.setTimeout(() => { - this.removalTimers.delete(id); - const currentIndex = this.items.value.findIndex(x => x.id === id); - if (currentIndex !== -1) { - this.items.value.splice(currentIndex, 1); - if (this.useShallowRef) triggerRef(this.items); - } - }, this.itemRemovalDelay + 20)); // アニメーション終了�らやや余裕をも��る - } - } - - private clearRemovalTimers(): void { - for (const timer of this.removalTimers.values()) { - window.clearTimeout(timer); } - this.removalTimers.clear(); } public updateItem(id: string, updater: (item: T) => T): void { From 521f6006fe4b68336c195a3b56215c4423c29d74 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 24 Jul 2026 10:06:56 +0900 Subject: [PATCH 456/578] add note --- packages/frontend/src/preferences/manager.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/frontend/src/preferences/manager.ts b/packages/frontend/src/preferences/manager.ts index 9a2056271fa..05df4c70d97 100644 --- a/packages/frontend/src/preferences/manager.ts +++ b/packages/frontend/src/preferences/manager.ts @@ -548,6 +548,8 @@ export class PreferencesManager extends EventEmitter { public renameProfile(name: string) { this.profile.name = name; + // TODO: �ックアップ�キー���ベース��る��を考�る���=ID��る�ら�idも�生��る方�自然�も�れ�� + // (将�������IDをキー��るよ��������場����を変�����ックアップ�キー�変�ら�����������) this.save(); } From 16ca5a72a6904183f8c8412e6ab3070d80abce24 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 24 Jul 2026 11:26:05 +0900 Subject: [PATCH 457/578] New Crowdin updates (#17733) * New translations ja-jp.yml (Chinese Simplified) [ci skip] * New translations ja-jp.yml (English) [ci skip] * New translations ja-jp.yml (Korean) [ci skip] * New translations ja-jp.yml (Chinese Simplified) [ci skip] * New translations ja-jp.yml (Chinese Simplified) [ci skip] * New translations ja-jp.yml (Italian) [ci skip] * New translations ja-jp.yml (Italian) [ci skip] * New translations ja-jp.yml (Italian) [ci skip] * New translations ja-jp.yml (Catalan) [ci skip] * New translations ja-jp.yml (Chinese Simplified) [ci skip] * New translations ja-jp.yml (Spanish) [ci skip] --- locales/ca-ES.yml | 15 +++++++++++++++ locales/en-US.yml | 15 +++++++++++++++ locales/es-ES.yml | 15 +++++++++++++++ locales/it-IT.yml | 15 +++++++++++++++ locales/ko-KR.yml | 15 +++++++++++++++ locales/zh-CN.yml | 25 ++++++++++++++++++++----- 6 files changed, 95 insertions(+), 5 deletions(-) diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index ec49f966aa1..a4e5d21cb05 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -619,6 +619,8 @@ output: "Sortida" script: "Script" disablePagesScript: "Desactivar AiScript a les pàgines " updateRemoteUser: "Actualitzar la informació de l'usuari remot" +unsetMfa: "Desactiva l'autenticació de dos factors" +unsetMfaConfirm: "Voldries desactivar l'autenticació de dos factors?" unsetUserAvatar: "Desactiva l'avatar " unsetUserAvatarConfirm: "Segur que vols desactivar l'avatar?" unsetUserBanner: "Desactiva el bàner " @@ -1417,6 +1419,8 @@ addToEmojiPalette: "Afegeix al calaix d'emojis" emojiPaletteAlreadyAddedConfirm: "Aquest emoji ja està inclòs en aquest calaix d'emojis. Vols afegir-lo de nou?" append: "Afegeix al final" prepend: "Afegeix al principi" +urlPreviewSensitiveList: "Llista d'URLs per restringir la visualització de miniatures" +urlPreviewSensitiveListDescription: "Si separeu els termes amb un espai, s'interpretarà com una condició 'AND'; si els separeu amb un salt de línia, s'interpretarà com una condició 'OR'. Si envolupeu els termes amb barres obliqües, s'interpretarà com una expressió regular. Si es troba una coincidència, la miniatura ja no es mostrarà." _imageEditing: _vars: caption: "Títol de l'arxiu" @@ -2149,6 +2153,15 @@ _sensitiveMediaDetection: setSensitiveFlagAutomaticallyDescription: "Els resultats de la detecció interna seran desats, inclòs si aquesta opció es troba desactivada." analyzeVideos: "Activar anàlisis de vídeos " analyzeVideosDescription: "Analitzar els vídeos a més de les imatges. Això incrementarà lleugerament la càrrega del servidor." + externalServiceInfo: "La detecció de mitjans sensibles s'ha delegat a un servei extern (sensitive-detector). Per utilitzar aquesta funció, cal configurar un servei sidecar separat i establir els detalls de connexió que es detallen a continuació. Si no es configuren els detalls de connexió, no es durà a terme cap detecció (el contingut es tractarà com a no sensible)." + apiUrl: "URL per connectar-se al servei de verificació" + apiUrlDescription: "L'URL base del servei de detector de sensibilitat (per exemple, http://localhost:3009). Si us connecteu a un servei en una xarxa privada, afegiu la xarxa de destinació a la configuració `allowedPrivateNetworks` del fitxer de configuració. Si utilitzeu un proxy, configureu també `proxyBypassHosts`. Si es deixa en blanc, no es realitzaran comprovacions de sensibilitat." + apiKey: "Clau de l'API" + apiKeyDescription: "Introduïu això si l'autenticació (token Bearer) està configurada al costat del servei d'autenticació. Si no està configurada, deixeu aquest camp en blanc." + timeout: "Temps d'espera (mil·lisegons)" + timeoutDescription: "1 Aquesta és la durada del temps mort per sol·licitud de validació." + maxImagesPerRequest: "1 Nombre màxim d'imatges per sol·licitud" + maxImagesPerRequestDescription: "1 Quan s'analitzen múltiples fotogrames, com en un vídeo, aquest és el nombre màxim d'imatges que es poden enviar en una única petició. Qualsevol imatge que superi aquest límit es dividirà en parts i s'enviarà seqüencialment. Assegureu-vos que aquest ajust no superi el valor de `maxParts` al costat del `sensitive-detector` (per defecte: 10). Si es supera aquest límit, totes les imatges d'aquest lot es consideraran no sensibles." _emailUnavailable: used: "Aquest correu electrònic ja s'està fent servir" format: "El format del correu electrònic és invàlid " @@ -2461,6 +2474,7 @@ _permissions: "read:admin:show-moderation-log": "Veure registre de moderació " "read:admin:show-user": "Veure informació privada de l'usuari " "write:admin:suspend-user": "Suspendre usuari" + "write:admin:unset-mfa": "Desactiva l'autenticació de dos factors per a un usuari" "write:admin:unset-user-avatar": "Esborrar avatar d'usuari " "write:admin:unset-user-banner": "Esborrar bàner de l'usuari " "write:admin:unsuspend-user": "Treure la suspensió d'un usuari" @@ -2976,6 +2990,7 @@ _moderationLogTypes: createAvatarDecoration: "Decoració de l'avatar creada" updateAvatarDecoration: "S'ha actualitzat la decoració de l'avatar " deleteAvatarDecoration: "S'ha esborrat la decoració de l'avatar " + unsetMfa: "Desactiva l'autenticació de dos factors per a l'usuari" unsetUserAvatar: "Esborrar l'avatar d'aquest usuari" unsetUserBanner: "Esborrar el bàner d'aquest usuari" createSystemWebhook: "Crear un SystemWebhook" diff --git a/locales/en-US.yml b/locales/en-US.yml index e998937dfb8..813d7ccc9a7 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -619,6 +619,8 @@ output: "Output" script: "Script" disablePagesScript: "Disable AiScript on Pages" updateRemoteUser: "Update remote user information" +unsetMfa: "Reset two-factor authentication" +unsetMfaConfirm: "Are you sure you want to reset two-factor authentication?" unsetUserAvatar: "Unset avatar" unsetUserAvatarConfirm: "Are you sure you want to unset the avatar?" unsetUserBanner: "Unset banner" @@ -1417,6 +1419,8 @@ addToEmojiPalette: "Add to emoji palette" emojiPaletteAlreadyAddedConfirm: "This emoji is already included in this emoji palette. Do you want to add it again?" append: "Append to end" prepend: "Append to beginning" +urlPreviewSensitiveList: "URL to restrict thumbnail display" +urlPreviewSensitiveListDescription: "Use spaces to specify AND conditions, and line breaks to specify OR conditions. Enclose text in slashes to use regular expressions. If a match is found, the thumbnail will be hidden." _imageEditing: _vars: caption: "File caption" @@ -2149,6 +2153,15 @@ _sensitiveMediaDetection: setSensitiveFlagAutomaticallyDescription: "The results of the internal detection will be retained even if this option is turned off." analyzeVideos: "Enable analysis of videos" analyzeVideosDescription: "Analyzes videos in addition to images. This will slightly increase the load on the server." + externalServiceInfo: "The detection of sensitive media has been offloaded to an external service (sensitive-detector). To use this feature, you must set up a separate service and configure the connection details provided below. If no connection details are configured, no detection will be performed (it will be treated as non-sensitive)." + apiUrl: "Detection service endpoint URL" + apiUrlDescription: "The base URL for the sensitive-detector service (e.g., http://localhost:3009). If you are connecting to a service on a private network, please allow the target network in the allowedPrivateNetworks setting in the configuration file. If you are using a proxy, please also configure proxyBypassHosts. If left blank, sensitive media detection will not be performed." + apiKey: "API key" + apiKeyDescription: "Enter this if authentication (Bearer token) is configured on the detector service. If it is not configured, please leave it blank." + timeout: "Timeout (Milliseconds)" + timeoutDescription: "Timeout duration for each judgment request." + maxImagesPerRequest: "Max images per request" + maxImagesPerRequestDescription: "Maximum number of images that can be sent in a single request when processing multi-frame at once, such as videos. Any images exceeding this limit will be split and sent sequentially. Please ensure this is set to not exceed the maxParts setting (default: 10) on the detector service. If it exceeds this limit, all items in that chunk will be treated as non-sensitive." _emailUnavailable: used: "This email address is already being used" format: "The format of this email address is invalid" @@ -2461,6 +2474,7 @@ _permissions: "read:admin:show-moderation-log": "View moderation log" "read:admin:show-user": "View private user info" "write:admin:suspend-user": "Suspend user" + "write:admin:unset-mfa": "Reset two-factor authentication for the user" "write:admin:unset-user-avatar": "Remove user avatar" "write:admin:unset-user-banner": "Remove user banner" "write:admin:unsuspend-user": "Unsuspend user" @@ -2976,6 +2990,7 @@ _moderationLogTypes: createAvatarDecoration: "Avatar decoration created" updateAvatarDecoration: "Avatar decoration updated" deleteAvatarDecoration: "Avatar decoration deleted" + unsetMfa: "Reset two-factor authentication for the user" unsetUserAvatar: "User avatar unset" unsetUserBanner: "User banner unset" createSystemWebhook: "System Webhook created" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 6d0508f9896..4dee6532863 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -619,6 +619,8 @@ output: "Salida" script: "Script" disablePagesScript: "Deshabilitar AiScript en Páginas" updateRemoteUser: "Actualizar información de usuario remoto" +unsetMfa: "Desactivar la autenticación de dos factores" +unsetMfaConfirm: "¿Desea desactivar la autenticación de dos factores?" unsetUserAvatar: "Quitar avatar" unsetUserAvatarConfirm: "¿Confirmas que quieres quitar tu avatar?" unsetUserBanner: "Quitar banner" @@ -1417,6 +1419,8 @@ addToEmojiPalette: "Añadir a la paleta de emojis" emojiPaletteAlreadyAddedConfirm: "Este emoji ya está incluido en esta paleta de emojis. ¿Quieres volver a añadirlo?" append: "Añadir al final" prepend: "Añadir al principio" +urlPreviewSensitiveList: "URL para restringir la visualización de miniaturas" +urlPreviewSensitiveListDescription: "Si se separan con un espacio, se interpretará como una condición «AND»; si se separan con un salto de línea, se interpretará como una condición «OR». Si se escriben entre barras, se interpretarán como expresiones regulares. Si se encuentra una coincidencia, no se mostrará la miniatura." _imageEditing: _vars: caption: "Título del archivo" @@ -2149,6 +2153,15 @@ _sensitiveMediaDetection: setSensitiveFlagAutomaticallyDescription: "Los resultados de la detección interna pueden ser retenidos incluso si la opción está desactivada." analyzeVideos: "Habilitar el análisis de videos" analyzeVideosDescription: "Analizar videos en adición a las imágenes. Esto puede incrementar ligeramente la carga del servidor." + externalServiceInfo: "La detección de contenidos sensibles se ha externalizado a un servicio externo (sensitive-detector). Para utilizar esta función, es necesario configurar por separado un servicio «sidecar» y establecer los datos de conexión que se indican a continuación. Si no se configuran los datos de conexión, no se realizará la detección (se tratará como contenido no sensible)." + apiUrl: "URL de conexión al servicio de verificación" + apiUrlDescription: "URL base del servicio «sensitive-detector» (por ejemplo: http://localhost:3009). Si te conectas a un servicio situado en una red privada, debes permitir la red de destino en el parámetro «allowedPrivateNetworks» del archivo de configuración. Si utilizas un proxy, configura también el parámetro «proxyBypassHosts». Si se deja en blanco, no se realizará la evaluación de datos sensibles." + apiKey: "Clave API" + apiKeyDescription: "Introduce este dato si se ha configurado la autenticación (token Bearer) en el servicio de validación. Si no se ha configurado, déjalo en blanco." + timeout: "Tiempo de espera (milisegundos)" + timeoutDescription: "Duración del tiempo de espera para cada solicitud de resolución." + maxImagesPerRequest: "Número máximo de imágenes por solicitud" + maxImagesPerRequestDescription: "Es el número máximo de imágenes que se pueden enviar en una sola solicitud al analizar varios fotogramas, como en un vídeo. Las imágenes que superen este límite se dividirán y se enviarán de forma secuencial. Configúralo de manera que no se supere el valor de «maxParts» de sensitive-detector (por defecto: 10). Si se supera este límite, todas las imágenes de ese fragmento se considerarán no sensibles." _emailUnavailable: used: "Ya fue usado" format: "Formato no válido." @@ -2461,6 +2474,7 @@ _permissions: "read:admin:show-moderation-log": "Ver log de moderación" "read:admin:show-user": "Ver información privada de usuario" "write:admin:suspend-user": "Suspender cuentas de usuario" + "write:admin:unset-mfa": "Desactivar la autenticación de dos factores del usuario" "write:admin:unset-user-avatar": "Quitar avatares de usuario" "write:admin:unset-user-banner": "Quitar banner de usuarios" "write:admin:unsuspend-user": "Quitar suspensión de cuentas de usuario" @@ -2976,6 +2990,7 @@ _moderationLogTypes: createAvatarDecoration: "Decoración de avatar creada" updateAvatarDecoration: "Decoración de avatar actualizada" deleteAvatarDecoration: "Decoración de avatar eliminada" + unsetMfa: "Desactivar la autenticación de dos factores del usuario" unsetUserAvatar: "Quitar decoración de avatar de este usuario" unsetUserBanner: "Quitar banner de este usuario" createSystemWebhook: "Crear un SystemWebhook" diff --git a/locales/it-IT.yml b/locales/it-IT.yml index a7712ae5cae..564dd458cef 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -619,6 +619,8 @@ output: "Output" script: "Script" disablePagesScript: "Disabilitare AiScript nelle pagine" updateRemoteUser: "Aggiorna dati dal profilo remoto" +unsetMfa: "Rimuovere l'autenticazione a due fattori (2FA/MFA)" +unsetMfaConfirm: "Vuoi davvero rimuovere l'autenticazione a due fattori?" unsetUserAvatar: "Rimozione foto profilo" unsetUserAvatarConfirm: "Vuoi davvero rimuovere la foto profilo?" unsetUserBanner: "Rimuovi intestazione profilo" @@ -1417,6 +1419,8 @@ addToEmojiPalette: "Aggiungi alla tavolozza emoji" emojiPaletteAlreadyAddedConfirm: "Questa emoji è già inclusa in nella tavolozza. Vuoi davvero aggiungerla?" append: "Accodare" prepend: "Anteporre" +urlPreviewSensitiveList: "URL da impedire alla vista delle anteprime" +urlPreviewSensitiveListDescription: "Separando con uno spazio si indica E, separando con una linea si indica O. Circondando con barre / si indica una Espressione Regolare.\nLe URL che coincidono con le indicazioni non verranno visualizzate." _imageEditing: _vars: caption: "Didascalia dell'immagine" @@ -2149,6 +2153,15 @@ _sensitiveMediaDetection: setSensitiveFlagAutomaticallyDescription: "Anche se questa impostazione è disattivata, il risultato della decisione viene conservato internamente." analyzeVideos: "Abilitazione dell'analisi video." analyzeVideosDescription: "Assicuratevi che vengano analizzati anche i video oltre alle immagini fisse. Il carico del server aumenterà leggermente." + externalServiceInfo: "Abbiamo spostato esternamente il riconoscimento di media espliciti (sensitive-detector). Per usufruirne devi impostare un servizio separato e indicare di seguito la destinazione. Se non è impostata, non viene emesso alcun giudizio (contenuto NON esplicito)." + apiUrl: "URL di connessione a Sensitive-Detector" + apiUrlDescription: "L'URL di base del servizio (ad esempio http://localhost:3009). Collegandosi a una rete privata, autorizzare la rete nel parametro allowedPrivateNetworks nel file di configurazione.\nCollegandosi con un proxy, è anche necessario impostare proxyBypassHosts. Nel caso il campo sia vuoto, non vengono emessi giudizi di sensibilità." + apiKey: "Chiave API" + apiKeyDescription: "Indicare il token di autenticazione (Bearer token), soltanto se occorre, altrimenti lasciare vuoto." + timeout: "Timeout (ms)" + timeoutDescription: "Tempo limite per ogni richiesta" + maxImagesPerRequest: "Numero massimo di media per ogni richiesta" + maxImagesPerRequestDescription: "In caso ci siano più fotogrammi, come nei video, questo è il numero massimo di immagini da inviare in una richiesta. Oltre questo numero, il totale sarà diviso e inviato in sequenza.\nImpostare in modo che non superi il valore maxParts (default: 10) in Sensitive-Detector. Se viene superato, il media sarà considerato non esplicito." _emailUnavailable: used: "Email già in uso" format: "Formato email non valido" @@ -2461,6 +2474,7 @@ _permissions: "read:admin:show-moderation-log": "Vedere lo storico di moderazione" "read:admin:show-user": "Vedere le informazioni private dei profili" "write:admin:suspend-user": "Sospendere i profili" + "write:admin:unset-mfa": "Può rimuovere l'autenticazione a due fattori (2FA/MFA)" "write:admin:unset-user-avatar": "Rimuovere la foto profilo dai profili" "write:admin:unset-user-banner": "Rimuovere l'immagine testata dai profili" "write:admin:unsuspend-user": "Rimuovere la sospensione ai profili" @@ -2976,6 +2990,7 @@ _moderationLogTypes: createAvatarDecoration: "Crea una decorazione della foto profilo" updateAvatarDecoration: "Modifica una decorazione della foto profilo" deleteAvatarDecoration: "Elimina una decorazione della foto profilo" + unsetMfa: "Rimossa l'autenticazione a due fattori (2FA7MFA)" unsetUserAvatar: "Toglie una foto profilo" unsetUserBanner: "Toglie una immagine di intestazione profilo" createSystemWebhook: "Aggiunge un System Webhook" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 06c7b27c1e0..6cb6d46a892 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -619,6 +619,8 @@ output: "출력" script: "스�립트" disablePagesScript: "Pages �서 AiScript 를 사용하지 않�" updateRemoteUser: "리모트 유저 정보 갱신" +unsetMfa: "2단계 �� 해제" +unsetMfaConfirm: "2단계 ��� 해제하시겠습니까?" unsetUserAvatar: "아바타 제거" unsetUserAvatarConfirm: "아바타를 제거할까요?" unsetUserBanner: "배너 제거" @@ -1417,6 +1419,8 @@ addToEmojiPalette: "�모지 팔레트� 추가" emojiPaletteAlreadyAddedConfirm: "� �모지는 �미 � �모지 팔레트� �함�있습니다. 다시 추가하시겠습니까?" append: "맨뒤� 추가" prepend: "맨앞� 추가" +urlPreviewSensitiveList: "�네� 표시 제한 URL" +urlPreviewSensitiveListDescription: "공백으로 구분하면 AND 지정으로 �고, 줄내림으로 구분하면 OR 지정으로 �니다. 슬래시로 �싸면 정규 표현으로 �니다. �치한 경우� �네�� 표시�지 않게 �니다." _imageEditing: _vars: caption: "파� 설명" @@ -2149,6 +2153,15 @@ _sensitiveMediaDetection: setSensitiveFlagAutomaticallyDescription: "� 설정� 해제해� �지 결과는 유지�니다." analyzeVideos: "���� 같� 확�하기" analyzeVideosDescription: "사진 �만 아니� ���� NSFW 여부� �지합니다. 서버� 부하를 약간 �가시킵니다." + externalServiceInfo: "민�한 미디어 �정� 외부 서비스(sensitive-detector)로 분리�습니다. � 기능� �용하려면 별� 사�드카 서비스를 설정하고, 아래� 접� 위치를 설정해야 합니다. 접� 위치가 설정�지 않� 경우�는 �정� �루어지지 않습니다. (민�하지 않� 처리)" + apiUrl: "�정 서비스� 접� 위치 URL" + apiUrlDescription: "sensitive-detector 서비스� 베�스 URL(예시: http://localhost:3009). 프��빗 네트워��� 서비스� 접�하는 경우�는 설정 파�� allowedPrivateNetworks로 접� 위치 네트워�를 허가해 주십시오. 프�시를 사용하고 있는 경우�는 proxyBypassHosts� 설정해 주십시오. 비어있으면 민�함 �정� �루어지지 않습니다." + apiKey: "API 키" + apiKeyDescription: "�정 서비스 측�서 ��(Bearer 토�)� 설정하고 있는 경우� 입력합니다. 설정하고 있지 않� 경우�는 빈칸으로 둬주십시오." + timeout: "타임아웃 (밀리초)" + timeoutDescription: "�정 요청 1회당 타임아웃 시간입니다." + maxImagesPerRequest: "한 요청당 최대 �미지 수" + maxImagesPerRequestDescription: "��� 등 여러 프레임� �정할 때, 한 번� 요청� 모아서 보내는 �미지� 최대 장수입니다. �를 넘으면 분할해 순차�으로 송신�니다. sensitive-detector 측� maxParts 설정(기본: 10)� 남지 않�� 설정해 주십시오. 넘� 경우�는 그 청�는 전부 민�하지 않� 처리로 �니다." _emailUnavailable: used: "� 메� 주소는 사용중입니다" format: "형�� 올바르지 않습니다" @@ -2461,6 +2474,7 @@ _permissions: "read:admin:show-moderation-log": "조정 기� 보기" "read:admin:show-user": "유저 개�정보 보기" "write:admin:suspend-user": "유저 정지하기" + "write:admin:unset-mfa": "사용�� 2단계 �� 해제" "write:admin:unset-user-avatar": "유저 아바타 삭제하기" "write:admin:unset-user-banner": "유저 배너 삭제하기" "write:admin:unsuspend-user": "유저 정지 해제하기" @@ -2976,6 +2990,7 @@ _moderationLogTypes: createAvatarDecoration: "아바타 장� 만들기" updateAvatarDecoration: "아바타 장� 수정" deleteAvatarDecoration: "아바타 장� 삭제" + unsetMfa: "사용�� 2단계 �� 해제" unsetUserAvatar: "유저 아바타 제거" unsetUserBanner: "유저 배너 제거" createSystemWebhook: "SystemWebhook� �성" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index f826b716c7b..53f7e865ad1 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -57,7 +57,7 @@ deleteAndEditConfirm: "�删除该帖并�新编辑�?该帖下的所有回 addToList: "添加至列表" addToAntenna: "添加到天线" sendMessage: "��消�" -copyRSS: "�制RSS" +copyRSS: "�制 RSS" copyUsername: "�制用户�" copyUserId: "�制用户 ID" copyNoteId: "�制帖� ID" @@ -456,8 +456,8 @@ about: "关于" aboutMisskey: "关于 Misskey" administrator: "管�员" token: "Token (令牌)" -2fa: "�因素认�" -setupOf2fa: "设置�因素认�" +2fa: "��验�" +setupOf2fa: "设置��验�" totp: "验�器" totpDescription: "使用验�器输入一次性密�" moderator: "监察员" @@ -485,7 +485,7 @@ markAsReadAllNotifications: "将所有通知标为已读" markAsReadAllUnreadNotes: "将所有帖�标记为已读" markAsReadAllTalkMessages: "将所有�信标记为已读" help: "帮助" -inputMessageHere: "在此键入信�" +inputMessageHere: "在此输入信�" close: "关闭" invites: "邀请" members: "�员" @@ -619,6 +619,8 @@ output: "输出" script: "脚本" disablePagesScript: "�用页�脚本" updateRemoteUser: "更新远程用户信�" +unsetMfa: "解除��验�" +unsetMfaConfirm: "确认解除��验��?" unsetUserAvatar: "清除头�" unsetUserAvatarConfirm: "�清除头��?" unsetUserBanner: "清除横幅" @@ -1417,6 +1419,8 @@ addToEmojiPalette: "添加至表情符�选择器" emojiPaletteAlreadyAddedConfirm: "此表情符�已存在于此表情符�选择器中。��次添加�?" append: "加到最�" prepend: "加到最�" +urlPreviewSensitiveList: "�制显示缩略图的 URL" +urlPreviewSensitiveListDescription: "AND �件用空格分隔,OR �件用�行符分隔,正则表达�用斜线包裹。�功匹�则��显示缩略图。" _imageEditing: _vars: caption: "文件标题" @@ -2149,6 +2153,15 @@ _sensitiveMediaDetection: setSensitiveFlagAutomaticallyDescription: "�使关闭此�置,识别结果也会在内部�存。" analyzeVideos: "�用对视频的检测" analyzeVideosDescription: "除了�止图�之外,还对视频进行分�。�务器负载会略微增加。" + externalServiceInfo: "检测�感媒体已分离至外部�务 (sensitive-detector)。若�使用,需�外部署 Sidecar �务,并设置下方的连接 URL。未设定时将�会进行检测(视为��感媒体)。" + apiUrl: "检测�务的连接 URL" + apiUrlDescription: "sensitive-detector �务的 base URL(如:http://localhost:3009)。若是连接至部署在专用网络上的�务,请在�置文件中的 allowedPrivateNetworks 里�许目标网络。若是使用了代�,请一并设置 proxyBypassHosts。留空则�进行�感媒体检测。" + apiKey: "API 密钥" + apiKeyDescription: "若�务端有设置验�(Bearer token)则填写,未设置则留空。" + timeout: "超时(毫秒)" + timeoutDescription: "此为�次检测请求的超时时长。" + maxImagesPerRequest: "�次检测请求最大图�数�" + maxImagesPerRequestDescription: "此为在检测动画等多帧图�时,�次请求中���的图�数�上�。超出此值时动画将被拆分并按���。请勿将此值设为超出 sensitive-detector 侧的 maxParts 的值(默认:10),�则对应的分�将全被视为��感媒体。" _emailUnavailable: used: "已�被使用过" format: "无效的格�" @@ -2461,6 +2474,7 @@ _permissions: "read:admin:show-moderation-log": "查看管�日志" "read:admin:show-user": "查看用户的�公开信�" "write:admin:suspend-user": "冻结用户" + "write:admin:unset-mfa": "解除用户的��验�" "write:admin:unset-user-avatar": "删除用户头�" "write:admin:unset-user-banner": "删除用户横幅" "write:admin:unsuspend-user": "解除用户冻结" @@ -2586,7 +2600,7 @@ _widgetOptions: _jobQueue: sound: "播放音效" _rss: - url: "RSS feed 的 URL" + url: "RSS 订阅�网�" refreshIntervalSec: "更新间隔(秒)" maxEntries: "最大显示个数" _rssTicker: @@ -2976,6 +2990,7 @@ _moderationLogTypes: createAvatarDecoration: "新建头�挂件" updateAvatarDecoration: "更新头�挂件" deleteAvatarDecoration: "删除头�挂件" + unsetMfa: "解除用户的��验�" unsetUserAvatar: "清除用户头�" unsetUserBanner: "清除用户横幅" createSystemWebhook: "新建了 SystemWebhook" From 7c29a18d61ab66eb59fc259c3f766f61a3e47ee3 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 24 Jul 2026 21:39:28 +0900 Subject: [PATCH 458/578] =?UTF-8?q?enhance(frontend):=20=E3=82=A2=E3=83=83?= =?UTF-8?q?=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89=E5=89=8D=E3=81=AE=E3=83=95?= =?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AE=E3=83=97=E3=83=AC=E3=83=93?= =?UTF-8?q?=E3=83=A5=E3=83=BC=E3=81=AB=E5=AF=BE=E5=BF=9C&=E3=82=A2?= =?UTF-8?q?=E3=83=83=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89=E5=BE=8C=E3=81=AE?= =?UTF-8?q?=E3=83=97=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E3=81=ABMkLightbo?= =?UTF-8?q?x=E3=82=92=E4=BD=BF=E7=94=A8=20(#17794)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip * [ci skip] Update CHANGELOG.md * Update MkUploaderItems.vue * Update MkUploaderItems.vue * Update MkUploaderItems.vue --- CHANGELOG.md | 3 +- packages/frontend/.storybook/generate.tsx | 1 - .../MkImgPreviewDialog.stories.impl.ts | 40 ------------ .../src/components/MkImgPreviewDialog.vue | 63 ------------------- .../frontend/src/components/MkLightbox.vue | 19 +++++- .../frontend/src/components/MkMediaList.vue | 4 +- .../src/components/MkPostFormAttaches.vue | 19 +++++- .../src/components/MkUploaderItems.vue | 50 +++++++++++++-- 8 files changed, 84 insertions(+), 115 deletions(-) delete mode 100644 packages/frontend/src/components/MkImgPreviewDialog.stories.impl.ts delete mode 100644 packages/frontend/src/components/MkImgPreviewDialog.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 61acf1fa7b4..4bcf30b6037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ ### Client - 2025.4.0 以��設定情報�移行処��削除�れ��� - 2025.4.0 �ら直接 2026.6.0 以上�アップデート�る場��設定�移行�れ��ん��注�������。移行���場��一度 2026.5.1 を経由������。 -- Enhance: 画�ビューワーを独自実装�変更・動画プレイヤーを統� +- Enhance: 画�ビューワーを刷新・動画プレイヤーを統� - �作性�改善 - ビューワー�Misskey��種機能��統�を強化 - パフォーマンス��上 @@ -29,6 +29,7 @@ - Fix: 幅�狭�画��動画��生�困難��題を修正 - Fix: 一部�画���センシティブ����ビューワー内�画�を切り替�る�センシティブ�画������表示�れる�題を修正 - Fix: 一部�画�をビューワー�読�込ん�際�正��表示�れ���題を修正 +- Enhance: ファイルアップロード��プレビュー��るよ�� - Enhance: タブ��ックグラウンド�間�必���定期更新処�を�止�るよ�� - Fix: 「画�を新��タブ�開���機能���������題を修正 - Fix: デ�イスタイプをスマートフォン�固定���る状態�画�幅�広����画�左上�アイコン�表示�れ���題を修正 diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx index 6005049dde3..01ddefa5448 100644 --- a/packages/frontend/.storybook/generate.tsx +++ b/packages/frontend/.storybook/generate.tsx @@ -458,7 +458,6 @@ function toStories(component: string): Promise { globSync('src/components/MkSignupServerRules.vue'), globSync('src/components/MkUserSetupDialog.vue'), globSync('src/components/MkUserSetupDialog.*.vue'), - globSync('src/components/MkImgPreviewDialog.vue'), globSync('src/components/MkInstanceCardMini.vue'), globSync('src/components/MkInviteCode.vue'), globSync('src/components/MkTagItem.vue'), diff --git a/packages/frontend/src/components/MkImgPreviewDialog.stories.impl.ts b/packages/frontend/src/components/MkImgPreviewDialog.stories.impl.ts deleted file mode 100644 index 7da705a23fb..00000000000 --- a/packages/frontend/src/components/MkImgPreviewDialog.stories.impl.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import type { StoryObj } from '@storybook/vue3'; -import { file } from '../../.storybook/fakes.js'; -import MkImgPreviewDialog from './MkImgPreviewDialog.vue'; -export const Default = { - render(args) { - return { - components: { - MkImgPreviewDialog, - }, - setup() { - return { - args, - }; - }, - computed: { - props() { - return { - ...this.args, - }; - }, - }, - template: '', - }; - }, - args: { - file: file(), - }, - parameters: { - chromatic: { - // NOTE: ロード�終�る��待� - delay: 3000, - }, - layout: 'centered', - }, -} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkImgPreviewDialog.vue b/packages/frontend/src/components/MkImgPreviewDialog.vue deleted file mode 100644 index 530b6c45db9..00000000000 --- a/packages/frontend/src/components/MkImgPreviewDialog.vue +++ /dev/null @@ -1,63 +0,0 @@ - - - - - diff --git a/packages/frontend/src/components/MkLightbox.vue b/packages/frontend/src/components/MkLightbox.vue index d999723c4ce..ae40c7a612f 100644 --- a/packages/frontend/src/components/MkLightbox.vue +++ b/packages/frontend/src/components/MkLightbox.vue @@ -48,13 +48,14 @@ SPDX-License-Identifier: AGPL-3.0-only From cf7a6b6efc05a6a016d5c60e2e00d7210d7ffa81 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Jul 2026 21:40:01 +0900 Subject: [PATCH 459/578] chore(deps): update [github actions] update dependencies (#17791) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/api-misskey-js.yml | 2 +- .github/workflows/backend-diagnostics.comment.yml | 2 +- .github/workflows/backend-diagnostics.inspect.yml | 2 +- .github/workflows/changelog-check.yml | 2 +- .github/workflows/check-misskey-js-autogen.yml | 2 +- .github/workflows/frontend-diagnostics.inspect.yml | 2 +- .github/workflows/get-api-diff.yml | 2 +- .github/workflows/lint.yml | 10 +++++----- .github/workflows/locale.yml | 2 +- .github/workflows/on-release-created.yml | 2 +- .github/workflows/packages-private.yml | 2 +- .github/workflows/storybook.yml | 2 +- .github/workflows/test-backend.yml | 8 ++++---- .github/workflows/test-federation.yml | 2 +- .github/workflows/test-frontend.yml | 4 ++-- .github/workflows/test-misskey-js.yml | 2 +- .github/workflows/test-production.yml | 2 +- .github/workflows/validate-api-json.yml | 2 +- 18 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml index 19987d2af41..073ba89ac40 100644 --- a/.github/workflows/api-misskey-js.yml +++ b/.github/workflows/api-misskey-js.yml @@ -22,7 +22,7 @@ jobs: uses: pnpm/action-setup@v6.0.9 - name: Setup Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/backend-diagnostics.comment.yml b/.github/workflows/backend-diagnostics.comment.yml index a6d914441c4..b9f72ad88d0 100644 --- a/.github/workflows/backend-diagnostics.comment.yml +++ b/.github/workflows/backend-diagnostics.comment.yml @@ -22,7 +22,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/backend-diagnostics.inspect.yml b/.github/workflows/backend-diagnostics.inspect.yml index 8040b13307a..f01a74375a6 100644 --- a/.github/workflows/backend-diagnostics.inspect.yml +++ b/.github/workflows/backend-diagnostics.inspect.yml @@ -51,7 +51,7 @@ jobs: with: package_json_file: head/package.json - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: 'head/.node-version' cache: 'pnpm' diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml index a6d222b6bd3..a54efff4b6f 100644 --- a/.github/workflows/changelog-check.yml +++ b/.github/workflows/changelog-check.yml @@ -18,7 +18,7 @@ jobs: uses: pnpm/action-setup@v6 - name: setup node - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: pnpm diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml index c5350b62d23..254c4bf80e4 100644 --- a/.github/workflows/check-misskey-js-autogen.yml +++ b/.github/workflows/check-misskey-js-autogen.yml @@ -29,7 +29,7 @@ jobs: - name: setup node id: setup-node - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: pnpm diff --git a/.github/workflows/frontend-diagnostics.inspect.yml b/.github/workflows/frontend-diagnostics.inspect.yml index ecf06c30925..ba7fc8ebfd9 100644 --- a/.github/workflows/frontend-diagnostics.inspect.yml +++ b/.github/workflows/frontend-diagnostics.inspect.yml @@ -79,7 +79,7 @@ jobs: package_json_file: head/package.json - name: Setup Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: head/.node-version cache: pnpm diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml index ef34d19e687..82ce6873c85 100644 --- a/.github/workflows/get-api-diff.yml +++ b/.github/workflows/get-api-diff.yml @@ -32,7 +32,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0e77f896a22..ebc88a74c49 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -46,7 +46,7 @@ jobs: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.4.0 + - uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' @@ -79,13 +79,13 @@ jobs: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.4.0 + - uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' - run: pnpm i --frozen-lockfile - name: Restore eslint cache - uses: actions/cache@v5.0.5 + uses: actions/cache@v5.1.0 with: path: ${{ env.eslint-cache-path }} key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }} @@ -110,7 +110,7 @@ jobs: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.4.0 + - uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' @@ -129,7 +129,7 @@ jobs: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.4.0 + - uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml index d87f18827e7..a0f26f4596b 100644 --- a/.github/workflows/locale.yml +++ b/.github/workflows/locale.yml @@ -22,7 +22,7 @@ jobs: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.4.0 + - uses: actions/setup-node@v6.5.0 with: node-version-file: ".node-version" cache: "pnpm" diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml index 76fd5548f25..48a20c360ef 100644 --- a/.github/workflows/on-release-created.yml +++ b/.github/workflows/on-release-created.yml @@ -22,7 +22,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/packages-private.yml b/.github/workflows/packages-private.yml index cf7e50670ab..b3f69e43aea 100644 --- a/.github/workflows/packages-private.yml +++ b/.github/workflows/packages-private.yml @@ -41,7 +41,7 @@ jobs: persist-credentials: false - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.4.0 + - uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 70bfa329a14..03e19f47800 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -39,7 +39,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index 3bf3b9eff59..4818fe051d5 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -43,7 +43,7 @@ jobs: ports: - 56312:6379 meilisearch: - image: getmeili/meilisearch:v1.48.1 + image: getmeili/meilisearch:v1.49.0 ports: - 57712:7700 env: @@ -60,7 +60,7 @@ jobs: run: | sudo apt install -y ffmpeg - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: ${{ matrix.node-version-file }} cache: 'pnpm' @@ -109,7 +109,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: ${{ matrix.node-version-file }} cache: 'pnpm' @@ -156,7 +156,7 @@ jobs: id: current-date run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: ${{ matrix.node-version-file }} cache: 'pnpm' diff --git a/.github/workflows/test-federation.yml b/.github/workflows/test-federation.yml index 14dc33f6263..0b2aa1bd4bb 100644 --- a/.github/workflows/test-federation.yml +++ b/.github/workflows/test-federation.yml @@ -35,7 +35,7 @@ jobs: run: | sudo apt install -y ffmpeg - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: ${{ matrix.node-version-file }} cache: 'pnpm' diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index e8a98b2b78e..abf3332d177 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -34,7 +34,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' @@ -77,7 +77,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index f3c6f0a5165..82e04f8c797 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -28,7 +28,7 @@ jobs: uses: pnpm/action-setup@v6.0.9 - name: Setup Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index 0d9b2293dcd..527b9f4c355 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -22,7 +22,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml index ada1b3b2d81..e59b39472f9 100644 --- a/.github/workflows/validate-api-json.yml +++ b/.github/workflows/validate-api-json.yml @@ -23,7 +23,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@v6.5.0 with: node-version-file: '.node-version' cache: 'pnpm' From d2973ecdcacc9276648c658bf7464bcbc6ddd931 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Jul 2026 22:46:54 +0900 Subject: [PATCH 460/578] chore(deps): update [github actions] update dependencies (major) (#17792) chore(deps): update [github actions] update dependencies Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/api-misskey-js.yml | 4 ++-- .../workflows/backend-diagnostics.comment.yml | 4 ++-- .../workflows/backend-diagnostics.inspect.yml | 6 +++--- .github/workflows/changelog-check.yml | 4 ++-- .github/workflows/check-misskey-js-autogen.yml | 6 +++--- .github/workflows/check-misskey-js-version.yml | 2 +- .github/workflows/check-spdx-license-id.yml | 2 +- .github/workflows/check_copyright_year.yml | 2 +- .github/workflows/docker-develop.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/dockle.yml | 2 +- .../workflows/frontend-diagnostics.inspect.yml | 6 +++--- .github/workflows/get-api-diff.yml | 4 ++-- .github/workflows/labeler.yml | 2 +- .github/workflows/lint.yml | 18 +++++++++--------- .github/workflows/locale.yml | 4 ++-- .github/workflows/on-release-created.yml | 4 ++-- .github/workflows/packages-private.yml | 4 ++-- .github/workflows/release-edit-with-push.yml | 2 +- .github/workflows/release-with-dispatch.yml | 2 +- .github/workflows/storybook.yml | 6 +++--- .github/workflows/test-backend.yml | 16 ++++++++-------- .github/workflows/test-federation.yml | 4 ++-- .github/workflows/test-frontend.yml | 10 +++++----- .github/workflows/test-misskey-js.yml | 6 +++--- .github/workflows/test-production.yml | 4 ++-- .github/workflows/validate-api-json.yml | 4 ++-- 27 files changed, 66 insertions(+), 66 deletions(-) diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml index 073ba89ac40..09e9c8ab6e8 100644 --- a/.github/workflows/api-misskey-js.yml +++ b/.github/workflows/api-misskey-js.yml @@ -16,13 +16,13 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Setup Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/backend-diagnostics.comment.yml b/.github/workflows/backend-diagnostics.comment.yml index b9f72ad88d0..51ac04e86a9 100644 --- a/.github/workflows/backend-diagnostics.comment.yml +++ b/.github/workflows/backend-diagnostics.comment.yml @@ -17,12 +17,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/backend-diagnostics.inspect.yml b/.github/workflows/backend-diagnostics.inspect.yml index f01a74375a6..c3b2e9e2b7b 100644 --- a/.github/workflows/backend-diagnostics.inspect.yml +++ b/.github/workflows/backend-diagnostics.inspect.yml @@ -35,13 +35,13 @@ jobs: steps: - name: Checkout base - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 with: ref: ${{ github.base_ref }} path: base submodules: true - name: Checkout head - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 with: ref: refs/pull/${{ github.event.number }}/merge path: head @@ -51,7 +51,7 @@ jobs: with: package_json_file: head/package.json - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: 'head/.node-version' cache: 'pnpm' diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml index a54efff4b6f..95fe48ab4cc 100644 --- a/.github/workflows/changelog-check.yml +++ b/.github/workflows/changelog-check.yml @@ -12,13 +12,13 @@ jobs: steps: - name: Checkout head - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 - name: setup pnpm uses: pnpm/action-setup@v6 - name: setup node - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: pnpm diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml index 254c4bf80e4..631daa79c88 100644 --- a/.github/workflows/check-misskey-js-autogen.yml +++ b/.github/workflows/check-misskey-js-autogen.yml @@ -18,7 +18,7 @@ jobs: if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }} steps: - name: checkout - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 with: submodules: true persist-credentials: false @@ -29,7 +29,7 @@ jobs: - name: setup node id: setup-node - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: pnpm @@ -66,7 +66,7 @@ jobs: if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }} steps: - name: checkout - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 with: submodules: true persist-credentials: false diff --git a/.github/workflows/check-misskey-js-version.yml b/.github/workflows/check-misskey-js-version.yml index 71351972f44..1d703ad2104 100644 --- a/.github/workflows/check-misskey-js-version.yml +++ b/.github/workflows/check-misskey-js-version.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 - name: Check version run: | if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then diff --git a/.github/workflows/check-spdx-license-id.yml b/.github/workflows/check-spdx-license-id.yml index d0cf6e3cf64..ae0102b92c5 100644 --- a/.github/workflows/check-spdx-license-id.yml +++ b/.github/workflows/check-spdx-license-id.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 - name: Check run: | counter=0 diff --git a/.github/workflows/check_copyright_year.yml b/.github/workflows/check_copyright_year.yml index 4b5e71c43a0..a6ed53a0f86 100644 --- a/.github/workflows/check_copyright_year.yml +++ b/.github/workflows/check_copyright_year.yml @@ -10,7 +10,7 @@ jobs: check_copyright_year: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 - run: | if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then echo "Please change copyright year!" diff --git a/.github/workflows/docker-develop.yml b/.github/workflows/docker-develop.yml index 983f6649172..f7dd869e02a 100644 --- a/.github/workflows/docker-develop.yml +++ b/.github/workflows/docker-develop.yml @@ -27,7 +27,7 @@ jobs: platform=${{ matrix.platform }} echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - name: Check out the repo - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Log in to Docker Hub diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 277c88894ea..8cf0c2b6663 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -32,7 +32,7 @@ jobs: platform=${{ matrix.platform }} echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - name: Check out the repo - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Docker meta diff --git a/.github/workflows/dockle.yml b/.github/workflows/dockle.yml index 87256c000ea..385cbede669 100644 --- a/.github/workflows/dockle.yml +++ b/.github/workflows/dockle.yml @@ -17,7 +17,7 @@ jobs: DOCKLE_VERSION: 0.4.15 steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 - name: Download and install dockle v${{ env.DOCKLE_VERSION }} run: | diff --git a/.github/workflows/frontend-diagnostics.inspect.yml b/.github/workflows/frontend-diagnostics.inspect.yml index ba7fc8ebfd9..acbc8ea77e5 100644 --- a/.github/workflows/frontend-diagnostics.inspect.yml +++ b/.github/workflows/frontend-diagnostics.inspect.yml @@ -56,7 +56,7 @@ jobs: steps: - name: Checkout base - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 with: persist-credentials: false repository: ${{ github.event.pull_request.base.repo.full_name }} @@ -65,7 +65,7 @@ jobs: submodules: true - name: Checkout head - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 with: persist-credentials: false repository: ${{ github.event.pull_request.head.repo.full_name }} @@ -79,7 +79,7 @@ jobs: package_json_file: head/package.json - name: Setup Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: head/.node-version cache: pnpm diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml index 82ce6873c85..77da3236347 100644 --- a/.github/workflows/get-api-diff.yml +++ b/.github/workflows/get-api-diff.yml @@ -25,14 +25,14 @@ jobs: ref: refs/pull/${{ github.event.number }}/merge steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: ref: ${{ matrix.ref }} submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 5787572dd5b..0cfbb22c65c 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -11,6 +11,6 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v6 + - uses: actions/labeler@v7 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ebc88a74c49..70b6f749814 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -40,13 +40,13 @@ jobs: pnpm_install: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: fetch-depth: 0 submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.5.0 + - uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' @@ -73,19 +73,19 @@ jobs: eslint-cache-version: v1 eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }} steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: fetch-depth: 0 submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.5.0 + - uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' - run: pnpm i --frozen-lockfile - name: Restore eslint cache - uses: actions/cache@v5.1.0 + uses: actions/cache@v6.1.0 with: path: ${{ env.eslint-cache-path }} key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }} @@ -104,13 +104,13 @@ jobs: - sw - misskey-js steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: fetch-depth: 0 submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.5.0 + - uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' @@ -123,13 +123,13 @@ jobs: runs-on: ubuntu-latest continue-on-error: true steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: fetch-depth: 0 submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.5.0 + - uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml index a0f26f4596b..1eb2f56056b 100644 --- a/.github/workflows/locale.yml +++ b/.github/workflows/locale.yml @@ -16,13 +16,13 @@ jobs: runs-on: ubuntu-latest continue-on-error: true steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: fetch-depth: 0 submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.5.0 + - uses: actions/setup-node@v7.0.0 with: node-version-file: ".node-version" cache: "pnpm" diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml index 48a20c360ef..37e976f25f0 100644 --- a/.github/workflows/on-release-created.yml +++ b/.github/workflows/on-release-created.yml @@ -16,13 +16,13 @@ jobs: id-token: write steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/packages-private.yml b/.github/workflows/packages-private.yml index b3f69e43aea..2a93455c254 100644 --- a/.github/workflows/packages-private.yml +++ b/.github/workflows/packages-private.yml @@ -36,12 +36,12 @@ jobs: - diagnostics-frontend - changelog-checker steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: persist-credentials: false - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - - uses: actions/setup-node@v6.5.0 + - uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/release-edit-with-push.yml b/.github/workflows/release-edit-with-push.yml index bc16dbcef21..176dcde1af2 100644 --- a/.github/workflows/release-edit-with-push.yml +++ b/.github/workflows/release-edit-with-push.yml @@ -19,7 +19,7 @@ jobs: edit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 # head�$GITHUB_REF_NAME, base�$STABLE_BRANCH��open�PRを1��得 - name: Get PR run: | diff --git a/.github/workflows/release-with-dispatch.yml b/.github/workflows/release-with-dispatch.yml index f3182005845..051a5e5419f 100644 --- a/.github/workflows/release-with-dispatch.yml +++ b/.github/workflows/release-with-dispatch.yml @@ -36,7 +36,7 @@ jobs: outputs: pr_number: ${{ steps.get_pr.outputs.pr_number }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 # head�$GITHUB_REF_NAME, base�$STABLE_BRANCH��open�PRを1��得 - name: Get PRs run: | diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 03e19f47800..670ac3549e2 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -22,12 +22,12 @@ jobs: NODE_OPTIONS: "--max_old_space_size=7168" steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 if: github.event_name != 'pull_request_target' with: fetch-depth: 0 submodules: true - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 if: github.event_name == 'pull_request_target' with: fetch-depth: 0 @@ -39,7 +39,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index 4818fe051d5..7992d5d83bf 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -51,7 +51,7 @@ jobs: MEILI_ENV: development steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: submodules: true - name: Setup pnpm @@ -60,7 +60,7 @@ jobs: run: | sudo apt install -y ffmpeg - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: ${{ matrix.node-version-file }} cache: 'pnpm' @@ -74,7 +74,7 @@ jobs: - name: Test run: pnpm --filter backend test-and-coverage - name: Upload to Codecov - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/backend/coverage/coverage-final.json @@ -103,13 +103,13 @@ jobs: - 56312:6379 steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: ${{ matrix.node-version-file }} cache: 'pnpm' @@ -123,7 +123,7 @@ jobs: - name: Test run: pnpm --filter backend test-and-coverage:e2e - name: Upload to Codecov - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/backend/coverage/coverage-final.json @@ -147,7 +147,7 @@ jobs: POSTGRES_HOST_AUTH_METHOD: trust steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: submodules: true - name: Setup pnpm @@ -156,7 +156,7 @@ jobs: id: current-date run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: ${{ matrix.node-version-file }} cache: 'pnpm' diff --git a/.github/workflows/test-federation.yml b/.github/workflows/test-federation.yml index 0b2aa1bd4bb..1005cfa0581 100644 --- a/.github/workflows/test-federation.yml +++ b/.github/workflows/test-federation.yml @@ -26,7 +26,7 @@ jobs: - .node-version - .github/min.node-version steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: submodules: true - name: Setup pnpm @@ -35,7 +35,7 @@ jobs: run: | sudo apt install -y ffmpeg - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: ${{ matrix.node-version-file }} cache: 'pnpm' diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index abf3332d177..774c552672f 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -28,13 +28,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' @@ -48,7 +48,7 @@ jobs: - name: Test run: pnpm --filter frontend test-and-coverage - name: Upload Coverage - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/frontend/coverage/coverage-final.json @@ -71,13 +71,13 @@ jobs: - 56312:6379 steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index 82e04f8c797..e3198051aaf 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -22,13 +22,13 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6.0.3 + uses: actions/checkout@v7.0.0 - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Setup Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' @@ -48,7 +48,7 @@ jobs: CI: true - name: Upload Coverage - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/misskey-js/coverage/coverage-final.json diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index 527b9f4c355..8192d21c817 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -16,13 +16,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml index e59b39472f9..b355f4e52b3 100644 --- a/.github/workflows/validate-api-json.yml +++ b/.github/workflows/validate-api-json.yml @@ -17,13 +17,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.3 + - uses: actions/checkout@v7.0.0 with: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v6.0.9 - name: Use Node.js - uses: actions/setup-node@v6.5.0 + uses: actions/setup-node@v7.0.0 with: node-version-file: '.node-version' cache: 'pnpm' From e8951b7aa1c8ad35474e76f49e1bf3ae186f7e23 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Jul 2026 09:27:15 +0900 Subject: [PATCH 461/578] fix(deps): update dependency @fastify/static to v10.1.2 [security] (#17796) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/backend/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- pnpm-workspace.yaml | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index a13ce02e8ad..7c456daeccb 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -58,7 +58,7 @@ "@fastify/http-proxy": "11.5.0", "@fastify/multipart": "10.1.0", "@fastify/otel": "0.20.1", - "@fastify/static": "10.1.0", + "@fastify/static": "10.1.2", "@kitajs/html": "4.2.13", "@misskey-dev/emoji-assets": "17.0.3", "@misskey-dev/emoji-data": "17.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a430acbf92d..4c73584bda4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -192,8 +192,8 @@ importers: specifier: 0.20.1 version: 0.20.1(@opentelemetry/api@1.9.1) '@fastify/static': - specifier: 10.1.0 - version: 10.1.0 + specifier: 10.1.2 + version: 10.1.2 '@kitajs/html': specifier: 4.2.13 version: 4.2.13 @@ -1955,8 +1955,8 @@ packages: '@fastify/send@4.1.0': resolution: {integrity: sha512-TMYeQLCBSy2TOFmV95hQWkiTYgC/SEx7vMdV+wnZVX4tt8VBLKzmH8vV9OzJehV0+XBfg+WxPMt5wp+JBUKsVw==} - '@fastify/static@10.1.0': - resolution: {integrity: sha512-iK/8TvRM/EgNOyQL+EpWu+x3aR6o4GWt+UI+27zmE7w6t/6d80mXqOtWLdEKQ13vL/g1Jry0ae2icj6GP7tGzA==} + '@fastify/static@10.1.2': + resolution: {integrity: sha512-G/g18cG9tLutT/OVyN1AIsHIl9L1UwmJ+S3dkyhVpplIx0nEMicd7RGQ+uJLyhKKF4a3tTcQydccn3Mop1fX+Q==} '@file-type/xml@0.4.4': resolution: {integrity: sha512-NhCyXoHlVZ8TqM476hyzwGJ24+D5IPSaZhmrPj7qXnEVb3q6jrFzA3mM9TBpknKSI9EuQeGTKRg2DXGUwvBBoQ==} @@ -10088,7 +10088,7 @@ snapshots: http-errors: 2.0.1 mime: 3.0.0 - '@fastify/static@10.1.0': + '@fastify/static@10.1.2': dependencies: '@fastify/accept-negotiator': 2.0.1 '@fastify/error': 4.2.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4d3caf525ae..2eb12d2e0c7 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -58,6 +58,8 @@ minimumReleaseAgeExclude: - "@opentelemetry/core@2.8.0" # Renovate security update: typeorm@1.1.0 - typeorm@1.1.0 + # Renovate security update: @fastify/static@10.1.2 + - "@fastify/static@10.1.2" overrides: '@aiscript-dev/aiscript-languageserver': '-' 'bullmq>ioredis': 5.11.1 From cde2fe24c4fe3fdceef8ad878c6f43f587aa7446 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Jul 2026 10:27:21 +0900 Subject: [PATCH 462/578] fix(deps): update dependency tar to v7.5.21 [security] (#17798) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ pnpm-workspace.yaml | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 63e6db5cef9..cac0c77cf23 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "execa": "9.6.1", "ignore-walk": "9.0.0", "js-yaml": "5.2.1", - "tar": "7.5.20" + "tar": "7.5.21" }, "devDependencies": { "@eslint/js": "9.39.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c73584bda4..dd7afbfad52 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,8 @@ importers: specifier: 5.2.1 version: 5.2.1 tar: - specifier: 7.5.20 - version: 7.5.20 + specifier: 7.5.21 + version: 7.5.21 devDependencies: '@eslint/js': specifier: 9.39.5 @@ -8613,8 +8613,8 @@ packages: tar-stream@3.2.0: resolution: {integrity: sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==} - tar@7.5.20: - resolution: {integrity: sha512-9FcyK4PA6+WbzlTM9WhQm6vB5W7cP7dUiPsv1g7YDwEQnQ1CGpK3MGlKk/ITVWMk05kHZuBhmVhiv8LZoy/PFQ==} + tar@7.5.21: + resolution: {integrity: sha512-XdhtCvlMywwxpCW8YEq3lOXBJpUPTR2OHHcwLPO3HwsJqOHa2Ok/oJ7ruGzp+JrKoRPVCzJwAdEjqLW/vNRPHA==} engines: {node: '>=18'} taskkill@5.0.0: @@ -15928,7 +15928,7 @@ snapshots: nopt: 10.0.1 proc-log: 7.0.0 semver: 7.8.5 - tar: 7.5.20 + tar: 7.5.21 tinyglobby: 0.2.17 undici: 6.25.0 which: 7.0.0 @@ -17586,7 +17586,7 @@ snapshots: - bare-buffer - react-native-b4a - tar@7.5.20: + tar@7.5.21: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2eb12d2e0c7..45c691ac273 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -60,6 +60,8 @@ minimumReleaseAgeExclude: - typeorm@1.1.0 # Renovate security update: @fastify/static@10.1.2 - "@fastify/static@10.1.2" + # Renovate security update: tar@7.5.21 + - tar@7.5.21 overrides: '@aiscript-dev/aiscript-languageserver': '-' 'bullmq>ioredis': 5.11.1 From c70fb20b9ef65e4694bc05569a3566be37668d16 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 25 Jul 2026 01:29:48 +0000 Subject: [PATCH 463/578] Bump version to 2026.7.0-beta.6 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index cac0c77cf23..07d2855fdb0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2026.7.0-beta.5", + "version": "2026.7.0-beta.6", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index b0a17f768a8..abe0cc5b600 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2026.7.0-beta.5", + "version": "2026.7.0-beta.6", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From 7ecce0901cbd9a512947e0d28f011ccc2a5f0b30 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Jul 2026 16:07:49 +0900 Subject: [PATCH 464/578] fix(deps): update dependency js-yaml to v5.2.2 [security] (#17797) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- packages/backend/package.json | 2 +- packages/i18n/package.json | 2 +- pnpm-lock.yaml | 18 +++++++++--------- pnpm-workspace.yaml | 2 ++ 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 07d2855fdb0..c073a72dfd0 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "esbuild": "0.28.1", "execa": "9.6.1", "ignore-walk": "9.0.0", - "js-yaml": "5.2.1", + "js-yaml": "5.2.2", "tar": "7.5.21" }, "devDependencies": { diff --git a/packages/backend/package.json b/packages/backend/package.json index 7c456daeccb..1adbde08275 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -193,7 +193,7 @@ "eslint-plugin-import": "2.32.0", "execa": "9.6.1", "fkill": "10.0.3", - "js-yaml": "5.2.1", + "js-yaml": "5.2.2", "pid-port": "2.1.1", "rolldown": "1.1.5", "simple-oauth2": "5.1.0", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index c5b4b9bdfc0..40a4b927325 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -38,6 +38,6 @@ "tsx": "4.23.0" }, "dependencies": { - "js-yaml": "5.2.1" + "js-yaml": "5.2.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dd7afbfad52..5bff769483c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: 9.0.0 version: 9.0.0 js-yaml: - specifier: 5.2.1 - version: 5.2.1 + specifier: 5.2.2 + version: 5.2.2 tar: specifier: 7.5.21 version: 7.5.21 @@ -592,8 +592,8 @@ importers: specifier: 10.0.3 version: 10.0.3 js-yaml: - specifier: 5.2.1 - version: 5.2.1 + specifier: 5.2.2 + version: 5.2.2 pid-port: specifier: 2.1.1 version: 2.1.1 @@ -1230,8 +1230,8 @@ importers: packages/i18n: dependencies: js-yaml: - specifier: 5.2.1 - version: 5.2.1 + specifier: 5.2.2 + version: 5.2.2 devDependencies: '@types/node': specifier: 26.1.1 @@ -6500,8 +6500,8 @@ packages: resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} hasBin: true - js-yaml@5.2.1: - resolution: {integrity: sha512-zfLtNfQqxVqq3uaTqSkh4x4hZw3KHobGUA0fJUj4wawW8bsQLTVqpHdXSIzidh7o+4lEW36tANuAGdaFx6Zgnw==} + js-yaml@5.2.2: + resolution: {integrity: sha512-dayzUzKkJ1MkuUtZglSebU43utNXH0OWQByK9rKOOuYIO8M5TV1y+n8ALMdG0rdzBnfNkOmZEqrURepb0ejqBw==} hasBin: true jsbn@0.1.1: @@ -15042,7 +15042,7 @@ snapshots: dependencies: argparse: 2.0.1 - js-yaml@5.2.1: + js-yaml@5.2.2: dependencies: argparse: 2.0.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 45c691ac273..55e7b614ea0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -62,6 +62,8 @@ minimumReleaseAgeExclude: - "@fastify/static@10.1.2" # Renovate security update: tar@7.5.21 - tar@7.5.21 + # Renovate security update: js-yaml@5.2.2 + - js-yaml@5.2.2 overrides: '@aiscript-dev/aiscript-languageserver': '-' 'bullmq>ioredis': 5.11.1 From 982d4905c0a6406bbcf4f205169b9ecd0d662787 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Sat, 25 Jul 2026 19:48:20 +0900 Subject: [PATCH 465/578] use UPSERT instead of select for hashtag statistics update (#17795) * feat: set defaults for hashtag table * chore: use upsert to update hashtag table * fix: query runner not cleaned up * fix: query runner not cleaned up correctly * chore: replace await using => try-finally --- .../1784899839024-HashtagTableDefaults.js | 26 +++ packages/backend/src/core/HashtagService.ts | 212 ++++++++---------- packages/backend/src/models/Hashtag.ts | 6 + 3 files changed, 126 insertions(+), 118 deletions(-) create mode 100644 packages/backend/migration/1784899839024-HashtagTableDefaults.js diff --git a/packages/backend/migration/1784899839024-HashtagTableDefaults.js b/packages/backend/migration/1784899839024-HashtagTableDefaults.js new file mode 100644 index 00000000000..4b890fa8493 --- /dev/null +++ b/packages/backend/migration/1784899839024-HashtagTableDefaults.js @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class HashtagTableDefaults1784899839024 { + name = 'HashtagTableDefaults1784899839024' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "mentionedUserIds" SET DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "mentionedLocalUserIds" SET DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "mentionedRemoteUserIds" SET DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "attachedUserIds" SET DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "attachedLocalUserIds" SET DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "attachedRemoteUserIds" SET DEFAULT '{}'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "attachedRemoteUserIds" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "attachedLocalUserIds" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "attachedUserIds" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "mentionedRemoteUserIds" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "mentionedLocalUserIds" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "hashtag" ALTER COLUMN "mentionedUserIds" DROP DEFAULT`); + } +} diff --git a/packages/backend/src/core/HashtagService.ts b/packages/backend/src/core/HashtagService.ts index beed786d1b9..750fbb06ffe 100644 --- a/packages/backend/src/core/HashtagService.ts +++ b/packages/backend/src/core/HashtagService.ts @@ -16,11 +16,20 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import { FeaturedService } from '@/core/FeaturedService.js'; import { UtilityService } from '@/core/UtilityService.js'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; import Logger from '../logger.js'; const logger = new Logger('hashtag/create'); +type AttachedOrMentioned = 'attached' | 'mentioned'; +type UpdatingHashtagColumn = { + totalUserIds: keyof MiHashtag & `${AttachedOrMentioned}UserIds`, + totalUsersCount: keyof MiHashtag & `${AttachedOrMentioned}UsersCount`, + localUserIds: keyof MiHashtag & `${AttachedOrMentioned}LocalUserIds`, + localUsersCount: keyof MiHashtag & `${AttachedOrMentioned}LocalUsersCount`, + remoteUserIds: keyof MiHashtag & `${AttachedOrMentioned}RemoteUserIds`, + remoteUsersCount: keyof MiHashtag & `${AttachedOrMentioned}RemoteUsersCount`, +}; + @Injectable() export class HashtagService { constructor( @@ -68,126 +77,93 @@ export class HashtagService { // TODO: サンプリング this.updateHashtagsRanking(tag, user.id); - { - const index = await this.hashtagsRepository.findOneBy({ name: tag }); - - if (index == null && inc) { - try { - if (isUserAttached) { - await this.hashtagsRepository.insert({ - id: this.idService.gen(), - name: tag, - mentionedUserIds: [], - mentionedUsersCount: 0, - mentionedLocalUserIds: [], - mentionedLocalUsersCount: 0, - mentionedRemoteUserIds: [], - mentionedRemoteUsersCount: 0, - attachedUserIds: [user.id], - attachedUsersCount: 1, - attachedLocalUserIds: this.userEntityService.isLocalUser(user) ? [user.id] : [], - attachedLocalUsersCount: this.userEntityService.isLocalUser(user) ? 1 : 0, - attachedRemoteUserIds: this.userEntityService.isRemoteUser(user) ? [user.id] : [], - attachedRemoteUsersCount: this.userEntityService.isRemoteUser(user) ? 1 : 0, - } as MiHashtag); - } else { - await this.hashtagsRepository.insert({ - id: this.idService.gen(), - name: tag, - mentionedUserIds: [user.id], - mentionedUsersCount: 1, - mentionedLocalUserIds: this.userEntityService.isLocalUser(user) ? [user.id] : [], - mentionedLocalUsersCount: this.userEntityService.isLocalUser(user) ? 1 : 0, - mentionedRemoteUserIds: this.userEntityService.isRemoteUser(user) ? [user.id] : [], - mentionedRemoteUsersCount: this.userEntityService.isRemoteUser(user) ? 1 : 0, - attachedUserIds: [], - attachedUsersCount: 0, - attachedLocalUserIds: [], - attachedLocalUsersCount: 0, - attachedRemoteUserIds: [], - attachedRemoteUsersCount: 0, - } as MiHashtag); - } - return; - } catch (err) { - if (isDuplicateKeyValueError(err)) { - logger.info(`Duplicate insertion detected. Falling back to update. #${tag}`); - } else { - throw err; - } - } - } + const column: UpdatingHashtagColumn = isUserAttached ? { + totalUserIds: 'attachedUserIds', + totalUsersCount: 'attachedUsersCount', + localUserIds: 'attachedLocalUserIds', + localUsersCount: 'attachedLocalUsersCount', + remoteUserIds: 'attachedRemoteUserIds', + remoteUsersCount: 'attachedRemoteUsersCount', + } : { + totalUserIds: 'mentionedUserIds', + totalUsersCount: 'mentionedUsersCount', + localUserIds: 'mentionedLocalUserIds', + localUsersCount: 'mentionedLocalUsersCount', + remoteUserIds: 'mentionedRemoteUserIds', + remoteUsersCount: 'mentionedRemoteUsersCount', + }; + + if (inc) { + await this.#incrementHashTag(user, tag, column); + } else { + await this.#decrementHashTag(user, tag, column); } + } - await this.db.transaction(async transactionalEntityManager => { - const transactionalHashtagRepository = transactionalEntityManager - .getRepository(MiHashtag); - - const index = await transactionalHashtagRepository - .createQueryBuilder() - .setLock('pessimistic_write') - .where('name = :name', { name: tag }) - .getOne(); - - if (index == null) return; - - const set = {} as any; - - if (isUserAttached) { - if (inc) { - // 自分������タグを使���ら - if (!index.attachedUserIds.some(id => id === user.id)) { - set.attachedUserIds = () => `array_append("attachedUserIds", '${user.id}')`; - set.attachedUsersCount = () => '"attachedUsersCount" + 1'; - } - // 自分�(ローカル内�)�����タグを使���ら - if (this.userEntityService.isLocalUser(user) && !index.attachedLocalUserIds.some(id => id === user.id)) { - set.attachedLocalUserIds = () => `array_append("attachedLocalUserIds", '${user.id}')`; - set.attachedLocalUsersCount = () => '"attachedLocalUsersCount" + 1'; - } - // 自分�(リモート�)�����タグを使���ら - if (this.userEntityService.isRemoteUser(user) && !index.attachedRemoteUserIds.some(id => id === user.id)) { - set.attachedRemoteUserIds = () => `array_append("attachedRemoteUserIds", '${user.id}')`; - set.attachedRemoteUsersCount = () => '"attachedRemoteUsersCount" + 1'; - } - } else { - set.attachedUserIds = () => `array_remove("attachedUserIds", '${user.id}')`; - set.attachedUsersCount = () => '"attachedUsersCount" - 1'; - if (this.userEntityService.isLocalUser(user)) { - set.attachedLocalUserIds = () => `array_remove("attachedLocalUserIds", '${user.id}')`; - set.attachedLocalUsersCount = () => '"attachedLocalUsersCount" - 1'; - } else { - set.attachedRemoteUserIds = () => `array_remove("attachedRemoteUserIds", '${user.id}')`; - set.attachedRemoteUsersCount = () => '"attachedRemoteUsersCount" - 1'; - } - } - } else { - // 自分������タグを使���ら - if (!index.mentionedUserIds.some(id => id === user.id)) { - set.mentionedUserIds = () => `array_append("mentionedUserIds", '${user.id}')`; - set.mentionedUsersCount = () => '"mentionedUsersCount" + 1'; - } - // 自分�(ローカル内�)�����タグを使���ら - if (this.userEntityService.isLocalUser(user) && !index.mentionedLocalUserIds.some(id => id === user.id)) { - set.mentionedLocalUserIds = () => `array_append("mentionedLocalUserIds", '${user.id}')`; - set.mentionedLocalUsersCount = () => '"mentionedLocalUsersCount" + 1'; - } - // 自分�(リモート�)�����タグを使���ら - if (this.userEntityService.isRemoteUser(user) && !index.mentionedRemoteUserIds.some(id => id === user.id)) { - set.mentionedRemoteUserIds = () => `array_append("mentionedRemoteUserIds", '${user.id}')`; - set.mentionedRemoteUsersCount = () => '"mentionedRemoteUsersCount" + 1'; - } - } + async #incrementHashTag( + user: { id: MiUser['id']; host: MiUser['host']; }, + tag: string, + columns: UpdatingHashtagColumn, + ) { + const isLocal = this.userEntityService.isLocalUser(user); + const { totalUserIds, totalUsersCount } = columns; + const localOrRemoteUserIds = isLocal ? columns.localUserIds : columns.remoteUserIds; + const localOrRemoteUserCount = isLocal ? columns.localUsersCount : columns.remoteUsersCount; + + const runner = this.db.createQueryRunner('master'); + try { + await runner.query( + `INSERT into "hashtag"("id", "name", "${totalUserIds}", "${totalUsersCount}", "${localOrRemoteUserIds}", + "${localOrRemoteUserCount}") + VALUES ($3, $1, ARRAY [$2], 1, ARRAY [$2], 1) + ON CONFLICT ("name") + DO UPDATE SET "${totalUserIds}" = ${appendUserIdIfNotExists(totalUserIds)}, + "${totalUsersCount}" = ${incrementCountIfNotExists(totalUserIds, totalUsersCount)}, + "${localOrRemoteUserIds}" = ${appendUserIdIfNotExists(localOrRemoteUserIds)}, + "${localOrRemoteUserCount}" = ${incrementCountIfNotExists(localOrRemoteUserIds, localOrRemoteUserCount)}`, + [tag, user.id, this.idService.gen()], + ); + } finally { + await runner.release(); + } - if (Object.keys(set).length > 0) { - await transactionalHashtagRepository - .createQueryBuilder() - .update() - .where('id = :id', { id: index.id }) - .set(set) - .execute(); - } - }); + function appendUserIdIfNotExists(userIds: keyof MiHashtag & `${string}UserIds`): string { + return `CASE WHEN NOT ("hashtag"."${userIds}" @> ARRAY[$2 ::varchar]) THEN array_append("hashtag"."${userIds}", $2) ELSE "hashtag"."${userIds}" END`; + } + + function incrementCountIfNotExists(userIds: keyof MiHashtag & `${string}UserIds`, userCount: keyof MiHashtag & `${string}UsersCount`): string { + return `CASE WHEN NOT ("hashtag"."${userIds}" @> ARRAY[$2 ::varchar]) THEN "hashtag"."${userCount}" + 1 ELSE "hashtag"."${userCount}" END`; + } + } + + async #decrementHashTag( + user: { id: MiUser['id']; host: MiUser['host']; }, + tag: string, + columns: UpdatingHashtagColumn, + ) { + const isLocal = this.userEntityService.isLocalUser(user); + const { totalUserIds, totalUsersCount } = columns; + const localOrRemoteUserIds = isLocal ? columns.localUserIds : columns.remoteUserIds; + const localOrRemoteUserCount = isLocal ? columns.localUsersCount : columns.remoteUsersCount; + + const runner = this.db.createQueryRunner('master'); + try { + await runner.query( + `UPDATE "hashtag" + SET "${totalUserIds}" = array_remove("${totalUserIds}", $2), + "${totalUsersCount}" = ${decrementIfExists(totalUserIds, totalUsersCount)}, + "${localOrRemoteUserIds}" = array_remove("${localOrRemoteUserIds}", $2), + "${localOrRemoteUserCount}" = ${decrementIfExists(localOrRemoteUserIds, localOrRemoteUserCount)} + WHERE "name" = $1`, + [tag, user.id], + ); + } finally { + await runner.release(); + } + + function decrementIfExists(userIds: keyof MiHashtag & `${string}UserIds`, userCount: keyof MiHashtag & `${string}UsersCount`): string { + return `CASE WHEN ("${userIds}" @> ARRAY[$2]) THEN "${userCount}" - 1 ELSE "${userCount}" END`; + } } @bindThis diff --git a/packages/backend/src/models/Hashtag.ts b/packages/backend/src/models/Hashtag.ts index 3add06d0c38..43013489573 100644 --- a/packages/backend/src/models/Hashtag.ts +++ b/packages/backend/src/models/Hashtag.ts @@ -20,6 +20,7 @@ export class MiHashtag { @Column({ ...id(), + default: [], array: true, }) public mentionedUserIds: MiUser['id'][]; @@ -32,6 +33,7 @@ export class MiHashtag { @Column({ ...id(), + default: [], array: true, }) public mentionedLocalUserIds: MiUser['id'][]; @@ -44,6 +46,7 @@ export class MiHashtag { @Column({ ...id(), + default: [], array: true, }) public mentionedRemoteUserIds: MiUser['id'][]; @@ -56,6 +59,7 @@ export class MiHashtag { @Column({ ...id(), + default: [], array: true, }) public attachedUserIds: MiUser['id'][]; @@ -68,6 +72,7 @@ export class MiHashtag { @Column({ ...id(), + default: [], array: true, }) public attachedLocalUserIds: MiUser['id'][]; @@ -80,6 +85,7 @@ export class MiHashtag { @Column({ ...id(), + default: [], array: true, }) public attachedRemoteUserIds: MiUser['id'][]; From 3e31e59bcd6f084d5e1253fad009323d0098eb58 Mon Sep 17 00:00:00 2001 From: 4ster1sk <146138447+4ster1sk@users.noreply.github.com> Date: Sat, 25 Jul 2026 21:09:12 +0900 Subject: [PATCH 466/578] =?UTF-8?q?fix(backend):=20=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E4=B8=AD=E3=81=AE=E3=83=81=E3=83=A3=E3=83=B3?= =?UTF-8?q?=E3=83=8D=E3=83=AB=E3=82=92=E5=86=8D=E5=BA=A6=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=81=97=E3=81=9F=E9=9A=9B=E3=81=ABALREADY?= =?UTF-8?q?=5FFOLLOWING=E3=82=A8=E3=83=A9=E3=83=BC=E3=82=92=E8=BF=94?= =?UTF-8?q?=E3=81=99=E3=82=88=E3=81=86=E3=81=AB=20(#17802)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test(e2e): フォロー中��ャン�ル��度フォローAPIを���場��テストを追加 * fix(backend): フォロー中��ャン�ルを�度フォロー��際�ALREADY_FOLLOWINGエラーを返�よ�� * docs(changelog): update changelog --- CHANGELOG.md | 1 + .../src/core/ChannelFollowingService.ts | 19 +++++++--- .../server/api/endpoints/channels/follow.ts | 15 +++++++- packages/backend/test/e2e/channel.ts | 36 +++++++++++++++++++ 4 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 packages/backend/test/e2e/channel.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bcf30b6037..aaf2234cc5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,7 @@ - Fix: フォロワー�定投稿��リプライをホーム投稿�出�る�題を修正 - Fix: ファイルをアップロード�るAPI���処�終了後�一時ファイル�削除�れ������る�題を修正 - Fix: �期設定�作���アカウント以外�アカウント作�API�使用�����題を修正 +- Fix: フォロー中��ャン�ルを�度フォロー��際�ALREADY_FOLLOWINGエラーを返�よ�� ## 2026.6.0 diff --git a/packages/backend/src/core/ChannelFollowingService.ts b/packages/backend/src/core/ChannelFollowingService.ts index 7dae8d10f39..54198fdc06c 100644 --- a/packages/backend/src/core/ChannelFollowingService.ts +++ b/packages/backend/src/core/ChannelFollowingService.ts @@ -13,6 +13,8 @@ import { GlobalEvents, GlobalEventService } from '@/core/GlobalEventService.js'; import { bindThis } from '@/decorators.js'; import type { MiLocalUser } from '@/models/User.js'; import { RedisKVCache } from '@/misc/cache.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; @Injectable() export class ChannelFollowingService implements OnModuleInit { @@ -96,11 +98,18 @@ export class ChannelFollowingService implements OnModuleInit { requestUser: MiLocalUser, targetChannel: MiChannel, ): Promise { - await this.channelFollowingsRepository.insert({ - id: this.idService.gen(), - followerId: requestUser.id, - followeeId: targetChannel.id, - }); + try { + await this.channelFollowingsRepository.insert({ + id: this.idService.gen(), + followerId: requestUser.id, + followeeId: targetChannel.id, + }); + } catch (e) { + if (isDuplicateKeyValueError(e)) { + throw new IdentifiableError('6e335e39-0203-4418-a936-b3f2dc987845', 'already following'); + } + throw e; + } this.globalEventService.publishInternalEvent('followChannel', { userId: requestUser.id, diff --git a/packages/backend/src/server/api/endpoints/channels/follow.ts b/packages/backend/src/server/api/endpoints/channels/follow.ts index 1812820ba29..b46552281f4 100644 --- a/packages/backend/src/server/api/endpoints/channels/follow.ts +++ b/packages/backend/src/server/api/endpoints/channels/follow.ts @@ -8,6 +8,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import type { ChannelsRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { ChannelFollowingService } from '@/core/ChannelFollowingService.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -25,6 +26,11 @@ export const meta = { code: 'NO_SUCH_CHANNEL', id: 'c0031718-d573-4e85-928e-10039f1fbb68', }, + alreadyFollowing: { + message: 'You are already following that channel.', + code: 'ALREADY_FOLLOWING', + id: '7db31665-651e-40c1-8e6e-28e9ad829a2d', + }, }, } as const; @@ -52,7 +58,14 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchChannel); } - await this.channelFollowingService.follow(me, channel); + try { + await this.channelFollowingService.follow(me, channel); + } catch (e) { + if (e instanceof IdentifiableError) { + if (e.id === '6e335e39-0203-4418-a936-b3f2dc987845') throw new ApiError(meta.errors.alreadyFollowing); + } + throw e; + } }); } } diff --git a/packages/backend/test/e2e/channel.ts b/packages/backend/test/e2e/channel.ts new file mode 100644 index 00000000000..c2fd98cbf41 --- /dev/null +++ b/packages/backend/test/e2e/channel.ts @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +process.env.NODE_ENV = 'test'; + +import * as assert from 'assert'; +import { describe, beforeAll, test } from 'vitest'; +import { api, castAsError, signup } from '../utils.js'; +import type * as misskey from 'misskey-js'; + +describe('Channel', () => { + let alice: misskey.entities.SignupResponse; + beforeAll(async () => { + alice = await signup({ username: 'alice' }); + }); + + describe('Follow', () => { + let channel: misskey.entities.ChannelsCreateResponse; + + beforeAll(async () => { + const res = await api('channels/create', { name: 'follow-test-channel' }, alice); + channel = res.body; + }); + + test('フォロー���る�ャン�ルを�度フォロー�る�ALREADY_FOLLOWINGエラー��る', async () => { + const res1 = await api('channels/follow', { channelId: channel.id }, alice); + assert.strictEqual(res1.status, 204); + + const res2 = await api('channels/follow', { channelId: channel.id }, alice); + assert.strictEqual(res2.status, 400); + assert.strictEqual(castAsError(res2.body as any).error.code, 'ALREADY_FOLLOWING'); + }); + }); +}); From 1a59ec20e3a917b23d12663e49329ecce1ea8e88 Mon Sep 17 00:00:00 2001 From: chocolate-pie <106949016+chocolate-pie@users.noreply.github.com> Date: Sat, 25 Jul 2026 21:34:46 +0900 Subject: [PATCH 467/578] Merge commit from fork MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Fix improper authorization in `admin/reset-password` * Apply suggestions from code review Co-authored-by: ����り <67428053+kakkokari-gtyih@users.noreply.github.com> * fix: improper authorization in `admin/unset-mfa` * fix --------- Co-authored-by: ����り <67428053+kakkokari-gtyih@users.noreply.github.com> --- .../server/api/endpoints/admin/reset-password.ts | 15 +++++++++------ .../src/server/api/endpoints/admin/unset-mfa.ts | 11 +++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index f19ffa173bc..dc867680447 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -9,7 +9,9 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { ApiError } from '@/server/api/error.js'; import type { UsersRepository, UserProfilesRepository, MiMeta } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; +import { ApiError } from '@/server/api/error.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; +import { RoleService } from '@/core/RoleService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { @@ -25,10 +27,10 @@ export const meta = { code: 'NO_SUCH_USER', id: 'ccafc7fe-5074-4edd-9dc0-8ef9ef6a701d', }, - cannotResetPasswordOfRootUser: { - message: 'Cannot reset password of the root user.', - code: 'CANNOT_RESET_PASSWORD_OF_ROOT_USER', - id: 'f28fc207-42ca-44c7-a577-44b4f0ec5999', + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: 'cda8f8ce-89a6-4f92-8055-33bbe0c1464d', }, }, @@ -66,6 +68,7 @@ export default class extends Endpoint { // eslint- @Inject(DI.userProfilesRepository) private userProfilesRepository: UserProfilesRepository, + private roleService: RoleService, private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { @@ -75,8 +78,8 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchUser); } - if (this.serverSettings.rootUserId === user.id) { - throw new ApiError(meta.errors.cannotResetPasswordOfRootUser); + if (await this.roleService.isAdministrator(user) && me.id !== user.id) { + throw new ApiError(meta.errors.accessDenied); } const passwd = secureRndstr(8); diff --git a/packages/backend/src/server/api/endpoints/admin/unset-mfa.ts b/packages/backend/src/server/api/endpoints/admin/unset-mfa.ts index 3d964825d3b..75b3e3e2bf9 100644 --- a/packages/backend/src/server/api/endpoints/admin/unset-mfa.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-mfa.ts @@ -11,6 +11,7 @@ import { MiUserProfile } from '@/models/UserProfile.js'; import { MiUserSecurityKey } from '@/models/UserSecurityKey.js'; import type { UsersRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; +import { RoleService } from '@/core/RoleService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { @@ -26,6 +27,11 @@ export const meta = { code: 'NO_SUCH_USER', id: 'ccafc7fe-5074-4edd-9dc0-8ef9ef6a701d', }, + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: 'cda8f8ce-89a6-4f92-8055-33bbe0c1464d', + }, }, } as const; @@ -46,6 +52,7 @@ export default class extends Endpoint { // eslint- @Inject(DI.usersRepository) private usersRepository: UsersRepository, + private roleService: RoleService, private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { @@ -55,6 +62,10 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchUser); } + if (await this.roleService.isAdministrator(user) && me.id !== user.id) { + throw new ApiError(meta.errors.accessDenied); + } + await this.db.transaction(async (transactionalEntityManager) => { // パスキーを全�削除 await transactionalEntityManager.delete(MiUserSecurityKey, { userId: user.id }); From daf2a855390949e489e285ba23a926a243b2eaac Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sat, 25 Jul 2026 21:37:20 +0900 Subject: [PATCH 468/578] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aaf2234cc5e..1cb45c9b43f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - Feat: コントロールパ�ル�ら二�素�証を解除��るよ�� - Feat: �件�一致��URLプレビュー�サム�イルを隠������るよ�� (Based on https://github.com/MisskeyIO/misskey/pull/214) +- Enhance: �存関係�更新 ### Client - 2025.4.0 以��設定情報�移行処��削除�れ��� @@ -31,6 +32,7 @@ - Fix: 一部�画�をビューワー�読�込ん�際�正��表示�れ���題を修正 - Enhance: ファイルアップロード��プレビュー��るよ�� - Enhance: タブ��ックグラウンド�間�必���定期更新処�を�止�るよ�� +- Enhance: 翻訳�更新 - Fix: 「画�を新��タブ�開���機能���������題を修正 - Fix: デ�イスタイプをスマートフォン�固定���る状態�画�幅�広����画�左上�アイコン�表示�れ���題を修正 - Fix: �ャット�IME�変�を確定�るEnter�メッセージ��信�れ��������る�題を修正 @@ -72,6 +74,7 @@ - Fix: ファイルをアップロード�るAPI���処�終了後�一時ファイル�削除�れ������る�題を修正 - Fix: �期設定�作���アカウント以外�アカウント作�API�使用�����題を修正 - Fix: フォロー中��ャン�ルを�度フォロー��際�ALREADY_FOLLOWINGエラーを返�よ�� +- Fix: セキュリティ�関�る修正 ## 2026.6.0 From e897255e71dd863fdeb88c01db361669061e9b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 25 Jul 2026 21:43:41 +0900 Subject: [PATCH 469/578] fix --- .../backend/src/server/api/endpoints/admin/reset-password.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index dc867680447..61aed000774 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -9,7 +9,6 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { ApiError } from '@/server/api/error.js'; import type { UsersRepository, UserProfilesRepository, MiMeta } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; -import { ApiError } from '@/server/api/error.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; import { RoleService } from '@/core/RoleService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; From f6979333d40cf3c7df98c72207dea2696be51670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 27 Jul 2026 00:14:34 +0900 Subject: [PATCH 470/578] docs: Update CHANGELOG.md to include about js-yaml changes (#17805) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cb45c9b43f..229e00d2b33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ - Node.js �セキュリティアップデート�伴��最低動作�ージョンを 22.22.2 / 24.17.0 / 26.4.0 �引�上����。 - Docker Image � Node.js 26.4.0-trixie �更新�れ����。 - �ックエンド�画�処��用���るライブラリ sharp �システム�件�変更�より�**SSE4.2 命令セットをサ�ート����� x86_64 CPU �� Misskey �正��動作����り��**。仮想マシン� Misskey をデプロイ���る場�や����ードウェアを�使��場���アップデート���使��環境を�確�����。���ARM64 �� x86_64 ����環境�������変更�よる影響��り��ん。 +- YAMLパーサーをアップデート��より厳格��ェック�行�れるよ���り���。起動時�config�読��り�構文エラー�発生�る�能性��り��。\ + 例�� `allowPrivateNetworks` を 2026.6.0 ��� `example.yml` �構文を元�記述���る場����列�閉�括弧�インデントを上�る��リスト表示�書���る必���り��。詳��� https://github.com/misskey-dev/misskey/pull/17701 を�覧����。 ### General - Feat: コントロールパ�ル�ら二�素�証を解除��るよ�� From cb58ff32a4a4fec6c706ddb8a00b1d74c32cdcab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:48:36 +0900 Subject: [PATCH 471/578] =?UTF-8?q?fix(gh):=20check-misskey-js-autogen?= =?UTF-8?q?=E3=81=8C=E5=A4=B1=E6=95=97=E3=81=99=E3=82=8B=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#17809)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(gh): check-misskey-js-autogen�失敗�る�題を修正 * fix comment * fix --- .../check-misskey-js-autogen.comment.yml | 73 +++++++++++++++++++ .../workflows/check-misskey-js-autogen.yml | 45 +++++------- 2 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 .github/workflows/check-misskey-js-autogen.comment.yml diff --git a/.github/workflows/check-misskey-js-autogen.comment.yml b/.github/workflows/check-misskey-js-autogen.comment.yml new file mode 100644 index 00000000000..0403b0c17ad --- /dev/null +++ b/.github/workflows/check-misskey-js-autogen.comment.yml @@ -0,0 +1,73 @@ +name: Check Misskey JS autogen (comment) + +on: + workflow_run: + types: [completed] + workflows: + - Check Misskey JS autogen # check-misskey-js-autogen.yml + +jobs: + comment-misskey-js-autogen: + runs-on: ubuntu-latest + # No code is cloned or executed here, so it is safe to hold pull-requests: write + if: ${{ github.event.workflow_run.event == 'pull_request' }} + permissions: + actions: read + pull-requests: write + + steps: + # The result is missing when the run failed before the check job (e.g. the PR does not build), so do not fail here + - name: Download result + id: download-result + continue-on-error: true + uses: actions/download-artifact@v8 + with: + name: misskey-js-autogen-result + path: result + github-token: ${{ github.token }} + repository: ${{ github.repository }} + run-id: ${{ github.event.workflow_run.id }} + + # The artifact comes from a run that built fork code, so validate it before using + - name: Load result + id: load-result + if: steps.download-result.outcome == 'success' + run: | + pr_number="$(cat result/pr-number)" + changes="$(cat result/changes)" + + case "$pr_number" in + ''|*[!0-9]*) echo "invalid pr number"; exit 1;; + esac + case "$changes" in + true|false) ;; + *) echo "invalid result"; exit 1;; + esac + + echo "pr-number=$pr_number" >> "$GITHUB_OUTPUT" + echo "changes=$changes" >> "$GITHUB_OUTPUT" + + - name: send message + if: steps.load-result.outputs.changes == 'true' + uses: thollander/actions-comment-pull-request@v3 + with: + pr-number: ${{ steps.load-result.outputs.pr-number }} + comment-tag: check-misskey-js-autogen + message: |- + Thank you for sending us a great Pull Request! � + Please regenerate misskey-js type definitions! � + + example: + ```sh + pnpm run build-misskey-js-with-types + ``` + + - name: send message + if: steps.load-result.outputs.changes == 'false' + uses: thollander/actions-comment-pull-request@v3 + with: + pr-number: ${{ steps.load-result.outputs.pr-number }} + comment-tag: check-misskey-js-autogen + mode: delete + message: "Thank you!" + create_if_not_exists: false diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml index 631daa79c88..518955dae2a 100644 --- a/.github/workflows/check-misskey-js-autogen.yml +++ b/.github/workflows/check-misskey-js-autogen.yml @@ -1,7 +1,8 @@ +# this name is used in check-misskey-js-autogen.comment.yml so be careful when change name name: Check Misskey JS autogen on: - pull_request_target: + pull_request: branches: - master - develop @@ -10,7 +11,6 @@ on: - packages/backend/** jobs: - # pull_request_target safety: permissions: read-all, and there are no secrets used in this job generate-misskey-js: runs-on: ubuntu-latest permissions: @@ -58,7 +58,6 @@ jobs: name: generated-misskey-js path: packages/misskey-js/generator/built/autogen - # pull_request_target safety: permissions: read-all, and no user codes are executed get-actual-misskey-js: runs-on: ubuntu-latest permissions: @@ -78,12 +77,11 @@ jobs: name: actual-misskey-js path: packages/misskey-js/src/autogen - # pull_request_target safety: nothing is cloned from repository - comment-misskey-js-autogen: + check-misskey-js-autogen: runs-on: ubuntu-latest needs: [generate-misskey-js, get-actual-misskey-js] permissions: - pull-requests: write + contents: read steps: - name: download generated-misskey-js uses: actions/download-artifact@v8 @@ -111,28 +109,21 @@ jobs: - name: Print full diff run: cat ./misskey-js.diff - - name: send message - if: steps.check-changes.outputs.changes == 'true' - uses: thollander/actions-comment-pull-request@v3 - with: - comment-tag: check-misskey-js-autogen - message: |- - Thank you for sending us a great Pull Request! � - Please regenerate misskey-js type definitions! � - - example: - ```sh - pnpm run build-misskey-js-with-types - ``` - - - name: send message - if: steps.check-changes.outputs.changes == 'false' - uses: thollander/actions-comment-pull-request@v3 + # A fork's pull_request token cannot comment, so hand the result to check-misskey-js-autogen.comment.yml + - name: Save result + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + CHANGES: ${{ steps.check-changes.outputs.changes }} + run: | + mkdir -p result + echo "$PR_NUMBER" > result/pr-number + echo "$CHANGES" > result/changes + + - name: Upload result + uses: actions/upload-artifact@v7 with: - comment-tag: check-misskey-js-autogen - mode: delete - message: "Thank you!" - create_if_not_exists: false + name: misskey-js-autogen-result + path: result - name: Make failure if changes are detected if: steps.check-changes.outputs.changes == 'true' From 703aa2360b627fa1f5ef4af2bef92ea2a8ad50b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 27 Jul 2026 18:34:31 +0900 Subject: [PATCH 472/578] =?UTF-8?q?enhance(frontend):=20UploaderItems?= =?UTF-8?q?=E3=81=AE=E8=A9=B3=E7=B4=B0=E3=83=A1=E3=83=8B=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E3=81=8B=E3=82=89=E3=82=82=E3=83=97=E3=83=AC=E3=83=93=E3=83=A5?= =?UTF-8?q?=E3=83=BC=E3=82=92=E8=B5=B7=E5=8B=95=E3=81=A7=E3=81=8D=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=20(#17811)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(frontend): UploaderItems�詳細メニュー�らもプレビューを起動��るよ�� * clean up --- .../src/components/MkUploaderItems.vue | 45 ++++--------- .../frontend/src/composables/use-uploader.ts | 64 +++++++++++++++---- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/packages/frontend/src/components/MkUploaderItems.vue b/packages/frontend/src/components/MkUploaderItems.vue index cf92828e2f5..ec7423e9716 100644 --- a/packages/frontend/src/components/MkUploaderItems.vue +++ b/packages/frontend/src/components/MkUploaderItems.vue @@ -49,7 +49,7 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/frontend/src/components/MkLightbox.item.controls.vue b/packages/frontend/src/components/MkLightbox.item.controls.vue new file mode 100644 index 00000000000..e2ac037a671 --- /dev/null +++ b/packages/frontend/src/components/MkLightbox.item.controls.vue @@ -0,0 +1,455 @@ + + + + + + + diff --git a/packages/frontend/src/components/MkLightbox.item.vue b/packages/frontend/src/components/MkLightbox.item.vue index c75c3402a76..1804c89755b 100644 --- a/packages/frontend/src/components/MkLightbox.item.vue +++ b/packages/frontend/src/components/MkLightbox.item.vue @@ -55,7 +55,7 @@ SPDX-License-Identifier: AGPL-3.0-only
    {{ i18n.ts.sensitive }} - {{ content.type === 'image' ? i18n.ts.image : i18n.ts.video }} + {{ contentHideFileText }} {{ i18n.ts.clickToShow }}
    @@ -82,7 +82,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
    +
    +
    + +
    + -
    +
    @@ -118,8 +138,8 @@ SPDX-License-Identifier: AGPL-3.0-only
    -
    - +
    +
    @@ -140,7 +160,7 @@ type Rect = Size & { export type Content = { id: string; - type: 'image' | 'video'; + type: 'image' | 'video' | 'audio'; url: string; thumbnailUrl?: string | null; width?: number | null; @@ -177,9 +197,10 @@ export function calculateSourceTransform({ diff --git a/packages/frontend/src/components/MkMediaBanner.vue b/packages/frontend/src/components/MkMediaBanner.vue index fd86b61b87a..c96e9da058a 100644 --- a/packages/frontend/src/components/MkMediaBanner.vue +++ b/packages/frontend/src/components/MkMediaBanner.vue @@ -5,8 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only