From d8dcad19a338336ec94f4ca7002ba0180a7c4609 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 23 Aug 2024 08:08:33 +0900
Subject: [PATCH] wip

---
 packages/embed/vite.config.local-dev.ts |  96 ++++++
 packages/embed/vite.config.ts           | 190 ++++++++++++
 packages/embed/vite.json5.ts            |  48 +++
 pnpm-lock.yaml                          | 379 ++++++++++++++++++++----
 4 files changed, 656 insertions(+), 57 deletions(-)
 create mode 100644 packages/embed/vite.config.local-dev.ts
 create mode 100644 packages/embed/vite.config.ts
 create mode 100644 packages/embed/vite.json5.ts

diff --git a/packages/embed/vite.config.local-dev.ts b/packages/embed/vite.config.local-dev.ts
new file mode 100644
index 0000000000..85ba03c0ba
--- /dev/null
+++ b/packages/embed/vite.config.local-dev.ts
@@ -0,0 +1,96 @@
+import dns from 'dns';
+import { readFile } from 'node:fs/promises';
+import type { IncomingMessage } from 'node:http';
+import { defineConfig } from 'vite';
+import type { UserConfig } from 'vite';
+import * as yaml from 'js-yaml';
+import locales from '../../locales/index.js';
+import { getConfig } from './vite.config.js';
+
+dns.setDefaultResultOrder('ipv4first');
+
+const defaultConfig = getConfig();
+
+const { port } = yaml.load(await readFile('../../.config/default.yml', 'utf-8'));
+
+const httpUrl = `http://localhost:${port}/`;
+const websocketUrl = `ws://localhost:${port}/`;
+
+// activitypubリクエストはProxyを通し、それ以外はViteの開発サーバーを返す
+function varyHandler(req: IncomingMessage) {
+	if (req.headers.accept?.includes('application/activity+json')) {
+		return null;
+	}
+	return '/index.html';
+}
+
+const devConfig: UserConfig = {
+	// 基本の設定は vite.config.js から引き継ぐ
+	...defaultConfig,
+	root: 'src',
+	publicDir: '../assets',
+	base: './',
+	server: {
+		host: 'localhost',
+		port: 5173,
+		proxy: {
+			'/api': {
+				changeOrigin: true,
+				target: httpUrl,
+			},
+			'/assets': httpUrl,
+			'/static-assets': httpUrl,
+			'/client-assets': httpUrl,
+			'/files': httpUrl,
+			'/twemoji': httpUrl,
+			'/fluent-emoji': httpUrl,
+			'/sw.js': httpUrl,
+			'/streaming': {
+				target: websocketUrl,
+				ws: true,
+			},
+			'/favicon.ico': httpUrl,
+			'/robots.txt': httpUrl,
+			'/embed.js': httpUrl,
+			'/identicon': {
+				target: httpUrl,
+				rewrite(path) {
+					return path.replace('@localhost:5173', '');
+				},
+			},
+			'/url': httpUrl,
+			'/proxy': httpUrl,
+			'/_info_card_': httpUrl,
+			'/bios': httpUrl,
+			'/cli': httpUrl,
+			'/inbox': httpUrl,
+			'/emoji/': httpUrl,
+			'/notes': {
+				target: httpUrl,
+				bypass: varyHandler,
+			},
+			'/users': {
+				target: httpUrl,
+				bypass: varyHandler,
+			},
+			'/.well-known': {
+				target: httpUrl,
+			},
+		},
+	},
+	build: {
+		...defaultConfig.build,
+		rollupOptions: {
+			...defaultConfig.build?.rollupOptions,
+			input: 'index.html',
+		},
+	},
+
+	define: {
+		...defaultConfig.define,
+		_LANGS_FULL_: JSON.stringify(Object.entries(locales)),
+	},
+};
+
+export default defineConfig(({ command, mode }) => devConfig);
+
diff --git a/packages/embed/vite.config.ts b/packages/embed/vite.config.ts
new file mode 100644
index 0000000000..20b9ac14b7
--- /dev/null
+++ b/packages/embed/vite.config.ts
@@ -0,0 +1,190 @@
+import path from 'path';
+import pluginReplace from '@rollup/plugin-replace';
+import pluginVue from '@vitejs/plugin-vue';
+import { type UserConfig, defineConfig } from 'vite';
+
+import locales from '../../locales/index.js';
+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';
+
+const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue'];
+
+/**
+ * Misskeyのフロントエンドにバンドルせず、CDNなどから別途読み込むリソースを記述する。
+ * CDNを使わずにバンドルしたい場合、以下の配列から該当要素を削除orコメントアウトすればOK
+ */
+const externalPackages = [
+	// shiki(コードブロックのシンタックスハイライトで使用中)はテーマ・言語の定義の容量が大きいため、それらはCDNから読み込む
+	{
+		name: 'shiki',
+		match: /^shiki\/(?<subPkg>(langs|themes))$/,
+		path(id: string, pattern: RegExp): string {
+			const match = pattern.exec(id)?.groups;
+			return match
+				? `https://esm.sh/shiki@${packageInfo.dependencies.shiki}/${match['subPkg']}`
+				: id;
+		},
+	},
+];
+
+const hash = (str: string, seed = 0): number => {
+	let h1 = 0xdeadbeef ^ seed,
+		h2 = 0x41c6ce57 ^ seed;
+	for (let i = 0, ch; i < str.length; i++) {
+		ch = str.charCodeAt(i);
+		h1 = Math.imul(h1 ^ ch, 2654435761);
+		h2 = Math.imul(h2 ^ ch, 1597334677);
+	}
+
+	h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
+	h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
+
+	return 4294967296 * (2097151 & h2) + (h1 >>> 0);
+};
+
+const BASE62_DIGITS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+
+function toBase62(n: number): string {
+	if (n === 0) {
+		return '0';
+	}
+	let result = '';
+	while (n > 0) {
+		result = BASE62_DIGITS[n % BASE62_DIGITS.length] + result;
+		n = Math.floor(n / BASE62_DIGITS.length);
+	}
+
+	return result;
+}
+
+export function getConfig(): UserConfig {
+	return {
+		base: '/vite/',
+
+		server: {
+			port: 5173,
+		},
+
+		plugins: [
+			pluginVue(),
+			pluginUnwindCssModuleClassName(),
+			pluginJson5(),
+			...process.env.NODE_ENV === 'production'
+				? [
+					pluginReplace({
+						preventAssignment: true,
+						values: {
+							'isChromatic()': JSON.stringify(false),
+						},
+					}),
+				]
+				: [],
+		],
+
+		resolve: {
+			extensions,
+			alias: {
+				'@/': __dirname + '/src/',
+				'/client-assets/': __dirname + '/assets/',
+				'/static-assets/': __dirname + '/../backend/assets/',
+				'/fluent-emojis/': __dirname + '/../../fluent-emojis/dist/',
+				'/fluent-emoji/': __dirname + '/../../fluent-emojis/dist/',
+			},
+		},
+
+		css: {
+			modules: {
+				generateScopedName(name, filename, _css): string {
+					const id = (path.relative(__dirname, filename.split('?')[0]) + '-' + name).replace(/[\\\/\.\?&=]/g, '-').replace(/(src-|vue-)/g, '');
+					if (process.env.NODE_ENV === 'production') {
+						return 'x' + toBase62(hash(id)).substring(0, 4);
+					} else {
+						return id;
+					}
+				},
+			},
+		},
+
+		define: {
+			_VERSION_: JSON.stringify(meta.version),
+			_LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]) => [k, v._lang_])),
+			_ENV_: JSON.stringify(process.env.NODE_ENV),
+			_DEV_: process.env.NODE_ENV !== 'production',
+			_PERF_PREFIX_: JSON.stringify('Misskey:'),
+			_DATA_TRANSFER_DRIVE_FILE_: JSON.stringify('mk_drive_file'),
+			_DATA_TRANSFER_DRIVE_FOLDER_: JSON.stringify('mk_drive_folder'),
+			_DATA_TRANSFER_DECK_COLUMN_: JSON.stringify('mk_deck_column'),
+			__VUE_OPTIONS_API__: true,
+			__VUE_PROD_DEVTOOLS__: false,
+		},
+
+		build: {
+			target: [
+				'chrome116',
+				'firefox116',
+				'safari16',
+			],
+			manifest: 'manifest.json',
+			rollupOptions: {
+				input: {
+					app: './src/_boot_.ts',
+					embedApp: './src/_embed_boot_.ts',
+				},
+				external: externalPackages.map(p => p.match),
+				output: {
+					manualChunks: {
+						vue: ['vue'],
+						photoswipe: ['photoswipe', 'photoswipe/lightbox', 'photoswipe/style.css'],
+					},
+					chunkFileNames: process.env.NODE_ENV === 'production' ? '[hash:8].js' : '[name]-[hash:8].js',
+					assetFileNames: process.env.NODE_ENV === 'production' ? '[hash:8][extname]' : '[name]-[hash:8][extname]',
+					paths(id) {
+						for (const p of externalPackages) {
+							if (p.match.test(id)) {
+								return p.path(id, p.match);
+							}
+						}
+
+						return id;
+					},
+				},
+			},
+			cssCodeSplit: true,
+			outDir: __dirname + '/../../built/_vite_',
+			assetsDir: '.',
+			emptyOutDir: false,
+			sourcemap: process.env.NODE_ENV === 'development',
+			reportCompressedSize: false,
+
+			// https://vitejs.dev/guide/dep-pre-bundling.html#monorepos-and-linked-dependencies
+			commonjsOptions: {
+				include: [/misskey-js/, /misskey-reversi/, /misskey-bubble-game/, /node_modules/],
+			},
+		},
+
+		worker: {
+			format: 'es',
+		},
+
+		test: {
+			environment: 'happy-dom',
+			deps: {
+				optimizer: {
+					web: {
+						include: [
+							// XXX: misskey-dev/browser-image-resizer has no "type": "module"
+							'browser-image-resizer',
+						],
+					},
+				},
+			},
+			includeSource: ['src/**/*.ts'],
+		},
+	};
+}
+
+const config = defineConfig(({ command, mode }) => getConfig());
+
+export default config;
diff --git a/packages/embed/vite.json5.ts b/packages/embed/vite.json5.ts
new file mode 100644
index 0000000000..87b67c2142
--- /dev/null
+++ b/packages/embed/vite.json5.ts
@@ -0,0 +1,48 @@
+// Original: https://github.com/rollup/plugins/tree/8835dd2aed92f408d7dc72d7cc25a9728e16face/packages/json
+
+import JSON5 from 'json5';
+import { Plugin } from 'rollup';
+import { createFilter, dataToEsm } from '@rollup/pluginutils';
+import { RollupJsonOptions } from '@rollup/plugin-json';
+
+// json5 extends SyntaxError with additional fields (without subclassing)
+// https://github.com/json5/json5/blob/de344f0619bda1465a6e25c76f1c0c3dda8108d9/lib/parse.js#L1111-L1112
+interface Json5SyntaxError extends SyntaxError {
+	lineNumber: number;
+	columnNumber: number;
+}
+
+export default function json5(options: RollupJsonOptions = {}): Plugin {
+	const filter = createFilter(options.include, options.exclude);
+	const indent = 'indent' in options ? options.indent : '\t';
+
+	return {
+		name: 'json5',
+
+		// eslint-disable-next-line no-shadow
+		transform(json, id) {
+			if (id.slice(-6) !== '.json5' || !filter(id)) return null;
+
+			try {
+				const parsed = JSON5.parse(json);
+				return {
+					code: dataToEsm(parsed, {
+						preferConst: options.preferConst,
+						compact: options.compact,
+						namedExports: options.namedExports,
+						indent,
+					}),
+					map: { mappings: '' },
+				};
+			} catch (err) {
+				if (!(err instanceof SyntaxError)) {
+					throw err;
+				}
+				const message = 'Could not parse JSON5 file';
+				const { lineNumber, columnNumber } = err as Json5SyntaxError;
+				this.warn({ message, id, loc: { line: lineNumber, column: columnNumber } });
+				return null;
+			}
+		},
+	};
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 71ce6f6c63..4db21a0bd7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -686,6 +686,214 @@ importers:
         specifier: 5.1.0
         version: 5.1.0
 
+  packages/embed:
+    dependencies:
+      '@discordapp/twemoji':
+        specifier: 15.0.3
+        version: 15.0.3
+      '@github/webauthn-json':
+        specifier: 2.1.1
+        version: 2.1.1
+      '@rollup/plugin-json':
+        specifier: 6.1.0
+        version: 6.1.0(rollup@4.19.1)
+      '@rollup/plugin-replace':
+        specifier: 5.0.7
+        version: 5.0.7(rollup@4.19.1)
+      '@rollup/pluginutils':
+        specifier: 5.1.0
+        version: 5.1.0(rollup@4.19.1)
+      '@tabler/icons-webfont':
+        specifier: 3.3.0
+        version: 3.3.0
+      '@twemoji/parser':
+        specifier: 15.1.1
+        version: 15.1.1
+      '@vitejs/plugin-vue':
+        specifier: 5.1.0
+        version: 5.1.0(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))(vue@3.4.37(typescript@5.5.4))
+      '@vue/compiler-sfc':
+        specifier: 3.4.37
+        version: 3.4.37
+      aiscript-vscode:
+        specifier: github:aiscript-dev/aiscript-vscode#v0.1.11
+        version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9
+      astring:
+        specifier: 1.8.6
+        version: 1.8.6
+      buraha:
+        specifier: 0.0.1
+        version: 0.0.1
+      compare-versions:
+        specifier: 6.1.1
+        version: 6.1.1
+      date-fns:
+        specifier: 2.30.0
+        version: 2.30.0
+      escape-regexp:
+        specifier: 0.0.1
+        version: 0.0.1
+      estree-walker:
+        specifier: 3.0.3
+        version: 3.0.3
+      eventemitter3:
+        specifier: 5.0.1
+        version: 5.0.1
+      idb-keyval:
+        specifier: 6.2.1
+        version: 6.2.1
+      is-file-animated:
+        specifier: 1.0.2
+        version: 1.0.2
+      json5:
+        specifier: 2.2.3
+        version: 2.2.3
+      mfm-js:
+        specifier: 0.24.0
+        version: 0.24.0
+      misskey-js:
+        specifier: workspace:*
+        version: link:../misskey-js
+      punycode:
+        specifier: 2.3.1
+        version: 2.3.1
+      rollup:
+        specifier: 4.19.1
+        version: 4.19.1
+      sanitize-html:
+        specifier: 2.13.0
+        version: 2.13.0
+      sass:
+        specifier: 1.77.8
+        version: 1.77.8
+      shiki:
+        specifier: 1.12.0
+        version: 1.12.0
+      strict-event-emitter-types:
+        specifier: 2.0.0
+        version: 2.0.0
+      throttle-debounce:
+        specifier: 5.0.2
+        version: 5.0.2
+      tinycolor2:
+        specifier: 1.6.0
+        version: 1.6.0
+      tsc-alias:
+        specifier: 1.8.10
+        version: 1.8.10
+      tsconfig-paths:
+        specifier: 4.2.0
+        version: 4.2.0
+      typescript:
+        specifier: 5.5.4
+        version: 5.5.4
+      uuid:
+        specifier: 10.0.0
+        version: 10.0.0
+      vite:
+        specifier: 5.3.5
+        version: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
+      vue:
+        specifier: 3.4.37
+        version: 3.4.37(typescript@5.5.4)
+    devDependencies:
+      '@misskey-dev/summaly':
+        specifier: 5.1.0
+        version: 5.1.0
+      '@testing-library/vue':
+        specifier: 8.1.0
+        version: 8.1.0(@vue/compiler-sfc@3.4.37)(@vue/server-renderer@3.4.37(vue@3.4.37(typescript@5.5.4)))(vue@3.4.37(typescript@5.5.4))
+      '@types/escape-regexp':
+        specifier: 0.0.3
+        version: 0.0.3
+      '@types/estree':
+        specifier: 1.0.5
+        version: 1.0.5
+      '@types/micromatch':
+        specifier: 4.0.9
+        version: 4.0.9
+      '@types/node':
+        specifier: 20.14.12
+        version: 20.14.12
+      '@types/punycode':
+        specifier: 2.1.4
+        version: 2.1.4
+      '@types/sanitize-html':
+        specifier: 2.11.0
+        version: 2.11.0
+      '@types/throttle-debounce':
+        specifier: 5.0.2
+        version: 5.0.2
+      '@types/tinycolor2':
+        specifier: 1.4.6
+        version: 1.4.6
+      '@types/uuid':
+        specifier: 10.0.0
+        version: 10.0.0
+      '@types/ws':
+        specifier: 8.5.11
+        version: 8.5.11
+      '@typescript-eslint/eslint-plugin':
+        specifier: 7.17.0
+        version: 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4)
+      '@typescript-eslint/parser':
+        specifier: 7.17.0
+        version: 7.17.0(eslint@9.8.0)(typescript@5.5.4)
+      '@vitest/coverage-v8':
+        specifier: 1.6.0
+        version: 1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.3))
+      '@vue/runtime-core':
+        specifier: 3.4.37
+        version: 3.4.37
+      acorn:
+        specifier: 8.12.1
+        version: 8.12.1
+      cross-env:
+        specifier: 7.0.3
+        version: 7.0.3
+      eslint-plugin-import:
+        specifier: 2.29.1
+        version: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)
+      eslint-plugin-vue:
+        specifier: 9.27.0
+        version: 9.27.0(eslint@9.8.0)
+      fast-glob:
+        specifier: 3.3.2
+        version: 3.3.2
+      happy-dom:
+        specifier: 10.0.3
+        version: 10.0.3
+      intersection-observer:
+        specifier: 0.12.2
+        version: 0.12.2
+      micromatch:
+        specifier: 4.0.7
+        version: 4.0.7
+      msw:
+        specifier: 2.3.4
+        version: 2.3.4(typescript@5.5.4)
+      nodemon:
+        specifier: 3.1.4
+        version: 3.1.4
+      prettier:
+        specifier: 3.3.3
+        version: 3.3.3
+      start-server-and-test:
+        specifier: 2.0.4
+        version: 2.0.4
+      vite-plugin-turbosnap:
+        specifier: 1.0.3
+        version: 1.0.3
+      vue-component-type-helpers:
+        specifier: 2.0.29
+        version: 2.0.29
+      vue-eslint-parser:
+        specifier: 9.4.3
+        version: 9.4.3(eslint@9.8.0)
+      vue-tsc:
+        specifier: 2.0.29
+        version: 2.0.29(typescript@5.5.4)
+
   packages/frontend:
     dependencies:
       '@discordapp/twemoji':
