···
51
51
"dependencies": {
52
52
"@foxui/core": "^0.5.2",
53
53
"@foxui/social": "^0.5.4",
54
54
-
"dexie": "^4.3.0",
55
55
-
"flexsearch": "^0.8.212",
54
54
+
"@tursodatabase/database-wasm": "^0.5.0",
56
55
"valibot": "^1.2.0",
57
56
"wrangler": "^4.69.0"
58
57
},
···
14
14
'@foxui/social':
15
15
specifier: ^0.5.4
16
16
version: 0.5.4(@internationalized/date@3.11.0)(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.6)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)))(svelte@5.53.6)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)))(svelte@5.53.6)(tailwindcss@4.2.1)
17
17
-
dexie:
18
18
-
specifier: ^4.3.0
19
19
-
version: 4.3.0
20
20
-
flexsearch:
21
21
-
specifier: ^0.8.212
22
22
-
version: 0.8.212
17
17
+
'@tursodatabase/database-wasm':
18
18
+
specifier: ^0.5.0
19
19
+
version: 0.5.0
23
20
valibot:
24
21
specifier: ^1.2.0
25
22
version: 1.2.0(typescript@5.9.3)
···
121
118
resolution: {integrity: sha512-+GKZpOc0PJcdWMQEkTfg/rSNDAAHxmAUGBl60g2az15etqJn5WaUPNGFE2sB7hKpwi5Ue2h/L0OacINcE/JDDQ==}
122
119
123
120
'@atcute/bluesky-richtext-segmenter@3.0.0':
124
124
-
resolution: {integrity: sha512-NhZTUKtFpeBBbILwAcxj5u4RobIoHOmGw3CAaaEFNebKYSvmTecrXJ7XufHw5DFOUdr8SiKXQVRQxGAxulMNWg==, tarball: https://registry.npmjs.org/@atcute/bluesky-richtext-segmenter/-/bluesky-richtext-segmenter-3.0.0.tgz}
121
121
+
resolution: {integrity: sha512-NhZTUKtFpeBBbILwAcxj5u4RobIoHOmGw3CAaaEFNebKYSvmTecrXJ7XufHw5DFOUdr8SiKXQVRQxGAxulMNWg==}
125
122
126
123
'@atcute/bluesky@3.2.19':
127
124
resolution: {integrity: sha512-W/Sy2671A5eKkdWJn6nfCGoixqMFOouEKRbqRV3630I13Er9iS+gA/rGWUXlp5xNpbfCNmsQ6C1pEidUmO+00g==}
···
175
172
engines: {node: '>= 18'}
176
173
177
174
'@cloudflare/kv-asset-handler@0.4.2':
178
178
-
resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==, tarball: https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz}
175
175
+
resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==}
179
176
engines: {node: '>=18.0.0'}
180
177
181
178
'@cloudflare/unenv-preset@2.14.0':
182
182
-
resolution: {integrity: sha512-XKAkWhi1nBdNsSEoNG9nkcbyvfUrSjSf+VYVPfOto3gLTZVc3F4g6RASCMh6IixBKCG2yDgZKQIHGKtjcnLnKg==, tarball: https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.14.0.tgz}
179
179
+
resolution: {integrity: sha512-XKAkWhi1nBdNsSEoNG9nkcbyvfUrSjSf+VYVPfOto3gLTZVc3F4g6RASCMh6IixBKCG2yDgZKQIHGKtjcnLnKg==}
183
180
peerDependencies:
184
181
unenv: 2.0.0-rc.24
185
182
workerd: ^1.20260218.0
···
188
185
optional: true
189
186
190
187
'@cloudflare/workerd-darwin-64@1.20260305.0':
191
191
-
resolution: {integrity: sha512-chhKOpymo0Eh9J3nymrauMqKGboCc4uz/j0gA1G4gioMnKsN2ZDKJ+qjRZDnCoVGy8u2C4pxlmyIfsXCAfIzhQ==, tarball: https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260305.0.tgz}
188
188
+
resolution: {integrity: sha512-chhKOpymo0Eh9J3nymrauMqKGboCc4uz/j0gA1G4gioMnKsN2ZDKJ+qjRZDnCoVGy8u2C4pxlmyIfsXCAfIzhQ==}
192
189
engines: {node: '>=16'}
193
190
cpu: [x64]
194
191
os: [darwin]
195
192
196
193
'@cloudflare/workerd-darwin-arm64@1.20260305.0':
197
197
-
resolution: {integrity: sha512-K9aG2OQk5bBfOP+fyGPqLcqZ9OR3ra6uwnxJ8f2mveq2A2LsCI7ZeGxQiAj75Ti80ytH/gJffZIx4Np2JtU3aQ==, tarball: https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260305.0.tgz}
194
194
+
resolution: {integrity: sha512-K9aG2OQk5bBfOP+fyGPqLcqZ9OR3ra6uwnxJ8f2mveq2A2LsCI7ZeGxQiAj75Ti80ytH/gJffZIx4Np2JtU3aQ==}
198
195
engines: {node: '>=16'}
199
196
cpu: [arm64]
200
197
os: [darwin]
201
198
202
199
'@cloudflare/workerd-linux-64@1.20260305.0':
203
203
-
resolution: {integrity: sha512-tt7XUoIw/cYFeGbkPkcZ6XX1aZm26Aju/4ih+DXxOosbBeGshFSrNJDBfAKKOvkjsAZymJ+WWVDBU+hmNaGfwA==, tarball: https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260305.0.tgz}
200
200
+
resolution: {integrity: sha512-tt7XUoIw/cYFeGbkPkcZ6XX1aZm26Aju/4ih+DXxOosbBeGshFSrNJDBfAKKOvkjsAZymJ+WWVDBU+hmNaGfwA==}
204
201
engines: {node: '>=16'}
205
202
cpu: [x64]
206
203
os: [linux]
207
204
208
205
'@cloudflare/workerd-linux-arm64@1.20260305.0':
209
209
-
resolution: {integrity: sha512-72QTkY5EzylmvCZ8ZTrnJ9DctmQsfSof1OKyOWqu/pv/B2yACfuPMikq8RpPxvVu7hhS0ztGP6ZvXz72Htq4Zg==, tarball: https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260305.0.tgz}
206
206
+
resolution: {integrity: sha512-72QTkY5EzylmvCZ8ZTrnJ9DctmQsfSof1OKyOWqu/pv/B2yACfuPMikq8RpPxvVu7hhS0ztGP6ZvXz72Htq4Zg==}
210
207
engines: {node: '>=16'}
211
208
cpu: [arm64]
212
209
os: [linux]
213
210
214
211
'@cloudflare/workerd-windows-64@1.20260305.0':
215
215
-
resolution: {integrity: sha512-BA0uaQPOaI2F6mJtBDqplGnQQhpXCzwEMI33p/TnDxtSk9u8CGIfBFuI6uqo8mJ6ijIaPjeBLGOn2CiRMET4qg==, tarball: https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260305.0.tgz}
212
212
+
resolution: {integrity: sha512-BA0uaQPOaI2F6mJtBDqplGnQQhpXCzwEMI33p/TnDxtSk9u8CGIfBFuI6uqo8mJ6ijIaPjeBLGOn2CiRMET4qg==}
216
213
engines: {node: '>=16'}
217
214
cpu: [x64]
218
215
os: [win32]
···
221
218
resolution: {integrity: sha512-klKnECMb5A4GtVF0P5NH6rCjtyjqIEKJaz6kEtx9YPHhfFO2HUEarO+MI4F8WPchgeZqpGlEpDhRapzrOTw51Q==}
222
219
223
220
'@cspotcode/source-map-support@0.8.1':
224
224
-
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, tarball: https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz}
221
221
+
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
225
222
engines: {node: '>=12'}
226
223
224
224
+
'@emnapi/core@1.8.1':
225
225
+
resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==}
226
226
+
227
227
'@emnapi/runtime@1.8.1':
228
228
-
resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==, tarball: https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz}
228
228
+
resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==}
229
229
+
230
230
+
'@emnapi/wasi-threads@1.1.0':
231
231
+
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
229
232
230
233
'@esbuild/aix-ppc64@0.27.3':
231
231
-
resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==, tarball: https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz}
234
234
+
resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
232
235
engines: {node: '>=18'}
233
236
cpu: [ppc64]
234
237
os: [aix]
235
238
236
239
'@esbuild/android-arm64@0.27.3':
237
237
-
resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==, tarball: https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz}
240
240
+
resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
238
241
engines: {node: '>=18'}
239
242
cpu: [arm64]
240
243
os: [android]
241
244
242
245
'@esbuild/android-arm@0.27.3':
243
243
-
resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==, tarball: https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz}
246
246
+
resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
244
247
engines: {node: '>=18'}
245
248
cpu: [arm]
246
249
os: [android]
247
250
248
251
'@esbuild/android-x64@0.27.3':
249
249
-
resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==, tarball: https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz}
252
252
+
resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
250
253
engines: {node: '>=18'}
251
254
cpu: [x64]
252
255
os: [android]
253
256
254
257
'@esbuild/darwin-arm64@0.27.3':
255
255
-
resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==, tarball: https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz}
258
258
+
resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
256
259
engines: {node: '>=18'}
257
260
cpu: [arm64]
258
261
os: [darwin]
259
262
260
263
'@esbuild/darwin-x64@0.27.3':
261
261
-
resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==, tarball: https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz}
264
264
+
resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
262
265
engines: {node: '>=18'}
263
266
cpu: [x64]
264
267
os: [darwin]
265
268
266
269
'@esbuild/freebsd-arm64@0.27.3':
267
267
-
resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==, tarball: https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz}
270
270
+
resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
268
271
engines: {node: '>=18'}
269
272
cpu: [arm64]
270
273
os: [freebsd]
271
274
272
275
'@esbuild/freebsd-x64@0.27.3':
273
273
-
resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==, tarball: https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz}
276
276
+
resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
274
277
engines: {node: '>=18'}
275
278
cpu: [x64]
276
279
os: [freebsd]
277
280
278
281
'@esbuild/linux-arm64@0.27.3':
279
279
-
resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==, tarball: https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz}
282
282
+
resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
280
283
engines: {node: '>=18'}
281
284
cpu: [arm64]
282
285
os: [linux]
283
286
284
287
'@esbuild/linux-arm@0.27.3':
285
285
-
resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==, tarball: https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz}
288
288
+
resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
286
289
engines: {node: '>=18'}
287
290
cpu: [arm]
288
291
os: [linux]
289
292
290
293
'@esbuild/linux-ia32@0.27.3':
291
291
-
resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==, tarball: https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz}
294
294
+
resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
292
295
engines: {node: '>=18'}
293
296
cpu: [ia32]
294
297
os: [linux]
295
298
296
299
'@esbuild/linux-loong64@0.27.3':
297
297
-
resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==, tarball: https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz}
300
300
+
resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
298
301
engines: {node: '>=18'}
299
302
cpu: [loong64]
300
303
os: [linux]
301
304
302
305
'@esbuild/linux-mips64el@0.27.3':
303
303
-
resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==, tarball: https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz}
306
306
+
resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
304
307
engines: {node: '>=18'}
305
308
cpu: [mips64el]
306
309
os: [linux]
307
310
308
311
'@esbuild/linux-ppc64@0.27.3':
309
309
-
resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==, tarball: https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz}
312
312
+
resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
310
313
engines: {node: '>=18'}
311
314
cpu: [ppc64]
312
315
os: [linux]
313
316
314
317
'@esbuild/linux-riscv64@0.27.3':
315
315
-
resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==, tarball: https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz}
318
318
+
resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
316
319
engines: {node: '>=18'}
317
320
cpu: [riscv64]
318
321
os: [linux]
319
322
320
323
'@esbuild/linux-s390x@0.27.3':
321
321
-
resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==, tarball: https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz}
324
324
+
resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
322
325
engines: {node: '>=18'}
323
326
cpu: [s390x]
324
327
os: [linux]
325
328
326
329
'@esbuild/linux-x64@0.27.3':
327
327
-
resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==, tarball: https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz}
330
330
+
resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
328
331
engines: {node: '>=18'}
329
332
cpu: [x64]
330
333
os: [linux]
331
334
332
335
'@esbuild/netbsd-arm64@0.27.3':
333
333
-
resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==, tarball: https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz}
336
336
+
resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
334
337
engines: {node: '>=18'}
335
338
cpu: [arm64]
336
339
os: [netbsd]
337
340
338
341
'@esbuild/netbsd-x64@0.27.3':
339
339
-
resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==, tarball: https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz}
342
342
+
resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
340
343
engines: {node: '>=18'}
341
344
cpu: [x64]
342
345
os: [netbsd]
343
346
344
347
'@esbuild/openbsd-arm64@0.27.3':
345
345
-
resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==, tarball: https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz}
348
348
+
resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
346
349
engines: {node: '>=18'}
347
350
cpu: [arm64]
348
351
os: [openbsd]
349
352
350
353
'@esbuild/openbsd-x64@0.27.3':
351
351
-
resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==, tarball: https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz}
354
354
+
resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
352
355
engines: {node: '>=18'}
353
356
cpu: [x64]
354
357
os: [openbsd]
355
358
356
359
'@esbuild/openharmony-arm64@0.27.3':
357
357
-
resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==, tarball: https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz}
360
360
+
resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
358
361
engines: {node: '>=18'}
359
362
cpu: [arm64]
360
363
os: [openharmony]
361
364
362
365
'@esbuild/sunos-x64@0.27.3':
363
363
-
resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==, tarball: https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz}
366
366
+
resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
364
367
engines: {node: '>=18'}
365
368
cpu: [x64]
366
369
os: [sunos]
367
370
368
371
'@esbuild/win32-arm64@0.27.3':
369
369
-
resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==, tarball: https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz}
372
372
+
resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
370
373
engines: {node: '>=18'}
371
374
cpu: [arm64]
372
375
os: [win32]
373
376
374
377
'@esbuild/win32-ia32@0.27.3':
375
375
-
resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==, tarball: https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz}
378
378
+
resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
376
379
engines: {node: '>=18'}
377
380
cpu: [ia32]
378
381
os: [win32]
379
382
380
383
'@esbuild/win32-x64@0.27.3':
381
381
-
resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==, tarball: https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz}
384
384
+
resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
382
385
engines: {node: '>=18'}
383
386
cpu: [x64]
384
387
os: [win32]
···
441
444
resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
442
445
443
446
'@foxui/core@0.5.2':
444
444
-
resolution: {integrity: sha512-SwzKizuPCpiD47YfDfZ4Ut0KX+WlmidbBTaNafQaSYpQA45D5avRksgbJWsUgIaLx2oyH8PwBq7r/KFjCuKx/g==, tarball: https://registry.npmjs.org/@foxui/core/-/core-0.5.2.tgz}
447
447
+
resolution: {integrity: sha512-SwzKizuPCpiD47YfDfZ4Ut0KX+WlmidbBTaNafQaSYpQA45D5avRksgbJWsUgIaLx2oyH8PwBq7r/KFjCuKx/g==}
445
448
peerDependencies:
446
449
svelte: '>=5'
447
450
tailwindcss: '>=3'
448
451
449
452
'@foxui/social@0.5.4':
450
450
-
resolution: {integrity: sha512-6IvVJv6+NyEf0MbLZiOsNW11qK6QDAIMGzF6Wa4v5xmE8F5HCIOsx7am7JRS8zE+4da8rQ5otM8NpAIQhb5Edw==, tarball: https://registry.npmjs.org/@foxui/social/-/social-0.5.4.tgz}
453
453
+
resolution: {integrity: sha512-6IvVJv6+NyEf0MbLZiOsNW11qK6QDAIMGzF6Wa4v5xmE8F5HCIOsx7am7JRS8zE+4da8rQ5otM8NpAIQhb5Edw==}
451
454
peerDependencies:
452
455
svelte: '>=5'
453
456
tailwindcss: '>=3'
454
457
455
458
'@foxui/time@0.5.2':
456
456
-
resolution: {integrity: sha512-CSIzydngnijCFY/W2PsVuWjIGKfSDMIs6bxvVwlpIWV8e8gzrzfK+DCwL5RO9rhZOppEOqN7VptItOcIplCALw==, tarball: https://registry.npmjs.org/@foxui/time/-/time-0.5.2.tgz}
459
459
+
resolution: {integrity: sha512-CSIzydngnijCFY/W2PsVuWjIGKfSDMIs6bxvVwlpIWV8e8gzrzfK+DCwL5RO9rhZOppEOqN7VptItOcIplCALw==}
457
460
peerDependencies:
458
461
svelte: '>=5'
459
462
tailwindcss: '>=3'
···
475
478
engines: {node: '>=18.18'}
476
479
477
480
'@img/colour@1.1.0':
478
478
-
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==, tarball: https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz}
481
481
+
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
479
482
engines: {node: '>=18'}
480
483
481
484
'@img/sharp-darwin-arm64@0.34.5':
482
482
-
resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==, tarball: https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz}
485
485
+
resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==}
483
486
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
484
487
cpu: [arm64]
485
488
os: [darwin]
486
489
487
490
'@img/sharp-darwin-x64@0.34.5':
488
488
-
resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==, tarball: https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz}
491
491
+
resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==}
489
492
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
490
493
cpu: [x64]
491
494
os: [darwin]
492
495
493
496
'@img/sharp-libvips-darwin-arm64@1.2.4':
494
494
-
resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==, tarball: https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz}
497
497
+
resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==}
495
498
cpu: [arm64]
496
499
os: [darwin]
497
500
498
501
'@img/sharp-libvips-darwin-x64@1.2.4':
499
499
-
resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==, tarball: https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz}
502
502
+
resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==}
500
503
cpu: [x64]
501
504
os: [darwin]
502
505
503
506
'@img/sharp-libvips-linux-arm64@1.2.4':
504
504
-
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz}
507
507
+
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
505
508
cpu: [arm64]
506
509
os: [linux]
510
510
+
libc: [glibc]
507
511
508
512
'@img/sharp-libvips-linux-arm@1.2.4':
509
509
-
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz}
513
513
+
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
510
514
cpu: [arm]
511
515
os: [linux]
516
516
+
libc: [glibc]
512
517
513
518
'@img/sharp-libvips-linux-ppc64@1.2.4':
514
514
-
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz}
519
519
+
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
515
520
cpu: [ppc64]
516
521
os: [linux]
522
522
+
libc: [glibc]
517
523
518
524
'@img/sharp-libvips-linux-riscv64@1.2.4':
519
519
-
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz}
525
525
+
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
520
526
cpu: [riscv64]
521
527
os: [linux]
528
528
+
libc: [glibc]
522
529
523
530
'@img/sharp-libvips-linux-s390x@1.2.4':
524
524
-
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz}
531
531
+
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
525
532
cpu: [s390x]
526
533
os: [linux]
534
534
+
libc: [glibc]
527
535
528
536
'@img/sharp-libvips-linux-x64@1.2.4':
529
529
-
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz}
537
537
+
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
530
538
cpu: [x64]
531
539
os: [linux]
540
540
+
libc: [glibc]
532
541
533
542
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
534
534
-
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz}
543
543
+
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
535
544
cpu: [arm64]
536
545
os: [linux]
546
546
+
libc: [musl]
537
547
538
548
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
539
539
-
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz}
549
549
+
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
540
550
cpu: [x64]
541
551
os: [linux]
552
552
+
libc: [musl]
542
553
543
554
'@img/sharp-linux-arm64@0.34.5':
544
544
-
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==, tarball: https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz}
555
555
+
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
545
556
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
546
557
cpu: [arm64]
547
558
os: [linux]
559
559
+
libc: [glibc]
548
560
549
561
'@img/sharp-linux-arm@0.34.5':
550
550
-
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==, tarball: https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz}
562
562
+
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
551
563
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
552
564
cpu: [arm]
553
565
os: [linux]
566
566
+
libc: [glibc]
554
567
555
568
'@img/sharp-linux-ppc64@0.34.5':
556
556
-
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==, tarball: https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz}
569
569
+
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
557
570
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
558
571
cpu: [ppc64]
559
572
os: [linux]
573
573
+
libc: [glibc]
560
574
561
575
'@img/sharp-linux-riscv64@0.34.5':
562
562
-
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==, tarball: https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz}
576
576
+
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
563
577
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
564
578
cpu: [riscv64]
565
579
os: [linux]
580
580
+
libc: [glibc]
566
581
567
582
'@img/sharp-linux-s390x@0.34.5':
568
568
-
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==, tarball: https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz}
583
583
+
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
569
584
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
570
585
cpu: [s390x]
571
586
os: [linux]
587
587
+
libc: [glibc]
572
588
573
589
'@img/sharp-linux-x64@0.34.5':
574
574
-
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==, tarball: https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz}
590
590
+
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
575
591
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
576
592
cpu: [x64]
577
593
os: [linux]
594
594
+
libc: [glibc]
578
595
579
596
'@img/sharp-linuxmusl-arm64@0.34.5':
580
580
-
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==, tarball: https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz}
597
597
+
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
581
598
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
582
599
cpu: [arm64]
583
600
os: [linux]
601
601
+
libc: [musl]
584
602
585
603
'@img/sharp-linuxmusl-x64@0.34.5':
586
586
-
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==, tarball: https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz}
604
604
+
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
587
605
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
588
606
cpu: [x64]
589
607
os: [linux]
608
608
+
libc: [musl]
590
609
591
610
'@img/sharp-wasm32@0.34.5':
592
592
-
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==, tarball: https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz}
611
611
+
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
593
612
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
594
613
cpu: [wasm32]
595
614
596
615
'@img/sharp-win32-arm64@0.34.5':
597
597
-
resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==, tarball: https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz}
616
616
+
resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==}
598
617
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
599
618
cpu: [arm64]
600
619
os: [win32]
601
620
602
621
'@img/sharp-win32-ia32@0.34.5':
603
603
-
resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==, tarball: https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz}
622
622
+
resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==}
604
623
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
605
624
cpu: [ia32]
606
625
os: [win32]
607
626
608
627
'@img/sharp-win32-x64@0.34.5':
609
609
-
resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==, tarball: https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz}
628
628
+
resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==}
610
629
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
611
630
cpu: [x64]
612
631
os: [win32]
613
632
614
633
'@internationalized/date@3.11.0':
615
615
-
resolution: {integrity: sha512-BOx5huLAWhicM9/ZFs84CzP+V3gBW6vlpM02yzsdYC7TGlZJX1OJiEEHcSayF00Z+3jLlm4w79amvSt6RqKN3Q==, tarball: https://registry.npmjs.org/@internationalized/date/-/date-3.11.0.tgz}
634
634
+
resolution: {integrity: sha512-BOx5huLAWhicM9/ZFs84CzP+V3gBW6vlpM02yzsdYC7TGlZJX1OJiEEHcSayF00Z+3jLlm4w79amvSt6RqKN3Q==}
616
635
617
636
'@jridgewell/gen-mapping@0.3.13':
618
637
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
···
631
650
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
632
651
633
652
'@jridgewell/trace-mapping@0.3.9':
634
634
-
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==, tarball: https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz}
653
653
+
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
654
654
+
655
655
+
'@napi-rs/wasm-runtime@1.1.1':
656
656
+
resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==}
635
657
636
658
'@number-flow/svelte@0.3.13':
637
659
resolution: {integrity: sha512-mvbxDeSFa1o/E4vGhrWuawAFCgcn5qTQ/s++FIoD88es5+JQa/aMQUypTy7qXIreTtTvncpIbkKdw9DMnweaSw==}
···
642
664
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
643
665
644
666
'@poppinss/colors@4.1.6':
645
645
-
resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==, tarball: https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz}
667
667
+
resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==}
646
668
647
669
'@poppinss/dumper@0.6.5':
648
648
-
resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==, tarball: https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz}
670
670
+
resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==}
649
671
650
672
'@poppinss/exception@1.2.3':
651
651
-
resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==, tarball: https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz}
673
673
+
resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==}
652
674
653
675
'@rollup/rollup-android-arm-eabi@4.59.0':
654
654
-
resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==, tarball: https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz}
676
676
+
resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==}
655
677
cpu: [arm]
656
678
os: [android]
657
679
658
680
'@rollup/rollup-android-arm64@4.59.0':
659
659
-
resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==, tarball: https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz}
681
681
+
resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==}
660
682
cpu: [arm64]
661
683
os: [android]
662
684
663
685
'@rollup/rollup-darwin-arm64@4.59.0':
664
664
-
resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==, tarball: https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz}
686
686
+
resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==}
665
687
cpu: [arm64]
666
688
os: [darwin]
667
689
668
690
'@rollup/rollup-darwin-x64@4.59.0':
669
669
-
resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==, tarball: https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz}
691
691
+
resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==}
670
692
cpu: [x64]
671
693
os: [darwin]
672
694
673
695
'@rollup/rollup-freebsd-arm64@4.59.0':
674
674
-
resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==, tarball: https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz}
696
696
+
resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==}
675
697
cpu: [arm64]
676
698
os: [freebsd]
677
699
678
700
'@rollup/rollup-freebsd-x64@4.59.0':
679
679
-
resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==, tarball: https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz}
701
701
+
resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==}
680
702
cpu: [x64]
681
703
os: [freebsd]
682
704
683
705
'@rollup/rollup-linux-arm-gnueabihf@4.59.0':
684
684
-
resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz}
706
706
+
resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==}
685
707
cpu: [arm]
686
708
os: [linux]
709
709
+
libc: [glibc]
687
710
688
711
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
689
689
-
resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz}
712
712
+
resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==}
690
713
cpu: [arm]
691
714
os: [linux]
715
715
+
libc: [musl]
692
716
693
717
'@rollup/rollup-linux-arm64-gnu@4.59.0':
694
694
-
resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz}
718
718
+
resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==}
695
719
cpu: [arm64]
696
720
os: [linux]
721
721
+
libc: [glibc]
697
722
698
723
'@rollup/rollup-linux-arm64-musl@4.59.0':
699
699
-
resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz}
724
724
+
resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==}
700
725
cpu: [arm64]
701
726
os: [linux]
727
727
+
libc: [musl]
702
728
703
729
'@rollup/rollup-linux-loong64-gnu@4.59.0':
704
704
-
resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz}
730
730
+
resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==}
705
731
cpu: [loong64]
706
732
os: [linux]
733
733
+
libc: [glibc]
707
734
708
735
'@rollup/rollup-linux-loong64-musl@4.59.0':
709
709
-
resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz}
736
736
+
resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==}
710
737
cpu: [loong64]
711
738
os: [linux]
739
739
+
libc: [musl]
712
740
713
741
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
714
714
-
resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz}
742
742
+
resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==}
715
743
cpu: [ppc64]
716
744
os: [linux]
745
745
+
libc: [glibc]
717
746
718
747
'@rollup/rollup-linux-ppc64-musl@4.59.0':
719
719
-
resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz}
748
748
+
resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==}
720
749
cpu: [ppc64]
721
750
os: [linux]
751
751
+
libc: [musl]
722
752
723
753
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
724
724
-
resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz}
754
754
+
resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==}
725
755
cpu: [riscv64]
726
756
os: [linux]
757
757
+
libc: [glibc]
727
758
728
759
'@rollup/rollup-linux-riscv64-musl@4.59.0':
729
729
-
resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz}
760
760
+
resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==}
730
761
cpu: [riscv64]
731
762
os: [linux]
763
763
+
libc: [musl]
732
764
733
765
'@rollup/rollup-linux-s390x-gnu@4.59.0':
734
734
-
resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz}
766
766
+
resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==}
735
767
cpu: [s390x]
736
768
os: [linux]
769
769
+
libc: [glibc]
737
770
738
771
'@rollup/rollup-linux-x64-gnu@4.59.0':
739
739
-
resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz}
772
772
+
resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==}
740
773
cpu: [x64]
741
774
os: [linux]
775
775
+
libc: [glibc]
742
776
743
777
'@rollup/rollup-linux-x64-musl@4.59.0':
744
744
-
resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz}
778
778
+
resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==}
745
779
cpu: [x64]
746
780
os: [linux]
781
781
+
libc: [musl]
747
782
748
783
'@rollup/rollup-openbsd-x64@4.59.0':
749
749
-
resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==, tarball: https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz}
784
784
+
resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==}
750
785
cpu: [x64]
751
786
os: [openbsd]
752
787
753
788
'@rollup/rollup-openharmony-arm64@4.59.0':
754
754
-
resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==, tarball: https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz}
789
789
+
resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==}
755
790
cpu: [arm64]
756
791
os: [openharmony]
757
792
758
793
'@rollup/rollup-win32-arm64-msvc@4.59.0':
759
759
-
resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz}
794
794
+
resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==}
760
795
cpu: [arm64]
761
796
os: [win32]
762
797
763
798
'@rollup/rollup-win32-ia32-msvc@4.59.0':
764
764
-
resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz}
799
799
+
resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==}
765
800
cpu: [ia32]
766
801
os: [win32]
767
802
768
803
'@rollup/rollup-win32-x64-gnu@4.59.0':
769
769
-
resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz}
804
804
+
resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==}
770
805
cpu: [x64]
771
806
os: [win32]
772
807
773
808
'@rollup/rollup-win32-x64-msvc@4.59.0':
774
774
-
resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz}
809
809
+
resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==}
775
810
cpu: [x64]
776
811
os: [win32]
777
812
778
813
'@sindresorhus/is@7.2.0':
779
779
-
resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==, tarball: https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz}
814
814
+
resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==}
780
815
engines: {node: '>=18'}
781
816
782
817
'@speed-highlight/core@1.2.14':
783
783
-
resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==, tarball: https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.14.tgz}
818
818
+
resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==}
784
819
785
820
'@standard-schema/spec@1.1.0':
786
821
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
···
828
863
vite: ^6.3.0 || ^7.0.0
829
864
830
865
'@swc/helpers@0.5.19':
831
831
-
resolution: {integrity: sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==, tarball: https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.19.tgz}
866
866
+
resolution: {integrity: sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==}
832
867
833
868
'@tailwindcss/forms@0.5.11':
834
869
resolution: {integrity: sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA==}
···
839
874
resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==}
840
875
841
876
'@tailwindcss/oxide-android-arm64@4.2.1':
842
842
-
resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz}
877
877
+
resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==}
843
878
engines: {node: '>= 20'}
844
879
cpu: [arm64]
845
880
os: [android]
846
881
847
882
'@tailwindcss/oxide-darwin-arm64@4.2.1':
848
848
-
resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz}
883
883
+
resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==}
849
884
engines: {node: '>= 20'}
850
885
cpu: [arm64]
851
886
os: [darwin]
852
887
853
888
'@tailwindcss/oxide-darwin-x64@4.2.1':
854
854
-
resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz}
889
889
+
resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==}
855
890
engines: {node: '>= 20'}
856
891
cpu: [x64]
857
892
os: [darwin]
858
893
859
894
'@tailwindcss/oxide-freebsd-x64@4.2.1':
860
860
-
resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz}
895
895
+
resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==}
861
896
engines: {node: '>= 20'}
862
897
cpu: [x64]
863
898
os: [freebsd]
864
899
865
900
'@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1':
866
866
-
resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz}
901
901
+
resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==}
867
902
engines: {node: '>= 20'}
868
903
cpu: [arm]
869
904
os: [linux]
870
905
871
906
'@tailwindcss/oxide-linux-arm64-gnu@4.2.1':
872
872
-
resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz}
907
907
+
resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==}
873
908
engines: {node: '>= 20'}
874
909
cpu: [arm64]
875
910
os: [linux]
911
911
+
libc: [glibc]
876
912
877
913
'@tailwindcss/oxide-linux-arm64-musl@4.2.1':
878
878
-
resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz}
914
914
+
resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==}
879
915
engines: {node: '>= 20'}
880
916
cpu: [arm64]
881
917
os: [linux]
918
918
+
libc: [musl]
882
919
883
920
'@tailwindcss/oxide-linux-x64-gnu@4.2.1':
884
884
-
resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz}
921
921
+
resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==}
885
922
engines: {node: '>= 20'}
886
923
cpu: [x64]
887
924
os: [linux]
925
925
+
libc: [glibc]
888
926
889
927
'@tailwindcss/oxide-linux-x64-musl@4.2.1':
890
890
-
resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz}
928
928
+
resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==}
891
929
engines: {node: '>= 20'}
892
930
cpu: [x64]
893
931
os: [linux]
932
932
+
libc: [musl]
894
933
895
934
'@tailwindcss/oxide-wasm32-wasi@4.2.1':
896
896
-
resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz}
935
935
+
resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==}
897
936
engines: {node: '>=14.0.0'}
898
937
cpu: [wasm32]
899
938
bundledDependencies:
···
905
944
- tslib
906
945
907
946
'@tailwindcss/oxide-win32-arm64-msvc@4.2.1':
908
908
-
resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz}
947
947
+
resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==}
909
948
engines: {node: '>= 20'}
910
949
cpu: [arm64]
911
950
os: [win32]
912
951
913
952
'@tailwindcss/oxide-win32-x64-msvc@4.2.1':
914
914
-
resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==, tarball: https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz}
953
953
+
resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==}
915
954
engines: {node: '>= 20'}
916
955
cpu: [x64]
917
956
os: [win32]
···
925
964
peerDependencies:
926
965
vite: ^5.2.0 || ^6 || ^7
927
966
967
967
+
'@tursodatabase/database-common@0.5.0':
968
968
+
resolution: {integrity: sha512-Yw1aJ7rw5Sshy7VvkLk3gZlHqNeM3nqs11G3qzhu1gjqLfVxT1MupVfB4AWLrvOwVMYWs560/Xfl9ITooJu5HQ==}
969
969
+
970
970
+
'@tursodatabase/database-wasm-common@0.5.0':
971
971
+
resolution: {integrity: sha512-l7Tf7m52sS0mRWD584WBpFXACZtdcd2iGHXa5Jsjr3Ia3X9sRmDNy/SQkncLQIHXoQ+EPFUC951v9C79Hdgg/w==}
972
972
+
973
973
+
'@tursodatabase/database-wasm@0.5.0':
974
974
+
resolution: {integrity: sha512-94ax/1oENl9wfOyQGIzWkcLE16FwPnOtM5zVTSRJ5NkOC/+FqbIGxWYL+jS4M8dd+U8FXSB2soQXLOWvCSHosg==}
975
975
+
976
976
+
'@tybys/wasm-util@0.10.1':
977
977
+
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
978
978
+
928
979
'@types/bun@1.3.10':
929
980
resolution: {integrity: sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ==}
930
981
···
1006
1057
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1007
1058
1008
1059
'@use-gesture/core@10.3.1':
1009
1009
-
resolution: {integrity: sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==, tarball: https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz}
1060
1060
+
resolution: {integrity: sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==}
1010
1061
1011
1062
'@use-gesture/vanilla@10.3.1':
1012
1012
-
resolution: {integrity: sha512-lT4scGLu59ovA3zmtUonukAGcA0AdOOh+iwNDS05Bsu7Lq9aZToDHhI6D8Q2qvsVraovtsLLYwPrWdG/noMAKw==, tarball: https://registry.npmjs.org/@use-gesture/vanilla/-/vanilla-10.3.1.tgz}
1063
1063
+
resolution: {integrity: sha512-lT4scGLu59ovA3zmtUonukAGcA0AdOOh+iwNDS05Bsu7Lq9aZToDHhI6D8Q2qvsVraovtsLLYwPrWdG/noMAKw==}
1013
1064
1014
1065
acorn-jsx@5.3.2:
1015
1066
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
···
1044
1095
svelte: ^5.33.0
1045
1096
1046
1097
blake3-wasm@2.1.5:
1047
1047
-
resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==, tarball: https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz}
1098
1098
+
resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
1048
1099
1049
1100
brace-expansion@5.0.4:
1050
1101
resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==}
···
1066
1117
engines: {node: '>= 0.6'}
1067
1118
1068
1119
cookie@1.1.1:
1069
1069
-
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==, tarball: https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz}
1120
1120
+
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
1070
1121
engines: {node: '>=18'}
1071
1122
1072
1123
core-js@3.48.0:
1073
1073
-
resolution: {integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==, tarball: https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz}
1124
1124
+
resolution: {integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==}
1074
1125
1075
1126
cross-spawn@7.0.6:
1076
1127
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
···
1082
1133
hasBin: true
1083
1134
1084
1135
custom-event-polyfill@1.0.7:
1085
1085
-
resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==, tarball: https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz}
1136
1136
+
resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==}
1086
1137
1087
1138
debug@4.4.3:
1088
1139
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
···
1111
1162
devalue@5.6.3:
1112
1163
resolution: {integrity: sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==}
1113
1164
1114
1114
-
dexie@4.3.0:
1115
1115
-
resolution: {integrity: sha512-5EeoQpJvMKHe6zWt/FSIIuRa3CWlZeIl6zKXt+Lz7BU6RoRRLgX9dZEynRfXrkLcldKYCBiz7xekTEylnie1Ug==, tarball: https://registry.npmjs.org/dexie/-/dexie-4.3.0.tgz}
1116
1116
-
1117
1165
dompurify@3.3.1:
1118
1118
-
resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==, tarball: https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz}
1166
1166
+
resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==}
1119
1167
1120
1168
emoji-picker-element@1.29.1:
1121
1121
-
resolution: {integrity: sha512-TOiHzu9Dqib3x4MwcAi3wi3RdyT4SoeB4b15AvH1ks4SBwTl7DeebhZ0d3x6dNi4XfNU7IGRZ7NBQllj0RqwrQ==, tarball: https://registry.npmjs.org/emoji-picker-element/-/emoji-picker-element-1.29.1.tgz}
1169
1169
+
resolution: {integrity: sha512-TOiHzu9Dqib3x4MwcAi3wi3RdyT4SoeB4b15AvH1ks4SBwTl7DeebhZ0d3x6dNi4XfNU7IGRZ7NBQllj0RqwrQ==}
1122
1170
1123
1171
enhanced-resolve@5.20.0:
1124
1172
resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==}
1125
1173
engines: {node: '>=10.13.0'}
1126
1174
1127
1175
error-stack-parser-es@1.0.5:
1128
1128
-
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==, tarball: https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz}
1176
1176
+
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
1129
1177
1130
1178
esbuild@0.27.3:
1131
1131
-
resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==, tarball: https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz}
1179
1179
+
resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
1132
1180
engines: {node: '>=18'}
1133
1181
hasBin: true
1134
1182
···
1245
1293
flatted@3.3.4:
1246
1294
resolution: {integrity: sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==}
1247
1295
1248
1248
-
flexsearch@0.8.212:
1249
1249
-
resolution: {integrity: sha512-wSyJr1GUWoOOIISRu+X2IXiOcVfg9qqBRyCPRUdLMIGJqPzMo+jMRlvE83t14v1j0dRMEaBbER/adQjp6Du2pw==}
1250
1250
-
1251
1296
fsevents@2.3.3:
1252
1252
-
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, tarball: https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz}
1297
1297
+
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
1253
1298
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
1254
1299
os: [darwin]
1255
1300
···
1272
1317
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
1273
1318
1274
1319
hls.js@1.6.15:
1275
1275
-
resolution: {integrity: sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==, tarball: https://registry.npmjs.org/hls.js/-/hls.js-1.6.15.tgz}
1320
1320
+
resolution: {integrity: sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==}
1276
1321
1277
1322
ignore@5.3.2:
1278
1323
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
···
1290
1335
resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
1291
1336
1292
1337
is-emoji-supported@0.0.5:
1293
1293
-
resolution: {integrity: sha512-WOlXUhDDHxYqcSmFZis+xWhhqXiK2SU0iYiqmth5Ip0FHLZQAt9rKL5ahnilE8/86WH8tZ3bmNNNC+bTzamqlw==, tarball: https://registry.npmjs.org/is-emoji-supported/-/is-emoji-supported-0.0.5.tgz}
1338
1338
+
resolution: {integrity: sha512-WOlXUhDDHxYqcSmFZis+xWhhqXiK2SU0iYiqmth5Ip0FHLZQAt9rKL5ahnilE8/86WH8tZ3bmNNNC+bTzamqlw==}
1294
1339
1295
1340
is-extglob@2.1.1:
1296
1341
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
···
1334
1379
engines: {node: '>= 0.8.0'}
1335
1380
1336
1381
lightningcss-android-arm64@1.31.1:
1337
1337
-
resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==, tarball: https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz}
1382
1382
+
resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==}
1338
1383
engines: {node: '>= 12.0.0'}
1339
1384
cpu: [arm64]
1340
1385
os: [android]
1341
1386
1342
1387
lightningcss-darwin-arm64@1.31.1:
1343
1343
-
resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==, tarball: https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz}
1388
1388
+
resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==}
1344
1389
engines: {node: '>= 12.0.0'}
1345
1390
cpu: [arm64]
1346
1391
os: [darwin]
1347
1392
1348
1393
lightningcss-darwin-x64@1.31.1:
1349
1349
-
resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==, tarball: https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz}
1394
1394
+
resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==}
1350
1395
engines: {node: '>= 12.0.0'}
1351
1396
cpu: [x64]
1352
1397
os: [darwin]
1353
1398
1354
1399
lightningcss-freebsd-x64@1.31.1:
1355
1355
-
resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==, tarball: https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz}
1400
1400
+
resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==}
1356
1401
engines: {node: '>= 12.0.0'}
1357
1402
cpu: [x64]
1358
1403
os: [freebsd]
1359
1404
1360
1405
lightningcss-linux-arm-gnueabihf@1.31.1:
1361
1361
-
resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==, tarball: https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz}
1406
1406
+
resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==}
1362
1407
engines: {node: '>= 12.0.0'}
1363
1408
cpu: [arm]
1364
1409
os: [linux]
1365
1410
1366
1411
lightningcss-linux-arm64-gnu@1.31.1:
1367
1367
-
resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==, tarball: https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz}
1412
1412
+
resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==}
1368
1413
engines: {node: '>= 12.0.0'}
1369
1414
cpu: [arm64]
1370
1415
os: [linux]
1416
1416
+
libc: [glibc]
1371
1417
1372
1418
lightningcss-linux-arm64-musl@1.31.1:
1373
1373
-
resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==, tarball: https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz}
1419
1419
+
resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==}
1374
1420
engines: {node: '>= 12.0.0'}
1375
1421
cpu: [arm64]
1376
1422
os: [linux]
1423
1423
+
libc: [musl]
1377
1424
1378
1425
lightningcss-linux-x64-gnu@1.31.1:
1379
1379
-
resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==, tarball: https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz}
1426
1426
+
resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==}
1380
1427
engines: {node: '>= 12.0.0'}
1381
1428
cpu: [x64]
1382
1429
os: [linux]
1430
1430
+
libc: [glibc]
1383
1431
1384
1432
lightningcss-linux-x64-musl@1.31.1:
1385
1385
-
resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==, tarball: https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz}
1433
1433
+
resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==}
1386
1434
engines: {node: '>= 12.0.0'}
1387
1435
cpu: [x64]
1388
1436
os: [linux]
1437
1437
+
libc: [musl]
1389
1438
1390
1439
lightningcss-win32-arm64-msvc@1.31.1:
1391
1391
-
resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==, tarball: https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz}
1440
1440
+
resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==}
1392
1441
engines: {node: '>= 12.0.0'}
1393
1442
cpu: [arm64]
1394
1443
os: [win32]
1395
1444
1396
1445
lightningcss-win32-x64-msvc@1.31.1:
1397
1397
-
resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==, tarball: https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz}
1446
1446
+
resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==}
1398
1447
engines: {node: '>= 12.0.0'}
1399
1448
cpu: [x64]
1400
1449
os: [win32]
···
1408
1457
engines: {node: '>=10'}
1409
1458
1410
1459
loadjs@4.3.0:
1411
1411
-
resolution: {integrity: sha512-vNX4ZZLJBeDEOBvdr2v/F+0aN5oMuPu7JTqrMwp+DtgK+AryOlpy6Xtm2/HpNr+azEa828oQjOtWsB6iDtSfSQ==, tarball: https://registry.npmjs.org/loadjs/-/loadjs-4.3.0.tgz}
1460
1460
+
resolution: {integrity: sha512-vNX4ZZLJBeDEOBvdr2v/F+0aN5oMuPu7JTqrMwp+DtgK+AryOlpy6Xtm2/HpNr+azEa828oQjOtWsB6iDtSfSQ==}
1412
1461
1413
1462
locate-character@3.0.0:
1414
1463
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
···
1429
1478
hasBin: true
1430
1479
1431
1480
miniflare@4.20260305.0:
1432
1432
-
resolution: {integrity: sha512-jVhtKJtiwaZa3rI+WgoLvSJmEazDsoUmAPYRUmEe2VO6VSbvkhbnDRm+dsPbYRatgNIExwrpqG1rv96jHiSb0w==, tarball: https://registry.npmjs.org/miniflare/-/miniflare-4.20260305.0.tgz}
1481
1481
+
resolution: {integrity: sha512-jVhtKJtiwaZa3rI+WgoLvSJmEazDsoUmAPYRUmEe2VO6VSbvkhbnDRm+dsPbYRatgNIExwrpqG1rv96jHiSb0w==}
1433
1482
engines: {node: '>=18.0.0'}
1434
1483
hasBin: true
1435
1484
···
1438
1487
engines: {node: 18 || 20 || >=22}
1439
1488
1440
1489
mode-watcher@1.1.0:
1441
1441
-
resolution: {integrity: sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g==, tarball: https://registry.npmjs.org/mode-watcher/-/mode-watcher-1.1.0.tgz}
1490
1490
+
resolution: {integrity: sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g==}
1442
1491
peerDependencies:
1443
1492
svelte: ^5.27.0
1444
1493
···
1497
1546
engines: {node: '>=8'}
1498
1547
1499
1548
path-to-regexp@6.3.0:
1500
1500
-
resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==, tarball: https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz}
1549
1549
+
resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
1501
1550
1502
1551
pathe@2.0.3:
1503
1503
-
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==, tarball: https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz}
1552
1552
+
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
1504
1553
1505
1554
picocolors@1.1.1:
1506
1555
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
···
1510
1559
engines: {node: '>=12'}
1511
1560
1512
1561
plyr@3.8.4:
1513
1513
-
resolution: {integrity: sha512-DrzLbK9Wol3zeiuZCleD9aUOl0KAaBHR9H6WVVVYPZ4Ya+LYxUFTgSF1jooHcMQCv96Ws96wCaZzIoP3bES8pQ==, tarball: https://registry.npmjs.org/plyr/-/plyr-3.8.4.tgz}
1562
1562
+
resolution: {integrity: sha512-DrzLbK9Wol3zeiuZCleD9aUOl0KAaBHR9H6WVVVYPZ4Ya+LYxUFTgSF1jooHcMQCv96Ws96wCaZzIoP3bES8pQ==}
1514
1563
1515
1564
postcss-load-config@3.1.4:
1516
1565
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
···
1619
1668
engines: {node: '>=6'}
1620
1669
1621
1670
rangetouch@2.0.1:
1622
1622
-
resolution: {integrity: sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==, tarball: https://registry.npmjs.org/rangetouch/-/rangetouch-2.0.1.tgz}
1671
1671
+
resolution: {integrity: sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==}
1623
1672
1624
1673
readdirp@4.1.2:
1625
1674
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
···
1638
1687
hasBin: true
1639
1688
1640
1689
runed@0.23.4:
1641
1641
-
resolution: {integrity: sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==, tarball: https://registry.npmjs.org/runed/-/runed-0.23.4.tgz}
1690
1690
+
resolution: {integrity: sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==}
1642
1691
peerDependencies:
1643
1692
svelte: ^5.7.0
1644
1693
1645
1694
runed@0.25.0:
1646
1646
-
resolution: {integrity: sha512-7+ma4AG9FT2sWQEA0Egf6mb7PBT2vHyuHail1ie8ropfSjvZGtEAx8YTmUjv/APCsdRRxEVvArNjALk9zFSOrg==, tarball: https://registry.npmjs.org/runed/-/runed-0.25.0.tgz}
1695
1695
+
resolution: {integrity: sha512-7+ma4AG9FT2sWQEA0Egf6mb7PBT2vHyuHail1ie8ropfSjvZGtEAx8YTmUjv/APCsdRRxEVvArNjALk9zFSOrg==}
1647
1696
peerDependencies:
1648
1697
svelte: ^5.7.0
1649
1698
1650
1699
runed@0.28.0:
1651
1651
-
resolution: {integrity: sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ==, tarball: https://registry.npmjs.org/runed/-/runed-0.28.0.tgz}
1700
1700
+
resolution: {integrity: sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ==}
1652
1701
peerDependencies:
1653
1702
svelte: ^5.7.0
1654
1703
···
1674
1723
resolution: {integrity: sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==}
1675
1724
1676
1725
sharp@0.34.5:
1677
1677
-
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==, tarball: https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz}
1726
1726
+
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
1678
1727
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
1679
1728
1680
1729
shebang-command@2.0.0:
···
1697
1746
resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==}
1698
1747
1699
1748
supports-color@10.2.2:
1700
1700
-
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==, tarball: https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz}
1749
1749
+
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
1701
1750
engines: {node: '>=18'}
1702
1751
1703
1752
svelte-check@4.4.4:
···
1718
1767
optional: true
1719
1768
1720
1769
svelte-sonner@1.0.7:
1721
1721
-
resolution: {integrity: sha512-1EUFYmd7q/xfs2qCHwJzGPh9n5VJ3X6QjBN10fof2vxgy8fYE7kVfZ7uGnd7i6fQaWIr5KvXcwYXE/cmTEjk5A==, tarball: https://registry.npmjs.org/svelte-sonner/-/svelte-sonner-1.0.7.tgz}
1770
1770
+
resolution: {integrity: sha512-1EUFYmd7q/xfs2qCHwJzGPh9n5VJ3X6QjBN10fof2vxgy8fYE7kVfZ7uGnd7i6fQaWIr5KvXcwYXE/cmTEjk5A==}
1722
1771
peerDependencies:
1723
1772
svelte: ^5.0.0
1724
1773
···
1729
1778
svelte: ^5.30.2
1730
1779
1731
1780
svelte-toolbelt@0.7.1:
1732
1732
-
resolution: {integrity: sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==, tarball: https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.7.1.tgz}
1781
1781
+
resolution: {integrity: sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==}
1733
1782
engines: {node: '>=18', pnpm: '>=8.7.0'}
1734
1783
peerDependencies:
1735
1784
svelte: ^5.0.0
···
1745
1794
resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==}
1746
1795
1747
1796
tailwind-variants@3.2.2:
1748
1748
-
resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==, tarball: https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-3.2.2.tgz}
1797
1797
+
resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==}
1749
1798
engines: {node: '>=16.x', pnpm: '>=7.x'}
1750
1799
peerDependencies:
1751
1800
tailwind-merge: '>=3.0.0'
···
1776
1825
typescript: '>=4.8.4'
1777
1826
1778
1827
tslib@2.8.1:
1779
1779
-
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, tarball: https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz}
1828
1828
+
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
1780
1829
1781
1830
tsx@4.21.0:
1782
1831
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
···
1803
1852
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
1804
1853
1805
1854
undici@7.18.2:
1806
1806
-
resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==, tarball: https://registry.npmjs.org/undici/-/undici-7.18.2.tgz}
1855
1855
+
resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==}
1807
1856
engines: {node: '>=20.18.1'}
1808
1857
1809
1858
unenv@2.0.0-rc.24:
1810
1810
-
resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==, tarball: https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz}
1859
1859
+
resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==}
1811
1860
1812
1861
unicode-segmenter@0.14.5:
1813
1862
resolution: {integrity: sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==}
···
1816
1865
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
1817
1866
1818
1867
url-polyfill@1.1.14:
1819
1819
-
resolution: {integrity: sha512-p4f3TTAG6ADVF3mwbXw7hGw+QJyw5CnNGvYh5fCuQQZIiuKUswqcznyV3pGDP9j0TSmC4UvRKm8kl1QsX1diiQ==, tarball: https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.14.tgz}
1868
1868
+
resolution: {integrity: sha512-p4f3TTAG6ADVF3mwbXw7hGw+QJyw5CnNGvYh5fCuQQZIiuKUswqcznyV3pGDP9j0TSmC4UvRKm8kl1QsX1diiQ==}
1820
1869
1821
1870
util-deprecate@1.0.2:
1822
1871
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
···
1887
1936
engines: {node: '>=0.10.0'}
1888
1937
1889
1938
workerd@1.20260305.0:
1890
1890
-
resolution: {integrity: sha512-JkhfCLU+w+KbQmZ9k49IcDYc78GBo7eG8Mir8E2+KVjR7otQAmpcLlsous09YLh8WQ3Bt3Mi6/WMStvMAPukeA==, tarball: https://registry.npmjs.org/workerd/-/workerd-1.20260305.0.tgz}
1939
1939
+
resolution: {integrity: sha512-JkhfCLU+w+KbQmZ9k49IcDYc78GBo7eG8Mir8E2+KVjR7otQAmpcLlsous09YLh8WQ3Bt3Mi6/WMStvMAPukeA==}
1891
1940
engines: {node: '>=16'}
1892
1941
hasBin: true
1893
1942
···
1896
1945
engines: {node: '>=12'}
1897
1946
1898
1947
wrangler@4.69.0:
1899
1899
-
resolution: {integrity: sha512-EmVfIM65I5b4ITHe3Y9R7zQyf4NUBQ1leStakMlWiVR9n6VlDwuEltyQI2l3i0JciDnWyR3uqe+T6C08ivniTQ==, tarball: https://registry.npmjs.org/wrangler/-/wrangler-4.69.0.tgz}
1948
1948
+
resolution: {integrity: sha512-EmVfIM65I5b4ITHe3Y9R7zQyf4NUBQ1leStakMlWiVR9n6VlDwuEltyQI2l3i0JciDnWyR3uqe+T6C08ivniTQ==}
1900
1949
engines: {node: '>=20.0.0'}
1901
1950
hasBin: true
1902
1951
peerDependencies:
···
1906
1955
optional: true
1907
1956
1908
1957
ws@8.18.0:
1909
1909
-
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==, tarball: https://registry.npmjs.org/ws/-/ws-8.18.0.tgz}
1958
1958
+
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
1910
1959
engines: {node: '>=10.0.0'}
1911
1960
peerDependencies:
1912
1961
bufferutil: ^4.0.1
···
1926
1975
engines: {node: '>=10'}
1927
1976
1928
1977
youch-core@0.3.3:
1929
1929
-
resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==, tarball: https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz}
1978
1978
+
resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==}
1930
1979
1931
1980
youch@4.1.0-beta.10:
1932
1932
-
resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==, tarball: https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz}
1981
1981
+
resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==}
1933
1982
1934
1983
zimmerframe@1.1.4:
1935
1984
resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==}
···
2056
2105
dependencies:
2057
2106
'@jridgewell/trace-mapping': 0.3.9
2058
2107
2108
2108
+
'@emnapi/core@1.8.1':
2109
2109
+
dependencies:
2110
2110
+
'@emnapi/wasi-threads': 1.1.0
2111
2111
+
tslib: 2.8.1
2112
2112
+
2059
2113
'@emnapi/runtime@1.8.1':
2060
2114
dependencies:
2061
2115
tslib: 2.8.1
2062
2062
-
optional: true
2116
2116
+
2117
2117
+
'@emnapi/wasi-threads@1.1.0':
2118
2118
+
dependencies:
2119
2119
+
tslib: 2.8.1
2063
2120
2064
2121
'@esbuild/aix-ppc64@0.27.3':
2065
2122
optional: true
···
2370
2427
'@jridgewell/resolve-uri': 3.1.2
2371
2428
'@jridgewell/sourcemap-codec': 1.5.5
2372
2429
2430
2430
+
'@napi-rs/wasm-runtime@1.1.1':
2431
2431
+
dependencies:
2432
2432
+
'@emnapi/core': 1.8.1
2433
2433
+
'@emnapi/runtime': 1.8.1
2434
2434
+
'@tybys/wasm-util': 0.10.1
2435
2435
+
2373
2436
'@number-flow/svelte@0.3.13(svelte@5.53.6)':
2374
2437
dependencies:
2375
2438
esm-env: 1.2.2
···
2596
2659
tailwindcss: 4.2.1
2597
2660
vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
2598
2661
2662
2662
+
'@tursodatabase/database-common@0.5.0': {}
2663
2663
+
2664
2664
+
'@tursodatabase/database-wasm-common@0.5.0':
2665
2665
+
dependencies:
2666
2666
+
'@napi-rs/wasm-runtime': 1.1.1
2667
2667
+
2668
2668
+
'@tursodatabase/database-wasm@0.5.0':
2669
2669
+
dependencies:
2670
2670
+
'@tursodatabase/database-common': 0.5.0
2671
2671
+
'@tursodatabase/database-wasm-common': 0.5.0
2672
2672
+
2673
2673
+
'@tybys/wasm-util@0.10.1':
2674
2674
+
dependencies:
2675
2675
+
tslib: 2.8.1
2676
2676
+
2599
2677
'@types/bun@1.3.10':
2600
2678
dependencies:
2601
2679
bun-types: 1.3.10
···
2789
2867
2790
2868
devalue@5.6.3: {}
2791
2869
2792
2792
-
dexie@4.3.0: {}
2793
2793
-
2794
2870
dompurify@3.3.1:
2795
2871
optionalDependencies:
2796
2872
'@types/trusted-types': 2.0.7
···
2967
3043
keyv: 4.5.4
2968
3044
2969
3045
flatted@3.3.4: {}
2970
2970
-
2971
2971
-
flexsearch@0.8.212: {}
2972
3046
2973
3047
fsevents@2.3.3:
2974
3048
optional: true
···
6
6
event.locals.session = session;
7
7
event.locals.client = client;
8
8
event.locals.did = did;
9
9
-
return resolve(event);
9
9
+
10
10
+
const response = await resolve(event);
11
11
+
12
12
+
// Required for @tursodatabase/database-wasm (OPFS + SharedArrayBuffer)
13
13
+
response.headers.set('Cross-Origin-Opener-Policy', 'same-origin');
14
14
+
response.headers.set('Cross-Origin-Embedder-Policy', 'credentialless');
15
15
+
16
16
+
return response;
10
17
};
···
1
1
-
import Dexie, { type EntityTable } from 'dexie';
1
1
+
import type { Database } from '@tursodatabase/database-wasm/vite';
2
2
+
3
3
+
export type SourceType = 'likes' | 'bookmarks' | 'posts' | 'reposts';
4
4
+
export const ALL_SOURCES: SourceType[] = ['likes', 'bookmarks', 'posts', 'reposts'];
5
5
+
6
6
+
let dbInstance: Database | null = null;
7
7
+
let dbReady: Promise<Database> | null = null;
8
8
+
9
9
+
const SCHEMA_VERSION = 2;
10
10
+
11
11
+
export async function getDb(): Promise<Database> {
12
12
+
if (dbInstance) return dbInstance;
13
13
+
if (dbReady) return dbReady;
14
14
+
dbReady = initDb();
15
15
+
dbInstance = await dbReady;
16
16
+
return dbInstance;
17
17
+
}
18
18
+
19
19
+
async function initDb(): Promise<Database> {
20
20
+
const { connect } = await import('@tursodatabase/database-wasm/vite');
21
21
+
const db: Database = await connect('atmo.db');
22
22
+
23
23
+
await db.exec('PRAGMA journal_mode = WAL');
24
24
+
await db.exec('PRAGMA foreign_keys = ON');
25
25
+
26
26
+
await db.exec(`CREATE TABLE IF NOT EXISTS schema_version (version INTEGER PRIMARY KEY)`);
27
27
+
const row = await (await db.prepare('SELECT version FROM schema_version ORDER BY version DESC LIMIT 1')).get() as
28
28
+
| { version: number }
29
29
+
| undefined;
30
30
+
const currentVersion = row?.version ?? 0;
31
31
+
32
32
+
if (currentVersion < SCHEMA_VERSION) {
33
33
+
await applyMigrations(db, currentVersion);
34
34
+
}
35
35
+
36
36
+
// Clean up legacy IndexedDB databases from Dexie + FlexSearch
37
37
+
if (typeof indexedDB !== 'undefined') {
38
38
+
try {
39
39
+
const dbs = await indexedDB.databases();
40
40
+
for (const dbInfo of dbs) {
41
41
+
if (dbInfo.name) indexedDB.deleteDatabase(dbInfo.name);
42
42
+
}
43
43
+
} catch {
44
44
+
// databases() may not be supported in all browsers
45
45
+
}
46
46
+
}
47
47
+
48
48
+
// Clean up legacy localStorage
49
49
+
for (const source of ALL_SOURCES) {
50
50
+
localStorage.removeItem(`${source}-ids`);
51
51
+
localStorage.removeItem(`${source}-cursor`);
52
52
+
}
53
53
+
54
54
+
return db;
55
55
+
}
56
56
+
57
57
+
async function applyMigrations(db: Database, fromVersion: number) {
58
58
+
if (fromVersion < 1) {
59
59
+
// Drop any partially-created tables from a previous failed migration
60
60
+
await db.exec(`
61
61
+
DROP TABLE IF EXISTS post_sources;
62
62
+
DROP TABLE IF EXISTS sync_cursors;
63
63
+
DROP TABLE IF EXISTS posts;
64
64
+
DROP TABLE IF EXISTS accounts;
65
65
+
`);
66
66
+
await db.exec(`
67
67
+
CREATE TABLE IF NOT EXISTS accounts (
68
68
+
did TEXT PRIMARY KEY,
69
69
+
handle TEXT NOT NULL,
70
70
+
display_name TEXT,
71
71
+
avatar TEXT,
72
72
+
added_at INTEGER NOT NULL DEFAULT (unixepoch('now'))
73
73
+
);
2
74
3
3
-
export interface StoredPost {
75
75
+
CREATE TABLE IF NOT EXISTS posts (
76
76
+
uri TEXT PRIMARY KEY,
77
77
+
author_did TEXT NOT NULL,
78
78
+
author_handle TEXT NOT NULL DEFAULT '',
79
79
+
author_display_name TEXT NOT NULL DEFAULT '',
80
80
+
text TEXT NOT NULL DEFAULT '',
81
81
+
created_at TEXT,
82
82
+
like_count INTEGER NOT NULL DEFAULT 0,
83
83
+
repost_count INTEGER NOT NULL DEFAULT 0,
84
84
+
reply_count INTEGER NOT NULL DEFAULT 0,
85
85
+
has_image INTEGER NOT NULL DEFAULT 0,
86
86
+
has_video INTEGER NOT NULL DEFAULT 0,
87
87
+
has_link INTEGER NOT NULL DEFAULT 0,
88
88
+
is_reply INTEGER NOT NULL DEFAULT 0,
89
89
+
embed_type TEXT,
90
90
+
embed_title TEXT NOT NULL DEFAULT '',
91
91
+
embed_description TEXT NOT NULL DEFAULT '',
92
92
+
quote_text TEXT NOT NULL DEFAULT '',
93
93
+
quote_author_handle TEXT NOT NULL DEFAULT '',
94
94
+
search_text TEXT NOT NULL DEFAULT '',
95
95
+
raw TEXT NOT NULL,
96
96
+
saved_at INTEGER NOT NULL,
97
97
+
fetched_at INTEGER NOT NULL
98
98
+
);
99
99
+
100
100
+
CREATE TABLE IF NOT EXISTS post_sources (
101
101
+
uri TEXT NOT NULL REFERENCES posts(uri) ON DELETE CASCADE,
102
102
+
account_did TEXT NOT NULL REFERENCES accounts(did) ON DELETE CASCADE,
103
103
+
source TEXT NOT NULL CHECK(source IN ('likes','bookmarks','posts','reposts')),
104
104
+
PRIMARY KEY (uri, account_did, source)
105
105
+
);
106
106
+
107
107
+
CREATE TABLE IF NOT EXISTS sync_cursors (
108
108
+
account_did TEXT NOT NULL,
109
109
+
source TEXT NOT NULL CHECK(source IN ('likes','bookmarks','posts','reposts')),
110
110
+
tail_cursor TEXT,
111
111
+
PRIMARY KEY (account_did, source)
112
112
+
);
113
113
+
114
114
+
-- Indexes for common query patterns
115
115
+
CREATE INDEX IF NOT EXISTS idx_posts_created_at ON posts(created_at DESC);
116
116
+
CREATE INDEX IF NOT EXISTS idx_posts_like_count ON posts(like_count);
117
117
+
CREATE INDEX IF NOT EXISTS idx_posts_repost_count ON posts(repost_count);
118
118
+
CREATE INDEX IF NOT EXISTS idx_posts_reply_count ON posts(reply_count);
119
119
+
CREATE INDEX IF NOT EXISTS idx_posts_author_handle ON posts(author_handle);
120
120
+
CREATE INDEX IF NOT EXISTS idx_posts_author_did ON posts(author_did);
121
121
+
CREATE INDEX IF NOT EXISTS idx_post_sources_account ON post_sources(account_did, source);
122
122
+
CREATE INDEX IF NOT EXISTS idx_post_sources_uri ON post_sources(uri);
123
123
+
`);
124
124
+
125
125
+
}
126
126
+
127
127
+
if (fromVersion >= 1 && fromVersion < 2) {
128
128
+
// v2: Added search_text column, removed FTS5.
129
129
+
// Easiest to drop and recreate since there's no user-created data to preserve.
130
130
+
await db.exec(`
131
131
+
DROP TABLE IF EXISTS post_sources;
132
132
+
DROP TABLE IF EXISTS sync_cursors;
133
133
+
DROP TABLE IF EXISTS posts;
134
134
+
DROP TABLE IF EXISTS accounts;
135
135
+
`);
136
136
+
// Re-create tables with the current v1 DDL (which includes search_text)
137
137
+
fromVersion = 0;
138
138
+
await applyMigrations(db, fromVersion);
139
139
+
}
140
140
+
141
141
+
await (await db.prepare('INSERT OR REPLACE INTO schema_version (version) VALUES (?)')).run(SCHEMA_VERSION);
142
142
+
}
143
143
+
144
144
+
// --- PostView field extraction ---
145
145
+
146
146
+
export interface ExtractedPost {
4
147
uri: string;
5
5
-
sources: string[];
6
6
-
savedAt: number;
7
7
-
fetchedAt: number;
8
8
-
// PostView fields stored inline
9
9
-
[key: string]: any;
148
148
+
author_did: string;
149
149
+
author_handle: string;
150
150
+
author_display_name: string;
151
151
+
text: string;
152
152
+
created_at: string | null;
153
153
+
like_count: number;
154
154
+
repost_count: number;
155
155
+
reply_count: number;
156
156
+
has_image: number;
157
157
+
has_video: number;
158
158
+
has_link: number;
159
159
+
is_reply: number;
160
160
+
embed_type: string | null;
161
161
+
embed_title: string;
162
162
+
embed_description: string;
163
163
+
quote_text: string;
164
164
+
quote_author_handle: string;
165
165
+
search_text: string;
166
166
+
raw: string;
167
167
+
saved_at: number;
168
168
+
fetched_at: number;
10
169
}
11
170
12
12
-
export interface SourceMeta {
13
13
-
source: string;
14
14
-
tailCursor?: string; // deepest point reached paginating into the past
171
171
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
172
172
+
export function extractPostFields(postView: any, savedAt: number, fetchedAt: number): ExtractedPost {
173
173
+
const embed = postView.embed;
174
174
+
const record = postView.record;
175
175
+
176
176
+
let hasImage = 0,
177
177
+
hasVideo = 0,
178
178
+
hasLink = 0;
179
179
+
let embedType: string | null = null;
180
180
+
let embedTitle = '',
181
181
+
embedDescription = '';
182
182
+
let quoteText = '',
183
183
+
quoteAuthorHandle = '';
184
184
+
185
185
+
if (embed) {
186
186
+
embedType = embed.$type;
187
187
+
188
188
+
if (embed.$type === 'app.bsky.embed.images#view') {
189
189
+
hasImage = 1;
190
190
+
} else if (embed.$type === 'app.bsky.embed.video#view') {
191
191
+
hasVideo = 1;
192
192
+
} else if (embed.$type === 'app.bsky.embed.external#view') {
193
193
+
hasLink = 1;
194
194
+
embedTitle = embed.external?.title ?? '';
195
195
+
embedDescription = embed.external?.description ?? '';
196
196
+
} else if (embed.$type === 'app.bsky.embed.record#view') {
197
197
+
const embeddedRecord = embed.record;
198
198
+
if (embeddedRecord?.value?.text) {
199
199
+
quoteText = embeddedRecord.value.text;
200
200
+
quoteAuthorHandle = embeddedRecord.author?.handle ?? '';
201
201
+
}
202
202
+
} else if (embed.$type === 'app.bsky.embed.recordWithMedia#view') {
203
203
+
const media = embed.media;
204
204
+
if (media?.$type === 'app.bsky.embed.images#view') hasImage = 1;
205
205
+
if (media?.$type === 'app.bsky.embed.video#view') hasVideo = 1;
206
206
+
if (media?.$type === 'app.bsky.embed.external#view') {
207
207
+
hasLink = 1;
208
208
+
embedTitle = media.external?.title ?? '';
209
209
+
embedDescription = media.external?.description ?? '';
210
210
+
}
211
211
+
const embeddedRecord = embed.record?.record;
212
212
+
if (embeddedRecord?.value?.text) {
213
213
+
quoteText = embeddedRecord.value.text;
214
214
+
quoteAuthorHandle = embeddedRecord.author?.handle ?? '';
215
215
+
}
216
216
+
}
217
217
+
}
218
218
+
219
219
+
// Check for links in facets
220
220
+
if (!hasLink && Array.isArray(record?.facets)) {
221
221
+
hasLink = record.facets.some(
222
222
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
223
223
+
(f: any) => f.features?.some((feat: any) => feat.$type === 'app.bsky.richtext.facet#link')
224
224
+
)
225
225
+
? 1
226
226
+
: 0;
227
227
+
}
228
228
+
229
229
+
const authorHandle = postView.author?.handle ?? '';
230
230
+
const authorDisplayName = postView.author?.displayName ?? '';
231
231
+
const postText = record?.text ?? '';
232
232
+
233
233
+
// Concatenate all searchable fields, lowercased, for LIKE-based search
234
234
+
const searchText = [authorHandle, authorDisplayName, postText, embedTitle, embedDescription, quoteText, quoteAuthorHandle]
235
235
+
.filter(Boolean)
236
236
+
.join(' ')
237
237
+
.toLowerCase();
238
238
+
239
239
+
return {
240
240
+
uri: postView.uri,
241
241
+
author_did: postView.author?.did ?? '',
242
242
+
author_handle: authorHandle,
243
243
+
author_display_name: authorDisplayName,
244
244
+
text: postText,
245
245
+
created_at: record?.createdAt ?? null,
246
246
+
like_count: postView.likeCount ?? 0,
247
247
+
repost_count: postView.repostCount ?? 0,
248
248
+
reply_count: postView.replyCount ?? 0,
249
249
+
has_image: hasImage,
250
250
+
has_video: hasVideo,
251
251
+
has_link: hasLink,
252
252
+
is_reply: record?.reply ? 1 : 0,
253
253
+
embed_type: embedType,
254
254
+
embed_title: embedTitle,
255
255
+
embed_description: embedDescription,
256
256
+
quote_text: quoteText,
257
257
+
quote_author_handle: quoteAuthorHandle,
258
258
+
search_text: searchText,
259
259
+
raw: JSON.stringify(postView),
260
260
+
saved_at: savedAt,
261
261
+
fetched_at: fetchedAt
262
262
+
};
15
263
}
16
264
17
17
-
export const db = new Dexie('atmo') as Dexie & {
18
18
-
posts: EntityTable<StoredPost, 'uri'>;
19
19
-
meta: EntityTable<SourceMeta, 'source'>;
265
265
+
// --- CRUD helpers ---
266
266
+
267
267
+
export async function upsertAccount(
268
268
+
db: Database,
269
269
+
did: string,
270
270
+
handle: string,
271
271
+
displayName?: string | null,
272
272
+
avatar?: string | null
273
273
+
) {
274
274
+
await (await db.prepare(
275
275
+
`INSERT INTO accounts (did, handle, display_name, avatar)
276
276
+
VALUES (?, ?, ?, ?)
277
277
+
ON CONFLICT(did) DO UPDATE SET
278
278
+
handle = excluded.handle,
279
279
+
display_name = excluded.display_name,
280
280
+
avatar = excluded.avatar`
281
281
+
)).run(did, handle, displayName ?? null, avatar ?? null);
282
282
+
}
283
283
+
284
284
+
export async function getAccounts(db: Database): Promise<{ did: string; handle: string; display_name: string | null }[]> {
285
285
+
return (await db.prepare('SELECT did, handle, display_name FROM accounts ORDER BY added_at')).all() as {
286
286
+
did: string;
287
287
+
handle: string;
288
288
+
display_name: string | null;
289
289
+
}[];
290
290
+
}
291
291
+
292
292
+
export async function postExistsForSource(
293
293
+
db: Database,
294
294
+
uri: string,
295
295
+
accountDid: string,
296
296
+
source: SourceType
297
297
+
): Promise<boolean> {
298
298
+
const row = await (await db.prepare(
299
299
+
'SELECT 1 FROM post_sources WHERE uri = ? AND account_did = ? AND source = ?'
300
300
+
)).get(uri, accountDid, source);
301
301
+
return !!row;
302
302
+
}
303
303
+
304
304
+
export async function postExists(db: Database, uri: string): Promise<boolean> {
305
305
+
const row = await (await db.prepare('SELECT 1 FROM posts WHERE uri = ?')).get(uri);
306
306
+
return !!row;
307
307
+
}
308
308
+
309
309
+
export async function getSourceCount(db: Database, accountDid: string, source: SourceType): Promise<number> {
310
310
+
const row = await (await db.prepare(
311
311
+
'SELECT COUNT(*) as count FROM post_sources WHERE account_did = ? AND source = ?'
312
312
+
)).get(accountDid, source) as { count: number } | undefined;
313
313
+
return row?.count ?? 0;
314
314
+
}
315
315
+
316
316
+
export async function getCursor(db: Database, accountDid: string, source: SourceType): Promise<string | undefined> {
317
317
+
const row = await (await db.prepare(
318
318
+
'SELECT tail_cursor FROM sync_cursors WHERE account_did = ? AND source = ?'
319
319
+
)).get(accountDid, source) as { tail_cursor: string | null } | undefined;
320
320
+
return row?.tail_cursor ?? undefined;
321
321
+
}
322
322
+
323
323
+
export async function setCursor(db: Database, accountDid: string, source: SourceType, cursor: string | undefined) {
324
324
+
await (await db.prepare(
325
325
+
`INSERT OR REPLACE INTO sync_cursors (account_did, source, tail_cursor)
326
326
+
VALUES (?, ?, ?)`
327
327
+
)).run(accountDid, source, cursor ?? null);
328
328
+
}
329
329
+
330
330
+
// --- Batch operations ---
331
331
+
332
332
+
export async function bulkUpsertPosts(
333
333
+
db: Database,
334
334
+
posts: ExtractedPost[],
335
335
+
accountDid: string,
336
336
+
source: SourceType
337
337
+
): Promise<number> {
338
338
+
if (posts.length === 0) return 0;
339
339
+
340
340
+
const insertPost = await db.prepare(
341
341
+
`INSERT INTO posts (uri, author_did, author_handle, author_display_name, text,
342
342
+
created_at, like_count, repost_count, reply_count, has_image, has_video,
343
343
+
has_link, is_reply, embed_type, embed_title, embed_description,
344
344
+
quote_text, quote_author_handle, search_text, raw, saved_at, fetched_at)
345
345
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
346
346
+
ON CONFLICT(uri) DO UPDATE SET
347
347
+
like_count = excluded.like_count,
348
348
+
repost_count = excluded.repost_count,
349
349
+
reply_count = excluded.reply_count,
350
350
+
raw = excluded.raw,
351
351
+
fetched_at = excluded.fetched_at`
352
352
+
);
353
353
+
354
354
+
const insertSource = await db.prepare(
355
355
+
`INSERT OR IGNORE INTO post_sources (uri, account_did, source) VALUES (?, ?, ?)`
356
356
+
);
357
357
+
358
358
+
let count = 0;
359
359
+
await db.exec('BEGIN TRANSACTION');
360
360
+
try {
361
361
+
for (const post of posts) {
362
362
+
await insertPost.run(
363
363
+
post.uri,
364
364
+
post.author_did,
365
365
+
post.author_handle,
366
366
+
post.author_display_name,
367
367
+
post.text,
368
368
+
post.created_at,
369
369
+
post.like_count,
370
370
+
post.repost_count,
371
371
+
post.reply_count,
372
372
+
post.has_image,
373
373
+
post.has_video,
374
374
+
post.has_link,
375
375
+
post.is_reply,
376
376
+
post.embed_type,
377
377
+
post.embed_title,
378
378
+
post.embed_description,
379
379
+
post.quote_text,
380
380
+
post.quote_author_handle,
381
381
+
post.search_text,
382
382
+
post.raw,
383
383
+
post.saved_at,
384
384
+
post.fetched_at
385
385
+
);
386
386
+
await insertSource.run(post.uri, accountDid, source);
387
387
+
count++;
388
388
+
}
389
389
+
await db.exec('COMMIT');
390
390
+
} catch (e) {
391
391
+
await db.exec('ROLLBACK');
392
392
+
throw e;
393
393
+
}
394
394
+
return count;
395
395
+
}
396
396
+
397
397
+
/**
398
398
+
* Tag existing posts with a source for this account (they already exist from another source).
399
399
+
* Returns number of posts that were newly tagged.
400
400
+
*/
401
401
+
export async function tagExistingPosts(
402
402
+
db: Database,
403
403
+
uris: string[],
404
404
+
accountDid: string,
405
405
+
source: SourceType
406
406
+
): Promise<number> {
407
407
+
if (uris.length === 0) return 0;
408
408
+
409
409
+
const insertSource = await db.prepare(
410
410
+
`INSERT OR IGNORE INTO post_sources (uri, account_did, source) VALUES (?, ?, ?)`
411
411
+
);
412
412
+
413
413
+
let count = 0;
414
414
+
await db.exec('BEGIN TRANSACTION');
415
415
+
try {
416
416
+
for (const uri of uris) {
417
417
+
const result = await insertSource.run(uri, accountDid, source);
418
418
+
if (result.changes > 0) count++;
419
419
+
}
420
420
+
await db.exec('COMMIT');
421
421
+
} catch (e) {
422
422
+
await db.exec('ROLLBACK');
423
423
+
throw e;
424
424
+
}
425
425
+
return count;
426
426
+
}
427
427
+
428
428
+
// --- Search ---
429
429
+
430
430
+
export type SearchFilters = {
431
431
+
handles: string[];
432
432
+
minLikes: number;
433
433
+
minReposts: number;
434
434
+
minReplies: number;
435
435
+
dateAfter: string;
436
436
+
dateBefore: string;
437
437
+
hasImage: boolean;
438
438
+
hasLink: boolean;
439
439
+
hasVideo: boolean;
440
440
+
showReplies: boolean;
20
441
};
21
442
22
22
-
db.version(1).stores({
23
23
-
posts: 'uri, *sources, savedAt, fetchedAt, likeCount, repostCount, replyCount',
24
24
-
meta: 'source'
25
25
-
});
443
443
+
export const DEFAULT_FILTERS: SearchFilters = {
444
444
+
handles: [],
445
445
+
minLikes: 0,
446
446
+
minReposts: 0,
447
447
+
minReplies: 0,
448
448
+
dateAfter: '',
449
449
+
dateBefore: '',
450
450
+
hasImage: false,
451
451
+
hasLink: false,
452
452
+
hasVideo: false,
453
453
+
showReplies: true
454
454
+
};
455
455
+
456
456
+
export function filtersActive(filters: SearchFilters): boolean {
457
457
+
return (
458
458
+
filters.handles.length > 0 ||
459
459
+
filters.minLikes > 0 ||
460
460
+
filters.minReposts > 0 ||
461
461
+
filters.minReplies > 0 ||
462
462
+
!!filters.dateAfter ||
463
463
+
!!filters.dateBefore ||
464
464
+
filters.hasImage ||
465
465
+
filters.hasLink ||
466
466
+
filters.hasVideo ||
467
467
+
!filters.showReplies
468
468
+
);
469
469
+
}
470
470
+
471
471
+
export interface SearchParams {
472
472
+
query: string;
473
473
+
filters: SearchFilters;
474
474
+
sources: SourceType[];
475
475
+
accountDids: string[];
476
476
+
limit: number;
477
477
+
offset: number;
478
478
+
}
479
479
+
480
480
+
export interface SearchResult {
481
481
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
482
482
+
doc: any;
483
483
+
isLiked: boolean;
484
484
+
isBookmarked: boolean;
485
485
+
}
486
486
+
487
487
+
export async function searchPosts(
488
488
+
db: Database,
489
489
+
params: SearchParams
490
490
+
): Promise<{ results: SearchResult[]; hasMore: boolean }> {
491
491
+
const conditions: string[] = [];
492
492
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
493
493
+
const bindings: any[] = [];
494
494
+
495
495
+
// Source filter
496
496
+
if (params.sources.length > 0) {
497
497
+
const placeholders = params.sources.map(() => '?').join(', ');
498
498
+
conditions.push(`ps.source IN (${placeholders})`);
499
499
+
bindings.push(...params.sources);
500
500
+
}
501
501
+
502
502
+
// Account filter
503
503
+
if (params.accountDids.length > 0) {
504
504
+
const placeholders = params.accountDids.map(() => '?').join(', ');
505
505
+
conditions.push(`ps.account_did IN (${placeholders})`);
506
506
+
bindings.push(...params.accountDids);
507
507
+
}
508
508
+
509
509
+
// Text search via LIKE on the pre-built search_text column
510
510
+
if (params.query.trim()) {
511
511
+
const terms = params.query.trim().toLowerCase().split(/\s+/).filter(Boolean);
512
512
+
for (const term of terms) {
513
513
+
conditions.push('p.search_text LIKE ?');
514
514
+
bindings.push(`%${term}%`);
515
515
+
}
516
516
+
}
517
517
+
518
518
+
// Structured filters
519
519
+
if (params.filters.handles.length > 0) {
520
520
+
const handleConditions = params.filters.handles.map(() => 'p.author_handle LIKE ?');
521
521
+
conditions.push(`(${handleConditions.join(' OR ')})`);
522
522
+
bindings.push(...params.filters.handles.map((h) => `%${h.toLowerCase()}%`));
523
523
+
}
524
524
+
if (params.filters.minLikes > 0) {
525
525
+
conditions.push('p.like_count >= ?');
526
526
+
bindings.push(params.filters.minLikes);
527
527
+
}
528
528
+
if (params.filters.minReposts > 0) {
529
529
+
conditions.push('p.repost_count >= ?');
530
530
+
bindings.push(params.filters.minReposts);
531
531
+
}
532
532
+
if (params.filters.minReplies > 0) {
533
533
+
conditions.push('p.reply_count >= ?');
534
534
+
bindings.push(params.filters.minReplies);
535
535
+
}
536
536
+
if (params.filters.dateAfter) {
537
537
+
conditions.push('p.created_at >= ?');
538
538
+
bindings.push(params.filters.dateAfter);
539
539
+
}
540
540
+
if (params.filters.dateBefore) {
541
541
+
const before = new Date(new Date(params.filters.dateBefore).getTime() + 86400000).toISOString();
542
542
+
conditions.push('p.created_at <= ?');
543
543
+
bindings.push(before);
544
544
+
}
545
545
+
if (params.filters.hasImage) {
546
546
+
conditions.push('p.has_image = 1');
547
547
+
}
548
548
+
if (params.filters.hasLink) {
549
549
+
conditions.push('p.has_link = 1');
550
550
+
}
551
551
+
if (params.filters.hasVideo) {
552
552
+
conditions.push('p.has_video = 1');
553
553
+
}
554
554
+
if (!params.filters.showReplies) {
555
555
+
conditions.push('p.is_reply = 0');
556
556
+
}
557
557
+
558
558
+
const whereClause = conditions.length > 0 ? 'WHERE ' + conditions.join(' AND ') : '';
559
559
+
560
560
+
// Always sort by date descending (no relevance ranking without FTS5)
561
561
+
const orderClause = 'ORDER BY p.created_at DESC';
562
562
+
563
563
+
// We need the current user's DID for liked/bookmarked status.
564
564
+
const currentDid = params.accountDids[0] ?? '';
565
565
+
566
566
+
// Build final bindings in positional order:
567
567
+
// 1. currentDid x2 (for EXISTS subqueries in SELECT)
568
568
+
// 2. WHERE clause bindings
569
569
+
// 3. LIMIT, OFFSET
570
570
+
const finalBindings = [currentDid, currentDid, ...bindings, params.limit + 1, params.offset];
571
571
+
572
572
+
const sql = `
573
573
+
SELECT DISTINCT p.raw, p.uri,
574
574
+
EXISTS(SELECT 1 FROM post_sources WHERE uri = p.uri AND account_did = ? AND source = 'likes') as is_liked,
575
575
+
EXISTS(SELECT 1 FROM post_sources WHERE uri = p.uri AND account_did = ? AND source = 'bookmarks') as is_bookmarked
576
576
+
FROM posts p
577
577
+
JOIN post_sources ps ON ps.uri = p.uri
578
578
+
${whereClause}
579
579
+
${orderClause}
580
580
+
LIMIT ? OFFSET ?
581
581
+
`;
582
582
+
583
583
+
const rows = await (await db.prepare(sql)).all(...finalBindings) as {
584
584
+
raw: string;
585
585
+
uri: string;
586
586
+
is_liked: number;
587
587
+
is_bookmarked: number;
588
588
+
}[];
589
589
+
590
590
+
const hasMore = rows.length > params.limit;
591
591
+
const results: SearchResult[] = rows.slice(0, params.limit).map((row) => ({
592
592
+
doc: JSON.parse(row.raw),
593
593
+
isLiked: row.is_liked === 1,
594
594
+
isBookmarked: row.is_bookmarked === 1
595
595
+
}));
596
596
+
597
597
+
return { results, hasMore };
598
598
+
}
599
599
+
600
600
+
// --- Clear operations ---
601
601
+
602
602
+
export async function clearSource(db: Database, accountDid: string, source: SourceType) {
603
603
+
await db.exec('BEGIN TRANSACTION');
604
604
+
try {
605
605
+
await (await db.prepare('DELETE FROM post_sources WHERE account_did = ? AND source = ?')).run(
606
606
+
accountDid,
607
607
+
source
608
608
+
);
609
609
+
await (await db.prepare('DELETE FROM sync_cursors WHERE account_did = ? AND source = ?')).run(
610
610
+
accountDid,
611
611
+
source
612
612
+
);
613
613
+
// Clean up orphaned posts
614
614
+
await db.exec('DELETE FROM posts WHERE uri NOT IN (SELECT DISTINCT uri FROM post_sources)');
615
615
+
await db.exec('COMMIT');
616
616
+
} catch (e) {
617
617
+
await db.exec('ROLLBACK');
618
618
+
throw e;
619
619
+
}
620
620
+
}
621
621
+
622
622
+
export async function clearAccountData(db: Database, accountDid: string) {
623
623
+
await db.exec('BEGIN TRANSACTION');
624
624
+
try {
625
625
+
await (await db.prepare('DELETE FROM post_sources WHERE account_did = ?')).run(accountDid);
626
626
+
await (await db.prepare('DELETE FROM sync_cursors WHERE account_did = ?')).run(accountDid);
627
627
+
await (await db.prepare('DELETE FROM accounts WHERE did = ?')).run(accountDid);
628
628
+
await db.exec('DELETE FROM posts WHERE uri NOT IN (SELECT DISTINCT uri FROM post_sources)');
629
629
+
await db.exec('COMMIT');
630
630
+
} catch (e) {
631
631
+
await db.exec('ROLLBACK');
632
632
+
throw e;
633
633
+
}
634
634
+
}
635
635
+
636
636
+
export async function clearAllData(db: Database) {
637
637
+
await db.exec('BEGIN TRANSACTION');
638
638
+
try {
639
639
+
await db.exec('DELETE FROM post_sources');
640
640
+
await db.exec('DELETE FROM posts');
641
641
+
await db.exec('DELETE FROM sync_cursors');
642
642
+
await db.exec('DELETE FROM accounts');
643
643
+
await db.exec('COMMIT');
644
644
+
} catch (e) {
645
645
+
await db.exec('ROLLBACK');
646
646
+
throw e;
647
647
+
}
648
648
+
}
649
649
+
650
650
+
// --- Utilities ---
651
651
+
652
652
+
export function getLink(uri: string, handle: string) {
653
653
+
const [, , rkey] = uri.replace('at://', '').split('/');
654
654
+
return `https://bsky.app/profile/${handle}/post/${rkey}`;
655
655
+
}
···
1
1
import { user } from '$lib/atproto';
2
2
import { toast } from '@foxui/core';
3
3
-
import { Document, Charset, IndexedDB } from 'flexsearch';
4
3
import { Client, simpleFetchHandler } from '@atcute/client';
5
5
-
import { db, type StoredPost } from '$lib/db';
4
4
+
import {
5
5
+
getDb,
6
6
+
extractPostFields,
7
7
+
upsertAccount,
8
8
+
postExistsForSource,
9
9
+
postExists,
10
10
+
getSourceCount,
11
11
+
getCursor,
12
12
+
setCursor,
13
13
+
bulkUpsertPosts,
14
14
+
tagExistingPosts,
15
15
+
searchPosts,
16
16
+
clearSource as dbClearSource,
17
17
+
clearAllData as dbClearAllData,
18
18
+
getAccounts as dbGetAccounts,
19
19
+
clearAccountData as dbClearAccountData,
20
20
+
ALL_SOURCES,
21
21
+
DEFAULT_FILTERS,
22
22
+
type SourceType,
23
23
+
type SearchFilters,
24
24
+
type ExtractedPost
25
25
+
} from '$lib/db';
6
26
7
7
-
export type SourceType = 'likes' | 'bookmarks' | 'posts' | 'reposts';
8
8
-
9
9
-
export type SearchFilters = {
10
10
-
handles: string[];
11
11
-
minLikes: number;
12
12
-
minReposts: number;
13
13
-
minReplies: number;
14
14
-
dateAfter: string;
15
15
-
dateBefore: string;
16
16
-
hasImage: boolean;
17
17
-
hasLink: boolean;
18
18
-
hasVideo: boolean;
19
19
-
showReplies: boolean;
20
20
-
};
21
21
-
22
22
-
export const DEFAULT_FILTERS: SearchFilters = {
23
23
-
handles: [],
24
24
-
minLikes: 0,
25
25
-
minReposts: 0,
26
26
-
minReplies: 0,
27
27
-
dateAfter: '',
28
28
-
dateBefore: '',
29
29
-
hasImage: false,
30
30
-
hasLink: false,
31
31
-
hasVideo: false,
32
32
-
showReplies: true
33
33
-
};
27
27
+
export { ALL_SOURCES, DEFAULT_FILTERS, type SourceType, type SearchFilters };
34
28
35
29
export const SOURCE_LABELS: Record<SourceType, string> = {
36
30
likes: 'Likes',
···
39
33
reposts: 'Reposts'
40
34
};
41
35
42
42
-
export const PLACEHOLDERS: Record<SourceType, string> = {
43
43
-
likes: 'Search liked posts',
44
44
-
bookmarks: 'Search bookmarks',
45
45
-
posts: 'Search my posts',
46
46
-
reposts: 'Search reposted posts'
47
47
-
};
48
48
-
49
49
-
export const ALL_SOURCES: SourceType[] = ['likes', 'bookmarks', 'posts', 'reposts'];
36
36
+
export function getPlaceholder(sources: SourceType[]): string {
37
37
+
if (sources.length === ALL_SOURCES.length) return 'Search all posts';
38
38
+
if (sources.length > 1)
39
39
+
return `Search ${sources.map((s) => SOURCE_LABELS[s].toLowerCase()).join(' & ')}`;
40
40
+
if (sources.length === 1) {
41
41
+
const labels: Record<SourceType, string> = {
42
42
+
likes: 'Search liked posts',
43
43
+
bookmarks: 'Search bookmarks',
44
44
+
posts: 'Search my posts',
45
45
+
reposts: 'Search reposted posts'
46
46
+
};
47
47
+
return labels[sources[0]];
48
48
+
}
49
49
+
return 'Select a source to search';
50
50
+
}
50
51
51
52
type SourceState = {
52
52
-
index: Document | null;
53
53
count: number;
54
54
indexed: number;
55
55
totalToIndex: number;
···
60
60
61
61
function createSourceState(): SourceState {
62
62
return {
63
63
-
index: null,
64
63
count: 0,
65
64
indexed: 0,
66
65
totalToIndex: 0,
···
70
69
};
71
70
}
72
71
73
73
-
function createIndex() {
74
74
-
return new Document({
75
75
-
document: {
76
76
-
id: 'uri',
77
77
-
store: false,
78
78
-
index: [
79
79
-
{
80
80
-
field: 'author:handle',
81
81
-
tokenize: 'forward',
82
82
-
encoder: Charset.LatinBalance
83
83
-
},
84
84
-
{
85
85
-
field: 'author:displayName',
86
86
-
tokenize: 'forward',
87
87
-
encoder: Charset.LatinBalance
88
88
-
},
89
89
-
{
90
90
-
field: 'record:text',
91
91
-
tokenize: 'forward',
92
92
-
encoder: Charset.LatinBalance
93
93
-
}
94
94
-
]
95
95
-
}
96
96
-
});
97
97
-
}
98
98
-
99
72
const publicClient = new Client({
100
73
handler: simpleFetchHandler({ service: 'https://public.api.bsky.app' })
101
74
});
···
107
80
posts: createSourceState(),
108
81
reposts: createSourceState()
109
82
} as Record<SourceType, SourceState>,
110
110
-
activeSource: 'likes' as SourceType
83
83
+
activeSources: ['likes'] as SourceType[]
111
84
});
112
85
113
86
let generation = 0;
114
87
115
88
export async function initSources() {
116
116
-
// Clean up legacy localStorage data
89
89
+
const db = await getDb();
90
90
+
const accountDid = user.did;
91
91
+
if (!accountDid) return;
92
92
+
93
93
+
// Register/update current account
94
94
+
await upsertAccount(
95
95
+
db,
96
96
+
accountDid,
97
97
+
user.profile?.handle ?? '',
98
98
+
user.profile?.displayName,
99
99
+
user.profile?.avatar
100
100
+
);
101
101
+
102
102
+
// Get counts for each source
117
103
for (const source of ALL_SOURCES) {
118
118
-
localStorage.removeItem(`${source}-ids`);
119
119
-
localStorage.removeItem(`${source}-cursor`);
104
104
+
searchState.sources[source].count = await getSourceCount(db, accountDid, source);
120
105
}
121
106
122
122
-
await Promise.all(
123
123
-
ALL_SOURCES.map(async (source) => {
124
124
-
const flexDb = new IndexedDB(`${source}-idx`);
125
125
-
searchState.sources[source].index = createIndex();
126
126
-
await searchState.sources[source].index!.mount(flexDb);
107
107
+
// Start loading active source first
108
108
+
startLoading(searchState.activeSources[0] ?? 'likes');
109
109
+
}
127
110
128
128
-
// Get count from Dexie
129
129
-
searchState.sources[source].count = await db.posts
130
130
-
.where('sources')
131
131
-
.equals(source)
132
132
-
.count();
133
133
-
})
134
134
-
);
111
111
+
export function toggleSource(source: SourceType) {
112
112
+
const current = searchState.activeSources;
113
113
+
if (current.includes(source)) {
114
114
+
// Don't allow deselecting all
115
115
+
if (current.length <= 1) return;
116
116
+
searchState.activeSources = current.filter((s) => s !== source);
117
117
+
} else {
118
118
+
searchState.activeSources = [...current, source];
119
119
+
}
135
120
136
136
-
// Start loading (active source first via loadNext)
137
137
-
startLoading(searchState.activeSource);
121
121
+
generation++;
122
122
+
// Start loading any sources that aren't done yet
123
123
+
for (const s of searchState.activeSources) {
124
124
+
if (searchState.sources[s].phase !== 'done') {
125
125
+
startLoading(s);
126
126
+
return;
127
127
+
}
128
128
+
}
129
129
+
loadNext(generation);
138
130
}
139
131
140
140
-
export function switchSource(source: SourceType) {
141
141
-
if (source === searchState.activeSource) return;
142
142
-
searchState.activeSource = source;
132
132
+
export function setActiveSources(sources: SourceType[]) {
133
133
+
if (sources.length === 0) return;
134
134
+
searchState.activeSources = sources;
143
135
generation++;
144
144
-
if (searchState.sources[source].phase !== 'done') {
145
145
-
startLoading(source);
146
146
-
} else {
147
147
-
loadNext(generation);
136
136
+
for (const s of sources) {
137
137
+
if (searchState.sources[s].phase !== 'done') {
138
138
+
startLoading(s);
139
139
+
return;
140
140
+
}
148
141
}
142
142
+
loadNext(generation);
149
143
}
150
144
151
145
export function startLoading(source: SourceType) {
···
162
156
function loadNext(currentGen: number) {
163
157
if (currentGen !== generation) return;
164
158
159
159
+
// Prioritize active sources, then others
165
160
const sorted = [
166
166
-
searchState.activeSource,
167
167
-
...ALL_SOURCES.filter((s) => s !== searchState.activeSource)
161
161
+
...searchState.activeSources,
162
162
+
...ALL_SOURCES.filter((s) => !searchState.activeSources.includes(s))
168
163
];
169
164
for (const source of sorted) {
170
165
if (searchState.sources[source].phase !== 'done') {
···
177
172
async function fetchRecordPage(
178
173
source: SourceType,
179
174
s: SourceState,
175
175
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
180
176
fetchFn: Function,
181
177
cursor: string | undefined,
182
178
myGen: number
183
179
): Promise<{ cursor: string | undefined; done: boolean }> {
184
180
if (myGen !== generation) return { cursor, done: true };
185
181
182
182
+
const accountDid = user.did;
183
183
+
if (!accountDid) return { cursor, done: true };
184
184
+
185
185
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
186
186
let data: any;
187
187
try {
188
188
data = await fetchFn({ limit: 100, cursor });
···
192
192
return { cursor, done: true };
193
193
}
194
194
195
195
-
const uris = data.records.map((r: any) =>
196
196
-
source === 'posts' ? r.uri : r.value.subject.uri
197
197
-
);
198
198
-
const existingDocs = await db.posts.bulkGet(uris);
199
199
-
const toUpdate: any[] = [];
200
200
-
const now = Date.now();
195
195
+
const db = await getDb();
196
196
+
197
197
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
198
198
+
const uris = data.records.map((r: any) => (source === 'posts' ? r.uri : r.value.subject.uri));
199
199
+
200
200
+
// Check which URIs already exist for this source
201
201
+
const toTag: string[] = [];
201
202
202
203
for (let j = 0; j < uris.length; j++) {
203
204
const subjectUri = uris[j];
204
204
-
const existing = existingDocs[j];
205
205
206
206
-
if (existing) {
207
207
-
if (existing.sources.includes(source)) {
208
208
-
// Already indexed for this source — flush updates and stop.
209
209
-
// Use the last record's rkey as cursor so the tail resumes past this point.
210
210
-
const lastRecord = data.records[j];
211
211
-
const stopCursor = lastRecord?.uri?.split('/').pop() ?? data.cursor;
212
212
-
if (toUpdate.length > 0) await db.posts.bulkPut(toUpdate);
213
213
-
return { cursor: stopCursor, done: true };
206
206
+
if (await postExistsForSource(db, subjectUri, accountDid, source)) {
207
207
+
// Already indexed for this source — flush tags and stop
208
208
+
if (toTag.length > 0) {
209
209
+
const tagged = await tagExistingPosts(db, toTag, accountDid, source);
210
210
+
s.count += tagged;
214
211
}
215
215
-
// Post exists from another source — queue source tag update
216
216
-
toUpdate.push({ ...existing, sources: [...existing.sources, source], fetchedAt: now });
217
217
-
s.index!.add(existing as any);
218
218
-
s.count++;
219
219
-
continue;
212
212
+
const lastRecord = data.records[j];
213
213
+
const stopCursor = lastRecord?.uri?.split('/').pop() ?? data.cursor;
214
214
+
return { cursor: stopCursor, done: true };
220
215
}
221
216
222
222
-
s.pendingUris.push(subjectUri);
217
217
+
// Check if post exists from another source (already in posts table)
218
218
+
if (await postExists(db, subjectUri)) {
219
219
+
toTag.push(subjectUri);
220
220
+
} else {
221
221
+
s.pendingUris.push(subjectUri);
222
222
+
}
223
223
}
224
224
225
225
-
if (toUpdate.length > 0) await db.posts.bulkPut(toUpdate);
225
225
+
if (toTag.length > 0) {
226
226
+
const tagged = await tagExistingPosts(db, toTag, accountDid, source);
227
227
+
s.count += tagged;
228
228
+
}
226
229
227
230
const nextCursor = data.records.length > 0 ? data.cursor : undefined;
228
228
-
// Detect stalled cursor — if the API returns the same cursor we sent, stop.
229
231
if (nextCursor && nextCursor === cursor) {
230
232
return { cursor: nextCursor, done: true };
231
233
}
···
233
235
}
234
236
235
237
async function loadRecords(source: SourceType, myGen: number) {
236
236
-
if (!user.did || !searchState.sources[source].index) return;
238
238
+
if (!user.did) return;
237
239
238
240
const { listLikeRecords, listPostRecords, listRepostRecords } = await import(
239
241
'$lib/atproto/server/search.remote'
···
246
248
: listPostRecords;
247
249
248
250
const s = searchState.sources[source];
251
251
+
const db = await getDb();
252
252
+
const accountDid = user.did;
249
253
250
254
if (s.phase === 'idle' || s.phase === 'fetching') {
251
255
s.phase = 'fetching';
252
256
253
253
-
const meta = await db.meta.get(source);
257
257
+
const tailCursor = await getCursor(db, accountDid, source);
254
258
255
255
-
// Step 1: Fetch new posts from the top until we hit one we already have
259
259
+
// Step 1: Fetch new posts from the top
256
260
let result = { cursor: undefined as string | undefined, done: false };
257
261
do {
258
262
result = await fetchRecordPage(source, s, fetchFn, result.cursor, myGen);
···
260
264
261
265
if (myGen !== generation) return;
262
266
263
263
-
// Step 2: Continue from where we left off last time (tail)
264
264
-
if (meta?.tailCursor) {
265
265
-
result = { cursor: meta.tailCursor, done: false };
267
267
+
// Step 2: Continue from tail cursor
268
268
+
if (tailCursor) {
269
269
+
result = { cursor: tailCursor, done: false };
266
270
do {
267
271
result = await fetchRecordPage(source, s, fetchFn, result.cursor, myGen);
268
272
} while (!result.done && myGen === generation);
···
270
274
if (myGen !== generation) return;
271
275
}
272
276
273
273
-
// Save how far we got into the past
274
274
-
if (result.cursor) {
275
275
-
await db.meta.put({ source, tailCursor: result.cursor });
276
276
-
} else {
277
277
-
// We've reached the very end — no tail cursor needed
278
278
-
await db.meta.put({ source, tailCursor: undefined });
279
279
-
}
277
277
+
// Save cursor progress
278
278
+
await setCursor(db, accountDid, source, result.cursor);
280
279
281
280
s.totalToIndex = s.pendingUris.length;
282
281
s.phase = 'hydrating';
···
289
288
290
289
async function hydrateUris(source: SourceType, myGen: number) {
291
290
const s = searchState.sources[source];
291
291
+
const accountDid = user.did;
292
292
+
if (!accountDid) return;
293
293
+
292
294
const BATCH_SIZE = 25;
293
295
const CONCURRENCY = 5;
294
296
···
298
300
batches.push(remaining.slice(i, i + BATCH_SIZE));
299
301
}
300
302
303
303
+
const db = await getDb();
304
304
+
301
305
for (let i = 0; i < batches.length; i += CONCURRENCY) {
302
306
if (myGen !== generation) return;
303
307
···
305
309
const results = await Promise.all(
306
310
chunk.map((uris) =>
307
311
publicClient
312
312
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
308
313
.get('app.bsky.feed.getPosts', { params: { uris: uris as any } })
309
314
.catch((e) => {
310
315
console.error(`Failed to hydrate ${source} batch:`, e);
···
314
319
);
315
320
316
321
// Collect all posts from this chunk
317
317
-
const allPosts: any[] = [];
322
322
+
const now = Date.now();
323
323
+
const extracted: ExtractedPost[] = [];
318
324
for (const result of results) {
319
325
if (result?.ok) {
320
320
-
allPosts.push(...result.data.posts);
326
326
+
for (const post of result.data.posts) {
327
327
+
extracted.push(extractPostFields(post, now, now));
328
328
+
}
321
329
}
322
330
}
323
331
324
324
-
if (allPosts.length > 0) {
325
325
-
// Batch-check which already exist in Dexie
326
326
-
const uris = allPosts.map((p) => p.uri);
327
327
-
const existing = await db.posts.bulkGet(uris);
328
328
-
const existingMap = new Map<string, StoredPost>();
329
329
-
for (const doc of existing) {
330
330
-
if (doc) existingMap.set(doc.uri, doc);
331
331
-
}
332
332
-
333
333
-
// Build batch for bulkPut
334
334
-
const now = Date.now();
335
335
-
const toPut: any[] = [];
336
336
-
for (const post of allPosts) {
337
337
-
const ex = existingMap.get(post.uri);
338
338
-
if (ex) {
339
339
-
toPut.push({ ...post, sources: [...ex.sources, source], savedAt: ex.savedAt, fetchedAt: now });
340
340
-
} else {
341
341
-
toPut.push({ ...post, sources: [source], savedAt: now, fetchedAt: now });
342
342
-
}
343
343
-
s.index!.add(post as any);
344
344
-
s.indexed++;
345
345
-
s.count++;
346
346
-
}
347
347
-
348
348
-
await db.posts.bulkPut(toPut);
332
332
+
if (extracted.length > 0) {
333
333
+
const count = await bulkUpsertPosts(db, extracted, accountDid, source);
334
334
+
s.indexed += count;
335
335
+
s.count += count;
349
336
}
350
337
351
338
s.pendingIndex += chunk.reduce((sum, b) => sum + b.length, 0);
352
352
-
await s.index!.commit();
353
339
}
354
340
355
341
s.phase = 'done';
···
359
345
async function fetchBookmarkPage(
360
346
source: SourceType,
361
347
s: SourceState,
362
362
-
getBookmarks: Function,
348
348
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
349
349
+
getBookmarksFn: Function,
363
350
cursor: string | undefined,
364
351
myGen: number
365
352
): Promise<{ cursor: string | undefined; done: boolean }> {
366
353
if (myGen !== generation) return { cursor, done: true };
367
354
355
355
+
const accountDid = user.did;
356
356
+
if (!accountDid) return { cursor, done: true };
357
357
+
358
358
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
368
359
let data: any;
369
360
try {
370
370
-
data = await getBookmarks({ limit: 100, cursor });
371
371
-
} catch (err: any) {
361
361
+
data = await getBookmarksFn({ limit: 100, cursor });
362
362
+
} catch (err: unknown) {
372
363
console.error('Failed to fetch bookmarks:', err);
373
373
-
toast.error(`Failed to fetch bookmarks: ${err?.body?.message ?? err?.message ?? err}`);
364
364
+
const message =
365
365
+
err && typeof err === 'object' && 'body' in err
366
366
+
? (err as { body?: { message?: string } }).body?.message
367
367
+
: err instanceof Error
368
368
+
? err.message
369
369
+
: String(err);
370
370
+
toast.error(`Failed to fetch bookmarks: ${message}`);
374
371
return { cursor, done: true };
375
372
}
376
373
374
374
+
const db = await getDb();
375
375
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
377
376
const validBookmarks = data.bookmarks.filter((b: any) => b.item?.uri);
378
378
-
const uris = validBookmarks.map((b: any) => b.item.uri);
379
379
-
const existingDocs = await db.posts.bulkGet(uris);
380
380
-
const toPut: any[] = [];
381
377
const now = Date.now();
378
378
+
const toInsert: ExtractedPost[] = [];
379
379
+
const toTag: string[] = [];
382
380
383
383
-
for (let j = 0; j < validBookmarks.length; j++) {
384
384
-
const bookmark = validBookmarks[j];
385
385
-
const postUri = uris[j];
386
386
-
const existing = existingDocs[j];
381
381
+
for (const bookmark of validBookmarks) {
382
382
+
const postUri = bookmark.item.uri;
387
383
388
388
-
if (existing) {
389
389
-
if (existing.sources.includes(source)) {
390
390
-
// Already indexed for this source — flush and stop
391
391
-
if (toPut.length > 0) await db.posts.bulkPut(toPut);
392
392
-
return { cursor: data.cursor ?? cursor, done: true };
384
384
+
if (await postExistsForSource(db, postUri, accountDid, source)) {
385
385
+
// Already indexed — flush and stop
386
386
+
if (toInsert.length > 0) {
387
387
+
const count = await bulkUpsertPosts(db, toInsert, accountDid, source);
388
388
+
s.count += count;
389
389
+
s.indexed += count;
393
390
}
394
394
-
// Exists from another source — queue tag update
395
395
-
toPut.push({ ...existing, sources: [...existing.sources, source], fetchedAt: now });
396
396
-
s.index!.add(existing as any);
397
397
-
s.count++;
398
398
-
continue;
391
391
+
if (toTag.length > 0) {
392
392
+
s.count += await tagExistingPosts(db, toTag, accountDid, source);
393
393
+
}
394
394
+
return { cursor: data.cursor ?? cursor, done: true };
399
395
}
400
396
401
401
-
// Bookmarks come with full PostView — queue for batch write
402
402
-
toPut.push({ ...bookmark.item, sources: [source], savedAt: now, fetchedAt: now });
403
403
-
s.index!.add(bookmark.item as any);
404
404
-
s.indexed++;
405
405
-
s.count++;
397
397
+
// Check if post exists from another source
398
398
+
if (await postExists(db, postUri)) {
399
399
+
toTag.push(postUri);
400
400
+
} else {
401
401
+
// Bookmarks come with full PostView
402
402
+
toInsert.push(extractPostFields(bookmark.item, now, now));
403
403
+
}
406
404
}
407
405
408
408
-
if (toPut.length > 0) await db.posts.bulkPut(toPut);
406
406
+
if (toInsert.length > 0) {
407
407
+
const count = await bulkUpsertPosts(db, toInsert, accountDid, source);
408
408
+
s.count += count;
409
409
+
s.indexed += count;
410
410
+
}
411
411
+
if (toTag.length > 0) {
412
412
+
s.count += await tagExistingPosts(db, toTag, accountDid, source);
413
413
+
}
409
414
410
415
const nextCursor = data.bookmarks.length > 0 ? data.cursor : undefined;
411
411
-
// Detect stalled cursor — if the API returns the same cursor we sent, stop.
412
416
if (nextCursor && nextCursor === cursor) {
413
417
return { cursor: nextCursor, done: true };
414
418
}
···
416
420
}
417
421
418
422
async function loadBookmarks(source: SourceType, myGen: number) {
419
419
-
if (!user.did || !searchState.sources[source].index) return;
423
423
+
if (!user.did) return;
420
424
421
425
const { getBookmarks } = await import('$lib/atproto/server/search.remote');
422
426
423
427
const s = searchState.sources[source];
428
428
+
const db = await getDb();
429
429
+
const accountDid = user.did;
424
430
s.phase = 'fetching';
425
431
426
426
-
const meta = await db.meta.get(source);
432
432
+
const tailCursor = await getCursor(db, accountDid, source);
427
433
428
428
-
// Step 1: Fetch new bookmarks from the top until we hit one we already have
434
434
+
// Step 1: Fetch new bookmarks from the top
429
435
let result = { cursor: undefined as string | undefined, done: false };
430
436
do {
431
437
result = await fetchBookmarkPage(source, s, getBookmarks, result.cursor, myGen);
432
432
-
await s.index!.commit();
433
438
} while (!result.done && myGen === generation);
434
439
435
440
if (myGen !== generation) return;
436
441
437
437
-
// Step 2: Continue from where we left off last time (tail)
438
438
-
if (meta?.tailCursor) {
439
439
-
result = { cursor: meta.tailCursor, done: false };
442
442
+
// Step 2: Continue from tail cursor
443
443
+
if (tailCursor) {
444
444
+
result = { cursor: tailCursor, done: false };
440
445
do {
441
446
result = await fetchBookmarkPage(source, s, getBookmarks, result.cursor, myGen);
442
442
-
await s.index!.commit();
443
447
} while (!result.done && myGen === generation);
444
448
445
449
if (myGen !== generation) return;
446
450
}
447
451
448
448
-
// Save how far we got into the past
449
449
-
if (result.cursor) {
450
450
-
await db.meta.put({ source, tailCursor: result.cursor });
451
451
-
} else {
452
452
-
await db.meta.put({ source, tailCursor: undefined });
453
453
-
}
452
452
+
await setCursor(db, accountDid, source, result.cursor);
454
453
455
455
-
await s.index!.commit();
456
454
s.phase = 'done';
457
455
loadNext(myGen);
458
456
}
459
457
460
460
-
// --- Filter helpers ---
461
461
-
462
462
-
function hasEmbedType(doc: any, type: string): boolean {
463
463
-
const embed = doc.embed;
464
464
-
if (!embed) return false;
465
465
-
if (embed.$type === type) return true;
466
466
-
if (embed.$type === 'app.bsky.embed.recordWithMedia#view') {
467
467
-
return embed.media?.$type === type;
468
468
-
}
469
469
-
return false;
470
470
-
}
471
471
-
472
472
-
function hasLinkInFacets(doc: any): boolean {
473
473
-
const facets = doc.record?.facets;
474
474
-
if (!Array.isArray(facets)) return false;
475
475
-
return facets.some(
476
476
-
(f: any) => f.features?.some((feat: any) => feat.$type === 'app.bsky.richtext.facet#link')
477
477
-
);
478
478
-
}
479
479
-
480
480
-
function applyFilters(results: any[], filters: SearchFilters): any[] {
481
481
-
let r = results;
482
482
-
if (filters.handles.length > 0) {
483
483
-
r = r.filter((item) => {
484
484
-
const h = item.doc.author?.handle?.toLowerCase();
485
485
-
return h && filters.handles.some((fh) => h.includes(fh.toLowerCase()));
486
486
-
});
487
487
-
}
488
488
-
if (filters.minLikes > 0) {
489
489
-
r = r.filter((item) => (item.doc.likeCount ?? 0) >= filters.minLikes);
490
490
-
}
491
491
-
if (filters.minReposts > 0) {
492
492
-
r = r.filter((item) => (item.doc.repostCount ?? 0) >= filters.minReposts);
493
493
-
}
494
494
-
if (filters.minReplies > 0) {
495
495
-
r = r.filter((item) => (item.doc.replyCount ?? 0) >= filters.minReplies);
496
496
-
}
497
497
-
if (filters.dateAfter) {
498
498
-
const after = new Date(filters.dateAfter).getTime();
499
499
-
r = r.filter((item) => {
500
500
-
const created = item.doc.record?.createdAt;
501
501
-
return created && new Date(created).getTime() >= after;
502
502
-
});
503
503
-
}
504
504
-
if (filters.dateBefore) {
505
505
-
const before = new Date(filters.dateBefore).getTime() + 86400000;
506
506
-
r = r.filter((item) => {
507
507
-
const created = item.doc.record?.createdAt;
508
508
-
return created && new Date(created).getTime() <= before;
509
509
-
});
510
510
-
}
511
511
-
if (filters.hasImage) {
512
512
-
r = r.filter((item) => hasEmbedType(item.doc, 'app.bsky.embed.images#view'));
513
513
-
}
514
514
-
if (filters.hasLink) {
515
515
-
r = r.filter(
516
516
-
(item) =>
517
517
-
hasEmbedType(item.doc, 'app.bsky.embed.external#view') || hasLinkInFacets(item.doc)
518
518
-
);
519
519
-
}
520
520
-
if (filters.hasVideo) {
521
521
-
r = r.filter((item) => hasEmbedType(item.doc, 'app.bsky.embed.video#view'));
522
522
-
}
523
523
-
if (!filters.showReplies) {
524
524
-
r = r.filter((item) => !item.doc.record?.reply);
525
525
-
}
526
526
-
return r;
527
527
-
}
458
458
+
// --- Public search API ---
528
459
529
529
-
export function filtersActive(filters: SearchFilters): boolean {
530
530
-
return (
531
531
-
filters.handles.length > 0 ||
532
532
-
filters.minLikes > 0 ||
533
533
-
filters.minReposts > 0 ||
534
534
-
filters.minReplies > 0 ||
535
535
-
!!filters.dateAfter ||
536
536
-
!!filters.dateBefore ||
537
537
-
filters.hasImage ||
538
538
-
filters.hasLink ||
539
539
-
filters.hasVideo ||
540
540
-
!filters.showReplies
541
541
-
);
542
542
-
}
543
543
-
544
544
-
function sortByDate(items: any[]): any[] {
545
545
-
return items.sort((a, b) => {
546
546
-
const dateA = a.doc.record?.createdAt ? new Date(a.doc.record.createdAt).getTime() : 0;
547
547
-
const dateB = b.doc.record?.createdAt ? new Date(b.doc.record.createdAt).getTime() : 0;
548
548
-
return dateB - dateA;
549
549
-
});
550
550
-
}
460
460
+
export { filtersActive } from '$lib/db';
551
461
552
462
export async function searchIndex(
553
463
query: string,
554
464
filters: SearchFilters = DEFAULT_FILTERS,
555
555
-
limit: number = 50
556
556
-
): Promise<{ results: any[]; hasMore: boolean }> {
557
557
-
const source = searchState.activeSource;
558
558
-
const hasFilters = filtersActive(filters);
465
465
+
sources: SourceType[] = searchState.activeSources,
466
466
+
limit: number = 50,
467
467
+
offset: number = 0
468
468
+
): Promise<{
469
469
+
results: { doc: unknown; isLiked: boolean; isBookmarked: boolean }[];
470
470
+
hasMore: boolean;
471
471
+
}> {
472
472
+
const accountDid = user.did;
473
473
+
if (!accountDid) return { results: [], hasMore: false };
559
474
560
560
-
let docs: any[];
475
475
+
const db = await getDb();
561
476
562
562
-
if (query) {
563
563
-
// Text search via FlexSearch → get URIs → lookup in Dexie
564
564
-
const idx = searchState.sources[source].index;
565
565
-
if (!idx) return { results: [], hasMore: false };
477
477
+
// Get all account DIDs for cross-account search (for now, just current account)
478
478
+
const accountDids = [accountDid];
566
479
567
567
-
const raw = await idx.search({
568
568
-
query,
569
569
-
merge: true,
570
570
-
limit: hasFilters ? 5000 : limit + 1
571
571
-
});
480
480
+
return searchPosts(db, {
481
481
+
query,
482
482
+
filters,
483
483
+
sources,
484
484
+
accountDids,
485
485
+
limit,
486
486
+
offset
487
487
+
});
488
488
+
}
572
489
573
573
-
const uris = raw.map((r: any) => r.id);
574
574
-
docs = (await db.posts.bulkGet(uris)).filter(Boolean) as any[];
575
575
-
} else {
576
576
-
// No query: get all docs for this source from Dexie
577
577
-
docs = await db.posts.where('sources').equals(source).toArray();
578
578
-
}
490
490
+
// --- Clear operations ---
579
491
580
580
-
let wrapped = docs.map((doc) => ({ doc }));
581
581
-
if (hasFilters) wrapped = applyFilters(wrapped, filters);
582
582
-
if (!query) wrapped = sortByDate(wrapped);
492
492
+
export async function clearSource(source: SourceType) {
493
493
+
const accountDid = user.did;
494
494
+
if (!accountDid) return;
583
495
584
584
-
const hasMore = wrapped.length > limit;
585
585
-
return { results: wrapped.slice(0, limit), hasMore };
586
586
-
}
496
496
+
const db = await getDb();
497
497
+
await dbClearSource(db, accountDid, source);
587
498
588
588
-
export async function clearSource(source: SourceType) {
589
589
-
// Remove source tag from all posts, delete orphans
590
590
-
const posts = await db.posts.where('sources').equals(source).toArray();
591
591
-
await db.transaction('rw', db.posts, async () => {
592
592
-
for (const post of posts) {
593
593
-
const newSources = post.sources.filter((s) => s !== source);
594
594
-
if (newSources.length === 0) {
595
595
-
await db.posts.delete(post.uri);
596
596
-
} else {
597
597
-
await db.posts.update(post.uri, { sources: newSources });
598
598
-
}
599
599
-
}
600
600
-
});
601
601
-
await db.meta.delete(source);
602
602
-
603
603
-
searchState.sources[source].index?.clear();
604
499
searchState.sources[source].count = 0;
605
500
searchState.sources[source].indexed = 0;
606
501
searchState.sources[source].totalToIndex = 0;
···
609
504
searchState.sources[source].pendingIndex = 0;
610
505
}
611
506
612
612
-
export function getLink(uri: string, handle: string) {
613
613
-
const [, , rkey] = uri.replace('at://', '').split('/');
614
614
-
return `https://bsky.app/profile/${handle}/post/${rkey}`;
507
507
+
export async function clearAll() {
508
508
+
const db = await getDb();
509
509
+
await dbClearAllData(db);
510
510
+
511
511
+
for (const source of ALL_SOURCES) {
512
512
+
searchState.sources[source].count = 0;
513
513
+
searchState.sources[source].indexed = 0;
514
514
+
searchState.sources[source].totalToIndex = 0;
515
515
+
searchState.sources[source].phase = 'idle';
516
516
+
searchState.sources[source].pendingUris = [];
517
517
+
searchState.sources[source].pendingIndex = 0;
518
518
+
}
519
519
+
}
520
520
+
521
521
+
export async function clearAccount(accountDid: string) {
522
522
+
const db = await getDb();
523
523
+
await dbClearAccountData(db, accountDid);
524
524
+
525
525
+
// If clearing current account, reset state
526
526
+
if (accountDid === user.did) {
527
527
+
for (const source of ALL_SOURCES) {
528
528
+
searchState.sources[source].count = 0;
529
529
+
searchState.sources[source].indexed = 0;
530
530
+
searchState.sources[source].totalToIndex = 0;
531
531
+
searchState.sources[source].phase = 'idle';
532
532
+
searchState.sources[source].pendingUris = [];
533
533
+
searchState.sources[source].pendingIndex = 0;
534
534
+
}
535
535
+
}
536
536
+
}
537
537
+
538
538
+
export async function listAccounts(): Promise<
539
539
+
{ did: string; handle: string; display_name: string | null }[]
540
540
+
> {
541
541
+
const db = await getDb();
542
542
+
return dbGetAccounts(db);
615
543
}
···
1
1
<script lang="ts">
2
2
import { Input, Navbar } from '@foxui/core';
3
3
-
import { AtprotoHandlePopup, BlueskyPost, blueskyPostToPostData, Post } from '@foxui/social';
3
3
+
import { AtprotoHandlePopup, BlueskyPost } from '@foxui/social';
4
4
import { onMount } from 'svelte';
5
5
import {
6
6
searchState,
7
7
initSources,
8
8
-
switchSource,
8
8
+
toggleSource,
9
9
+
setActiveSources,
9
10
searchIndex,
10
10
-
filtersActive,
11
11
-
DEFAULT_FILTERS,
12
11
SOURCE_LABELS,
13
13
-
PLACEHOLDERS,
12
12
+
getPlaceholder,
14
13
ALL_SOURCES,
14
14
+
DEFAULT_FILTERS,
15
15
type SourceType,
16
16
type SearchFilters
17
17
} from '$lib/search-state.svelte';
18
18
+
import { filtersActive } from '$lib/db';
18
19
19
20
let input: HTMLInputElement | null = $state(null);
20
21
let search = $state('');
21
21
-
let results: any[] = $state([]);
22
22
+
let results: { doc: any; isLiked: boolean; isBookmarked: boolean }[] = $state([]);
22
23
let hasMore = $state(false);
23
23
-
let limit = $state(50);
24
24
+
let offset = $state(0);
24
25
let sentinel: HTMLElement | null = $state(null);
25
26
let scrollY = $state(0);
26
27
···
29
30
let handleInput = $state('');
30
31
let hasActiveFilters = $derived(filtersActive(filters));
31
32
33
33
+
const PAGE_SIZE = 50;
34
34
+
32
35
onMount(() => {
33
36
initSources();
34
37
});
35
38
36
36
-
function handleSwitchSource(source: SourceType) {
37
37
-
switchSource(source);
38
38
-
}
39
39
-
40
40
-
// Reset limit when search params change
39
39
+
// Reset offset when search params change
41
40
$effect(() => {
42
42
-
searchState.activeSource;
41
41
+
searchState.activeSources;
43
42
$state.snapshot(filters);
44
43
search;
45
45
-
limit = 50;
44
44
+
offset = 0;
45
45
+
results = [];
46
46
});
47
47
48
48
// Fetch results
49
49
$effect(() => {
50
50
-
const _source = searchState.activeSource;
50
50
+
const _sources = searchState.activeSources;
51
51
const _filters = $state.snapshot(filters);
52
52
-
const _count = searchState.sources[_source].count;
53
53
-
const _limit = limit;
52
52
+
const _offset = offset;
53
53
+
// Track counts of active sources so we re-query as data loads in
54
54
+
for (const s of _sources) {
55
55
+
searchState.sources[s].count;
56
56
+
}
54
57
55
55
-
searchIndex(search, _filters, _limit).then((res) => {
56
56
-
results = res.results;
58
58
+
searchIndex(search, _filters, _sources, PAGE_SIZE, _offset).then((res) => {
59
59
+
if (_offset === 0) {
60
60
+
results = res.results;
61
61
+
} else {
62
62
+
results = [...results, ...res.results];
63
63
+
}
57
64
hasMore = res.hasMore;
58
65
});
59
66
});
···
66
73
const observer = new IntersectionObserver(
67
74
(entries) => {
68
75
if (entries[0].isIntersecting && hasMore) {
69
69
-
limit += 50;
76
76
+
offset += PAGE_SIZE;
70
77
}
71
78
},
72
79
{ rootMargin: '400px' }
···
82
89
? 'bg-accent-600 text-white'
83
90
: 'text-base-600 dark:text-base-400 hover:bg-base-200 dark:hover:bg-base-800'
84
91
}`;
92
92
+
93
93
+
const allSourcesActive = $derived(searchState.activeSources.length === ALL_SOURCES.length);
94
94
+
95
95
+
// Check if only "posts" source is selected (hide handle filter for own posts)
96
96
+
const onlyPosts = $derived(
97
97
+
searchState.activeSources.length === 1 && searchState.activeSources[0] === 'posts'
98
98
+
);
85
99
</script>
86
100
87
101
<svelte:window
···
112
126
<div class="flex gap-1">
113
127
{#each ALL_SOURCES as source}
114
128
<button
115
115
-
class="cursor-pointer rounded-full px-3 py-1 text-sm font-medium transition-colors {searchState.activeSource ===
116
116
-
source
129
129
+
class="cursor-pointer rounded-full px-3 py-1 text-sm font-medium transition-colors {searchState.activeSources.includes(
130
130
+
source
131
131
+
)
117
132
? 'bg-accent-600 text-white'
118
133
: 'text-base-600 dark:text-base-400 hover:bg-base-200 dark:hover:bg-base-800'}"
119
119
-
onclick={() => handleSwitchSource(source)}
134
134
+
onclick={() => toggleSource(source)}
120
135
>
121
136
{SOURCE_LABELS[source]}
122
137
</button>
123
138
{/each}
139
139
+
<button
140
140
+
class="cursor-pointer rounded-full px-3 py-1 text-sm font-medium transition-colors {allSourcesActive
141
141
+
? 'bg-accent-600 text-white'
142
142
+
: 'text-base-600 dark:text-base-400 hover:bg-base-200 dark:hover:bg-base-800'}"
143
143
+
onclick={() => setActiveSources([...ALL_SOURCES])}
144
144
+
>
145
145
+
All
146
146
+
</button>
124
147
</div>
125
148
</div>
126
149
···
130
153
bind:value={search}
131
154
class="w-full"
132
155
sizeVariant="lg"
133
133
-
placeholder={PLACEHOLDERS[searchState.activeSource]}
156
156
+
placeholder={getPlaceholder(searchState.activeSources)}
134
157
/>
135
158
<button
136
159
class="text-base-500 dark:text-base-400 hover:text-accent-600 dark:hover:text-accent-400 relative cursor-pointer p-2 transition-colors"
···
157
180
158
181
{#if showFilters}
159
182
<div class="mt-3 flex w-full flex-col gap-3 px-2">
160
160
-
{#if searchState.activeSource !== 'posts'}
183
183
+
{#if !onlyPosts}
161
184
<div class="flex flex-col gap-1.5">
162
185
<div class="flex items-center gap-2">
163
186
<label class="text-base-500 dark:text-base-400 w-16 shrink-0 text-xs">Handle</label>
···
284
307
</div>
285
308
{/if}
286
309
287
287
-
{@const src = searchState.sources[searchState.activeSource]}
288
310
<span class="text-base-600 dark:text-base-400 mx-4 mt-2 text-xs">
289
289
-
{#if src.phase === 'idle'}
290
290
-
loading...
291
291
-
{:else if src.phase === 'fetching'}
292
292
-
fetching {SOURCE_LABELS[searchState.activeSource].toLowerCase()}... ({src.count +
293
293
-
src.pendingUris.length} found)
294
294
-
{:else if src.phase === 'hydrating'}
295
295
-
indexing {src.indexed}/{src.totalToIndex}
296
296
-
{SOURCE_LABELS[searchState.activeSource].toLowerCase()}... ({src.count} searchable)
311
311
+
{#if searchState.activeSources.length === 1}
312
312
+
{@const src = searchState.sources[searchState.activeSources[0]]}
313
313
+
{#if src.phase === 'idle'}
314
314
+
loading...
315
315
+
{:else if src.phase === 'fetching'}
316
316
+
fetching {SOURCE_LABELS[searchState.activeSources[0]].toLowerCase()}... ({src.count +
317
317
+
src.pendingUris.length} found)
318
318
+
{:else if src.phase === 'hydrating'}
319
319
+
indexing {src.indexed}/{src.totalToIndex}
320
320
+
{SOURCE_LABELS[searchState.activeSources[0]].toLowerCase()}... ({src.count} searchable)
321
321
+
{:else}
322
322
+
{SOURCE_LABELS[searchState.activeSources[0]].toLowerCase()}: {src.count}{#if results.length > 0},
323
323
+
{results.length}
324
324
+
results{/if}
325
325
+
{/if}
297
326
{:else}
298
298
-
{SOURCE_LABELS[searchState.activeSource].toLowerCase()}: {src.count}{#if results.length > 0}, {results.length}
299
299
-
results{/if}
327
327
+
{@const totalCount = searchState.activeSources.reduce(
328
328
+
(sum, s) => sum + searchState.sources[s].count,
329
329
+
0
330
330
+
)}
331
331
+
{@const allDone = searchState.activeSources.every((s) => searchState.sources[s].phase === 'done')}
332
332
+
{#if allDone}
333
333
+
{totalCount} posts{#if results.length > 0}, {results.length} results{/if}
334
334
+
{:else}
335
335
+
loading... ({totalCount} found)
336
336
+
{/if}
300
337
{/if}
301
338
</span>
302
339
</Navbar>
···
310
347
{#each results as result (result.doc.uri)}
311
348
<li class="py-4">
312
349
<BlueskyPost
313
313
-
liked={result.doc.sources?.includes('likes')}
314
314
-
bookmarked={result.doc.sources?.includes('bookmarks')}
350
350
+
liked={result.isLiked}
351
351
+
bookmarked={result.isBookmarked}
315
352
showLogo
316
353
feedViewPost={result.doc}
317
354
/>
···
1
1
<script lang="ts">
2
2
import { user, logout } from '$lib/atproto';
3
3
import { Button, Heading, toast } from '@foxui/core';
4
4
-
import { clearSource, ALL_SOURCES } from '$lib/search-state.svelte';
4
4
+
import { clearAll, clearAccount, listAccounts } from '$lib/search-state.svelte';
5
5
import { goto } from '$app/navigation';
6
6
+
import { onMount } from 'svelte';
7
7
+
8
8
+
let accounts: { did: string; handle: string; display_name: string | null }[] = $state([]);
9
9
+
10
10
+
onMount(async () => {
11
11
+
accounts = await listAccounts();
12
12
+
});
6
13
</script>
7
14
8
15
{#if user.isLoggedIn}
···
21
28
<p class="text-base-600 dark:text-base-400 text-sm">Signed in as <span class="text-base-800 dark:text-base-200 font-medium">@{user.profile?.handle}</span></p>
22
29
</div>
23
30
31
31
+
{#if accounts.length > 0}
32
32
+
<div class="border-base-300 dark:border-base-800 flex flex-col gap-3 border-t pt-4">
33
33
+
<p class="text-base-600 dark:text-base-400 text-xs font-medium uppercase tracking-wide">Cached accounts</p>
34
34
+
{#each accounts as account}
35
35
+
<div class="flex items-center justify-between">
36
36
+
<div class="flex items-center gap-2">
37
37
+
<span class="text-base-800 dark:text-base-200 text-sm">@{account.handle}</span>
38
38
+
{#if account.did === user.did}
39
39
+
<span class="text-base-500 dark:text-base-400 text-xs">(current)</span>
40
40
+
{/if}
41
41
+
</div>
42
42
+
<Button
43
43
+
variant="ghost"
44
44
+
size="sm"
45
45
+
onclick={async () => {
46
46
+
await clearAccount(account.did);
47
47
+
accounts = accounts.filter((a) => a.did !== account.did);
48
48
+
toast.success(`Cleared data for @${account.handle}`);
49
49
+
}}
50
50
+
>
51
51
+
Clear data
52
52
+
</Button>
53
53
+
</div>
54
54
+
{/each}
55
55
+
</div>
56
56
+
{/if}
57
57
+
24
58
<div class="border-base-300 dark:border-base-800 flex flex-col gap-3 border-t pt-4">
25
59
<Button
26
60
variant="ghost"
27
61
onclick={async () => {
28
28
-
for (const source of ALL_SOURCES) {
29
29
-
await clearSource(source);
30
30
-
}
31
31
-
const dbs = await indexedDB.databases();
32
32
-
for (const dbInfo of dbs) {
33
33
-
if (dbInfo.name) indexedDB.deleteDatabase(dbInfo.name);
34
34
-
}
62
62
+
await clearAll();
63
63
+
accounts = [];
35
64
toast.success('All data cleared');
36
36
-
setTimeout(() => location.reload(), 500);
37
65
}}
38
66
>
39
67
Reset all data
···
1
1
import tailwindcss from '@tailwindcss/vite';
2
2
import { sveltekit } from '@sveltejs/kit/vite';
3
3
-
import { defineConfig } from 'vite';
3
3
+
import { defineConfig, type Plugin } from 'vite';
4
4
import { DEV_PORT } from './src/lib/atproto/port';
5
5
6
6
+
function coopCoepHeaders(): Plugin {
7
7
+
return {
8
8
+
name: 'coop-coep-headers',
9
9
+
configureServer(server) {
10
10
+
server.middlewares.use((_req, res, next) => {
11
11
+
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
12
12
+
res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless');
13
13
+
next();
14
14
+
});
15
15
+
}
16
16
+
};
17
17
+
}
18
18
+
6
19
export default defineConfig({
7
7
-
plugins: [sveltekit(), tailwindcss()],
20
20
+
plugins: [sveltekit(), tailwindcss(), coopCoepHeaders()],
8
21
server: {
9
22
host: '127.0.0.1',
10
23
port: DEV_PORT
24
24
+
},
25
25
+
optimizeDeps: {
26
26
+
exclude: ['@tursodatabase/database-wasm']
11
27
}
12
28
});