detached 2b8397d

Merge pull request #1 from pdraim/staging

v0.2.0: Major text formatting, validation, and UI enhancement release
commit
2b8397da172d7a4e3ef092aea89ac26d5a1aa786
author
pdraim · · 2025-07-03 20:18 UTC
committer
GitHub · · 2025-07-03 20:18 UTC
merge of
d5464c3 + 1301099 · diff against the first parent
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
54 files · +6288 -1121
M .gitignore +3 -1
@@ -22,4 +22,6 @@ Thumbs.db
2222 vite.config.js.timestamp-*
2323 vite.config.ts.timestamp-*
2424
25-docs/⏎̸
25+docs/
26+
27+.serena/⏎̸
M package.json +35 -26
@@ -1,7 +1,7 @@
11 {
22 "name": "pdraim",
33 "private": true,
4- "version": "0.1.5",
4+ "version": "0.2.0",
55 "type": "module",
66 "engines": {
77 "node": ">=22.13.0"
@@ -19,44 +19,53 @@
1919 "test": "npm run test:unit -- --run",
2020 "db:generate": "npx drizzle-kit generate",
2121 "db:push": "npx drizzle-kit push",
22+ "db:push-prod": "bash -c 'source .env && TURSO_DATABASE_URL=\"$TURSO_DATABASE_URL_PROD\" TURSO_AUTH_TOKEN=\"$TURSO_AUTH_TOKEN_PROD\" npx drizzle-kit push'",
2223 "db:flush": "tsx utils/db-flush.ts"
2324 },
2425 "devDependencies": {
25- "@eslint/compat": "^1.2.6",
26- "@eslint/js": "^9.20.0",
27- "@sveltejs/adapter-cloudflare": "^5.0.3",
28- "@sveltejs/kit": "^2.17.2",
29- "@sveltejs/vite-plugin-svelte": "^5.0.3",
26+ "@eslint/compat": "^1.3.1",
27+ "@eslint/js": "^9.30.1",
28+ "@sveltejs/adapter-cloudflare": "^5.1.0",
29+ "@sveltejs/kit": "^2.22.2",
30+ "@sveltejs/vite-plugin-svelte": "^5.1.0",
3031 "@tailwindcss/container-queries": "^0.1.1",
3132 "@tailwindcss/forms": "^0.5.10",
3233 "@tailwindcss/typography": "^0.5.16",
33- "@types/node": "^22.13.4",
34- "autoprefixer": "^10.4.20",
35- "drizzle-kit": "^0.30.4",
36- "eslint": "^9.20.1",
37- "eslint-config-prettier": "^10.0.1",
34+ "@types/node": "^22.16.0",
35+ "autoprefixer": "^10.4.21",
36+ "drizzle-kit": "^0.30.6",
37+ "eslint": "^9.30.1",
38+ "eslint-config-prettier": "^10.1.5",
3839 "eslint-plugin-svelte": "^2.46.1",
3940 "globals": "^15.15.0",
40- "prettier": "^3.5.1",
41- "prettier-plugin-svelte": "^3.3.3",
42- "prettier-plugin-tailwindcss": "^0.6.11",
43- "svelte": "^5.20.1",
44- "svelte-check": "^4.1.4",
41+ "jsdom": "^26.1.0",
42+ "prettier": "^3.6.2",
43+ "prettier-plugin-svelte": "^3.4.0",
44+ "prettier-plugin-tailwindcss": "^0.6.13",
45+ "svelte": "^5.35.2",
46+ "svelte-check": "^4.2.2",
4547 "tailwindcss": "^3.4.17",
46- "terser": "^5.39.0",
47- "tsx": "^4.19.2",
48- "typescript": "^5.7.3",
49- "typescript-eslint": "^8.24.0",
50- "vite": "^6.1.0",
51- "vitest": "^3.0.5"
48+ "terser": "^5.43.1",
49+ "tsx": "^4.20.3",
50+ "typescript": "^5.8.3",
51+ "typescript-eslint": "^8.35.1",
52+ "vite": "^6.3.5",
53+ "vitest": "^3.2.4"
5254 },
5355 "dependencies": {
5456 "@libsql/client": "^0.14.0",
55- "dotenv": "^16.4.7",
57+ "dotenv": "^16.6.1",
5658 "drizzle-orm": "^0.39.3",
57- "pino": "^9.6.0",
59+ "pino": "^9.7.0",
5860 "pino-pretty": "^13.0.0",
59- "uuid": "^11.0.5",
60- "xp.css": "^0.2.6"
61+ "rehype": "^13.0.2",
62+ "rehype-sanitize": "^6.0.0",
63+ "rehype-stringify": "^10.0.1",
64+ "remark-parse": "^11.0.0",
65+ "remark-rehype": "^11.1.2",
66+ "unified": "^11.0.5",
67+ "uuid": "^11.1.0",
68+ "xp.css": "^0.2.6",
69+ "zod": "^3.25.71"
6170 }
6271 }
M pnpm-lock.yaml +1921 -874
@@ -12,39 +12,60 @@ importers:
1212 specifier: ^0.14.0
1313 version: 0.14.0
1414 dotenv:
15- specifier: ^16.4.7
16- version: 16.4.7
15+ specifier: ^16.6.1
16+ version: 16.6.1
1717 drizzle-orm:
1818 specifier: ^0.39.3
19- version: 0.39.3(@cloudflare/workers-types@4.20250214.0)(@libsql/client@0.14.0)
19+ version: 0.39.3(@cloudflare/workers-types@4.20250703.0)(@libsql/client@0.14.0)
2020 pino:
21- specifier: ^9.6.0
22- version: 9.6.0
21+ specifier: ^9.7.0
22+ version: 9.7.0
2323 pino-pretty:
2424 specifier: ^13.0.0
2525 version: 13.0.0
26- uuid:
26+ rehype:
27+ specifier: ^13.0.2
28+ version: 13.0.2
29+ rehype-sanitize:
30+ specifier: ^6.0.0
31+ version: 6.0.0
32+ rehype-stringify:
33+ specifier: ^10.0.1
34+ version: 10.0.1
35+ remark-parse:
36+ specifier: ^11.0.0
37+ version: 11.0.0
38+ remark-rehype:
39+ specifier: ^11.1.2
40+ version: 11.1.2
41+ unified:
2742 specifier: ^11.0.5
2843 version: 11.0.5
44+ uuid:
45+ specifier: ^11.1.0
46+ version: 11.1.0
2947 xp.css:
3048 specifier: ^0.2.6
3149 version: 0.2.6
50+ zod:
51+ specifier: ^3.25.71
52+ version: 3.25.71
3253 devDependencies:
3354 '@eslint/compat':
34- specifier: ^1.2.6
35- version: 1.2.6(eslint@9.20.1(jiti@1.21.7))
55+ specifier: ^1.3.1
56+ version: 1.3.1(eslint@9.30.1(jiti@1.21.7))
3657 '@eslint/js':
37- specifier: ^9.20.0
38- version: 9.20.0
58+ specifier: ^9.30.1
59+ version: 9.30.1
3960 '@sveltejs/adapter-cloudflare':
40- specifier: ^5.0.3
41- version: 5.0.3(@sveltejs/kit@2.17.2(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(wrangler@3.107.3(@cloudflare/workers-types@4.20250214.0))
61+ specifier: ^5.1.0
62+ version: 5.1.0(@sveltejs/kit@2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(wrangler@3.107.3(@cloudflare/workers-types@4.20250703.0))
4263 '@sveltejs/kit':
43- specifier: ^2.17.2
44- version: 2.17.2(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))
64+ specifier: ^2.22.2
65+ version: 2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
4566 '@sveltejs/vite-plugin-svelte':
46- specifier: ^5.0.3
47- version: 5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))
67+ specifier: ^5.1.0
68+ version: 5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
4869 '@tailwindcss/container-queries':
4970 specifier: ^0.1.1
5071 version: 0.1.1(tailwindcss@3.4.17)
@@ -55,62 +76,65 @@ importers:
5576 specifier: ^0.5.16
5677 version: 0.5.16(tailwindcss@3.4.17)
5778 '@types/node':
58- specifier: ^22.13.4
59- version: 22.13.4
79+ specifier: ^22.16.0
80+ version: 22.16.0
6081 autoprefixer:
61- specifier: ^10.4.20
62- version: 10.4.20(postcss@8.5.2)
82+ specifier: ^10.4.21
83+ version: 10.4.21(postcss@8.5.6)
6384 drizzle-kit:
64- specifier: ^0.30.4
65- version: 0.30.4
85+ specifier: ^0.30.6
86+ version: 0.30.6
6687 eslint:
67- specifier: ^9.20.1
68- version: 9.20.1(jiti@1.21.7)
88+ specifier: ^9.30.1
89+ version: 9.30.1(jiti@1.21.7)
6990 eslint-config-prettier:
70- specifier: ^10.0.1
71- version: 10.0.1(eslint@9.20.1(jiti@1.21.7))
91+ specifier: ^10.1.5
92+ version: 10.1.5(eslint@9.30.1(jiti@1.21.7))
7293 eslint-plugin-svelte:
7394 specifier: ^2.46.1
74- version: 2.46.1(eslint@9.20.1(jiti@1.21.7))(svelte@5.20.1)
95+ version: 2.46.1(eslint@9.30.1(jiti@1.21.7))(svelte@5.35.2)
7596 globals:
7697 specifier: ^15.15.0
7798 version: 15.15.0
99+ jsdom:
100+ specifier: ^26.1.0
101+ version: 26.1.0
78102 prettier:
79- specifier: ^3.5.1
80- version: 3.5.1
103+ specifier: ^3.6.2
104+ version: 3.6.2
81105 prettier-plugin-svelte:
82- specifier: ^3.3.3
83- version: 3.3.3(prettier@3.5.1)(svelte@5.20.1)
106+ specifier: ^3.4.0
107+ version: 3.4.0(prettier@3.6.2)(svelte@5.35.2)
84108 prettier-plugin-tailwindcss:
85- specifier: ^0.6.11
86- version: 0.6.11(prettier-plugin-svelte@3.3.3(prettier@3.5.1)(svelte@5.20.1))(prettier@3.5.1)
109+ specifier: ^0.6.13
110+ version: 0.6.13(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.35.2))(prettier@3.6.2)
87111 svelte:
88- specifier: ^5.20.1
89- version: 5.20.1
112+ specifier: ^5.35.2
113+ version: 5.35.2
90114 svelte-check:
91- specifier: ^4.1.4
92- version: 4.1.4(svelte@5.20.1)(typescript@5.7.3)
115+ specifier: ^4.2.2
116+ version: 4.2.2(picomatch@4.0.2)(svelte@5.35.2)(typescript@5.8.3)
93117 tailwindcss:
94118 specifier: ^3.4.17
95119 version: 3.4.17
96120 terser:
97- specifier: ^5.39.0
98- version: 5.39.0
121+ specifier: ^5.43.1
122+ version: 5.43.1
99123 tsx:
100- specifier: ^4.19.2
101- version: 4.19.2
124+ specifier: ^4.20.3
125+ version: 4.20.3
102126 typescript:
103- specifier: ^5.7.3
104- version: 5.7.3
127+ specifier: ^5.8.3
128+ version: 5.8.3
105129 typescript-eslint:
106- specifier: ^8.24.0
107- version: 8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)
130+ specifier: ^8.35.1
131+ version: 8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)
108132 vite:
109- specifier: ^6.1.0
110- version: 6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
133+ specifier: ^6.3.5
134+ version: 6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
111135 vitest:
112- specifier: ^3.0.5
113- version: 3.0.5(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
136+ specifier: ^3.2.4
137+ version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
114138
115139 packages:
116140
@@ -122,6 +146,9 @@ packages:
122146 resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
123147 engines: {node: '>=6.0.0'}
124148
149+ '@asamuzakjp/css-color@3.2.0':
150+ resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==}
151+
125152 '@cloudflare/kv-asset-handler@0.3.4':
126153 resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==}
127154 engines: {node: '>=16.13'}
@@ -156,13 +183,41 @@ packages:
156183 cpu: [x64]
157184 os: [win32]
158185
159- '@cloudflare/workers-types@4.20250214.0':
160- resolution: {integrity: sha512-+M8oOFVbyXT5GeJrYLWMUGyPf5wGB4+k59PPqdedtOig7NjZ5r4S79wMdaZ/EV5IV8JPtZBSNjTKpDnNmfxjaQ==}
186+ '@cloudflare/workers-types@4.20250703.0':
187+ resolution: {integrity: sha512-6ITY5VL2eDkwFVWtF4OSsLIalyuwAE8/eH76fFn1KNGsH5V8JdjYriFTa/3YaJ+mzt4n4X6Hv06zrg00IKBTIA==}
161188
162189 '@cspotcode/source-map-support@0.8.1':
163190 resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
164191 engines: {node: '>=12'}
165192
193+ '@csstools/color-helpers@5.0.2':
194+ resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==}
195+ engines: {node: '>=18'}
196+
197+ '@csstools/css-calc@2.1.4':
198+ resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==}
199+ engines: {node: '>=18'}
200+ peerDependencies:
201+ '@csstools/css-parser-algorithms': ^3.0.5
202+ '@csstools/css-tokenizer': ^3.0.4
203+
204+ '@csstools/css-color-parser@3.0.10':
205+ resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==}
206+ engines: {node: '>=18'}
207+ peerDependencies:
208+ '@csstools/css-parser-algorithms': ^3.0.5
209+ '@csstools/css-tokenizer': ^3.0.4
210+
211+ '@csstools/css-parser-algorithms@3.0.5':
212+ resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==}
213+ engines: {node: '>=18'}
214+ peerDependencies:
215+ '@csstools/css-tokenizer': ^3.0.4
216+
217+ '@csstools/css-tokenizer@3.0.4':
218+ resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
219+ engines: {node: '>=18'}
220+
166221 '@drizzle-team/brocli@0.10.2':
167222 resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
168223
@@ -190,14 +245,14 @@ packages:
190245 cpu: [ppc64]
191246 os: [aix]
192247
193- '@esbuild/aix-ppc64@0.23.1':
194- resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
248+ '@esbuild/aix-ppc64@0.24.2':
249+ resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
195250 engines: {node: '>=18'}
196251 cpu: [ppc64]
197252 os: [aix]
198253
199- '@esbuild/aix-ppc64@0.24.2':
200- resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
254+ '@esbuild/aix-ppc64@0.25.5':
255+ resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==}
201256 engines: {node: '>=18'}
202257 cpu: [ppc64]
203258 os: [aix]
@@ -220,14 +275,14 @@ packages:
220275 cpu: [arm64]
221276 os: [android]
222277
223- '@esbuild/android-arm64@0.23.1':
224- resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
278+ '@esbuild/android-arm64@0.24.2':
279+ resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
225280 engines: {node: '>=18'}
226281 cpu: [arm64]
227282 os: [android]
228283
229- '@esbuild/android-arm64@0.24.2':
230- resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
284+ '@esbuild/android-arm64@0.25.5':
285+ resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==}
231286 engines: {node: '>=18'}
232287 cpu: [arm64]
233288 os: [android]
@@ -250,14 +305,14 @@ packages:
250305 cpu: [arm]
251306 os: [android]
252307
253- '@esbuild/android-arm@0.23.1':
254- resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
308+ '@esbuild/android-arm@0.24.2':
309+ resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
255310 engines: {node: '>=18'}
256311 cpu: [arm]
257312 os: [android]
258313
259- '@esbuild/android-arm@0.24.2':
260- resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
314+ '@esbuild/android-arm@0.25.5':
315+ resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==}
261316 engines: {node: '>=18'}
262317 cpu: [arm]
263318 os: [android]
@@ -280,14 +335,14 @@ packages:
280335 cpu: [x64]
281336 os: [android]
282337
283- '@esbuild/android-x64@0.23.1':
284- resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
338+ '@esbuild/android-x64@0.24.2':
339+ resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
285340 engines: {node: '>=18'}
286341 cpu: [x64]
287342 os: [android]
288343
289- '@esbuild/android-x64@0.24.2':
290- resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
344+ '@esbuild/android-x64@0.25.5':
345+ resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==}
291346 engines: {node: '>=18'}
292347 cpu: [x64]
293348 os: [android]
@@ -310,14 +365,14 @@ packages:
310365 cpu: [arm64]
311366 os: [darwin]
312367
313- '@esbuild/darwin-arm64@0.23.1':
314- resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
368+ '@esbuild/darwin-arm64@0.24.2':
369+ resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
315370 engines: {node: '>=18'}
316371 cpu: [arm64]
317372 os: [darwin]
318373
319- '@esbuild/darwin-arm64@0.24.2':
320- resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
374+ '@esbuild/darwin-arm64@0.25.5':
375+ resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==}
321376 engines: {node: '>=18'}
322377 cpu: [arm64]
323378 os: [darwin]
@@ -340,14 +395,14 @@ packages:
340395 cpu: [x64]
341396 os: [darwin]
342397
343- '@esbuild/darwin-x64@0.23.1':
344- resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
398+ '@esbuild/darwin-x64@0.24.2':
399+ resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
345400 engines: {node: '>=18'}
346401 cpu: [x64]
347402 os: [darwin]
348403
349- '@esbuild/darwin-x64@0.24.2':
350- resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
404+ '@esbuild/darwin-x64@0.25.5':
405+ resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==}
351406 engines: {node: '>=18'}
352407 cpu: [x64]
353408 os: [darwin]
@@ -370,14 +425,14 @@ packages:
370425 cpu: [arm64]
371426 os: [freebsd]
372427
373- '@esbuild/freebsd-arm64@0.23.1':
374- resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
428+ '@esbuild/freebsd-arm64@0.24.2':
429+ resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
375430 engines: {node: '>=18'}
376431 cpu: [arm64]
377432 os: [freebsd]
378433
379- '@esbuild/freebsd-arm64@0.24.2':
380- resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
434+ '@esbuild/freebsd-arm64@0.25.5':
435+ resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==}
381436 engines: {node: '>=18'}
382437 cpu: [arm64]
383438 os: [freebsd]
@@ -400,14 +455,14 @@ packages:
400455 cpu: [x64]
401456 os: [freebsd]
402457
403- '@esbuild/freebsd-x64@0.23.1':
404- resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
458+ '@esbuild/freebsd-x64@0.24.2':
459+ resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
405460 engines: {node: '>=18'}
406461 cpu: [x64]
407462 os: [freebsd]
408463
409- '@esbuild/freebsd-x64@0.24.2':
410- resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
464+ '@esbuild/freebsd-x64@0.25.5':
465+ resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==}
411466 engines: {node: '>=18'}
412467 cpu: [x64]
413468 os: [freebsd]
@@ -430,14 +485,14 @@ packages:
430485 cpu: [arm64]
431486 os: [linux]
432487
433- '@esbuild/linux-arm64@0.23.1':
434- resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
488+ '@esbuild/linux-arm64@0.24.2':
489+ resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
435490 engines: {node: '>=18'}
436491 cpu: [arm64]
437492 os: [linux]
438493
439- '@esbuild/linux-arm64@0.24.2':
440- resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
494+ '@esbuild/linux-arm64@0.25.5':
495+ resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==}
441496 engines: {node: '>=18'}
442497 cpu: [arm64]
443498 os: [linux]
@@ -460,14 +515,14 @@ packages:
460515 cpu: [arm]
461516 os: [linux]
462517
463- '@esbuild/linux-arm@0.23.1':
464- resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
518+ '@esbuild/linux-arm@0.24.2':
519+ resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
465520 engines: {node: '>=18'}
466521 cpu: [arm]
467522 os: [linux]
468523
469- '@esbuild/linux-arm@0.24.2':
470- resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
524+ '@esbuild/linux-arm@0.25.5':
525+ resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==}
471526 engines: {node: '>=18'}
472527 cpu: [arm]
473528 os: [linux]
@@ -490,14 +545,14 @@ packages:
490545 cpu: [ia32]
491546 os: [linux]
492547
493- '@esbuild/linux-ia32@0.23.1':
494- resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
548+ '@esbuild/linux-ia32@0.24.2':
549+ resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
495550 engines: {node: '>=18'}
496551 cpu: [ia32]
497552 os: [linux]
498553
499- '@esbuild/linux-ia32@0.24.2':
500- resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
554+ '@esbuild/linux-ia32@0.25.5':
555+ resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==}
501556 engines: {node: '>=18'}
502557 cpu: [ia32]
503558 os: [linux]
@@ -520,14 +575,14 @@ packages:
520575 cpu: [loong64]
521576 os: [linux]
522577
523- '@esbuild/linux-loong64@0.23.1':
524- resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
578+ '@esbuild/linux-loong64@0.24.2':
579+ resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
525580 engines: {node: '>=18'}
526581 cpu: [loong64]
527582 os: [linux]
528583
529- '@esbuild/linux-loong64@0.24.2':
530- resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
584+ '@esbuild/linux-loong64@0.25.5':
585+ resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==}
531586 engines: {node: '>=18'}
532587 cpu: [loong64]
533588 os: [linux]
@@ -550,14 +605,14 @@ packages:
550605 cpu: [mips64el]
551606 os: [linux]
552607
553- '@esbuild/linux-mips64el@0.23.1':
554- resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
608+ '@esbuild/linux-mips64el@0.24.2':
609+ resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
555610 engines: {node: '>=18'}
556611 cpu: [mips64el]
557612 os: [linux]
558613
559- '@esbuild/linux-mips64el@0.24.2':
560- resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
614+ '@esbuild/linux-mips64el@0.25.5':
615+ resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==}
561616 engines: {node: '>=18'}
562617 cpu: [mips64el]
563618 os: [linux]
@@ -580,14 +635,14 @@ packages:
580635 cpu: [ppc64]
581636 os: [linux]
582637
583- '@esbuild/linux-ppc64@0.23.1':
584- resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
638+ '@esbuild/linux-ppc64@0.24.2':
639+ resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
585640 engines: {node: '>=18'}
586641 cpu: [ppc64]
587642 os: [linux]
588643
589- '@esbuild/linux-ppc64@0.24.2':
590- resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
644+ '@esbuild/linux-ppc64@0.25.5':
645+ resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==}
591646 engines: {node: '>=18'}
592647 cpu: [ppc64]
593648 os: [linux]
@@ -610,14 +665,14 @@ packages:
610665 cpu: [riscv64]
611666 os: [linux]
612667
613- '@esbuild/linux-riscv64@0.23.1':
614- resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
668+ '@esbuild/linux-riscv64@0.24.2':
669+ resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
615670 engines: {node: '>=18'}
616671 cpu: [riscv64]
617672 os: [linux]
618673
619- '@esbuild/linux-riscv64@0.24.2':
620- resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
674+ '@esbuild/linux-riscv64@0.25.5':
675+ resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==}
621676 engines: {node: '>=18'}
622677 cpu: [riscv64]
623678 os: [linux]
@@ -640,14 +695,14 @@ packages:
640695 cpu: [s390x]
641696 os: [linux]
642697
643- '@esbuild/linux-s390x@0.23.1':
644- resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
698+ '@esbuild/linux-s390x@0.24.2':
699+ resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
645700 engines: {node: '>=18'}
646701 cpu: [s390x]
647702 os: [linux]
648703
649- '@esbuild/linux-s390x@0.24.2':
650- resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
704+ '@esbuild/linux-s390x@0.25.5':
705+ resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==}
651706 engines: {node: '>=18'}
652707 cpu: [s390x]
653708 os: [linux]
@@ -670,14 +725,14 @@ packages:
670725 cpu: [x64]
671726 os: [linux]
672727
673- '@esbuild/linux-x64@0.23.1':
674- resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
728+ '@esbuild/linux-x64@0.24.2':
729+ resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
675730 engines: {node: '>=18'}
676731 cpu: [x64]
677732 os: [linux]
678733
679- '@esbuild/linux-x64@0.24.2':
680- resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
734+ '@esbuild/linux-x64@0.25.5':
735+ resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==}
681736 engines: {node: '>=18'}
682737 cpu: [x64]
683738 os: [linux]
@@ -688,6 +743,12 @@ packages:
688743 cpu: [arm64]
689744 os: [netbsd]
690745
746+ '@esbuild/netbsd-arm64@0.25.5':
747+ resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==}
748+ engines: {node: '>=18'}
749+ cpu: [arm64]
750+ os: [netbsd]
751+
691752 '@esbuild/netbsd-x64@0.17.19':
692753 resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==}
693754 engines: {node: '>=12'}
@@ -706,26 +767,26 @@ packages:
706767 cpu: [x64]
707768 os: [netbsd]
708769
709- '@esbuild/netbsd-x64@0.23.1':
710- resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
770+ '@esbuild/netbsd-x64@0.24.2':
771+ resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
711772 engines: {node: '>=18'}
712773 cpu: [x64]
713774 os: [netbsd]
714775
715- '@esbuild/netbsd-x64@0.24.2':
716- resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
776+ '@esbuild/netbsd-x64@0.25.5':
777+ resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==}
717778 engines: {node: '>=18'}
718779 cpu: [x64]
719780 os: [netbsd]
720781
721- '@esbuild/openbsd-arm64@0.23.1':
722- resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==}
782+ '@esbuild/openbsd-arm64@0.24.2':
783+ resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
723784 engines: {node: '>=18'}
724785 cpu: [arm64]
725786 os: [openbsd]
726787
727- '@esbuild/openbsd-arm64@0.24.2':
728- resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
788+ '@esbuild/openbsd-arm64@0.25.5':
789+ resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==}
729790 engines: {node: '>=18'}
730791 cpu: [arm64]
731792 os: [openbsd]
@@ -748,14 +809,14 @@ packages:
748809 cpu: [x64]
749810 os: [openbsd]
750811
751- '@esbuild/openbsd-x64@0.23.1':
752- resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
812+ '@esbuild/openbsd-x64@0.24.2':
813+ resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
753814 engines: {node: '>=18'}
754815 cpu: [x64]
755816 os: [openbsd]
756817
757- '@esbuild/openbsd-x64@0.24.2':
758- resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
818+ '@esbuild/openbsd-x64@0.25.5':
819+ resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==}
759820 engines: {node: '>=18'}
760821 cpu: [x64]
761822 os: [openbsd]
@@ -778,14 +839,14 @@ packages:
778839 cpu: [x64]
779840 os: [sunos]
780841
781- '@esbuild/sunos-x64@0.23.1':
782- resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
842+ '@esbuild/sunos-x64@0.24.2':
843+ resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
783844 engines: {node: '>=18'}
784845 cpu: [x64]
785846 os: [sunos]
786847
787- '@esbuild/sunos-x64@0.24.2':
788- resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
848+ '@esbuild/sunos-x64@0.25.5':
849+ resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==}
789850 engines: {node: '>=18'}
790851 cpu: [x64]
791852 os: [sunos]
@@ -808,14 +869,14 @@ packages:
808869 cpu: [arm64]
809870 os: [win32]
810871
811- '@esbuild/win32-arm64@0.23.1':
812- resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
872+ '@esbuild/win32-arm64@0.24.2':
873+ resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
813874 engines: {node: '>=18'}
814875 cpu: [arm64]
815876 os: [win32]
816877
817- '@esbuild/win32-arm64@0.24.2':
818- resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
878+ '@esbuild/win32-arm64@0.25.5':
879+ resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==}
819880 engines: {node: '>=18'}
820881 cpu: [arm64]
821882 os: [win32]
@@ -838,14 +899,14 @@ packages:
838899 cpu: [ia32]
839900 os: [win32]
840901
841- '@esbuild/win32-ia32@0.23.1':
842- resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
902+ '@esbuild/win32-ia32@0.24.2':
903+ resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
843904 engines: {node: '>=18'}
844905 cpu: [ia32]
845906 os: [win32]
846907
847- '@esbuild/win32-ia32@0.24.2':
848- resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
908+ '@esbuild/win32-ia32@0.25.5':
909+ resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==}
849910 engines: {node: '>=18'}
850911 cpu: [ia32]
851912 os: [win32]
@@ -868,20 +929,20 @@ packages:
868929 cpu: [x64]
869930 os: [win32]
870931
871- '@esbuild/win32-x64@0.23.1':
872- resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
932+ '@esbuild/win32-x64@0.24.2':
933+ resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
873934 engines: {node: '>=18'}
874935 cpu: [x64]
875936 os: [win32]
876937
877- '@esbuild/win32-x64@0.24.2':
878- resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
938+ '@esbuild/win32-x64@0.25.5':
939+ resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==}
879940 engines: {node: '>=18'}
880941 cpu: [x64]
881942 os: [win32]
882943
883- '@eslint-community/eslint-utils@4.4.1':
884- resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==}
944+ '@eslint-community/eslint-utils@4.7.0':
945+ resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
885946 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
886947 peerDependencies:
887948 eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
@@ -890,41 +951,45 @@ packages:
890951 resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
891952 engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
892953
893- '@eslint/compat@1.2.6':
894- resolution: {integrity: sha512-k7HNCqApoDHM6XzT30zGoETj+D+uUcZUb+IVAJmar3u6bvHf7hhHJcWx09QHj4/a2qrKZMWU0E16tvkiAdv06Q==}
954+ '@eslint/compat@1.3.1':
955+ resolution: {integrity: sha512-k8MHony59I5EPic6EQTCNOuPoVBnoYXkP+20xvwFjN7t0qI3ImyvyBgg+hIVPwC8JaxVjjUZld+cLfBLFDLucg==}
895956 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
896957 peerDependencies:
897- eslint: ^9.10.0
958+ eslint: ^8.40 || 9
898959 peerDependenciesMeta:
899960 eslint:
900961 optional: true
901962
902- '@eslint/config-array@0.19.2':
903- resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==}
963+ '@eslint/config-array@0.21.0':
964+ resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==}
965+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
966+
967+ '@eslint/config-helpers@0.3.0':
968+ resolution: {integrity: sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==}
904969 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
905970
906- '@eslint/core@0.10.0':
907- resolution: {integrity: sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==}
971+ '@eslint/core@0.14.0':
972+ resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==}
908973 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
909974
910- '@eslint/core@0.11.0':
911- resolution: {integrity: sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==}
975+ '@eslint/core@0.15.1':
976+ resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==}
912977 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
913978
914- '@eslint/eslintrc@3.2.0':
915- resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==}
979+ '@eslint/eslintrc@3.3.1':
980+ resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
916981 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
917982
918- '@eslint/js@9.20.0':
919- resolution: {integrity: sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==}
983+ '@eslint/js@9.30.1':
984+ resolution: {integrity: sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==}
920985 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
921986
922987 '@eslint/object-schema@2.1.6':
923988 resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
924989 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
925990
926- '@eslint/plugin-kit@0.2.5':
927- resolution: {integrity: sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==}
991+ '@eslint/plugin-kit@0.3.3':
992+ resolution: {integrity: sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==}
928993 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
929994
930995 '@fastify/busboy@2.1.1':
@@ -947,34 +1012,29 @@ packages:
9471012 resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
9481013 engines: {node: '>=18.18'}
9491014
950- '@humanwhocodes/retry@0.4.1':
951- resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==}
1015+ '@humanwhocodes/retry@0.4.3':
1016+ resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
9521017 engines: {node: '>=18.18'}
9531018
9541019 '@isaacs/cliui@8.0.2':
9551020 resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
9561021 engines: {node: '>=12'}
9571022
958- '@jridgewell/gen-mapping@0.3.8':
959- resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
960- engines: {node: '>=6.0.0'}
1023+ '@jridgewell/gen-mapping@0.3.12':
1024+ resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==}
9611025
9621026 '@jridgewell/resolve-uri@3.1.2':
9631027 resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
9641028 engines: {node: '>=6.0.0'}
9651029
966- '@jridgewell/set-array@1.2.1':
967- resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
968- engines: {node: '>=6.0.0'}
969-
970- '@jridgewell/source-map@0.3.6':
971- resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==}
1030+ '@jridgewell/source-map@0.3.10':
1031+ resolution: {integrity: sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==}
9721032
973- '@jridgewell/sourcemap-codec@1.5.0':
974- resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
1033+ '@jridgewell/sourcemap-codec@1.5.4':
1034+ resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
9751035
976- '@jridgewell/trace-mapping@0.3.25':
977- resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
1036+ '@jridgewell/trace-mapping@0.3.29':
1037+ resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
9781038
9791039 '@jridgewell/trace-mapping@0.3.9':
9801040 resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
@@ -1045,122 +1105,135 @@ packages:
10451105 resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
10461106 engines: {node: '>= 8'}
10471107
1108+ '@petamoriken/float16@3.9.2':
1109+ resolution: {integrity: sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==}
1110+
10481111 '@pkgjs/parseargs@0.11.0':
10491112 resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
10501113 engines: {node: '>=14'}
10511114
1052- '@polka/url@1.0.0-next.28':
1053- resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==}
1115+ '@polka/url@1.0.0-next.29':
1116+ resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
10541117
1055- '@rollup/rollup-android-arm-eabi@4.34.8':
1056- resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==}
1118+ '@rollup/rollup-android-arm-eabi@4.44.1':
1119+ resolution: {integrity: sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==}
10571120 cpu: [arm]
10581121 os: [android]
10591122
1060- '@rollup/rollup-android-arm64@4.34.8':
1061- resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==}
1123+ '@rollup/rollup-android-arm64@4.44.1':
1124+ resolution: {integrity: sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==}
10621125 cpu: [arm64]
10631126 os: [android]
10641127
1065- '@rollup/rollup-darwin-arm64@4.34.8':
1066- resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==}
1128+ '@rollup/rollup-darwin-arm64@4.44.1':
1129+ resolution: {integrity: sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==}
10671130 cpu: [arm64]
10681131 os: [darwin]
10691132
1070- '@rollup/rollup-darwin-x64@4.34.8':
1071- resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==}
1133+ '@rollup/rollup-darwin-x64@4.44.1':
1134+ resolution: {integrity: sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==}
10721135 cpu: [x64]
10731136 os: [darwin]
10741137
1075- '@rollup/rollup-freebsd-arm64@4.34.8':
1076- resolution: {integrity: sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==}
1138+ '@rollup/rollup-freebsd-arm64@4.44.1':
1139+ resolution: {integrity: sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==}
10771140 cpu: [arm64]
10781141 os: [freebsd]
10791142
1080- '@rollup/rollup-freebsd-x64@4.34.8':
1081- resolution: {integrity: sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==}
1143+ '@rollup/rollup-freebsd-x64@4.44.1':
1144+ resolution: {integrity: sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==}
10821145 cpu: [x64]
10831146 os: [freebsd]
10841147
1085- '@rollup/rollup-linux-arm-gnueabihf@4.34.8':
1086- resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==}
1148+ '@rollup/rollup-linux-arm-gnueabihf@4.44.1':
1149+ resolution: {integrity: sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==}
10871150 cpu: [arm]
10881151 os: [linux]
10891152
1090- '@rollup/rollup-linux-arm-musleabihf@4.34.8':
1091- resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==}
1153+ '@rollup/rollup-linux-arm-musleabihf@4.44.1':
1154+ resolution: {integrity: sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==}
10921155 cpu: [arm]
10931156 os: [linux]
10941157
1095- '@rollup/rollup-linux-arm64-gnu@4.34.8':
1096- resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==}
1158+ '@rollup/rollup-linux-arm64-gnu@4.44.1':
1159+ resolution: {integrity: sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==}
10971160 cpu: [arm64]
10981161 os: [linux]
10991162
1100- '@rollup/rollup-linux-arm64-musl@4.34.8':
1101- resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==}
1163+ '@rollup/rollup-linux-arm64-musl@4.44.1':
1164+ resolution: {integrity: sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==}
11021165 cpu: [arm64]
11031166 os: [linux]
11041167
1105- '@rollup/rollup-linux-loongarch64-gnu@4.34.8':
1106- resolution: {integrity: sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==}
1168+ '@rollup/rollup-linux-loongarch64-gnu@4.44.1':
1169+ resolution: {integrity: sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==}
11071170 cpu: [loong64]
11081171 os: [linux]
11091172
1110- '@rollup/rollup-linux-powerpc64le-gnu@4.34.8':
1111- resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==}
1173+ '@rollup/rollup-linux-powerpc64le-gnu@4.44.1':
1174+ resolution: {integrity: sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==}
11121175 cpu: [ppc64]
11131176 os: [linux]
11141177
1115- '@rollup/rollup-linux-riscv64-gnu@4.34.8':
1116- resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==}
1178+ '@rollup/rollup-linux-riscv64-gnu@4.44.1':
1179+ resolution: {integrity: sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==}
1180+ cpu: [riscv64]
1181+ os: [linux]
1182+
1183+ '@rollup/rollup-linux-riscv64-musl@4.44.1':
1184+ resolution: {integrity: sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==}
11171185 cpu: [riscv64]
11181186 os: [linux]
11191187
1120- '@rollup/rollup-linux-s390x-gnu@4.34.8':
1121- resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==}
1188+ '@rollup/rollup-linux-s390x-gnu@4.44.1':
1189+ resolution: {integrity: sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==}
11221190 cpu: [s390x]
11231191 os: [linux]
11241192
1125- '@rollup/rollup-linux-x64-gnu@4.34.8':
1126- resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==}
1193+ '@rollup/rollup-linux-x64-gnu@4.44.1':
1194+ resolution: {integrity: sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==}
11271195 cpu: [x64]
11281196 os: [linux]
11291197
1130- '@rollup/rollup-linux-x64-musl@4.34.8':
1131- resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==}
1198+ '@rollup/rollup-linux-x64-musl@4.44.1':
1199+ resolution: {integrity: sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==}
11321200 cpu: [x64]
11331201 os: [linux]
11341202
1135- '@rollup/rollup-win32-arm64-msvc@4.34.8':
1136- resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==}
1203+ '@rollup/rollup-win32-arm64-msvc@4.44.1':
1204+ resolution: {integrity: sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==}
11371205 cpu: [arm64]
11381206 os: [win32]
11391207
1140- '@rollup/rollup-win32-ia32-msvc@4.34.8':
1141- resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==}
1208+ '@rollup/rollup-win32-ia32-msvc@4.44.1':
1209+ resolution: {integrity: sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==}
11421210 cpu: [ia32]
11431211 os: [win32]
11441212
1145- '@rollup/rollup-win32-x64-msvc@4.34.8':
1146- resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==}
1213+ '@rollup/rollup-win32-x64-msvc@4.44.1':
1214+ resolution: {integrity: sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==}
11471215 cpu: [x64]
11481216 os: [win32]
11491217
1150- '@sveltejs/adapter-cloudflare@5.0.3':
1151- resolution: {integrity: sha512-jRJmt3JtGp5ockFxoDLKPisK0RPGnitNfHS9+xhRTpRaBV7jS/fQfAmpaey7rwKWaDUnkoHx0DV0WvISHNfUEA==}
1218+ '@sveltejs/acorn-typescript@1.0.5':
1219+ resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==}
1220+ peerDependencies:
1221+ acorn: ^8.9.0
1222+
1223+ '@sveltejs/adapter-cloudflare@5.1.0':
1224+ resolution: {integrity: sha512-moQwTcJTYY3cV/SA0FJClsJS+u7zjrziYNlDHLbb+lIbBc0Ze4Cki8MSYwY1qMmP3iarQIb8OXFn7m9TEisW1A==}
11521225 peerDependencies:
11531226 '@sveltejs/kit': ^2.0.0
1154- wrangler: ^3.87.0
1227+ wrangler: ^3.87.0 || ^4.0.0
11551228
1156- '@sveltejs/kit@2.17.2':
1157- resolution: {integrity: sha512-Vypk02baf7qd3SOB1uUwUC/3Oka+srPo2J0a8YN3EfJypRshDkNx9HzNKjSmhOnGWwT+SSO06+N0mAb8iVTmTQ==}
1229+ '@sveltejs/kit@2.22.2':
1230+ resolution: {integrity: sha512-2MvEpSYabUrsJAoq5qCOBGAlkICjfjunrnLcx3YAk2XV7TvAIhomlKsAgR4H/4uns5rAfYmj7Wet5KRtc8dPIg==}
11581231 engines: {node: '>=18.13'}
11591232 hasBin: true
11601233 peerDependencies:
1161- '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0
1234+ '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0
11621235 svelte: ^4.0.0 || ^5.0.0-next.0
1163- vite: ^5.0.3 || ^6.0.0
1236+ vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0
11641237
11651238 '@sveltejs/vite-plugin-svelte-inspector@4.0.1':
11661239 resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==}
@@ -1170,8 +1243,8 @@ packages:
11701243 svelte: ^5.0.0
11711244 vite: ^6.0.0
11721245
1173- '@sveltejs/vite-plugin-svelte@5.0.3':
1174- resolution: {integrity: sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==}
1246+ '@sveltejs/vite-plugin-svelte@5.1.0':
1247+ resolution: {integrity: sha512-wojIS/7GYnJDYIg1higWj2ROA6sSRWvcR1PO/bqEyFr/5UZah26c8Cz4u0NaqjPeVltzsVpt2Tm8d2io0V+4Tw==}
11751248 engines: {node: ^18.0.0 || ^20.0.0 || >=22}
11761249 peerDependencies:
11771250 svelte: ^5.0.0
@@ -1192,116 +1265,151 @@ packages:
11921265 peerDependencies:
11931266 tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
11941267
1268+ '@types/chai@5.2.2':
1269+ resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==}
1270+
11951271 '@types/cookie@0.6.0':
11961272 resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
11971273
1198- '@types/estree@1.0.6':
1199- resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
1274+ '@types/debug@4.1.12':
1275+ resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
1276+
1277+ '@types/deep-eql@4.0.2':
1278+ resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
1279+
1280+ '@types/estree@1.0.8':
1281+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
1282+
1283+ '@types/hast@3.0.4':
1284+ resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
12001285
12011286 '@types/json-schema@7.0.15':
12021287 resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
12031288
1204- '@types/node@22.13.4':
1205- resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==}
1289+ '@types/mdast@4.0.4':
1290+ resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
1291+
1292+ '@types/ms@2.1.0':
1293+ resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
1294+
1295+ '@types/node@22.16.0':
1296+ resolution: {integrity: sha512-B2egV9wALML1JCpv3VQoQ+yesQKAmNMBIAY7OteVrikcOcAkWm+dGL6qpeCktPjAv6N1JLnhbNiqS35UpFyBsQ==}
12061297
1207- '@types/ws@8.5.14':
1208- resolution: {integrity: sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==}
1298+ '@types/unist@3.0.3':
1299+ resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
12091300
1210- '@typescript-eslint/eslint-plugin@8.24.0':
1211- resolution: {integrity: sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ==}
1301+ '@types/ws@8.18.1':
1302+ resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
1303+
1304+ '@typescript-eslint/eslint-plugin@8.35.1':
1305+ resolution: {integrity: sha512-9XNTlo7P7RJxbVeICaIIIEipqxLKguyh+3UbXuT2XQuFp6d8VOeDEGuz5IiX0dgZo8CiI6aOFLg4e8cF71SFVg==}
12121306 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
12131307 peerDependencies:
1214- '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
1308+ '@typescript-eslint/parser': ^8.35.1
12151309 eslint: ^8.57.0 || ^9.0.0
1216- typescript: '>=4.8.4 <5.8.0'
1310+ typescript: '>=4.8.4 <5.9.0'
12171311
1218- '@typescript-eslint/parser@8.24.0':
1219- resolution: {integrity: sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA==}
1312+ '@typescript-eslint/parser@8.35.1':
1313+ resolution: {integrity: sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==}
12201314 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
12211315 peerDependencies:
12221316 eslint: ^8.57.0 || ^9.0.0
1223- typescript: '>=4.8.4 <5.8.0'
1317+ typescript: '>=4.8.4 <5.9.0'
1318+
1319+ '@typescript-eslint/project-service@8.35.1':
1320+ resolution: {integrity: sha512-VYxn/5LOpVxADAuP3NrnxxHYfzVtQzLKeldIhDhzC8UHaiQvYlXvKuVho1qLduFbJjjy5U5bkGwa3rUGUb1Q6Q==}
1321+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1322+ peerDependencies:
1323+ typescript: '>=4.8.4 <5.9.0'
12241324
1225- '@typescript-eslint/scope-manager@8.24.0':
1226- resolution: {integrity: sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==}
1325+ '@typescript-eslint/scope-manager@8.35.1':
1326+ resolution: {integrity: sha512-s/Bpd4i7ht2934nG+UoSPlYXd08KYz3bmjLEb7Ye1UVob0d1ENiT3lY8bsCmik4RqfSbPw9xJJHbugpPpP5JUg==}
12271327 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
12281328
1229- '@typescript-eslint/type-utils@8.24.0':
1230- resolution: {integrity: sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA==}
1329+ '@typescript-eslint/tsconfig-utils@8.35.1':
1330+ resolution: {integrity: sha512-K5/U9VmT9dTHoNowWZpz+/TObS3xqC5h0xAIjXPw+MNcKV9qg6eSatEnmeAwkjHijhACH0/N7bkhKvbt1+DXWQ==}
1331+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1332+ peerDependencies:
1333+ typescript: '>=4.8.4 <5.9.0'
1334+
1335+ '@typescript-eslint/type-utils@8.35.1':
1336+ resolution: {integrity: sha512-HOrUBlfVRz5W2LIKpXzZoy6VTZzMu2n8q9C2V/cFngIC5U1nStJgv0tMV4sZPzdf4wQm9/ToWUFPMN9Vq9VJQQ==}
12311337 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
12321338 peerDependencies:
12331339 eslint: ^8.57.0 || ^9.0.0
1234- typescript: '>=4.8.4 <5.8.0'
1340+ typescript: '>=4.8.4 <5.9.0'
12351341
1236- '@typescript-eslint/types@8.24.0':
1237- resolution: {integrity: sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==}
1342+ '@typescript-eslint/types@8.35.1':
1343+ resolution: {integrity: sha512-q/O04vVnKHfrrhNAscndAn1tuQhIkwqnaW+eu5waD5IPts2eX1dgJxgqcPx5BX109/qAz7IG6VrEPTOYKCNfRQ==}
12381344 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
12391345
1240- '@typescript-eslint/typescript-estree@8.24.0':
1241- resolution: {integrity: sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==}
1346+ '@typescript-eslint/typescript-estree@8.35.1':
1347+ resolution: {integrity: sha512-Vvpuvj4tBxIka7cPs6Y1uvM7gJgdF5Uu9F+mBJBPY4MhvjrjWGK4H0lVgLJd/8PWZ23FTqsaJaLEkBCFUk8Y9g==}
12421348 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
12431349 peerDependencies:
1244- typescript: '>=4.8.4 <5.8.0'
1350+ typescript: '>=4.8.4 <5.9.0'
12451351
1246- '@typescript-eslint/utils@8.24.0':
1247- resolution: {integrity: sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==}
1352+ '@typescript-eslint/utils@8.35.1':
1353+ resolution: {integrity: sha512-lhnwatFmOFcazAsUm3ZnZFpXSxiwoa1Lj50HphnDe1Et01NF4+hrdXONSUHIcbVu2eFb1bAf+5yjXkGVkXBKAQ==}
12481354 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
12491355 peerDependencies:
12501356 eslint: ^8.57.0 || ^9.0.0
1251- typescript: '>=4.8.4 <5.8.0'
1357+ typescript: '>=4.8.4 <5.9.0'
12521358
1253- '@typescript-eslint/visitor-keys@8.24.0':
1254- resolution: {integrity: sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==}
1359+ '@typescript-eslint/visitor-keys@8.35.1':
1360+ resolution: {integrity: sha512-VRwixir4zBWCSTP/ljEo091lbpypz57PoeAQ9imjG+vbeof9LplljsL1mos4ccG6H9IjfrVGM359RozUnuFhpw==}
12551361 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
12561362
1257- '@vitest/expect@3.0.5':
1258- resolution: {integrity: sha512-nNIOqupgZ4v5jWuQx2DSlHLEs7Q4Oh/7AYwNyE+k0UQzG7tSmjPXShUikn1mpNGzYEN2jJbTvLejwShMitovBA==}
1363+ '@ungap/structured-clone@1.3.0':
1364+ resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
1365+
1366+ '@vitest/expect@3.2.4':
1367+ resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
12591368
1260- '@vitest/mocker@3.0.5':
1261- resolution: {integrity: sha512-CLPNBFBIE7x6aEGbIjaQAX03ZZlBMaWwAjBdMkIf/cAn6xzLTiM3zYqO/WAbieEjsAZir6tO71mzeHZoodThvw==}
1369+ '@vitest/mocker@3.2.4':
1370+ resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
12621371 peerDependencies:
12631372 msw: ^2.4.9
1264- vite: ^5.0.0 || ^6.0.0
1373+ vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
12651374 peerDependenciesMeta:
12661375 msw:
12671376 optional: true
12681377 vite:
12691378 optional: true
12701379
1271- '@vitest/pretty-format@3.0.5':
1272- resolution: {integrity: sha512-CjUtdmpOcm4RVtB+up8r2vVDLR16Mgm/bYdkGFe3Yj/scRfCpbSi2W/BDSDcFK7ohw8UXvjMbOp9H4fByd/cOA==}
1380+ '@vitest/pretty-format@3.2.4':
1381+ resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
12731382
1274- '@vitest/runner@3.0.5':
1275- resolution: {integrity: sha512-BAiZFityFexZQi2yN4OX3OkJC6scwRo8EhRB0Z5HIGGgd2q+Nq29LgHU/+ovCtd0fOfXj5ZI6pwdlUmC5bpi8A==}
1383+ '@vitest/runner@3.2.4':
1384+ resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
12761385
1277- '@vitest/snapshot@3.0.5':
1278- resolution: {integrity: sha512-GJPZYcd7v8QNUJ7vRvLDmRwl+a1fGg4T/54lZXe+UOGy47F9yUfE18hRCtXL5aHN/AONu29NGzIXSVFh9K0feA==}
1386+ '@vitest/snapshot@3.2.4':
1387+ resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
12791388
1280- '@vitest/spy@3.0.5':
1281- resolution: {integrity: sha512-5fOzHj0WbUNqPK6blI/8VzZdkBlQLnT25knX0r4dbZI9qoZDf3qAdjoMmDcLG5A83W6oUUFJgUd0EYBc2P5xqg==}
1389+ '@vitest/spy@3.2.4':
1390+ resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
12821391
1283- '@vitest/utils@3.0.5':
1284- resolution: {integrity: sha512-N9AX0NUoUtVwKwy21JtwzaqR5L5R5A99GAbrHfCCXK1lp593i/3AZAXhSP43wRQuxYsflrdzEfXZFo1reR1Nkg==}
1392+ '@vitest/utils@3.2.4':
1393+ resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
12851394
12861395 acorn-jsx@5.3.2:
12871396 resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
12881397 peerDependencies:
12891398 acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
12901399
1291- acorn-typescript@1.4.13:
1292- resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==}
1293- peerDependencies:
1294- acorn: '>=8.9.0'
1295-
12961400 acorn-walk@8.3.4:
12971401 resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
12981402 engines: {node: '>=0.4.0'}
12991403
1300- acorn@8.14.0:
1301- resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
1404+ acorn@8.15.0:
1405+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
13021406 engines: {node: '>=0.4.0'}
13031407 hasBin: true
13041408
1409+ agent-base@7.1.3:
1410+ resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
1411+ engines: {node: '>= 14'}
1412+
13051413 ajv@6.12.6:
13061414 resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
13071415
@@ -1349,8 +1457,8 @@ packages:
13491457 resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
13501458 engines: {node: '>=8.0.0'}
13511459
1352- autoprefixer@10.4.20:
1353- resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
1460+ autoprefixer@10.4.21:
1461+ resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==}
13541462 engines: {node: ^10 || ^12 || >=14}
13551463 hasBin: true
13561464 peerDependencies:
@@ -1360,6 +1468,9 @@ packages:
13601468 resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
13611469 engines: {node: '>= 0.4'}
13621470
1471+ bail@2.0.2:
1472+ resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
1473+
13631474 balanced-match@1.0.2:
13641475 resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
13651476
@@ -1370,18 +1481,18 @@ packages:
13701481 blake3-wasm@2.1.5:
13711482 resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
13721483
1373- brace-expansion@1.1.11:
1374- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
1484+ brace-expansion@1.1.12:
1485+ resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
13751486
1376- brace-expansion@2.0.1:
1377- resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
1487+ brace-expansion@2.0.2:
1488+ resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
13781489
13791490 braces@3.0.3:
13801491 resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
13811492 engines: {node: '>=8'}
13821493
1383- browserslist@4.24.4:
1384- resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==}
1494+ browserslist@4.25.1:
1495+ resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==}
13851496 engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
13861497 hasBin: true
13871498
@@ -1400,8 +1511,11 @@ packages:
14001511 resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
14011512 engines: {node: '>= 6'}
14021513
1403- caniuse-lite@1.0.30001700:
1404- resolution: {integrity: sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==}
1514+ caniuse-lite@1.0.30001726:
1515+ resolution: {integrity: sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==}
1516+
1517+ ccount@2.0.1:
1518+ resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
14051519
14061520 chai@5.2.0:
14071521 resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
@@ -1411,6 +1525,15 @@ packages:
14111525 resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
14121526 engines: {node: '>=10'}
14131527
1528+ character-entities-html4@2.1.0:
1529+ resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
1530+
1531+ character-entities-legacy@3.0.0:
1532+ resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
1533+
1534+ character-entities@2.0.2:
1535+ resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
1536+
14141537 check-error@2.1.1:
14151538 resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
14161539 engines: {node: '>= 16'}
@@ -1437,6 +1560,9 @@ packages:
14371560 colorette@2.0.20:
14381561 resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
14391562
1563+ comma-separated-tokens@2.0.3:
1564+ resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
1565+
14401566 commander@2.20.3:
14411567 resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
14421568
@@ -1467,6 +1593,10 @@ packages:
14671593 engines: {node: '>=4'}
14681594 hasBin: true
14691595
1596+ cssstyle@4.6.0:
1597+ resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==}
1598+ engines: {node: '>=18'}
1599+
14701600 data-uri-to-buffer@2.0.2:
14711601 resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==}
14721602
@@ -1474,11 +1604,15 @@ packages:
14741604 resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
14751605 engines: {node: '>= 12'}
14761606
1607+ data-urls@5.0.0:
1608+ resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
1609+ engines: {node: '>=18'}
1610+
14771611 dateformat@4.6.3:
14781612 resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
14791613
1480- debug@4.4.0:
1481- resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
1614+ debug@4.4.1:
1615+ resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
14821616 engines: {node: '>=6.0'}
14831617 peerDependencies:
14841618 supports-color: '*'
@@ -1486,6 +1620,12 @@ packages:
14861620 supports-color:
14871621 optional: true
14881622
1623+ decimal.js@10.5.0:
1624+ resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==}
1625+
1626+ decode-named-character-reference@1.2.0:
1627+ resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==}
1628+
14891629 deep-eql@5.0.2:
14901630 resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
14911631 engines: {node: '>=6'}
@@ -1500,6 +1640,10 @@ packages:
15001640 defu@6.1.4:
15011641 resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
15021642
1643+ dequal@2.0.3:
1644+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
1645+ engines: {node: '>=6'}
1646+
15031647 detect-libc@2.0.2:
15041648 resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
15051649 engines: {node: '>=8'}
@@ -1507,18 +1651,21 @@ packages:
15071651 devalue@5.1.1:
15081652 resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==}
15091653
1654+ devlop@1.1.0:
1655+ resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
1656+
15101657 didyoumean@1.2.2:
15111658 resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
15121659
15131660 dlv@1.1.3:
15141661 resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
15151662
1516- dotenv@16.4.7:
1517- resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
1663+ dotenv@16.6.1:
1664+ resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
15181665 engines: {node: '>=12'}
15191666
1520- drizzle-kit@0.30.4:
1521- resolution: {integrity: sha512-B2oJN5UkvwwNHscPWXDG5KqAixu7AUzZ3qbe++KU9SsQ+cZWR4DXEPYcvWplyFAno0dhRJECNEhNxiDmFaPGyQ==}
1667+ drizzle-kit@0.30.6:
1668+ resolution: {integrity: sha512-U4wWit0fyZuGuP7iNmRleQyK2V8wCuv57vf5l3MnG4z4fzNTjY/U13M8owyQ5RavqvqxBifWORaR3wIUzlN64g==}
15221669 hasBin: true
15231670
15241671 drizzle-orm@0.39.3:
@@ -1610,8 +1757,8 @@ packages:
16101757 eastasianwidth@0.2.0:
16111758 resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
16121759
1613- electron-to-chromium@1.5.101:
1614- resolution: {integrity: sha512-L0ISiQrP/56Acgu4/i/kfPwWSgrzYZUnQrC0+QPFuhqlLP1Ir7qzPPDVS9BcKIyWTRU8+o6CC8dKw38tSWhYIA==}
1760+ electron-to-chromium@1.5.179:
1761+ resolution: {integrity: sha512-UWKi/EbBopgfFsc5k61wFpV7WrnnSlSzW/e2XcBmS6qKYTivZlLtoll5/rdqRTxGglGHkmkW0j0pFNJG10EUIQ==}
16151762
16161763 emoji-regex@8.0.0:
16171764 resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1619,11 +1766,19 @@ packages:
16191766 emoji-regex@9.2.2:
16201767 resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
16211768
1622- end-of-stream@1.4.4:
1623- resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
1769+ end-of-stream@1.4.5:
1770+ resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
1771+
1772+ entities@6.0.1:
1773+ resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
1774+ engines: {node: '>=0.12'}
16241775
1625- es-module-lexer@1.6.0:
1626- resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==}
1776+ env-paths@3.0.0:
1777+ resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==}
1778+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
1779+
1780+ es-module-lexer@1.7.0:
1781+ resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
16271782
16281783 esbuild-register@3.6.0:
16291784 resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==}
@@ -1645,13 +1800,13 @@ packages:
16451800 engines: {node: '>=12'}
16461801 hasBin: true
16471802
1648- esbuild@0.23.1:
1649- resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
1803+ esbuild@0.24.2:
1804+ resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
16501805 engines: {node: '>=18'}
16511806 hasBin: true
16521807
1653- esbuild@0.24.2:
1654- resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
1808+ esbuild@0.25.5:
1809+ resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==}
16551810 engines: {node: '>=18'}
16561811 hasBin: true
16571812
@@ -1669,8 +1824,8 @@ packages:
16691824 peerDependencies:
16701825 eslint: '>=6.0.0'
16711826
1672- eslint-config-prettier@10.0.1:
1673- resolution: {integrity: sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==}
1827+ eslint-config-prettier@10.1.5:
1828+ resolution: {integrity: sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==}
16741829 hasBin: true
16751830 peerDependencies:
16761831 eslint: '>=7.0.0'
@@ -1689,20 +1844,20 @@ packages:
16891844 resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
16901845 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
16911846
1692- eslint-scope@8.2.0:
1693- resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==}
1847+ eslint-scope@8.4.0:
1848+ resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
16941849 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
16951850
16961851 eslint-visitor-keys@3.4.3:
16971852 resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
16981853 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
16991854
1700- eslint-visitor-keys@4.2.0:
1701- resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
1855+ eslint-visitor-keys@4.2.1:
1856+ resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
17021857 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
17031858
1704- eslint@9.20.1:
1705- resolution: {integrity: sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==}
1859+ eslint@9.30.1:
1860+ resolution: {integrity: sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==}
17061861 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
17071862 hasBin: true
17081863 peerDependencies:
@@ -1714,8 +1869,8 @@ packages:
17141869 esm-env@1.2.2:
17151870 resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
17161871
1717- espree@10.3.0:
1718- resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
1872+ espree@10.4.0:
1873+ resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
17191874 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
17201875
17211876 espree@9.6.1:
@@ -1726,8 +1881,8 @@ packages:
17261881 resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
17271882 engines: {node: '>=0.10'}
17281883
1729- esrap@1.4.5:
1730- resolution: {integrity: sha512-CjNMjkBWWZeHn+VX+gS8YvFwJ5+NDhg8aWZBSFJPR8qQduDNjbJodA2WcwCm7uQa5Rjqj+nZvVmceg1RbHFB9g==}
1884+ esrap@2.1.0:
1885+ resolution: {integrity: sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==}
17311886
17321887 esrecurse@4.3.0:
17331888 resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
@@ -1751,10 +1906,13 @@ packages:
17511906 resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==}
17521907 engines: {node: '>=6'}
17531908
1754- expect-type@1.1.0:
1755- resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
1909+ expect-type@1.2.1:
1910+ resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==}
17561911 engines: {node: '>=12.0.0'}
17571912
1913+ extend@3.0.2:
1914+ resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
1915+
17581916 fast-copy@3.0.2:
17591917 resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==}
17601918
@@ -1778,11 +1936,11 @@ packages:
17781936 fast-safe-stringify@2.1.1:
17791937 resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
17801938
1781- fastq@1.19.0:
1782- resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==}
1939+ fastq@1.19.1:
1940+ resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
17831941
1784- fdir@6.4.3:
1785- resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==}
1942+ fdir@6.4.6:
1943+ resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
17861944 peerDependencies:
17871945 picomatch: ^3 || ^4
17881946 peerDependenciesMeta:
@@ -1809,11 +1967,11 @@ packages:
18091967 resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
18101968 engines: {node: '>=16'}
18111969
1812- flatted@3.3.2:
1813- resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
1970+ flatted@3.3.3:
1971+ resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
18141972
1815- foreground-child@3.3.0:
1816- resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
1973+ foreground-child@3.3.1:
1974+ resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
18171975 engines: {node: '>=14'}
18181976
18191977 formdata-polyfill@4.0.10:
@@ -1831,11 +1989,16 @@ packages:
18311989 function-bind@1.1.2:
18321990 resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
18331991
1992+ gel@2.1.1:
1993+ resolution: {integrity: sha512-Newg9X7mRYskoBjSw70l1YnJ/ZGbq64VPyR821H5WVkTGpHG2O0mQILxCeUhxdYERLFY9B4tUyKLyf3uMTjtKw==}
1994+ engines: {node: '>= 18.0.0'}
1995+ hasBin: true
1996+
18341997 get-source@2.0.12:
18351998 resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==}
18361999
1837- get-tsconfig@4.10.0:
1838- resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==}
2000+ get-tsconfig@4.10.1:
2001+ resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==}
18392002
18402003 glob-parent@5.1.2:
18412004 resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
@@ -1871,20 +2034,61 @@ packages:
18712034 resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
18722035 engines: {node: '>= 0.4'}
18732036
2037+ hast-util-from-html@2.0.3:
2038+ resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==}
2039+
2040+ hast-util-from-parse5@8.0.3:
2041+ resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
2042+
2043+ hast-util-parse-selector@4.0.0:
2044+ resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
2045+
2046+ hast-util-sanitize@5.0.2:
2047+ resolution: {integrity: sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==}
2048+
2049+ hast-util-to-html@9.0.5:
2050+ resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
2051+
2052+ hast-util-whitespace@3.0.0:
2053+ resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
2054+
2055+ hastscript@9.0.1:
2056+ resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
2057+
18742058 help-me@5.0.0:
18752059 resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
18762060
2061+ html-encoding-sniffer@4.0.0:
2062+ resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
2063+ engines: {node: '>=18'}
2064+
2065+ html-void-elements@3.0.0:
2066+ resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
2067+
2068+ http-proxy-agent@7.0.2:
2069+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
2070+ engines: {node: '>= 14'}
2071+
2072+ https-proxy-agent@7.0.6:
2073+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
2074+ engines: {node: '>= 14'}
2075+
2076+ iconv-lite@0.6.3:
2077+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
2078+ engines: {node: '>=0.10.0'}
2079+
18772080 ignore@5.3.2:
18782081 resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
18792082 engines: {node: '>= 4'}
18802083
2084+ ignore@7.0.5:
2085+ resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
2086+ engines: {node: '>= 4'}
2087+
18812088 import-fresh@3.3.1:
18822089 resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
18832090 engines: {node: '>=6'}
18842091
1885- import-meta-resolve@4.1.0:
1886- resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==}
1887-
18882092 imurmurhash@0.1.4:
18892093 resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
18902094 engines: {node: '>=0.8.19'}
@@ -1913,12 +2117,23 @@ packages:
19132117 resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
19142118 engines: {node: '>=0.12.0'}
19152119
2120+ is-plain-obj@4.1.0:
2121+ resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
2122+ engines: {node: '>=12'}
2123+
2124+ is-potential-custom-element-name@1.0.1:
2125+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
2126+
19162127 is-reference@3.0.3:
19172128 resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
19182129
19192130 isexe@2.0.0:
19202131 resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
19212132
2133+ isexe@3.1.1:
2134+ resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
2135+ engines: {node: '>=16'}
2136+
19222137 jackspeak@3.4.3:
19232138 resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
19242139
@@ -1933,10 +2148,22 @@ packages:
19332148 js-base64@3.7.7:
19342149 resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
19352150
2151+ js-tokens@9.0.1:
2152+ resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
2153+
19362154 js-yaml@4.1.0:
19372155 resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
19382156 hasBin: true
19392157
2158+ jsdom@26.1.0:
2159+ resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==}
2160+ engines: {node: '>=18'}
2161+ peerDependencies:
2162+ canvas: ^3.0.0
2163+ peerDependenciesMeta:
2164+ canvas:
2165+ optional: true
2166+
19402167 json-buffer@3.0.1:
19412168 resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
19422169
@@ -1992,8 +2219,8 @@ packages:
19922219 lodash.merge@4.6.2:
19932220 resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
19942221
1995- loupe@3.1.3:
1996- resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
2222+ loupe@3.1.4:
2223+ resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==}
19972224
19982225 lru-cache@10.4.3:
19992226 resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
@@ -2004,10 +2231,82 @@ packages:
20042231 magic-string@0.30.17:
20052232 resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
20062233
2234+ mdast-util-from-markdown@2.0.2:
2235+ resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==}
2236+
2237+ mdast-util-to-hast@13.2.0:
2238+ resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==}
2239+
2240+ mdast-util-to-string@4.0.0:
2241+ resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
2242+
20072243 merge2@1.4.1:
20082244 resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
20092245 engines: {node: '>= 8'}
20102246
2247+ micromark-core-commonmark@2.0.3:
2248+ resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
2249+
2250+ micromark-factory-destination@2.0.1:
2251+ resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
2252+
2253+ micromark-factory-label@2.0.1:
2254+ resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==}
2255+
2256+ micromark-factory-space@2.0.1:
2257+ resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==}
2258+
2259+ micromark-factory-title@2.0.1:
2260+ resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==}
2261+
2262+ micromark-factory-whitespace@2.0.1:
2263+ resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==}
2264+
2265+ micromark-util-character@2.1.1:
2266+ resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
2267+
2268+ micromark-util-chunked@2.0.1:
2269+ resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==}
2270+
2271+ micromark-util-classify-character@2.0.1:
2272+ resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==}
2273+
2274+ micromark-util-combine-extensions@2.0.1:
2275+ resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==}
2276+
2277+ micromark-util-decode-numeric-character-reference@2.0.2:
2278+ resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==}
2279+
2280+ micromark-util-decode-string@2.0.1:
2281+ resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==}
2282+
2283+ micromark-util-encode@2.0.1:
2284+ resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
2285+
2286+ micromark-util-html-tag-name@2.0.1:
2287+ resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==}
2288+
2289+ micromark-util-normalize-identifier@2.0.1:
2290+ resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==}
2291+
2292+ micromark-util-resolve-all@2.0.1:
2293+ resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==}
2294+
2295+ micromark-util-sanitize-uri@2.0.1:
2296+ resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
2297+
2298+ micromark-util-subtokenize@2.1.0:
2299+ resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==}
2300+
2301+ micromark-util-symbol@2.0.1:
2302+ resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
2303+
2304+ micromark-util-types@2.0.2:
2305+ resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==}
2306+
2307+ micromark@4.0.2:
2308+ resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
2309+
20112310 micromatch@4.0.8:
20122311 resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
20132312 engines: {node: '>=8.6'}
@@ -2047,8 +2346,8 @@ packages:
20472346 resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
20482347 engines: {node: '>=4'}
20492348
2050- mrmime@2.0.0:
2051- resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==}
2349+ mrmime@2.0.1:
2350+ resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
20522351 engines: {node: '>=10'}
20532352
20542353 ms@2.1.3:
@@ -2061,8 +2360,8 @@ packages:
20612360 mz@2.7.0:
20622361 resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
20632362
2064- nanoid@3.3.8:
2065- resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
2363+ nanoid@3.3.11:
2364+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
20662365 engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
20672366 hasBin: true
20682367
@@ -2072,6 +2371,7 @@ packages:
20722371 node-domexception@1.0.0:
20732372 resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
20742373 engines: {node: '>=10.5.0'}
2374+ deprecated: Use your platform's native DOMException instead
20752375
20762376 node-fetch@3.3.2:
20772377 resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
@@ -2088,6 +2388,9 @@ packages:
20882388 resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
20892389 engines: {node: '>=0.10.0'}
20902390
2391+ nwsapi@2.2.20:
2392+ resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==}
2393+
20912394 object-assign@4.1.1:
20922395 resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
20932396 engines: {node: '>=0.10.0'}
@@ -2096,8 +2399,8 @@ packages:
20962399 resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
20972400 engines: {node: '>= 6'}
20982401
2099- ohash@1.1.4:
2100- resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==}
2402+ ohash@1.1.6:
2403+ resolution: {integrity: sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg==}
21012404
21022405 on-exit-leak-free@2.1.2:
21032406 resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
@@ -2125,6 +2428,9 @@ packages:
21252428 resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
21262429 engines: {node: '>=6'}
21272430
2431+ parse5@7.3.0:
2432+ resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
2433+
21282434 path-exists@4.0.0:
21292435 resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
21302436 engines: {node: '>=8'}
@@ -2149,8 +2455,8 @@ packages:
21492455 pathe@2.0.3:
21502456 resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
21512457
2152- pathval@2.0.0:
2153- resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
2458+ pathval@2.0.1:
2459+ resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
21542460 engines: {node: '>= 14.16'}
21552461
21562462 picocolors@1.1.1:
@@ -2160,6 +2466,10 @@ packages:
21602466 resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
21612467 engines: {node: '>=8.6'}
21622468
2469+ picomatch@4.0.2:
2470+ resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
2471+ engines: {node: '>=12'}
2472+
21632473 pify@2.3.0:
21642474 resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
21652475 engines: {node: '>=0.10.0'}
@@ -2174,12 +2484,12 @@ packages:
21742484 pino-std-serializers@7.0.0:
21752485 resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==}
21762486
2177- pino@9.6.0:
2178- resolution: {integrity: sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==}
2487+ pino@9.7.0:
2488+ resolution: {integrity: sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg==}
21792489 hasBin: true
21802490
2181- pirates@4.0.6:
2182- resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
2491+ pirates@4.0.7:
2492+ resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
21832493 engines: {node: '>= 6'}
21842494
21852495 pkg-types@1.3.1:
@@ -2250,22 +2560,22 @@ packages:
22502560 postcss-value-parser@4.2.0:
22512561 resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
22522562
2253- postcss@8.5.2:
2254- resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==}
2563+ postcss@8.5.6:
2564+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
22552565 engines: {node: ^10 || ^12 || >=14}
22562566
22572567 prelude-ls@1.2.1:
22582568 resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
22592569 engines: {node: '>= 0.8.0'}
22602570
2261- prettier-plugin-svelte@3.3.3:
2262- resolution: {integrity: sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==}
2571+ prettier-plugin-svelte@3.4.0:
2572+ resolution: {integrity: sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==}
22632573 peerDependencies:
22642574 prettier: ^3.0.0
22652575 svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0
22662576
2267- prettier-plugin-tailwindcss@0.6.11:
2268- resolution: {integrity: sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==}
2577+ prettier-plugin-tailwindcss@0.6.13:
2578+ resolution: {integrity: sha512-uQ0asli1+ic8xrrSmIOaElDu0FacR4x69GynTh2oZjFY10JUt6EEumTQl5tB4fMeD6I1naKd+4rXQQ7esT2i1g==}
22692579 engines: {node: '>=14.21.3'}
22702580 peerDependencies:
22712581 '@ianvs/prettier-plugin-sort-imports': '*'
@@ -2319,22 +2629,25 @@ packages:
23192629 prettier-plugin-svelte:
23202630 optional: true
23212631
2322- prettier@3.5.1:
2323- resolution: {integrity: sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==}
2632+ prettier@3.6.2:
2633+ resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
23242634 engines: {node: '>=14'}
23252635 hasBin: true
23262636
23272637 printable-characters@1.0.42:
23282638 resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==}
23292639
2330- process-warning@4.0.1:
2331- resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==}
2640+ process-warning@5.0.0:
2641+ resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==}
23322642
23332643 promise-limit@2.7.0:
23342644 resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==}
23352645
2336- pump@3.0.2:
2337- resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
2646+ property-information@7.1.0:
2647+ resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
2648+
2649+ pump@3.0.3:
2650+ resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
23382651
23392652 punycode@2.3.1:
23402653 resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
@@ -2365,6 +2678,24 @@ packages:
23652678 resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==}
23662679 engines: {node: '>=8'}
23672680
2681+ rehype-parse@9.0.1:
2682+ resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==}
2683+
2684+ rehype-sanitize@6.0.0:
2685+ resolution: {integrity: sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==}
2686+
2687+ rehype-stringify@10.0.1:
2688+ resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==}
2689+
2690+ rehype@13.0.2:
2691+ resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==}
2692+
2693+ remark-parse@11.0.0:
2694+ resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
2695+
2696+ remark-rehype@11.1.2:
2697+ resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==}
2698+
23682699 resolve-from@4.0.0:
23692700 resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
23702701 engines: {node: '>=4'}
@@ -2377,8 +2708,8 @@ packages:
23772708 engines: {node: '>= 0.4'}
23782709 hasBin: true
23792710
2380- reusify@1.0.4:
2381- resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
2711+ reusify@1.1.0:
2712+ resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
23822713 engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
23832714
23842715 rollup-plugin-inject@3.0.2:
@@ -2391,11 +2722,14 @@ packages:
23912722 rollup-pluginutils@2.8.2:
23922723 resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==}
23932724
2394- rollup@4.34.8:
2395- resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==}
2725+ rollup@4.44.1:
2726+ resolution: {integrity: sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==}
23962727 engines: {node: '>=18.0.0', npm: '>=8.0.0'}
23972728 hasBin: true
23982729
2730+ rrweb-cssom@0.8.0:
2731+ resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
2732+
23992733 run-parallel@1.2.0:
24002734 resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
24012735
@@ -2407,11 +2741,18 @@ packages:
24072741 resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
24082742 engines: {node: '>=10'}
24092743
2744+ safer-buffer@2.1.2:
2745+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
2746+
2747+ saxes@6.0.0:
2748+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
2749+ engines: {node: '>=v12.22.7'}
2750+
24102751 secure-json-parse@2.7.0:
24112752 resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
24122753
2413- semver@7.7.1:
2414- resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
2754+ semver@7.7.2:
2755+ resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
24152756 engines: {node: '>=10'}
24162757 hasBin: true
24172758
@@ -2426,6 +2767,10 @@ packages:
24262767 resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
24272768 engines: {node: '>=8'}
24282769
2770+ shell-quote@1.8.3:
2771+ resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==}
2772+ engines: {node: '>= 0.4'}
2773+
24292774 siginfo@2.0.0:
24302775 resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
24312776
@@ -2433,8 +2778,8 @@ packages:
24332778 resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
24342779 engines: {node: '>=14'}
24352780
2436- sirv@3.0.0:
2437- resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==}
2781+ sirv@3.0.1:
2782+ resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
24382783 engines: {node: '>=18'}
24392784
24402785 sonic-boom@4.2.0:
@@ -2455,6 +2800,9 @@ packages:
24552800 resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
24562801 deprecated: Please use @jridgewell/sourcemap-codec instead
24572802
2803+ space-separated-tokens@2.0.2:
2804+ resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
2805+
24582806 split2@4.2.0:
24592807 resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
24602808 engines: {node: '>= 10.x'}
@@ -2465,8 +2813,8 @@ packages:
24652813 stacktracey@2.1.8:
24662814 resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==}
24672815
2468- std-env@3.8.0:
2469- resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==}
2816+ std-env@3.9.0:
2817+ resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==}
24702818
24712819 stoppable@1.1.0:
24722820 resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==}
@@ -2480,6 +2828,9 @@ packages:
24802828 resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
24812829 engines: {node: '>=12'}
24822830
2831+ stringify-entities@4.0.4:
2832+ resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
2833+
24832834 strip-ansi@6.0.1:
24842835 resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
24852836 engines: {node: '>=8'}
@@ -2492,6 +2843,9 @@ packages:
24922843 resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
24932844 engines: {node: '>=8'}
24942845
2846+ strip-literal@3.0.0:
2847+ resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==}
2848+
24952849 sucrase@3.35.0:
24962850 resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
24972851 engines: {node: '>=16 || 14 >=14.17'}
@@ -2505,8 +2859,8 @@ packages:
25052859 resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
25062860 engines: {node: '>= 0.4'}
25072861
2508- svelte-check@4.1.4:
2509- resolution: {integrity: sha512-v0j7yLbT29MezzaQJPEDwksybTE2Ups9rUxEXy92T06TiA0cbqcO8wAOwNUVkFW6B0hsYHA+oAX3BS8b/2oHtw==}
2862+ svelte-check@4.2.2:
2863+ resolution: {integrity: sha512-1+31EOYZ7NKN0YDMKusav2hhEoA51GD9Ws6o//0SphMT0ve9mBTsTUEX7OmDMadUP3KjNHsSKtJrqdSaD8CrGQ==}
25102864 engines: {node: '>= 18.0.0'}
25112865 hasBin: true
25122866 peerDependencies:
@@ -2522,17 +2876,20 @@ packages:
25222876 svelte:
25232877 optional: true
25242878
2525- svelte@5.20.1:
2526- resolution: {integrity: sha512-aCARru2WTdzJl55Ws8SK27+kvQwd8tijl4kY7NoDUXUHtTHhxMa8Lf6QNZKmU7cuPu3jjFloDO1j5HgYJNIIWg==}
2879+ svelte@5.35.2:
2880+ resolution: {integrity: sha512-uW/rRXYrhZ7Dh4UQNZ0t+oVGL1dEM+95GavCO8afAk1IY2cPq9BcZv9C3um5aLIya2y8lIeLPxLII9ASGg9Dzw==}
25272881 engines: {node: '>=18'}
25282882
2883+ symbol-tree@3.2.4:
2884+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
2885+
25292886 tailwindcss@3.4.17:
25302887 resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==}
25312888 engines: {node: '>=14.0.0'}
25322889 hasBin: true
25332890
2534- terser@5.39.0:
2535- resolution: {integrity: sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==}
2891+ terser@5.43.1:
2892+ resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==}
25362893 engines: {node: '>=10'}
25372894 hasBin: true
25382895
@@ -2552,18 +2909,29 @@ packages:
25522909 tinyexec@0.3.2:
25532910 resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
25542911
2555- tinypool@1.0.2:
2556- resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==}
2912+ tinyglobby@0.2.14:
2913+ resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
2914+ engines: {node: '>=12.0.0'}
2915+
2916+ tinypool@1.1.1:
2917+ resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
25572918 engines: {node: ^18.0.0 || >=20.0.0}
25582919
25592920 tinyrainbow@2.0.0:
25602921 resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
25612922 engines: {node: '>=14.0.0'}
25622923
2563- tinyspy@3.0.2:
2564- resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
2924+ tinyspy@4.0.3:
2925+ resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==}
25652926 engines: {node: '>=14.0.0'}
25662927
2928+ tldts-core@6.1.86:
2929+ resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==}
2930+
2931+ tldts@6.1.86:
2932+ resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==}
2933+ hasBin: true
2934+
25672935 to-regex-range@5.0.1:
25682936 resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
25692937 engines: {node: '>=8.0'}
@@ -2572,17 +2940,31 @@ packages:
25722940 resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
25732941 engines: {node: '>=6'}
25742942
2575- ts-api-utils@2.0.1:
2576- resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==}
2577- engines: {node: '>=18.12'}
2578- peerDependencies:
2579- typescript: '>=4.8.4'
2943+ tough-cookie@5.1.2:
2944+ resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==}
2945+ engines: {node: '>=16'}
2946+
2947+ tr46@5.1.1:
2948+ resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
2949+ engines: {node: '>=18'}
2950+
2951+ trim-lines@3.0.1:
2952+ resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
2953+
2954+ trough@2.2.0:
2955+ resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
2956+
2957+ ts-api-utils@2.1.0:
2958+ resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
2959+ engines: {node: '>=18.12'}
2960+ peerDependencies:
2961+ typescript: '>=4.8.4'
25802962
25812963 ts-interface-checker@0.1.13:
25822964 resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
25832965
2584- tsx@4.19.2:
2585- resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==}
2966+ tsx@4.20.3:
2967+ resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==}
25862968 engines: {node: '>=18.0.0'}
25872969 hasBin: true
25882970
@@ -2590,33 +2972,51 @@ packages:
25902972 resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
25912973 engines: {node: '>= 0.8.0'}
25922974
2593- typescript-eslint@8.24.0:
2594- resolution: {integrity: sha512-/lmv4366en/qbB32Vz5+kCNZEMf6xYHwh1z48suBwZvAtnXKbP+YhGe8OLE2BqC67LMqKkCNLtjejdwsdW6uOQ==}
2975+ typescript-eslint@8.35.1:
2976+ resolution: {integrity: sha512-xslJjFzhOmHYQzSB/QTeASAHbjmxOGEP6Coh93TXmUBFQoJ1VU35UHIDmG06Jd6taf3wqqC1ntBnCMeymy5Ovw==}
25952977 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
25962978 peerDependencies:
25972979 eslint: ^8.57.0 || ^9.0.0
2598- typescript: '>=4.8.4 <5.8.0'
2980+ typescript: '>=4.8.4 <5.9.0'
25992981
2600- typescript@5.7.3:
2601- resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==}
2982+ typescript@5.8.3:
2983+ resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
26022984 engines: {node: '>=14.17'}
26032985 hasBin: true
26042986
2605- ufo@1.5.4:
2606- resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
2987+ ufo@1.6.1:
2988+ resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
26072989
2608- undici-types@6.20.0:
2609- resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
2990+ undici-types@6.21.0:
2991+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
26102992
2611- undici@5.28.5:
2612- resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==}
2993+ undici@5.29.0:
2994+ resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==}
26132995 engines: {node: '>=14.0'}
26142996
26152997 unenv@2.0.0-rc.1:
26162998 resolution: {integrity: sha512-PU5fb40H8X149s117aB4ytbORcCvlASdtF97tfls4BPIyj4PeVxvpSuy1jAptqYHqB0vb2w2sHvzM0XWcp2OKg==}
26172999
2618- update-browserslist-db@1.1.2:
2619- resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==}
3000+ unified@11.0.5:
3001+ resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
3002+
3003+ unist-util-is@6.0.0:
3004+ resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
3005+
3006+ unist-util-position@5.0.0:
3007+ resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
3008+
3009+ unist-util-stringify-position@4.0.0:
3010+ resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
3011+
3012+ unist-util-visit-parents@6.0.1:
3013+ resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
3014+
3015+ unist-util-visit@5.0.0:
3016+ resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
3017+
3018+ update-browserslist-db@1.1.3:
3019+ resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
26203020 hasBin: true
26213021 peerDependencies:
26223022 browserslist: '>= 4.21.0'
@@ -2627,17 +3027,26 @@ packages:
26273027 util-deprecate@1.0.2:
26283028 resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
26293029
2630- uuid@11.0.5:
2631- resolution: {integrity: sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==}
3030+ uuid@11.1.0:
3031+ resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
26323032 hasBin: true
26333033
2634- vite-node@3.0.5:
2635- resolution: {integrity: sha512-02JEJl7SbtwSDJdYS537nU6l+ktdvcREfLksk/NDAqtdKWGqHl+joXzEubHROmS3E6pip+Xgu2tFezMu75jH7A==}
3034+ vfile-location@5.0.3:
3035+ resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
3036+
3037+ vfile-message@4.0.2:
3038+ resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
3039+
3040+ vfile@6.0.3:
3041+ resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
3042+
3043+ vite-node@3.2.4:
3044+ resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
26363045 engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
26373046 hasBin: true
26383047
2639- vite@6.1.0:
2640- resolution: {integrity: sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==}
3048+ vite@6.3.5:
3049+ resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==}
26413050 engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
26423051 hasBin: true
26433052 peerDependencies:
@@ -2676,24 +3085,24 @@ packages:
26763085 yaml:
26773086 optional: true
26783087
2679- vitefu@1.0.5:
2680- resolution: {integrity: sha512-h4Vflt9gxODPFNGPwp4zAMZRpZR7eslzwH2c5hn5kNZ5rhnKyRJ50U+yGCdc2IRaBs8O4haIgLNGrV5CrpMsCA==}
3088+ vitefu@1.1.0:
3089+ resolution: {integrity: sha512-AiG/L9DVsEYHWQ9jAEnke0nKiASlPw+JYwDl6Z4l6a6/IqT1tKseEl6R5+rVnKJt/K3jCTWiQvgoIh5MuqBJJQ==}
26813090 peerDependencies:
2682- vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
3091+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
26833092 peerDependenciesMeta:
26843093 vite:
26853094 optional: true
26863095
2687- vitest@3.0.5:
2688- resolution: {integrity: sha512-4dof+HvqONw9bvsYxtkfUp2uHsTN9bV2CZIi1pWgoFpL1Lld8LA1ka9q/ONSsoScAKG7NVGf2stJTI7XRkXb2Q==}
3096+ vitest@3.2.4:
3097+ resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
26893098 engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
26903099 hasBin: true
26913100 peerDependencies:
26923101 '@edge-runtime/vm': '*'
26933102 '@types/debug': ^4.1.12
26943103 '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
2695- '@vitest/browser': 3.0.5
2696- '@vitest/ui': 3.0.5
3104+ '@vitest/browser': 3.2.4
3105+ '@vitest/ui': 3.2.4
26973106 happy-dom: '*'
26983107 jsdom: '*'
26993108 peerDependenciesMeta:
@@ -2712,15 +3121,43 @@ packages:
27123121 jsdom:
27133122 optional: true
27143123
3124+ w3c-xmlserializer@5.0.0:
3125+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
3126+ engines: {node: '>=18'}
3127+
3128+ web-namespaces@2.0.1:
3129+ resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
3130+
27153131 web-streams-polyfill@3.3.3:
27163132 resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
27173133 engines: {node: '>= 8'}
27183134
3135+ webidl-conversions@7.0.0:
3136+ resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
3137+ engines: {node: '>=12'}
3138+
3139+ whatwg-encoding@3.1.1:
3140+ resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
3141+ engines: {node: '>=18'}
3142+
3143+ whatwg-mimetype@4.0.0:
3144+ resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
3145+ engines: {node: '>=18'}
3146+
3147+ whatwg-url@14.2.0:
3148+ resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
3149+ engines: {node: '>=18'}
3150+
27193151 which@2.0.2:
27203152 resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
27213153 engines: {node: '>= 8'}
27223154 hasBin: true
27233155
3156+ which@4.0.0:
3157+ resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
3158+ engines: {node: ^16.13.0 || >=18.0.0}
3159+ hasBin: true
3160+
27243161 why-is-node-running@2.3.0:
27253162 resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
27263163 engines: {node: '>=8'}
@@ -2760,8 +3197,8 @@ packages:
27603197 wrappy@1.0.2:
27613198 resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
27623199
2763- ws@8.18.0:
2764- resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
3200+ ws@8.18.3:
3201+ resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
27653202 engines: {node: '>=10.0.0'}
27663203 peerDependencies:
27673204 bufferutil: ^4.0.1
@@ -2772,6 +3209,13 @@ packages:
27723209 utf-8-validate:
27733210 optional: true
27743211
3212+ xml-name-validator@5.0.0:
3213+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
3214+ engines: {node: '>=18'}
3215+
3216+ xmlchars@2.2.0:
3217+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
3218+
27753219 xp.css@0.2.6:
27763220 resolution: {integrity: sha512-v0qUB4wOvyXIMLNid5bIpm+0n5aL4i8wE5dqJH8LNVxE04PxUUxjwf2rNzengegUIK03XC4vbfLVCPAfMLtuqA==}
27773221
@@ -2779,9 +3223,9 @@ packages:
27793223 resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
27803224 engines: {node: '>= 6'}
27813225
2782- yaml@2.7.0:
2783- resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==}
2784- engines: {node: '>= 14'}
3226+ yaml@2.8.0:
3227+ resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==}
3228+ engines: {node: '>= 14.6'}
27853229 hasBin: true
27863230
27873231 yocto-queue@0.1.0:
@@ -2794,8 +3238,11 @@ packages:
27943238 zimmerframe@1.1.2:
27953239 resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
27963240
2797- zod@3.24.2:
2798- resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==}
3241+ zod@3.25.71:
3242+ resolution: {integrity: sha512-BsBc/NPk7h8WsUWYWYL+BajcJPY8YhjelaWu2NMLuzgraKAz4Lb4/6K11g9jpuDetjMiqhZ6YaexFLOC0Ogi3Q==}
3243+
3244+ zwitch@2.0.4:
3245+ resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
27993246
28003247 snapshots:
28013248
@@ -2803,8 +3250,16 @@ snapshots:
28033250
28043251 '@ampproject/remapping@2.3.0':
28053252 dependencies:
2806- '@jridgewell/gen-mapping': 0.3.8
2807- '@jridgewell/trace-mapping': 0.3.25
3253+ '@jridgewell/gen-mapping': 0.3.12
3254+ '@jridgewell/trace-mapping': 0.3.29
3255+
3256+ '@asamuzakjp/css-color@3.2.0':
3257+ dependencies:
3258+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
3259+ '@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
3260+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
3261+ '@csstools/css-tokenizer': 3.0.4
3262+ lru-cache: 10.4.3
28083263
28093264 '@cloudflare/kv-asset-handler@0.3.4':
28103265 dependencies:
@@ -2825,12 +3280,32 @@ snapshots:
28253280 '@cloudflare/workerd-windows-64@1.20250129.0':
28263281 optional: true
28273282
2828- '@cloudflare/workers-types@4.20250214.0': {}
3283+ '@cloudflare/workers-types@4.20250703.0': {}
28293284
28303285 '@cspotcode/source-map-support@0.8.1':
28313286 dependencies:
28323287 '@jridgewell/trace-mapping': 0.3.9
28333288
3289+ '@csstools/color-helpers@5.0.2': {}
3290+
3291+ '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
3292+ dependencies:
3293+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
3294+ '@csstools/css-tokenizer': 3.0.4
3295+
3296+ '@csstools/css-color-parser@3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
3297+ dependencies:
3298+ '@csstools/color-helpers': 5.0.2
3299+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
3300+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
3301+ '@csstools/css-tokenizer': 3.0.4
3302+
3303+ '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
3304+ dependencies:
3305+ '@csstools/css-tokenizer': 3.0.4
3306+
3307+ '@csstools/css-tokenizer@3.0.4': {}
3308+
28343309 '@drizzle-team/brocli@0.10.2': {}
28353310
28363311 '@esbuild-kit/core-utils@3.3.2':
@@ -2841,7 +3316,7 @@ snapshots:
28413316 '@esbuild-kit/esm-loader@2.6.5':
28423317 dependencies:
28433318 '@esbuild-kit/core-utils': 3.3.2
2844- get-tsconfig: 4.10.0
3319+ get-tsconfig: 4.10.1
28453320
28463321 '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)':
28473322 dependencies:
@@ -2856,10 +3331,10 @@ snapshots:
28563331 '@esbuild/aix-ppc64@0.19.12':
28573332 optional: true
28583333
2859- '@esbuild/aix-ppc64@0.23.1':
3334+ '@esbuild/aix-ppc64@0.24.2':
28603335 optional: true
28613336
2862- '@esbuild/aix-ppc64@0.24.2':
3337+ '@esbuild/aix-ppc64@0.25.5':
28633338 optional: true
28643339
28653340 '@esbuild/android-arm64@0.17.19':
@@ -2871,10 +3346,10 @@ snapshots:
28713346 '@esbuild/android-arm64@0.19.12':
28723347 optional: true
28733348
2874- '@esbuild/android-arm64@0.23.1':
3349+ '@esbuild/android-arm64@0.24.2':
28753350 optional: true
28763351
2877- '@esbuild/android-arm64@0.24.2':
3352+ '@esbuild/android-arm64@0.25.5':
28783353 optional: true
28793354
28803355 '@esbuild/android-arm@0.17.19':
@@ -2886,10 +3361,10 @@ snapshots:
28863361 '@esbuild/android-arm@0.19.12':
28873362 optional: true
28883363
2889- '@esbuild/android-arm@0.23.1':
3364+ '@esbuild/android-arm@0.24.2':
28903365 optional: true
28913366
2892- '@esbuild/android-arm@0.24.2':
3367+ '@esbuild/android-arm@0.25.5':
28933368 optional: true
28943369
28953370 '@esbuild/android-x64@0.17.19':
@@ -2901,10 +3376,10 @@ snapshots:
29013376 '@esbuild/android-x64@0.19.12':
29023377 optional: true
29033378
2904- '@esbuild/android-x64@0.23.1':
3379+ '@esbuild/android-x64@0.24.2':
29053380 optional: true
29063381
2907- '@esbuild/android-x64@0.24.2':
3382+ '@esbuild/android-x64@0.25.5':
29083383 optional: true
29093384
29103385 '@esbuild/darwin-arm64@0.17.19':
@@ -2916,10 +3391,10 @@ snapshots:
29163391 '@esbuild/darwin-arm64@0.19.12':
29173392 optional: true
29183393
2919- '@esbuild/darwin-arm64@0.23.1':
3394+ '@esbuild/darwin-arm64@0.24.2':
29203395 optional: true
29213396
2922- '@esbuild/darwin-arm64@0.24.2':
3397+ '@esbuild/darwin-arm64@0.25.5':
29233398 optional: true
29243399
29253400 '@esbuild/darwin-x64@0.17.19':
@@ -2931,10 +3406,10 @@ snapshots:
29313406 '@esbuild/darwin-x64@0.19.12':
29323407 optional: true
29333408
2934- '@esbuild/darwin-x64@0.23.1':
3409+ '@esbuild/darwin-x64@0.24.2':
29353410 optional: true
29363411
2937- '@esbuild/darwin-x64@0.24.2':
3412+ '@esbuild/darwin-x64@0.25.5':
29383413 optional: true
29393414
29403415 '@esbuild/freebsd-arm64@0.17.19':
@@ -2946,10 +3421,10 @@ snapshots:
29463421 '@esbuild/freebsd-arm64@0.19.12':
29473422 optional: true
29483423
2949- '@esbuild/freebsd-arm64@0.23.1':
3424+ '@esbuild/freebsd-arm64@0.24.2':
29503425 optional: true
29513426
2952- '@esbuild/freebsd-arm64@0.24.2':
3427+ '@esbuild/freebsd-arm64@0.25.5':
29533428 optional: true
29543429
29553430 '@esbuild/freebsd-x64@0.17.19':
@@ -2961,10 +3436,10 @@ snapshots:
29613436 '@esbuild/freebsd-x64@0.19.12':
29623437 optional: true
29633438
2964- '@esbuild/freebsd-x64@0.23.1':
3439+ '@esbuild/freebsd-x64@0.24.2':
29653440 optional: true
29663441
2967- '@esbuild/freebsd-x64@0.24.2':
3442+ '@esbuild/freebsd-x64@0.25.5':
29683443 optional: true
29693444
29703445 '@esbuild/linux-arm64@0.17.19':
@@ -2976,10 +3451,10 @@ snapshots:
29763451 '@esbuild/linux-arm64@0.19.12':
29773452 optional: true
29783453
2979- '@esbuild/linux-arm64@0.23.1':
3454+ '@esbuild/linux-arm64@0.24.2':
29803455 optional: true
29813456
2982- '@esbuild/linux-arm64@0.24.2':
3457+ '@esbuild/linux-arm64@0.25.5':
29833458 optional: true
29843459
29853460 '@esbuild/linux-arm@0.17.19':
@@ -2991,10 +3466,10 @@ snapshots:
29913466 '@esbuild/linux-arm@0.19.12':
29923467 optional: true
29933468
2994- '@esbuild/linux-arm@0.23.1':
3469+ '@esbuild/linux-arm@0.24.2':
29953470 optional: true
29963471
2997- '@esbuild/linux-arm@0.24.2':
3472+ '@esbuild/linux-arm@0.25.5':
29983473 optional: true
29993474
30003475 '@esbuild/linux-ia32@0.17.19':
@@ -3006,10 +3481,10 @@ snapshots:
30063481 '@esbuild/linux-ia32@0.19.12':
30073482 optional: true
30083483
3009- '@esbuild/linux-ia32@0.23.1':
3484+ '@esbuild/linux-ia32@0.24.2':
30103485 optional: true
30113486
3012- '@esbuild/linux-ia32@0.24.2':
3487+ '@esbuild/linux-ia32@0.25.5':
30133488 optional: true
30143489
30153490 '@esbuild/linux-loong64@0.17.19':
@@ -3021,10 +3496,10 @@ snapshots:
30213496 '@esbuild/linux-loong64@0.19.12':
30223497 optional: true
30233498
3024- '@esbuild/linux-loong64@0.23.1':
3499+ '@esbuild/linux-loong64@0.24.2':
30253500 optional: true
30263501
3027- '@esbuild/linux-loong64@0.24.2':
3502+ '@esbuild/linux-loong64@0.25.5':
30283503 optional: true
30293504
30303505 '@esbuild/linux-mips64el@0.17.19':
@@ -3036,10 +3511,10 @@ snapshots:
30363511 '@esbuild/linux-mips64el@0.19.12':
30373512 optional: true
30383513
3039- '@esbuild/linux-mips64el@0.23.1':
3514+ '@esbuild/linux-mips64el@0.24.2':
30403515 optional: true
30413516
3042- '@esbuild/linux-mips64el@0.24.2':
3517+ '@esbuild/linux-mips64el@0.25.5':
30433518 optional: true
30443519
30453520 '@esbuild/linux-ppc64@0.17.19':
@@ -3051,10 +3526,10 @@ snapshots:
30513526 '@esbuild/linux-ppc64@0.19.12':
30523527 optional: true
30533528
3054- '@esbuild/linux-ppc64@0.23.1':
3529+ '@esbuild/linux-ppc64@0.24.2':
30553530 optional: true
30563531
3057- '@esbuild/linux-ppc64@0.24.2':
3532+ '@esbuild/linux-ppc64@0.25.5':
30583533 optional: true
30593534
30603535 '@esbuild/linux-riscv64@0.17.19':
@@ -3066,10 +3541,10 @@ snapshots:
30663541 '@esbuild/linux-riscv64@0.19.12':
30673542 optional: true
30683543
3069- '@esbuild/linux-riscv64@0.23.1':
3544+ '@esbuild/linux-riscv64@0.24.2':
30703545 optional: true
30713546
3072- '@esbuild/linux-riscv64@0.24.2':
3547+ '@esbuild/linux-riscv64@0.25.5':
30733548 optional: true
30743549
30753550 '@esbuild/linux-s390x@0.17.19':
@@ -3081,10 +3556,10 @@ snapshots:
30813556 '@esbuild/linux-s390x@0.19.12':
30823557 optional: true
30833558
3084- '@esbuild/linux-s390x@0.23.1':
3559+ '@esbuild/linux-s390x@0.24.2':
30853560 optional: true
30863561
3087- '@esbuild/linux-s390x@0.24.2':
3562+ '@esbuild/linux-s390x@0.25.5':
30883563 optional: true
30893564
30903565 '@esbuild/linux-x64@0.17.19':
@@ -3096,15 +3571,18 @@ snapshots:
30963571 '@esbuild/linux-x64@0.19.12':
30973572 optional: true
30983573
3099- '@esbuild/linux-x64@0.23.1':
3574+ '@esbuild/linux-x64@0.24.2':
31003575 optional: true
31013576
3102- '@esbuild/linux-x64@0.24.2':
3577+ '@esbuild/linux-x64@0.25.5':
31033578 optional: true
31043579
31053580 '@esbuild/netbsd-arm64@0.24.2':
31063581 optional: true
31073582
3583+ '@esbuild/netbsd-arm64@0.25.5':
3584+ optional: true
3585+
31083586 '@esbuild/netbsd-x64@0.17.19':
31093587 optional: true
31103588
@@ -3114,18 +3592,18 @@ snapshots:
31143592 '@esbuild/netbsd-x64@0.19.12':
31153593 optional: true
31163594
3117- '@esbuild/netbsd-x64@0.23.1':
3118- optional: true
3119-
31203595 '@esbuild/netbsd-x64@0.24.2':
31213596 optional: true
31223597
3123- '@esbuild/openbsd-arm64@0.23.1':
3598+ '@esbuild/netbsd-x64@0.25.5':
31243599 optional: true
31253600
31263601 '@esbuild/openbsd-arm64@0.24.2':
31273602 optional: true
31283603
3604+ '@esbuild/openbsd-arm64@0.25.5':
3605+ optional: true
3606+
31293607 '@esbuild/openbsd-x64@0.17.19':
31303608 optional: true
31313609
@@ -3135,10 +3613,10 @@ snapshots:
31353613 '@esbuild/openbsd-x64@0.19.12':
31363614 optional: true
31373615
3138- '@esbuild/openbsd-x64@0.23.1':
3616+ '@esbuild/openbsd-x64@0.24.2':
31393617 optional: true
31403618
3141- '@esbuild/openbsd-x64@0.24.2':
3619+ '@esbuild/openbsd-x64@0.25.5':
31423620 optional: true
31433621
31443622 '@esbuild/sunos-x64@0.17.19':
@@ -3150,10 +3628,10 @@ snapshots:
31503628 '@esbuild/sunos-x64@0.19.12':
31513629 optional: true
31523630
3153- '@esbuild/sunos-x64@0.23.1':
3631+ '@esbuild/sunos-x64@0.24.2':
31543632 optional: true
31553633
3156- '@esbuild/sunos-x64@0.24.2':
3634+ '@esbuild/sunos-x64@0.25.5':
31573635 optional: true
31583636
31593637 '@esbuild/win32-arm64@0.17.19':
@@ -3165,10 +3643,10 @@ snapshots:
31653643 '@esbuild/win32-arm64@0.19.12':
31663644 optional: true
31673645
3168- '@esbuild/win32-arm64@0.23.1':
3646+ '@esbuild/win32-arm64@0.24.2':
31693647 optional: true
31703648
3171- '@esbuild/win32-arm64@0.24.2':
3649+ '@esbuild/win32-arm64@0.25.5':
31723650 optional: true
31733651
31743652 '@esbuild/win32-ia32@0.17.19':
@@ -3180,10 +3658,10 @@ snapshots:
31803658 '@esbuild/win32-ia32@0.19.12':
31813659 optional: true
31823660
3183- '@esbuild/win32-ia32@0.23.1':
3661+ '@esbuild/win32-ia32@0.24.2':
31843662 optional: true
31853663
3186- '@esbuild/win32-ia32@0.24.2':
3664+ '@esbuild/win32-ia32@0.25.5':
31873665 optional: true
31883666
31893667 '@esbuild/win32-x64@0.17.19':
@@ -3195,44 +3673,46 @@ snapshots:
31953673 '@esbuild/win32-x64@0.19.12':
31963674 optional: true
31973675
3198- '@esbuild/win32-x64@0.23.1':
3676+ '@esbuild/win32-x64@0.24.2':
31993677 optional: true
32003678
3201- '@esbuild/win32-x64@0.24.2':
3679+ '@esbuild/win32-x64@0.25.5':
32023680 optional: true
32033681
3204- '@eslint-community/eslint-utils@4.4.1(eslint@9.20.1(jiti@1.21.7))':
3682+ '@eslint-community/eslint-utils@4.7.0(eslint@9.30.1(jiti@1.21.7))':
32053683 dependencies:
3206- eslint: 9.20.1(jiti@1.21.7)
3684+ eslint: 9.30.1(jiti@1.21.7)
32073685 eslint-visitor-keys: 3.4.3
32083686
32093687 '@eslint-community/regexpp@4.12.1': {}
32103688
3211- '@eslint/compat@1.2.6(eslint@9.20.1(jiti@1.21.7))':
3689+ '@eslint/compat@1.3.1(eslint@9.30.1(jiti@1.21.7))':
32123690 optionalDependencies:
3213- eslint: 9.20.1(jiti@1.21.7)
3691+ eslint: 9.30.1(jiti@1.21.7)
32143692
3215- '@eslint/config-array@0.19.2':
3693+ '@eslint/config-array@0.21.0':
32163694 dependencies:
32173695 '@eslint/object-schema': 2.1.6
3218- debug: 4.4.0
3696+ debug: 4.4.1
32193697 minimatch: 3.1.2
32203698 transitivePeerDependencies:
32213699 - supports-color
32223700
3223- '@eslint/core@0.10.0':
3701+ '@eslint/config-helpers@0.3.0': {}
3702+
3703+ '@eslint/core@0.14.0':
32243704 dependencies:
32253705 '@types/json-schema': 7.0.15
32263706
3227- '@eslint/core@0.11.0':
3707+ '@eslint/core@0.15.1':
32283708 dependencies:
32293709 '@types/json-schema': 7.0.15
32303710
3231- '@eslint/eslintrc@3.2.0':
3711+ '@eslint/eslintrc@3.3.1':
32323712 dependencies:
32333713 ajv: 6.12.6
3234- debug: 4.4.0
3235- espree: 10.3.0
3714+ debug: 4.4.1
3715+ espree: 10.4.0
32363716 globals: 14.0.0
32373717 ignore: 5.3.2
32383718 import-fresh: 3.3.1
@@ -3242,13 +3722,13 @@ snapshots:
32423722 transitivePeerDependencies:
32433723 - supports-color
32443724
3245- '@eslint/js@9.20.0': {}
3725+ '@eslint/js@9.30.1': {}
32463726
32473727 '@eslint/object-schema@2.1.6': {}
32483728
3249- '@eslint/plugin-kit@0.2.5':
3729+ '@eslint/plugin-kit@0.3.3':
32503730 dependencies:
3251- '@eslint/core': 0.10.0
3731+ '@eslint/core': 0.15.1
32523732 levn: 0.4.1
32533733
32543734 '@fastify/busboy@2.1.1': {}
@@ -3264,7 +3744,7 @@ snapshots:
32643744
32653745 '@humanwhocodes/retry@0.3.1': {}
32663746
3267- '@humanwhocodes/retry@0.4.1': {}
3747+ '@humanwhocodes/retry@0.4.3': {}
32683748
32693749 '@isaacs/cliui@8.0.2':
32703750 dependencies:
@@ -3275,32 +3755,29 @@ snapshots:
32753755 wrap-ansi: 8.1.0
32763756 wrap-ansi-cjs: wrap-ansi@7.0.0
32773757
3278- '@jridgewell/gen-mapping@0.3.8':
3758+ '@jridgewell/gen-mapping@0.3.12':
32793759 dependencies:
3280- '@jridgewell/set-array': 1.2.1
3281- '@jridgewell/sourcemap-codec': 1.5.0
3282- '@jridgewell/trace-mapping': 0.3.25
3760+ '@jridgewell/sourcemap-codec': 1.5.4
3761+ '@jridgewell/trace-mapping': 0.3.29
32833762
32843763 '@jridgewell/resolve-uri@3.1.2': {}
32853764
3286- '@jridgewell/set-array@1.2.1': {}
3287-
3288- '@jridgewell/source-map@0.3.6':
3765+ '@jridgewell/source-map@0.3.10':
32893766 dependencies:
3290- '@jridgewell/gen-mapping': 0.3.8
3291- '@jridgewell/trace-mapping': 0.3.25
3767+ '@jridgewell/gen-mapping': 0.3.12
3768+ '@jridgewell/trace-mapping': 0.3.29
32923769
3293- '@jridgewell/sourcemap-codec@1.5.0': {}
3770+ '@jridgewell/sourcemap-codec@1.5.4': {}
32943771
3295- '@jridgewell/trace-mapping@0.3.25':
3772+ '@jridgewell/trace-mapping@0.3.29':
32963773 dependencies:
32973774 '@jridgewell/resolve-uri': 3.1.2
3298- '@jridgewell/sourcemap-codec': 1.5.0
3775+ '@jridgewell/sourcemap-codec': 1.5.4
32993776
33003777 '@jridgewell/trace-mapping@0.3.9':
33013778 dependencies:
33023779 '@jridgewell/resolve-uri': 3.1.2
3303- '@jridgewell/sourcemap-codec': 1.5.0
3780+ '@jridgewell/sourcemap-codec': 1.5.4
33043781
33053782 '@libsql/client@0.14.0':
33063783 dependencies:
@@ -3337,8 +3814,8 @@ snapshots:
33373814
33383815 '@libsql/isomorphic-ws@0.1.5':
33393816 dependencies:
3340- '@types/ws': 8.5.14
3341- ws: 8.18.0
3817+ '@types/ws': 8.18.1
3818+ ws: 8.18.3
33423819 transitivePeerDependencies:
33433820 - bufferutil
33443821 - utf-8-validate
@@ -3370,114 +3847,125 @@ snapshots:
33703847 '@nodelib/fs.walk@1.2.8':
33713848 dependencies:
33723849 '@nodelib/fs.scandir': 2.1.5
3373- fastq: 1.19.0
3850+ fastq: 1.19.1
3851+
3852+ '@petamoriken/float16@3.9.2': {}
33743853
33753854 '@pkgjs/parseargs@0.11.0':
33763855 optional: true
33773856
3378- '@polka/url@1.0.0-next.28': {}
3857+ '@polka/url@1.0.0-next.29': {}
3858+
3859+ '@rollup/rollup-android-arm-eabi@4.44.1':
3860+ optional: true
33793861
3380- '@rollup/rollup-android-arm-eabi@4.34.8':
3862+ '@rollup/rollup-android-arm64@4.44.1':
33813863 optional: true
33823864
3383- '@rollup/rollup-android-arm64@4.34.8':
3865+ '@rollup/rollup-darwin-arm64@4.44.1':
33843866 optional: true
33853867
3386- '@rollup/rollup-darwin-arm64@4.34.8':
3868+ '@rollup/rollup-darwin-x64@4.44.1':
33873869 optional: true
33883870
3389- '@rollup/rollup-darwin-x64@4.34.8':
3871+ '@rollup/rollup-freebsd-arm64@4.44.1':
33903872 optional: true
33913873
3392- '@rollup/rollup-freebsd-arm64@4.34.8':
3874+ '@rollup/rollup-freebsd-x64@4.44.1':
33933875 optional: true
33943876
3395- '@rollup/rollup-freebsd-x64@4.34.8':
3877+ '@rollup/rollup-linux-arm-gnueabihf@4.44.1':
33963878 optional: true
33973879
3398- '@rollup/rollup-linux-arm-gnueabihf@4.34.8':
3880+ '@rollup/rollup-linux-arm-musleabihf@4.44.1':
33993881 optional: true
34003882
3401- '@rollup/rollup-linux-arm-musleabihf@4.34.8':
3883+ '@rollup/rollup-linux-arm64-gnu@4.44.1':
34023884 optional: true
34033885
3404- '@rollup/rollup-linux-arm64-gnu@4.34.8':
3886+ '@rollup/rollup-linux-arm64-musl@4.44.1':
34053887 optional: true
34063888
3407- '@rollup/rollup-linux-arm64-musl@4.34.8':
3889+ '@rollup/rollup-linux-loongarch64-gnu@4.44.1':
34083890 optional: true
34093891
3410- '@rollup/rollup-linux-loongarch64-gnu@4.34.8':
3892+ '@rollup/rollup-linux-powerpc64le-gnu@4.44.1':
34113893 optional: true
34123894
3413- '@rollup/rollup-linux-powerpc64le-gnu@4.34.8':
3895+ '@rollup/rollup-linux-riscv64-gnu@4.44.1':
34143896 optional: true
34153897
3416- '@rollup/rollup-linux-riscv64-gnu@4.34.8':
3898+ '@rollup/rollup-linux-riscv64-musl@4.44.1':
34173899 optional: true
34183900
3419- '@rollup/rollup-linux-s390x-gnu@4.34.8':
3901+ '@rollup/rollup-linux-s390x-gnu@4.44.1':
34203902 optional: true
34213903
3422- '@rollup/rollup-linux-x64-gnu@4.34.8':
3904+ '@rollup/rollup-linux-x64-gnu@4.44.1':
34233905 optional: true
34243906
3425- '@rollup/rollup-linux-x64-musl@4.34.8':
3907+ '@rollup/rollup-linux-x64-musl@4.44.1':
34263908 optional: true
34273909
3428- '@rollup/rollup-win32-arm64-msvc@4.34.8':
3910+ '@rollup/rollup-win32-arm64-msvc@4.44.1':
34293911 optional: true
34303912
3431- '@rollup/rollup-win32-ia32-msvc@4.34.8':
3913+ '@rollup/rollup-win32-ia32-msvc@4.44.1':
34323914 optional: true
34333915
3434- '@rollup/rollup-win32-x64-msvc@4.34.8':
3916+ '@rollup/rollup-win32-x64-msvc@4.44.1':
34353917 optional: true
34363918
3437- '@sveltejs/adapter-cloudflare@5.0.3(@sveltejs/kit@2.17.2(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(wrangler@3.107.3(@cloudflare/workers-types@4.20250214.0))':
3919+ '@sveltejs/acorn-typescript@1.0.5(acorn@8.15.0)':
3920+ dependencies:
3921+ acorn: 8.15.0
3922+
3923+ '@sveltejs/adapter-cloudflare@5.1.0(@sveltejs/kit@2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(wrangler@3.107.3(@cloudflare/workers-types@4.20250703.0))':
34383924 dependencies:
3439- '@cloudflare/workers-types': 4.20250214.0
3440- '@sveltejs/kit': 2.17.2(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))
3925+ '@cloudflare/workers-types': 4.20250703.0
3926+ '@sveltejs/kit': 2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
34413927 esbuild: 0.24.2
34423928 worktop: 0.8.0-next.18
3443- wrangler: 3.107.3(@cloudflare/workers-types@4.20250214.0)
3929+ wrangler: 3.107.3(@cloudflare/workers-types@4.20250703.0)
34443930
3445- '@sveltejs/kit@2.17.2(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))':
3931+ '@sveltejs/kit@2.22.2(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
34463932 dependencies:
3447- '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))
3933+ '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
3934+ '@sveltejs/vite-plugin-svelte': 5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
34483935 '@types/cookie': 0.6.0
3936+ acorn: 8.15.0
34493937 cookie: 0.6.0
34503938 devalue: 5.1.1
34513939 esm-env: 1.2.2
3452- import-meta-resolve: 4.1.0
34533940 kleur: 4.1.5
34543941 magic-string: 0.30.17
3455- mrmime: 2.0.0
3942+ mrmime: 2.0.1
34563943 sade: 1.8.1
34573944 set-cookie-parser: 2.7.1
3458- sirv: 3.0.0
3459- svelte: 5.20.1
3460- vite: 6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
3945+ sirv: 3.0.1
3946+ svelte: 5.35.2
3947+ vite: 6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
3948+ vitefu: 1.1.0(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
34613949
3462- '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))':
3950+ '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
34633951 dependencies:
3464- '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))
3465- debug: 4.4.0
3466- svelte: 5.20.1
3467- vite: 6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
3952+ '@sveltejs/vite-plugin-svelte': 5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
3953+ debug: 4.4.1
3954+ svelte: 5.35.2
3955+ vite: 6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
34683956 transitivePeerDependencies:
34693957 - supports-color
34703958
3471- '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))':
3959+ '@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
34723960 dependencies:
3473- '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)))(svelte@5.20.1)(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))
3474- debug: 4.4.0
3961+ '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.35.2)(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
3962+ debug: 4.4.1
34753963 deepmerge: 4.3.1
34763964 kleur: 4.1.5
34773965 magic-string: 0.30.17
3478- svelte: 5.20.1
3479- vite: 6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
3480- vitefu: 1.0.5(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))
3966+ svelte: 5.35.2
3967+ vite: 6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
3968+ vitefu: 1.1.0(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
34813969 transitivePeerDependencies:
34823970 - supports-color
34833971
@@ -3498,150 +3986,189 @@ snapshots:
34983986 postcss-selector-parser: 6.0.10
34993987 tailwindcss: 3.4.17
35003988
3989+ '@types/chai@5.2.2':
3990+ dependencies:
3991+ '@types/deep-eql': 4.0.2
3992+
35013993 '@types/cookie@0.6.0': {}
35023994
3503- '@types/estree@1.0.6': {}
3995+ '@types/debug@4.1.12':
3996+ dependencies:
3997+ '@types/ms': 2.1.0
3998+
3999+ '@types/deep-eql@4.0.2': {}
4000+
4001+ '@types/estree@1.0.8': {}
4002+
4003+ '@types/hast@3.0.4':
4004+ dependencies:
4005+ '@types/unist': 3.0.3
35044006
35054007 '@types/json-schema@7.0.15': {}
35064008
3507- '@types/node@22.13.4':
4009+ '@types/mdast@4.0.4':
4010+ dependencies:
4011+ '@types/unist': 3.0.3
4012+
4013+ '@types/ms@2.1.0': {}
4014+
4015+ '@types/node@22.16.0':
35084016 dependencies:
3509- undici-types: 6.20.0
4017+ undici-types: 6.21.0
35104018
3511- '@types/ws@8.5.14':
4019+ '@types/unist@3.0.3': {}
4020+
4021+ '@types/ws@8.18.1':
35124022 dependencies:
3513- '@types/node': 22.13.4
4023+ '@types/node': 22.16.0
35144024
3515- '@typescript-eslint/eslint-plugin@8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3))(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)':
4025+ '@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)':
35164026 dependencies:
35174027 '@eslint-community/regexpp': 4.12.1
3518- '@typescript-eslint/parser': 8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)
3519- '@typescript-eslint/scope-manager': 8.24.0
3520- '@typescript-eslint/type-utils': 8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)
3521- '@typescript-eslint/utils': 8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)
3522- '@typescript-eslint/visitor-keys': 8.24.0
3523- eslint: 9.20.1(jiti@1.21.7)
4028+ '@typescript-eslint/parser': 8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)
4029+ '@typescript-eslint/scope-manager': 8.35.1
4030+ '@typescript-eslint/type-utils': 8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)
4031+ '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)
4032+ '@typescript-eslint/visitor-keys': 8.35.1
4033+ eslint: 9.30.1(jiti@1.21.7)
35244034 graphemer: 1.4.0
3525- ignore: 5.3.2
4035+ ignore: 7.0.5
35264036 natural-compare: 1.4.0
3527- ts-api-utils: 2.0.1(typescript@5.7.3)
3528- typescript: 5.7.3
4037+ ts-api-utils: 2.1.0(typescript@5.8.3)
4038+ typescript: 5.8.3
35294039 transitivePeerDependencies:
35304040 - supports-color
35314041
3532- '@typescript-eslint/parser@8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)':
4042+ '@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)':
35334043 dependencies:
3534- '@typescript-eslint/scope-manager': 8.24.0
3535- '@typescript-eslint/types': 8.24.0
3536- '@typescript-eslint/typescript-estree': 8.24.0(typescript@5.7.3)
3537- '@typescript-eslint/visitor-keys': 8.24.0
3538- debug: 4.4.0
3539- eslint: 9.20.1(jiti@1.21.7)
3540- typescript: 5.7.3
4044+ '@typescript-eslint/scope-manager': 8.35.1
4045+ '@typescript-eslint/types': 8.35.1
4046+ '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3)
4047+ '@typescript-eslint/visitor-keys': 8.35.1
4048+ debug: 4.4.1
4049+ eslint: 9.30.1(jiti@1.21.7)
4050+ typescript: 5.8.3
35414051 transitivePeerDependencies:
35424052 - supports-color
35434053
3544- '@typescript-eslint/scope-manager@8.24.0':
4054+ '@typescript-eslint/project-service@8.35.1(typescript@5.8.3)':
35454055 dependencies:
3546- '@typescript-eslint/types': 8.24.0
3547- '@typescript-eslint/visitor-keys': 8.24.0
4056+ '@typescript-eslint/tsconfig-utils': 8.35.1(typescript@5.8.3)
4057+ '@typescript-eslint/types': 8.35.1
4058+ debug: 4.4.1
4059+ typescript: 5.8.3
4060+ transitivePeerDependencies:
4061+ - supports-color
35484062
3549- '@typescript-eslint/type-utils@8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)':
4063+ '@typescript-eslint/scope-manager@8.35.1':
35504064 dependencies:
3551- '@typescript-eslint/typescript-estree': 8.24.0(typescript@5.7.3)
3552- '@typescript-eslint/utils': 8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)
3553- debug: 4.4.0
3554- eslint: 9.20.1(jiti@1.21.7)
3555- ts-api-utils: 2.0.1(typescript@5.7.3)
3556- typescript: 5.7.3
4065+ '@typescript-eslint/types': 8.35.1
4066+ '@typescript-eslint/visitor-keys': 8.35.1
4067+
4068+ '@typescript-eslint/tsconfig-utils@8.35.1(typescript@5.8.3)':
4069+ dependencies:
4070+ typescript: 5.8.3
4071+
4072+ '@typescript-eslint/type-utils@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)':
4073+ dependencies:
4074+ '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3)
4075+ '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)
4076+ debug: 4.4.1
4077+ eslint: 9.30.1(jiti@1.21.7)
4078+ ts-api-utils: 2.1.0(typescript@5.8.3)
4079+ typescript: 5.8.3
35574080 transitivePeerDependencies:
35584081 - supports-color
35594082
3560- '@typescript-eslint/types@8.24.0': {}
4083+ '@typescript-eslint/types@8.35.1': {}
35614084
3562- '@typescript-eslint/typescript-estree@8.24.0(typescript@5.7.3)':
4085+ '@typescript-eslint/typescript-estree@8.35.1(typescript@5.8.3)':
35634086 dependencies:
3564- '@typescript-eslint/types': 8.24.0
3565- '@typescript-eslint/visitor-keys': 8.24.0
3566- debug: 4.4.0
4087+ '@typescript-eslint/project-service': 8.35.1(typescript@5.8.3)
4088+ '@typescript-eslint/tsconfig-utils': 8.35.1(typescript@5.8.3)
4089+ '@typescript-eslint/types': 8.35.1
4090+ '@typescript-eslint/visitor-keys': 8.35.1
4091+ debug: 4.4.1
35674092 fast-glob: 3.3.3
35684093 is-glob: 4.0.3
35694094 minimatch: 9.0.5
3570- semver: 7.7.1
3571- ts-api-utils: 2.0.1(typescript@5.7.3)
3572- typescript: 5.7.3
4095+ semver: 7.7.2
4096+ ts-api-utils: 2.1.0(typescript@5.8.3)
4097+ typescript: 5.8.3
35734098 transitivePeerDependencies:
35744099 - supports-color
35754100
3576- '@typescript-eslint/utils@8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)':
4101+ '@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)':
35774102 dependencies:
3578- '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7))
3579- '@typescript-eslint/scope-manager': 8.24.0
3580- '@typescript-eslint/types': 8.24.0
3581- '@typescript-eslint/typescript-estree': 8.24.0(typescript@5.7.3)
3582- eslint: 9.20.1(jiti@1.21.7)
3583- typescript: 5.7.3
4103+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@1.21.7))
4104+ '@typescript-eslint/scope-manager': 8.35.1
4105+ '@typescript-eslint/types': 8.35.1
4106+ '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3)
4107+ eslint: 9.30.1(jiti@1.21.7)
4108+ typescript: 5.8.3
35844109 transitivePeerDependencies:
35854110 - supports-color
35864111
3587- '@typescript-eslint/visitor-keys@8.24.0':
4112+ '@typescript-eslint/visitor-keys@8.35.1':
35884113 dependencies:
3589- '@typescript-eslint/types': 8.24.0
3590- eslint-visitor-keys: 4.2.0
4114+ '@typescript-eslint/types': 8.35.1
4115+ eslint-visitor-keys: 4.2.1
35914116
3592- '@vitest/expect@3.0.5':
4117+ '@ungap/structured-clone@1.3.0': {}
4118+
4119+ '@vitest/expect@3.2.4':
35934120 dependencies:
3594- '@vitest/spy': 3.0.5
3595- '@vitest/utils': 3.0.5
4121+ '@types/chai': 5.2.2
4122+ '@vitest/spy': 3.2.4
4123+ '@vitest/utils': 3.2.4
35964124 chai: 5.2.0
35974125 tinyrainbow: 2.0.0
35984126
3599- '@vitest/mocker@3.0.5(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))':
4127+ '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
36004128 dependencies:
3601- '@vitest/spy': 3.0.5
4129+ '@vitest/spy': 3.2.4
36024130 estree-walker: 3.0.3
36034131 magic-string: 0.30.17
36044132 optionalDependencies:
3605- vite: 6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
4133+ vite: 6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
36064134
3607- '@vitest/pretty-format@3.0.5':
4135+ '@vitest/pretty-format@3.2.4':
36084136 dependencies:
36094137 tinyrainbow: 2.0.0
36104138
3611- '@vitest/runner@3.0.5':
4139+ '@vitest/runner@3.2.4':
36124140 dependencies:
3613- '@vitest/utils': 3.0.5
4141+ '@vitest/utils': 3.2.4
36144142 pathe: 2.0.3
4143+ strip-literal: 3.0.0
36154144
3616- '@vitest/snapshot@3.0.5':
4145+ '@vitest/snapshot@3.2.4':
36174146 dependencies:
3618- '@vitest/pretty-format': 3.0.5
4147+ '@vitest/pretty-format': 3.2.4
36194148 magic-string: 0.30.17
36204149 pathe: 2.0.3
36214150
3622- '@vitest/spy@3.0.5':
4151+ '@vitest/spy@3.2.4':
36234152 dependencies:
3624- tinyspy: 3.0.2
4153+ tinyspy: 4.0.3
36254154
3626- '@vitest/utils@3.0.5':
4155+ '@vitest/utils@3.2.4':
36274156 dependencies:
3628- '@vitest/pretty-format': 3.0.5
3629- loupe: 3.1.3
4157+ '@vitest/pretty-format': 3.2.4
4158+ loupe: 3.1.4
36304159 tinyrainbow: 2.0.0
36314160
3632- acorn-jsx@5.3.2(acorn@8.14.0):
3633- dependencies:
3634- acorn: 8.14.0
3635-
3636- acorn-typescript@1.4.13(acorn@8.14.0):
4161+ acorn-jsx@5.3.2(acorn@8.15.0):
36374162 dependencies:
3638- acorn: 8.14.0
4163+ acorn: 8.15.0
36394164
36404165 acorn-walk@8.3.4:
36414166 dependencies:
3642- acorn: 8.14.0
4167+ acorn: 8.15.0
4168+
4169+ acorn@8.15.0: {}
36434170
3644- acorn@8.14.0: {}
4171+ agent-base@7.1.3: {}
36454172
36464173 ajv@6.12.6:
36474174 dependencies:
@@ -3681,30 +4208,32 @@ snapshots:
36814208
36824209 atomic-sleep@1.0.0: {}
36834210
3684- autoprefixer@10.4.20(postcss@8.5.2):
4211+ autoprefixer@10.4.21(postcss@8.5.6):
36854212 dependencies:
3686- browserslist: 4.24.4
3687- caniuse-lite: 1.0.30001700
4213+ browserslist: 4.25.1
4214+ caniuse-lite: 1.0.30001726
36884215 fraction.js: 4.3.7
36894216 normalize-range: 0.1.2
36904217 picocolors: 1.1.1
3691- postcss: 8.5.2
4218+ postcss: 8.5.6
36924219 postcss-value-parser: 4.2.0
36934220
36944221 axobject-query@4.1.0: {}
36954222
4223+ bail@2.0.2: {}
4224+
36964225 balanced-match@1.0.2: {}
36974226
36984227 binary-extensions@2.3.0: {}
36994228
37004229 blake3-wasm@2.1.5: {}
37014230
3702- brace-expansion@1.1.11:
4231+ brace-expansion@1.1.12:
37034232 dependencies:
37044233 balanced-match: 1.0.2
37054234 concat-map: 0.0.1
37064235
3707- brace-expansion@2.0.1:
4236+ brace-expansion@2.0.2:
37084237 dependencies:
37094238 balanced-match: 1.0.2
37104239
@@ -3712,12 +4241,12 @@ snapshots:
37124241 dependencies:
37134242 fill-range: 7.1.1
37144243
3715- browserslist@4.24.4:
4244+ browserslist@4.25.1:
37164245 dependencies:
3717- caniuse-lite: 1.0.30001700
3718- electron-to-chromium: 1.5.101
4246+ caniuse-lite: 1.0.30001726
4247+ electron-to-chromium: 1.5.179
37194248 node-releases: 2.0.19
3720- update-browserslist-db: 1.1.2(browserslist@4.24.4)
4249+ update-browserslist-db: 1.1.3(browserslist@4.25.1)
37214250
37224251 buffer-from@1.1.2: {}
37234252
@@ -3727,21 +4256,29 @@ snapshots:
37274256
37284257 camelcase-css@2.0.1: {}
37294258
3730- caniuse-lite@1.0.30001700: {}
4259+ caniuse-lite@1.0.30001726: {}
4260+
4261+ ccount@2.0.1: {}
37314262
37324263 chai@5.2.0:
37334264 dependencies:
37344265 assertion-error: 2.0.1
37354266 check-error: 2.1.1
37364267 deep-eql: 5.0.2
3737- loupe: 3.1.3
3738- pathval: 2.0.0
4268+ loupe: 3.1.4
4269+ pathval: 2.0.1
37394270
37404271 chalk@4.1.2:
37414272 dependencies:
37424273 ansi-styles: 4.3.0
37434274 supports-color: 7.2.0
37444275
4276+ character-entities-html4@2.1.0: {}
4277+
4278+ character-entities-legacy@3.0.0: {}
4279+
4280+ character-entities@2.0.2: {}
4281+
37454282 check-error@2.1.1: {}
37464283
37474284 chokidar@3.6.0:
@@ -3770,6 +4307,8 @@ snapshots:
37704307
37714308 colorette@2.0.20: {}
37724309
4310+ comma-separated-tokens@2.0.3: {}
4311+
37734312 commander@2.20.3: {}
37744313
37754314 commander@4.1.1: {}
@@ -3790,16 +4329,32 @@ snapshots:
37904329
37914330 cssesc@3.0.0: {}
37924331
4332+ cssstyle@4.6.0:
4333+ dependencies:
4334+ '@asamuzakjp/css-color': 3.2.0
4335+ rrweb-cssom: 0.8.0
4336+
37934337 data-uri-to-buffer@2.0.2: {}
37944338
37954339 data-uri-to-buffer@4.0.1: {}
37964340
4341+ data-urls@5.0.0:
4342+ dependencies:
4343+ whatwg-mimetype: 4.0.0
4344+ whatwg-url: 14.2.0
4345+
37974346 dateformat@4.6.3: {}
37984347
3799- debug@4.4.0:
4348+ debug@4.4.1:
38004349 dependencies:
38014350 ms: 2.1.3
38024351
4352+ decimal.js@10.5.0: {}
4353+
4354+ decode-named-character-reference@1.2.0:
4355+ dependencies:
4356+ character-entities: 2.0.2
4357+
38034358 deep-eql@5.0.2: {}
38044359
38054360 deep-is@0.1.4: {}
@@ -3808,47 +4363,58 @@ snapshots:
38084363
38094364 defu@6.1.4: {}
38104365
4366+ dequal@2.0.3: {}
4367+
38114368 detect-libc@2.0.2: {}
38124369
38134370 devalue@5.1.1: {}
38144371
4372+ devlop@1.1.0:
4373+ dependencies:
4374+ dequal: 2.0.3
4375+
38154376 didyoumean@1.2.2: {}
38164377
38174378 dlv@1.1.3: {}
38184379
3819- dotenv@16.4.7: {}
4380+ dotenv@16.6.1: {}
38204381
3821- drizzle-kit@0.30.4:
4382+ drizzle-kit@0.30.6:
38224383 dependencies:
38234384 '@drizzle-team/brocli': 0.10.2
38244385 '@esbuild-kit/esm-loader': 2.6.5
38254386 esbuild: 0.19.12
38264387 esbuild-register: 3.6.0(esbuild@0.19.12)
4388+ gel: 2.1.1
38274389 transitivePeerDependencies:
38284390 - supports-color
38294391
3830- drizzle-orm@0.39.3(@cloudflare/workers-types@4.20250214.0)(@libsql/client@0.14.0):
4392+ drizzle-orm@0.39.3(@cloudflare/workers-types@4.20250703.0)(@libsql/client@0.14.0):
38314393 optionalDependencies:
3832- '@cloudflare/workers-types': 4.20250214.0
4394+ '@cloudflare/workers-types': 4.20250703.0
38334395 '@libsql/client': 0.14.0
38344396
38354397 eastasianwidth@0.2.0: {}
38364398
3837- electron-to-chromium@1.5.101: {}
4399+ electron-to-chromium@1.5.179: {}
38384400
38394401 emoji-regex@8.0.0: {}
38404402
38414403 emoji-regex@9.2.2: {}
38424404
3843- end-of-stream@1.4.4:
4405+ end-of-stream@1.4.5:
38444406 dependencies:
38454407 once: 1.4.0
38464408
3847- es-module-lexer@1.6.0: {}
4409+ entities@6.0.1: {}
4410+
4411+ env-paths@3.0.0: {}
4412+
4413+ es-module-lexer@1.7.0: {}
38484414
38494415 esbuild-register@3.6.0(esbuild@0.19.12):
38504416 dependencies:
3851- debug: 4.4.0
4417+ debug: 4.4.1
38524418 esbuild: 0.19.12
38534419 transitivePeerDependencies:
38544420 - supports-color
@@ -3929,33 +4495,6 @@ snapshots:
39294495 '@esbuild/win32-ia32': 0.19.12
39304496 '@esbuild/win32-x64': 0.19.12
39314497
3932- esbuild@0.23.1:
3933- optionalDependencies:
3934- '@esbuild/aix-ppc64': 0.23.1
3935- '@esbuild/android-arm': 0.23.1
3936- '@esbuild/android-arm64': 0.23.1
3937- '@esbuild/android-x64': 0.23.1
3938- '@esbuild/darwin-arm64': 0.23.1
3939- '@esbuild/darwin-x64': 0.23.1
3940- '@esbuild/freebsd-arm64': 0.23.1
3941- '@esbuild/freebsd-x64': 0.23.1
3942- '@esbuild/linux-arm': 0.23.1
3943- '@esbuild/linux-arm64': 0.23.1
3944- '@esbuild/linux-ia32': 0.23.1
3945- '@esbuild/linux-loong64': 0.23.1
3946- '@esbuild/linux-mips64el': 0.23.1
3947- '@esbuild/linux-ppc64': 0.23.1
3948- '@esbuild/linux-riscv64': 0.23.1
3949- '@esbuild/linux-s390x': 0.23.1
3950- '@esbuild/linux-x64': 0.23.1
3951- '@esbuild/netbsd-x64': 0.23.1
3952- '@esbuild/openbsd-arm64': 0.23.1
3953- '@esbuild/openbsd-x64': 0.23.1
3954- '@esbuild/sunos-x64': 0.23.1
3955- '@esbuild/win32-arm64': 0.23.1
3956- '@esbuild/win32-ia32': 0.23.1
3957- '@esbuild/win32-x64': 0.23.1
3958-
39594498 esbuild@0.24.2:
39604499 optionalDependencies:
39614500 '@esbuild/aix-ppc64': 0.24.2
@@ -3984,35 +4523,63 @@ snapshots:
39844523 '@esbuild/win32-ia32': 0.24.2
39854524 '@esbuild/win32-x64': 0.24.2
39864525
4526+ esbuild@0.25.5:
4527+ optionalDependencies:
4528+ '@esbuild/aix-ppc64': 0.25.5
4529+ '@esbuild/android-arm': 0.25.5
4530+ '@esbuild/android-arm64': 0.25.5
4531+ '@esbuild/android-x64': 0.25.5
4532+ '@esbuild/darwin-arm64': 0.25.5
4533+ '@esbuild/darwin-x64': 0.25.5
4534+ '@esbuild/freebsd-arm64': 0.25.5
4535+ '@esbuild/freebsd-x64': 0.25.5
4536+ '@esbuild/linux-arm': 0.25.5
4537+ '@esbuild/linux-arm64': 0.25.5
4538+ '@esbuild/linux-ia32': 0.25.5
4539+ '@esbuild/linux-loong64': 0.25.5
4540+ '@esbuild/linux-mips64el': 0.25.5
4541+ '@esbuild/linux-ppc64': 0.25.5
4542+ '@esbuild/linux-riscv64': 0.25.5
4543+ '@esbuild/linux-s390x': 0.25.5
4544+ '@esbuild/linux-x64': 0.25.5
4545+ '@esbuild/netbsd-arm64': 0.25.5
4546+ '@esbuild/netbsd-x64': 0.25.5
4547+ '@esbuild/openbsd-arm64': 0.25.5
4548+ '@esbuild/openbsd-x64': 0.25.5
4549+ '@esbuild/sunos-x64': 0.25.5
4550+ '@esbuild/win32-arm64': 0.25.5
4551+ '@esbuild/win32-ia32': 0.25.5
4552+ '@esbuild/win32-x64': 0.25.5
4553+
39874554 escalade@3.2.0: {}
39884555
39894556 escape-string-regexp@4.0.0: {}
39904557
3991- eslint-compat-utils@0.5.1(eslint@9.20.1(jiti@1.21.7)):
4558+ eslint-compat-utils@0.5.1(eslint@9.30.1(jiti@1.21.7)):
39924559 dependencies:
3993- eslint: 9.20.1(jiti@1.21.7)
3994- semver: 7.7.1
4560+ eslint: 9.30.1(jiti@1.21.7)
4561+ semver: 7.7.2
39954562
3996- eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@1.21.7)):
4563+ eslint-config-prettier@10.1.5(eslint@9.30.1(jiti@1.21.7)):
39974564 dependencies:
3998- eslint: 9.20.1(jiti@1.21.7)
4565+ eslint: 9.30.1(jiti@1.21.7)
39994566
4000- eslint-plugin-svelte@2.46.1(eslint@9.20.1(jiti@1.21.7))(svelte@5.20.1):
4567+ eslint-plugin-svelte@2.46.1(eslint@9.30.1(jiti@1.21.7))(svelte@5.35.2):
40014568 dependencies:
4002- '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7))
4003- '@jridgewell/sourcemap-codec': 1.5.0
4004- eslint: 9.20.1(jiti@1.21.7)
4005- eslint-compat-utils: 0.5.1(eslint@9.20.1(jiti@1.21.7))
4569+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@1.21.7))
4570+ '@jridgewell/sourcemap-codec': 1.5.4
4571+ eslint: 9.30.1(jiti@1.21.7)
4572+ eslint-compat-utils: 0.5.1(eslint@9.30.1(jiti@1.21.7))
40064573 esutils: 2.0.3
40074574 known-css-properties: 0.35.0
4008- postcss: 8.5.2
4009- postcss-load-config: 3.1.4(postcss@8.5.2)
4010- postcss-safe-parser: 6.0.0(postcss@8.5.2)
4575+ postcss: 8.5.6
4576+ postcss-load-config: 3.1.4(postcss@8.5.6)
4577+ postcss-safe-parser: 6.0.0(postcss@8.5.6)
40114578 postcss-selector-parser: 6.1.2
4012- semver: 7.7.1
4013- svelte-eslint-parser: 0.43.0(svelte@5.20.1)
4579+ semver: 7.7.2
4580+ svelte-eslint-parser: 0.43.0(svelte@5.35.2)
40144581 optionalDependencies:
4015- svelte: 5.20.1
4582+ svelte: 5.35.2
40164583 transitivePeerDependencies:
40174584 - ts-node
40184585
@@ -4021,37 +4588,38 @@ snapshots:
40214588 esrecurse: 4.3.0
40224589 estraverse: 5.3.0
40234590
4024- eslint-scope@8.2.0:
4591+ eslint-scope@8.4.0:
40254592 dependencies:
40264593 esrecurse: 4.3.0
40274594 estraverse: 5.3.0
40284595
40294596 eslint-visitor-keys@3.4.3: {}
40304597
4031- eslint-visitor-keys@4.2.0: {}
4598+ eslint-visitor-keys@4.2.1: {}
40324599
4033- eslint@9.20.1(jiti@1.21.7):
4600+ eslint@9.30.1(jiti@1.21.7):
40344601 dependencies:
4035- '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7))
4602+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@1.21.7))
40364603 '@eslint-community/regexpp': 4.12.1
4037- '@eslint/config-array': 0.19.2
4038- '@eslint/core': 0.11.0
4039- '@eslint/eslintrc': 3.2.0
4040- '@eslint/js': 9.20.0
4041- '@eslint/plugin-kit': 0.2.5
4604+ '@eslint/config-array': 0.21.0
4605+ '@eslint/config-helpers': 0.3.0
4606+ '@eslint/core': 0.14.0
4607+ '@eslint/eslintrc': 3.3.1
4608+ '@eslint/js': 9.30.1
4609+ '@eslint/plugin-kit': 0.3.3
40424610 '@humanfs/node': 0.16.6
40434611 '@humanwhocodes/module-importer': 1.0.1
4044- '@humanwhocodes/retry': 0.4.1
4045- '@types/estree': 1.0.6
4612+ '@humanwhocodes/retry': 0.4.3
4613+ '@types/estree': 1.0.8
40464614 '@types/json-schema': 7.0.15
40474615 ajv: 6.12.6
40484616 chalk: 4.1.2
40494617 cross-spawn: 7.0.6
4050- debug: 4.4.0
4618+ debug: 4.4.1
40514619 escape-string-regexp: 4.0.0
4052- eslint-scope: 8.2.0
4053- eslint-visitor-keys: 4.2.0
4054- espree: 10.3.0
4620+ eslint-scope: 8.4.0
4621+ eslint-visitor-keys: 4.2.1
4622+ espree: 10.4.0
40554623 esquery: 1.6.0
40564624 esutils: 2.0.3
40574625 fast-deep-equal: 3.1.3
@@ -4073,25 +4641,25 @@ snapshots:
40734641
40744642 esm-env@1.2.2: {}
40754643
4076- espree@10.3.0:
4644+ espree@10.4.0:
40774645 dependencies:
4078- acorn: 8.14.0
4079- acorn-jsx: 5.3.2(acorn@8.14.0)
4080- eslint-visitor-keys: 4.2.0
4646+ acorn: 8.15.0
4647+ acorn-jsx: 5.3.2(acorn@8.15.0)
4648+ eslint-visitor-keys: 4.2.1
40814649
40824650 espree@9.6.1:
40834651 dependencies:
4084- acorn: 8.14.0
4085- acorn-jsx: 5.3.2(acorn@8.14.0)
4652+ acorn: 8.15.0
4653+ acorn-jsx: 5.3.2(acorn@8.15.0)
40864654 eslint-visitor-keys: 3.4.3
40874655
40884656 esquery@1.6.0:
40894657 dependencies:
40904658 estraverse: 5.3.0
40914659
4092- esrap@1.4.5:
4660+ esrap@2.1.0:
40934661 dependencies:
4094- '@jridgewell/sourcemap-codec': 1.5.0
4662+ '@jridgewell/sourcemap-codec': 1.5.4
40954663
40964664 esrecurse@4.3.0:
40974665 dependencies:
@@ -4103,13 +4671,15 @@ snapshots:
41034671
41044672 estree-walker@3.0.3:
41054673 dependencies:
4106- '@types/estree': 1.0.6
4674+ '@types/estree': 1.0.8
41074675
41084676 esutils@2.0.3: {}
41094677
41104678 exit-hook@2.2.1: {}
41114679
4112- expect-type@1.1.0: {}
4680+ expect-type@1.2.1: {}
4681+
4682+ extend@3.0.2: {}
41134683
41144684 fast-copy@3.0.2: {}
41154685
@@ -4131,11 +4701,13 @@ snapshots:
41314701
41324702 fast-safe-stringify@2.1.1: {}
41334703
4134- fastq@1.19.0:
4704+ fastq@1.19.1:
41354705 dependencies:
4136- reusify: 1.0.4
4706+ reusify: 1.1.0
41374707
4138- fdir@6.4.3: {}
4708+ fdir@6.4.6(picomatch@4.0.2):
4709+ optionalDependencies:
4710+ picomatch: 4.0.2
41394711
41404712 fetch-blob@3.2.0:
41414713 dependencies:
@@ -4157,12 +4729,12 @@ snapshots:
41574729
41584730 flat-cache@4.0.1:
41594731 dependencies:
4160- flatted: 3.3.2
4732+ flatted: 3.3.3
41614733 keyv: 4.5.4
41624734
4163- flatted@3.3.2: {}
4735+ flatted@3.3.3: {}
41644736
4165- foreground-child@3.3.0:
4737+ foreground-child@3.3.1:
41664738 dependencies:
41674739 cross-spawn: 7.0.6
41684740 signal-exit: 4.1.0
@@ -4178,12 +4750,23 @@ snapshots:
41784750
41794751 function-bind@1.1.2: {}
41804752
4753+ gel@2.1.1:
4754+ dependencies:
4755+ '@petamoriken/float16': 3.9.2
4756+ debug: 4.4.1
4757+ env-paths: 3.0.0
4758+ semver: 7.7.2
4759+ shell-quote: 1.8.3
4760+ which: 4.0.0
4761+ transitivePeerDependencies:
4762+ - supports-color
4763+
41814764 get-source@2.0.12:
41824765 dependencies:
41834766 data-uri-to-buffer: 2.0.2
41844767 source-map: 0.6.1
41854768
4186- get-tsconfig@4.10.0:
4769+ get-tsconfig@4.10.1:
41874770 dependencies:
41884771 resolve-pkg-maps: 1.0.0
41894772
@@ -4199,7 +4782,7 @@ snapshots:
41994782
42004783 glob@10.4.5:
42014784 dependencies:
4202- foreground-child: 3.3.0
4785+ foreground-child: 3.3.1
42034786 jackspeak: 3.4.3
42044787 minimatch: 9.0.5
42054788 minipass: 7.1.2
@@ -4218,17 +4801,97 @@ snapshots:
42184801 dependencies:
42194802 function-bind: 1.1.2
42204803
4804+ hast-util-from-html@2.0.3:
4805+ dependencies:
4806+ '@types/hast': 3.0.4
4807+ devlop: 1.1.0
4808+ hast-util-from-parse5: 8.0.3
4809+ parse5: 7.3.0
4810+ vfile: 6.0.3
4811+ vfile-message: 4.0.2
4812+
4813+ hast-util-from-parse5@8.0.3:
4814+ dependencies:
4815+ '@types/hast': 3.0.4
4816+ '@types/unist': 3.0.3
4817+ devlop: 1.1.0
4818+ hastscript: 9.0.1
4819+ property-information: 7.1.0
4820+ vfile: 6.0.3
4821+ vfile-location: 5.0.3
4822+ web-namespaces: 2.0.1
4823+
4824+ hast-util-parse-selector@4.0.0:
4825+ dependencies:
4826+ '@types/hast': 3.0.4
4827+
4828+ hast-util-sanitize@5.0.2:
4829+ dependencies:
4830+ '@types/hast': 3.0.4
4831+ '@ungap/structured-clone': 1.3.0
4832+ unist-util-position: 5.0.0
4833+
4834+ hast-util-to-html@9.0.5:
4835+ dependencies:
4836+ '@types/hast': 3.0.4
4837+ '@types/unist': 3.0.3
4838+ ccount: 2.0.1
4839+ comma-separated-tokens: 2.0.3
4840+ hast-util-whitespace: 3.0.0
4841+ html-void-elements: 3.0.0
4842+ mdast-util-to-hast: 13.2.0
4843+ property-information: 7.1.0
4844+ space-separated-tokens: 2.0.2
4845+ stringify-entities: 4.0.4
4846+ zwitch: 2.0.4
4847+
4848+ hast-util-whitespace@3.0.0:
4849+ dependencies:
4850+ '@types/hast': 3.0.4
4851+
4852+ hastscript@9.0.1:
4853+ dependencies:
4854+ '@types/hast': 3.0.4
4855+ comma-separated-tokens: 2.0.3
4856+ hast-util-parse-selector: 4.0.0
4857+ property-information: 7.1.0
4858+ space-separated-tokens: 2.0.2
4859+
42214860 help-me@5.0.0: {}
42224861
4862+ html-encoding-sniffer@4.0.0:
4863+ dependencies:
4864+ whatwg-encoding: 3.1.1
4865+
4866+ html-void-elements@3.0.0: {}
4867+
4868+ http-proxy-agent@7.0.2:
4869+ dependencies:
4870+ agent-base: 7.1.3
4871+ debug: 4.4.1
4872+ transitivePeerDependencies:
4873+ - supports-color
4874+
4875+ https-proxy-agent@7.0.6:
4876+ dependencies:
4877+ agent-base: 7.1.3
4878+ debug: 4.4.1
4879+ transitivePeerDependencies:
4880+ - supports-color
4881+
4882+ iconv-lite@0.6.3:
4883+ dependencies:
4884+ safer-buffer: 2.1.2
4885+
42234886 ignore@5.3.2: {}
42244887
4888+ ignore@7.0.5: {}
4889+
42254890 import-fresh@3.3.1:
42264891 dependencies:
42274892 parent-module: 1.0.1
42284893 resolve-from: 4.0.0
42294894
4230- import-meta-resolve@4.1.0: {}
4231-
42324895 imurmurhash@0.1.4: {}
42334896
42344897 is-binary-path@2.1.0:
@@ -4249,12 +4912,18 @@ snapshots:
42494912
42504913 is-number@7.0.0: {}
42514914
4915+ is-plain-obj@4.1.0: {}
4916+
4917+ is-potential-custom-element-name@1.0.1: {}
4918+
42524919 is-reference@3.0.3:
42534920 dependencies:
4254- '@types/estree': 1.0.6
4921+ '@types/estree': 1.0.8
42554922
42564923 isexe@2.0.0: {}
42574924
4925+ isexe@3.1.1: {}
4926+
42584927 jackspeak@3.4.3:
42594928 dependencies:
42604929 '@isaacs/cliui': 8.0.2
@@ -4267,10 +4936,39 @@ snapshots:
42674936
42684937 js-base64@3.7.7: {}
42694938
4939+ js-tokens@9.0.1: {}
4940+
42704941 js-yaml@4.1.0:
42714942 dependencies:
42724943 argparse: 2.0.1
42734944
4945+ jsdom@26.1.0:
4946+ dependencies:
4947+ cssstyle: 4.6.0
4948+ data-urls: 5.0.0
4949+ decimal.js: 10.5.0
4950+ html-encoding-sniffer: 4.0.0
4951+ http-proxy-agent: 7.0.2
4952+ https-proxy-agent: 7.0.6
4953+ is-potential-custom-element-name: 1.0.1
4954+ nwsapi: 2.2.20
4955+ parse5: 7.3.0
4956+ rrweb-cssom: 0.8.0
4957+ saxes: 6.0.0
4958+ symbol-tree: 3.2.4
4959+ tough-cookie: 5.1.2
4960+ w3c-xmlserializer: 5.0.0
4961+ webidl-conversions: 7.0.0
4962+ whatwg-encoding: 3.1.1
4963+ whatwg-mimetype: 4.0.0
4964+ whatwg-url: 14.2.0
4965+ ws: 8.18.3
4966+ xml-name-validator: 5.0.0
4967+ transitivePeerDependencies:
4968+ - bufferutil
4969+ - supports-color
4970+ - utf-8-validate
4971+
42744972 json-buffer@3.0.1: {}
42754973
42764974 json-schema-traverse@0.4.1: {}
@@ -4321,7 +5019,7 @@ snapshots:
43215019
43225020 lodash.merge@4.6.2: {}
43235021
4324- loupe@3.1.3: {}
5022+ loupe@3.1.4: {}
43255023
43265024 lru-cache@10.4.3: {}
43275025
@@ -4331,10 +5029,176 @@ snapshots:
43315029
43325030 magic-string@0.30.17:
43335031 dependencies:
4334- '@jridgewell/sourcemap-codec': 1.5.0
5032+ '@jridgewell/sourcemap-codec': 1.5.4
5033+
5034+ mdast-util-from-markdown@2.0.2:
5035+ dependencies:
5036+ '@types/mdast': 4.0.4
5037+ '@types/unist': 3.0.3
5038+ decode-named-character-reference: 1.2.0
5039+ devlop: 1.1.0
5040+ mdast-util-to-string: 4.0.0
5041+ micromark: 4.0.2
5042+ micromark-util-decode-numeric-character-reference: 2.0.2
5043+ micromark-util-decode-string: 2.0.1
5044+ micromark-util-normalize-identifier: 2.0.1
5045+ micromark-util-symbol: 2.0.1
5046+ micromark-util-types: 2.0.2
5047+ unist-util-stringify-position: 4.0.0
5048+ transitivePeerDependencies:
5049+ - supports-color
5050+
5051+ mdast-util-to-hast@13.2.0:
5052+ dependencies:
5053+ '@types/hast': 3.0.4
5054+ '@types/mdast': 4.0.4
5055+ '@ungap/structured-clone': 1.3.0
5056+ devlop: 1.1.0
5057+ micromark-util-sanitize-uri: 2.0.1
5058+ trim-lines: 3.0.1
5059+ unist-util-position: 5.0.0
5060+ unist-util-visit: 5.0.0
5061+ vfile: 6.0.3
5062+
5063+ mdast-util-to-string@4.0.0:
5064+ dependencies:
5065+ '@types/mdast': 4.0.4
43355066
43365067 merge2@1.4.1: {}
43375068
5069+ micromark-core-commonmark@2.0.3:
5070+ dependencies:
5071+ decode-named-character-reference: 1.2.0
5072+ devlop: 1.1.0
5073+ micromark-factory-destination: 2.0.1
5074+ micromark-factory-label: 2.0.1
5075+ micromark-factory-space: 2.0.1
5076+ micromark-factory-title: 2.0.1
5077+ micromark-factory-whitespace: 2.0.1
5078+ micromark-util-character: 2.1.1
5079+ micromark-util-chunked: 2.0.1
5080+ micromark-util-classify-character: 2.0.1
5081+ micromark-util-html-tag-name: 2.0.1
5082+ micromark-util-normalize-identifier: 2.0.1
5083+ micromark-util-resolve-all: 2.0.1
5084+ micromark-util-subtokenize: 2.1.0
5085+ micromark-util-symbol: 2.0.1
5086+ micromark-util-types: 2.0.2
5087+
5088+ micromark-factory-destination@2.0.1:
5089+ dependencies:
5090+ micromark-util-character: 2.1.1
5091+ micromark-util-symbol: 2.0.1
5092+ micromark-util-types: 2.0.2
5093+
5094+ micromark-factory-label@2.0.1:
5095+ dependencies:
5096+ devlop: 1.1.0
5097+ micromark-util-character: 2.1.1
5098+ micromark-util-symbol: 2.0.1
5099+ micromark-util-types: 2.0.2
5100+
5101+ micromark-factory-space@2.0.1:
5102+ dependencies:
5103+ micromark-util-character: 2.1.1
5104+ micromark-util-types: 2.0.2
5105+
5106+ micromark-factory-title@2.0.1:
5107+ dependencies:
5108+ micromark-factory-space: 2.0.1
5109+ micromark-util-character: 2.1.1
5110+ micromark-util-symbol: 2.0.1
5111+ micromark-util-types: 2.0.2
5112+
5113+ micromark-factory-whitespace@2.0.1:
5114+ dependencies:
5115+ micromark-factory-space: 2.0.1
5116+ micromark-util-character: 2.1.1
5117+ micromark-util-symbol: 2.0.1
5118+ micromark-util-types: 2.0.2
5119+
5120+ micromark-util-character@2.1.1:
5121+ dependencies:
5122+ micromark-util-symbol: 2.0.1
5123+ micromark-util-types: 2.0.2
5124+
5125+ micromark-util-chunked@2.0.1:
5126+ dependencies:
5127+ micromark-util-symbol: 2.0.1
5128+
5129+ micromark-util-classify-character@2.0.1:
5130+ dependencies:
5131+ micromark-util-character: 2.1.1
5132+ micromark-util-symbol: 2.0.1
5133+ micromark-util-types: 2.0.2
5134+
5135+ micromark-util-combine-extensions@2.0.1:
5136+ dependencies:
5137+ micromark-util-chunked: 2.0.1
5138+ micromark-util-types: 2.0.2
5139+
5140+ micromark-util-decode-numeric-character-reference@2.0.2:
5141+ dependencies:
5142+ micromark-util-symbol: 2.0.1
5143+
5144+ micromark-util-decode-string@2.0.1:
5145+ dependencies:
5146+ decode-named-character-reference: 1.2.0
5147+ micromark-util-character: 2.1.1
5148+ micromark-util-decode-numeric-character-reference: 2.0.2
5149+ micromark-util-symbol: 2.0.1
5150+
5151+ micromark-util-encode@2.0.1: {}
5152+
5153+ micromark-util-html-tag-name@2.0.1: {}
5154+
5155+ micromark-util-normalize-identifier@2.0.1:
5156+ dependencies:
5157+ micromark-util-symbol: 2.0.1
5158+
5159+ micromark-util-resolve-all@2.0.1:
5160+ dependencies:
5161+ micromark-util-types: 2.0.2
5162+
5163+ micromark-util-sanitize-uri@2.0.1:
5164+ dependencies:
5165+ micromark-util-character: 2.1.1
5166+ micromark-util-encode: 2.0.1
5167+ micromark-util-symbol: 2.0.1
5168+
5169+ micromark-util-subtokenize@2.1.0:
5170+ dependencies:
5171+ devlop: 1.1.0
5172+ micromark-util-chunked: 2.0.1
5173+ micromark-util-symbol: 2.0.1
5174+ micromark-util-types: 2.0.2
5175+
5176+ micromark-util-symbol@2.0.1: {}
5177+
5178+ micromark-util-types@2.0.2: {}
5179+
5180+ micromark@4.0.2:
5181+ dependencies:
5182+ '@types/debug': 4.1.12
5183+ debug: 4.4.1
5184+ decode-named-character-reference: 1.2.0
5185+ devlop: 1.1.0
5186+ micromark-core-commonmark: 2.0.3
5187+ micromark-factory-space: 2.0.1
5188+ micromark-util-character: 2.1.1
5189+ micromark-util-chunked: 2.0.1
5190+ micromark-util-combine-extensions: 2.0.1
5191+ micromark-util-decode-numeric-character-reference: 2.0.2
5192+ micromark-util-encode: 2.0.1
5193+ micromark-util-normalize-identifier: 2.0.1
5194+ micromark-util-resolve-all: 2.0.1
5195+ micromark-util-sanitize-uri: 2.0.1
5196+ micromark-util-subtokenize: 2.1.0
5197+ micromark-util-symbol: 2.0.1
5198+ micromark-util-types: 2.0.2
5199+ transitivePeerDependencies:
5200+ - supports-color
5201+
43385202 micromatch@4.0.8:
43395203 dependencies:
43405204 braces: 3.0.3
@@ -4347,27 +5211,27 @@ snapshots:
43475211 miniflare@3.20250129.0:
43485212 dependencies:
43495213 '@cspotcode/source-map-support': 0.8.1
4350- acorn: 8.14.0
5214+ acorn: 8.15.0
43515215 acorn-walk: 8.3.4
43525216 exit-hook: 2.2.1
43535217 glob-to-regexp: 0.4.1
43545218 stoppable: 1.1.0
4355- undici: 5.28.5
5219+ undici: 5.29.0
43565220 workerd: 1.20250129.0
4357- ws: 8.18.0
5221+ ws: 8.18.3
43585222 youch: 3.3.4
4359- zod: 3.24.2
5223+ zod: 3.25.71
43605224 transitivePeerDependencies:
43615225 - bufferutil
43625226 - utf-8-validate
43635227
43645228 minimatch@3.1.2:
43655229 dependencies:
4366- brace-expansion: 1.1.11
5230+ brace-expansion: 1.1.12
43675231
43685232 minimatch@9.0.5:
43695233 dependencies:
4370- brace-expansion: 2.0.1
5234+ brace-expansion: 2.0.2
43715235
43725236 minimist@1.2.8: {}
43735237
@@ -4375,14 +5239,14 @@ snapshots:
43755239
43765240 mlly@1.7.4:
43775241 dependencies:
4378- acorn: 8.14.0
5242+ acorn: 8.15.0
43795243 pathe: 2.0.3
43805244 pkg-types: 1.3.1
4381- ufo: 1.5.4
5245+ ufo: 1.6.1
43825246
43835247 mri@1.2.0: {}
43845248
4385- mrmime@2.0.0: {}
5249+ mrmime@2.0.1: {}
43865250
43875251 ms@2.1.3: {}
43885252
@@ -4394,7 +5258,7 @@ snapshots:
43945258 object-assign: 4.1.1
43955259 thenify-all: 1.6.0
43965260
4397- nanoid@3.3.8: {}
5261+ nanoid@3.3.11: {}
43985262
43995263 natural-compare@1.4.0: {}
44005264
@@ -4412,11 +5276,13 @@ snapshots:
44125276
44135277 normalize-range@0.1.2: {}
44145278
5279+ nwsapi@2.2.20: {}
5280+
44155281 object-assign@4.1.1: {}
44165282
44175283 object-hash@3.0.0: {}
44185284
4419- ohash@1.1.4: {}
5285+ ohash@1.1.6: {}
44205286
44215287 on-exit-leak-free@2.1.2: {}
44225288
@@ -4447,6 +5313,10 @@ snapshots:
44475313 dependencies:
44485314 callsites: 3.1.0
44495315
5316+ parse5@7.3.0:
5317+ dependencies:
5318+ entities: 6.0.1
5319+
44505320 path-exists@4.0.0: {}
44515321
44525322 path-key@3.1.1: {}
@@ -4464,12 +5334,14 @@ snapshots:
44645334
44655335 pathe@2.0.3: {}
44665336
4467- pathval@2.0.0: {}
5337+ pathval@2.0.1: {}
44685338
44695339 picocolors@1.1.1: {}
44705340
44715341 picomatch@2.3.1: {}
44725342
5343+ picomatch@4.0.2: {}
5344+
44735345 pify@2.3.0: {}
44745346
44755347 pino-abstract-transport@2.0.0:
@@ -4487,28 +5359,28 @@ snapshots:
44875359 minimist: 1.2.8
44885360 on-exit-leak-free: 2.1.2
44895361 pino-abstract-transport: 2.0.0
4490- pump: 3.0.2
5362+ pump: 3.0.3
44915363 secure-json-parse: 2.7.0
44925364 sonic-boom: 4.2.0
44935365 strip-json-comments: 3.1.1
44945366
44955367 pino-std-serializers@7.0.0: {}
44965368
4497- pino@9.6.0:
5369+ pino@9.7.0:
44985370 dependencies:
44995371 atomic-sleep: 1.0.0
45005372 fast-redact: 3.5.0
45015373 on-exit-leak-free: 2.1.2
45025374 pino-abstract-transport: 2.0.0
45035375 pino-std-serializers: 7.0.0
4504- process-warning: 4.0.1
5376+ process-warning: 5.0.0
45055377 quick-format-unescaped: 4.0.4
45065378 real-require: 0.2.0
45075379 safe-stable-stringify: 2.5.0
45085380 sonic-boom: 4.2.0
45095381 thread-stream: 3.1.0
45105382
4511- pirates@4.0.6: {}
5383+ pirates@4.0.7: {}
45125384
45135385 pkg-types@1.3.1:
45145386 dependencies:
@@ -4516,44 +5388,44 @@ snapshots:
45165388 mlly: 1.7.4
45175389 pathe: 2.0.3
45185390
4519- postcss-import@15.1.0(postcss@8.5.2):
5391+ postcss-import@15.1.0(postcss@8.5.6):
45205392 dependencies:
4521- postcss: 8.5.2
5393+ postcss: 8.5.6
45225394 postcss-value-parser: 4.2.0
45235395 read-cache: 1.0.0
45245396 resolve: 1.22.10
45255397
4526- postcss-js@4.0.1(postcss@8.5.2):
5398+ postcss-js@4.0.1(postcss@8.5.6):
45275399 dependencies:
45285400 camelcase-css: 2.0.1
4529- postcss: 8.5.2
5401+ postcss: 8.5.6
45305402
4531- postcss-load-config@3.1.4(postcss@8.5.2):
5403+ postcss-load-config@3.1.4(postcss@8.5.6):
45325404 dependencies:
45335405 lilconfig: 2.1.0
45345406 yaml: 1.10.2
45355407 optionalDependencies:
4536- postcss: 8.5.2
5408+ postcss: 8.5.6
45375409
4538- postcss-load-config@4.0.2(postcss@8.5.2):
5410+ postcss-load-config@4.0.2(postcss@8.5.6):
45395411 dependencies:
45405412 lilconfig: 3.1.3
4541- yaml: 2.7.0
5413+ yaml: 2.8.0
45425414 optionalDependencies:
4543- postcss: 8.5.2
5415+ postcss: 8.5.6
45445416
4545- postcss-nested@6.2.0(postcss@8.5.2):
5417+ postcss-nested@6.2.0(postcss@8.5.6):
45465418 dependencies:
4547- postcss: 8.5.2
5419+ postcss: 8.5.6
45485420 postcss-selector-parser: 6.1.2
45495421
4550- postcss-safe-parser@6.0.0(postcss@8.5.2):
5422+ postcss-safe-parser@6.0.0(postcss@8.5.6):
45515423 dependencies:
4552- postcss: 8.5.2
5424+ postcss: 8.5.6
45535425
4554- postcss-scss@4.0.9(postcss@8.5.2):
5426+ postcss-scss@4.0.9(postcss@8.5.6):
45555427 dependencies:
4556- postcss: 8.5.2
5428+ postcss: 8.5.6
45575429
45585430 postcss-selector-parser@6.0.10:
45595431 dependencies:
@@ -4567,36 +5439,38 @@ snapshots:
45675439
45685440 postcss-value-parser@4.2.0: {}
45695441
4570- postcss@8.5.2:
5442+ postcss@8.5.6:
45715443 dependencies:
4572- nanoid: 3.3.8
5444+ nanoid: 3.3.11
45735445 picocolors: 1.1.1
45745446 source-map-js: 1.2.1
45755447
45765448 prelude-ls@1.2.1: {}
45775449
4578- prettier-plugin-svelte@3.3.3(prettier@3.5.1)(svelte@5.20.1):
5450+ prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.35.2):
45795451 dependencies:
4580- prettier: 3.5.1
4581- svelte: 5.20.1
5452+ prettier: 3.6.2
5453+ svelte: 5.35.2
45825454
4583- prettier-plugin-tailwindcss@0.6.11(prettier-plugin-svelte@3.3.3(prettier@3.5.1)(svelte@5.20.1))(prettier@3.5.1):
5455+ prettier-plugin-tailwindcss@0.6.13(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.35.2))(prettier@3.6.2):
45845456 dependencies:
4585- prettier: 3.5.1
5457+ prettier: 3.6.2
45865458 optionalDependencies:
4587- prettier-plugin-svelte: 3.3.3(prettier@3.5.1)(svelte@5.20.1)
5459+ prettier-plugin-svelte: 3.4.0(prettier@3.6.2)(svelte@5.35.2)
45885460
4589- prettier@3.5.1: {}
5461+ prettier@3.6.2: {}
45905462
45915463 printable-characters@1.0.42: {}
45925464
4593- process-warning@4.0.1: {}
5465+ process-warning@5.0.0: {}
45945466
45955467 promise-limit@2.7.0: {}
45965468
4597- pump@3.0.2:
5469+ property-information@7.1.0: {}
5470+
5471+ pump@3.0.3:
45985472 dependencies:
4599- end-of-stream: 1.4.4
5473+ end-of-stream: 1.4.5
46005474 once: 1.4.0
46015475
46025476 punycode@2.3.1: {}
@@ -4619,6 +5493,47 @@ snapshots:
46195493
46205494 regexparam@3.0.0: {}
46215495
5496+ rehype-parse@9.0.1:
5497+ dependencies:
5498+ '@types/hast': 3.0.4
5499+ hast-util-from-html: 2.0.3
5500+ unified: 11.0.5
5501+
5502+ rehype-sanitize@6.0.0:
5503+ dependencies:
5504+ '@types/hast': 3.0.4
5505+ hast-util-sanitize: 5.0.2
5506+
5507+ rehype-stringify@10.0.1:
5508+ dependencies:
5509+ '@types/hast': 3.0.4
5510+ hast-util-to-html: 9.0.5
5511+ unified: 11.0.5
5512+
5513+ rehype@13.0.2:
5514+ dependencies:
5515+ '@types/hast': 3.0.4
5516+ rehype-parse: 9.0.1
5517+ rehype-stringify: 10.0.1
5518+ unified: 11.0.5
5519+
5520+ remark-parse@11.0.0:
5521+ dependencies:
5522+ '@types/mdast': 4.0.4
5523+ mdast-util-from-markdown: 2.0.2
5524+ micromark-util-types: 2.0.2
5525+ unified: 11.0.5
5526+ transitivePeerDependencies:
5527+ - supports-color
5528+
5529+ remark-rehype@11.1.2:
5530+ dependencies:
5531+ '@types/hast': 3.0.4
5532+ '@types/mdast': 4.0.4
5533+ mdast-util-to-hast: 13.2.0
5534+ unified: 11.0.5
5535+ vfile: 6.0.3
5536+
46225537 resolve-from@4.0.0: {}
46235538
46245539 resolve-pkg-maps@1.0.0: {}
@@ -4629,7 +5544,7 @@ snapshots:
46295544 path-parse: 1.0.7
46305545 supports-preserve-symlinks-flag: 1.0.0
46315546
4632- reusify@1.0.4: {}
5547+ reusify@1.1.0: {}
46335548
46345549 rollup-plugin-inject@3.0.2:
46355550 dependencies:
@@ -4645,31 +5560,34 @@ snapshots:
46455560 dependencies:
46465561 estree-walker: 0.6.1
46475562
4648- rollup@4.34.8:
5563+ rollup@4.44.1:
46495564 dependencies:
4650- '@types/estree': 1.0.6
5565+ '@types/estree': 1.0.8
46515566 optionalDependencies:
4652- '@rollup/rollup-android-arm-eabi': 4.34.8
4653- '@rollup/rollup-android-arm64': 4.34.8
4654- '@rollup/rollup-darwin-arm64': 4.34.8
4655- '@rollup/rollup-darwin-x64': 4.34.8
4656- '@rollup/rollup-freebsd-arm64': 4.34.8
4657- '@rollup/rollup-freebsd-x64': 4.34.8
4658- '@rollup/rollup-linux-arm-gnueabihf': 4.34.8
4659- '@rollup/rollup-linux-arm-musleabihf': 4.34.8
4660- '@rollup/rollup-linux-arm64-gnu': 4.34.8
4661- '@rollup/rollup-linux-arm64-musl': 4.34.8
4662- '@rollup/rollup-linux-loongarch64-gnu': 4.34.8
4663- '@rollup/rollup-linux-powerpc64le-gnu': 4.34.8
4664- '@rollup/rollup-linux-riscv64-gnu': 4.34.8
4665- '@rollup/rollup-linux-s390x-gnu': 4.34.8
4666- '@rollup/rollup-linux-x64-gnu': 4.34.8
4667- '@rollup/rollup-linux-x64-musl': 4.34.8
4668- '@rollup/rollup-win32-arm64-msvc': 4.34.8
4669- '@rollup/rollup-win32-ia32-msvc': 4.34.8
4670- '@rollup/rollup-win32-x64-msvc': 4.34.8
5567+ '@rollup/rollup-android-arm-eabi': 4.44.1
5568+ '@rollup/rollup-android-arm64': 4.44.1
5569+ '@rollup/rollup-darwin-arm64': 4.44.1
5570+ '@rollup/rollup-darwin-x64': 4.44.1
5571+ '@rollup/rollup-freebsd-arm64': 4.44.1
5572+ '@rollup/rollup-freebsd-x64': 4.44.1
5573+ '@rollup/rollup-linux-arm-gnueabihf': 4.44.1
5574+ '@rollup/rollup-linux-arm-musleabihf': 4.44.1
5575+ '@rollup/rollup-linux-arm64-gnu': 4.44.1
5576+ '@rollup/rollup-linux-arm64-musl': 4.44.1
5577+ '@rollup/rollup-linux-loongarch64-gnu': 4.44.1
5578+ '@rollup/rollup-linux-powerpc64le-gnu': 4.44.1
5579+ '@rollup/rollup-linux-riscv64-gnu': 4.44.1
5580+ '@rollup/rollup-linux-riscv64-musl': 4.44.1
5581+ '@rollup/rollup-linux-s390x-gnu': 4.44.1
5582+ '@rollup/rollup-linux-x64-gnu': 4.44.1
5583+ '@rollup/rollup-linux-x64-musl': 4.44.1
5584+ '@rollup/rollup-win32-arm64-msvc': 4.44.1
5585+ '@rollup/rollup-win32-ia32-msvc': 4.44.1
5586+ '@rollup/rollup-win32-x64-msvc': 4.44.1
46715587 fsevents: 2.3.3
46725588
5589+ rrweb-cssom@0.8.0: {}
5590+
46735591 run-parallel@1.2.0:
46745592 dependencies:
46755593 queue-microtask: 1.2.3
@@ -4680,9 +5598,15 @@ snapshots:
46805598
46815599 safe-stable-stringify@2.5.0: {}
46825600
5601+ safer-buffer@2.1.2: {}
5602+
5603+ saxes@6.0.0:
5604+ dependencies:
5605+ xmlchars: 2.2.0
5606+
46835607 secure-json-parse@2.7.0: {}
46845608
4685- semver@7.7.1: {}
5609+ semver@7.7.2: {}
46865610
46875611 set-cookie-parser@2.7.1: {}
46885612
@@ -4692,14 +5616,16 @@ snapshots:
46925616
46935617 shebang-regex@3.0.0: {}
46945618
5619+ shell-quote@1.8.3: {}
5620+
46955621 siginfo@2.0.0: {}
46965622
46975623 signal-exit@4.1.0: {}
46985624
4699- sirv@3.0.0:
5625+ sirv@3.0.1:
47005626 dependencies:
4701- '@polka/url': 1.0.0-next.28
4702- mrmime: 2.0.0
5627+ '@polka/url': 1.0.0-next.29
5628+ mrmime: 2.0.1
47035629 totalist: 3.0.1
47045630
47055631 sonic-boom@4.2.0:
@@ -4717,6 +5643,8 @@ snapshots:
47175643
47185644 sourcemap-codec@1.4.8: {}
47195645
5646+ space-separated-tokens@2.0.2: {}
5647+
47205648 split2@4.2.0: {}
47215649
47225650 stackback@0.0.2: {}
@@ -4726,7 +5654,7 @@ snapshots:
47265654 as-table: 1.0.55
47275655 get-source: 2.0.12
47285656
4729- std-env@3.8.0: {}
5657+ std-env@3.9.0: {}
47305658
47315659 stoppable@1.1.0: {}
47325660
@@ -4742,6 +5670,11 @@ snapshots:
47425670 emoji-regex: 9.2.2
47435671 strip-ansi: 7.1.0
47445672
5673+ stringify-entities@4.0.4:
5674+ dependencies:
5675+ character-entities-html4: 2.1.0
5676+ character-entities-legacy: 3.0.0
5677+
47455678 strip-ansi@6.0.1:
47465679 dependencies:
47475680 ansi-regex: 5.0.1
@@ -4752,14 +5685,18 @@ snapshots:
47525685
47535686 strip-json-comments@3.1.1: {}
47545687
5688+ strip-literal@3.0.0:
5689+ dependencies:
5690+ js-tokens: 9.0.1
5691+
47555692 sucrase@3.35.0:
47565693 dependencies:
4757- '@jridgewell/gen-mapping': 0.3.8
5694+ '@jridgewell/gen-mapping': 0.3.12
47585695 commander: 4.1.1
47595696 glob: 10.4.5
47605697 lines-and-columns: 1.2.4
47615698 mz: 2.7.0
4762- pirates: 4.0.6
5699+ pirates: 4.0.7
47635700 ts-interface-checker: 0.1.13
47645701
47655702 supports-color@7.2.0:
@@ -4768,45 +5705,47 @@ snapshots:
47685705
47695706 supports-preserve-symlinks-flag@1.0.0: {}
47705707
4771- svelte-check@4.1.4(svelte@5.20.1)(typescript@5.7.3):
5708+ svelte-check@4.2.2(picomatch@4.0.2)(svelte@5.35.2)(typescript@5.8.3):
47725709 dependencies:
4773- '@jridgewell/trace-mapping': 0.3.25
5710+ '@jridgewell/trace-mapping': 0.3.29
47745711 chokidar: 4.0.3
4775- fdir: 6.4.3
5712+ fdir: 6.4.6(picomatch@4.0.2)
47765713 picocolors: 1.1.1
47775714 sade: 1.8.1
4778- svelte: 5.20.1
4779- typescript: 5.7.3
5715+ svelte: 5.35.2
5716+ typescript: 5.8.3
47805717 transitivePeerDependencies:
47815718 - picomatch
47825719
4783- svelte-eslint-parser@0.43.0(svelte@5.20.1):
5720+ svelte-eslint-parser@0.43.0(svelte@5.35.2):
47845721 dependencies:
47855722 eslint-scope: 7.2.2
47865723 eslint-visitor-keys: 3.4.3
47875724 espree: 9.6.1
4788- postcss: 8.5.2
4789- postcss-scss: 4.0.9(postcss@8.5.2)
5725+ postcss: 8.5.6
5726+ postcss-scss: 4.0.9(postcss@8.5.6)
47905727 optionalDependencies:
4791- svelte: 5.20.1
5728+ svelte: 5.35.2
47925729
4793- svelte@5.20.1:
5730+ svelte@5.35.2:
47945731 dependencies:
47955732 '@ampproject/remapping': 2.3.0
4796- '@jridgewell/sourcemap-codec': 1.5.0
4797- '@types/estree': 1.0.6
4798- acorn: 8.14.0
4799- acorn-typescript: 1.4.13(acorn@8.14.0)
5733+ '@jridgewell/sourcemap-codec': 1.5.4
5734+ '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
5735+ '@types/estree': 1.0.8
5736+ acorn: 8.15.0
48005737 aria-query: 5.3.2
48015738 axobject-query: 4.1.0
48025739 clsx: 2.1.1
48035740 esm-env: 1.2.2
4804- esrap: 1.4.5
5741+ esrap: 2.1.0
48055742 is-reference: 3.0.3
48065743 locate-character: 3.0.0
48075744 magic-string: 0.30.17
48085745 zimmerframe: 1.1.2
48095746
5747+ symbol-tree@3.2.4: {}
5748+
48105749 tailwindcss@3.4.17:
48115750 dependencies:
48125751 '@alloc/quick-lru': 5.2.0
@@ -4823,21 +5762,21 @@ snapshots:
48235762 normalize-path: 3.0.0
48245763 object-hash: 3.0.0
48255764 picocolors: 1.1.1
4826- postcss: 8.5.2
4827- postcss-import: 15.1.0(postcss@8.5.2)
4828- postcss-js: 4.0.1(postcss@8.5.2)
4829- postcss-load-config: 4.0.2(postcss@8.5.2)
4830- postcss-nested: 6.2.0(postcss@8.5.2)
5765+ postcss: 8.5.6
5766+ postcss-import: 15.1.0(postcss@8.5.6)
5767+ postcss-js: 4.0.1(postcss@8.5.6)
5768+ postcss-load-config: 4.0.2(postcss@8.5.6)
5769+ postcss-nested: 6.2.0(postcss@8.5.6)
48315770 postcss-selector-parser: 6.1.2
48325771 resolve: 1.22.10
48335772 sucrase: 3.35.0
48345773 transitivePeerDependencies:
48355774 - ts-node
48365775
4837- terser@5.39.0:
5776+ terser@5.43.1:
48385777 dependencies:
4839- '@jridgewell/source-map': 0.3.6
4840- acorn: 8.14.0
5778+ '@jridgewell/source-map': 0.3.10
5779+ acorn: 8.15.0
48415780 commander: 2.20.3
48425781 source-map-support: 0.5.21
48435782
@@ -4857,11 +5796,22 @@ snapshots:
48575796
48585797 tinyexec@0.3.2: {}
48595798
4860- tinypool@1.0.2: {}
5799+ tinyglobby@0.2.14:
5800+ dependencies:
5801+ fdir: 6.4.6(picomatch@4.0.2)
5802+ picomatch: 4.0.2
5803+
5804+ tinypool@1.1.1: {}
48615805
48625806 tinyrainbow@2.0.0: {}
48635807
4864- tinyspy@3.0.2: {}
5808+ tinyspy@4.0.3: {}
5809+
5810+ tldts-core@6.1.86: {}
5811+
5812+ tldts@6.1.86:
5813+ dependencies:
5814+ tldts-core: 6.1.86
48655815
48665816 to-regex-range@5.0.1:
48675817 dependencies:
@@ -4869,16 +5819,28 @@ snapshots:
48695819
48705820 totalist@3.0.1: {}
48715821
4872- ts-api-utils@2.0.1(typescript@5.7.3):
5822+ tough-cookie@5.1.2:
5823+ dependencies:
5824+ tldts: 6.1.86
5825+
5826+ tr46@5.1.1:
5827+ dependencies:
5828+ punycode: 2.3.1
5829+
5830+ trim-lines@3.0.1: {}
5831+
5832+ trough@2.2.0: {}
5833+
5834+ ts-api-utils@2.1.0(typescript@5.8.3):
48735835 dependencies:
4874- typescript: 5.7.3
5836+ typescript: 5.8.3
48755837
48765838 ts-interface-checker@0.1.13: {}
48775839
4878- tsx@4.19.2:
5840+ tsx@4.20.3:
48795841 dependencies:
4880- esbuild: 0.23.1
4881- get-tsconfig: 4.10.0
5842+ esbuild: 0.25.5
5843+ get-tsconfig: 4.10.1
48825844 optionalDependencies:
48835845 fsevents: 2.3.3
48845846
@@ -4886,23 +5848,23 @@ snapshots:
48865848 dependencies:
48875849 prelude-ls: 1.2.1
48885850
4889- typescript-eslint@8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3):
5851+ typescript-eslint@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3):
48905852 dependencies:
4891- '@typescript-eslint/eslint-plugin': 8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3))(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)
4892- '@typescript-eslint/parser': 8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)
4893- '@typescript-eslint/utils': 8.24.0(eslint@9.20.1(jiti@1.21.7))(typescript@5.7.3)
4894- eslint: 9.20.1(jiti@1.21.7)
4895- typescript: 5.7.3
5853+ '@typescript-eslint/eslint-plugin': 8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)
5854+ '@typescript-eslint/parser': 8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)
5855+ '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)
5856+ eslint: 9.30.1(jiti@1.21.7)
5857+ typescript: 5.8.3
48965858 transitivePeerDependencies:
48975859 - supports-color
48985860
4899- typescript@5.7.3: {}
5861+ typescript@5.8.3: {}
49005862
4901- ufo@1.5.4: {}
5863+ ufo@1.6.1: {}
49025864
4903- undici-types@6.20.0: {}
5865+ undici-types@6.21.0: {}
49045866
4905- undici@5.28.5:
5867+ undici@5.29.0:
49065868 dependencies:
49075869 '@fastify/busboy': 2.1.1
49085870
@@ -4910,13 +5872,46 @@ snapshots:
49105872 dependencies:
49115873 defu: 6.1.4
49125874 mlly: 1.7.4
4913- ohash: 1.1.4
5875+ ohash: 1.1.6
49145876 pathe: 1.1.2
4915- ufo: 1.5.4
5877+ ufo: 1.6.1
5878+
5879+ unified@11.0.5:
5880+ dependencies:
5881+ '@types/unist': 3.0.3
5882+ bail: 2.0.2
5883+ devlop: 1.1.0
5884+ extend: 3.0.2
5885+ is-plain-obj: 4.1.0
5886+ trough: 2.2.0
5887+ vfile: 6.0.3
5888+
5889+ unist-util-is@6.0.0:
5890+ dependencies:
5891+ '@types/unist': 3.0.3
5892+
5893+ unist-util-position@5.0.0:
5894+ dependencies:
5895+ '@types/unist': 3.0.3
49165896
4917- update-browserslist-db@1.1.2(browserslist@4.24.4):
5897+ unist-util-stringify-position@4.0.0:
49185898 dependencies:
4919- browserslist: 4.24.4
5899+ '@types/unist': 3.0.3
5900+
5901+ unist-util-visit-parents@6.0.1:
5902+ dependencies:
5903+ '@types/unist': 3.0.3
5904+ unist-util-is: 6.0.0
5905+
5906+ unist-util-visit@5.0.0:
5907+ dependencies:
5908+ '@types/unist': 3.0.3
5909+ unist-util-is: 6.0.0
5910+ unist-util-visit-parents: 6.0.1
5911+
5912+ update-browserslist-db@1.1.3(browserslist@4.25.1):
5913+ dependencies:
5914+ browserslist: 4.25.1
49205915 escalade: 3.2.0
49215916 picocolors: 1.1.1
49225917
@@ -4926,15 +5921,30 @@ snapshots:
49265921
49275922 util-deprecate@1.0.2: {}
49285923
4929- uuid@11.0.5: {}
5924+ uuid@11.1.0: {}
5925+
5926+ vfile-location@5.0.3:
5927+ dependencies:
5928+ '@types/unist': 3.0.3
5929+ vfile: 6.0.3
5930+
5931+ vfile-message@4.0.2:
5932+ dependencies:
5933+ '@types/unist': 3.0.3
5934+ unist-util-stringify-position: 4.0.0
49305935
4931- vite-node@3.0.5(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0):
5936+ vfile@6.0.3:
5937+ dependencies:
5938+ '@types/unist': 3.0.3
5939+ vfile-message: 4.0.2
5940+
5941+ vite-node@3.2.4(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0):
49325942 dependencies:
49335943 cac: 6.7.14
4934- debug: 4.4.0
4935- es-module-lexer: 1.6.0
5944+ debug: 4.4.1
5945+ es-module-lexer: 1.7.0
49365946 pathe: 2.0.3
4937- vite: 6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
5947+ vite: 6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
49385948 transitivePeerDependencies:
49395949 - '@types/node'
49405950 - jiti
@@ -4949,47 +5959,55 @@ snapshots:
49495959 - tsx
49505960 - yaml
49515961
4952- vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0):
5962+ vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0):
49535963 dependencies:
4954- esbuild: 0.24.2
4955- postcss: 8.5.2
4956- rollup: 4.34.8
5964+ esbuild: 0.25.5
5965+ fdir: 6.4.6(picomatch@4.0.2)
5966+ picomatch: 4.0.2
5967+ postcss: 8.5.6
5968+ rollup: 4.44.1
5969+ tinyglobby: 0.2.14
49575970 optionalDependencies:
4958- '@types/node': 22.13.4
5971+ '@types/node': 22.16.0
49595972 fsevents: 2.3.3
49605973 jiti: 1.21.7
4961- terser: 5.39.0
4962- tsx: 4.19.2
4963- yaml: 2.7.0
5974+ terser: 5.43.1
5975+ tsx: 4.20.3
5976+ yaml: 2.8.0
49645977
4965- vitefu@1.0.5(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)):
5978+ vitefu@1.1.0(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)):
49665979 optionalDependencies:
4967- vite: 6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
4968-
4969- vitest@3.0.5(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0):
4970- dependencies:
4971- '@vitest/expect': 3.0.5
4972- '@vitest/mocker': 3.0.5(vite@6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0))
4973- '@vitest/pretty-format': 3.0.5
4974- '@vitest/runner': 3.0.5
4975- '@vitest/snapshot': 3.0.5
4976- '@vitest/spy': 3.0.5
4977- '@vitest/utils': 3.0.5
5980+ vite: 6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
5981+
5982+ vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0):
5983+ dependencies:
5984+ '@types/chai': 5.2.2
5985+ '@vitest/expect': 3.2.4
5986+ '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
5987+ '@vitest/pretty-format': 3.2.4
5988+ '@vitest/runner': 3.2.4
5989+ '@vitest/snapshot': 3.2.4
5990+ '@vitest/spy': 3.2.4
5991+ '@vitest/utils': 3.2.4
49785992 chai: 5.2.0
4979- debug: 4.4.0
4980- expect-type: 1.1.0
5993+ debug: 4.4.1
5994+ expect-type: 1.2.1
49815995 magic-string: 0.30.17
49825996 pathe: 2.0.3
4983- std-env: 3.8.0
5997+ picomatch: 4.0.2
5998+ std-env: 3.9.0
49845999 tinybench: 2.9.0
49856000 tinyexec: 0.3.2
4986- tinypool: 1.0.2
6001+ tinyglobby: 0.2.14
6002+ tinypool: 1.1.1
49876003 tinyrainbow: 2.0.0
4988- vite: 6.1.0(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
4989- vite-node: 3.0.5(@types/node@22.13.4)(jiti@1.21.7)(terser@5.39.0)(tsx@4.19.2)(yaml@2.7.0)
6004+ vite: 6.3.5(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
6005+ vite-node: 3.2.4(@types/node@22.16.0)(jiti@1.21.7)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
49906006 why-is-node-running: 2.3.0
49916007 optionalDependencies:
4992- '@types/node': 22.13.4
6008+ '@types/debug': 4.1.12
6009+ '@types/node': 22.16.0
6010+ jsdom: 26.1.0
49936011 transitivePeerDependencies:
49946012 - jiti
49956013 - less
@@ -5004,12 +6022,35 @@ snapshots:
50046022 - tsx
50056023 - yaml
50066024
6025+ w3c-xmlserializer@5.0.0:
6026+ dependencies:
6027+ xml-name-validator: 5.0.0
6028+
6029+ web-namespaces@2.0.1: {}
6030+
50076031 web-streams-polyfill@3.3.3: {}
50086032
6033+ webidl-conversions@7.0.0: {}
6034+
6035+ whatwg-encoding@3.1.1:
6036+ dependencies:
6037+ iconv-lite: 0.6.3
6038+
6039+ whatwg-mimetype@4.0.0: {}
6040+
6041+ whatwg-url@14.2.0:
6042+ dependencies:
6043+ tr46: 5.1.1
6044+ webidl-conversions: 7.0.0
6045+
50096046 which@2.0.2:
50106047 dependencies:
50116048 isexe: 2.0.0
50126049
6050+ which@4.0.0:
6051+ dependencies:
6052+ isexe: 3.1.1
6053+
50136054 why-is-node-running@2.3.0:
50146055 dependencies:
50156056 siginfo: 2.0.0
@@ -5027,10 +6068,10 @@ snapshots:
50276068
50286069 worktop@0.8.0-next.18:
50296070 dependencies:
5030- mrmime: 2.0.0
6071+ mrmime: 2.0.1
50316072 regexparam: 3.0.0
50326073
5033- wrangler@3.107.3(@cloudflare/workers-types@4.20250214.0):
6074+ wrangler@3.107.3(@cloudflare/workers-types@4.20250703.0):
50346075 dependencies:
50356076 '@cloudflare/kv-asset-handler': 0.3.4
50366077 '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19)
@@ -5042,7 +6083,7 @@ snapshots:
50426083 unenv: 2.0.0-rc.1
50436084 workerd: 1.20250129.0
50446085 optionalDependencies:
5045- '@cloudflare/workers-types': 4.20250214.0
6086+ '@cloudflare/workers-types': 4.20250703.0
50466087 fsevents: 2.3.3
50476088 transitivePeerDependencies:
50486089 - bufferutil
@@ -5062,13 +6103,17 @@ snapshots:
50626103
50636104 wrappy@1.0.2: {}
50646105
5065- ws@8.18.0: {}
6106+ ws@8.18.3: {}
6107+
6108+ xml-name-validator@5.0.0: {}
6109+
6110+ xmlchars@2.2.0: {}
50666111
50676112 xp.css@0.2.6: {}
50686113
50696114 yaml@1.10.2: {}
50706115
5071- yaml@2.7.0: {}
6116+ yaml@2.8.0: {}
50726117
50736118 yocto-queue@0.1.0: {}
50746119
@@ -5080,4 +6125,6 @@ snapshots:
50806125
50816126 zimmerframe@1.1.2: {}
50826127
5083- zod@3.24.2: {}
6128+ zod@3.25.71: {}
6129+
6130+ zwitch@2.0.4: {}
M src/app.css +445 -0
@@ -2,4 +2,449 @@
22 @import 'tailwindcss/components';
33 @import 'tailwindcss/utilities';
44 @import 'xp.css';
5+@import './lib/styles/fonts.css';
6+
7+/* Local font faces with 30-day cache */
8+@font-face {
9+ font-family: 'Arial';
10+ src: url('/fonts/Arial.TTF') format('truetype');
11+ font-display: swap;
12+ font-weight: normal;
13+ font-style: normal;
14+}
15+
16+@font-face {
17+ font-family: 'Arial';
18+ src: url('/fonts/Arialbd.TTF') format('truetype');
19+ font-display: swap;
20+ font-weight: bold;
21+ font-style: normal;
22+}
23+
24+@font-face {
25+ font-family: 'Arial';
26+ src: url('/fonts/Ariali.TTF') format('truetype');
27+ font-display: swap;
28+ font-weight: normal;
29+ font-style: italic;
30+}
31+
32+@font-face {
33+ font-family: 'Arial';
34+ src: url('/fonts/Arialbi.TTF') format('truetype');
35+ font-display: swap;
36+ font-weight: bold;
37+ font-style: italic;
38+}
39+
40+@font-face {
41+ font-family: 'Tahoma';
42+ src: url('/fonts/tahoma.ttf') format('truetype');
43+ font-display: swap;
44+ font-weight: 80;
45+ font-style: normal;
46+}
47+
48+@font-face {
49+ font-family: 'Tahoma';
50+ src: url('/fonts/tahomabd.ttf') format('truetype');
51+ font-display: swap;
52+ font-weight: 200;
53+ font-style: normal;
54+}
55+
56+@font-face {
57+ font-family: 'Verdana';
58+ src: url('/fonts/Verdana.TTF') format('truetype');
59+ font-display: swap;
60+ font-weight: normal;
61+ font-style: normal;
62+}
63+
64+@font-face {
65+ font-family: 'Verdana';
66+ src: url('/fonts/Verdanab.TTF') format('truetype');
67+ font-display: swap;
68+ font-weight: bold;
69+ font-style: normal;
70+}
71+
72+@font-face {
73+ font-family: 'Verdana';
74+ src: url('/fonts/Verdanai.TTF') format('truetype');
75+ font-display: swap;
76+ font-weight: normal;
77+ font-style: italic;
78+}
79+
80+@font-face {
81+ font-family: 'Verdana';
82+ src: url('/fonts/Verdanaz.TTF') format('truetype');
83+ font-display: swap;
84+ font-weight: bold;
85+ font-style: italic;
86+}
87+
88+@font-face {
89+ font-family: 'Comic Sans MS';
90+ src: url('/fonts/Comic.TTF') format('truetype');
91+ font-display: swap;
92+ font-weight: normal;
93+ font-style: normal;
94+}
95+
96+@font-face {
97+ font-family: 'Comic Sans MS';
98+ src: url('/fonts/Comicbd.TTF') format('truetype');
99+ font-display: swap;
100+ font-weight: bold;
101+ font-style: normal;
102+}
103+
104+@font-face {
105+ font-family: 'Times New Roman';
106+ src: url('/fonts/Times.TTF') format('truetype');
107+ font-display: swap;
108+ font-weight: normal;
109+ font-style: normal;
110+}
111+
112+@font-face {
113+ font-family: 'Times New Roman';
114+ src: url('/fonts/Timesbd.TTF') format('truetype');
115+ font-display: swap;
116+ font-weight: bold;
117+ font-style: normal;
118+}
119+
120+@font-face {
121+ font-family: 'Times New Roman';
122+ src: url('/fonts/Timesi.TTF') format('truetype');
123+ font-display: swap;
124+ font-weight: normal;
125+ font-style: italic;
126+}
127+
128+@font-face {
129+ font-family: 'Times New Roman';
130+ src: url('/fonts/Timesbi.TTF') format('truetype');
131+ font-display: swap;
132+ font-weight: bold;
133+ font-style: italic;
134+}
135+
136+@font-face {
137+ font-family: 'Courier New';
138+ src: url('/fonts/LiberationMono-Regular.ttf') format('truetype');
139+ font-display: swap;
140+ font-weight: normal;
141+ font-style: normal;
142+}
143+
144+@font-face {
145+ font-family: 'Courier New';
146+ src: url('/fonts/LiberationMono-Bold.ttf') format('truetype');
147+ font-display: swap;
148+ font-weight: bold;
149+ font-style: normal;
150+}
151+
152+@font-face {
153+ font-family: 'Courier New';
154+ src: url('/fonts/LiberationMono-Italic.ttf') format('truetype');
155+ font-display: swap;
156+ font-weight: normal;
157+ font-style: italic;
158+}
159+
160+@font-face {
161+ font-family: 'Courier New';
162+ src: url('/fonts/LiberationMono-BoldItalic.ttf') format('truetype');
163+ font-display: swap;
164+ font-weight: bold;
165+ font-style: italic;
166+}
167+
168+/* ===== RETRO FONT STYLING ===== */
169+/* Retro Windows fonts with proper fallbacks */
170+.retro-font-pixelated {
171+ font-family: "Pixelated MS Sans Serif", "Tahoma", Geneva, sans-serif;
172+}
173+
174+.retro-font-tahoma {
175+ font-family: Tahoma, "Pixelated MS Sans Serif", Geneva, sans-serif;
176+}
177+
178+.retro-font-verdana {
179+ font-family: Verdana, "Pixelated MS Sans Serif", Geneva, sans-serif;
180+}
181+
182+.retro-font-comicSans {
183+ font-family: "Comic Sans MS", "Pixelated MS Sans Serif", cursive, sans-serif;
184+}
185+
186+.retro-font-timesNewRoman {
187+ font-family: "Times New Roman", Times, serif;
188+}
189+
190+.retro-font-arial {
191+ font-family: Arial, "Pixelated MS Sans Serif", Helvetica, sans-serif;
192+}
193+
194+.retro-font-courierNew {
195+ font-family: "Courier New", "Perfect DOS VGA 437 Win", Courier, monospace;
196+}
197+
198+.retro-font-dos {
199+ font-family: "Perfect DOS VGA 437 Win", "Courier New", Courier, monospace;
200+}
201+
202+/* ===== GRADIENT TEXT EFFECTS ===== */
203+.gradient-text {
204+ background-size: 200% 200%;
205+ -webkit-background-clip: text;
206+ -webkit-text-fill-color: transparent;
207+ background-clip: text;
208+ animation: gradientShift 3s ease infinite;
209+}
210+
211+.gradient-text-static {
212+ /* Remove text-fill-color to allow inline color styles to work */
213+ /* Individual spans will have their own colors set inline */
214+ letter-spacing: normal;
215+ word-spacing: normal;
216+}
217+
218+/* Gradient text container uses flexbox */
219+.gradient-text-static {
220+ display: inline-flex !important;
221+ flex-wrap: wrap !important;
222+ align-items: baseline !important;
223+}
224+
225+/* Ensure gradient character spans don't add spacing */
226+.gradient-text-static > span {
227+ display: inline !important;
228+ margin: 0 !important;
229+ padding: 0 !important;
230+ letter-spacing: 0 !important;
231+ line-height: inherit !important;
232+ font-size: inherit !important;
233+}
234+
235+/* Ensure gradient character colors from inline styles are respected */
236+.gradient-text-static .gradient-char {
237+ -webkit-text-fill-color: initial !important;
238+}
239+
240+/* Gradient text in input fields - preserve normal input background */
241+input[style*="background-clip: text"] {
242+ /* Keep default input background while allowing gradient text */
243+}
244+
245+/* Gradient animation for AOL-style effects */
246+@keyframes gradientShift {
247+ 0% { background-position: 0% 50%; }
248+ 50% { background-position: 100% 50%; }
249+ 100% { background-position: 0% 50%; }
250+}
251+
252+/* Specific gradient presets */
253+.gradient-rainbow {
254+ background: linear-gradient(45deg,
255+ #FF0000, #FF8000, #FFFF00, #80FF00, #00FF00, #00FF80,
256+ #00FFFF, #0080FF, #0000FF, #8000FF, #FF00FF, #FF0080);
257+}
258+
259+.gradient-fire {
260+ background: linear-gradient(45deg, #FF0000, #FF4000, #FF8000, #FFBF00, #FFFF00);
261+}
262+
263+.gradient-ocean {
264+ background: linear-gradient(45deg, #000080, #0040FF, #0080FF, #00BFFF, #00FFFF);
265+}
266+
267+.gradient-sunset {
268+ background: linear-gradient(45deg, #FF4500, #FF6347, #FFD700, #FFFF00);
269+}
270+
271+.gradient-neon {
272+ background: linear-gradient(45deg, #FF00FF, #8000FF, #0080FF, #00FFFF);
273+}
274+
275+.gradient-forest {
276+ background: linear-gradient(45deg, #006400, #228B22, #32CD32, #90EE90);
277+}
278+
279+.gradient-royal {
280+ background: linear-gradient(45deg, #4B0082, #6A5ACD, #9370DB, #DDA0DD);
281+}
282+
283+/* ===== CHAT MESSAGE FORMATTING ===== */
284+.formatted-message {
285+ word-break: break-word;
286+ line-height: 1.4;
287+ max-width: 100%;
288+}
289+
290+.formatted-message strong {
291+ font-weight: bold;
292+}
293+
294+.formatted-message em {
295+ font-style: italic;
296+}
297+
298+.formatted-message u {
299+ text-decoration: underline;
300+}
301+
302+.formatted-message s {
303+ text-decoration: line-through;
304+}
305+
306+.formatted-message code {
307+ background: #f0f0f0;
308+ padding: 1px 3px;
309+ border-radius: 2px;
310+ font-family: 'Courier New', Courier, monospace;
311+ font-size: 0.9em;
312+}
313+
314+/* ===== INPUT STYLING FIXES ===== */
315+/* Fix letter spacing issues with gradient text in inputs */
316+input[style*="background-clip: text"] {
317+ letter-spacing: normal !important;
318+ word-spacing: normal !important;
319+}
320+
321+/* Ensure gradient inputs don't have extra padding */
322+input.styled-input {
323+ letter-spacing: 0;
324+ word-spacing: 0;
325+}
326+
327+/* Ensure proper font weights are used */
328+.retro-font-tahoma {
329+ font-weight: 80;
330+}
331+
332+/* ===== TEXT STYLE SELECTOR STYLING ===== */
333+.text-formatting-toolbar {
334+ background: #f0f0f0;
335+ border: 2px inset #dfdfdf;
336+ padding: 4px;
337+ margin-bottom: 8px;
338+ display: flex;
339+ flex-wrap: wrap;
340+ gap: 4px;
341+ align-items: center;
342+}
343+
344+.formatting-button {
345+ width: 24px;
346+ height: 24px;
347+ border: 1px outset #dfdfdf;
348+ background: #f0f0f0;
349+ cursor: pointer;
350+ display: flex;
351+ align-items: center;
352+ justify-content: center;
353+ font-size: 12px;
354+ font-weight: bold;
355+ transition: all 0.1s ease;
356+}
357+
358+.formatting-button:hover {
359+ background: #e0e0e0;
360+}
361+
362+.formatting-button:active,
363+.formatting-button.active {
364+ border: 1px inset #dfdfdf;
365+ background: #d0d0d0;
366+}
367+
368+.font-selector {
369+ padding: 2px 4px;
370+ border: 1px inset #dfdfdf;
371+ background: white;
372+ font-size: 11px;
373+ min-width: 80px;
374+}
375+
376+.size-slider {
377+ width: 60px;
378+}
379+
380+.color-indicator {
381+ width: 16px;
382+ height: 16px;
383+ border: 1px solid #000;
384+ cursor: pointer;
385+ display: inline-block;
386+}
387+
388+/* ===== ACCESSIBILITY IMPROVEMENTS ===== */
389+@media (prefers-reduced-motion: reduce) {
390+ .gradient-text {
391+ animation: none;
392+ }
393+}
394+
395+/* High contrast mode support */
396+@media (prefers-contrast: high) {
397+ .gradient-text {
398+ -webkit-text-fill-color: unset;
399+ background: none;
400+ color: inherit;
401+ }
402+
403+ .gradient-text-static {
404+ -webkit-text-fill-color: unset;
405+ background: none;
406+ color: inherit;
407+ }
408+}
409+
410+/* ===== RETRO STYLING ENHANCEMENTS ===== */
411+.retro-message {
412+ font-family: inherit;
413+ line-height: 1.3;
414+ word-wrap: break-word;
415+}
416+
417+.retro-message.style-bold {
418+ font-weight: bold;
419+}
420+
421+.retro-message.style-italic {
422+ font-style: italic;
423+}
424+
425+.retro-message.style-underline {
426+ text-decoration: underline;
427+}
428+
429+.retro-message.style-strikethrough {
430+ text-decoration: line-through;
431+}
432+
433+.retro-message.style-underline.style-strikethrough {
434+ text-decoration: underline line-through;
435+}
436+
437+/* ===== PERFORMANCE OPTIMIZATIONS ===== */
438+.gradient-text,
439+.gradient-text-static {
440+ will-change: background-position;
441+ contain: layout style paint;
442+}
443+
444+/* Limit gradient text length for performance */
445+.gradient-text-long {
446+ max-width: 500px;
447+ overflow: hidden;
448+ text-overflow: ellipsis;
449+}
5450
A src/lib/buddyListCache.ts +55 -0
@@ -0,0 +1,55 @@
1+import { createLogger } from './utils/logger.server';
2+import type { SafeUser } from './types/chat';
3+
4+const log = createLogger('buddy-list-cache');
5+
6+class BuddyListCache {
7+ private cache: SafeUser[] | null = null;
8+ private lastHash: string = '';
9+ private lastFetch: number = 0;
10+ private isDirty: boolean = true; // Force initial fetch
11+
12+ // Mark cache as needing refresh
13+ invalidate(): void {
14+ this.isDirty = true;
15+ log.debug('Buddy list cache invalidated');
16+ }
17+
18+ // Check if we need to fetch new data
19+ needsRefresh(): boolean {
20+ return this.isDirty || this.cache === null;
21+ }
22+
23+ // Update cache with new data
24+ update(users: SafeUser[]): boolean {
25+ const newHash = JSON.stringify(users);
26+ const hasChanged = newHash !== this.lastHash;
27+
28+ if (hasChanged) {
29+ this.cache = users;
30+ this.lastHash = newHash;
31+ this.lastFetch = Date.now();
32+ this.isDirty = false;
33+
34+ log.debug('Buddy list cache updated', {
35+ userCount: users.length,
36+ changed: hasChanged
37+ });
38+ }
39+
40+ return hasChanged;
41+ }
42+
43+ // Get cached data
44+ get(): SafeUser[] | null {
45+ return this.cache;
46+ }
47+
48+ // Get cache age in milliseconds
49+ getAge(): number {
50+ return this.cache ? Date.now() - this.lastFetch : Infinity;
51+ }
52+}
53+
54+// Export singleton instance
55+export const buddyListCache = new BuddyListCache();⏎̸
M src/lib/components/aim-login.svelte +50 -45
@@ -5,9 +5,10 @@
55 import type { User, SafeUser } from '$lib/types/chat';
66 import { invalidateAll } from '$app/navigation';
77 import { chatState } from '$lib/states/chat.svelte';
8- import Turnstile from './turnstile.svelte';
98 import { createSafeUser } from '$lib/types/chat';
109 import { onMount } from 'svelte';
10+ import PasswordStrengthIndicator from './password-strength-indicator.svelte';
11+ import { loginSchema, createRegistrationSchema, validatePasswordStrength, DEFAULT_PASSWORD_CONSTRAINTS, type PasswordConstraints } from '../validation/password';
1112
1213 interface $$Props {
1314 showAuth: boolean;
@@ -24,7 +25,6 @@
2425 let siPassword = $state('');
2526 let error = $state('');
2627 let loginStatus = $state('idle');
27- let siTurnstileToken = $state('');
2828
2929 // Sign Up state
3030 let suUsername = $state('');
@@ -35,6 +35,10 @@
3535 let signupStatus = $state('idle');
3636 let suTurnstileToken = $state('');
3737
38+ // Password validation state
39+ let passwordConstraints: PasswordConstraints = DEFAULT_PASSWORD_CONSTRAINTS;
40+ let showPasswordStrength = $state(false);
41+
3842 // Added dragging state and handler similar to chat-room
3943 let windowX = $state(0);
4044 let windowY = $state(0);
@@ -60,8 +64,11 @@
6064 async function handleSigninSubmit() {
6165 error = '';
6266 loginStatus = 'loading';
63- if (!siUsername || !siPassword || !siTurnstileToken) {
64- error = 'Please complete all fields including the security check';
67+
68+ // Validate login data
69+ const validationError = validateLoginData();
70+ if (validationError) {
71+ error = validationError;
6572 loginStatus = 'error';
6673 return;
6774 }
@@ -73,8 +80,7 @@
7380 headers: { 'Content-Type': 'application/json' },
7481 body: JSON.stringify({
7582 username: siUsername,
76- password: siPassword,
77- turnstileToken: siTurnstileToken
83+ password: siPassword
7884 })
7985 });
8086
@@ -107,41 +113,30 @@
107113 }
108114 }
109115
110- // New: Create a helper function for client-side validations based on server rules.
111- function validateSignupData(): string | null {
112- // Trim values
113- const username = suUsername.trim();
114- const password = suPassword.trim();
115- const confirmPasswordValue = suConfirmPassword.trim();
116-
117- if (!username || !password || !confirmPasswordValue) {
118- return 'All fields must be filled';
119- }
120-
121- if (username.length < 3) {
122- return 'Username must be at least 3 characters';
123- }
124-
125- if (username.length > 32) {
126- return 'Username must be at most 32 characters';
127- }
128-
129- // Only allow letters, numbers, underscores, and dashes in the username.
130- const usernameRegex = /^[a-zA-Z0-9_-]+$/;
131- if (!usernameRegex.test(username)) {
132- return 'Invalid username. Only letters, numbers, underscores, and dashes are allowed.';
133- }
134-
135- if (password !== confirmPasswordValue) {
136- return 'Passwords do not match';
116+ // Validation using Zod schemas
117+ function validateLoginData() {
118+ try {
119+ loginSchema.parse({ username: siUsername.trim(), password: siPassword.trim() });
120+ return null;
121+ } catch (err: any) {
122+ return err.errors?.[0]?.message || 'Invalid input';
137123 }
124+ }
138125
139- if (password.length < 8 || password.length > 64) {
140- return 'Password must be between 8 and 64 characters';
126+ function validateSignupData() {
127+ try {
128+ const registrationSchema = createRegistrationSchema(passwordConstraints);
129+ registrationSchema.parse({
130+ suUsername: suUsername.trim(),
131+ suPassword: suPassword.trim(),
132+ suConfirmPassword: suConfirmPassword.trim(),
133+ captchaAnswer: captchaAnswer.trim(),
134+ turnstileToken: suTurnstileToken
135+ });
136+ return null;
137+ } catch (err: any) {
138+ return err.errors?.[0]?.message || 'Invalid input';
141139 }
142-
143- // All checks passed.
144- return null;
145140 }
146141
147142 async function handleSignupSubmit() {
@@ -156,10 +151,9 @@
156151 return;
157152 }
158153
159- // Additional check for captcha and Turnstile token,
160- // in case those fields are not filled.
161- if (!captchaAnswer || !suTurnstileToken) {
162- signupError = 'Please complete all fields including the security check';
154+ // Additional check for captcha
155+ if (!captchaAnswer) {
156+ signupError = 'Please complete all fields including the PDR question';
163157 signupStatus = 'error';
164158 return;
165159 }
@@ -271,7 +265,6 @@
271265 <label for="si-password">Mot de passe</label>
272266 <input type="password" id="si-password" bind:value={siPassword} placeholder="Mot de passe" />
273267 </div>
274- <Turnstile onVerify={(token: string) => siTurnstileToken = token} />
275268 {#if error}
276269 <div class="error">{error}</div>
277270 {/if}
@@ -311,7 +304,20 @@
311304 </div>
312305 <div class="form-group">
313306 <label for="su-password">Mot de passe</label>
314- <input type="password" id="su-password" bind:value={suPassword} placeholder="Mot de passe" />
307+ <input
308+ type="password"
309+ id="su-password"
310+ bind:value={suPassword}
311+ placeholder="Mot de passe"
312+ onfocus={() => showPasswordStrength = true}
313+ />
314+ {#if showPasswordStrength}
315+ <PasswordStrengthIndicator
316+ password={suPassword}
317+ constraints={passwordConstraints}
318+ showDetails={true}
319+ />
320+ {/if}
315321 </div>
316322 <div class="form-group">
317323 <label for="su-confirm-password">Confirmer le mot de passe</label>
@@ -321,7 +327,6 @@
321327 <label for="captcha">Quelle est la signification de PDR ?</label>
322328 <input type="text" id="captcha" bind:value={captchaAnswer} placeholder="Entrez votre réponse" />
323329 </div>
324- <Turnstile onVerify={(token: string) => suTurnstileToken = token} />
325330 {#if signupError}
326331 <div class="error">{signupError}</div>
327332 {/if}
M src/lib/components/chat-room.svelte +82 -15
@@ -11,8 +11,14 @@ import LoadingButton from './ui/button-loading.svelte';
1111 import Tooltip from './ui/tooltip.svelte';
1212 import LoadingDots from './ui/loading-dots.svelte';
1313 import AimLogin from './aim-login.svelte';
14+import FormattedMessage from './formatted-message.svelte';
15+import TextFormattingToolbar from './text-formatting-toolbar.svelte';
16+import { DEFAULT_TEXT_STYLE, type TextStyle, generateInputCSSStyle } from '../types/text-formatting';
1417 import { formatFrenchDateTime, formatFrenchRelativeTimeSafe } from '$lib/utils/date-format';
1518
19+// Props destructuring must come first
20+let { showChatRoom = $bindable(), initialTextStyle = DEFAULT_TEXT_STYLE } = $props();
21+
1622 // Initialize with default values for SSR
1723 let windowWidth = $state(400);
1824 let windowHeight = $state(500);
@@ -26,6 +32,14 @@ let isInitialLoading = $state(true);
2632 let showAuth = $state(false);
2733 let isMinimized = $state(false);
2834
35+// Text formatting state - initialize directly with merged initial style
36+let currentTextStyle = $state<TextStyle>({
37+ ...DEFAULT_TEXT_STYLE,
38+ ...initialTextStyle,
39+ color: initialTextStyle.color || '#000000' // Ensure we always have a valid color
40+});
41+let showFormattingToolbar = $state(true);
42+
2943 // Rate limiting state
3044 let cooldownEndTime = $state<number | null>(null);
3145 let cooldownProgress = $state(0);
@@ -60,8 +74,6 @@ function startCooldownTimer(retryAfter: number) {
6074 updateCooldownProgress();
6175 }
6276
63-let { showChatRoom = $bindable() } = $props();
64-
6577 function handleClose() {
6678 showChatRoom = false;
6779 }
@@ -239,7 +251,7 @@ async function handleSubmit() {
239251
240252 isSendingMessage = true;
241253 try {
242- const response = await chatState.sendMessage(currentMessage);
254+ const response = await chatState.sendMessage(currentMessage, 'chat', currentTextStyle);
243255 if (!response.success && response.isRateLimited && response.retryAfter) {
244256 startCooldownTimer(response.retryAfter);
245257 rateLimitWarning = 'Whoa there! You\'re sending messages too quickly. Take a breather...';
@@ -459,7 +471,7 @@ function handleLoginSuccess() {
459471 ondragmove={handleDragMove}
460472 >
461473 <div class="title-bar">
462- <div class="title-bar-text" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
474+ <div class="title-bar-text" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-family: 'MS Sans Serif', 'Pixelated MS Sans Serif', sans-serif;">
463475 Pdr Aim {#if currentUser} - {currentUser.nickname}{:else} - {totalUsers} membre{totalUsers > 1 ? 's' : ''}{/if}
464476 {#if sseError && !isMinimized}
465477 <span class="connection-error">⚠️ Erreur de connexion</span>
@@ -563,21 +575,49 @@ function handleLoginSuccess() {
563575 }}>
564576 <span class="nickname pointer-events-none">{message.user.nickname}:</span>
565577 </Tooltip>
566- <span class="content">{message.content}</span>
578+ <FormattedMessage {message} allowFormatting={true} />
567579 {/if}
568580 </div>
569581 {/each}
570582 </div>
571583
584+ <!-- Text Formatting Toolbar -->
585+ {#if currentUser}
586+ <div style="margin-bottom: 0.25rem;">
587+ <TextFormattingToolbar
588+ bind:style={currentTextStyle}
589+ compact={true}
590+ showFontSelector={true}
591+ showGradients={true}
592+ />
593+ </div>
594+ {/if}
595+
596+
572597 <div class="field-row input-container" style="margin: 0;">
573- <input
574- type="text"
575- bind:value={currentMessage}
576- style="flex: 1;"
577- onkeydown={(e) => e.key === 'Enter' && handleSubmit()}
578- placeholder={cooldownEndTime ? `Patientez ${cooldownProgress.toFixed(1)}s...` : "Écrivez un message..."}
579- disabled={!currentUser || Boolean(cooldownEndTime)}
580- />
598+ {#if currentTextStyle.gradient && currentTextStyle.gradient.length > 1}
599+ <div class="gradient-input-wrapper" style="flex: 1; position: relative; background: white;">
600+ <input
601+ type="text"
602+ bind:value={currentMessage}
603+ class="styled-input retro-font-{currentTextStyle.fontFamily}"
604+ style="width: 100%; background: transparent; {generateInputCSSStyle(currentTextStyle)}"
605+ onkeydown={(e) => e.key === 'Enter' && handleSubmit()}
606+ placeholder={cooldownEndTime ? `Patientez ${cooldownProgress.toFixed(1)}s...` : "Écrivez un message..."}
607+ disabled={!currentUser || Boolean(cooldownEndTime)}
608+ />
609+ </div>
610+ {:else}
611+ <input
612+ type="text"
613+ bind:value={currentMessage}
614+ class="styled-input retro-font-{currentTextStyle.fontFamily}"
615+ style="flex: 1; {generateInputCSSStyle(currentTextStyle)}"
616+ onkeydown={(e) => e.key === 'Enter' && handleSubmit()}
617+ placeholder={cooldownEndTime ? `Patientez ${cooldownProgress.toFixed(1)}s...` : "Écrivez un message..."}
618+ disabled={!currentUser || Boolean(cooldownEndTime)}
619+ />
620+ {/if}
581621 <LoadingButton
582622 onclick={handleSubmit}
583623 disabled={!currentUser || Boolean(cooldownEndTime)}
@@ -632,9 +672,14 @@ function handleLoginSuccess() {
632672 {/if}
633673
634674 <style>
635- .chat-area, .users-list, input {
675+ .chat-area, .users-list {
636676 font-size: 1rem;
637- font-family: Arial, Verdana, Tahoma, sans-serif;
677+ font-family: "Pixelated MS Sans Serif", Arial, Verdana, Tahoma, sans-serif;
678+ }
679+
680+ input:not(.styled-input) {
681+ font-size: 1rem;
682+ font-family: "Pixelated MS Sans Serif", Arial, Verdana, Tahoma, sans-serif;
638683 }
639684
640685 .title-bar {
@@ -674,6 +719,16 @@ function handleLoginSuccess() {
674719 gap: 0.5rem;
675720 align-items: flex-start;
676721 }
722+
723+ /* Fix gradient text spacing in messages */
724+ .message :global(.gradient-text-static) {
725+ letter-spacing: normal !important;
726+ word-spacing: normal !important;
727+ }
728+
729+ .message :global(.gradient-text-static span) {
730+ letter-spacing: 0 !important;
731+ }
677732
678733 .message .nickname {
679734 font-weight: bold;
@@ -1036,4 +1091,16 @@ function handleLoginSuccess() {
10361091 .pointer-events-none {
10371092 pointer-events: none;
10381093 }
1094+
1095+ .gradient-input-wrapper {
1096+ border: 1px inset #dfdfdf;
1097+ padding: 2px;
1098+ }
1099+
1100+ .gradient-input-wrapper input {
1101+ border: none !important;
1102+ outline: none !important;
1103+ padding: 1px 3px;
1104+ }
1105+
10391106 </style>⏎̸
A src/lib/components/color-picker-256.svelte +453 -0
@@ -0,0 +1,453 @@
1+<script lang="ts">
2+import { generate256Colors, CLASSIC_COLORS } from '../types/text-formatting';
3+
4+// Props
5+let {
6+ selectedColor = $bindable('#000000'),
7+ selectedGradient = $bindable(undefined),
8+ onColorChange,
9+ onGradientChange,
10+ compact = true
11+} = $props<{
12+ selectedColor?: string;
13+ selectedGradient?: string[];
14+ onColorChange?: (color: string) => void;
15+ onGradientChange?: (gradient: string[]) => void;
16+ compact?: boolean;
17+}>();
18+
19+// State
20+let showPicker = $state(false);
21+let gradientColors = $state<string[]>([selectedColor || '#000000']);
22+let activeGradientSlot = $state(0);
23+
24+// Generate color palette
25+const colors256 = generate256Colors();
26+const classicColors = Object.values(CLASSIC_COLORS);
27+
28+// Initialize gradient colors from props
29+$effect(() => {
30+ if (selectedGradient && selectedGradient.length > 0) {
31+ gradientColors = [...selectedGradient];
32+ } else if (selectedColor) {
33+ gradientColors = [selectedColor];
34+ }
35+});
36+
37+// Get current display color/gradient
38+let displayStyle = $derived(() => {
39+ if (gradientColors.length > 1) {
40+ return `background: linear-gradient(45deg, ${gradientColors.join(', ')})`;
41+ }
42+ return `background: ${gradientColors[0] || '#000000'}`;
43+});
44+
45+// Handle color selection
46+function selectColor(color: string) {
47+ if (activeGradientSlot < gradientColors.length) {
48+ gradientColors[activeGradientSlot] = color;
49+ gradientColors = [...gradientColors]; // Trigger reactivity
50+
51+ if (gradientColors.length === 1) {
52+ // Single color mode
53+ selectedColor = color;
54+ selectedGradient = undefined;
55+ onColorChange?.(color);
56+ } else {
57+ // Gradient mode
58+ selectedGradient = [...gradientColors];
59+ selectedColor = gradientColors[0];
60+ onGradientChange?.(gradientColors);
61+ }
62+ }
63+}
64+
65+// Gradient management
66+function addGradientColor() {
67+ if (gradientColors.length < 3) {
68+ const newColor = gradientColors[gradientColors.length - 1] || '#FFFFFF';
69+ gradientColors = [...gradientColors, newColor];
70+ activeGradientSlot = gradientColors.length - 1;
71+ selectedGradient = [...gradientColors];
72+ onGradientChange?.(gradientColors);
73+ }
74+}
75+
76+function removeGradientColor(index: number) {
77+ if (gradientColors.length > 1) {
78+ gradientColors = gradientColors.filter((_, i) => i !== index);
79+ activeGradientSlot = Math.min(activeGradientSlot, gradientColors.length - 1);
80+
81+ if (gradientColors.length === 1) {
82+ // Back to single color mode
83+ selectedColor = gradientColors[0];
84+ selectedGradient = undefined;
85+ onColorChange?.(gradientColors[0]);
86+ } else {
87+ selectedGradient = [...gradientColors];
88+ onGradientChange?.(gradientColors);
89+ }
90+ }
91+}
92+
93+function setActiveSlot(index: number) {
94+ activeGradientSlot = index;
95+}
96+
97+// Close picker
98+function closePicker() {
99+ showPicker = false;
100+}
101+
102+// Handle click outside to close
103+function handleClickOutside(event: MouseEvent) {
104+ const target = event.target as HTMLElement;
105+ const colorPickerContainer = document.querySelector('.color-picker-container');
106+
107+ if (showPicker && colorPickerContainer && !colorPickerContainer.contains(target)) {
108+ closePicker();
109+ }
110+}
111+
112+// Add/remove click outside listener
113+$effect(() => {
114+ if (showPicker) {
115+ document.addEventListener('click', handleClickOutside);
116+ return () => {
117+ document.removeEventListener('click', handleClickOutside);
118+ };
119+ }
120+});
121+</script>
122+
123+<div class="color-picker-container">
124+ <!-- Color picker button -->
125+ <button
126+ onclick={(e) => {
127+ e.stopPropagation();
128+ showPicker = !showPicker;
129+ }}
130+ title={gradientColors.length > 1 ? 'Gradient Color' : 'Text Color'}
131+ style="width: 20px; height: 20px; padding: 0;"
132+ >
133+ <div
134+ class="color-indicator"
135+ style="{displayStyle()}; width: 12px; height: 12px; border: 1px solid #000;"
136+ ></div>
137+ </button>
138+
139+ <!-- Color picker dropdown -->
140+ {#if showPicker}
141+ <div class="picker-dropdown sunken-panel" onclick={(e) => e.stopPropagation()}>
142+ <!-- Gradient controls -->
143+ <div class="gradient-controls">
144+ <div class="gradient-slots">
145+ {#each gradientColors as color, index}
146+ <button
147+ class="gradient-slot"
148+ class:active={activeGradientSlot === index}
149+ style="background-color: {color} !important;"
150+ onclick={() => setActiveSlot(index)}
151+ title="Color {index + 1} - Click to select this color slot"
152+ >
153+ {#if gradientColors.length > 1}
154+ <span
155+ class="remove-slot"
156+ onclick={(e) => {
157+ e.stopPropagation();
158+ removeGradientColor(index);
159+ }}
160+ title="Remove this color"
161+ role="button"
162+ tabindex="0"
163+ >×</span>
164+ {/if}
165+ </button>
166+ {/each}
167+
168+ {#if gradientColors.length < 3}
169+ <button
170+ class="add-slot"
171+ onclick={addGradientColor}
172+ title="Add another color to create gradient"
173+ >+</button>
174+ {/if}
175+ </div>
176+
177+ {#if gradientColors.length > 1}
178+ <div class="gradient-preview" style="background: linear-gradient(90deg, {gradientColors.join(', ')});"></div>
179+ {/if}
180+ </div>
181+
182+ <!-- Classic colors (first row) -->
183+ <div class="color-section">
184+ <div class="section-title">Classic Colors</div>
185+ <div class="color-row">
186+ {#each classicColors as color}
187+ <button
188+ class="color-swatch classic-swatch"
189+ style="--swatch-color: {color}; background-color: {color} !important;"
190+ onclick={() => selectColor(color)}
191+ title={color}
192+ ></button>
193+ {/each}
194+ </div>
195+ </div>
196+
197+ <!-- 256-color palette -->
198+ <div class="color-section">
199+ <div class="section-title">Full Palette</div>
200+ <div class="color-grid">
201+ {#each colors256 as color}
202+ <button
203+ class="color-swatch"
204+ style="--swatch-color: {color}; background-color: {color} !important;"
205+ onclick={() => selectColor(color)}
206+ title={color}
207+ ></button>
208+ {/each}
209+ </div>
210+ </div>
211+
212+ <!-- Close button -->
213+ <div class="picker-footer">
214+ <button onclick={closePicker}>Close</button>
215+ </div>
216+ </div>
217+ {/if}
218+</div>
219+
220+<style>
221+ .color-picker-container {
222+ position: relative;
223+ display: inline-block;
224+ }
225+
226+ .picker-dropdown {
227+ position: absolute;
228+ top: 100%;
229+ right: 0; /* Changed from left: 0 to prevent cutoff */
230+ z-index: 1000;
231+ padding: 4px;
232+ margin-top: 2px;
233+ background: #ece9d8; /* Authentic XP dialog background */
234+ width: 420px;
235+ max-height: 380px;
236+ overflow-y: auto;
237+ border: 2px outset #c0c0c0;
238+ box-shadow: 2px 2px 4px rgba(0,0,0,0.3);
239+ box-sizing: border-box;
240+ }
241+
242+ /* Responsive positioning for mobile/small screens */
243+ @media (max-width: 768px) {
244+ .picker-dropdown {
245+ position: fixed;
246+ top: 50%;
247+ left: 50%;
248+ transform: translate(-50%, -50%);
249+ right: auto;
250+ width: 90vw;
251+ max-width: 420px;
252+ max-height: 85vh;
253+ }
254+ }
255+
256+ .gradient-controls {
257+ margin-bottom: 6px;
258+ padding: 4px;
259+ border: 1px inset #dfdfdf;
260+ background: #ece9d8;
261+ }
262+
263+ .gradient-slots {
264+ display: flex;
265+ gap: 4px;
266+ margin-bottom: 4px;
267+ align-items: center;
268+ flex-wrap: wrap;
269+ }
270+
271+ .gradient-slot {
272+ width: 24px;
273+ height: 24px;
274+ border: 2px outset #c0c0c0 !important;
275+ cursor: pointer;
276+ position: relative;
277+ padding: 0 !important;
278+ margin: 0 !important;
279+ background-image: none !important;
280+ min-width: 24px !important;
281+ min-height: 24px !important;
282+ max-width: 24px !important;
283+ max-height: 24px !important;
284+ box-sizing: border-box !important;
285+ flex-shrink: 0;
286+ transition: all 0.2s ease;
287+ }
288+
289+ .gradient-slot.active {
290+ border: 2px inset #c0c0c0 !important;
291+ box-shadow: inset 0 0 0 1px #000 !important;
292+ }
293+
294+ .gradient-slot:hover {
295+ transform: scale(1.1);
296+ }
297+
298+ .gradient-slot .remove-slot {
299+ position: absolute;
300+ top: -4px;
301+ right: -4px;
302+ width: 12px !important;
303+ height: 12px !important;
304+ min-width: 12px !important;
305+ min-height: 12px !important;
306+ max-width: 12px !important;
307+ max-height: 12px !important;
308+ background-color: #808080 !important;
309+ color: white !important;
310+ border: 1px solid #000 !important;
311+ font-size: 9px !important;
312+ line-height: 1 !important;
313+ cursor: pointer !important;
314+ display: inline-flex !important;
315+ align-items: center !important;
316+ justify-content: center !important;
317+ border-radius: 0 !important;
318+ padding: 0 !important;
319+ margin: 0 !important;
320+ font-weight: normal !important;
321+ font-family: 'MS Sans Serif', sans-serif !important;
322+ z-index: 10;
323+ opacity: 0;
324+ transition: opacity 0.15s ease;
325+ text-align: center !important;
326+ box-sizing: border-box !important;
327+ user-select: none;
328+ }
329+
330+ .gradient-slot:hover .remove-slot {
331+ opacity: 0.8;
332+ }
333+
334+ .gradient-slot .remove-slot:hover {
335+ background-color: #000 !important;
336+ opacity: 1;
337+ }
338+
339+ .add-slot {
340+ width: 24px;
341+ height: 24px;
342+ border: 2px dashed #666 !important;
343+ background: #f0f0f0 !important;
344+ cursor: pointer;
345+ font-weight: bold;
346+ padding: 0 !important;
347+ margin: 0 !important;
348+ min-width: 24px !important;
349+ min-height: 24px !important;
350+ max-width: 24px !important;
351+ max-height: 24px !important;
352+ background-image: none !important;
353+ box-sizing: border-box !important;
354+ flex-shrink: 0;
355+ display: flex !important;
356+ align-items: center !important;
357+ justify-content: center !important;
358+ font-size: 14px !important;
359+ color: #666 !important;
360+ transition: all 0.2s ease;
361+ }
362+
363+ .add-slot:hover {
364+ background: #e0e0e0 !important;
365+ border-color: #333 !important;
366+ transform: scale(1.05);
367+ }
368+
369+ .gradient-preview {
370+ height: 12px;
371+ border: 1px inset #dfdfdf;
372+ }
373+
374+ .color-section {
375+ margin-bottom: 6px;
376+ }
377+
378+ .section-title {
379+ font-size: 10px;
380+ font-weight: bold;
381+ margin-bottom: 2px;
382+ color: #000;
383+ }
384+
385+ .color-row {
386+ display: flex;
387+ flex-wrap: wrap;
388+ gap: 2px;
389+ margin-bottom: 4px;
390+ padding: 3px;
391+ background: #ece9d8;
392+ border: 1px inset #dfdfdf;
393+ }
394+
395+ .classic-swatch {
396+ width: 18px !important;
397+ height: 18px !important;
398+ min-width: 18px !important;
399+ min-height: 18px !important;
400+ }
401+
402+ .color-grid {
403+ display: grid;
404+ grid-template-columns: repeat(16, 1fr);
405+ gap: 2px;
406+ width: 100%;
407+ padding: 3px;
408+ background: #ece9d8;
409+ border: 1px inset #dfdfdf;
410+ box-sizing: border-box;
411+ }
412+
413+ .color-swatch {
414+ width: 18px !important;
415+ height: 18px !important;
416+ min-width: 18px !important;
417+ min-height: 18px !important;
418+ border: 1px solid #808080 !important; /* Override xp.css */
419+ cursor: pointer;
420+ padding: 0 !important;
421+ margin: 0 !important;
422+ box-sizing: border-box !important;
423+ outline: none !important;
424+ /* Remove any xp.css button styling */
425+ background-image: none !important;
426+ background-color: var(--swatch-color, #000000) !important;
427+ font-size: 0 !important; /* Hide any text */
428+ line-height: 0 !important;
429+ }
430+
431+ .color-swatch:hover {
432+ border: 2px solid #000000 !important;
433+ transform: scale(1.1) !important;
434+ z-index: 5;
435+ position: relative;
436+ }
437+
438+ .color-swatch:active {
439+ border: 2px solid #ffffff !important;
440+ transform: scale(0.95) !important;
441+ }
442+
443+ .picker-footer {
444+ text-align: center;
445+ padding-top: 4px;
446+ border-top: 1px solid #808080;
447+ margin-top: 4px;
448+ }
449+
450+ .color-indicator {
451+ border-radius: 1px;
452+ }
453+</style>⏎̸
A src/lib/components/formatted-message.svelte +249 -0
@@ -0,0 +1,249 @@
1+<script lang="ts">
2+import { onMount } from 'svelte';
3+import type { EnrichedMessage } from '../types/chat';
4+import type { TextStyle } from '../types/text-formatting';
5+import { formatText, createGradientText } from '../utils/text-formatter';
6+import { DEFAULT_TEXT_STYLE, generateCSSStyle, RETRO_FONTS } from '../types/text-formatting';
7+
8+// Props
9+let {
10+ message,
11+ allowFormatting = true
12+} = $props<{
13+ message: EnrichedMessage;
14+ allowFormatting?: boolean;
15+}>();
16+
17+// State
18+let formattedContent = $state('');
19+let isProcessing = $state(false);
20+let hasError = $state(false);
21+
22+// Process message formatting
23+async function processMessage() {
24+ if (!allowFormatting || !message.hasFormatting) {
25+ formattedContent = escapeHtml(message.content);
26+ return;
27+ }
28+
29+ isProcessing = true;
30+ hasError = false;
31+
32+ try {
33+ // Parse style data if available
34+ let style: TextStyle = DEFAULT_TEXT_STYLE;
35+ if (message.styleData) {
36+ try {
37+ style = JSON.parse(message.styleData);
38+ console.debug('Parsed message style:', style, 'for message:', message.content);
39+ } catch (parseError) {
40+ console.warn('Failed to parse message style data:', parseError);
41+ }
42+ }
43+
44+ // Check if this is a gradient message
45+ if (style.gradient && Array.isArray(style.gradient) && style.gradient.length > 1) {
46+ // Use character-by-character gradient for better compatibility
47+ console.debug('Creating gradient text with colors:', style.gradient, 'for text:', message.content);
48+ formattedContent = createGradientText(message.content, style.gradient, 'gradient-text-static', style);
49+ console.debug('Generated gradient HTML:', formattedContent);
50+ return;
51+ }
52+
53+ // Regular formatted text (no gradient)
54+ const styleWithoutGradient = { ...style, gradient: undefined };
55+ formattedContent = await formatText(message.content, styleWithoutGradient, allowFormatting);
56+
57+ } catch (error) {
58+ console.error('Message formatting error:', error);
59+ hasError = true;
60+ formattedContent = escapeHtml(message.content);
61+ } finally {
62+ isProcessing = false;
63+ }
64+}
65+
66+// Process message when it changes
67+$effect(() => {
68+ processMessage();
69+});
70+
71+// Utility function to escape HTML
72+function escapeHtml(text: string): string {
73+ const div = document.createElement('div');
74+ div.textContent = text;
75+ return div.innerHTML;
76+}
77+
78+// Generate inline styles for the message
79+function getMessageStyles(): string {
80+ if (!message.hasFormatting || !message.styleData) {
81+ return '';
82+ }
83+
84+ try {
85+ const style: TextStyle = JSON.parse(message.styleData);
86+ // For gradient messages, we still need some styles but not font-family (use class instead)
87+ if (style.gradient && Array.isArray(style.gradient) && style.gradient.length > 1) {
88+ // Return only non-color and non-font-family styles for gradient messages
89+ const styles: string[] = [];
90+ styles.push(`font-size: ${style.fontSize}px`);
91+ if (style.bold) styles.push(`font-weight: bold`);
92+ if (style.italic) styles.push(`font-style: italic`);
93+ const decorations: string[] = [];
94+ if (style.underline) decorations.push('underline');
95+ if (style.strikethrough) decorations.push('line-through');
96+ if (decorations.length > 0) {
97+ styles.push(`text-decoration: ${decorations.join(' ')}`);
98+ }
99+ return styles.join('; ');
100+ }
101+ // For non-gradient messages, exclude font-family (use class instead)
102+ const styles: string[] = [];
103+ styles.push(`font-size: ${style.fontSize}px`);
104+ if (style.color) styles.push(`color: ${style.color}`);
105+ if (style.bold) styles.push(`font-weight: bold`);
106+ if (style.italic) styles.push(`font-style: italic`);
107+ const decorations: string[] = [];
108+ if (style.underline) decorations.push('underline');
109+ if (style.strikethrough) decorations.push('line-through');
110+ if (decorations.length > 0) {
111+ styles.push(`text-decoration: ${decorations.join(' ')}`);
112+ }
113+ return styles.join('; ');
114+ } catch (error) {
115+ console.warn('Failed to generate message styles:', error);
116+ return '';
117+ }
118+}
119+
120+// Get CSS classes for the message
121+function getMessageClasses(): string {
122+ const classes = ['formatted-message'];
123+
124+ if (!message.hasFormatting || !message.styleData) {
125+ return classes.join(' ');
126+ }
127+
128+ try {
129+ const style: TextStyle = JSON.parse(message.styleData);
130+
131+ // Add font family class
132+ classes.push(`retro-font-${style.fontFamily}`);
133+
134+ // Add style classes
135+ if (style.bold) classes.push('style-bold');
136+ if (style.italic) classes.push('style-italic');
137+ if (style.underline) classes.push('style-underline');
138+ if (style.strikethrough) classes.push('style-strikethrough');
139+
140+ // Add gradient class if applicable
141+ if (style.gradient && Array.isArray(style.gradient) && style.gradient.length > 1) {
142+ classes.push('gradient-text-static');
143+ }
144+
145+ } catch (error) {
146+ console.warn('Failed to parse message style for classes:', error);
147+ }
148+
149+ return classes.join(' ');
150+}
151+</script>
152+
153+{#if isProcessing}
154+ <span class={getMessageClasses()} style={getMessageStyles()}>
155+ <span class="processing">...</span>
156+ </span>
157+{:else if hasError}
158+ <span class={getMessageClasses()} style={getMessageStyles()}>
159+ <span class="error" title="Formatting error - showing plain text">{message.content}</span>
160+ </span>
161+{:else}
162+ <!-- For gradient messages, render without wrapper to avoid conflicts -->
163+ {#if message.hasFormatting && message.styleData}
164+ {@const parsedStyle = (() => {
165+ try {
166+ return JSON.parse(message.styleData);
167+ } catch {
168+ return null;
169+ }
170+ })()}
171+ {#if parsedStyle?.gradient && Array.isArray(parsedStyle.gradient) && parsedStyle.gradient.length > 1}
172+ <!-- Gradient messages are already wrapped properly -->
173+ {@html formattedContent}
174+ {:else}
175+ <!-- Regular formatted messages -->
176+ <span class={getMessageClasses()} style={getMessageStyles()}>
177+ {@html formattedContent}
178+ </span>
179+ {/if}
180+ {:else}
181+ <!-- Plain messages -->
182+ <span class={getMessageClasses()}>
183+ {@html formattedContent}
184+ </span>
185+ {/if}
186+{/if}
187+
188+<style>
189+ .processing {
190+ color: #666;
191+ font-style: italic;
192+ animation: pulse 1s infinite;
193+ }
194+
195+ .error {
196+ color: #cc0000;
197+ border-bottom: 1px dotted #cc0000;
198+ }
199+
200+ @keyframes pulse {
201+ 0%, 100% { opacity: 1; }
202+ 50% { opacity: 0.5; }
203+ }
204+
205+ /* Ensure formatted messages don't break layout */
206+ :global(.formatted-message) {
207+ word-break: break-word;
208+ overflow-wrap: break-word;
209+ hyphens: auto;
210+ }
211+
212+ /* Improve gradient text readability */
213+ :global(.formatted-message.gradient-text-static) {
214+ font-weight: bold;
215+ }
216+
217+ /* Ensure gradient spans are visible and preserve their colors */
218+ :global(.gradient-text-static .gradient-char) {
219+ display: inline;
220+ opacity: 1 !important;
221+ margin: 0 !important;
222+ padding: 0 !important;
223+ letter-spacing: 0 !important;
224+ -webkit-text-fill-color: initial !important;
225+ }
226+
227+ /* Don't override inline styles for gradient chars - removed to let inline styles work */
228+
229+ /* Remove any blur or gray effects */
230+ :global(.formatted-message) {
231+ opacity: 1 !important;
232+ filter: none !important;
233+ }
234+
235+ /* Don't inherit color for gradient text spans */
236+ :global(.formatted-message:not(.gradient-text-static)) {
237+ color: inherit;
238+ }
239+
240+ /* Ensure accessibility for screen readers */
241+ :global(.formatted-message[aria-label]) {
242+ position: relative;
243+ }
244+
245+ /* Performance optimization for complex messages */
246+ :global(.formatted-message) {
247+ contain: layout style;
248+ }
249+</style>⏎̸
A src/lib/components/password-strength-indicator.svelte +165 -0
@@ -0,0 +1,165 @@
1+<script lang="ts">
2+ import { validatePasswordStrength, type PasswordConstraints, DEFAULT_PASSWORD_CONSTRAINTS } from '../validation/password';
3+
4+ interface $$Props {
5+ password: string;
6+ constraints?: PasswordConstraints;
7+ showDetails?: boolean;
8+ }
9+
10+ let {
11+ password = '',
12+ constraints = DEFAULT_PASSWORD_CONSTRAINTS,
13+ showDetails = true
14+ } = $props();
15+
16+ // Reactive validation result
17+ let validation = $derived(validatePasswordStrength(password, constraints));
18+
19+ // Get strength color and label
20+ function getStrengthInfo(strength: number) {
21+ if (strength < 30) return { color: '#ff4444', label: 'Weak', class: 'weak' };
22+ if (strength < 60) return { color: '#ffaa00', label: 'Fair', class: 'fair' };
23+ if (strength < 80) return { color: '#44aa44', label: 'Good', class: 'good' };
24+ return { color: '#00aa00', label: 'Strong', class: 'strong' };
25+ }
26+
27+ let strengthInfo = $derived(getStrengthInfo(validation.strength));
28+</script>
29+
30+<div class="password-strength-indicator">
31+ {#if password.length > 0}
32+ <!-- Strength bar -->
33+ <div class="strength-bar">
34+ <div class="strength-bar-bg">
35+ <div
36+ class="strength-bar-fill {strengthInfo.class}"
37+ style="width: {validation.strength}%; background-color: {strengthInfo.color};"
38+ ></div>
39+ </div>
40+ <span class="strength-label {strengthInfo.class}">{strengthInfo.label}</span>
41+ </div>
42+
43+ {#if showDetails}
44+ <!-- Requirements checklist -->
45+ <div class="requirements-list">
46+ {#each validation.requirements as requirement}
47+ <div class="requirement {requirement.met ? 'met' : 'unmet'}">
48+ <span class="requirement-icon">
49+ {requirement.met ? '✓' : '✗'}
50+ </span>
51+ <span class="requirement-text">{requirement.message}</span>
52+ </div>
53+ {/each}
54+ </div>
55+
56+ <!-- Error messages -->
57+ {#if validation.errors.length > 0}
58+ <div class="error-messages">
59+ {#each validation.errors as error}
60+ <div class="error-message">{error}</div>
61+ {/each}
62+ </div>
63+ {/if}
64+ {/if}
65+ {/if}
66+</div>
67+
68+<style>
69+ .password-strength-indicator {
70+ margin-top: 8px;
71+ font-size: 0.875rem;
72+ }
73+
74+ .strength-bar {
75+ display: flex;
76+ align-items: center;
77+ gap: 8px;
78+ margin-bottom: 8px;
79+ }
80+
81+ .strength-bar-bg {
82+ flex: 1;
83+ height: 6px;
84+ background-color: #ddd;
85+ border-radius: 3px;
86+ overflow: hidden;
87+ }
88+
89+ .strength-bar-fill {
90+ height: 100%;
91+ transition: width 0.3s ease, background-color 0.3s ease;
92+ border-radius: 3px;
93+ }
94+
95+ .strength-label {
96+ min-width: 50px;
97+ font-weight: bold;
98+ font-size: 0.75rem;
99+ }
100+
101+ .strength-label.weak { color: #ff4444; }
102+ .strength-label.fair { color: #ffaa00; }
103+ .strength-label.good { color: #44aa44; }
104+ .strength-label.strong { color: #00aa00; }
105+
106+ .requirements-list {
107+ display: flex;
108+ flex-direction: column;
109+ gap: 4px;
110+ margin-bottom: 8px;
111+ }
112+
113+ .requirement {
114+ display: flex;
115+ align-items: center;
116+ gap: 6px;
117+ font-size: 0.75rem;
118+ }
119+
120+ .requirement-icon {
121+ width: 12px;
122+ text-align: center;
123+ font-weight: bold;
124+ }
125+
126+ .requirement.met {
127+ color: #00aa00;
128+ }
129+
130+ .requirement.met .requirement-icon {
131+ color: #00aa00;
132+ }
133+
134+ .requirement.unmet {
135+ color: #888;
136+ }
137+
138+ .requirement.unmet .requirement-icon {
139+ color: #ff4444;
140+ }
141+
142+ .error-messages {
143+ display: flex;
144+ flex-direction: column;
145+ gap: 4px;
146+ }
147+
148+ .error-message {
149+ color: #ff4444;
150+ font-size: 0.75rem;
151+ }
152+
153+ /* Compact mode styles */
154+ :global(.compact) .password-strength-indicator {
155+ font-size: 0.75rem;
156+ }
157+
158+ :global(.compact) .requirements-list {
159+ display: none;
160+ }
161+
162+ :global(.compact) .strength-bar {
163+ margin-bottom: 4px;
164+ }
165+</style>⏎̸
A src/lib/components/text-formatting-toolbar.svelte +216 -0
@@ -0,0 +1,216 @@
1+<script lang="ts">
2+import {
3+ RETRO_FONTS,
4+ CLASSIC_COLORS,
5+ GRADIENT_PRESETS,
6+ DEFAULT_TEXT_STYLE,
7+ type TextStyle,
8+ type FontFamily
9+} from '../types/text-formatting';
10+import ColorPicker256 from './color-picker-256.svelte';
11+
12+// Props
13+let {
14+ style = $bindable(DEFAULT_TEXT_STYLE),
15+ onPreviewText,
16+ compact = true,
17+ showFontSelector = false,
18+ showGradients = true
19+} = $props<{
20+ style?: TextStyle;
21+ onPreviewText?: (text: string) => void;
22+ compact?: boolean;
23+ showFontSelector?: boolean;
24+ showGradients?: boolean;
25+}>();
26+
27+// State
28+let currentColor = $state(style.color || '#000000');
29+let currentGradient = $state(style.gradient);
30+
31+// Toggle functions
32+function toggleBold() {
33+ style = { ...style, bold: !style.bold };
34+}
35+
36+function toggleItalic() {
37+ style = { ...style, italic: !style.italic };
38+}
39+
40+function toggleUnderline() {
41+ style = { ...style, underline: !style.underline };
42+}
43+
44+function handleColorChange(color: string) {
45+ currentColor = color;
46+ style = { ...style, color, gradient: undefined };
47+}
48+
49+function handleGradientChange(gradient: string[]) {
50+ currentGradient = gradient;
51+ style = { ...style, gradient, color: gradient[0] };
52+}
53+
54+function selectFont(fontFamily: FontFamily) {
55+ style = { ...style, fontFamily };
56+}
57+
58+// Keyboard shortcuts handler
59+function handleKeydown(event: KeyboardEvent) {
60+ if (event.ctrlKey || event.metaKey) {
61+ switch (event.key.toLowerCase()) {
62+ case 'b':
63+ event.preventDefault();
64+ toggleBold();
65+ break;
66+ case 'i':
67+ event.preventDefault();
68+ toggleItalic();
69+ break;
70+ case 'u':
71+ event.preventDefault();
72+ toggleUnderline();
73+ break;
74+ }
75+ }
76+}
77+
78+// Preview text change
79+function previewTextChanged() {
80+ if (onPreviewText) {
81+ onPreviewText('Sample formatted text');
82+ }
83+}
84+
85+// Update internal state when style prop changes
86+$effect(() => {
87+ currentColor = style.color || '#000000';
88+ currentGradient = style.gradient;
89+});
90+</script>
91+
92+<svelte:window onkeydown={handleKeydown} />
93+
94+<div class="text-formatting-toolbar sunken-panel" class:compact>
95+
96+ <!-- Font selector (if enabled) -->
97+ {#if showFontSelector}
98+ <select
99+ value={style.fontFamily}
100+ onchange={(e) => selectFont((e.target as HTMLSelectElement).value as FontFamily)}
101+ title="Font Family"
102+ >
103+ {#each Object.entries(RETRO_FONTS) as [key, font]}
104+ <option value={key} style="font-family: {font.stack};">{font.name}</option>
105+ {/each}
106+ </select>
107+ {/if}
108+
109+ <!-- Size slider -->
110+ <div class="size-control">
111+ <input
112+ type="range"
113+ min="8"
114+ max="18"
115+ bind:value={style.fontSize}
116+ class="size-slider"
117+ title="Font Size: {style.fontSize}px"
118+ />
119+ <span class="size-display">{style.fontSize}</span>
120+ </div>
121+
122+ <!-- Style toggle buttons -->
123+ <div class="style-toggles">
124+ <button
125+ onclick={toggleBold}
126+ title="Bold (Ctrl+B)"
127+ style="width: 20px; height: 20px; padding: 0; font-size: 10px;"
128+ >
129+ <strong>B</strong>
130+ </button>
131+
132+ <button
133+ onclick={toggleItalic}
134+ title="Italic (Ctrl+I)"
135+ style="width: 20px; height: 20px; padding: 0; font-size: 10px;"
136+ >
137+ <em>I</em>
138+ </button>
139+
140+ <button
141+ onclick={toggleUnderline}
142+ title="Underline (Ctrl+U)"
143+ style="width: 20px; height: 20px; padding: 0; font-size: 10px;"
144+ >
145+ <u>U</u>
146+ </button>
147+ </div>
148+
149+ <!-- Color controls -->
150+ <div class="color-controls">
151+ <ColorPicker256
152+ bind:selectedColor={currentColor}
153+ bind:selectedGradient={currentGradient}
154+ onColorChange={handleColorChange}
155+ onGradientChange={handleGradientChange}
156+ {compact}
157+ />
158+ </div>
159+
160+
161+</div>
162+
163+<style>
164+ .text-formatting-toolbar {
165+ display: flex;
166+ align-items: center;
167+ gap: 4px;
168+ padding: 2px;
169+ font-size: 11px;
170+ position: relative;
171+ flex-wrap: wrap;
172+ }
173+
174+ .size-control {
175+ display: flex;
176+ align-items: center;
177+ gap: 2px;
178+ }
179+
180+ .size-slider {
181+ width: 50px;
182+ height: 12px;
183+ }
184+
185+ .size-display {
186+ font-size: 9px;
187+ color: #666;
188+ min-width: 18px;
189+ text-align: center;
190+ }
191+
192+ .style-toggles {
193+ display: flex;
194+ gap: 1px;
195+ }
196+
197+ .color-controls {
198+ display: flex;
199+ gap: 1px;
200+ }
201+
202+ /* Fix font dropdown text alignment */
203+ select {
204+ height: 20px;
205+ line-height: 1;
206+ vertical-align: middle;
207+ padding: 1px 4px;
208+ font-size: 11px;
209+ }
210+
211+ select option {
212+ padding: 2px 4px;
213+ line-height: normal;
214+ }
215+
216+</style>⏎̸
A src/lib/components/text-style-selector.svelte +323 -0
@@ -0,0 +1,323 @@
1+<script lang="ts">
2+import {
3+ RETRO_FONTS,
4+ CLASSIC_COLORS,
5+ DEFAULT_TEXT_STYLE,
6+ type TextStyle,
7+ type FontFamily,
8+ generateCSSStyle
9+} from '../types/text-formatting';
10+import ColorPicker256 from './color-picker-256.svelte';
11+import { formatText, createGradientText } from '../utils/text-formatter';
12+
13+// Props
14+let {
15+ style = $bindable(DEFAULT_TEXT_STYLE),
16+ previewText = "Sample text preview",
17+ showPreview = true,
18+ compact = false
19+} = $props<{
20+ style?: TextStyle;
21+ previewText?: string;
22+ showPreview?: boolean;
23+ compact?: boolean;
24+}>();
25+
26+// Local state
27+let currentColor = $state(style.color || '#000000');
28+let currentGradient = $state(style.gradient);
29+let formattedPreview = $state('');
30+let isProcessing = $state(false);
31+
32+// Update preview when style changes
33+$effect(() => {
34+ if (!showPreview) return;
35+
36+ async function updatePreview() {
37+ isProcessing = true;
38+ try {
39+ if (style.gradient && Array.isArray(style.gradient) && style.gradient.length > 1) {
40+ formattedPreview = createGradientText(previewText, style.gradient, 'preview-gradient');
41+ } else {
42+ formattedPreview = await formatText(previewText, style, false);
43+ }
44+ } catch (error) {
45+ console.error('Preview formatting error:', error);
46+ formattedPreview = previewText;
47+ } finally {
48+ isProcessing = false;
49+ }
50+ }
51+
52+ updatePreview();
53+});
54+
55+// Font family selection
56+function selectFont(fontFamily: FontFamily) {
57+ style = { ...style, fontFamily };
58+}
59+
60+// Color selection
61+function handleColorChange(color: string) {
62+ currentColor = color;
63+ style = { ...style, color, gradient: undefined };
64+}
65+
66+// Gradient selection
67+function handleGradientChange(gradient: string[]) {
68+ currentGradient = gradient;
69+ style = { ...style, gradient, color: gradient[0] };
70+}
71+
72+// Update internal state when style prop changes
73+$effect(() => {
74+ currentColor = style.color || '#000000';
75+ currentGradient = style.gradient;
76+});
77+
78+// Toggle style options
79+function toggleBold() {
80+ style = { ...style, bold: !style.bold };
81+}
82+
83+function toggleItalic() {
84+ style = { ...style, italic: !style.italic };
85+}
86+
87+function toggleUnderline() {
88+ style = { ...style, underline: !style.underline };
89+}
90+
91+function toggleStrikethrough() {
92+ style = { ...style, strikethrough: !style.strikethrough };
93+}
94+
95+// Font size adjustment
96+function updateFontSize(size: number) {
97+ style = { ...style, fontSize: Math.max(8, Math.min(18, size)) };
98+}
99+
100+</script>
101+
102+<div class="text-style-selector" class:compact>
103+ <!-- Font Family Selection -->
104+ <div class="style-group">
105+ <label>Font:</label>
106+ <select
107+ bind:value={style.fontFamily}
108+ onchange={(e) => selectFont((e.target as HTMLSelectElement).value as FontFamily)}
109+ >
110+ {#each Object.entries(RETRO_FONTS) as [key, font]}
111+ <option value={key} style="font-family: {font.stack}">
112+ {font.name}
113+ </option>
114+ {/each}
115+ </select>
116+ </div>
117+
118+ <!-- Font Size -->
119+ <div class="style-group">
120+ <label>Size:</label>
121+ <input
122+ type="range"
123+ min="8"
124+ max="18"
125+ bind:value={style.fontSize}
126+ oninput={(e) => updateFontSize(parseInt((e.target as HTMLInputElement).value))}
127+ />
128+ <span class="size-display">{style.fontSize}px</span>
129+ </div>
130+
131+ <!-- Style Toggles -->
132+ <div class="style-group toggles">
133+ <button
134+ class="style-toggle"
135+ class:active={style.bold}
136+ onclick={toggleBold}
137+ title="Bold (Ctrl+B)"
138+ >
139+ <strong>B</strong>
140+ </button>
141+ <button
142+ class="style-toggle"
143+ class:active={style.italic}
144+ onclick={toggleItalic}
145+ title="Italic (Ctrl+I)"
146+ >
147+ <em>I</em>
148+ </button>
149+ <button
150+ class="style-toggle"
151+ class:active={style.underline}
152+ onclick={toggleUnderline}
153+ title="Underline (Ctrl+U)"
154+ >
155+ <u>U</u>
156+ </button>
157+ <button
158+ class="style-toggle"
159+ class:active={style.strikethrough}
160+ onclick={toggleStrikethrough}
161+ title="Strikethrough"
162+ >
163+ <s>S</s>
164+ </button>
165+ </div>
166+
167+ <!-- Color & Gradient Selection -->
168+ <div class="style-group">
169+ <label>Color:</label>
170+ <div class="color-controls">
171+ <ColorPicker256
172+ bind:selectedColor={currentColor}
173+ bind:selectedGradient={currentGradient}
174+ onColorChange={handleColorChange}
175+ onGradientChange={handleGradientChange}
176+ compact={false}
177+ />
178+ </div>
179+ </div>
180+
181+
182+ <!-- Preview -->
183+ {#if showPreview}
184+ <div class="preview-section">
185+ <label>Preview:</label>
186+ <div
187+ class="preview-text"
188+ style={generateCSSStyle(style)}
189+ >
190+ {#if isProcessing}
191+ <span class="loading">Processing...</span>
192+ {:else}
193+ {@html formattedPreview}
194+ {/if}
195+ </div>
196+ </div>
197+ {/if}
198+</div>
199+
200+<style>
201+ .text-style-selector {
202+ background: #f0f0f0;
203+ border: 2px inset #dfdfdf;
204+ padding: 8px;
205+ font-family: 'MS Sans Serif', sans-serif;
206+ font-size: 11px;
207+ }
208+
209+ .text-style-selector.compact {
210+ padding: 4px;
211+ }
212+
213+ .style-group {
214+ display: flex;
215+ align-items: center;
216+ gap: 8px;
217+ margin-bottom: 8px;
218+ }
219+
220+ .style-group label {
221+ font-weight: bold;
222+ min-width: 50px;
223+ }
224+
225+ .style-group select {
226+ flex: 1;
227+ padding: 2px;
228+ border: 1px inset #dfdfdf;
229+ background: white;
230+ }
231+
232+ .style-group input[type="range"] {
233+ flex: 1;
234+ }
235+
236+ .size-display {
237+ min-width: 35px;
238+ font-size: 10px;
239+ color: #666;
240+ }
241+
242+ .toggles {
243+ gap: 4px;
244+ }
245+
246+ .style-toggle {
247+ width: 24px;
248+ height: 24px;
249+ border: 1px outset #dfdfdf;
250+ background: #f0f0f0;
251+ cursor: pointer;
252+ display: flex;
253+ align-items: center;
254+ justify-content: center;
255+ font-size: 12px;
256+ font-weight: bold;
257+ }
258+
259+ .style-toggle:hover {
260+ background: #e0e0e0;
261+ }
262+
263+ .style-toggle.active {
264+ border: 1px inset #dfdfdf;
265+ background: #d0d0d0;
266+ }
267+
268+ .color-controls {
269+ display: flex;
270+ gap: 4px;
271+ }
272+
273+ .preview-section {
274+ margin-top: 12px;
275+ padding-top: 8px;
276+ border-top: 1px solid #ccc;
277+ }
278+
279+ .preview-section label {
280+ display: block;
281+ margin-bottom: 4px;
282+ font-weight: bold;
283+ }
284+
285+ .preview-text {
286+ padding: 8px;
287+ border: 1px inset #dfdfdf;
288+ background: white;
289+ min-height: 24px;
290+ line-height: 1.4;
291+ }
292+
293+ .loading {
294+ color: #666;
295+ font-style: italic;
296+ }
297+
298+ /* Gradient text support */
299+ :global(.preview-gradient) {
300+ display: inline;
301+ }
302+
303+ /* Compact mode adjustments */
304+ .compact .style-group {
305+ margin-bottom: 4px;
306+ }
307+
308+ .compact .style-group label {
309+ min-width: 40px;
310+ font-size: 10px;
311+ }
312+
313+ .compact .style-toggle {
314+ width: 20px;
315+ height: 20px;
316+ font-size: 10px;
317+ }
318+
319+ .compact .color-button, .compact .gradient-button {
320+ font-size: 9px;
321+ padding: 1px 4px;
322+ }
323+</style>⏎̸
A src/lib/components/user-preferences-modal.svelte +492 -0
@@ -0,0 +1,492 @@
1+<script lang="ts">
2+import { onMount } from 'svelte';
3+import TextStyleSelector from './text-style-selector.svelte';
4+import {
5+ DEFAULT_USER_PREFERENCES,
6+ DEFAULT_TEXT_STYLE,
7+ type UserTextPreferences,
8+ type TextStyle
9+} from '../types/text-formatting';
10+
11+// Props
12+let {
13+ showModal = $bindable(false),
14+ onSave
15+} = $props<{
16+ showModal: boolean;
17+ onSave?: (preferences: UserTextPreferences) => void;
18+}>();
19+
20+// State
21+let preferences = $state<UserTextPreferences>({ ...DEFAULT_USER_PREFERENCES });
22+let currentStyle = $state<TextStyle>({ ...DEFAULT_TEXT_STYLE });
23+let isSaving = $state(false);
24+let hasChanges = $state(false);
25+
26+// Track changes
27+$effect(() => {
28+ hasChanges = JSON.stringify(preferences) !== JSON.stringify(DEFAULT_USER_PREFERENCES);
29+});
30+
31+// Update preferences when style changes
32+$effect(() => {
33+ preferences.defaultStyle = { ...currentStyle };
34+});
35+
36+// Load user preferences on mount
37+onMount(async () => {
38+ try {
39+ const response = await fetch('/api/user/text-preferences');
40+ if (response.ok) {
41+ const data = await response.json();
42+ if (data.success && data.preferences) {
43+ preferences = { ...DEFAULT_USER_PREFERENCES, ...data.preferences };
44+ currentStyle = { ...DEFAULT_TEXT_STYLE, ...preferences.defaultStyle };
45+ }
46+ }
47+ } catch (error) {
48+ console.error('Failed to load user preferences:', error);
49+ }
50+});
51+
52+// Save preferences
53+async function savePreferences() {
54+ if (!onSave) return;
55+
56+ isSaving = true;
57+ try {
58+ await onSave(preferences);
59+ showModal = false;
60+ } catch (error) {
61+ console.error('Failed to save preferences:', error);
62+ alert('Failed to save preferences. Please try again.');
63+ } finally {
64+ isSaving = false;
65+ }
66+}
67+
68+// Reset to defaults
69+function resetToDefaults() {
70+ preferences = { ...DEFAULT_USER_PREFERENCES };
71+ currentStyle = { ...DEFAULT_TEXT_STYLE };
72+}
73+
74+// Cancel changes
75+function cancel() {
76+ showModal = false;
77+}
78+
79+// Handle keyboard shortcuts
80+function handleKeydown(event: KeyboardEvent) {
81+ if (event.key === 'Escape') {
82+ cancel();
83+ } else if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
84+ savePreferences();
85+ }
86+}
87+</script>
88+
89+{#if showModal}
90+ <!-- Modal backdrop -->
91+ <div
92+ class="modal-backdrop"
93+ onclick={cancel}
94+ onkeydown={handleKeydown}
95+ role="dialog"
96+ aria-modal="true"
97+ aria-labelledby="preferences-title"
98+ >
99+ <!-- Modal content -->
100+ <div class="modal-window window" onclick={(e) => e.stopPropagation()}>
101+ <div class="title-bar">
102+ <div class="title-bar-text" id="preferences-title">
103+ Text Formatting Preferences
104+ </div>
105+ <div class="title-bar-controls">
106+ <button onclick={cancel} aria-label="Close"></button>
107+ </div>
108+ </div>
109+
110+ <div class="window-body">
111+ <div class="preferences-content">
112+
113+ <!-- Enable/Disable Formatting -->
114+ <div class="preference-group">
115+ <label class="checkbox-label">
116+ <input
117+ type="checkbox"
118+ bind:checked={preferences.allowFormatting}
119+ />
120+ Enable text formatting in messages
121+ </label>
122+ <small class="help-text">
123+ When enabled, you can use formatting options like bold, italic, colors, and gradients.
124+ </small>
125+ </div>
126+
127+ <!-- Default Text Style -->
128+ <div class="preference-group">
129+ <h3>Default Text Style</h3>
130+ <p class="description">
131+ These settings will be used as defaults when you send new messages.
132+ </p>
133+
134+ <TextStyleSelector
135+ bind:style={currentStyle}
136+ previewText="This is how your messages will look by default"
137+ showPreview={true}
138+ compact={false}
139+ />
140+ </div>
141+
142+ <!-- Message Settings -->
143+ <div class="preference-group">
144+ <h3>Message Settings</h3>
145+
146+ <div class="setting-row">
147+ <label for="max-length">Maximum message length:</label>
148+ <input
149+ id="max-length"
150+ type="number"
151+ min="100"
152+ max="2000"
153+ bind:value={preferences.maxMessageLength}
154+ class="length-input"
155+ />
156+ <span class="unit">characters</span>
157+ </div>
158+
159+ <small class="help-text">
160+ Longer messages may take more time to process and display.
161+ </small>
162+ </div>
163+
164+ <!-- Format Help -->
165+ <div class="preference-group">
166+ <details class="format-help">
167+ <summary>Formatting Guide</summary>
168+ <div class="format-examples">
169+ <h4>BBCode Style:</h4>
170+ <ul>
171+ <li><code>[b]bold text[/b]</code> → <strong>bold text</strong></li>
172+ <li><code>[i]italic text[/i]</code> → <em>italic text</em></li>
173+ <li><code>[u]underlined[/u]</code> → <u>underlined</u></li>
174+ <li><code>[s]strikethrough[/s]</code> → <s>strikethrough</s></li>
175+ <li><code>[color=red]red text[/color]</code> → <span style="color: red">red text</span></li>
176+ </ul>
177+
178+ <h4>Markdown Style:</h4>
179+ <ul>
180+ <li><code>**bold text**</code> → <strong>bold text</strong></li>
181+ <li><code>*italic text*</code> → <em>italic text</em></li>
182+ <li><code>~~strikethrough~~</code> → <s>strikethrough</s></li>
183+ <li><code>`code text`</code> → <code>code text</code></li>
184+ </ul>
185+ </div>
186+ </details>
187+ </div>
188+
189+ </div>
190+
191+ <!-- Modal buttons -->
192+ <div class="modal-buttons">
193+ <button
194+ class="reset-button"
195+ onclick={resetToDefaults}
196+ disabled={isSaving}
197+ >
198+ Reset to Defaults
199+ </button>
200+
201+ <div class="main-buttons">
202+ <button
203+ onclick={cancel}
204+ disabled={isSaving}
205+ >
206+ Cancel
207+ </button>
208+
209+ <button
210+ class="save-button"
211+ onclick={savePreferences}
212+ disabled={isSaving || !hasChanges}
213+ >
214+ {#if isSaving}
215+ Saving...
216+ {:else}
217+ Save Changes
218+ {/if}
219+ </button>
220+ </div>
221+ </div>
222+ </div>
223+ </div>
224+ </div>
225+{/if}
226+
227+<style>
228+ .modal-backdrop {
229+ position: fixed;
230+ top: 0;
231+ left: 0;
232+ right: 0;
233+ bottom: 0;
234+ background: rgba(0, 0, 0, 0.5);
235+ display: flex;
236+ align-items: center;
237+ justify-content: center;
238+ z-index: 1000;
239+ padding: 20px;
240+ }
241+
242+ .modal-window {
243+ width: 100%;
244+ max-width: 600px;
245+ max-height: 90vh;
246+ overflow: hidden;
247+ box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.3);
248+ }
249+
250+ .window-body {
251+ display: flex;
252+ flex-direction: column;
253+ height: 70vh;
254+ max-height: 600px;
255+ }
256+
257+ .preferences-content {
258+ flex: 1;
259+ overflow-y: auto;
260+ padding: 16px;
261+ }
262+
263+ .preference-group {
264+ margin-bottom: 24px;
265+ padding-bottom: 16px;
266+ border-bottom: 1px solid #ddd;
267+ }
268+
269+ .preference-group:last-child {
270+ border-bottom: none;
271+ margin-bottom: 0;
272+ }
273+
274+ .preference-group h3 {
275+ margin: 0 0 8px 0;
276+ font-size: 14px;
277+ font-weight: bold;
278+ color: #2d31a6;
279+ }
280+
281+ .description {
282+ margin: 0 0 12px 0;
283+ font-size: 12px;
284+ color: #666;
285+ }
286+
287+ .checkbox-label {
288+ display: flex;
289+ align-items: center;
290+ gap: 8px;
291+ font-size: 12px;
292+ cursor: pointer;
293+ }
294+
295+ .help-text {
296+ display: block;
297+ margin-top: 4px;
298+ font-size: 11px;
299+ color: #666;
300+ font-style: italic;
301+ }
302+
303+ .setting-row {
304+ display: flex;
305+ align-items: center;
306+ gap: 8px;
307+ margin-bottom: 8px;
308+ }
309+
310+ .setting-row label {
311+ font-size: 12px;
312+ min-width: 140px;
313+ }
314+
315+ .length-input {
316+ width: 80px;
317+ padding: 2px 4px;
318+ border: 1px inset #dfdfdf;
319+ background: white;
320+ font-size: 11px;
321+ }
322+
323+ .unit {
324+ font-size: 11px;
325+ color: #666;
326+ }
327+
328+ .format-help {
329+ margin-top: 8px;
330+ }
331+
332+ .format-help summary {
333+ font-size: 12px;
334+ font-weight: bold;
335+ cursor: pointer;
336+ padding: 4px 0;
337+ }
338+
339+ .format-examples {
340+ padding: 8px 0;
341+ font-size: 11px;
342+ }
343+
344+ .format-examples h4 {
345+ margin: 12px 0 4px 0;
346+ font-size: 11px;
347+ color: #2d31a6;
348+ }
349+
350+ .format-examples ul {
351+ margin: 0;
352+ padding-left: 16px;
353+ }
354+
355+ .format-examples li {
356+ margin-bottom: 2px;
357+ }
358+
359+ .format-examples code {
360+ background: #f0f0f0;
361+ padding: 1px 3px;
362+ border-radius: 2px;
363+ font-family: 'Courier New', monospace;
364+ font-size: 10px;
365+ }
366+
367+ .modal-buttons {
368+ display: flex;
369+ justify-content: space-between;
370+ align-items: center;
371+ padding: 12px 16px;
372+ border-top: 1px solid #ddd;
373+ background: #f8f8f8;
374+ }
375+
376+ .main-buttons {
377+ display: flex;
378+ gap: 8px;
379+ }
380+
381+ .reset-button {
382+ padding: 4px 12px;
383+ font-size: 11px;
384+ border: 1px outset #dfdfdf;
385+ background: #f0f0f0;
386+ cursor: pointer;
387+ }
388+
389+ .reset-button:hover {
390+ background: #e0e0e0;
391+ }
392+
393+ .reset-button:disabled {
394+ opacity: 0.6;
395+ cursor: not-allowed;
396+ }
397+
398+ .save-button {
399+ padding: 4px 16px;
400+ font-size: 11px;
401+ font-weight: bold;
402+ border: 1px outset #dfdfdf;
403+ background: #0078d4;
404+ color: white;
405+ cursor: pointer;
406+ }
407+
408+ .save-button:hover:not(:disabled) {
409+ background: #106ebe;
410+ }
411+
412+ .save-button:disabled {
413+ opacity: 0.6;
414+ cursor: not-allowed;
415+ background: #999;
416+ }
417+
418+ button {
419+ padding: 4px 12px;
420+ font-size: 11px;
421+ border: 1px outset #dfdfdf;
422+ background: #f0f0f0;
423+ cursor: pointer;
424+ }
425+
426+ button:hover:not(:disabled) {
427+ background: #e0e0e0;
428+ }
429+
430+ button:disabled {
431+ opacity: 0.6;
432+ cursor: not-allowed;
433+ }
434+
435+ /* Scrollbar styling */
436+ .preferences-content::-webkit-scrollbar {
437+ width: 12px;
438+ }
439+
440+ .preferences-content::-webkit-scrollbar-track {
441+ background: #f0f0f0;
442+ border: 1px inset #dfdfdf;
443+ }
444+
445+ .preferences-content::-webkit-scrollbar-thumb {
446+ background: #c0c0c0;
447+ border: 1px outset #dfdfdf;
448+ }
449+
450+ .preferences-content::-webkit-scrollbar-thumb:hover {
451+ background: #a0a0a0;
452+ }
453+
454+ /* Mobile responsive */
455+ @media (max-width: 768px) {
456+ .modal-backdrop {
457+ padding: 10px;
458+ }
459+
460+ .modal-window {
461+ max-width: none;
462+ max-height: 95vh;
463+ }
464+
465+ .window-body {
466+ height: 80vh;
467+ }
468+
469+ .preferences-content {
470+ padding: 12px;
471+ }
472+
473+ .setting-row {
474+ flex-direction: column;
475+ align-items: flex-start;
476+ gap: 4px;
477+ }
478+
479+ .setting-row label {
480+ min-width: auto;
481+ }
482+
483+ .modal-buttons {
484+ flex-direction: column;
485+ gap: 8px;
486+ }
487+
488+ .main-buttons {
489+ order: -1;
490+ }
491+ }
492+</style>⏎̸
M src/lib/db/schema.ts +19 -0
@@ -47,6 +47,23 @@ export const messages = table(
4747 content: t.text("content").notNull(),
4848 type: t.text("type").$type<MessageType>().notNull().default("chat"),
4949 timestamp: t.integer("timestamp").notNull(),
50+ styleData: t.text("style_data"), // JSON string of TextStyle object
51+ hasFormatting: t.integer("has_formatting", { mode: "boolean" }).default(false), // Boolean flag
52+ }
53+);
54+
55+export const userTextPreferences = table(
56+ "user_text_preferences",
57+ {
58+ userId: t.text("user_id").references(() => users.id).primaryKey(),
59+ defaultFontFamily: t.text("default_font_family").default("tahoma"),
60+ defaultFontSize: t.integer("default_font_size").default(14),
61+ defaultColor: t.text("default_color").default("black"),
62+ allowFormatting: t.integer("allow_formatting", { mode: "boolean" }).default(true),
63+ maxMessageLength: t.integer("max_message_length").default(500),
64+ stylePresets: t.text("style_presets"), // JSON array of saved styles
65+ createdAt: t.integer("created_at").notNull(),
66+ updatedAt: t.integer("updated_at").notNull(),
5067 }
5168 );
5269
@@ -55,6 +72,7 @@ export type Users = typeof users.$inferSelect;
5572 export type ChatRooms = typeof chatRooms.$inferSelect;
5673 export type Messages = typeof messages.$inferSelect;
5774 export type Sessions = typeof sessions.$inferSelect;
75+export type UserTextPreferences = typeof userTextPreferences.$inferSelect;
5876 // These type assertions will fail if the schema doesn't match the interfaces
5977 export type _UsersValidation = Omit<User, keyof Users> & Omit<Users, keyof User>;
6078 export type _ChatRoomsValidation = Omit<ChatRoom, keyof ChatRooms> & Omit<ChatRooms, keyof ChatRoom>;
@@ -100,6 +118,7 @@ const schema = {
100118 sessions,
101119 chatRooms,
102120 messages,
121+ userTextPreferences,
103122 userView,
104123 chatRoomView,
105124 messageView
A src/lib/sseConnectionTracker.ts +90 -0
@@ -0,0 +1,90 @@
1+import { createLogger } from './utils/logger.server';
2+
3+const log = createLogger('sse-connection-tracker');
4+
5+interface ConnectionInfo {
6+ userId: string;
7+ connectedAt: number;
8+ lastActivity: number;
9+}
10+
11+class SSEConnectionTracker {
12+ private connections = new Map<string, ConnectionInfo>();
13+
14+ addConnection(userId: string): boolean {
15+ const existing = this.connections.get(userId);
16+ if (existing) {
17+ log.debug('User already has active connection', { userId });
18+ // Update last activity but don't trigger status update
19+ existing.lastActivity = Date.now();
20+ return false; // Connection already exists
21+ }
22+
23+ this.connections.set(userId, {
24+ userId,
25+ connectedAt: Date.now(),
26+ lastActivity: Date.now()
27+ });
28+
29+ log.debug('New SSE connection tracked', {
30+ userId,
31+ totalConnections: this.connections.size
32+ });
33+ return true; // New connection
34+ }
35+
36+ removeConnection(userId: string): boolean {
37+ const deleted = this.connections.delete(userId);
38+ if (deleted) {
39+ log.debug('SSE connection removed', {
40+ userId,
41+ remainingConnections: this.connections.size
42+ });
43+ }
44+ return deleted;
45+ }
46+
47+ hasConnection(userId: string): boolean {
48+ return this.connections.has(userId);
49+ }
50+
51+ updateActivity(userId: string): void {
52+ const connection = this.connections.get(userId);
53+ if (connection) {
54+ connection.lastActivity = Date.now();
55+ }
56+ }
57+
58+ getActiveUserIds(): string[] {
59+ return Array.from(this.connections.keys());
60+ }
61+
62+ getConnectionCount(): number {
63+ return this.connections.size;
64+ }
65+
66+ // Clean up stale connections (e.g., if server didn't properly close them)
67+ cleanupStaleConnections(maxInactivityMs: number = 5 * 60 * 1000): string[] {
68+ const now = Date.now();
69+ const staleUserIds: string[] = [];
70+
71+ for (const [userId, info] of this.connections.entries()) {
72+ if (now - info.lastActivity > maxInactivityMs) {
73+ this.connections.delete(userId);
74+ staleUserIds.push(userId);
75+ }
76+ }
77+
78+ if (staleUserIds.length > 0) {
79+ log.info('Cleaned up stale connections', {
80+ count: staleUserIds.length,
81+ userIds: staleUserIds
82+ });
83+ }
84+
85+ return staleUserIds;
86+ }
87+}
88+
89+// Export singleton instance
90+export const sseConnectionTracker = new SSEConnectionTracker();⏎̸
M src/lib/states/chat.svelte.ts +6 -1
@@ -488,7 +488,7 @@ class ChatState {
488488 }
489489 }
490490
491- async sendMessage(content: string, type: Message['type'] = 'chat'): Promise<SendMessageResponse> {
491+ async sendMessage(content: string, type: Message['type'] = 'chat', textStyle?: any): Promise<SendMessageResponse> {
492492 const user = this.getCurrentUser();
493493 if (!user) {
494494 console.debug('Cannot send message: No current user');
@@ -505,6 +505,11 @@ class ChatState {
505505 userId: user.id,
506506 chatRoomId: DEFAULT_CHAT_ROOM_ID
507507 };
508+
509+ // Add styleData if textStyle is provided
510+ if (textStyle) {
511+ (payload as any).styleData = JSON.stringify(textStyle);
512+ }
508513
509514 console.debug('Sending message with payload:', payload);
510515
A src/lib/styles/fonts.css +100 -0
@@ -0,0 +1,100 @@
1+/* Windows Classic Font Fallbacks */
2+/*
3+ * These @font-face declarations ensure consistent font rendering
4+ * by providing proper fallbacks for classic Windows fonts
5+ */
6+
7+/* Tahoma - Primary UI font */
8+@font-face {
9+ font-family: 'Tahoma Web';
10+ src: local('Tahoma'), local('Tahoma Regular');
11+ font-weight: normal;
12+ font-style: normal;
13+}
14+
15+@font-face {
16+ font-family: 'Tahoma Web';
17+ src: local('Tahoma Bold');
18+ font-weight: bold;
19+ font-style: normal;
20+}
21+
22+/* Verdana - Secondary UI font */
23+@font-face {
24+ font-family: 'Verdana Web';
25+ src: local('Verdana'), local('Verdana Regular');
26+ font-weight: normal;
27+ font-style: normal;
28+}
29+
30+@font-face {
31+ font-family: 'Verdana Web';
32+ src: local('Verdana Bold');
33+ font-weight: bold;
34+ font-style: normal;
35+}
36+
37+/* Arial - General purpose */
38+@font-face {
39+ font-family: 'Arial Web';
40+ src: local('Arial'), local('Arial Regular');
41+ font-weight: normal;
42+ font-style: normal;
43+}
44+
45+@font-face {
46+ font-family: 'Arial Web';
47+ src: local('Arial Bold');
48+ font-weight: bold;
49+ font-style: normal;
50+}
51+
52+/* Times New Roman - Serif font */
53+@font-face {
54+ font-family: 'Times New Roman Web';
55+ src: local('Times New Roman'), local('Times New Roman Regular');
56+ font-weight: normal;
57+ font-style: normal;
58+}
59+
60+@font-face {
61+ font-family: 'Times New Roman Web';
62+ src: local('Times New Roman Bold');
63+ font-weight: bold;
64+ font-style: normal;
65+}
66+
67+/* Courier New - Monospace */
68+@font-face {
69+ font-family: 'Courier New Web';
70+ src: local('Courier New'), local('Courier New Regular');
71+ font-weight: normal;
72+ font-style: normal;
73+}
74+
75+@font-face {
76+ font-family: 'Courier New Web';
77+ src: local('Courier New Bold');
78+ font-weight: bold;
79+ font-style: normal;
80+}
81+
82+/* Comic Sans MS - Fun font */
83+@font-face {
84+ font-family: 'Comic Sans MS Web';
85+ src: local('Comic Sans MS'), local('Comic Sans MS Regular');
86+ font-weight: normal;
87+ font-style: normal;
88+}
89+
90+@font-face {
91+ font-family: 'Comic Sans MS Web';
92+ src: local('Comic Sans MS Bold');
93+ font-weight: bold;
94+ font-style: normal;
95+}
96+
97+/* Ensure font-display for better performance */
98+@font-face {
99+ font-display: swap;
100+}⏎̸
M src/lib/types/chat.ts +2 -0
@@ -27,6 +27,8 @@ export type UserStatus = 'offline' | 'online' | 'away' | string;
2727 content: string;
2828 type: MessageType; // Default is 'chat'
2929 timestamp: number; // Timestamp when the message was sent
30+ styleData?: string; // JSON string of TextStyle object for formatting
31+ hasFormatting?: boolean; // Flag to indicate if message has custom formatting
3032 }
3133
3234 // Safe user type for API responses - omits sensitive information
M src/lib/types/payloads.ts +1 -0
@@ -44,6 +44,7 @@ export interface SendMessageRequest {
4444 type?: Message['type'];
4545 userId: string;
4646 chatRoomId?: string;
47+ styleData?: string; // JSON stringified TextStyle
4748 }
4849
4950 export interface SendMessageResponseSuccess {
A src/lib/types/text-formatting.ts +273 -0
@@ -0,0 +1,273 @@
1+// Font and styling configuration for chat messages
2+
3+// Retro Windows fonts
4+// Primary font is Pixelated MS Sans Serif from xp.css which works for all users
5+// Secondary fonts use local system fonts with proper fallbacks
6+export const RETRO_FONTS = {
7+ pixelated: { name: 'Pixelated MS Sans Serif', stack: '"Pixelated MS Sans Serif", "Tahoma", Geneva, sans-serif' },
8+ tahoma: { name: 'Tahoma', stack: 'Tahoma, "Pixelated MS Sans Serif", Geneva, sans-serif' },
9+ verdana: { name: 'Verdana', stack: 'Verdana, "Pixelated MS Sans Serif", Geneva, sans-serif' },
10+ comicSans: { name: 'Comic Sans MS', stack: '"Comic Sans MS", "Pixelated MS Sans Serif", cursive, sans-serif' },
11+ timesNewRoman: { name: 'Times New Roman', stack: '"Times New Roman", Times, serif' },
12+ arial: { name: 'Arial', stack: 'Arial, "Pixelated MS Sans Serif", Helvetica, sans-serif' },
13+ courierNew: { name: 'Courier New', stack: '"Courier New", "Perfect DOS VGA 437 Win", Courier, monospace' },
14+ dos: { name: 'Perfect DOS VGA 437', stack: '"Perfect DOS VGA 437 Win", "Courier New", Courier, monospace' }
15+} as const;
16+
17+export type FontFamily = keyof typeof RETRO_FONTS;
18+
19+// Generate 256-color web-safe palette ordered by hue
20+export function generate256Colors(): string[] {
21+ const colors: string[] = [];
22+
23+ // Start with grayscale colors
24+ colors.push('#000000', '#333333', '#666666', '#999999', '#CCCCCC', '#FFFFFF');
25+
26+ // Then add colors in a more logical order by hue
27+ // Red hues
28+ colors.push('#330000', '#660000', '#990000', '#CC0000', '#FF0000');
29+ colors.push('#FF3333', '#FF6666', '#FF9999', '#FFCCCC');
30+
31+ // Orange hues
32+ colors.push('#663300', '#993300', '#CC3300', '#FF3300');
33+ colors.push('#FF6600', '#FF9900', '#FFCC00', '#FFCC33', '#FFCC66', '#FFCC99');
34+
35+ // Yellow hues
36+ colors.push('#666600', '#999900', '#CCCC00', '#FFFF00');
37+ colors.push('#FFFF33', '#FFFF66', '#FFFF99', '#FFFFCC');
38+
39+ // Green hues
40+ colors.push('#003300', '#006600', '#009900', '#00CC00', '#00FF00');
41+ colors.push('#33FF33', '#66FF66', '#99FF99', '#CCFFCC');
42+ colors.push('#336633', '#669966', '#99CC99', '#CCFFCC');
43+
44+ // Cyan hues
45+ colors.push('#006666', '#009999', '#00CCCC', '#00FFFF');
46+ colors.push('#33FFFF', '#66FFFF', '#99FFFF', '#CCFFFF');
47+ colors.push('#336666', '#669999', '#99CCCC');
48+
49+ // Blue hues
50+ colors.push('#000033', '#000066', '#000099', '#0000CC', '#0000FF');
51+ colors.push('#3333FF', '#6666FF', '#9999FF', '#CCCCFF');
52+ colors.push('#003366', '#006699', '#0099CC', '#3399FF', '#66CCFF');
53+
54+ // Purple hues
55+ colors.push('#330033', '#660066', '#990099', '#CC00CC', '#FF00FF');
56+ colors.push('#FF33FF', '#FF66FF', '#FF99FF', '#FFCCFF');
57+ colors.push('#663366', '#996699', '#CC99CC');
58+
59+ // Pink hues
60+ colors.push('#660033', '#990066', '#CC0099', '#FF0099');
61+ colors.push('#FF3399', '#FF66CC', '#FF99CC');
62+
63+ // Browns
64+ colors.push('#663333', '#996633', '#CC9966', '#996666');
65+
66+ // Now fill in any missing combinations to get full 216 web-safe colors
67+ const webSafeValues = ['00', '33', '66', '99', 'CC', 'FF'];
68+ const existingColors = new Set(colors);
69+
70+ for (const r of webSafeValues) {
71+ for (const g of webSafeValues) {
72+ for (const b of webSafeValues) {
73+ const color = `#${r}${g}${b}`.toUpperCase();
74+ if (!existingColors.has(color)) {
75+ colors.push(color);
76+ }
77+ }
78+ }
79+ }
80+
81+ return colors;
82+}
83+
84+// Classic retro colors for backward compatibility
85+export const CLASSIC_COLORS = {
86+ black: '#000000',
87+ darkBlue: '#000080',
88+ green: '#008000',
89+ teal: '#008080',
90+ darkRed: '#800000',
91+ purple: '#800080',
92+ brown: '#808000',
93+ silver: '#C0C0C0',
94+ gray: '#808080',
95+ blue: '#0000FF',
96+ lime: '#00FF00',
97+ aqua: '#00FFFF',
98+ red: '#FF0000',
99+ fuchsia: '#FF00FF',
100+ yellow: '#FFFF00',
101+ white: '#FFFFFF'
102+} as const;
103+
104+export type ClassicColor = keyof typeof CLASSIC_COLORS;
105+
106+// Gradient presets inspired by AOL faders
107+export const GRADIENT_PRESETS = {
108+ rainbow: ['#FF0000', '#FF8000', '#FFFF00', '#80FF00', '#00FF00', '#00FF80', '#00FFFF', '#0080FF', '#0000FF', '#8000FF', '#FF00FF', '#FF0080'],
109+ fire: ['#FF0000', '#FF4000', '#FF8000', '#FFBF00', '#FFFF00'],
110+ ocean: ['#000080', '#0040FF', '#0080FF', '#00BFFF', '#00FFFF'],
111+ sunset: ['#FF4500', '#FF6347', '#FFD700', '#FFFF00'],
112+ neon: ['#FF00FF', '#8000FF', '#0080FF', '#00FFFF'],
113+ forest: ['#006400', '#228B22', '#32CD32', '#90EE90'],
114+ royal: ['#4B0082', '#6A5ACD', '#9370DB', '#DDA0DD']
115+} as const;
116+
117+export type GradientPreset = keyof typeof GRADIENT_PRESETS;
118+
119+// Text styling options
120+export interface TextStyle {
121+ fontFamily: FontFamily;
122+ fontSize: number; // in pixels
123+ color?: string; // hex color string
124+ gradient?: string[]; // array of 1-3 hex colors for gradients
125+ bold: boolean;
126+ italic: boolean;
127+ underline: boolean;
128+ strikethrough: boolean;
129+}
130+
131+// Default text style
132+export const DEFAULT_TEXT_STYLE: TextStyle = {
133+ fontFamily: 'pixelated',
134+ fontSize: 14,
135+ color: '#000000',
136+ bold: false,
137+ italic: false,
138+ underline: false,
139+ strikethrough: false
140+};
141+
142+// User preferences for text formatting
143+export interface UserTextPreferences {
144+ defaultStyle: TextStyle;
145+ allowFormatting: boolean;
146+ maxMessageLength: number;
147+}
148+
149+// Default user preferences
150+export const DEFAULT_USER_PREFERENCES: UserTextPreferences = {
151+ defaultStyle: DEFAULT_TEXT_STYLE,
152+ allowFormatting: true,
153+ maxMessageLength: 500
154+};
155+
156+// Hex color validation
157+export function isValidHexColor(color: string): boolean {
158+ return /^#[0-9A-Fa-f]{6}$/.test(color);
159+}
160+
161+// Formatting validation
162+export function validateTextStyle(style: Partial<TextStyle>): TextStyle {
163+ return {
164+ fontFamily: style.fontFamily && style.fontFamily in RETRO_FONTS ? style.fontFamily : DEFAULT_TEXT_STYLE.fontFamily,
165+ fontSize: Math.max(8, Math.min(18, style.fontSize || DEFAULT_TEXT_STYLE.fontSize)),
166+ color: style.color && isValidHexColor(style.color) ? style.color : DEFAULT_TEXT_STYLE.color,
167+ gradient: style.gradient && Array.isArray(style.gradient) && style.gradient.length <= 3 && style.gradient.every(isValidHexColor) ? style.gradient : undefined,
168+ bold: Boolean(style.bold),
169+ italic: Boolean(style.italic),
170+ underline: Boolean(style.underline),
171+ strikethrough: Boolean(style.strikethrough)
172+ };
173+}
174+
175+// Generate CSS style string from TextStyle
176+export function generateCSSStyle(style: TextStyle): string {
177+ const styles: string[] = [];
178+
179+ // Font family
180+ styles.push(`font-family: ${RETRO_FONTS[style.fontFamily].stack}`);
181+
182+ // Font size
183+ styles.push(`font-size: ${style.fontSize}px`);
184+
185+ // Color or gradient
186+ if (style.gradient && style.gradient.length > 1) {
187+ const gradientStops = style.gradient.join(', ');
188+ styles.push(`background: linear-gradient(45deg, ${gradientStops})`);
189+ styles.push(`-webkit-background-clip: text`);
190+ styles.push(`-webkit-text-fill-color: transparent`);
191+ styles.push(`background-clip: text`);
192+ } else if (style.color) {
193+ styles.push(`color: ${style.color}`);
194+ }
195+
196+ // Font weight
197+ if (style.bold) {
198+ // Use correct weight for Tahoma (200) vs standard bold (700)
199+ if (style.fontFamily === 'tahoma') {
200+ styles.push(`font-weight: 200`);
201+ } else {
202+ styles.push(`font-weight: 700`);
203+ }
204+ }
205+
206+ // Font style
207+ if (style.italic) {
208+ styles.push(`font-style: italic`);
209+ }
210+
211+ // Text decoration
212+ const decorations: string[] = [];
213+ if (style.underline) decorations.push('underline');
214+ if (style.strikethrough) decorations.push('line-through');
215+ if (decorations.length > 0) {
216+ styles.push(`text-decoration: ${decorations.join(' ')}`);
217+ }
218+
219+ return styles.join('; ');
220+}
221+
222+// Generate CSS style string for input fields (without font-family which should be handled by classes)
223+export function generateInputCSSStyle(style: TextStyle): string {
224+ const styles: string[] = [];
225+
226+ // Font size
227+ styles.push(`font-size: ${style.fontSize}px`);
228+
229+ // Color handling for inputs
230+ if (style.gradient && style.gradient.length > 1) {
231+ // Apply gradient background with text clipping for gradient effect
232+ const gradientStops = style.gradient.join(', ');
233+ styles.push(`background: linear-gradient(to right, ${gradientStops})`);
234+ styles.push(`-webkit-background-clip: text`);
235+ styles.push(`-webkit-text-fill-color: transparent`);
236+ styles.push(`background-clip: text`);
237+ styles.push(`letter-spacing: 0`);
238+ styles.push(`word-spacing: 0`);
239+ } else if (style.gradient && style.gradient.length === 1) {
240+ // Single color from gradient array
241+ styles.push(`color: ${style.gradient[0]}`);
242+ } else if (style.color) {
243+ styles.push(`color: ${style.color}`);
244+ } else {
245+ // Fallback to black if no color is set
246+ styles.push(`color: #000000`);
247+ }
248+
249+ // Font weight
250+ if (style.bold) {
251+ // Use correct weight for Tahoma (200) vs standard bold (700)
252+ if (style.fontFamily === 'tahoma') {
253+ styles.push(`font-weight: 200`);
254+ } else {
255+ styles.push(`font-weight: 700`);
256+ }
257+ }
258+
259+ // Font style
260+ if (style.italic) {
261+ styles.push(`font-style: italic`);
262+ }
263+
264+ // Text decoration
265+ const decorations: string[] = [];
266+ if (style.underline) decorations.push('underline');
267+ if (style.strikethrough) decorations.push('line-through');
268+ if (decorations.length > 0) {
269+ styles.push(`text-decoration: ${decorations.join(' ')}`);
270+ }
271+
272+ return styles.join('; ');
273+}⏎̸
A src/lib/utils/security-tests.ts +373 -0
@@ -0,0 +1,373 @@
1+import { formatText, validateMessageContent, createGradientText } from './text-formatter';
2+import { validateTextStyle, DEFAULT_TEXT_STYLE } from '../types/text-formatting';
3+
4+// XSS Test Vectors
5+const XSS_TEST_VECTORS = [
6+ // Script injection
7+ '<script>alert("XSS")</script>',
8+ '<script src="malicious.js"></script>',
9+ '<img src="x" onerror="alert(\'XSS\')">',
10+ '<svg onload="alert(\'XSS\')">',
11+ '<iframe src="javascript:alert(\'XSS\')"></iframe>',
12+
13+ // Event handlers
14+ '<div onclick="alert(\'XSS\')">Click me</div>',
15+ '<input onfocus="alert(\'XSS\')" autofocus>',
16+ '<body onload="alert(\'XSS\')">',
17+ '<a href="javascript:alert(\'XSS\')">Link</a>',
18+
19+ // CSS injection
20+ '<style>body{background:url("javascript:alert(\'XSS\')")}</style>',
21+ '<div style="background-image:url(javascript:alert(\'XSS\'))">',
22+ '<div style="expression(alert(\'XSS\'))">',
23+
24+ // Data URIs
25+ '<img src="data:text/html,<script>alert(\'XSS\')</script>">',
26+ '<iframe src="data:text/html,<script>alert(\'XSS\')</script>">',
27+
28+ // HTML injection
29+ '<object data="malicious.swf">',
30+ '<embed src="malicious.swf">',
31+ '<applet code="malicious.class">',
32+
33+ // BBCode injection attempts
34+ '[script]alert("XSS")[/script]',
35+ '[img=javascript:alert("XSS")]',
36+ '[url=javascript:alert("XSS")]Link[/url]',
37+
38+ // Markdown injection attempts
39+ '![XSS](javascript:alert("XSS"))',
40+ '[XSS](javascript:alert("XSS"))',
41+
42+ // Unicode and encoding bypasses
43+ '<script>alert(&#34;XSS&#34;)</script>',
44+ '<script>alert(String.fromCharCode(88,83,83))</script>',
45+ '<img src="x" onerror="&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;">',
46+
47+ // CSS expression injection
48+ '<div style="width:expression(alert(\'XSS\'))">',
49+ '<div style="background:url(vbscript:alert(\'XSS\'))">',
50+
51+ // Mixed content attacks
52+ 'Normal text <script>alert("XSS")</script> more text',
53+ '[b]Bold <script>alert("XSS")</script> text[/b]',
54+ '**Bold <img src="x" onerror="alert(\'XSS\')"> text**'
55+];
56+
57+// CSS Injection Test Vectors
58+const CSS_INJECTION_VECTORS = [
59+ 'color: red; background: url(javascript:alert("XSS"))',
60+ 'font-family: "Arial"; } body { background: red; .fake {',
61+ 'font-size: expression(alert("XSS"))',
62+ 'background: url("data:text/html,<script>alert(\'XSS\')</script>")',
63+ 'color: red; } .injected { background: red',
64+ '@import url("malicious.css")',
65+ 'behavior: url("malicious.htc")'
66+];
67+
68+// Test Results Interface
69+interface SecurityTestResult {
70+ input: string;
71+ output: string;
72+ passed: boolean;
73+ vulnerabilities: string[];
74+ testType: string;
75+}
76+
77+interface SecurityTestSuite {
78+ xssTests: SecurityTestResult[];
79+ cssInjectionTests: SecurityTestResult[];
80+ validationTests: SecurityTestResult[];
81+ gradientTests: SecurityTestResult[];
82+ summary: {
83+ totalTests: number;
84+ passed: number;
85+ failed: number;
86+ vulnerabilities: string[];
87+ };
88+}
89+
90+// Check if output contains dangerous patterns
91+function detectVulnerabilities(output: string): string[] {
92+ const vulnerabilities: string[] = [];
93+
94+ // Script tags
95+ if (/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi.test(output)) {
96+ vulnerabilities.push('Script tag injection');
97+ }
98+
99+ // Event handlers
100+ if (/on\w+\s*=/gi.test(output)) {
101+ vulnerabilities.push('Event handler injection');
102+ }
103+
104+ // JavaScript URLs
105+ if (/javascript\s*:/gi.test(output)) {
106+ vulnerabilities.push('JavaScript URL injection');
107+ }
108+
109+ // Data URLs with HTML/JS
110+ if (/data\s*:\s*text\/html/gi.test(output)) {
111+ vulnerabilities.push('Data URL HTML injection');
112+ }
113+
114+ // CSS expressions
115+ if (/expression\s*\(/gi.test(output)) {
116+ vulnerabilities.push('CSS expression injection');
117+ }
118+
119+ // Dangerous CSS URLs
120+ if (/url\s*\(\s*['"]*javascript:/gi.test(output)) {
121+ vulnerabilities.push('CSS JavaScript URL injection');
122+ }
123+
124+ // Iframe with dangerous src
125+ if (/<iframe[^>]*src\s*=\s*['"]*(?:javascript:|data:)/gi.test(output)) {
126+ vulnerabilities.push('Dangerous iframe injection');
127+ }
128+
129+ // Object/embed tags
130+ if (/<(?:object|embed|applet)\b/gi.test(output)) {
131+ vulnerabilities.push('Dangerous object/embed tag');
132+ }
133+
134+ // Style tag injection
135+ if (/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi.test(output)) {
136+ vulnerabilities.push('Style tag injection');
137+ }
138+
139+ return vulnerabilities;
140+}
141+
142+// Run XSS tests
143+async function runXSSTests(): Promise<SecurityTestResult[]> {
144+ const results: SecurityTestResult[] = [];
145+
146+ for (const vector of XSS_TEST_VECTORS) {
147+ try {
148+ const output = await formatText(vector, DEFAULT_TEXT_STYLE, true);
149+ const vulnerabilities = detectVulnerabilities(output);
150+
151+ results.push({
152+ input: vector,
153+ output,
154+ passed: vulnerabilities.length === 0,
155+ vulnerabilities,
156+ testType: 'XSS'
157+ });
158+ } catch (error) {
159+ results.push({
160+ input: vector,
161+ output: `Error: ${error}`,
162+ passed: true, // Errors are acceptable for malicious input
163+ vulnerabilities: [],
164+ testType: 'XSS'
165+ });
166+ }
167+ }
168+
169+ return results;
170+}
171+
172+// Run CSS injection tests
173+async function runCSSInjectionTests(): Promise<SecurityTestResult[]> {
174+ const results: SecurityTestResult[] = [];
175+
176+ for (const vector of CSS_INJECTION_VECTORS) {
177+ try {
178+ const testStyle = { ...DEFAULT_TEXT_STYLE, color: 'red' as any };
179+ const output = await formatText(`Test with style`, testStyle, true);
180+ const vulnerabilities = detectVulnerabilities(output);
181+
182+ results.push({
183+ input: vector,
184+ output,
185+ passed: vulnerabilities.length === 0,
186+ vulnerabilities,
187+ testType: 'CSS Injection'
188+ });
189+ } catch (error) {
190+ results.push({
191+ input: vector,
192+ output: `Error: ${error}`,
193+ passed: true,
194+ vulnerabilities: [],
195+ testType: 'CSS Injection'
196+ });
197+ }
198+ }
199+
200+ return results;
201+}
202+
203+// Run validation tests
204+function runValidationTests(): SecurityTestResult[] {
205+ const results: SecurityTestResult[] = [];
206+
207+ const testCases = [
208+ 'Normal text',
209+ 'Text with <script>alert("XSS")</script>',
210+ 'Very long text '.repeat(200), // Test length limits
211+ '', // Empty text
212+ 'Text with\nnewlines\nand\ttabs',
213+ 'Special chars: <>&"\'`',
214+ 'Unicode: 你好世界 🌍 🎉',
215+ 'Mixed: Normal **bold** and <script>alert("XSS")</script>'
216+ ];
217+
218+ for (const testCase of testCases) {
219+ const validation = validateMessageContent(testCase);
220+ const vulnerabilities = detectVulnerabilities(validation.sanitizedContent);
221+
222+ results.push({
223+ input: testCase,
224+ output: validation.sanitizedContent,
225+ passed: validation.isValid && vulnerabilities.length === 0,
226+ vulnerabilities: [...validation.errors, ...vulnerabilities],
227+ testType: 'Validation'
228+ });
229+ }
230+
231+ return results;
232+}
233+
234+// Run gradient text security tests
235+function runGradientTests(): SecurityTestResult[] {
236+ const results: SecurityTestResult[] = [];
237+
238+ const testCases = [
239+ 'Normal gradient text',
240+ '<script>alert("XSS")</script>',
241+ 'Text with "quotes" and \'apostrophes\'',
242+ 'Very long gradient text '.repeat(50),
243+ 'Special chars: <>&\'"',
244+ ''
245+ ];
246+
247+ const testColors = ['#FF0000', '#00FF00', '#0000FF'];
248+
249+ for (const testCase of testCases) {
250+ try {
251+ const output = createGradientText(testCase, testColors);
252+ const vulnerabilities = detectVulnerabilities(output);
253+
254+ results.push({
255+ input: testCase,
256+ output,
257+ passed: vulnerabilities.length === 0,
258+ vulnerabilities,
259+ testType: 'Gradient'
260+ });
261+ } catch (error) {
262+ results.push({
263+ input: testCase,
264+ output: `Error: ${error}`,
265+ passed: true,
266+ vulnerabilities: [],
267+ testType: 'Gradient'
268+ });
269+ }
270+ }
271+
272+ return results;
273+}
274+
275+// Run complete security test suite
276+export async function runSecurityTestSuite(): Promise<SecurityTestSuite> {
277+ console.log('🔒 Running comprehensive security test suite...');
278+
279+ const xssTests = await runXSSTests();
280+ const cssInjectionTests = await runCSSInjectionTests();
281+ const validationTests = runValidationTests();
282+ const gradientTests = runGradientTests();
283+
284+ const allTests = [...xssTests, ...cssInjectionTests, ...validationTests, ...gradientTests];
285+ const passed = allTests.filter(test => test.passed).length;
286+ const failed = allTests.length - passed;
287+
288+ // Collect all unique vulnerabilities
289+ const allVulnerabilities = new Set<string>();
290+ allTests.forEach(test => {
291+ test.vulnerabilities.forEach(vuln => allVulnerabilities.add(vuln));
292+ });
293+
294+ const results: SecurityTestSuite = {
295+ xssTests,
296+ cssInjectionTests,
297+ validationTests,
298+ gradientTests,
299+ summary: {
300+ totalTests: allTests.length,
301+ passed,
302+ failed,
303+ vulnerabilities: Array.from(allVulnerabilities)
304+ }
305+ };
306+
307+ console.log(`✅ Security tests completed:`);
308+ console.log(` Total tests: ${results.summary.totalTests}`);
309+ console.log(` Passed: ${results.summary.passed}`);
310+ console.log(` Failed: ${results.summary.failed}`);
311+
312+ if (results.summary.vulnerabilities.length > 0) {
313+ console.warn(`⚠️ Vulnerabilities detected:`, results.summary.vulnerabilities);
314+ } else {
315+ console.log(`🛡️ No vulnerabilities detected!`);
316+ }
317+
318+ return results;
319+}
320+
321+// Quick security check function
322+export async function quickSecurityCheck(input: string): Promise<boolean> {
323+ try {
324+ const output = await formatText(input, DEFAULT_TEXT_STYLE, true);
325+ const vulnerabilities = detectVulnerabilities(output);
326+ return vulnerabilities.length === 0;
327+ } catch (error) {
328+ // Errors on malicious input are acceptable
329+ return true;
330+ }
331+}
332+
333+// Style validation tests
334+export function testStyleValidation(): boolean {
335+ const testCases = [
336+ // Valid styles
337+ { fontFamily: 'tahoma', fontSize: 14, color: 'red', bold: true },
338+ { fontFamily: 'verdana', fontSize: 16, color: 'blue', italic: true },
339+
340+ // Invalid styles (should be sanitized)
341+ { fontFamily: 'malicious-font', fontSize: 999, color: 'invalid-color' },
342+ { fontFamily: 'tahoma', fontSize: -10, color: 'red' },
343+ { fontFamily: 'tahoma', fontSize: 'invalid' as any, color: 'red' }
344+ ];
345+
346+ for (const testCase of testCases) {
347+ try {
348+ const validated = validateTextStyle(testCase as Partial<TextStyle>);
349+
350+ // Check that validated style has safe values
351+ if (!validated.fontFamily ||
352+ validated.fontSize < 8 ||
353+ validated.fontSize > 72) {
354+ console.error('Style validation failed for:', testCase);
355+ return false;
356+ }
357+ } catch (error) {
358+ console.error('Style validation error:', error);
359+ return false;
360+ }
361+ }
362+
363+ return true;
364+}
365+
366+// Export test utilities
367+export {
368+ XSS_TEST_VECTORS,
369+ CSS_INJECTION_VECTORS,
370+ detectVulnerabilities,
371+ type SecurityTestResult,
372+ type SecurityTestSuite
373+};⏎̸
A src/lib/utils/text-formatter.ts +354 -0
@@ -0,0 +1,354 @@
1+import { unified } from 'unified';
2+import remarkParse from 'remark-parse';
3+import remarkRehype from 'remark-rehype';
4+import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
5+import rehypeStringify from 'rehype-stringify';
6+import type { TextStyle } from '../types/text-formatting';
7+import { generateCSSStyle, validateTextStyle } from '../types/text-formatting';
8+
9+// Define allowed HTML tags and attributes for security
10+const ALLOWED_SCHEMA = {
11+ ...defaultSchema,
12+ tagNames: [
13+ ...(defaultSchema.tagNames || []),
14+ 'span',
15+ 'strong',
16+ 'em',
17+ 'u',
18+ 's',
19+ 'mark'
20+ ],
21+ attributes: {
22+ ...defaultSchema.attributes,
23+ span: ['style', 'class', 'data-gradient'],
24+ strong: ['style', 'class'],
25+ em: ['style', 'class'],
26+ u: ['style', 'class'],
27+ s: ['style', 'class'],
28+ mark: ['style', 'class']
29+ },
30+ protocols: {
31+ ...defaultSchema.protocols,
32+ style: []
33+ }
34+};
35+
36+// Custom rehype plugin to apply text styles
37+function rehypeApplyStyles(userStyle: TextStyle) {
38+ return function(tree: any) {
39+ // We don't need to apply styles here anymore
40+ // The formatted-message component handles all styling
41+ return tree;
42+ };
43+}
44+
45+// BBCode-style formatting patterns
46+const BB_CODE_PATTERNS: Array<{
47+ pattern: RegExp;
48+ replacement: string;
49+}> = [
50+ // Bold
51+ { pattern: /\[b\](.*?)\[\/b\]/gi, replacement: '<strong>$1</strong>' },
52+
53+ // Italic
54+ { pattern: /\[i\](.*?)\[\/i\]/gi, replacement: '<em>$1</em>' },
55+
56+ // Underline
57+ { pattern: /\[u\](.*?)\[\/u\]/gi, replacement: '<u>$1</u>' },
58+
59+ // Strikethrough
60+ { pattern: /\[s\](.*?)\[\/s\]/gi, replacement: '<s>$1</s>' },
61+
62+ // Color
63+ { pattern: /\[color=([#\w]+)\](.*?)\[\/color\]/gi, replacement: '<span style="color: $1">$2</span>' },
64+
65+ // Size
66+ { pattern: /\[size=(\d+)\](.*?)\[\/size\]/gi, replacement: '<span style="font-size: $1px">$2</span>' },
67+
68+ // Font
69+ { pattern: /\[font=([^[\]]+)\](.*?)\[\/font\]/gi, replacement: '<span style="font-family: $1">$2</span>' }
70+];
71+
72+// Markdown-style formatting patterns
73+const MARKDOWN_PATTERNS: Array<{
74+ pattern: RegExp;
75+ replacement: string;
76+}> = [
77+ // Bold (double asterisk or double underscore)
78+ { pattern: /\*\*(.*?)\*\*/g, replacement: '<strong>$1</strong>' },
79+ { pattern: /__(.*?)__/g, replacement: '<strong>$1</strong>' },
80+
81+ // Italic (single asterisk or single underscore)
82+ { pattern: /\*(.*?)\*/g, replacement: '<em>$1</em>' },
83+ { pattern: /_(.*?)_/g, replacement: '<em>$1</em>' },
84+
85+ // Strikethrough
86+ { pattern: /~~(.*?)~~/g, replacement: '<s>$1</s>' },
87+
88+ // Inline code
89+ { pattern: /`([^`]+)`/g, replacement: '<code>$1</code>' }
90+];
91+
92+// Preprocess text to convert BBCode and Markdown to HTML
93+function preprocessFormatting(text: string): string {
94+ let processedText = text;
95+
96+ // Apply BBCode patterns first
97+ BB_CODE_PATTERNS.forEach(({ pattern, replacement }) => {
98+ processedText = processedText.replace(pattern, replacement);
99+ });
100+
101+ // Apply Markdown patterns (but avoid conflicts with already processed BBCode)
102+ MARKDOWN_PATTERNS.forEach(({ pattern, replacement }) => {
103+ // Only apply if not already inside HTML tags
104+ processedText = processedText.replace(pattern, (match, content) => {
105+ // Simple check to avoid replacing inside existing HTML tags
106+ const beforeMatch = processedText.substring(0, processedText.indexOf(match));
107+ const openTags = (beforeMatch.match(/<[^/][^>]*>/g) || []).length;
108+ const closeTags = (beforeMatch.match(/<\/[^>]*>/g) || []).length;
109+
110+ // If we're inside an unclosed tag, don't apply markdown
111+ if (openTags > closeTags) {
112+ return match;
113+ }
114+
115+ return replacement.replace('$1', content);
116+ });
117+ });
118+
119+ return processedText;
120+}
121+
122+// Main text formatting function
123+export async function formatText(
124+ text: string,
125+ userStyle?: Partial<TextStyle>,
126+ allowRichFormatting: boolean = true
127+): Promise<string> {
128+ try {
129+ // If text is empty, return empty string
130+ if (!text) return '';
131+
132+ // Validate and apply user style
133+ const validatedStyle = validateTextStyle(userStyle || {});
134+
135+ // Preprocess the text for formatting if allowed
136+ let processedText = text;
137+ if (allowRichFormatting) {
138+ processedText = preprocessFormatting(text);
139+ }
140+
141+ // If no rich formatting, just return escaped text
142+ if (!allowRichFormatting && !processedText.includes('<')) {
143+ return escapeHtml(text);
144+ }
145+
146+ // Create the unified processor
147+ const processor = unified()
148+ .use(remarkParse, {
149+ fragment: true // Parse as fragment, not full document
150+ })
151+ .use(remarkRehype, {
152+ allowDangerousHtml: true // Allow preprocessed HTML to pass through
153+ })
154+ .use(rehypeSanitize, ALLOWED_SCHEMA) // Sanitize HTML
155+ .use(rehypeStringify);
156+
157+ // Process the text
158+ const result = await processor.process(processedText);
159+ let formattedHtml = String(result).trim();
160+
161+ // If we got an empty result, return the escaped text
162+ if (!formattedHtml || formattedHtml === '<p></p>' || formattedHtml === '') {
163+ return escapeHtml(text);
164+ }
165+
166+ // Remove wrapping <p> tags if it's just a single paragraph
167+ if (formattedHtml.startsWith('<p>') && formattedHtml.endsWith('</p>')) {
168+ const pCount = (formattedHtml.match(/<p>/g) || []).length;
169+ if (pCount === 1) {
170+ formattedHtml = formattedHtml.slice(3, -4).trim();
171+ }
172+ }
173+
174+ // Final check - if we ended up with empty content, return escaped text
175+ if (!formattedHtml) {
176+ return escapeHtml(text);
177+ }
178+
179+ return formattedHtml;
180+
181+ } catch (error) {
182+ console.error('Text formatting error:', error);
183+ // Return escaped plain text as fallback
184+ return escapeHtml(text);
185+ }
186+}
187+
188+// Utility function to escape HTML
189+function escapeHtml(text: string): string {
190+ const div = document.createElement('div');
191+ div.textContent = text;
192+ return div.innerHTML;
193+}
194+
195+// Generate CSS style string excluding font-family (which should be handled by classes)
196+function generateCSSStyleWithoutFont(style: TextStyle): string {
197+ const styles: string[] = [];
198+
199+ // Font size
200+ styles.push(`font-size: ${style.fontSize}px`);
201+
202+ // Color (not for gradients)
203+ if (style.color && !style.gradient) {
204+ styles.push(`color: ${style.color}`);
205+ }
206+
207+ // Font weight
208+ if (style.bold) {
209+ styles.push(`font-weight: bold`);
210+ }
211+
212+ // Font style
213+ if (style.italic) {
214+ styles.push(`font-style: italic`);
215+ }
216+
217+ // Text decoration
218+ const decorations: string[] = [];
219+ if (style.underline) decorations.push('underline');
220+ if (style.strikethrough) decorations.push('line-through');
221+ if (decorations.length > 0) {
222+ styles.push(`text-decoration: ${decorations.join(' ')}`);
223+ }
224+
225+ return styles.join('; ');
226+}
227+
228+// Create gradient text effect
229+export function createGradientText(
230+ text: string,
231+ colors: string[],
232+ className: string = 'gradient-text',
233+ style?: TextStyle
234+): string {
235+ console.debug('createGradientText called with:', { text, colors, className, style });
236+
237+ if (colors.length < 2) {
238+ const fontClass = style?.fontFamily ? ` retro-font-${style.fontFamily}` : '';
239+ const inlineStyle = style ? generateCSSStyleWithoutFont({...style, gradient: undefined}) : '';
240+ const result = `<span class="${className}${fontClass}" style="${inlineStyle}">${escapeHtml(text)}</span>`;
241+ console.debug('Single color result:', result);
242+ return result;
243+ }
244+
245+ const chars = Array.from(text);
246+ const totalChars = chars.length;
247+
248+ if (totalChars === 0) return '';
249+
250+ // Create spans for each character with interpolated colors
251+ const gradientSpans = chars.map((char, index) => {
252+ if (char === ' ') {
253+ return '&nbsp;'; // Use non-breaking space to preserve spacing
254+ }
255+
256+ // Calculate color position (0 to 1)
257+ const position = totalChars === 1 ? 0 : index / (totalChars - 1);
258+
259+ // Find the two colors to interpolate between
260+ const colorIndex = position * (colors.length - 1);
261+ const lowerIndex = Math.floor(colorIndex);
262+ const upperIndex = Math.min(lowerIndex + 1, colors.length - 1);
263+ const t = colorIndex - lowerIndex;
264+
265+ // Interpolate between colors
266+ const color1 = hexToRgb(colors[lowerIndex]);
267+ const color2 = hexToRgb(colors[upperIndex]);
268+
269+ if (!color1 || !color2) {
270+ const fallbackStyle = style ? generateCSSStyleWithoutFont({...style, gradient: undefined}) : '';
271+ return `<span class="${className}" style="${fallbackStyle}">${escapeHtml(char)}</span>`;
272+ }
273+
274+ const r = Math.round(color1.r + t * (color2.r - color1.r));
275+ const g = Math.round(color1.g + t * (color2.g - color1.g));
276+ const b = Math.round(color1.b + t * (color2.b - color1.b));
277+
278+ const interpolatedColor = `rgb(${r}, ${g}, ${b})`;
279+
280+ // Combine interpolated color with other styles
281+ let inlineStyle = `color: ${interpolatedColor}`;
282+ if (style) {
283+ // Get styles without font-family and color
284+ if (style.fontSize !== 14) inlineStyle += `; font-size: ${style.fontSize}px`;
285+ if (style.bold) inlineStyle += `; font-weight: bold`;
286+ if (style.italic) inlineStyle += `; font-style: italic`;
287+ const decorations: string[] = [];
288+ if (style.underline) decorations.push('underline');
289+ if (style.strikethrough) decorations.push('line-through');
290+ if (decorations.length > 0) {
291+ inlineStyle += `; text-decoration: ${decorations.join(' ')}`;
292+ }
293+ }
294+
295+ return `<span class="gradient-char" style="${inlineStyle}">${escapeHtml(char)}</span>`;
296+ });
297+
298+ // Wrap all spans in a container that uses flexbox to eliminate spacing
299+ const fontClass = style?.fontFamily ? ` retro-font-${style.fontFamily}` : '';
300+ const containerStyle = style ? generateCSSStyleWithoutFont({...style, gradient: undefined, color: undefined}) : '';
301+ const result = `<span class="${className}${fontClass}" style="display: inline-flex; flex-wrap: wrap; ${containerStyle}">${gradientSpans.join('')}</span>`;
302+ console.debug('Final gradient HTML:', result);
303+ return result;
304+}
305+
306+// Helper function to convert hex to RGB
307+function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
308+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
309+ return result ? {
310+ r: parseInt(result[1], 16),
311+ g: parseInt(result[2], 16),
312+ b: parseInt(result[3], 16)
313+ } : null;
314+}
315+
316+// Validate message content for security
317+export function validateMessageContent(content: string): {
318+ isValid: boolean;
319+ sanitizedContent: string;
320+ errors: string[];
321+} {
322+ const errors: string[] = [];
323+ let sanitizedContent = content;
324+
325+ // Check length
326+ if (content.length > 2000) {
327+ errors.push('Message too long (max 2000 characters)');
328+ sanitizedContent = content.substring(0, 2000);
329+ }
330+
331+ // Check for potential XSS patterns
332+ const dangerousPatterns = [
333+ /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
334+ /javascript:/gi,
335+ /vbscript:/gi,
336+ /onload\s*=/gi,
337+ /onerror\s*=/gi,
338+ /onclick\s*=/gi,
339+ /onmouseover\s*=/gi
340+ ];
341+
342+ dangerousPatterns.forEach(pattern => {
343+ if (pattern.test(content)) {
344+ errors.push('Potentially dangerous content detected');
345+ sanitizedContent = sanitizedContent.replace(pattern, '');
346+ }
347+ });
348+
349+ return {
350+ isValid: errors.length === 0,
351+ sanitizedContent,
352+ errors
353+ };
354+}⏎̸
A src/lib/validation/password.ts +199 -0
@@ -0,0 +1,199 @@
1+import { z } from 'zod';
2+
3+// Dynamic password constraints configuration
4+export interface PasswordConstraints {
5+ minLength: number;
6+ maxLength: number;
7+ requireUppercase: boolean;
8+ requireLowercase: boolean;
9+ requireNumbers: boolean;
10+ requireSpecialChars: boolean;
11+ forbiddenPatterns: string[];
12+}
13+
14+// Default password constraints
15+export const DEFAULT_PASSWORD_CONSTRAINTS: PasswordConstraints = {
16+ minLength: 8,
17+ maxLength: 64,
18+ requireUppercase: true,
19+ requireLowercase: true,
20+ requireNumbers: true,
21+ requireSpecialChars: false,
22+ forbiddenPatterns: ['password', '123456', 'qwerty', 'admin']
23+};
24+
25+// Validation error messages
26+export const PASSWORD_ERROR_MESSAGES = {
27+ minLength: (min: number) => `Password must be at least ${min} characters long`,
28+ maxLength: (max: number) => `Password must be at most ${max} characters long`,
29+ requireUppercase: 'Password must contain at least one uppercase letter',
30+ requireLowercase: 'Password must contain at least one lowercase letter',
31+ requireNumbers: 'Password must contain at least one number',
32+ requireSpecialChars: 'Password must contain at least one special character (!@#$%^&*)',
33+ forbiddenPattern: (pattern: string) => `Password cannot contain '${pattern}'`,
34+ common: 'Password is too common or weak'
35+};
36+
37+// Create dynamic password schema based on constraints
38+export function createPasswordSchema(constraints: PasswordConstraints = DEFAULT_PASSWORD_CONSTRAINTS) {
39+ let schema = z.string()
40+ .min(constraints.minLength, PASSWORD_ERROR_MESSAGES.minLength(constraints.minLength))
41+ .max(constraints.maxLength, PASSWORD_ERROR_MESSAGES.maxLength(constraints.maxLength));
42+
43+ // Add character type requirements
44+ if (constraints.requireUppercase) {
45+ schema = schema.regex(/[A-Z]/, PASSWORD_ERROR_MESSAGES.requireUppercase);
46+ }
47+
48+ if (constraints.requireLowercase) {
49+ schema = schema.regex(/[a-z]/, PASSWORD_ERROR_MESSAGES.requireLowercase);
50+ }
51+
52+ if (constraints.requireNumbers) {
53+ schema = schema.regex(/\d/, PASSWORD_ERROR_MESSAGES.requireNumbers);
54+ }
55+
56+ if (constraints.requireSpecialChars) {
57+ schema = schema.regex(/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/, PASSWORD_ERROR_MESSAGES.requireSpecialChars);
58+ }
59+
60+ // Add forbidden patterns check
61+ if (constraints.forbiddenPatterns.length > 0) {
62+ return schema.refine(
63+ (password) => {
64+ const lowerPassword = password.toLowerCase();
65+ return !constraints.forbiddenPatterns.some(pattern =>
66+ lowerPassword.includes(pattern.toLowerCase())
67+ );
68+ },
69+ {
70+ message: PASSWORD_ERROR_MESSAGES.common
71+ }
72+ );
73+ }
74+
75+ return schema;
76+}
77+
78+// Login validation schema
79+export const loginSchema = z.object({
80+ username: z.string()
81+ .min(3, 'Username must be at least 3 characters')
82+ .max(32, 'Username must be at most 32 characters')
83+ .regex(/^[a-zA-Z0-9_-]+$/, 'Username can only contain letters, numbers, underscores, and dashes'),
84+ password: z.string().min(1, 'Password is required')
85+});
86+
87+// Registration validation schema (using dynamic password validation)
88+export function createRegistrationSchema(constraints: PasswordConstraints = DEFAULT_PASSWORD_CONSTRAINTS) {
89+ return z.object({
90+ suUsername: z.string()
91+ .min(3, 'Username must be at least 3 characters')
92+ .max(32, 'Username must be at most 32 characters')
93+ .regex(/^[a-zA-Z0-9_-]+$/, 'Username can only contain letters, numbers, underscores, and dashes'),
94+ suPassword: createPasswordSchema(constraints),
95+ suConfirmPassword: z.string(),
96+ captchaAnswer: z.string().min(1, 'Please answer the PDR question'),
97+ turnstileToken: z.string().optional()
98+ }).refine(
99+ (data) => data.suPassword === data.suConfirmPassword,
100+ {
101+ message: 'Passwords do not match',
102+ path: ['suConfirmPassword']
103+ }
104+ );
105+}
106+
107+// Utility function to validate password strength and return detailed feedback
108+export function validatePasswordStrength(password: string, constraints: PasswordConstraints = DEFAULT_PASSWORD_CONSTRAINTS) {
109+ const errors: string[] = [];
110+ const requirements: { met: boolean; message: string }[] = [];
111+
112+ // Length checks
113+ if (password.length < constraints.minLength) {
114+ errors.push(PASSWORD_ERROR_MESSAGES.minLength(constraints.minLength));
115+ }
116+ requirements.push({
117+ met: password.length >= constraints.minLength,
118+ message: `At least ${constraints.minLength} characters`
119+ });
120+
121+ if (password.length > constraints.maxLength) {
122+ errors.push(PASSWORD_ERROR_MESSAGES.maxLength(constraints.maxLength));
123+ }
124+
125+ // Character type checks
126+ if (constraints.requireUppercase) {
127+ const hasUppercase = /[A-Z]/.test(password);
128+ if (!hasUppercase) errors.push(PASSWORD_ERROR_MESSAGES.requireUppercase);
129+ requirements.push({
130+ met: hasUppercase,
131+ message: 'At least one uppercase letter'
132+ });
133+ }
134+
135+ if (constraints.requireLowercase) {
136+ const hasLowercase = /[a-z]/.test(password);
137+ if (!hasLowercase) errors.push(PASSWORD_ERROR_MESSAGES.requireLowercase);
138+ requirements.push({
139+ met: hasLowercase,
140+ message: 'At least one lowercase letter'
141+ });
142+ }
143+
144+ if (constraints.requireNumbers) {
145+ const hasNumbers = /\d/.test(password);
146+ if (!hasNumbers) errors.push(PASSWORD_ERROR_MESSAGES.requireNumbers);
147+ requirements.push({
148+ met: hasNumbers,
149+ message: 'At least one number'
150+ });
151+ }
152+
153+ if (constraints.requireSpecialChars) {
154+ const hasSpecialChars = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password);
155+ if (!hasSpecialChars) errors.push(PASSWORD_ERROR_MESSAGES.requireSpecialChars);
156+ requirements.push({
157+ met: hasSpecialChars,
158+ message: 'At least one special character'
159+ });
160+ }
161+
162+ // Forbidden patterns check
163+ if (constraints.forbiddenPatterns.length > 0) {
164+ const lowerPassword = password.toLowerCase();
165+ const hasForbiddenPattern = constraints.forbiddenPatterns.some(pattern =>
166+ lowerPassword.includes(pattern.toLowerCase())
167+ );
168+ if (hasForbiddenPattern) {
169+ errors.push(PASSWORD_ERROR_MESSAGES.common);
170+ }
171+ requirements.push({
172+ met: !hasForbiddenPattern,
173+ message: 'Not a common or weak password'
174+ });
175+ }
176+
177+ return {
178+ isValid: errors.length === 0,
179+ errors,
180+ requirements,
181+ strength: calculatePasswordStrength(password, requirements)
182+ };
183+}
184+
185+// Calculate password strength score (0-100)
186+function calculatePasswordStrength(password: string, requirements: { met: boolean; message: string }[]): number {
187+ const metRequirements = requirements.filter(req => req.met).length;
188+ const totalRequirements = requirements.length;
189+
190+ if (totalRequirements === 0) return 0;
191+
192+ let baseScore = (metRequirements / totalRequirements) * 80;
193+
194+ // Bonus points for length beyond minimum
195+ if (password.length > 12) baseScore += 10;
196+ if (password.length > 16) baseScore += 10;
197+
198+ return Math.min(100, Math.round(baseScore));
199+}⏎̸
A src/lib/validation/text-formatting.ts +81 -0
@@ -0,0 +1,81 @@
1+import type { TextStyle } from '$lib/types/text-formatting';
2+import { RETRO_FONTS } from '$lib/types/text-formatting';
3+
4+const MIN_FONT_SIZE = 8;
5+const MAX_FONT_SIZE = 18;
6+const MAX_GRADIENT_COLORS = 3;
7+const HEX_COLOR_REGEX = /^#[0-9A-Fa-f]{6}$/;
8+
9+export function validateHexColor(color: string): boolean {
10+ return HEX_COLOR_REGEX.test(color);
11+}
12+
13+export function validateFontFamily(fontFamily: string): boolean {
14+ return fontFamily in RETRO_FONTS;
15+}
16+
17+export function validateFontSize(size: number): number {
18+ return Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, size));
19+}
20+
21+export function validateGradient(gradient: unknown): string[] | undefined {
22+ if (!Array.isArray(gradient)) return undefined;
23+ if (gradient.length === 0 || gradient.length > MAX_GRADIENT_COLORS) return undefined;
24+
25+ const validColors = gradient.filter(color =>
26+ typeof color === 'string' && validateHexColor(color)
27+ );
28+
29+ return validColors.length === gradient.length ? validColors : undefined;
30+}
31+
32+export function validateTextStyle(style: unknown): TextStyle | null {
33+ if (!style || typeof style !== 'object') return null;
34+
35+ const rawStyle = style as Record<string, unknown>;
36+
37+ const validated: TextStyle = {
38+ fontFamily: 'pixelated',
39+ fontSize: 14,
40+ bold: false,
41+ italic: false,
42+ underline: false,
43+ strikethrough: false
44+ };
45+
46+ // Validate font family
47+ if (typeof rawStyle.fontFamily === 'string' && validateFontFamily(rawStyle.fontFamily)) {
48+ validated.fontFamily = rawStyle.fontFamily as keyof typeof RETRO_FONTS;
49+ }
50+
51+ // Validate font size
52+ if (typeof rawStyle.fontSize === 'number') {
53+ validated.fontSize = validateFontSize(rawStyle.fontSize);
54+ }
55+
56+ // Validate color
57+ if (typeof rawStyle.color === 'string' && validateHexColor(rawStyle.color)) {
58+ validated.color = rawStyle.color;
59+ }
60+
61+ // Validate gradient
62+ const validatedGradient = validateGradient(rawStyle.gradient);
63+ if (validatedGradient) {
64+ validated.gradient = validatedGradient;
65+ }
66+
67+ // Validate boolean properties
68+ validated.bold = Boolean(rawStyle.bold);
69+ validated.italic = Boolean(rawStyle.italic);
70+ validated.underline = Boolean(rawStyle.underline);
71+ validated.strikethrough = Boolean(rawStyle.strikethrough);
72+
73+ return validated;
74+}
75+
76+export function sanitizeStyleData(styleData: unknown): TextStyle | undefined {
77+ if (!styleData) return undefined;
78+
79+ const validated = validateTextStyle(styleData);
80+ return validated || undefined;
81+}⏎̸
A src/routes/+page.server.ts +63 -0
@@ -0,0 +1,63 @@
1+import type { PageServerLoad } from './$types';
2+import { validateSessionToken } from '$lib/api/session.server';
3+import db from '$lib/db/db.server';
4+import { userTextPreferences, users, messages } from '$lib/db/schema';
5+import { eq, desc } from 'drizzle-orm';
6+import { DEFAULT_TEXT_STYLE, type TextStyle } from '$lib/types/text-formatting';
7+
8+export const load: PageServerLoad = async ({ cookies }) => {
9+ const token = cookies.get('session');
10+
11+ if (!token) {
12+ return {
13+ user: null,
14+ lastTextStyle: DEFAULT_TEXT_STYLE
15+ };
16+ }
17+
18+ try {
19+ const { user } = await validateSessionToken(token);
20+
21+ if (!user) {
22+ return {
23+ user: null,
24+ lastTextStyle: DEFAULT_TEXT_STYLE
25+ };
26+ }
27+
28+ // Get user's last used text styling from their most recent message
29+ const lastMessage = await db.query.messages.findFirst({
30+ where: eq(messages.senderId, user.id),
31+ orderBy: [desc(messages.timestamp)],
32+ columns: {
33+ styleData: true
34+ }
35+ });
36+
37+ let lastTextStyle: TextStyle = DEFAULT_TEXT_STYLE;
38+
39+ if (lastMessage?.styleData) {
40+ try {
41+ const parsedStyle = JSON.parse(lastMessage.styleData);
42+ // Merge with default style to ensure all required properties
43+ lastTextStyle = {
44+ ...DEFAULT_TEXT_STYLE,
45+ ...parsedStyle
46+ };
47+ } catch (error) {
48+ console.warn('Failed to parse last text style:', error);
49+ }
50+ }
51+
52+ return {
53+ user,
54+ lastTextStyle
55+ };
56+ } catch (error) {
57+ console.error('Error loading page data:', error);
58+ return {
59+ user: null,
60+ lastTextStyle: DEFAULT_TEXT_STYLE
61+ };
62+ }
63+};⏎̸
M src/routes/+page.svelte +4 -1
@@ -2,7 +2,10 @@
22 import ChatRoom from '$lib/components/chat-room.svelte';
33 import DesktopIcons from '$lib/components/desktop-icons.svelte';
44 import AimLogin from '$lib/components/aim-login.svelte';
5+ import type { PageData } from './$types';
56
7+ let { data }: { data: PageData } = $props();
8+
69 let showChatRoom = $state(true);
710 let showAuth = $state(false);
811
@@ -15,7 +18,7 @@
1518 <DesktopIcons bind:showChatRoom bind:showAuth />
1619
1720 {#if showChatRoom}
18- <ChatRoom bind:showChatRoom />
21+ <ChatRoom bind:showChatRoom initialTextStyle={data.lastTextStyle} />
1922 {/if}
2023
2124 {#if showAuth}
M src/routes/api/chat/messages/+server.ts +12 -2
@@ -15,6 +15,7 @@ import { chatRooms } from '$lib/db/schema';
1515 import { users } from '$lib/db/schema';
1616 import { DEFAULT_CHAT_ROOM_ID } from '$lib/utils/chat.server';
1717 import { createLogger } from '$lib/utils/logger.server';
18+import { sanitizeStyleData } from '$lib/validation/text-formatting';
1819
1920 const log = createLogger('chat-server');
2021
@@ -83,7 +84,12 @@ export async function GET({ request, locals }) {
8384 .from(messages)
8485 .where(conditions)
8586 .orderBy(desc(messages.timestamp))
86- .limit(fetchLimit);
87+ .limit(fetchLimit)
88+ .then(rows => rows.map(row => ({
89+ ...row,
90+ styleData: row.styleData ?? undefined,
91+ hasFormatting: row.hasFormatting ?? false
92+ })));
8793
8894 const response: GetMessagesResponse = {
8995 success: true,
@@ -182,13 +188,17 @@ export async function POST({ request, locals }: { request: Request, locals: App.
182188 return new Response(JSON.stringify(errorResponse), { status: 404 });
183189 }
184190
191+ const validatedStyleData = sanitizeStyleData(data.styleData);
192+
185193 const newMessage: Message = {
186194 id: uuidv4(),
187195 chatRoomId,
188196 senderId: data.userId,
189197 content: data.content,
190198 type: data.type || 'chat',
191- timestamp: Date.now()
199+ timestamp: Date.now(),
200+ styleData: validatedStyleData,
201+ hasFormatting: Boolean(validatedStyleData)
192202 };
193203
194204 // Save to DB
M src/routes/api/register/+server.ts +15 -57
@@ -3,7 +3,7 @@ import type { RegisterResponseSuccess, RegisterResponseError } from '$lib/types/
33 import db from '$lib/db/db.server';
44 import { users } from '$lib/db/schema';
55 import { hashPassword } from '$lib/utils/password';
6-import { validateTurnstileToken } from '$lib/utils/turnstile.server';
6+import { createRegistrationSchema, DEFAULT_PASSWORD_CONSTRAINTS } from '$lib/validation/password';
77 import { createLogger } from '$lib/utils/logger.server';
88 import { eq } from 'drizzle-orm/sql';
99
@@ -54,24 +54,22 @@ export const POST: RequestHandler = async ({ request }) => {
5454 turnstileToken?: string
5555 };
5656
57- if (!suUsername || !suPassword || !suConfirmPassword || !captchaAnswer || (!isDev && !turnstileToken)) {
58- log.warn('Missing required fields', {
59- hasUsername: Boolean(suUsername),
60- hasPassword: Boolean(suPassword),
61- hasConfirmPassword: Boolean(suConfirmPassword),
62- hasCaptcha: Boolean(captchaAnswer),
63- hasTurnstileToken: Boolean(turnstileToken),
64- isDev
57+ // Validate input using Zod schema
58+ try {
59+ const registrationSchema = createRegistrationSchema(DEFAULT_PASSWORD_CONSTRAINTS);
60+ registrationSchema.parse({
61+ suUsername,
62+ suPassword,
63+ suConfirmPassword,
64+ captchaAnswer,
65+ turnstileToken
6566 });
66- return new Response(JSON.stringify({ error: 'All fields are required' } as RegisterResponseError), { status: 400 });
67+ } catch (err: any) {
68+ const errorMessage = err.errors?.[0]?.message || 'Invalid input data';
69+ log.warn('Registration validation failed', { error: errorMessage });
70+ return new Response(JSON.stringify({ error: errorMessage } as RegisterResponseError), { status: 400 });
6771 }
6872
69- // Validate Turnstile token (will be automatically bypassed in dev mode)
70- const isValidTurnstile = await validateTurnstileToken(turnstileToken || '', ip);
71- if (!isValidTurnstile) {
72- log.warn('Invalid Turnstile token', { maskedIp });
73- return new Response(JSON.stringify({ error: 'Security check failed. Please try again.' } as RegisterResponseError), { status: 400 });
74- }
7573
7674 // Validate PDR captcha
7775 const normalizedAnswer = captchaAnswer.trim().toLowerCase();
@@ -86,49 +84,9 @@ export const POST: RequestHandler = async ({ request }) => {
8684 // Reset captcha attempts on success
8785 captchaAttempts.delete(ip);
8886
89- // Destructure and validate required fields from the payload.
90- if (typeof suUsername !== 'string' || typeof suPassword !== 'string' ||
91- typeof suConfirmPassword !== 'string') {
92- log.warn('Missing or invalid input fields');
93- return new Response(JSON.stringify({ error: 'Missing or invalid input fields' } as RegisterResponseError), { status: 400 });
94- }
95-
96- // Trim input values.
87+ // Trim input values (validation already done by Zod)
9788 const username = suUsername.trim();
9889 const password = suPassword.trim();
99- const confirmPassword = suConfirmPassword.trim();
100-
101- // Basic validations.
102- if (!username || !password || !confirmPassword) {
103- log.warn('All fields must be filled');
104- return new Response(JSON.stringify({ error: 'All fields must be filled' } as RegisterResponseError), { status: 400 });
105- }
106-
107- if (username.length < 3) {
108- log.warn('Username must be at least 3 characters');
109- return new Response(JSON.stringify({ error: 'Username must be at least 3 characters' } as RegisterResponseError), { status: 400 });
110- }
111-
112- if (username.length > 32) {
113- log.warn('Username must be at most 32 characters');
114- return new Response(JSON.stringify({ error: 'Username must be at most 32 characters' } as RegisterResponseError), { status: 400 });
115- }
116- // Only allow letters, numbers, underscores, and dashes in the username.
117- const usernameRegex = /^[a-zA-Z0-9_-]+$/;
118- if (!usernameRegex.test(username)) {
119- log.warn('Invalid username. Only letters, numbers, underscores, and dashes are allowed.');
120- return new Response(JSON.stringify({ error: 'Invalid username. Only letters, numbers, underscores, and dashes are allowed.' } as RegisterResponseError), { status: 400 });
121- }
122-
123- if (password !== confirmPassword) {
124- log.warn('Passwords do not match');
125- return new Response(JSON.stringify({ error: 'Passwords do not match' } as RegisterResponseError), { status: 400 });
126- }
127-
128- if (password.length < 8 || password.length > 64) {
129- log.warn('Password must be between 8 and 64 characters');
130- return new Response(JSON.stringify({ error: 'Password must be between 8 and 64 characters' } as RegisterResponseError), { status: 400 });
131- }
13290
13391 // Check if nickname already exists
13492 const existingUser = await db.select().from(users).where(eq(users.nickname, username));
M src/routes/api/rooms/[roomId]/+server.ts +3 -3
@@ -40,7 +40,7 @@ export async function GET({ params, url, locals }): Promise<Response> {
4040 // Process users to mark them as offline if they've timed out
4141 const processedUsers = normalizedUsers.map(
4242 (user: SafeUser & { lastSeen: number }) => {
43- const shouldBeOffline = user.status === 'online' && user.lastSeen < timeoutThreshold;
43+ const shouldBeOffline = user.status !== 'offline' && user.lastSeen < timeoutThreshold;
4444 return {
4545 ...user,
4646 status: shouldBeOffline ? 'offline' : user.status
@@ -48,13 +48,13 @@ export async function GET({ params, url, locals }): Promise<Response> {
4848 }
4949 );
5050
51- // Find users who were originally online but now marked offline
51+ // Find users who were originally non-offline but now marked offline
5252 const usersToUpdate = processedUsers.filter(
5353 (user: SafeUser & { lastSeen: number }) =>
5454 user.status === 'offline' &&
5555 normalizedUsers.find(
5656 (u: SafeUser & { lastSeen: number }) => u.id === user.id
57- )?.status === 'online'
57+ )?.status !== 'offline'
5858 );
5959
6060 if (usersToUpdate.length > 0) {
M src/routes/api/session/login/+server.ts +11 -48
@@ -8,10 +8,10 @@ import { generateSessionToken, createSession } from '$lib/api/session.server';
88 import { setSessionTokenCookie } from '$lib/api/session.cookie';
99 import { createSafeUser } from '$lib/types/chat';
1010 import { createLogger } from '$lib/utils/logger.server';
11-import { validateTurnstileToken } from '$lib/utils/turnstile.server';
11+import { loginSchema } from '$lib/validation/password';
12+import { z } from 'zod';
1213
1314 const log = createLogger('login-server');
14-const isDev = process.env.NODE_ENV === 'development';
1515
1616 // In-memory map to track failed login attempts per IP
1717 const loginAttempts = new Map<string, { count: number, lastAttempt: number }>();
@@ -29,14 +29,6 @@ setInterval(() => {
2929 }
3030 }, 60 * 60 * 1000);
3131
32-// Helper to parse clearance cookie from headers
33-function getClearanceCookie(cookieHeader: string | null): string | null {
34- if (!cookieHeader) return null;
35- // Use a case-insensitive regex to match either "cf-clearance" or "cf_clearance"
36- const regex = /cf[-_]clearance=([^;]+)/i;
37- const match = cookieHeader.match(regex);
38- return match ? match[1] : null;
39-}
4032
4133 export const POST: RequestHandler = async ({ request, cookies }) => {
4234 log.debug('New login attempt received');
@@ -72,53 +64,24 @@ export const POST: RequestHandler = async ({ request, cookies }) => {
7264 );
7365 }
7466
75- // Extract cookie header and clearance cookie BEFORE validating input.
76- const cookieHeader = request.headers.get('cookie');
77- const clearanceCookie = getClearanceCookie(cookieHeader);
78-
79- // Note: Mark turnstileToken as optional if a valid clearance cookie exists or in dev mode.
80- const { username, password, turnstileToken } = body as {
67+ const { username, password } = body as {
8168 username: string;
8269 password: string;
83- turnstileToken?: string;
8470 };
8571
86- if (
87- typeof username !== 'string' ||
88- typeof password !== 'string' ||
89- (!isDev && !clearanceCookie && typeof turnstileToken !== 'string')
90- ) {
91- log.warn('Missing or invalid input fields', {
92- hasUsername: typeof username === 'string',
93- hasPassword: typeof password === 'string',
94- hasTurnstileToken: typeof turnstileToken === 'string',
95- isDev
96- });
72+ // Validate input using Zod schema
73+ try {
74+ loginSchema.parse({ username, password });
75+ } catch (err) {
76+ const zodError = err as z.ZodError;
77+ const errorMessage = zodError.errors?.[0]?.message || 'Invalid input data';
78+ log.warn('Login validation failed', { error: errorMessage });
9779 return new Response(
98- JSON.stringify({ error: 'Missing or invalid input fields' } as LoginResponseError),
80+ JSON.stringify({ error: errorMessage } as LoginResponseError),
9981 { status: 400 }
10082 );
10183 }
10284
103- // Check for dev mode or clearance cookie before validating Turnstile token.
104- let isValidTurnstile = false;
105- if (isDev) {
106- log.debug('Development mode: bypassing token challenge.');
107- isValidTurnstile = true;
108- } else if (clearanceCookie) {
109- log.debug('Clearance cookie detected; bypassing token challenge.');
110- isValidTurnstile = true;
111- } else {
112- isValidTurnstile = await validateTurnstileToken(turnstileToken as string, ip);
113- }
114-
115- if (!isValidTurnstile) {
116- log.warn('Invalid Turnstile token', { maskedIp });
117- return new Response(
118- JSON.stringify({ error: 'Security check failed. Please try again.' } as LoginResponseError),
119- { status: 400 }
120- );
121- }
12285
12386 // Find user by username
12487 const user = await db.query.users.findFirst({
M src/routes/api/sse/+server.ts +122 -48
@@ -8,9 +8,11 @@ import type { RequestHandler } from './$types';
88 import { sseEmitter } from '$lib/sseEmitter';
99 import db from '$lib/db/db.server';
1010 import { users } from '$lib/db/schema';
11-import { eq, and, lt } from 'drizzle-orm';
11+import { eq, and, lt, ne } from 'drizzle-orm';
1212 import { createSafeUser } from '$lib/types/chat';
1313 import { createLogger } from '$lib/utils/logger.server';
14+import { sseConnectionTracker } from '$lib/sseConnectionTracker';
15+import { buddyListCache } from '$lib/buddyListCache';
1416
1517 const log = createLogger('sse-server');
1618
@@ -52,7 +54,7 @@ function startTimeoutCheck() {
5254 })
5355 .where(
5456 and(
55- eq(users.status, 'online'), // Only update online users
57+ ne(users.status, 'offline'), // Update any non-offline users
5658 lt(users.lastSeen, timeoutThreshold) // Who haven't been seen recently
5759 )
5860 )
@@ -67,6 +69,9 @@ function startTimeoutCheck() {
6769 usersUpdated: result.length,
6870 timeoutThreshold: new Date(timeoutThreshold).toISOString()
6971 });
72+
73+ // Invalidate buddy list cache when users timeout
74+ buddyListCache.invalidate();
7075 }
7176 } catch (error) {
7277 log.error('Error during timeout check', { error });
@@ -84,19 +89,35 @@ function startBuddyListUpdateInterval() {
8489 const now = Date.now();
8590 // Only fetch and broadcast if 10 seconds have passed since last update
8691 if (now - lastBuddyListUpdate >= BUDDY_LIST_BROADCAST_INTERVAL) {
87- log.debug('Broadcasting buddy list update...');
88- // Query the complete buddy list from the database.
89- const buddyList = await db.select().from(users);
90- // Use createSafeUser to properly sanitize user data
91- const safeBuddyList = buddyList.map(user => createSafeUser(user));
92-
93- // Only broadcast if data has changed
94- if (JSON.stringify(safeBuddyList) !== JSON.stringify(lastBuddyListData)) {
95- lastBuddyListData = safeBuddyList;
96- sseEmitter.emit('sse', {
97- type: 'buddyListUpdate',
98- data: safeBuddyList
99- });
92+ // Only query database if cache is invalid or doesn't exist
93+ if (buddyListCache.needsRefresh()) {
94+ log.debug('Fetching buddy list from database (cache miss)...');
95+ // Query the complete buddy list from the database.
96+ const buddyList = await db.select().from(users);
97+ // Use createSafeUser to properly sanitize user data
98+ const safeBuddyList = buddyList.map(user => createSafeUser(user));
99+
100+ // Update cache and check if data changed
101+ const hasChanged = buddyListCache.update(safeBuddyList);
102+
103+ if (hasChanged) {
104+ log.debug('Broadcasting buddy list update (data changed)...');
105+ sseEmitter.emit('sse', {
106+ type: 'buddyListUpdate',
107+ data: safeBuddyList
108+ });
109+ }
110+ } else {
111+ // Use cached data
112+ const cachedData = buddyListCache.get();
113+ if (cachedData && JSON.stringify(cachedData) !== JSON.stringify(lastBuddyListData)) {
114+ log.debug('Broadcasting buddy list update from cache...');
115+ lastBuddyListData = cachedData;
116+ sseEmitter.emit('sse', {
117+ type: 'buddyListUpdate',
118+ data: cachedData
119+ });
120+ }
100121 }
101122 lastBuddyListUpdate = now;
102123 }
@@ -106,10 +127,38 @@ function startBuddyListUpdateInterval() {
106127 }, 1000); // Check every second but only broadcast every 10 seconds
107128 }
108129
130+// Add periodic cleanup for stale connections
131+let connectionCleanupInterval: ReturnType<typeof setInterval>;
132+
133+function startConnectionCleanup() {
134+ if (connectionCleanupInterval) {
135+ clearInterval(connectionCleanupInterval);
136+ }
137+
138+ connectionCleanupInterval = setInterval(() => {
139+ const staleUserIds = sseConnectionTracker.cleanupStaleConnections();
140+ if (staleUserIds.length > 0) {
141+ // Mark stale connections as offline
142+ staleUserIds.forEach(async (userId) => {
143+ try {
144+ await db.update(users)
145+ .set({ status: 'offline', lastSeen: Date.now() })
146+ .where(eq(users.id, userId));
147+
148+ buddyListCache.invalidate();
149+ } catch (error) {
150+ log.error('Error updating stale user status', { userId, error });
151+ }
152+ });
153+ }
154+ }, 60000); // Run every minute
155+}
156+
109157 // <<< NEW: Ensure intervals are started only once >>>
110158 if (!globalThis.__sseIntervalsStarted) {
111159 startTimeoutCheck();
112160 startBuddyListUpdateInterval();
161+ startConnectionCleanup();
113162 globalThis.__sseIntervalsStarted = true;
114163 log.info('Started global intervals for timeout and buddy list updates');
115164 } else {
@@ -121,18 +170,21 @@ if (typeof process !== 'undefined') {
121170 process.on('beforeExit', () => {
122171 if (timeoutInterval) clearInterval(timeoutInterval);
123172 if (buddyListInterval) clearInterval(buddyListInterval);
173+ if (connectionCleanupInterval) clearInterval(connectionCleanupInterval);
124174 });
125175
126176 // Also handle SIGTERM and SIGINT
127177 process.on('SIGTERM', () => {
128178 if (timeoutInterval) clearInterval(timeoutInterval);
129179 if (buddyListInterval) clearInterval(buddyListInterval);
180+ if (connectionCleanupInterval) clearInterval(connectionCleanupInterval);
130181 process.exit(0);
131182 });
132183
133184 process.on('SIGINT', () => {
134185 if (timeoutInterval) clearInterval(timeoutInterval);
135186 if (buddyListInterval) clearInterval(buddyListInterval);
187+ if (connectionCleanupInterval) clearInterval(connectionCleanupInterval);
136188 process.exit(0);
137189 });
138190 }
@@ -160,29 +212,42 @@ export const GET: RequestHandler = async ({ request, locals, }) => {
160212
161213 const now = Date.now();
162214
163- try {
164- await db.update(users)
165- .set({
166- status: 'online',
167- lastSeen: now
168- })
169- .where(eq(users.id, userId));
170-
171- log.info('User status updated to online', {
172- userId: `${userId.slice(0, 4)}...${userId.slice(-4)}`,
173- timestamp: new Date(now).toISOString()
174- });
215+ // Only update status if this is a new connection
216+ const isNewConnection = sseConnectionTracker.addConnection(userId);
217+
218+ if (isNewConnection) {
219+ try {
220+ await db.update(users)
221+ .set({
222+ status: 'online',
223+ lastSeen: now
224+ })
225+ .where(eq(users.id, userId));
175226
176- sseEmitter.emit('sse', {
177- type: 'userStatusUpdate',
178- data: {
179- userId,
180- status: 'online',
181- lastSeen: now
182- }
227+ log.info('User status updated to online', {
228+ userId: `${userId.slice(0, 4)}...${userId.slice(-4)}`,
229+ timestamp: new Date(now).toISOString()
230+ });
231+
232+ // Invalidate buddy list cache when user status changes
233+ buddyListCache.invalidate();
234+
235+ sseEmitter.emit('sse', {
236+ type: 'userStatusUpdate',
237+ data: {
238+ userId,
239+ status: 'online',
240+ lastSeen: now
241+ }
242+ });
243+ } catch (error) {
244+ log.error('Error updating user status', { error });
245+ sseConnectionTracker.removeConnection(userId);
246+ }
247+ } else {
248+ log.debug('User already has active SSE connection, skipping status update', {
249+ userId: `${userId.slice(0, 4)}...${userId.slice(-4)}`
183250 });
184- } catch (error) {
185- log.error('Error updating user status', { error });
186251 }
187252
188253 const stream = new ReadableStream({
@@ -225,19 +290,28 @@ export const GET: RequestHandler = async ({ request, locals, }) => {
225290 const maskedUserId = `${userId.slice(0, 4)}...${userId.slice(-4)}`;
226291 log.info('Connection closed', { userId: maskedUserId, reason });
227292
228- const now = Date.now();
229- await db.update(users)
230- .set({ status: 'offline', lastSeen: now })
231- .where(eq(users.id, userId));
293+ // Remove from connection tracker
294+ const wasTracked = sseConnectionTracker.removeConnection(userId);
232295
233- sseEmitter.emit('sse', {
234- type: 'userStatusUpdate',
235- data: {
236- userId,
237- status: 'offline',
238- lastSeen: now
239- }
240- });
296+ // Only update database if this was the last connection
297+ if (wasTracked && !sseConnectionTracker.hasConnection(userId)) {
298+ const now = Date.now();
299+ await db.update(users)
300+ .set({ status: 'offline', lastSeen: now })
301+ .where(eq(users.id, userId));
302+
303+ // Invalidate buddy list cache when user goes offline
304+ buddyListCache.invalidate();
305+
306+ sseEmitter.emit('sse', {
307+ type: 'userStatusUpdate',
308+ data: {
309+ userId,
310+ status: 'offline',
311+ lastSeen: now
312+ }
313+ });
314+ }
241315 }
242316 });
243317
M src/routes/api/status/+server.ts +4 -0
@@ -5,6 +5,7 @@ import { validateSessionToken, generateSessionToken, createSession } from '$lib/
55 import { setSessionTokenCookie } from '$lib/api/session.cookie';
66 import { createSafeUser } from '$lib/types/chat';
77 import { createLogger } from '$lib/utils/logger.server';
8+import { buddyListCache } from '$lib/buddyListCache';
89 import type { RequestHandler } from './$types';
910
1011 const log = createLogger('status-server');
@@ -46,6 +47,9 @@ export const POST: RequestHandler = async ({ request, cookies, locals }) => {
4647 .returning()
4748 .get();
4849 log.debug('Database updated successfully', { userId: maskedUserId, status });
50+
51+ // Invalidate buddy list cache when status changes
52+ buddyListCache.invalidate();
4953
5054 // Renew session if status is online and session expires in less than 1 day
5155 if (status === 'online') {
A static/_headers +18 -0
@@ -0,0 +1,18 @@
1+# Cache configuration for static assets
2+
3+# Font files - cache for 1 year (31536000 seconds)
4+/fonts/*
5+ Cache-Control: public, max-age=31536000, immutable
6+ Access-Control-Allow-Origin: *
7+ Cross-Origin-Resource-Policy: cross-origin
8+
9+# General static assets - cache for 1 month (2592000 seconds)
10+/favicon.png
11+ Cache-Control: public, max-age=2592000
12+
13+# Icons and images - cache for 1 month
14+/aim/*
15+ Cache-Control: public, max-age=2592000
16+
17+/desktop/*
18+ Cache-Control: public, max-age=2592000⏎̸
A static/fonts/Arial.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Arialbd.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Arialbi.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Ariali.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Comic.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Comicbd.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/LiberationMono-Bold.ttf +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/LiberationMono-BoldItalic.ttf +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/LiberationMono-Italic.ttf +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/LiberationMono-Regular.ttf +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Times.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Timesbd.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Timesbi.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Timesi.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Verdana.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Verdanab.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Verdanai.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/Verdanaz.TTF +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/tahoma.ttf +0 -0 binary file: no text diff

binary file: no text diff

A static/fonts/tahomabd.ttf +0 -0 binary file: no text diff

binary file: no text diff

A test-gradient-fixes.md +49 -0
@@ -0,0 +1,49 @@
1+# Gradient and Text Formatting Fixes Summary
2+
3+## Issues Fixed:
4+
5+### 1. Color Picker Button Gradient Preview
6+**Problem**: The color picker button wasn't showing gradient preview correctly.
7+**Fix**: Updated `displayStyle` in `color-picker-256.svelte` to use consistent `background` property instead of `background-color`.
8+
9+### 2. Text Input Gradient Display
10+**Problem**: Text input only showed the first color of a gradient.
11+**Fix**: This is by design to preserve the input background. Added a visual gradient indicator next to the input field in `chat-room.svelte` when gradient mode is active.
12+
13+### 3. Chat Messages Formatting
14+**Problem**: Messages weren't displaying with user-specific fonts, styles and colors.
15+**Fixes**:
16+- Updated `sendMessage` function to accept and pass `textStyle` parameter
17+- Added `styleData` field to `SendMessageRequest` payload type
18+- Updated server-side message handler to save `styleData` and `hasFormatting` fields
19+- Fixed `formatted-message.svelte` to properly handle gradient styles
20+- Updated text formatter to apply styles correctly to paragraph elements
21+
22+## Files Modified:
23+
24+1. `/src/lib/components/color-picker-256.svelte` - Fixed gradient preview display
25+2. `/src/lib/components/chat-room.svelte` - Added textStyle to sendMessage call and gradient indicator
26+3. `/src/lib/components/formatted-message.svelte` - Fixed style application for gradients
27+4. `/src/lib/utils/text-formatter.ts` - Fixed style application to all text elements
28+5. `/src/lib/states/chat.svelte.ts` - Added textStyle parameter to sendMessage
29+6. `/src/lib/types/payloads.ts` - Added styleData to SendMessageRequest
30+7. `/src/routes/api/chat/messages/+server.ts` - Added styleData handling in message creation
31+
32+## How It Works Now:
33+
34+1. When a user selects colors/gradients and formatting options in the toolbar, the `currentTextStyle` state is updated
35+2. When sending a message, the style data is serialized and sent along with the message content
36+3. The server saves the style data with the message in the database
37+4. When messages are displayed, the `FormattedMessage` component applies the saved styles
38+5. Gradients are rendered character-by-character for the classic AOL effect
39+6. The input field shows a gradient indicator bar when gradient mode is active
40+
41+## Testing:
42+
43+To test the fixes:
44+1. Open the chat window
45+2. Select a gradient using the color picker (add 2-3 colors)
46+3. Choose a font and adjust size
47+4. Type a message - you should see the first gradient color in the input
48+5. Send the message - it should display with the full gradient effect
49+6. Other users should see your message with your chosen formatting⏎̸

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 9

↑↓ moveenter openesc close