@@ -5386,9 +5594,6 @@ packages:
   '@vue/compiler-core@3.4.37':
     resolution: {integrity: sha512-ZDDT/KiLKuCRXyzWecNzC5vTcubGz4LECAtfGPENpo0nrmqJHwuWtRLxk/Sb9RAKtR9iFflFycbkjkY+W/PZUQ==}
 
-  '@vue/compiler-dom@3.4.34':
-    resolution: {integrity: sha512-3PUOTS1h5cskdOJMExCu2TInXuM0j60DRPpSCJDqOCupCfUZCJoyQmKtRmA8EgDNZ5kcEE7vketamRZfrEuVDw==}
-
   '@vue/compiler-dom@3.4.37':
     resolution: {integrity: sha512-rIiSmL3YrntvgYV84rekAtU/xfogMUJIclUMeIKEtVBFngOL3IeZHhsH3UaFEgB5iFGpj6IW+8YuM/2Up+vVag==}
 
@@ -6985,10 +7190,6 @@ packages:
     engines: {node: '>=4'}
     hasBin: true
 
-  esquery@1.4.2:
-    resolution: {integrity: sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==}
-    engines: {node: '>=0.10'}
-
   esquery@1.6.0:
     resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
     engines: {node: '>=0.10'}
@@ -9198,10 +9399,6 @@ packages:
     resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
     engines: {node: '>=10'}
 
