integrate real ATProto labeler for spam detection

- add labeler/ cloudflare worker with proper label signing
- secp256k1 + DAG-CBOR label signatures
- queryLabels XRPC endpoint
- spam management endpoints
- create labeler DID (did:plc:x6io7svnbth4pikg2e63vvkx)
- update pds.js to check labeler before accepting messages
- update frontend LabelerClient to use remote labeler

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Changed files
+2093 -12
labeler
src
+1609
labeler/package-lock.json
··· 1 + { 2 + "name": "spam-labeler", 3 + "version": "0.0.1", 4 + "lockfileVersion": 3, 5 + "requires": true, 6 + "packages": { 7 + "": { 8 + "name": "spam-labeler", 9 + "version": "0.0.1", 10 + "dependencies": { 11 + "@ipld/dag-cbor": "^9.2.5", 12 + "@noble/curves": "^1.8.1", 13 + "@noble/hashes": "^1.7.1", 14 + "multiformats": "^13.3.1", 15 + "uint8arrays": "^5.1.0" 16 + }, 17 + "devDependencies": { 18 + "wrangler": "^4.0.0" 19 + } 20 + }, 21 + "node_modules/@cloudflare/kv-asset-handler": { 22 + "version": "0.4.1", 23 + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.1.tgz", 24 + "integrity": "sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==", 25 + "dev": true, 26 + "license": "MIT OR Apache-2.0", 27 + "dependencies": { 28 + "mime": "^3.0.0" 29 + }, 30 + "engines": { 31 + "node": ">=18.0.0" 32 + } 33 + }, 34 + "node_modules/@cloudflare/unenv-preset": { 35 + "version": "2.8.0", 36 + "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.8.0.tgz", 37 + "integrity": "sha512-oIAu6EdQ4zJuPwwKr9odIEqd8AV96z1aqi3RBEA4iKaJ+Vd3fvuI6m5EDC7/QCv+oaPIhy1SkYBYxmD09N+oZg==", 38 + "dev": true, 39 + "license": "MIT OR Apache-2.0", 40 + "peerDependencies": { 41 + "unenv": "2.0.0-rc.24", 42 + "workerd": "^1.20251202.0" 43 + }, 44 + "peerDependenciesMeta": { 45 + "workerd": { 46 + "optional": true 47 + } 48 + } 49 + }, 50 + "node_modules/@cloudflare/workerd-darwin-64": { 51 + "version": "1.20260103.0", 52 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260103.0.tgz", 53 + "integrity": "sha512-jhpwADN14T+plfDt3ljYAJL2+nTdTJQ3I/OpedweOz1l2jYZITRD+EI0zUpOzGJRqCE1k5SCkHUXINsWaE6aKg==", 54 + "cpu": [ 55 + "x64" 56 + ], 57 + "dev": true, 58 + "license": "Apache-2.0", 59 + "optional": true, 60 + "os": [ 61 + "darwin" 62 + ], 63 + "engines": { 64 + "node": ">=16" 65 + } 66 + }, 67 + "node_modules/@cloudflare/workerd-darwin-arm64": { 68 + "version": "1.20260103.0", 69 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260103.0.tgz", 70 + "integrity": "sha512-RoVMzq+TMoKTPr0aewwRasJumMqNYlBJuTC7ZwPAjfjuqedkLfvLx8GsXkW5zpyUMEsUciRh4DPJfDPKVgAy9g==", 71 + "cpu": [ 72 + "arm64" 73 + ], 74 + "dev": true, 75 + "license": "Apache-2.0", 76 + "optional": true, 77 + "os": [ 78 + "darwin" 79 + ], 80 + "engines": { 81 + "node": ">=16" 82 + } 83 + }, 84 + "node_modules/@cloudflare/workerd-linux-64": { 85 + "version": "1.20260103.0", 86 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260103.0.tgz", 87 + "integrity": "sha512-JQN4FnsTiBgtLF/9ABcgJjew+QxonE3ZxnqCT355x45mksJuArjD2iZ4kLZQ16OSEAkno8fmVw0VvljdGd41kg==", 88 + "cpu": [ 89 + "x64" 90 + ], 91 + "dev": true, 92 + "license": "Apache-2.0", 93 + "optional": true, 94 + "os": [ 95 + "linux" 96 + ], 97 + "engines": { 98 + "node": ">=16" 99 + } 100 + }, 101 + "node_modules/@cloudflare/workerd-linux-arm64": { 102 + "version": "1.20260103.0", 103 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260103.0.tgz", 104 + "integrity": "sha512-kjMHGrnnZrOyQnXuJ8YpblKtjkv45o+utIYk4AZUoaUBbEltwn7CXucDa0MG0jsDDvCCwRabdaJSAXHV6JB/ZQ==", 105 + "cpu": [ 106 + "arm64" 107 + ], 108 + "dev": true, 109 + "license": "Apache-2.0", 110 + "optional": true, 111 + "os": [ 112 + "linux" 113 + ], 114 + "engines": { 115 + "node": ">=16" 116 + } 117 + }, 118 + "node_modules/@cloudflare/workerd-windows-64": { 119 + "version": "1.20260103.0", 120 + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260103.0.tgz", 121 + "integrity": "sha512-M7mZHV6uWVE+Mf8r/nT6/21N1+Z4JmZTPJjek3rB4n7netOJGZIUQwyuY+5gwOnq+qJsqHoU/RP7b4lFSoMZuQ==", 122 + "cpu": [ 123 + "x64" 124 + ], 125 + "dev": true, 126 + "license": "Apache-2.0", 127 + "optional": true, 128 + "os": [ 129 + "win32" 130 + ], 131 + "engines": { 132 + "node": ">=16" 133 + } 134 + }, 135 + "node_modules/@cspotcode/source-map-support": { 136 + "version": "0.8.1", 137 + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 138 + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 139 + "dev": true, 140 + "license": "MIT", 141 + "dependencies": { 142 + "@jridgewell/trace-mapping": "0.3.9" 143 + }, 144 + "engines": { 145 + "node": ">=12" 146 + } 147 + }, 148 + "node_modules/@emnapi/runtime": { 149 + "version": "1.8.1", 150 + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", 151 + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", 152 + "dev": true, 153 + "license": "MIT", 154 + "optional": true, 155 + "dependencies": { 156 + "tslib": "^2.4.0" 157 + } 158 + }, 159 + "node_modules/@esbuild/aix-ppc64": { 160 + "version": "0.27.0", 161 + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz", 162 + "integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==", 163 + "cpu": [ 164 + "ppc64" 165 + ], 166 + "dev": true, 167 + "license": "MIT", 168 + "optional": true, 169 + "os": [ 170 + "aix" 171 + ], 172 + "engines": { 173 + "node": ">=18" 174 + } 175 + }, 176 + "node_modules/@esbuild/android-arm": { 177 + "version": "0.27.0", 178 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.0.tgz", 179 + "integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==", 180 + "cpu": [ 181 + "arm" 182 + ], 183 + "dev": true, 184 + "license": "MIT", 185 + "optional": true, 186 + "os": [ 187 + "android" 188 + ], 189 + "engines": { 190 + "node": ">=18" 191 + } 192 + }, 193 + "node_modules/@esbuild/android-arm64": { 194 + "version": "0.27.0", 195 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz", 196 + "integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==", 197 + "cpu": [ 198 + "arm64" 199 + ], 200 + "dev": true, 201 + "license": "MIT", 202 + "optional": true, 203 + "os": [ 204 + "android" 205 + ], 206 + "engines": { 207 + "node": ">=18" 208 + } 209 + }, 210 + "node_modules/@esbuild/android-x64": { 211 + "version": "0.27.0", 212 + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.0.tgz", 213 + "integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==", 214 + "cpu": [ 215 + "x64" 216 + ], 217 + "dev": true, 218 + "license": "MIT", 219 + "optional": true, 220 + "os": [ 221 + "android" 222 + ], 223 + "engines": { 224 + "node": ">=18" 225 + } 226 + }, 227 + "node_modules/@esbuild/darwin-arm64": { 228 + "version": "0.27.0", 229 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz", 230 + "integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==", 231 + "cpu": [ 232 + "arm64" 233 + ], 234 + "dev": true, 235 + "license": "MIT", 236 + "optional": true, 237 + "os": [ 238 + "darwin" 239 + ], 240 + "engines": { 241 + "node": ">=18" 242 + } 243 + }, 244 + "node_modules/@esbuild/darwin-x64": { 245 + "version": "0.27.0", 246 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz", 247 + "integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==", 248 + "cpu": [ 249 + "x64" 250 + ], 251 + "dev": true, 252 + "license": "MIT", 253 + "optional": true, 254 + "os": [ 255 + "darwin" 256 + ], 257 + "engines": { 258 + "node": ">=18" 259 + } 260 + }, 261 + "node_modules/@esbuild/freebsd-arm64": { 262 + "version": "0.27.0", 263 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz", 264 + "integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==", 265 + "cpu": [ 266 + "arm64" 267 + ], 268 + "dev": true, 269 + "license": "MIT", 270 + "optional": true, 271 + "os": [ 272 + "freebsd" 273 + ], 274 + "engines": { 275 + "node": ">=18" 276 + } 277 + }, 278 + "node_modules/@esbuild/freebsd-x64": { 279 + "version": "0.27.0", 280 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz", 281 + "integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==", 282 + "cpu": [ 283 + "x64" 284 + ], 285 + "dev": true, 286 + "license": "MIT", 287 + "optional": true, 288 + "os": [ 289 + "freebsd" 290 + ], 291 + "engines": { 292 + "node": ">=18" 293 + } 294 + }, 295 + "node_modules/@esbuild/linux-arm": { 296 + "version": "0.27.0", 297 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz", 298 + "integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==", 299 + "cpu": [ 300 + "arm" 301 + ], 302 + "dev": true, 303 + "license": "MIT", 304 + "optional": true, 305 + "os": [ 306 + "linux" 307 + ], 308 + "engines": { 309 + "node": ">=18" 310 + } 311 + }, 312 + "node_modules/@esbuild/linux-arm64": { 313 + "version": "0.27.0", 314 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz", 315 + "integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==", 316 + "cpu": [ 317 + "arm64" 318 + ], 319 + "dev": true, 320 + "license": "MIT", 321 + "optional": true, 322 + "os": [ 323 + "linux" 324 + ], 325 + "engines": { 326 + "node": ">=18" 327 + } 328 + }, 329 + "node_modules/@esbuild/linux-ia32": { 330 + "version": "0.27.0", 331 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz", 332 + "integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==", 333 + "cpu": [ 334 + "ia32" 335 + ], 336 + "dev": true, 337 + "license": "MIT", 338 + "optional": true, 339 + "os": [ 340 + "linux" 341 + ], 342 + "engines": { 343 + "node": ">=18" 344 + } 345 + }, 346 + "node_modules/@esbuild/linux-loong64": { 347 + "version": "0.27.0", 348 + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz", 349 + "integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==", 350 + "cpu": [ 351 + "loong64" 352 + ], 353 + "dev": true, 354 + "license": "MIT", 355 + "optional": true, 356 + "os": [ 357 + "linux" 358 + ], 359 + "engines": { 360 + "node": ">=18" 361 + } 362 + }, 363 + "node_modules/@esbuild/linux-mips64el": { 364 + "version": "0.27.0", 365 + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz", 366 + "integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==", 367 + "cpu": [ 368 + "mips64el" 369 + ], 370 + "dev": true, 371 + "license": "MIT", 372 + "optional": true, 373 + "os": [ 374 + "linux" 375 + ], 376 + "engines": { 377 + "node": ">=18" 378 + } 379 + }, 380 + "node_modules/@esbuild/linux-ppc64": { 381 + "version": "0.27.0", 382 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz", 383 + "integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==", 384 + "cpu": [ 385 + "ppc64" 386 + ], 387 + "dev": true, 388 + "license": "MIT", 389 + "optional": true, 390 + "os": [ 391 + "linux" 392 + ], 393 + "engines": { 394 + "node": ">=18" 395 + } 396 + }, 397 + "node_modules/@esbuild/linux-riscv64": { 398 + "version": "0.27.0", 399 + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz", 400 + "integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==", 401 + "cpu": [ 402 + "riscv64" 403 + ], 404 + "dev": true, 405 + "license": "MIT", 406 + "optional": true, 407 + "os": [ 408 + "linux" 409 + ], 410 + "engines": { 411 + "node": ">=18" 412 + } 413 + }, 414 + "node_modules/@esbuild/linux-s390x": { 415 + "version": "0.27.0", 416 + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz", 417 + "integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==", 418 + "cpu": [ 419 + "s390x" 420 + ], 421 + "dev": true, 422 + "license": "MIT", 423 + "optional": true, 424 + "os": [ 425 + "linux" 426 + ], 427 + "engines": { 428 + "node": ">=18" 429 + } 430 + }, 431 + "node_modules/@esbuild/linux-x64": { 432 + "version": "0.27.0", 433 + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz", 434 + "integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==", 435 + "cpu": [ 436 + "x64" 437 + ], 438 + "dev": true, 439 + "license": "MIT", 440 + "optional": true, 441 + "os": [ 442 + "linux" 443 + ], 444 + "engines": { 445 + "node": ">=18" 446 + } 447 + }, 448 + "node_modules/@esbuild/netbsd-arm64": { 449 + "version": "0.27.0", 450 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz", 451 + "integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==", 452 + "cpu": [ 453 + "arm64" 454 + ], 455 + "dev": true, 456 + "license": "MIT", 457 + "optional": true, 458 + "os": [ 459 + "netbsd" 460 + ], 461 + "engines": { 462 + "node": ">=18" 463 + } 464 + }, 465 + "node_modules/@esbuild/netbsd-x64": { 466 + "version": "0.27.0", 467 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz", 468 + "integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==", 469 + "cpu": [ 470 + "x64" 471 + ], 472 + "dev": true, 473 + "license": "MIT", 474 + "optional": true, 475 + "os": [ 476 + "netbsd" 477 + ], 478 + "engines": { 479 + "node": ">=18" 480 + } 481 + }, 482 + "node_modules/@esbuild/openbsd-arm64": { 483 + "version": "0.27.0", 484 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz", 485 + "integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==", 486 + "cpu": [ 487 + "arm64" 488 + ], 489 + "dev": true, 490 + "license": "MIT", 491 + "optional": true, 492 + "os": [ 493 + "openbsd" 494 + ], 495 + "engines": { 496 + "node": ">=18" 497 + } 498 + }, 499 + "node_modules/@esbuild/openbsd-x64": { 500 + "version": "0.27.0", 501 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz", 502 + "integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==", 503 + "cpu": [ 504 + "x64" 505 + ], 506 + "dev": true, 507 + "license": "MIT", 508 + "optional": true, 509 + "os": [ 510 + "openbsd" 511 + ], 512 + "engines": { 513 + "node": ">=18" 514 + } 515 + }, 516 + "node_modules/@esbuild/openharmony-arm64": { 517 + "version": "0.27.0", 518 + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz", 519 + "integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==", 520 + "cpu": [ 521 + "arm64" 522 + ], 523 + "dev": true, 524 + "license": "MIT", 525 + "optional": true, 526 + "os": [ 527 + "openharmony" 528 + ], 529 + "engines": { 530 + "node": ">=18" 531 + } 532 + }, 533 + "node_modules/@esbuild/sunos-x64": { 534 + "version": "0.27.0", 535 + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz", 536 + "integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==", 537 + "cpu": [ 538 + "x64" 539 + ], 540 + "dev": true, 541 + "license": "MIT", 542 + "optional": true, 543 + "os": [ 544 + "sunos" 545 + ], 546 + "engines": { 547 + "node": ">=18" 548 + } 549 + }, 550 + "node_modules/@esbuild/win32-arm64": { 551 + "version": "0.27.0", 552 + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz", 553 + "integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==", 554 + "cpu": [ 555 + "arm64" 556 + ], 557 + "dev": true, 558 + "license": "MIT", 559 + "optional": true, 560 + "os": [ 561 + "win32" 562 + ], 563 + "engines": { 564 + "node": ">=18" 565 + } 566 + }, 567 + "node_modules/@esbuild/win32-ia32": { 568 + "version": "0.27.0", 569 + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz", 570 + "integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==", 571 + "cpu": [ 572 + "ia32" 573 + ], 574 + "dev": true, 575 + "license": "MIT", 576 + "optional": true, 577 + "os": [ 578 + "win32" 579 + ], 580 + "engines": { 581 + "node": ">=18" 582 + } 583 + }, 584 + "node_modules/@esbuild/win32-x64": { 585 + "version": "0.27.0", 586 + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz", 587 + "integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==", 588 + "cpu": [ 589 + "x64" 590 + ], 591 + "dev": true, 592 + "license": "MIT", 593 + "optional": true, 594 + "os": [ 595 + "win32" 596 + ], 597 + "engines": { 598 + "node": ">=18" 599 + } 600 + }, 601 + "node_modules/@img/sharp-darwin-arm64": { 602 + "version": "0.33.5", 603 + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", 604 + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", 605 + "cpu": [ 606 + "arm64" 607 + ], 608 + "dev": true, 609 + "license": "Apache-2.0", 610 + "optional": true, 611 + "os": [ 612 + "darwin" 613 + ], 614 + "engines": { 615 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 616 + }, 617 + "funding": { 618 + "url": "https://opencollective.com/libvips" 619 + }, 620 + "optionalDependencies": { 621 + "@img/sharp-libvips-darwin-arm64": "1.0.4" 622 + } 623 + }, 624 + "node_modules/@img/sharp-darwin-x64": { 625 + "version": "0.33.5", 626 + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", 627 + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", 628 + "cpu": [ 629 + "x64" 630 + ], 631 + "dev": true, 632 + "license": "Apache-2.0", 633 + "optional": true, 634 + "os": [ 635 + "darwin" 636 + ], 637 + "engines": { 638 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 639 + }, 640 + "funding": { 641 + "url": "https://opencollective.com/libvips" 642 + }, 643 + "optionalDependencies": { 644 + "@img/sharp-libvips-darwin-x64": "1.0.4" 645 + } 646 + }, 647 + "node_modules/@img/sharp-libvips-darwin-arm64": { 648 + "version": "1.0.4", 649 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", 650 + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", 651 + "cpu": [ 652 + "arm64" 653 + ], 654 + "dev": true, 655 + "license": "LGPL-3.0-or-later", 656 + "optional": true, 657 + "os": [ 658 + "darwin" 659 + ], 660 + "funding": { 661 + "url": "https://opencollective.com/libvips" 662 + } 663 + }, 664 + "node_modules/@img/sharp-libvips-darwin-x64": { 665 + "version": "1.0.4", 666 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", 667 + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", 668 + "cpu": [ 669 + "x64" 670 + ], 671 + "dev": true, 672 + "license": "LGPL-3.0-or-later", 673 + "optional": true, 674 + "os": [ 675 + "darwin" 676 + ], 677 + "funding": { 678 + "url": "https://opencollective.com/libvips" 679 + } 680 + }, 681 + "node_modules/@img/sharp-libvips-linux-arm": { 682 + "version": "1.0.5", 683 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", 684 + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", 685 + "cpu": [ 686 + "arm" 687 + ], 688 + "dev": true, 689 + "license": "LGPL-3.0-or-later", 690 + "optional": true, 691 + "os": [ 692 + "linux" 693 + ], 694 + "funding": { 695 + "url": "https://opencollective.com/libvips" 696 + } 697 + }, 698 + "node_modules/@img/sharp-libvips-linux-arm64": { 699 + "version": "1.0.4", 700 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", 701 + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", 702 + "cpu": [ 703 + "arm64" 704 + ], 705 + "dev": true, 706 + "license": "LGPL-3.0-or-later", 707 + "optional": true, 708 + "os": [ 709 + "linux" 710 + ], 711 + "funding": { 712 + "url": "https://opencollective.com/libvips" 713 + } 714 + }, 715 + "node_modules/@img/sharp-libvips-linux-s390x": { 716 + "version": "1.0.4", 717 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", 718 + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", 719 + "cpu": [ 720 + "s390x" 721 + ], 722 + "dev": true, 723 + "license": "LGPL-3.0-or-later", 724 + "optional": true, 725 + "os": [ 726 + "linux" 727 + ], 728 + "funding": { 729 + "url": "https://opencollective.com/libvips" 730 + } 731 + }, 732 + "node_modules/@img/sharp-libvips-linux-x64": { 733 + "version": "1.0.4", 734 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", 735 + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", 736 + "cpu": [ 737 + "x64" 738 + ], 739 + "dev": true, 740 + "license": "LGPL-3.0-or-later", 741 + "optional": true, 742 + "os": [ 743 + "linux" 744 + ], 745 + "funding": { 746 + "url": "https://opencollective.com/libvips" 747 + } 748 + }, 749 + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { 750 + "version": "1.0.4", 751 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", 752 + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", 753 + "cpu": [ 754 + "arm64" 755 + ], 756 + "dev": true, 757 + "license": "LGPL-3.0-or-later", 758 + "optional": true, 759 + "os": [ 760 + "linux" 761 + ], 762 + "funding": { 763 + "url": "https://opencollective.com/libvips" 764 + } 765 + }, 766 + "node_modules/@img/sharp-libvips-linuxmusl-x64": { 767 + "version": "1.0.4", 768 + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", 769 + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", 770 + "cpu": [ 771 + "x64" 772 + ], 773 + "dev": true, 774 + "license": "LGPL-3.0-or-later", 775 + "optional": true, 776 + "os": [ 777 + "linux" 778 + ], 779 + "funding": { 780 + "url": "https://opencollective.com/libvips" 781 + } 782 + }, 783 + "node_modules/@img/sharp-linux-arm": { 784 + "version": "0.33.5", 785 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", 786 + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", 787 + "cpu": [ 788 + "arm" 789 + ], 790 + "dev": true, 791 + "license": "Apache-2.0", 792 + "optional": true, 793 + "os": [ 794 + "linux" 795 + ], 796 + "engines": { 797 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 798 + }, 799 + "funding": { 800 + "url": "https://opencollective.com/libvips" 801 + }, 802 + "optionalDependencies": { 803 + "@img/sharp-libvips-linux-arm": "1.0.5" 804 + } 805 + }, 806 + "node_modules/@img/sharp-linux-arm64": { 807 + "version": "0.33.5", 808 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", 809 + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", 810 + "cpu": [ 811 + "arm64" 812 + ], 813 + "dev": true, 814 + "license": "Apache-2.0", 815 + "optional": true, 816 + "os": [ 817 + "linux" 818 + ], 819 + "engines": { 820 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 821 + }, 822 + "funding": { 823 + "url": "https://opencollective.com/libvips" 824 + }, 825 + "optionalDependencies": { 826 + "@img/sharp-libvips-linux-arm64": "1.0.4" 827 + } 828 + }, 829 + "node_modules/@img/sharp-linux-s390x": { 830 + "version": "0.33.5", 831 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", 832 + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", 833 + "cpu": [ 834 + "s390x" 835 + ], 836 + "dev": true, 837 + "license": "Apache-2.0", 838 + "optional": true, 839 + "os": [ 840 + "linux" 841 + ], 842 + "engines": { 843 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 844 + }, 845 + "funding": { 846 + "url": "https://opencollective.com/libvips" 847 + }, 848 + "optionalDependencies": { 849 + "@img/sharp-libvips-linux-s390x": "1.0.4" 850 + } 851 + }, 852 + "node_modules/@img/sharp-linux-x64": { 853 + "version": "0.33.5", 854 + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", 855 + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", 856 + "cpu": [ 857 + "x64" 858 + ], 859 + "dev": true, 860 + "license": "Apache-2.0", 861 + "optional": true, 862 + "os": [ 863 + "linux" 864 + ], 865 + "engines": { 866 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 867 + }, 868 + "funding": { 869 + "url": "https://opencollective.com/libvips" 870 + }, 871 + "optionalDependencies": { 872 + "@img/sharp-libvips-linux-x64": "1.0.4" 873 + } 874 + }, 875 + "node_modules/@img/sharp-linuxmusl-arm64": { 876 + "version": "0.33.5", 877 + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", 878 + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", 879 + "cpu": [ 880 + "arm64" 881 + ], 882 + "dev": true, 883 + "license": "Apache-2.0", 884 + "optional": true, 885 + "os": [ 886 + "linux" 887 + ], 888 + "engines": { 889 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 890 + }, 891 + "funding": { 892 + "url": "https://opencollective.com/libvips" 893 + }, 894 + "optionalDependencies": { 895 + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" 896 + } 897 + }, 898 + "node_modules/@img/sharp-linuxmusl-x64": { 899 + "version": "0.33.5", 900 + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", 901 + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", 902 + "cpu": [ 903 + "x64" 904 + ], 905 + "dev": true, 906 + "license": "Apache-2.0", 907 + "optional": true, 908 + "os": [ 909 + "linux" 910 + ], 911 + "engines": { 912 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 913 + }, 914 + "funding": { 915 + "url": "https://opencollective.com/libvips" 916 + }, 917 + "optionalDependencies": { 918 + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" 919 + } 920 + }, 921 + "node_modules/@img/sharp-wasm32": { 922 + "version": "0.33.5", 923 + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", 924 + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", 925 + "cpu": [ 926 + "wasm32" 927 + ], 928 + "dev": true, 929 + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", 930 + "optional": true, 931 + "dependencies": { 932 + "@emnapi/runtime": "^1.2.0" 933 + }, 934 + "engines": { 935 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 936 + }, 937 + "funding": { 938 + "url": "https://opencollective.com/libvips" 939 + } 940 + }, 941 + "node_modules/@img/sharp-win32-ia32": { 942 + "version": "0.33.5", 943 + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", 944 + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", 945 + "cpu": [ 946 + "ia32" 947 + ], 948 + "dev": true, 949 + "license": "Apache-2.0 AND LGPL-3.0-or-later", 950 + "optional": true, 951 + "os": [ 952 + "win32" 953 + ], 954 + "engines": { 955 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 956 + }, 957 + "funding": { 958 + "url": "https://opencollective.com/libvips" 959 + } 960 + }, 961 + "node_modules/@img/sharp-win32-x64": { 962 + "version": "0.33.5", 963 + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", 964 + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", 965 + "cpu": [ 966 + "x64" 967 + ], 968 + "dev": true, 969 + "license": "Apache-2.0 AND LGPL-3.0-or-later", 970 + "optional": true, 971 + "os": [ 972 + "win32" 973 + ], 974 + "engines": { 975 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 976 + }, 977 + "funding": { 978 + "url": "https://opencollective.com/libvips" 979 + } 980 + }, 981 + "node_modules/@ipld/dag-cbor": { 982 + "version": "9.2.5", 983 + "resolved": "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-9.2.5.tgz", 984 + "integrity": "sha512-84wSr4jv30biui7endhobYhXBQzQE4c/wdoWlFrKcfiwH+ofaPg8fwsM8okX9cOzkkrsAsNdDyH3ou+kiLquwQ==", 985 + "license": "Apache-2.0 OR MIT", 986 + "dependencies": { 987 + "cborg": "^4.0.0", 988 + "multiformats": "^13.1.0" 989 + }, 990 + "engines": { 991 + "node": ">=16.0.0", 992 + "npm": ">=7.0.0" 993 + } 994 + }, 995 + "node_modules/@jridgewell/resolve-uri": { 996 + "version": "3.1.2", 997 + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 998 + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 999 + "dev": true, 1000 + "license": "MIT", 1001 + "engines": { 1002 + "node": ">=6.0.0" 1003 + } 1004 + }, 1005 + "node_modules/@jridgewell/sourcemap-codec": { 1006 + "version": "1.5.5", 1007 + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", 1008 + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", 1009 + "dev": true, 1010 + "license": "MIT" 1011 + }, 1012 + "node_modules/@jridgewell/trace-mapping": { 1013 + "version": "0.3.9", 1014 + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 1015 + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 1016 + "dev": true, 1017 + "license": "MIT", 1018 + "dependencies": { 1019 + "@jridgewell/resolve-uri": "^3.0.3", 1020 + "@jridgewell/sourcemap-codec": "^1.4.10" 1021 + } 1022 + }, 1023 + "node_modules/@noble/curves": { 1024 + "version": "1.9.7", 1025 + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", 1026 + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", 1027 + "license": "MIT", 1028 + "dependencies": { 1029 + "@noble/hashes": "1.8.0" 1030 + }, 1031 + "engines": { 1032 + "node": "^14.21.3 || >=16" 1033 + }, 1034 + "funding": { 1035 + "url": "https://paulmillr.com/funding/" 1036 + } 1037 + }, 1038 + "node_modules/@noble/hashes": { 1039 + "version": "1.8.0", 1040 + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", 1041 + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", 1042 + "license": "MIT", 1043 + "engines": { 1044 + "node": "^14.21.3 || >=16" 1045 + }, 1046 + "funding": { 1047 + "url": "https://paulmillr.com/funding/" 1048 + } 1049 + }, 1050 + "node_modules/@poppinss/colors": { 1051 + "version": "4.1.6", 1052 + "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz", 1053 + "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==", 1054 + "dev": true, 1055 + "license": "MIT", 1056 + "dependencies": { 1057 + "kleur": "^4.1.5" 1058 + } 1059 + }, 1060 + "node_modules/@poppinss/dumper": { 1061 + "version": "0.6.5", 1062 + "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz", 1063 + "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==", 1064 + "dev": true, 1065 + "license": "MIT", 1066 + "dependencies": { 1067 + "@poppinss/colors": "^4.1.5", 1068 + "@sindresorhus/is": "^7.0.2", 1069 + "supports-color": "^10.0.0" 1070 + } 1071 + }, 1072 + "node_modules/@poppinss/exception": { 1073 + "version": "1.2.3", 1074 + "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz", 1075 + "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", 1076 + "dev": true, 1077 + "license": "MIT" 1078 + }, 1079 + "node_modules/@sindresorhus/is": { 1080 + "version": "7.2.0", 1081 + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", 1082 + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", 1083 + "dev": true, 1084 + "license": "MIT", 1085 + "engines": { 1086 + "node": ">=18" 1087 + }, 1088 + "funding": { 1089 + "url": "https://github.com/sindresorhus/is?sponsor=1" 1090 + } 1091 + }, 1092 + "node_modules/@speed-highlight/core": { 1093 + "version": "1.2.14", 1094 + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.14.tgz", 1095 + "integrity": "sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==", 1096 + "dev": true, 1097 + "license": "CC0-1.0" 1098 + }, 1099 + "node_modules/acorn": { 1100 + "version": "8.14.0", 1101 + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", 1102 + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", 1103 + "dev": true, 1104 + "license": "MIT", 1105 + "bin": { 1106 + "acorn": "bin/acorn" 1107 + }, 1108 + "engines": { 1109 + "node": ">=0.4.0" 1110 + } 1111 + }, 1112 + "node_modules/acorn-walk": { 1113 + "version": "8.3.2", 1114 + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", 1115 + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", 1116 + "dev": true, 1117 + "license": "MIT", 1118 + "engines": { 1119 + "node": ">=0.4.0" 1120 + } 1121 + }, 1122 + "node_modules/blake3-wasm": { 1123 + "version": "2.1.5", 1124 + "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", 1125 + "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", 1126 + "dev": true, 1127 + "license": "MIT" 1128 + }, 1129 + "node_modules/cborg": { 1130 + "version": "4.3.2", 1131 + "resolved": "https://registry.npmjs.org/cborg/-/cborg-4.3.2.tgz", 1132 + "integrity": "sha512-l+QzebEAG0vb09YKkaOrMi2zmm80UNjmbvocMIeW5hO7JOXWdrQ/H49yOKfYX0MBgrj/KWgatBnEgRXyNyKD+A==", 1133 + "license": "Apache-2.0", 1134 + "bin": { 1135 + "cborg": "lib/bin.js" 1136 + } 1137 + }, 1138 + "node_modules/color": { 1139 + "version": "4.2.3", 1140 + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", 1141 + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", 1142 + "dev": true, 1143 + "license": "MIT", 1144 + "dependencies": { 1145 + "color-convert": "^2.0.1", 1146 + "color-string": "^1.9.0" 1147 + }, 1148 + "engines": { 1149 + "node": ">=12.5.0" 1150 + } 1151 + }, 1152 + "node_modules/color-convert": { 1153 + "version": "2.0.1", 1154 + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1155 + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1156 + "dev": true, 1157 + "license": "MIT", 1158 + "dependencies": { 1159 + "color-name": "~1.1.4" 1160 + }, 1161 + "engines": { 1162 + "node": ">=7.0.0" 1163 + } 1164 + }, 1165 + "node_modules/color-name": { 1166 + "version": "1.1.4", 1167 + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1168 + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1169 + "dev": true, 1170 + "license": "MIT" 1171 + }, 1172 + "node_modules/color-string": { 1173 + "version": "1.9.1", 1174 + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", 1175 + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", 1176 + "dev": true, 1177 + "license": "MIT", 1178 + "dependencies": { 1179 + "color-name": "^1.0.0", 1180 + "simple-swizzle": "^0.2.2" 1181 + } 1182 + }, 1183 + "node_modules/cookie": { 1184 + "version": "1.1.1", 1185 + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", 1186 + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", 1187 + "dev": true, 1188 + "license": "MIT", 1189 + "engines": { 1190 + "node": ">=18" 1191 + }, 1192 + "funding": { 1193 + "type": "opencollective", 1194 + "url": "https://opencollective.com/express" 1195 + } 1196 + }, 1197 + "node_modules/detect-libc": { 1198 + "version": "2.1.2", 1199 + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", 1200 + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", 1201 + "dev": true, 1202 + "license": "Apache-2.0", 1203 + "engines": { 1204 + "node": ">=8" 1205 + } 1206 + }, 1207 + "node_modules/error-stack-parser-es": { 1208 + "version": "1.0.5", 1209 + "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", 1210 + "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", 1211 + "dev": true, 1212 + "license": "MIT", 1213 + "funding": { 1214 + "url": "https://github.com/sponsors/antfu" 1215 + } 1216 + }, 1217 + "node_modules/esbuild": { 1218 + "version": "0.27.0", 1219 + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz", 1220 + "integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==", 1221 + "dev": true, 1222 + "hasInstallScript": true, 1223 + "license": "MIT", 1224 + "bin": { 1225 + "esbuild": "bin/esbuild" 1226 + }, 1227 + "engines": { 1228 + "node": ">=18" 1229 + }, 1230 + "optionalDependencies": { 1231 + "@esbuild/aix-ppc64": "0.27.0", 1232 + "@esbuild/android-arm": "0.27.0", 1233 + "@esbuild/android-arm64": "0.27.0", 1234 + "@esbuild/android-x64": "0.27.0", 1235 + "@esbuild/darwin-arm64": "0.27.0", 1236 + "@esbuild/darwin-x64": "0.27.0", 1237 + "@esbuild/freebsd-arm64": "0.27.0", 1238 + "@esbuild/freebsd-x64": "0.27.0", 1239 + "@esbuild/linux-arm": "0.27.0", 1240 + "@esbuild/linux-arm64": "0.27.0", 1241 + "@esbuild/linux-ia32": "0.27.0", 1242 + "@esbuild/linux-loong64": "0.27.0", 1243 + "@esbuild/linux-mips64el": "0.27.0", 1244 + "@esbuild/linux-ppc64": "0.27.0", 1245 + "@esbuild/linux-riscv64": "0.27.0", 1246 + "@esbuild/linux-s390x": "0.27.0", 1247 + "@esbuild/linux-x64": "0.27.0", 1248 + "@esbuild/netbsd-arm64": "0.27.0", 1249 + "@esbuild/netbsd-x64": "0.27.0", 1250 + "@esbuild/openbsd-arm64": "0.27.0", 1251 + "@esbuild/openbsd-x64": "0.27.0", 1252 + "@esbuild/openharmony-arm64": "0.27.0", 1253 + "@esbuild/sunos-x64": "0.27.0", 1254 + "@esbuild/win32-arm64": "0.27.0", 1255 + "@esbuild/win32-ia32": "0.27.0", 1256 + "@esbuild/win32-x64": "0.27.0" 1257 + } 1258 + }, 1259 + "node_modules/exit-hook": { 1260 + "version": "2.2.1", 1261 + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", 1262 + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", 1263 + "dev": true, 1264 + "license": "MIT", 1265 + "engines": { 1266 + "node": ">=6" 1267 + }, 1268 + "funding": { 1269 + "url": "https://github.com/sponsors/sindresorhus" 1270 + } 1271 + }, 1272 + "node_modules/fsevents": { 1273 + "version": "2.3.3", 1274 + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1275 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1276 + "dev": true, 1277 + "hasInstallScript": true, 1278 + "license": "MIT", 1279 + "optional": true, 1280 + "os": [ 1281 + "darwin" 1282 + ], 1283 + "engines": { 1284 + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1285 + } 1286 + }, 1287 + "node_modules/glob-to-regexp": { 1288 + "version": "0.4.1", 1289 + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", 1290 + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", 1291 + "dev": true, 1292 + "license": "BSD-2-Clause" 1293 + }, 1294 + "node_modules/is-arrayish": { 1295 + "version": "0.3.4", 1296 + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", 1297 + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", 1298 + "dev": true, 1299 + "license": "MIT" 1300 + }, 1301 + "node_modules/kleur": { 1302 + "version": "4.1.5", 1303 + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", 1304 + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", 1305 + "dev": true, 1306 + "license": "MIT", 1307 + "engines": { 1308 + "node": ">=6" 1309 + } 1310 + }, 1311 + "node_modules/mime": { 1312 + "version": "3.0.0", 1313 + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", 1314 + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", 1315 + "dev": true, 1316 + "license": "MIT", 1317 + "bin": { 1318 + "mime": "cli.js" 1319 + }, 1320 + "engines": { 1321 + "node": ">=10.0.0" 1322 + } 1323 + }, 1324 + "node_modules/miniflare": { 1325 + "version": "4.20260103.0", 1326 + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260103.0.tgz", 1327 + "integrity": "sha512-iuSU0e+KMuFD7gxuPKoJXFi6cvDu/w/lQP4Wayq3v+YsmZ0dVMAJY9LMZ0TKMLicdAj2So9WcReAhJmJJ9Ppnw==", 1328 + "dev": true, 1329 + "license": "MIT", 1330 + "dependencies": { 1331 + "@cspotcode/source-map-support": "0.8.1", 1332 + "acorn": "8.14.0", 1333 + "acorn-walk": "8.3.2", 1334 + "exit-hook": "2.2.1", 1335 + "glob-to-regexp": "0.4.1", 1336 + "sharp": "^0.33.5", 1337 + "stoppable": "1.1.0", 1338 + "undici": "7.14.0", 1339 + "workerd": "1.20260103.0", 1340 + "ws": "8.18.0", 1341 + "youch": "4.1.0-beta.10", 1342 + "zod": "^3.25.76" 1343 + }, 1344 + "bin": { 1345 + "miniflare": "bootstrap.js" 1346 + }, 1347 + "engines": { 1348 + "node": ">=18.0.0" 1349 + } 1350 + }, 1351 + "node_modules/multiformats": { 1352 + "version": "13.4.2", 1353 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.4.2.tgz", 1354 + "integrity": "sha512-eh6eHCrRi1+POZ3dA+Dq1C6jhP1GNtr9CRINMb67OKzqW9I5DUuZM/3jLPlzhgpGeiNUlEGEbkCYChXMCc/8DQ==", 1355 + "license": "Apache-2.0 OR MIT" 1356 + }, 1357 + "node_modules/path-to-regexp": { 1358 + "version": "6.3.0", 1359 + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", 1360 + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", 1361 + "dev": true, 1362 + "license": "MIT" 1363 + }, 1364 + "node_modules/pathe": { 1365 + "version": "2.0.3", 1366 + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", 1367 + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", 1368 + "dev": true, 1369 + "license": "MIT" 1370 + }, 1371 + "node_modules/semver": { 1372 + "version": "7.7.3", 1373 + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", 1374 + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", 1375 + "dev": true, 1376 + "license": "ISC", 1377 + "bin": { 1378 + "semver": "bin/semver.js" 1379 + }, 1380 + "engines": { 1381 + "node": ">=10" 1382 + } 1383 + }, 1384 + "node_modules/sharp": { 1385 + "version": "0.33.5", 1386 + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", 1387 + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", 1388 + "dev": true, 1389 + "hasInstallScript": true, 1390 + "license": "Apache-2.0", 1391 + "dependencies": { 1392 + "color": "^4.2.3", 1393 + "detect-libc": "^2.0.3", 1394 + "semver": "^7.6.3" 1395 + }, 1396 + "engines": { 1397 + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" 1398 + }, 1399 + "funding": { 1400 + "url": "https://opencollective.com/libvips" 1401 + }, 1402 + "optionalDependencies": { 1403 + "@img/sharp-darwin-arm64": "0.33.5", 1404 + "@img/sharp-darwin-x64": "0.33.5", 1405 + "@img/sharp-libvips-darwin-arm64": "1.0.4", 1406 + "@img/sharp-libvips-darwin-x64": "1.0.4", 1407 + "@img/sharp-libvips-linux-arm": "1.0.5", 1408 + "@img/sharp-libvips-linux-arm64": "1.0.4", 1409 + "@img/sharp-libvips-linux-s390x": "1.0.4", 1410 + "@img/sharp-libvips-linux-x64": "1.0.4", 1411 + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", 1412 + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", 1413 + "@img/sharp-linux-arm": "0.33.5", 1414 + "@img/sharp-linux-arm64": "0.33.5", 1415 + "@img/sharp-linux-s390x": "0.33.5", 1416 + "@img/sharp-linux-x64": "0.33.5", 1417 + "@img/sharp-linuxmusl-arm64": "0.33.5", 1418 + "@img/sharp-linuxmusl-x64": "0.33.5", 1419 + "@img/sharp-wasm32": "0.33.5", 1420 + "@img/sharp-win32-ia32": "0.33.5", 1421 + "@img/sharp-win32-x64": "0.33.5" 1422 + } 1423 + }, 1424 + "node_modules/simple-swizzle": { 1425 + "version": "0.2.4", 1426 + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", 1427 + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", 1428 + "dev": true, 1429 + "license": "MIT", 1430 + "dependencies": { 1431 + "is-arrayish": "^0.3.1" 1432 + } 1433 + }, 1434 + "node_modules/stoppable": { 1435 + "version": "1.1.0", 1436 + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", 1437 + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", 1438 + "dev": true, 1439 + "license": "MIT", 1440 + "engines": { 1441 + "node": ">=4", 1442 + "npm": ">=6" 1443 + } 1444 + }, 1445 + "node_modules/supports-color": { 1446 + "version": "10.2.2", 1447 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", 1448 + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", 1449 + "dev": true, 1450 + "license": "MIT", 1451 + "engines": { 1452 + "node": ">=18" 1453 + }, 1454 + "funding": { 1455 + "url": "https://github.com/chalk/supports-color?sponsor=1" 1456 + } 1457 + }, 1458 + "node_modules/tslib": { 1459 + "version": "2.8.1", 1460 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 1461 + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 1462 + "dev": true, 1463 + "license": "0BSD", 1464 + "optional": true 1465 + }, 1466 + "node_modules/uint8arrays": { 1467 + "version": "5.1.0", 1468 + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", 1469 + "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", 1470 + "license": "Apache-2.0 OR MIT", 1471 + "dependencies": { 1472 + "multiformats": "^13.0.0" 1473 + } 1474 + }, 1475 + "node_modules/undici": { 1476 + "version": "7.14.0", 1477 + "resolved": "https://registry.npmjs.org/undici/-/undici-7.14.0.tgz", 1478 + "integrity": "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==", 1479 + "dev": true, 1480 + "license": "MIT", 1481 + "engines": { 1482 + "node": ">=20.18.1" 1483 + } 1484 + }, 1485 + "node_modules/unenv": { 1486 + "version": "2.0.0-rc.24", 1487 + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", 1488 + "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", 1489 + "dev": true, 1490 + "license": "MIT", 1491 + "dependencies": { 1492 + "pathe": "^2.0.3" 1493 + } 1494 + }, 1495 + "node_modules/workerd": { 1496 + "version": "1.20260103.0", 1497 + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260103.0.tgz", 1498 + "integrity": "sha512-uB5eliFHVCdPD3uaPGe6zNRFjWzijOb26c0/1oXKmQFUSUR7GFPCTTd0iJXZAGKZDZ0DNgzQCPoolWelz6W5Zg==", 1499 + "dev": true, 1500 + "hasInstallScript": true, 1501 + "license": "Apache-2.0", 1502 + "bin": { 1503 + "workerd": "bin/workerd" 1504 + }, 1505 + "engines": { 1506 + "node": ">=16" 1507 + }, 1508 + "optionalDependencies": { 1509 + "@cloudflare/workerd-darwin-64": "1.20260103.0", 1510 + "@cloudflare/workerd-darwin-arm64": "1.20260103.0", 1511 + "@cloudflare/workerd-linux-64": "1.20260103.0", 1512 + "@cloudflare/workerd-linux-arm64": "1.20260103.0", 1513 + "@cloudflare/workerd-windows-64": "1.20260103.0" 1514 + } 1515 + }, 1516 + "node_modules/wrangler": { 1517 + "version": "4.57.0", 1518 + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.57.0.tgz", 1519 + "integrity": "sha512-JTVHmL2zr5PUJ22kT21fNXZBgVm4WzXSHsVc+VVIRANBVgTwn6EikXBx1DMyvHDQP6vkaojuyrRjeasB7rxV9A==", 1520 + "dev": true, 1521 + "license": "MIT OR Apache-2.0", 1522 + "dependencies": { 1523 + "@cloudflare/kv-asset-handler": "0.4.1", 1524 + "@cloudflare/unenv-preset": "2.8.0", 1525 + "blake3-wasm": "2.1.5", 1526 + "esbuild": "0.27.0", 1527 + "miniflare": "4.20260103.0", 1528 + "path-to-regexp": "6.3.0", 1529 + "unenv": "2.0.0-rc.24", 1530 + "workerd": "1.20260103.0" 1531 + }, 1532 + "bin": { 1533 + "wrangler": "bin/wrangler.js", 1534 + "wrangler2": "bin/wrangler.js" 1535 + }, 1536 + "engines": { 1537 + "node": ">=20.0.0" 1538 + }, 1539 + "optionalDependencies": { 1540 + "fsevents": "~2.3.2" 1541 + }, 1542 + "peerDependencies": { 1543 + "@cloudflare/workers-types": "^4.20260103.0" 1544 + }, 1545 + "peerDependenciesMeta": { 1546 + "@cloudflare/workers-types": { 1547 + "optional": true 1548 + } 1549 + } 1550 + }, 1551 + "node_modules/ws": { 1552 + "version": "8.18.0", 1553 + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", 1554 + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", 1555 + "dev": true, 1556 + "license": "MIT", 1557 + "engines": { 1558 + "node": ">=10.0.0" 1559 + }, 1560 + "peerDependencies": { 1561 + "bufferutil": "^4.0.1", 1562 + "utf-8-validate": ">=5.0.2" 1563 + }, 1564 + "peerDependenciesMeta": { 1565 + "bufferutil": { 1566 + "optional": true 1567 + }, 1568 + "utf-8-validate": { 1569 + "optional": true 1570 + } 1571 + } 1572 + }, 1573 + "node_modules/youch": { 1574 + "version": "4.1.0-beta.10", 1575 + "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz", 1576 + "integrity": "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==", 1577 + "dev": true, 1578 + "license": "MIT", 1579 + "dependencies": { 1580 + "@poppinss/colors": "^4.1.5", 1581 + "@poppinss/dumper": "^0.6.4", 1582 + "@speed-highlight/core": "^1.2.7", 1583 + "cookie": "^1.0.2", 1584 + "youch-core": "^0.3.3" 1585 + } 1586 + }, 1587 + "node_modules/youch-core": { 1588 + "version": "0.3.3", 1589 + "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz", 1590 + "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==", 1591 + "dev": true, 1592 + "license": "MIT", 1593 + "dependencies": { 1594 + "@poppinss/exception": "^1.2.2", 1595 + "error-stack-parser-es": "^1.0.5" 1596 + } 1597 + }, 1598 + "node_modules/zod": { 1599 + "version": "3.25.76", 1600 + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", 1601 + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", 1602 + "dev": true, 1603 + "license": "MIT", 1604 + "funding": { 1605 + "url": "https://github.com/sponsors/colinhacks" 1606 + } 1607 + } 1608 + } 1609 + }
+20
labeler/package.json
··· 1 + { 2 + "name": "spam-labeler", 3 + "version": "0.0.1", 4 + "private": true, 5 + "type": "module", 6 + "scripts": { 7 + "dev": "wrangler dev", 8 + "deploy": "wrangler deploy" 9 + }, 10 + "dependencies": { 11 + "@ipld/dag-cbor": "^9.2.5", 12 + "@noble/curves": "^1.8.1", 13 + "@noble/hashes": "^1.7.1", 14 + "multiformats": "^13.3.1", 15 + "uint8arrays": "^5.1.0" 16 + }, 17 + "devDependencies": { 18 + "wrangler": "^4.0.0" 19 + } 20 + }
+116
labeler/scripts/create-did.js
··· 1 + /** 2 + * Script to create a labeler DID on plc.directory 3 + * 4 + * Run with: node scripts/create-did.js <labeler-endpoint> 5 + * Example: node scripts/create-did.js https://spam-labeler.nate-8fe.workers.dev 6 + */ 7 + 8 + import { secp256k1 } from '@noble/curves/secp256k1'; 9 + import { sha256 } from '@noble/hashes/sha256'; 10 + import * as cbor from '@ipld/dag-cbor'; 11 + import { base32 } from 'multiformats/bases/base32'; 12 + import * as uint8arrays from 'uint8arrays'; 13 + 14 + const PLC_DIRECTORY = 'https://plc.directory'; 15 + 16 + // Generate a new secp256k1 keypair 17 + function generateKeypair() { 18 + const privateKey = secp256k1.utils.randomPrivateKey(); 19 + const publicKey = secp256k1.getPublicKey(privateKey, true); // compressed 20 + return { privateKey, publicKey }; 21 + } 22 + 23 + // Convert public key to did:key format for secp256k1 24 + function publicKeyToDidKey(publicKey) { 25 + // secp256k1 multicodec prefix is 0xe7 0x01 26 + const multicodec = new Uint8Array([0xe7, 0x01, ...publicKey]); 27 + const encoded = uint8arrays.toString(multicodec, 'base58btc'); 28 + return `did:key:z${encoded}`; 29 + } 30 + 31 + // Sign an operation with secp256k1 32 + async function signOperation(unsigned, privateKey) { 33 + const bytes = cbor.encode(unsigned); 34 + const hash = sha256(bytes); 35 + const sig = secp256k1.sign(hash, privateKey, { lowS: true }); 36 + const sigBytes = sig.toCompactRawBytes(); 37 + const sigB64 = uint8arrays.toString(sigBytes, 'base64url'); 38 + return { ...unsigned, sig: sigB64 }; 39 + } 40 + 41 + // Compute DID from genesis operation 42 + async function didForCreateOp(op) { 43 + const bytes = cbor.encode(op); 44 + const hash = sha256(bytes); 45 + const hashB32 = uint8arrays.toString(hash, 'base32'); 46 + const truncated = hashB32.slice(0, 24); 47 + return `did:plc:${truncated}`; 48 + } 49 + 50 + async function main() { 51 + const endpoint = process.argv[2]; 52 + if (!endpoint) { 53 + console.error('Usage: node scripts/create-did.js <labeler-endpoint>'); 54 + console.error('Example: node scripts/create-did.js https://spam-labeler.nate-8fe.workers.dev'); 55 + process.exit(1); 56 + } 57 + 58 + console.log('Generating secp256k1 keypair...'); 59 + const { privateKey, publicKey } = generateKeypair(); 60 + const didKey = publicKeyToDidKey(publicKey); 61 + 62 + console.log('Creating labeler DID operation...'); 63 + const unsigned = { 64 + type: 'plc_operation', 65 + alsoKnownAs: [], 66 + rotationKeys: [didKey], 67 + verificationMethods: { 68 + atproto_label: didKey, 69 + }, 70 + services: { 71 + atproto_labeler: { 72 + type: 'AtprotoLabeler', 73 + endpoint: endpoint, 74 + }, 75 + }, 76 + prev: null, 77 + }; 78 + 79 + const signed = await signOperation(unsigned, privateKey); 80 + const did = await didForCreateOp(signed); 81 + 82 + console.log('\n=== LABELER CREDENTIALS ===\n'); 83 + console.log('DID:', did); 84 + console.log('Private Key (hex):', uint8arrays.toString(privateKey, 'hex')); 85 + console.log('Public Key (did:key):', didKey); 86 + console.log('\nEndpoint:', endpoint); 87 + 88 + console.log('\n=== SUBMITTING TO PLC DIRECTORY ===\n'); 89 + 90 + try { 91 + const res = await fetch(`${PLC_DIRECTORY}/${did}`, { 92 + method: 'POST', 93 + headers: { 'Content-Type': 'application/json' }, 94 + body: JSON.stringify(signed), 95 + }); 96 + 97 + if (res.ok) { 98 + console.log('SUCCESS! DID created on plc.directory'); 99 + console.log('\nVerify at:', `${PLC_DIRECTORY}/${did}`); 100 + 101 + console.log('\n=== NEXT STEPS ===\n'); 102 + console.log('1. Add to wrangler.toml:'); 103 + console.log(` LABELER_DID = "${did}"`); 104 + console.log('\n2. Set the secret:'); 105 + console.log(` wrangler secret put SIGNING_KEY`); 106 + console.log(` (paste the private key hex when prompted)`); 107 + } else { 108 + const text = await res.text(); 109 + console.error('Failed to create DID:', res.status, text); 110 + } 111 + } catch (err) { 112 + console.error('Error:', err.message); 113 + } 114 + } 115 + 116 + main();
+284
labeler/src/labeler.js
··· 1 + /** 2 + * Spam Labeler - ATProto-compliant labeler service for the PDS messaging demo 3 + * 4 + * Endpoints: 5 + * - GET /xrpc/com.atproto.label.queryLabels - query labels by URI pattern 6 + * - POST /xrpc/xyz.fake.labeler.addSpam - add spam label to a DID 7 + * - POST /xrpc/xyz.fake.labeler.removeSpam - remove spam label from a DID 8 + * - GET /xrpc/xyz.fake.labeler.listSpam - list all spam-labeled DIDs 9 + */ 10 + 11 + import { secp256k1 } from '@noble/curves/secp256k1'; 12 + import { sha256 } from '@noble/hashes/sha256'; 13 + import * as cbor from '@ipld/dag-cbor'; 14 + import * as uint8arrays from 'uint8arrays'; 15 + 16 + // CORS headers 17 + const CORS_HEADERS = { 18 + 'Access-Control-Allow-Origin': '*', 19 + 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 20 + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', 21 + }; 22 + 23 + /** 24 + * Sign a label with the labeler's secp256k1 key 25 + */ 26 + function signLabel(label, privateKeyHex) { 27 + const privateKey = uint8arrays.fromString(privateKeyHex, 'hex'); 28 + 29 + // Create unsigned label (without sig field) 30 + const unsigned = { 31 + ver: label.ver, 32 + src: label.src, 33 + uri: label.uri, 34 + val: label.val, 35 + cts: label.cts, 36 + }; 37 + if (label.cid) unsigned.cid = label.cid; 38 + if (label.neg) unsigned.neg = label.neg; 39 + if (label.exp) unsigned.exp = label.exp; 40 + 41 + // Encode to DAG-CBOR and sign 42 + const bytes = cbor.encode(unsigned); 43 + const hash = sha256(bytes); 44 + const sig = secp256k1.sign(hash, privateKey, { lowS: true }); 45 + 46 + return { 47 + ...unsigned, 48 + sig: sig.toCompactRawBytes(), 49 + }; 50 + } 51 + 52 + /** 53 + * Create a new spam label for a DID 54 + */ 55 + function createSpamLabel(did, labelerDid, privateKeyHex, neg = false) { 56 + const label = { 57 + ver: 1, 58 + src: labelerDid, 59 + uri: did, // Label applies to the account (DID) 60 + val: 'spam', 61 + cts: new Date().toISOString(), 62 + }; 63 + if (neg) label.neg = true; 64 + 65 + return signLabel(label, privateKeyHex); 66 + } 67 + 68 + /** 69 + * Serialize label for JSON response (convert Uint8Array sig to base64) 70 + */ 71 + function serializeLabel(label) { 72 + return { 73 + ...label, 74 + sig: label.sig ? uint8arrays.toString(label.sig, 'base64') : undefined, 75 + }; 76 + } 77 + 78 + /** 79 + * Parse stored label from KV (sig is stored as base64) 80 + */ 81 + function parseStoredLabel(stored) { 82 + return { 83 + ...stored, 84 + sig: stored.sig ? uint8arrays.fromString(stored.sig, 'base64') : undefined, 85 + }; 86 + } 87 + 88 + /** 89 + * Handle OPTIONS preflight 90 + */ 91 + function handleOptions() { 92 + return new Response(null, { status: 204, headers: CORS_HEADERS }); 93 + } 94 + 95 + /** 96 + * JSON response helper 97 + */ 98 + function jsonResponse(data, status = 200) { 99 + return new Response(JSON.stringify(data), { 100 + status, 101 + headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' }, 102 + }); 103 + } 104 + 105 + /** 106 + * Error response helper 107 + */ 108 + function errorResponse(error, message, status = 400) { 109 + return jsonResponse({ error, message }, status); 110 + } 111 + 112 + /** 113 + * GET /xrpc/com.atproto.label.queryLabels 114 + * 115 + * Query labels by URI patterns. For this demo labeler, we only have spam labels on DIDs. 116 + */ 117 + async function handleQueryLabels(url, env) { 118 + const uriPatterns = url.searchParams.get('uriPatterns'); 119 + if (!uriPatterns) { 120 + return errorResponse('InvalidRequest', 'uriPatterns required'); 121 + } 122 + 123 + const patterns = uriPatterns.split(',').map((p) => p.trim()); 124 + const labels = []; 125 + 126 + // Get all spam DIDs from KV 127 + const list = await env.LABELS.list({ prefix: 'label:' }); 128 + 129 + for (const key of list.keys) { 130 + const stored = await env.LABELS.get(key.name, 'json'); 131 + if (!stored) continue; 132 + 133 + // Check if this label matches any of the patterns 134 + const labelUri = stored.uri; 135 + const matches = patterns.some((pattern) => { 136 + if (pattern.endsWith('*')) { 137 + return labelUri.startsWith(pattern.slice(0, -1)); 138 + } 139 + return labelUri === pattern; 140 + }); 141 + 142 + if (matches) { 143 + labels.push(serializeLabel(parseStoredLabel(stored))); 144 + } 145 + } 146 + 147 + return jsonResponse({ labels }); 148 + } 149 + 150 + /** 151 + * POST /xrpc/xyz.fake.labeler.addSpam 152 + * 153 + * Add a spam label to a DID. Body: { did: "did:plc:..." } 154 + */ 155 + async function handleAddSpam(request, env) { 156 + const body = await request.json(); 157 + const did = body.did; 158 + 159 + if (!did || !did.startsWith('did:')) { 160 + return errorResponse('InvalidRequest', 'valid did required'); 161 + } 162 + 163 + // Check if already labeled 164 + const existing = await env.LABELS.get(`label:${did}`, 'json'); 165 + if (existing && !existing.neg) { 166 + return jsonResponse({ status: 'already_labeled', did }); 167 + } 168 + 169 + // Create and sign the spam label 170 + const label = createSpamLabel(did, env.LABELER_DID, env.SIGNING_KEY); 171 + 172 + // Store in KV (serialize sig as base64 for storage) 173 + await env.LABELS.put(`label:${did}`, JSON.stringify(serializeLabel(label))); 174 + 175 + // Also maintain a set of spam DIDs for quick lookup 176 + await env.LABELS.put(`spam:${did}`, '1'); 177 + 178 + return jsonResponse({ status: 'labeled', did, label: serializeLabel(label) }); 179 + } 180 + 181 + /** 182 + * POST /xrpc/xyz.fake.labeler.removeSpam 183 + * 184 + * Remove spam label from a DID by emitting a negation label. 185 + * Body: { did: "did:plc:..." } 186 + */ 187 + async function handleRemoveSpam(request, env) { 188 + const body = await request.json(); 189 + const did = body.did; 190 + 191 + if (!did || !did.startsWith('did:')) { 192 + return errorResponse('InvalidRequest', 'valid did required'); 193 + } 194 + 195 + // Check if labeled 196 + const existing = await env.LABELS.get(`label:${did}`, 'json'); 197 + if (!existing || existing.neg) { 198 + return jsonResponse({ status: 'not_labeled', did }); 199 + } 200 + 201 + // Create negation label 202 + const negLabel = createSpamLabel(did, env.LABELER_DID, env.SIGNING_KEY, true); 203 + 204 + // Update stored label to negation 205 + await env.LABELS.put(`label:${did}`, JSON.stringify(serializeLabel(negLabel))); 206 + 207 + // Remove from spam set 208 + await env.LABELS.delete(`spam:${did}`); 209 + 210 + return jsonResponse({ status: 'unlabeled', did, label: serializeLabel(negLabel) }); 211 + } 212 + 213 + /** 214 + * GET /xrpc/xyz.fake.labeler.listSpam 215 + * 216 + * List all DIDs currently labeled as spam. 217 + */ 218 + async function handleListSpam(env) { 219 + const list = await env.LABELS.list({ prefix: 'spam:' }); 220 + const dids = list.keys.map((k) => k.name.replace('spam:', '')); 221 + return jsonResponse({ dids }); 222 + } 223 + 224 + /** 225 + * GET /xrpc/xyz.fake.labeler.hasSpam 226 + * 227 + * Check if a DID has spam label. Query param: ?did=did:plc:... 228 + */ 229 + async function handleHasSpam(url, env) { 230 + const did = url.searchParams.get('did'); 231 + if (!did) { 232 + return errorResponse('InvalidRequest', 'did query param required'); 233 + } 234 + 235 + const hasSpam = (await env.LABELS.get(`spam:${did}`)) !== null; 236 + return jsonResponse({ did, spam: hasSpam }); 237 + } 238 + 239 + /** 240 + * Main request handler 241 + */ 242 + export default { 243 + async fetch(request, env) { 244 + const url = new URL(request.url); 245 + const path = url.pathname; 246 + 247 + // Handle CORS preflight 248 + if (request.method === 'OPTIONS') { 249 + return handleOptions(); 250 + } 251 + 252 + // Health check 253 + if (path === '/health' || path === '/') { 254 + return jsonResponse({ 255 + status: 'ok', 256 + labeler: env.LABELER_DID || 'not configured', 257 + }); 258 + } 259 + 260 + // ATProto standard endpoint 261 + if (path === '/xrpc/com.atproto.label.queryLabels' && request.method === 'GET') { 262 + return handleQueryLabels(url, env); 263 + } 264 + 265 + // Demo-specific endpoints 266 + if (path === '/xrpc/xyz.fake.labeler.addSpam' && request.method === 'POST') { 267 + return handleAddSpam(request, env); 268 + } 269 + 270 + if (path === '/xrpc/xyz.fake.labeler.removeSpam' && request.method === 'POST') { 271 + return handleRemoveSpam(request, env); 272 + } 273 + 274 + if (path === '/xrpc/xyz.fake.labeler.listSpam' && request.method === 'GET') { 275 + return handleListSpam(env); 276 + } 277 + 278 + if (path === '/xrpc/xyz.fake.labeler.hasSpam' && request.method === 'GET') { 279 + return handleHasSpam(url, env); 280 + } 281 + 282 + return errorResponse('NotFound', `unknown endpoint: ${path}`, 404); 283 + }, 284 + };
+11
labeler/wrangler.toml
··· 1 + name = "spam-labeler" 2 + main = "src/labeler.js" 3 + compatibility_date = "2024-09-23" 4 + compatibility_flags = ["nodejs_compat"] 5 + 6 + [vars] 7 + LABELER_DID = "did:plc:x6io7svnbth4pikg2e63vvkx" 8 + 9 + [[kv_namespaces]] 10 + binding = "LABELS" 11 + id = "6d64184bb18645ccaf4229586ff350d6"
+46 -7
src/lib/client.js
··· 197 197 } 198 198 } 199 199 200 + const LABELER_URL = 'https://spam-labeler.nate-8fe.workers.dev'; 201 + 200 202 export class LabelerClient { 201 203 constructor() { 202 - this.labels = new Map(); 204 + // cache of spam-labeled DIDs (synced with remote) 205 + this.spamDids = new Set(); 203 206 } 204 207 205 - addLabel(did, label) { 206 - if (!this.labels.has(did)) this.labels.set(did, new Set()); 207 - this.labels.get(did).add(label); 208 + async addLabel(did, label) { 209 + if (label !== 'spam') return; 210 + try { 211 + const res = await fetch(`${LABELER_URL}/xrpc/xyz.fake.labeler.addSpam`, { 212 + method: 'POST', 213 + headers: { 'Content-Type': 'application/json' }, 214 + body: JSON.stringify({ did }) 215 + }); 216 + if (res.ok) { 217 + this.spamDids.add(did); 218 + } 219 + } catch (e) { 220 + console.error('labeler addLabel failed:', e); 221 + } 208 222 } 209 223 210 - removeLabel(did, label) { 211 - if (this.labels.has(did)) this.labels.get(did).delete(label); 224 + async removeLabel(did, label) { 225 + if (label !== 'spam') return; 226 + try { 227 + const res = await fetch(`${LABELER_URL}/xrpc/xyz.fake.labeler.removeSpam`, { 228 + method: 'POST', 229 + headers: { 'Content-Type': 'application/json' }, 230 + body: JSON.stringify({ did }) 231 + }); 232 + if (res.ok) { 233 + this.spamDids.delete(did); 234 + } 235 + } catch (e) { 236 + console.error('labeler removeLabel failed:', e); 237 + } 212 238 } 213 239 214 240 hasLabel(did, label) { 215 - return this.labels.has(did) && this.labels.get(did).has(label); 241 + if (label !== 'spam') return false; 242 + return this.spamDids.has(did); 243 + } 244 + 245 + async sync() { 246 + try { 247 + const res = await fetch(`${LABELER_URL}/xrpc/xyz.fake.labeler.listSpam`); 248 + if (res.ok) { 249 + const { dids } = await res.json(); 250 + this.spamDids = new Set(dids); 251 + } 252 + } catch (e) { 253 + console.error('labeler sync failed:', e); 254 + } 216 255 } 217 256 } 218 257
+1 -1
src/lib/components/PdsPanel.svelte
··· 37 37 <div class="inbox"> 38 38 <h3>inbox</h3> 39 39 {#if pds.inbox.length > 0} 40 - {#each pds.inbox.slice(-5) as msg} 40 + {#each pds.inbox.slice(0, 5) as msg} 41 41 <div class="message"> 42 42 <span class="from">{getShortName(msg.from)}</span> 43 43 <span class="text">{msg.text}</span>
+1 -1
src/lib/stores.js
··· 1 1 import { writable } from 'svelte/store'; 2 2 import { createClients, LabelerClient } from './client.js'; 3 3 4 - // global labeler instance (still in-memory for demo) 4 + // global labeler instance using real ATProto labeler 5 5 export const labeler = new LabelerClient(); 6 6 7 7 // network of PDS clients (populated on init)
+5 -3
src/routes/+page.svelte
··· 33 33 onMount(async () => { 34 34 try { 35 35 await initNetwork(); 36 + await labeler.sync(); 36 37 log('connected', 'green'); 37 38 ready.set(true); 38 39 } catch (e) { ··· 121 122 [senderHandle, recipientHandle] = [recipientHandle, senderHandle]; 122 123 } 123 124 124 - function toggleSpam() { 125 + async function toggleSpam() { 125 126 if (labeler.hasLabel(sender.did, 'spam')) { 126 - labeler.removeLabel(sender.did, 'spam'); 127 + await labeler.removeLabel(sender.did, 'spam'); 127 128 log(`removed 'spam' from ${senderHandle}`, 'magenta'); 128 129 } else { 129 - labeler.addLabel(sender.did, 'spam'); 130 + await labeler.addLabel(sender.did, 'spam'); 130 131 log(`added 'spam' to ${senderHandle}`, 'magenta'); 131 132 } 133 + refresh(); 132 134 } 133 135 134 136 function getShortName(did) {