-  normalize-url@8.0.0:
-    resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==}
-    engines: {node: '>=14.16'}
-
   normalize-url@8.0.1:
     resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==}
     engines: {node: '>=14.16'}
@@ -9837,10 +10034,6 @@ packages:
   postcss-value-parser@4.2.0:
     resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
 
-  postcss@8.4.38:
-    resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
-    engines: {node: ^10 || ^12 || >=14}
-
   postcss@8.4.40:
     resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==}
     engines: {node: ^10 || ^12 || >=14}
@@ -11909,8 +12102,8 @@ snapshots:
 
   '@ampproject/remapping@2.2.1':
     dependencies:
-      '@jridgewell/gen-mapping': 0.3.2
-      '@jridgewell/trace-mapping': 0.3.18
+      '@jridgewell/gen-mapping': 0.3.5
+      '@jridgewell/trace-mapping': 0.3.25
 
   '@apidevtools/openapi-schemas@2.1.0': {}
 
@@ -12435,7 +12628,7 @@ snapshots:
   '@babel/code-frame@7.24.7':
     dependencies:
       '@babel/highlight': 7.24.7
-      picocolors: 1.0.0
+      picocolors: 1.0.1
 
   '@babel/compat-data@7.23.5': {}
 
@@ -12710,7 +12903,7 @@ snapshots:
       '@babel/helper-validator-identifier': 7.24.7
       chalk: 2.4.2
       js-tokens: 4.0.0
-      picocolors: 1.0.0
+      picocolors: 1.0.1
 
   '@babel/parser@7.24.7':
     dependencies:
@@ -13390,7 +13583,7 @@ snapshots:
 
   '@babel/template@7.22.15':
     dependencies:
-      '@babel/code-frame': 7.23.5
+      '@babel/code-frame': 7.24.7
       '@babel/parser': 7.24.7
       '@babel/types': 7.24.7
 
@@ -13408,7 +13601,7 @@ snapshots:
 
   '@babel/traverse@7.23.5':
     dependencies:
-      '@babel/code-frame': 7.23.5
+      '@babel/code-frame': 7.24.7
       '@babel/generator': 7.23.5
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-function-name': 7.23.0
@@ -14303,7 +14496,7 @@ snapshots:
 
   '@jest/source-map@29.6.3':
     dependencies:
-      '@jridgewell/trace-mapping': 0.3.18
+      '@jridgewell/trace-mapping': 0.3.25
       callsites: 3.1.0
       graceful-fs: 4.2.11
 
@@ -16527,7 +16720,7 @@ snapshots:
 
   '@testing-library/dom@9.3.4':
     dependencies:
-      '@babel/code-frame': 7.23.5
+      '@babel/code-frame': 7.24.7
       '@babel/runtime': 7.23.4
       '@types/aria-query': 5.0.1
       aria-query: 5.1.3
@@ -17238,14 +17431,14 @@ snapshots:
     dependencies:
       '@ampproject/remapping': 2.2.1
       '@bcoe/v8-coverage': 0.2.3
-      debug: 4.3.4(supports-color@5.5.0)
+      debug: 4.3.5(supports-color@8.1.1)
       istanbul-lib-coverage: 3.2.2
       istanbul-lib-report: 3.0.1
       istanbul-lib-source-maps: 5.0.4
       istanbul-reports: 3.1.6
       magic-string: 0.30.10
       magicast: 0.3.4
-      picocolors: 1.0.0
+      picocolors: 1.0.1
       std-env: 3.7.0
       strip-literal: 2.1.0
       test-exclude: 6.0.0
@@ -17253,6 +17446,25 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.3))':
+    dependencies:
+      '@ampproject/remapping': 2.2.1
+      '@bcoe/v8-coverage': 0.2.3
+      debug: 4.3.5(supports-color@8.1.1)
+      istanbul-lib-coverage: 3.2.2
+      istanbul-lib-report: 3.0.1
+      istanbul-lib-source-maps: 5.0.4
+      istanbul-reports: 3.1.6
+      magic-string: 0.30.10
+      magicast: 0.3.4
+      picocolors: 1.0.1
+      std-env: 3.7.0
+      strip-literal: 2.1.0
+      test-exclude: 6.0.0
+      vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.3)
+    transitivePeerDependencies:
+      - supports-color
+
   '@vitest/expect@1.6.0':
     dependencies:
       '@vitest/spy': 1.6.0
@@ -17331,11 +17543,6 @@ snapshots:
       estree-walker: 2.0.2
       source-map-js: 1.2.0
 
-  '@vue/compiler-dom@3.4.34':
-    dependencies:
-      '@vue/compiler-core': 3.4.34
-      '@vue/shared': 3.4.34
-
   '@vue/compiler-dom@3.4.37':
     dependencies:
       '@vue/compiler-core': 3.4.37
@@ -17368,8 +17575,8 @@ snapshots:
   '@vue/language-core@2.0.16(typescript@5.5.4)':
     dependencies:
       '@volar/language-core': 2.2.0
-      '@vue/compiler-dom': 3.4.34
-      '@vue/shared': 3.4.34
+      '@vue/compiler-dom': 3.4.37
+      '@vue/shared': 3.4.37
       computeds: 0.0.1
       minimatch: 9.0.4
       path-browserify: 1.0.1
@@ -17380,9 +17587,9 @@ snapshots:
   '@vue/language-core@2.0.29(typescript@5.5.4)':
     dependencies:
       '@volar/language-core': 2.4.0-alpha.18
-      '@vue/compiler-dom': 3.4.34
+      '@vue/compiler-dom': 3.4.37
       '@vue/compiler-vue2': 2.7.16
-      '@vue/shared': 3.4.34
+      '@vue/shared': 3.4.37
       computeds: 0.0.1
       minimatch: 9.0.4
       muggle-string: 0.4.1
@@ -18076,7 +18283,7 @@ snapshots:
       http-cache-semantics: 4.1.1
       keyv: 4.5.4
       mimic-response: 4.0.0
-      normalize-url: 8.0.0
+      normalize-url: 8.0.1
       responselike: 3.0.0
 
   cacheable-request@12.0.1:
@@ -18688,6 +18895,12 @@ snapshots:
     optionalDependencies:
       supports-color: 5.5.0
 
+  debug@4.3.5(supports-color@5.5.0):
+    dependencies:
+      ms: 2.1.2
+    optionalDependencies:
+      supports-color: 5.5.0
+
   debug@4.3.5(supports-color@8.1.1):
     dependencies:
       ms: 2.1.2
@@ -19290,10 +19503,6 @@ snapshots:
 
   esprima@4.0.1: {}
 
-  esquery@1.4.2:
-    dependencies:
-      estraverse: 5.3.0
-
   esquery@1.6.0:
     dependencies:
       estraverse: 5.3.0
@@ -21008,6 +21217,35 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  jsdom@24.1.1:
+    dependencies:
+      cssstyle: 4.0.1
+      data-urls: 5.0.0
+      decimal.js: 10.4.3
+      form-data: 4.0.0
+      html-encoding-sniffer: 4.0.0
+      http-proxy-agent: 7.0.2
+      https-proxy-agent: 7.0.5
+      is-potential-custom-element-name: 1.0.1
+      nwsapi: 2.2.12
+      parse5: 7.1.2
+      rrweb-cssom: 0.7.1
+      saxes: 6.0.0
+      symbol-tree: 3.2.4
+      tough-cookie: 4.1.4
+      w3c-xmlserializer: 5.0.0
+      webidl-conversions: 7.0.0
+      whatwg-encoding: 3.1.1
+      whatwg-mimetype: 4.0.0
+      whatwg-url: 14.0.0
+      ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+      xml-name-validator: 5.0.0
+    transitivePeerDependencies:
+      - bufferutil
+      - supports-color
+      - utf-8-validate
+    optional: true
+
   jsdom@24.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3):
     dependencies:
       cssstyle: 4.0.1
@@ -22066,7 +22304,7 @@ snapshots:
   nodemon@3.1.4:
     dependencies:
       chokidar: 3.5.3
-      debug: 4.3.4(supports-color@5.5.0)
+      debug: 4.3.5(supports-color@5.5.0)
       ignore-by-default: 1.0.1
       minimatch: 3.1.2
       pstree.remy: 1.1.8
@@ -22113,8 +22351,6 @@ snapshots:
 
   normalize-url@6.1.0: {}
 
-  normalize-url@8.0.0: {}
-
   normalize-url@8.0.1: {}
 
   npm-run-path@2.0.2:
@@ -22727,12 +22963,6 @@ snapshots:
 
   postcss-value-parser@4.2.0: {}
 
-  postcss@8.4.38:
-    dependencies:
-      nanoid: 3.3.7
-      picocolors: 1.0.0
-      source-map-js: 1.2.0
-
   postcss@8.4.40:
     dependencies:
       nanoid: 3.3.7
@@ -23399,7 +23629,7 @@ snapshots:
       htmlparser2: 8.0.1
       is-plain-object: 5.0.0
       parse-srcset: 1.0.2
-      postcss: 8.4.38
+      postcss: 8.4.40
 
   sass@1.77.8:
     dependencies:
@@ -23968,7 +24198,7 @@ snapshots:
       css-tree: 2.3.1
       css-what: 6.1.0
       csso: 5.0.5
-      picocolors: 1.0.0
+      picocolors: 1.0.1
 
   symbol-tree@3.2.4: {}
 
@@ -24391,13 +24621,13 @@ snapshots:
     dependencies:
       browserslist: 4.22.2
       escalade: 3.1.1
-      picocolors: 1.0.0
+      picocolors: 1.0.1
 
   update-browserslist-db@1.0.13(browserslist@4.23.0):
     dependencies:
       browserslist: 4.23.0
       escalade: 3.1.1
-      picocolors: 1.0.0
+      picocolors: 1.0.1
 
   uri-js@4.4.1:
     dependencies:
@@ -24449,7 +24679,7 @@ snapshots:
 
   v8-to-istanbul@9.2.0:
     dependencies:
-      '@jridgewell/trace-mapping': 0.3.18
+      '@jridgewell/trace-mapping': 0.3.25
       '@types/istanbul-lib-coverage': 2.0.4
       convert-source-map: 2.0.0
 
@@ -24482,7 +24712,7 @@ snapshots:
       cac: 6.7.14
       debug: 4.3.5(supports-color@8.1.1)
       pathe: 1.1.2
-      picocolors: 1.0.0
+      picocolors: 1.0.1
       vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
     transitivePeerDependencies:
       - '@types/node'
@@ -24549,6 +24779,41 @@ snapshots:
       - supports-color
       - terser
 
+  vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.3):
+    dependencies:
+      '@vitest/expect': 1.6.0
+      '@vitest/runner': 1.6.0
+      '@vitest/snapshot': 1.6.0
+      '@vitest/spy': 1.6.0
+      '@vitest/utils': 1.6.0
+      acorn-walk: 8.3.2
+      chai: 4.3.10
+      debug: 4.3.4(supports-color@5.5.0)
+      execa: 8.0.1
+      local-pkg: 0.5.0
+      magic-string: 0.30.10
+      pathe: 1.1.2
+      picocolors: 1.0.0
+      std-env: 3.7.0
+      strip-literal: 2.1.0
+      tinybench: 2.6.0
+      tinypool: 0.8.4
+      vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
+      vite-node: 1.6.0(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
+      why-is-node-running: 2.2.2
+    optionalDependencies:
+      '@types/node': 20.14.12
+      happy-dom: 10.0.3
+      jsdom: 24.1.1
+    transitivePeerDependencies:
+      - less
+      - lightningcss
+      - sass
+      - stylus
+      - sugarss
+      - supports-color
+      - terser
+
   void-elements@3.1.0: {}
 
   vscode-jsonrpc@8.2.0: {}
@@ -24597,7 +24862,7 @@ snapshots:
     dependencies:
       '@babel/parser': 7.24.7
       '@babel/types': 7.24.7
-      '@vue/compiler-dom': 3.4.34
+      '@vue/compiler-dom': 3.4.37
       '@vue/compiler-sfc': 3.4.37
       ast-types: 0.16.1
       hash-sum: 2.0.0
@@ -24610,12 +24875,12 @@ snapshots:
 
   vue-eslint-parser@9.4.3(eslint@9.8.0):
     dependencies:
-      debug: 4.3.4(supports-color@5.5.0)
+      debug: 4.3.5(supports-color@8.1.1)
       eslint: 9.8.0
       eslint-scope: 7.2.2
       eslint-visitor-keys: 3.4.3
       espree: 9.6.1
-      esquery: 1.4.2
+      esquery: 1.6.0
       lodash: 4.17.21
       semver: 7.6.0
     transitivePeerDependencies: