Superpowered to do lists. No signup required.

Compare changes

Choose any two refs to compare.

+36 -176
bun.lock
··· 4 4 "": { 5 5 "name": "easytodo.link", 6 6 "dependencies": { 7 - "@atproto/api": "latest", 8 - "@atproto/oauth-client-node": "latest", 9 - "@oslojs/encoding": "latest", 10 - "@tailwindcss/vite": "latest", 11 - "drizzle-orm": "latest", 12 - "oslo": "latest", 13 - "postgres": "latest", 14 - "svelte-french-toast": "latest", 15 - "tailwindcss": "latest", 7 + "@tailwindcss/vite": "^4.1.13", 8 + "oslo": "^1.2.1", 9 + "svelte-french-toast": "^1.2.0", 10 + "tailwindcss": "^4.1.13", 16 11 }, 17 12 "devDependencies": { 18 - "@sveltejs/adapter-netlify": "latest", 19 - "@sveltejs/kit": "latest", 20 - "@sveltejs/vite-plugin-svelte": "latest", 21 - "drizzle-kit": "latest", 22 - "svelte": "latest", 23 - "svelte-check": "latest", 24 - "tslib": "latest", 25 - "typescript": "latest", 26 - "vite": "latest", 13 + "@deno/svelte-adapter": "^0.1.0", 14 + "@sveltejs/kit": "^2.43.5", 15 + "@sveltejs/vite-plugin-svelte": "^6.2.1", 16 + "svelte": "^5.39.6", 17 + "svelte-check": "^4.3.2", 18 + "tslib": "^2.8.1", 19 + "typescript": "^5.9.2", 20 + "vite": "^7.1.7", 27 21 }, 28 22 }, 29 23 }, 30 24 "packages": { 31 - "@atproto-labs/did-resolver": ["@atproto-labs/did-resolver@0.2.1", "", { "dependencies": { "@atproto-labs/fetch": "0.2.3", "@atproto-labs/pipe": "0.1.1", "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.0", "zod": "^3.23.8" } }, "sha512-zSoHyqwwRYUtMNLW+RrWsImt1U5S47nJv5FfmAXTmon6wVKjxKD/PFrD1pg/4G6THqJmQHTs1Hj+54XVupYnvQ=="], 32 - 33 - "@atproto-labs/fetch": ["@atproto-labs/fetch@0.2.3", "", { "dependencies": { "@atproto-labs/pipe": "0.1.1" } }, "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw=="], 34 - 35 - "@atproto-labs/fetch-node": ["@atproto-labs/fetch-node@0.1.10", "", { "dependencies": { "@atproto-labs/fetch": "0.2.3", "@atproto-labs/pipe": "0.1.1", "ipaddr.js": "^2.1.0", "undici": "^6.14.1" } }, "sha512-o7hGaonA71A6p7O107VhM6UBUN/g9tTyYohMp1q0Kf6xQ4npnuZYRSHSf2g6reSfGQJ1GoFNjBObETTT1ge/jQ=="], 36 - 37 - "@atproto-labs/handle-resolver": ["@atproto-labs/handle-resolver@0.3.1", "", { "dependencies": { "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.0", "zod": "^3.23.8" } }, "sha512-mLZdMNvwomgnn9sffKO1/xr02ctgeiT0FUVw7JekbchTckub2RM7qMu8Rw1mC4bpCpW+i7DXDiOxpoajkppwYQ=="], 38 - 39 - "@atproto-labs/handle-resolver-node": ["@atproto-labs/handle-resolver-node@0.1.19", "", { "dependencies": { "@atproto-labs/fetch-node": "0.1.10", "@atproto-labs/handle-resolver": "0.3.1", "@atproto/did": "0.2.0" } }, "sha512-nNVCfiKudvMYfDcWCa9koOMOpCYaC0wG4Uys5dZev99s/Nka7tRlIZIV+u+GWivnG9lqCupKATkoyCd6Per8Gw=="], 40 - 41 - "@atproto-labs/identity-resolver": ["@atproto-labs/identity-resolver@0.3.1", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.1", "@atproto-labs/handle-resolver": "0.3.1" } }, "sha512-jCgotRRqPykPwh4gh0FBLOqeofv1G8OH/DZ5s88HWm7biUZeksZwDrEvL5TnqEFUpXT3O9Hcyp/XEpfCAplRoQ=="], 42 - 43 - "@atproto-labs/pipe": ["@atproto-labs/pipe@0.1.1", "", {}, "sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg=="], 44 - 45 - "@atproto-labs/simple-store": ["@atproto-labs/simple-store@0.3.0", "", {}, "sha512-nOb6ONKBRJHRlukW1sVawUkBqReLlLx6hT35VS3imaNPwiXDxLnTK7lxw3Lrl9k5yugSBDQAkZAq3MPTEFSUBQ=="], 46 - 47 - "@atproto-labs/simple-store-memory": ["@atproto-labs/simple-store-memory@0.1.4", "", { "dependencies": { "@atproto-labs/simple-store": "0.3.0", "lru-cache": "^10.2.0" } }, "sha512-3mKY4dP8I7yKPFj9VKpYyCRzGJOi5CEpOLPlRhoJyLmgs3J4RzDrjn323Oakjz2Aj2JzRU/AIvWRAZVhpYNJHw=="], 48 - 49 - "@atproto/api": ["@atproto/api@0.17.0", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/lexicon": "^0.5.1", "@atproto/syntax": "^0.4.1", "@atproto/xrpc": "^0.7.5", "await-lock": "^2.2.2", "multiformats": "^9.9.0", "tlds": "^1.234.0", "zod": "^3.23.8" } }, "sha512-FNS9SW7/3kslAnJH7F4fO9/jPjXzC0NMD6u9NjJ/h4EnaIEpWHZQPkmD9Q2hvAwD6+Uo2boYZEPKkOa55Lr5Dg=="], 50 - 51 - "@atproto/common-web": ["@atproto/common-web@0.4.3", "", { "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="], 52 - 53 - "@atproto/did": ["@atproto/did@0.2.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-BskT39KYbwY1DUsWekkHh47xS+wvJpFq5F9acsicNfYniinyAMnNTzGKQEhnjQuG7K0qQItg/SnmC+y0tJXV7Q=="], 54 - 55 - "@atproto/jwk": ["@atproto/jwk@0.5.0", "", { "dependencies": { "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-Qi2NtEqhkG+uz3CKia4+H05WMV/z//dz3ESo5+cyBKrOnxVTJ5ZubMyltWjoYvy6v/jLhorXdDWcjn07yky7MQ=="], 25 + "@deno/experimental-route-config": ["@deno/experimental-route-config@0.0.5", "", { "dependencies": { "urlpattern-polyfill": "^10.0.0" } }, "sha512-0PN4qij3sC3Qm8WbiOBGlOQz8WtB0AENGkzsTHOYyPenf40iW7OGFid8QT3L8lGApnz3t6ufET0c2XgagV8Jjw=="], 56 26 57 - "@atproto/jwk-jose": ["@atproto/jwk-jose@0.1.10", "", { "dependencies": { "@atproto/jwk": "0.5.0", "jose": "^5.2.0" } }, "sha512-Eiu/u4tZHz3IIhHZt0zneYEffSAO3Oqk/ToKwlu1TqKte6sjtPs/4uquSiAAGFYozqgo92JC/AQclWzzkHI5QQ=="], 58 - 59 - "@atproto/jwk-webcrypto": ["@atproto/jwk-webcrypto@0.1.10", "", { "dependencies": { "@atproto/jwk": "0.5.0", "@atproto/jwk-jose": "0.1.10", "zod": "^3.23.8" } }, "sha512-JZsavs6JiSmw5rgcjkGDwzr1aCJGdybZOjVfYH+m9sXRU1BrUCA30uwNfZY7eFyWXyRAnCFiYiGVZgypXyKotw=="], 60 - 61 - "@atproto/lexicon": ["@atproto/lexicon@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A=="], 62 - 63 - "@atproto/oauth-client": ["@atproto/oauth-client@0.5.6", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.1", "@atproto-labs/fetch": "0.2.3", "@atproto-labs/handle-resolver": "0.3.1", "@atproto-labs/identity-resolver": "0.3.1", "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.0", "@atproto/jwk": "0.5.0", "@atproto/oauth-types": "0.4.1", "@atproto/xrpc": "0.7.5", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-O1S9lPptJxWPcNd2kODaLgWntz+A7PzskU2hP4IFa7hVLs4aEnEt9dKq5wJE97tDli8mgyh/ndPQhxUaCVQ5iQ=="], 64 - 65 - "@atproto/oauth-client-node": ["@atproto/oauth-client-node@0.3.8", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.1", "@atproto-labs/handle-resolver-node": "0.1.19", "@atproto-labs/simple-store": "0.3.0", "@atproto/did": "0.2.0", "@atproto/jwk": "0.5.0", "@atproto/jwk-jose": "0.1.10", "@atproto/jwk-webcrypto": "0.1.10", "@atproto/oauth-client": "0.5.6", "@atproto/oauth-types": "0.4.1" } }, "sha512-HIBiYQERj04Xa0l8cJkqcZC0BbHH5uqDEvhqHWnJ5umSq/ms0+HZi3JKJXGv1XfYOvxUxx6NKgXJ8VhhYoQa5A=="], 66 - 67 - "@atproto/oauth-types": ["@atproto/oauth-types@0.4.1", "", { "dependencies": { "@atproto/jwk": "0.5.0", "zod": "^3.23.8" } }, "sha512-c5ixf2ZOzcltOu1fDBnO/tok6Wj7JDDK66+Z0q/+bAr8LXgOnxP7zQfJ+DD4gTkB+saTqsqWtVv8qvx/IEtm1g=="], 68 - 69 - "@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw=="], 70 - 71 - "@atproto/xrpc": ["@atproto/xrpc@0.7.5", "", { "dependencies": { "@atproto/lexicon": "^0.5.1", "zod": "^3.23.8" } }, "sha512-MUYNn5d2hv8yVegRL0ccHvTHAVj5JSnW07bkbiaz96UH45lvYNRVwt44z+yYVnb0/mvBzyD3/ZQ55TRGt7fHkA=="], 72 - 73 - "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], 27 + "@deno/svelte-adapter": ["@deno/svelte-adapter@0.1.0", "", { "dependencies": { "@deno/experimental-route-config": "^0.0.5" }, "peerDependencies": { "@sveltejs/kit": "2.x" } }, "sha512-fx4Kj1lSx1rJvjtPr3cXO7qKveI1vUyGW8jX+clJHQEqEeIDnEcBW0FpMZEVORPlay2SGydQWSGbwh4j2iENzg=="], 74 28 75 29 "@emnapi/core": ["@emnapi/core@0.45.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-DPWjcUDQkCeEM4VnljEOEcXdAD7pp8zSZsgOujk/LGIwCXWbXJngin+MO4zbH429lzeC3WbYLGjE2MaUOwzpyw=="], 76 30 77 31 "@emnapi/runtime": ["@emnapi/runtime@0.45.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w=="], 78 - 79 - "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="], 80 - 81 - "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], 82 32 83 33 "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.10", "", { "os": "aix", "cpu": "ppc64" }, "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw=="], 84 34 ··· 131 81 "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.10", "", { "os": "win32", "cpu": "ia32" }, "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw=="], 132 82 133 83 "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.10", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="], 134 - 135 - "@iarna/toml": ["@iarna/toml@2.2.5", "", {}, "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="], 136 84 137 85 "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], 138 86 ··· 206 154 207 155 "@node-rs/bcrypt-win32-x64-msvc": ["@node-rs/bcrypt-win32-x64-msvc@1.9.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2y0Tuo6ZAT2Cz8V7DHulSlv1Bip3zbzeXyeur+uR25IRNYXKvI/P99Zl85Fbuu/zzYAZRLLlGTRe6/9IHofe/w=="], 208 156 209 - "@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="], 210 - 211 157 "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], 212 158 213 159 "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.3", "", { "os": "android", "cpu": "arm" }, "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw=="], ··· 258 204 259 205 "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.6", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ=="], 260 206 261 - "@sveltejs/adapter-netlify": ["@sveltejs/adapter-netlify@5.2.4", "", { "dependencies": { "@iarna/toml": "^2.2.5", "esbuild": "^0.25.4", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "@sveltejs/kit": "^2.4.0" } }, "sha512-UtPcZq1HUA43hM8uLi+nsm5Q+YjHNj7/SMFoyeLZeY/VTloVWABEZ0tJ5WodTUmy/8j5QJ7oLZjj28aQxi8y3g=="], 262 - 263 - "@sveltejs/kit": ["@sveltejs/kit@2.44.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.3.2", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["@opentelemetry/api"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-xU5qP7PiYmrSH70Whm/I+nf0j4xBnHyRQNkC1SEfaBOwCCkkeuL6WNxSb8q4Ib7+Z+sZ4JUTDYHfoyVm02EXVQ=="], 207 + "@sveltejs/kit": ["@sveltejs/kit@2.43.5", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.3.2", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["@opentelemetry/api"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-44Mm5csR4mesKx2Eyhtk8UVrLJ4c04BT2wMTfYGKJMOkUqpHP5KLL2DPV0hXUA4t4+T3ZYe0aBygd42lVYv2cA=="], 264 208 265 209 "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@6.2.1", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "debug": "^4.4.1", "deepmerge": "^4.3.1", "magic-string": "^0.30.17", "vitefu": "^1.1.1" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ=="], 266 210 267 211 "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@5.0.1", "", { "dependencies": { "debug": "^4.4.1" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-ubWshlMk4bc8mkwWbg6vNvCeT7lGQojE3ijDh3QTR6Zr/R+GXxsGbyH4PExEPpiFmqPhYiVSVmHBjUcVc1JIrA=="], 268 212 269 - "@tailwindcss/node": ["@tailwindcss/node@4.1.14", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.0", "lightningcss": "1.30.1", "magic-string": "^0.30.19", "source-map-js": "^1.2.1", "tailwindcss": "4.1.14" } }, "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw=="], 213 + "@tailwindcss/node": ["@tailwindcss/node@4.1.13", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.5.1", "lightningcss": "1.30.1", "magic-string": "^0.30.18", "source-map-js": "^1.2.1", "tailwindcss": "4.1.13" } }, "sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw=="], 270 214 271 - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.14", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.5.1" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.14", "@tailwindcss/oxide-darwin-arm64": "4.1.14", "@tailwindcss/oxide-darwin-x64": "4.1.14", "@tailwindcss/oxide-freebsd-x64": "4.1.14", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14", "@tailwindcss/oxide-linux-arm64-musl": "4.1.14", "@tailwindcss/oxide-linux-x64-gnu": "4.1.14", "@tailwindcss/oxide-linux-x64-musl": "4.1.14", "@tailwindcss/oxide-wasm32-wasi": "4.1.14", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14", "@tailwindcss/oxide-win32-x64-msvc": "4.1.14" } }, "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw=="], 215 + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.13", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.13", "@tailwindcss/oxide-darwin-arm64": "4.1.13", "@tailwindcss/oxide-darwin-x64": "4.1.13", "@tailwindcss/oxide-freebsd-x64": "4.1.13", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.13", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.13", "@tailwindcss/oxide-linux-arm64-musl": "4.1.13", "@tailwindcss/oxide-linux-x64-gnu": "4.1.13", "@tailwindcss/oxide-linux-x64-musl": "4.1.13", "@tailwindcss/oxide-wasm32-wasi": "4.1.13", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.13", "@tailwindcss/oxide-win32-x64-msvc": "4.1.13" } }, "sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA=="], 272 216 273 - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.14", "", { "os": "android", "cpu": "arm64" }, "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ=="], 217 + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.13", "", { "os": "android", "cpu": "arm64" }, "sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew=="], 274 218 275 - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA=="], 219 + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ=="], 276 220 277 - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw=="], 221 + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw=="], 278 222 279 - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.14", "", { "os": "freebsd", "cpu": "x64" }, "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw=="], 223 + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.13", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ=="], 280 224 281 - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14", "", { "os": "linux", "cpu": "arm" }, "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw=="], 225 + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13", "", { "os": "linux", "cpu": "arm" }, "sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw=="], 282 226 283 - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w=="], 227 + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ=="], 284 228 285 - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ=="], 229 + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg=="], 286 230 287 - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.14", "", { "os": "linux", "cpu": "x64" }, "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg=="], 231 + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.13", "", { "os": "linux", "cpu": "x64" }, "sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ=="], 288 232 289 - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.14", "", { "os": "linux", "cpu": "x64" }, "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q=="], 233 + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.13", "", { "os": "linux", "cpu": "x64" }, "sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ=="], 290 234 291 - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.14", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.5", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ=="], 235 + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.13", "", { "dependencies": { "@emnapi/core": "^1.4.5", "@emnapi/runtime": "^1.4.5", "@emnapi/wasi-threads": "^1.0.4", "@napi-rs/wasm-runtime": "^0.2.12", "@tybys/wasm-util": "^0.10.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA=="], 292 236 293 - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA=="], 237 + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg=="], 294 238 295 - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.14", "", { "os": "win32", "cpu": "x64" }, "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA=="], 239 + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.13", "", { "os": "win32", "cpu": "x64" }, "sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw=="], 296 240 297 - "@tailwindcss/vite": ["@tailwindcss/vite@4.1.14", "", { "dependencies": { "@tailwindcss/node": "4.1.14", "@tailwindcss/oxide": "4.1.14", "tailwindcss": "4.1.14" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA=="], 241 + "@tailwindcss/vite": ["@tailwindcss/vite@4.1.13", "", { "dependencies": { "@tailwindcss/node": "4.1.13", "@tailwindcss/oxide": "4.1.13", "tailwindcss": "4.1.13" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-0PmqLQ010N58SbMTJ7BVJ4I2xopiQn/5i6nlb4JmxzQf8zcS5+m2Cv6tqh+sfDwtIdjoEnOvwsGQ1hkUi8QEHQ=="], 298 242 299 243 "@tybys/wasm-util": ["@tybys/wasm-util@0.8.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Z96T/L6dUFFxgFJ+pQtkPpne9q7i6kIPYCFnQBHSgSPV9idTsKfIhCss0h5iM9irweZCatkrdeP8yi5uM1eX6Q=="], 300 244 ··· 306 250 307 251 "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], 308 252 309 - "await-lock": ["await-lock@2.2.2", "", {}, "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw=="], 310 - 311 253 "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], 312 - 313 - "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], 314 254 315 255 "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], 316 256 ··· 328 268 329 269 "devalue": ["devalue@5.3.2", "", {}, "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw=="], 330 270 331 - "drizzle-kit": ["drizzle-kit@0.31.5", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-+CHgPFzuoTQTt7cOYCV6MOw2w8vqEn/ap1yv4bpZOWL03u7rlVRQhUY0WYT3rHsgVTXwYQDZaSUJSQrMBUKuWg=="], 332 - 333 - "drizzle-orm": ["drizzle-orm@0.44.6", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-uy6uarrrEOc9K1u5/uhBFJbdF5VJ5xQ/Yzbecw3eAYOunv5FDeYkR2m8iitocdHBOHbvorviKOW5GVw0U1j4LQ=="], 334 - 335 271 "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="], 336 272 337 273 "esbuild": ["esbuild@0.25.10", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.10", "@esbuild/android-arm": "0.25.10", "@esbuild/android-arm64": "0.25.10", "@esbuild/android-x64": "0.25.10", "@esbuild/darwin-arm64": "0.25.10", "@esbuild/darwin-x64": "0.25.10", "@esbuild/freebsd-arm64": "0.25.10", "@esbuild/freebsd-x64": "0.25.10", "@esbuild/linux-arm": "0.25.10", "@esbuild/linux-arm64": "0.25.10", "@esbuild/linux-ia32": "0.25.10", "@esbuild/linux-loong64": "0.25.10", "@esbuild/linux-mips64el": "0.25.10", "@esbuild/linux-ppc64": "0.25.10", "@esbuild/linux-riscv64": "0.25.10", "@esbuild/linux-s390x": "0.25.10", "@esbuild/linux-x64": "0.25.10", "@esbuild/netbsd-arm64": "0.25.10", "@esbuild/netbsd-x64": "0.25.10", "@esbuild/openbsd-arm64": "0.25.10", "@esbuild/openbsd-x64": "0.25.10", "@esbuild/openharmony-arm64": "0.25.10", "@esbuild/sunos-x64": "0.25.10", "@esbuild/win32-arm64": "0.25.10", "@esbuild/win32-ia32": "0.25.10", "@esbuild/win32-x64": "0.25.10" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ=="], 338 - 339 - "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], 340 274 341 275 "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], 342 276 ··· 348 282 349 283 "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 350 284 351 - "get-tsconfig": ["get-tsconfig@4.10.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ=="], 352 - 353 285 "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], 354 286 355 - "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], 356 - 357 - "ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="], 358 - 359 287 "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], 360 288 361 - "iso-datestring-validator": ["iso-datestring-validator@2.2.2", "", {}, "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA=="], 362 - 363 289 "jiti": ["jiti@2.6.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ=="], 364 - 365 - "jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], 366 290 367 291 "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], 368 292 ··· 390 314 391 315 "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], 392 316 393 - "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], 394 - 395 317 "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], 396 318 397 319 "memfs": ["memfs@3.5.3", "", { "dependencies": { "fs-monkey": "^1.0.4" } }, "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw=="], ··· 407 329 "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], 408 330 409 331 "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 410 - 411 - "multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 412 332 413 333 "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 414 334 ··· 420 340 421 341 "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], 422 342 423 - "postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="], 424 - 425 343 "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], 426 - 427 - "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], 428 344 429 345 "rollup": ["rollup@4.52.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.3", "@rollup/rollup-android-arm64": "4.52.3", "@rollup/rollup-darwin-arm64": "4.52.3", "@rollup/rollup-darwin-x64": "4.52.3", "@rollup/rollup-freebsd-arm64": "4.52.3", "@rollup/rollup-freebsd-x64": "4.52.3", "@rollup/rollup-linux-arm-gnueabihf": "4.52.3", "@rollup/rollup-linux-arm-musleabihf": "4.52.3", "@rollup/rollup-linux-arm64-gnu": "4.52.3", "@rollup/rollup-linux-arm64-musl": "4.52.3", "@rollup/rollup-linux-loong64-gnu": "4.52.3", "@rollup/rollup-linux-ppc64-gnu": "4.52.3", "@rollup/rollup-linux-riscv64-gnu": "4.52.3", "@rollup/rollup-linux-riscv64-musl": "4.52.3", "@rollup/rollup-linux-s390x-gnu": "4.52.3", "@rollup/rollup-linux-x64-gnu": "4.52.3", "@rollup/rollup-linux-x64-musl": "4.52.3", "@rollup/rollup-openharmony-arm64": "4.52.3", "@rollup/rollup-win32-arm64-msvc": "4.52.3", "@rollup/rollup-win32-ia32-msvc": "4.52.3", "@rollup/rollup-win32-x64-gnu": "4.52.3", "@rollup/rollup-win32-x64-msvc": "4.52.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A=="], 430 346 ··· 433 349 "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], 434 350 435 351 "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="], 436 - 437 - "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], 438 352 439 353 "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], 440 354 441 - "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], 442 - 443 - "svelte": ["svelte@5.39.8", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-KfZ3hCITdxIXTOvrea4nFZX2o+47HPTChKeocgj9BwJQYqWrviVCcPj4boXHF5yf8+eBKqhHY8xii//XaakKXA=="], 355 + "svelte": ["svelte@5.39.6", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-bOJXmuwLNaoqPCTWO8mPu/fwxI5peGE5Efe7oo6Cakpz/G60vsnVF6mxbGODaxMUFUKEnjm6XOwHEqOht6cbvw=="], 444 356 445 357 "svelte-check": ["svelte-check@4.3.2", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-71udP5w2kaSTcX8iV0hn3o2FWlabQHhJTJLIQrCqMsrcOeDUO2VhCQKKCA8AMVHSPwdxLEWkUWh9OKxns5PD9w=="], 446 358 ··· 448 360 449 361 "svelte-writable-derived": ["svelte-writable-derived@3.1.1", "", { "peerDependencies": { "svelte": "^3.2.1 || ^4.0.0-next.1 || ^5.0.0-next.94" } }, "sha512-w4LR6/bYZEuCs7SGr+M54oipk/UQKtiMadyOhW0PTwAtJ/Ai12QS77sLngEcfBx2q4H8ZBQucc9ktSA5sUGZWw=="], 450 362 451 - "tailwindcss": ["tailwindcss@4.1.14", "", {}, "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA=="], 363 + "tailwindcss": ["tailwindcss@4.1.13", "", {}, "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w=="], 452 364 453 365 "tapable": ["tapable@2.2.3", "", {}, "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg=="], 454 366 ··· 456 368 457 369 "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], 458 370 459 - "tlds": ["tlds@1.260.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-78+28EWBhCEE7qlyaHA9OR3IPvbCLiDh3Ckla593TksfFc9vfTsgvH7eS+dr3o9qr31gwGbogcI16yN91PoRjQ=="], 460 - 461 371 "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], 462 372 463 373 "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 464 374 465 - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], 466 - 467 - "uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA=="], 375 + "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], 468 376 469 - "undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="], 377 + "urlpattern-polyfill": ["urlpattern-polyfill@10.1.0", "", {}, "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw=="], 470 378 471 - "vite": ["vite@7.1.9", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg=="], 379 + "vite": ["vite@7.1.7", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA=="], 472 380 473 381 "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="], 474 382 475 383 "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], 476 384 477 385 "zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="], 478 - 479 - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], 480 - 481 - "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], 482 386 483 387 "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="], 484 388 ··· 486 390 487 391 "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], 488 392 489 - "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.6", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-DXj75ewm11LIWUk198QSKUTxjyRjsBwk09MuMk5DGK+GDUtyPhhEHOGP/Xwwj3DjQXXkivoBirmOnKrLfc0+9g=="], 393 + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" }, "bundled": true }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], 490 394 491 395 "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], 492 396 493 397 "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 494 - 495 - "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], 496 - 497 - "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], 498 - 499 - "@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="], 500 - 501 - "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="], 502 - 503 - "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="], 504 - 505 - "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="], 506 - 507 - "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="], 508 - 509 - "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="], 510 - 511 - "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="], 512 - 513 - "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="], 514 - 515 - "@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="], 516 - 517 - "@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="], 518 - 519 - "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="], 520 - 521 - "@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="], 522 - 523 - "@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="], 524 - 525 - "@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="], 526 - 527 - "@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="], 528 - 529 - "@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="], 530 - 531 - "@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="], 532 - 533 - "@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="], 534 - 535 - "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], 536 - 537 - "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], 538 398 } 539 399 }
-11
drizzle/0000_first_praxagora.sql
··· 1 - CREATE TABLE "auth_session" ( 2 - "key" text PRIMARY KEY NOT NULL, 3 - "session" json NOT NULL, 4 - CONSTRAINT "auth_session_key_unique" UNIQUE("key") 5 - ); 6 - --> statement-breakpoint 7 - CREATE TABLE "auth_state" ( 8 - "key" text PRIMARY KEY NOT NULL, 9 - "state" json NOT NULL, 10 - CONSTRAINT "auth_state_key_unique" UNIQUE("key") 11 - );
-85
drizzle/meta/0000_snapshot.json
··· 1 - { 2 - "id": "6e06677f-9a96-41ee-82f8-e0f6e1ea34e3", 3 - "prevId": "00000000-0000-0000-0000-000000000000", 4 - "version": "7", 5 - "dialect": "postgresql", 6 - "tables": { 7 - "public.auth_session": { 8 - "name": "auth_session", 9 - "schema": "", 10 - "columns": { 11 - "key": { 12 - "name": "key", 13 - "type": "text", 14 - "primaryKey": true, 15 - "notNull": true 16 - }, 17 - "session": { 18 - "name": "session", 19 - "type": "json", 20 - "primaryKey": false, 21 - "notNull": true 22 - } 23 - }, 24 - "indexes": {}, 25 - "foreignKeys": {}, 26 - "compositePrimaryKeys": {}, 27 - "uniqueConstraints": { 28 - "auth_session_key_unique": { 29 - "name": "auth_session_key_unique", 30 - "nullsNotDistinct": false, 31 - "columns": [ 32 - "key" 33 - ] 34 - } 35 - }, 36 - "policies": {}, 37 - "checkConstraints": {}, 38 - "isRLSEnabled": false 39 - }, 40 - "public.auth_state": { 41 - "name": "auth_state", 42 - "schema": "", 43 - "columns": { 44 - "key": { 45 - "name": "key", 46 - "type": "text", 47 - "primaryKey": true, 48 - "notNull": true 49 - }, 50 - "state": { 51 - "name": "state", 52 - "type": "json", 53 - "primaryKey": false, 54 - "notNull": true 55 - } 56 - }, 57 - "indexes": {}, 58 - "foreignKeys": {}, 59 - "compositePrimaryKeys": {}, 60 - "uniqueConstraints": { 61 - "auth_state_key_unique": { 62 - "name": "auth_state_key_unique", 63 - "nullsNotDistinct": false, 64 - "columns": [ 65 - "key" 66 - ] 67 - } 68 - }, 69 - "policies": {}, 70 - "checkConstraints": {}, 71 - "isRLSEnabled": false 72 - } 73 - }, 74 - "enums": {}, 75 - "schemas": {}, 76 - "sequences": {}, 77 - "roles": {}, 78 - "policies": {}, 79 - "views": {}, 80 - "_meta": { 81 - "columns": {}, 82 - "schemas": {}, 83 - "tables": {} 84 - } 85 - }
-13
drizzle/meta/_journal.json
··· 1 - { 2 - "version": "7", 3 - "dialect": "postgresql", 4 - "entries": [ 5 - { 6 - "idx": 0, 7 - "version": "7", 8 - "when": 1759136833553, 9 - "tag": "0000_first_praxagora", 10 - "breakpoints": true 11 - } 12 - ] 13 - }
-12
drizzle.config.ts
··· 1 - import { defineConfig } from "drizzle-kit"; 2 - if (!process.env.DATABASE_URL) throw new Error("DATABASE_URL is not set"); 3 - 4 - export default defineConfig({ 5 - schema: "./src/lib/schema.ts", 6 - dbCredentials: { 7 - url: process.env.DATABASE_URL 8 - }, 9 - verbose: true, 10 - strict: true, 11 - dialect: "postgresql" 12 - });
-27
link/easytodo/tasks/list.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "link.easytodo.tasks.list", 4 - "defs": { 5 - "main": { 6 - "type": "record", 7 - "description": "A list of items to do.", 8 - "key": "tid", 9 - "record": { 10 - "type": "object", 11 - "required": ["id", "title", "createdAt"], 12 - "properties": { 13 - "id": { "type": "string" }, 14 - "title": { "type": "string" }, 15 - "createdAt": { "type": "string", "format": "datetime" }, 16 - "tasks": { 17 - "type": "array", 18 - "items": { 19 - "type": "ref", 20 - "ref": "link.easytodo.tasks.task" 21 - } 22 - } 23 - } 24 - } 25 - } 26 - } 27 - }
-21
link/easytodo/tasks/task.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "link.easytodo.tasks.task", 4 - "defs": { 5 - "main": { 6 - "type": "record", 7 - "description": "An item to do.", 8 - "key": "tid", 9 - "record": { 10 - "type": "object", 11 - "required": ["id", "description", "is_completed"], 12 - "properties": { 13 - "id": { "type": "string" }, 14 - "description": { "type": "string" }, 15 - "is_completed": { "type": "boolean", "default": false }, 16 - "duration": { "type": "integer" } 17 - } 18 - } 19 - } 20 - } 21 - }
+7 -17
package.json
··· 7 7 "build": "vite build", 8 8 "preview": "vite preview", 9 9 "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 10 - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 11 - "db:push": "drizzle-kit push", 12 - "db:migrate": "drizzle-kit migrate", 13 - "db:studio": "drizzle-kit studio" 10 + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" 14 11 }, 15 12 "devDependencies": { 16 - "@sveltejs/adapter-netlify": "^5.2.4", 17 - "@sveltejs/kit": "^2.44.0", 13 + "@sveltejs/kit": "^2.43.5", 18 14 "@sveltejs/vite-plugin-svelte": "^6.2.1", 19 - "drizzle-kit": "^0.31.5", 20 - "svelte": "^5.39.8", 15 + "svelte": "^5.39.6", 21 16 "svelte-check": "^4.3.2", 22 17 "tslib": "^2.8.1", 23 - "typescript": "^5.9.3", 24 - "vite": "^7.1.9" 18 + "typescript": "^5.9.2", 19 + "vite": "^7.1.7" 25 20 }, 26 21 "type": "module", 27 22 "dependencies": { 28 - "@atproto/api": "^0.17.0", 29 - "@atproto/oauth-client-node": "^0.3.8", 30 - "@oslojs/encoding": "^1.1.0", 31 - "@tailwindcss/vite": "^4.1.14", 32 - "drizzle-orm": "^0.44.6", 23 + "@tailwindcss/vite": "^4.1.13", 33 24 "oslo": "^1.2.1", 34 - "postgres": "^3.4.7", 35 25 "svelte-french-toast": "^1.2.0", 36 - "tailwindcss": "^4.1.14" 26 + "tailwindcss": "^4.1.13" 37 27 } 38 28 }
+2 -12
src/app.d.ts
··· 1 - // See https://svelte.dev/docs/kit/types#app.d.ts 2 - 3 - import type { Agent } from "@atproto/api"; 4 - import type { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs"; 5 - 1 + // See https://kit.svelte.dev/docs/types#app 6 2 // for information about these interfaces 7 3 declare global { 8 4 namespace App { 9 5 // interface Error {} 10 - 11 - // set on `hooks.server.ts`, available on server functions 12 - interface Locals { 13 - authedAgent: Agent | undefined; 14 - user: ProfileViewDetailed | undefined; 15 - } 16 - 6 + // interface Locals {} 17 7 // interface PageData {} 18 8 // interface PageState {} 19 9 // interface Platform {}
-41
src/hooks.server.ts
··· 1 - import { Agent } from "@atproto/api"; 2 - import { atclient } from "$lib/atproto"; 3 - 4 - import { decryptToString } from "$lib/server/encryption"; 5 - import { decodeBase64, decodeBase64urlIgnorePadding } from "@oslojs/encoding"; 6 - 7 - import type { Handle } from "@sveltejs/kit"; 8 - import { ENCRYPTION_PASSWORD } from "$env/static/private"; 9 - 10 - // runs everytime there's a new request 11 - export const handle: Handle = async ({ event, resolve }) => { 12 - const sid = event.cookies.get("sid"); 13 - 14 - // if there is a session cookie 15 - if (sid) { 16 - // if a user is already authed, skip reauthing 17 - if (event.locals.user) { return resolve(event); } 18 - 19 - // decrypt session cookie 20 - const decoded = decodeBase64urlIgnorePadding(sid); 21 - const key = decodeBase64(ENCRYPTION_PASSWORD); 22 - const decrypted = await decryptToString(key, decoded); 23 - 24 - // get oauth session from client using decrypted cookie 25 - const oauthSession = await atclient.restore(decrypted); 26 - 27 - // set the authed agent 28 - const authedAgent = new Agent(oauthSession); 29 - if (!event.locals.authedAgent) { 30 - event.locals.authedAgent = authedAgent; 31 - } 32 - 33 - // set the authed user with decrypted session DID 34 - const user = await authedAgent.getProfile({ actor: decrypted }); 35 - event.locals.user = user.data; 36 - } 37 - 38 - return resolve(event); 39 - } 40 - 41 -
-92
src/lib/atproto.ts
··· 1 - import { eq } from "drizzle-orm"; 2 - import * as schema from "./schema"; 3 - import { db as database } from "./server/db"; 4 - import { NodeOAuthClient } from "@atproto/oauth-client-node"; 5 - import type { NodeSavedSession, NodeSavedSessionStore, NodeSavedState, NodeSavedStateStore } from "@atproto/oauth-client-node"; 6 - import { db } from "./server/db"; 7 - import { dev } from "$app/environment"; 8 - 9 - // can be implemented with your preferred DB and ORM 10 - // both stores are the same, only different is 'state' and 'session' 11 - 12 - export class AuthStateStore implements NodeSavedStateStore { 13 - constructor(private db: typeof database) {} 14 - 15 - async get(key: string): Promise<NodeSavedState | undefined> { 16 - const result = await this.db.query.AuthState.findFirst({ 17 - where: eq(schema.AuthState.key, key) 18 - }); 19 - 20 - if (!result) return; 21 - 22 - return result.state as NodeSavedState; 23 - } 24 - 25 - async set(key: string, val: NodeSavedState) { 26 - await this.db.insert(schema.AuthState) 27 - .values({ key, state: val }) 28 - .onConflictDoUpdate({ 29 - target: schema.AuthState.key, 30 - set: { state: val } 31 - }); 32 - } 33 - 34 - async del(key: string) { 35 - await this.db.delete(schema.AuthState) 36 - .where(eq(schema.AuthState.key, key)); 37 - } 38 - } 39 - 40 - export class AuthSessionStore implements NodeSavedSessionStore { 41 - constructor(private db: typeof database) {} 42 - 43 - async get(key: string): Promise<NodeSavedSession | undefined> { 44 - const result = await this.db.query.AuthSession.findFirst({ 45 - where: eq(schema.AuthSession.key, key) 46 - }); 47 - 48 - if (!result) return; 49 - return result.session as NodeSavedSession; 50 - } 51 - 52 - async set(key: string, val: NodeSavedSession) { 53 - await this.db.insert(schema.AuthSession) 54 - .values({ key, session: val }) 55 - .onConflictDoUpdate({ 56 - target: schema.AuthSession.key, 57 - set: { session: val } 58 - }); 59 - } 60 - 61 - async del(key: string) { 62 - await this.db.delete(schema.AuthSession) 63 - .where(eq(schema.AuthSession.key, key)); 64 - } 65 - } 66 - 67 - const publicUrl = "https://easytodo.link" 68 - // localhost resolves to either 127.0.0.1 or [::1] (if ipv6) 69 - const url = dev ? "http://[::1]:5173" : publicUrl; 70 - 71 - export const atclient = new NodeOAuthClient({ 72 - stateStore: new AuthStateStore(db), 73 - sessionStore: new AuthSessionStore(db), 74 - clientMetadata: { 75 - client_name: "easytodo.link", 76 - client_id: !dev ? `${publicUrl}/client-metadata.json` 77 - : `http://localhost?redirect_uri=${ 78 - encodeURIComponent(`${url}/oauth/callback`) 79 - }&scope=${ 80 - encodeURIComponent(`atproto repo:link.easytodo.tasks.list repo:link.easytodo.tasks.task rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app%23bsky_appview`) 81 - }`, 82 - client_uri: url, 83 - redirect_uris: [`${url}/oauth/callback`], 84 - scope: "atproto repo:link.easytodo.tasks.list repo:link.easytodo.tasks.task rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app%23bsky_appview", 85 - grant_types: ["authorization_code", "refresh_token"], 86 - application_type: "web", 87 - token_endpoint_auth_method: "none", 88 - dpop_bound_access_tokens: true 89 - } 90 - }); 91 - 92 -
-11
src/lib/schema.ts
··· 1 - import { pgTable, text, json } from 'drizzle-orm/pg-core'; 2 - 3 - export const AuthState = pgTable('auth_state', { 4 - key: text('key').primaryKey().unique(), 5 - state: json('state').notNull() 6 - }); 7 - 8 - export const AuthSession = pgTable('auth_session', { 9 - key: text('key').primaryKey().unique(), 10 - session: json('session').notNull() 11 - });
-10
src/lib/server/db.ts
··· 1 - import { drizzle } from 'drizzle-orm/postgres-js'; 2 - import postgres from 'postgres'; 3 - import { env } from '$env/dynamic/private'; 4 - import * as schema from "../schema"; 5 - 6 - if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set'); 7 - const client = postgres(env.DATABASE_URL); 8 - 9 - // add schema 10 - export const db = drizzle(client, { schema });
-50
src/lib/server/encryption.ts
··· 1 - // Code by @pilcrowonpaper on GitHub: https://gist.github.com/pilcrowonpaper/353318556029221c8e25f451b91e5f76 2 - // AES128 with the Web Crypto API. 3 - async function encrypt(key: Uint8Array, data: Uint8Array): Promise<Uint8Array> { 4 - const iv = new Uint8Array(16); 5 - crypto.getRandomValues(iv); 6 - const cryptoKey = await crypto.subtle.importKey("raw", key, "AES-GCM", false, ["encrypt"]); 7 - const cipher = await crypto.subtle.encrypt( 8 - { 9 - name: "AES-GCM", 10 - iv, 11 - tagLength: 128 12 - }, 13 - cryptoKey, 14 - data 15 - ); 16 - const encrypted = new Uint8Array(iv.byteLength + cipher.byteLength); 17 - encrypted.set(iv); 18 - encrypted.set(new Uint8Array(cipher), iv.byteLength); 19 - return encrypted; 20 - } 21 - 22 - export async function encryptString(key: Uint8Array, data: string): Promise<Uint8Array> { 23 - const encoded = new TextEncoder().encode(data); 24 - const encrypted = await encrypt(key, encoded); 25 - return encrypted; 26 - } 27 - 28 - async function decrypt(key: Uint8Array, encrypted: Uint8Array): Promise<Uint8Array> { 29 - if (encrypted.length < 16) { 30 - throw new Error("Invalid data"); 31 - } 32 - const cryptoKey = await crypto.subtle.importKey("raw", key, "AES-GCM", false, ["decrypt"]); 33 - const decrypted = await crypto.subtle.decrypt( 34 - { 35 - name: "AES-GCM", 36 - iv: encrypted.slice(0, 16), 37 - tagLength: 128 38 - }, 39 - cryptoKey, 40 - encrypted.slice(16) 41 - ); 42 - return new Uint8Array(decrypted); 43 - } 44 - 45 - export async function decryptToString(key: Uint8Array, data: Uint8Array): Promise<string> { 46 - const decrypted = await decrypt(key, data); 47 - const decoded = new TextDecoder().decode(decrypted); 48 - return decoded; 49 - } 50 -
-2
src/lib/stores.svelte.ts
··· 38 38 // optional 39 39 duration?: number; 40 40 stopwatchInterval?: number; 41 - rkey?: string; 42 41 } 43 42 44 43 export type List = { 45 44 id: string; 46 45 title: string; 47 46 tasks: Task[]; 48 - rkey?: string; 49 47 } 50 48 51 49 export const local_lists = persisted<List[]>("local_lists", [
-10
src/lib/utils.ts
··· 4 4 return generateRandomString(10, alphabet("a-z", "0-9")); 5 5 } 6 6 7 - export function parseAtUri(uri: string) { 8 - const regex = /at:\/\/(?<did>did.*)\/(?<lexi>.*)\/(?<rkey>.*)/; 9 - const groups = regex.exec(uri)?.groups; 10 - return { 11 - did: groups?.did, 12 - lexi: groups?.lexi, 13 - rkey: groups?.rkey 14 - } 15 - } 16 - 17 7 export function formatSecondsToDuration(seconds: number = 0) { 18 8 let hours = Math.floor(seconds / 3600); 19 9 let minutes = Math.floor((seconds - (hours * 3600)) / 60);
-10
src/routes/+layout.server.ts
··· 1 - import type { LayoutServerLoadEvent } from "./$types"; 2 - 3 - export async function load({ locals }: LayoutServerLoadEvent) { 4 - // have user available throughout the app via LayoutData 5 - return !locals.user ? undefined : { user: { 6 - did: locals.user.did, 7 - handle: locals.user.handle, 8 - avatar: locals.user.avatar 9 - }}; 10 - }
+16 -54
src/routes/+layout.svelte
··· 1 1 <script lang="ts"> 2 2 import "../app.css"; 3 - import { onMount } from "svelte"; 3 + import { onMount, type Snippet } from "svelte"; 4 4 import { page } from "$app/state"; 5 5 import { goto } from "$app/navigation"; 6 6 import { fade } from "svelte/transition"; 7 - import type { LayoutProps } from "./$types"; 8 7 import toast, { Toaster } from "svelte-french-toast"; 9 8 import { persisted, pinned_list } from "$lib/stores.svelte"; 10 9 11 - let { data, children }: LayoutProps = $props(); 12 - let { user } = $derived(data); 10 + interface Props { 11 + children: Snippet 12 + } 13 + 14 + let { children }: Props = $props(); 13 15 14 16 let theme = persisted<string>("theme", "dark"); 15 17 let is_menu_open = $state(false); 16 - let loginDialog = $state<HTMLDialogElement>(); 17 - let accountDialog = $state<HTMLDialogElement>(); 18 18 let theme_style = $derived(theme.value === "dark" 19 19 ? "text-white absolute top-0 z-[-2] h-screen w-screen bg-[#000000] bg-[radial-gradient(#ffffff33_1px,#00091d_1px)] bg-size-[20px_20px]" 20 20 : "text-black absolute inset-0 -z-10 h-full w-full bg-white bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] bg-size-[16px_16px]" ··· 36 36 {@render children()} 37 37 </section> 38 38 39 - <dialog bind:this={loginDialog} class="flex flex-col w-lg gap-4 bg-white top-1/2 left-1/2 -translate-1/2 p-4 rounded"> 40 - <span class="flex items-center gap-4 self-end w-full justify-between"> 41 - <h1 class="text-xl font-bold">Log into the Atmosphere</h1> 42 - <button onclick={() => loginDialog?.close()} class="bg-gray-100 px-3 py-2 rounded self-end">Close</button> 43 - </span> 44 - <form method="POST" action="/?/login" class="flex flex-col gap-4"> 45 - <input name="handle" type="text" placeholder="zeu.dev" class="border rounded px-4 py-2" /> 46 - <button type="submit" class="border px-3 py-2 rounded">Login</button> 47 - </form> 48 - <details class="border border-gray-300 px-3 py-2 rounded"> 49 - <summary class="marker:hidden font-semibold cursor-pointer"> 50 - <span class="text-blue-500">@</span> Enter your internet handle 51 - </summary> 52 - <span class="flex flex-col gap-2 text-sm pt-1"> 53 - <p> 54 - This would be a domain you control, most likely first created with Bluesky, Tangled, Gander, 55 - or other Atmosphere applications. 56 - </p> 57 - <a href="" class="text-blue-500 underline"> 58 - Learn more about ATproto and controlling your social media data 59 - </a> 60 - </span> 61 - </details> 62 - </dialog> 63 - 64 - <dialog bind:this={accountDialog} class="bg-white p-6 shadow top-1/2 left-1/2 -translate-1/2"> 65 - <h1>Account</h1> 66 - <button onclick={() => accountDialog?.close()}>Close</button> 67 - <form method="POST" action="/?/logout"> 68 - <button type="submit">Logout</button> 69 - </form> 70 - </dialog> 71 - 72 39 <aside class="z-50 fixed inset-x-0 bottom-0 text-black! flex w-full h-fit items-end justify-between p-8 pointer-events-none"> 73 40 <div class="flex flex-col justify-start gap-4 pointer-events-auto"> 74 41 {#if is_menu_open} ··· 116 83 </button> 117 84 118 85 <!-- TODO: change to <a href='/login'> --> 119 - {#if !user} 120 - <button 121 - onclick={() => loginDialog?.showModal()} 122 - class="items-center h-fit w-full hover:bg-slate-500/10 rounded-full" 123 - > 124 - <img src="/login-line.svg" alt="Login" class="w-12 h-12"/> 125 - </button> 126 - {:else} 127 - <button 128 - onclick={() => accountDialog?.showModal()} 129 - class="items-center h-fit w-full rounded-full" 130 - > 131 - <img src={user.avatar || "/user-line.svg"} alt="Login" class="w-10 h-10 rounded-full" /> 132 - </button> 133 - {/if} 86 + <button 87 + onclick={comingSoon} 88 + class="items-center h-fit w-full hover:bg-slate-500/10 rounded-full" 89 + > 90 + <img src="/login-line.svg" alt="Login" class="w-12 h-12"/> 91 + </button> 134 92 </nav> 135 93 </div> 136 94 ··· 148 106 </aside> 149 107 <Toaster /> 150 108 </div> 109 + 110 + <style lang="postcss"> 111 + @reference "tailwindcss"; 112 + </style>
-116
src/routes/+page.server.ts
··· 1 - import { atclient } from "$lib/atproto"; 2 - import type { Task } from "$lib/stores.svelte"; 3 - import { parseAtUri } from "$lib/utils"; 4 - import type { $Typed } from "@atproto/api"; 5 - import type { Create, CreateResult } from "@atproto/api/dist/client/types/com/atproto/repo/applyWrites"; 6 - import { isValidHandle } from "@atproto/syntax"; 7 - import { error, fail, redirect, type Actions } from "@sveltejs/kit"; 8 - 9 - export const actions: Actions = { 10 - login: async ({ request }) => { 11 - // get handle from form 12 - const formData = await request.formData(); 13 - const handle = formData.get("handle") as string; 14 - 15 - // validate handle using ATProto SDK 16 - if (!isValidHandle(handle)) { 17 - error(400, { message: "Invalid handle" }); 18 - } 19 - 20 - // get oauth authorizing url to redirect to 21 - const redirectUrl = await atclient.authorize(handle, { 22 - scope: "atproto repo:link.easytodo.tasks.list repo:link.easytodo.tasks.task rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app%23bsky_appview" 23 - }); 24 - 25 - if (!redirectUrl) { 26 - error(500, { message: "Unable to authorize" }); 27 - } 28 - 29 - // redirect for user to authorize 30 - redirect(301, redirectUrl.toString()); 31 - }, 32 - logout: async ({ cookies }) => { 33 - cookies.delete("sid", { path: "/" }); 34 - redirect(301, "/"); 35 - }, 36 - 37 - 38 - // ATProto CRUD 39 - saveListRecord: async ({ request, locals }) => { 40 - const user = locals.user; 41 - const agent = locals.authedAgent; 42 - if (!user || !agent) { return fail(401); } 43 - 44 - const formData = await request.formData(); 45 - const id = formData.get("id") as string; 46 - const list_rkey = formData.get("rkey") as string; 47 - const title = formData.get("title") as string; 48 - const tasks = JSON.parse(formData.get("tasks") as string) as Task[]; 49 - 50 - const response = await agent.com.atproto.repo.applyWrites({ 51 - repo: user.did, 52 - writes: tasks.map((t) => { 53 - const { rkey: task_rkey, stopwatchInterval, ...rest } = t; 54 - if (task_rkey) { 55 - console.log("UPDATE TASK"); 56 - return { 57 - $type: 'com.atproto.repo.applyWrites#update', 58 - collection: "link.easytodo.tasks.task", 59 - rkey: task_rkey, 60 - value: { 61 - $type: "link.easytodo.tasks.task", 62 - ...rest 63 - } 64 - } 65 - } 66 - else { 67 - console.log("CREATE TASK"); 68 - return { 69 - $type: 'com.atproto.repo.applyWrites#create', 70 - collection: "link.easytodo.tasks.task", 71 - value: { 72 - $type: "link.easytodo.tasks.task", 73 - ...rest 74 - }, 75 - } 76 - } 77 - }) 78 - }); 79 - 80 - if (response.success) { 81 - console.log(response.data.results); 82 - const list_record = { 83 - $type: "link.easytodo.tasks.list", 84 - createdAt: new Date().toISOString(), 85 - id, 86 - title, 87 - tasks: response.data.results?.map((t) => { 88 - // @ts-ignore 89 - return { cid: t.cid, uri: t.uri } 90 - }) 91 - }; 92 - 93 - if (list_rkey) { 94 - const { success, data } = await agent.com.atproto.repo.putRecord({ 95 - rkey: list_rkey, 96 - repo: user.did, 97 - collection: "link.easytodo.tasks.list", 98 - record: list_record 99 - }); 100 - console.log("UPDATE LIST", { success, uri: data.uri }); 101 - return { saveListRecordResult: { success, rkey: list_rkey, uri: data.uri }}; 102 - } 103 - else { 104 - const { success, data } = await agent.com.atproto.repo.createRecord({ 105 - repo: user.did, 106 - collection: "link.easytodo.tasks.list", 107 - record: list_record 108 - }); 109 - const { rkey } = parseAtUri(data.uri); 110 - console.log("CREATE LIST", { success, rkey, uri: data.uri }); 111 - return { saveListRecordResult: { success, rkey, uri: data.uri }}; 112 - } 113 - 114 - } 115 - } 116 - };
+7 -44
src/routes/[id]/+page.svelte
··· 1 1 <script lang="ts"> 2 2 import { onMount } from "svelte"; 3 3 import { page } from "$app/state"; 4 - import { enhance } from "$app/forms"; 5 4 import { goto } from "$app/navigation"; 6 5 import toast from "svelte-french-toast"; 7 - import type { PageProps } from "../$types.js"; 8 6 import { formatSecondsToDuration, generateId } from "$lib/utils"; 9 7 import { local_lists, pinned_list, type List, type Task } from "$lib/stores.svelte"; 10 8 11 - let { data, form }: PageProps = $props(); 12 - let { user } = $derived(data); 13 - let is_lists_menu_open = $state(false); 14 - let is_cloud_menu_open = $state(false); 9 + let is_menu_open = $state(false); 15 10 let list : List | undefined = $state(local_lists.value!.find((l) => l.id === page.params.id)); 16 11 let task_input = $state(""); 17 12 let user_lists = $derived(local_lists.value) as List[]; ··· 19 14 // since list points to something inside local_lists, 20 15 // it will run when list state changes 21 16 $effect(() => local_lists.update()); 22 - 23 - $effect(() => { 24 - if (form?.saveListRecordResult.success) { 25 - toast.success("Successfully saved to PDS!"); 26 - } 27 - }); 28 17 29 18 function addTask() { 30 19 if (task_input.length === 0) { ··· 117 106 {#if list} 118 107 <section class="relative flex gap-4 w-full"> 119 108 <div class="flex gap-4 border-black border w-fit h-fit p-2 bg-white rounded-xl"> 120 - <button onclick={() => is_lists_menu_open = !is_lists_menu_open}> 109 + <button onclick={() => is_menu_open = !is_menu_open}> 121 110 <img 122 111 src="/list-box-line.svg" 123 - alt="Lists menu button" 112 + alt="Lists button" 124 113 class="w-12 h-12 hover:bg-slate-500/10 rounded-full" 125 114 /> 126 115 </button> ··· 131 120 class="w-12 h-12 hover:bg-slate-500/10 rounded-full" 132 121 /> 133 122 </button> 134 - {#if user} 135 - <button onclick={() => is_cloud_menu_open = !is_cloud_menu_open}> 136 - <img 137 - src="/cloud.svg" 138 - alt="Cloud menu button" 139 - class="w-12 h-12 p-2 hover:bg-slate-500/10 rounded-full" 140 - /> 141 - </button> 142 - {/if} 143 123 <button onclick={deleteList}> 144 124 <img 145 125 src="/trash-line.svg" ··· 149 129 </button> 150 130 </div> 151 131 152 - {#if is_lists_menu_open} 132 + {#if is_menu_open} 153 133 <menu class="absolute flex flex-col gap-2 w-fit h-fit top-20 p-2 bg-white border border-black rounded-lg text-black! text-lg!"> 154 134 {#each user_lists as user_list : List (user_list.id)} 155 135 <button 156 136 onclick={() => { 157 - switchToList(user_list.id); 158 - is_lists_menu_open = false; 137 + switchToList(user_list.id) 138 + is_menu_open = false; 159 139 }} 160 140 class="flex gap-2 justify-between text-start w-full h-full rounded-xl pl-2 pr-5 py-2 hover:bg-slate-500/10 transition-all duration-150 items-center" 161 141 > ··· 168 148 <button 169 149 onclick={() => { 170 150 createList(); 171 - is_lists_menu_open = false; 151 + is_menu_open = false; 172 152 }} 173 153 class="flex gap-2 justify-between text-start w-full h-full rounded-xl pl-2 pr-5 py-2 hover:bg-slate-500/10 transition-all duration-150 items-center" 174 154 > 175 155 Create new list 176 156 </button> 177 - </menu> 178 - {/if} 179 - 180 - {#if is_cloud_menu_open} 181 - <menu class="absolute flex flex-col gap-2 w-fit h-fit top-20 p-2 bg-white border border-black rounded-lg text-black! text-lg!"> 182 - <form method="POST" action="/?/saveListRecord" use:enhance> 183 - <input name="id" type="hidden" value={list.id} /> 184 - <input name="title" type="hidden" value={list.title} /> 185 - <input name="tasks" type="hidden" value={JSON.stringify(list.tasks)} /> 186 - <button 187 - type="submit" 188 - class="flex gap-2 justify-between text-start w-full h-full rounded-xl pl-2 pr-5 py-2 hover:bg-slate-500/10 transition-all duration-150 items-center" 189 - > 190 - <img src="/save.svg" alt="Save to PDS button" class="w-8 h-8 p-2"/> 191 - Save to PDS 192 - </button> 193 - </form> 194 157 </menu> 195 158 {/if} 196 159 </section>
-6
src/routes/client-metadata.json/+server.ts
··· 1 - import { atclient } from "$lib/atproto"; 2 - import { json } from "@sveltejs/kit"; 3 - 4 - export async function GET() { 5 - return json(atclient.clientMetadata); 6 - }
-34
src/routes/oauth/callback/+server.ts
··· 1 - import { atclient } from "$lib/atproto"; 2 - import { encryptString } from "$lib/server/encryption"; 3 - import { decodeBase64, encodeBase64urlNoPadding } from "@oslojs/encoding"; 4 - 5 - import { error, redirect } from "@sveltejs/kit"; 6 - import type { RequestEvent } from "@sveltejs/kit"; 7 - import { ENCRYPTION_PASSWORD } from "$env/static/private"; 8 - 9 - // called on after authorizing OAuth 10 - export async function GET({ request, cookies }: RequestEvent) { 11 - // get parameters set by the callback 12 - const params = new URLSearchParams(request.url.split("?")[1]); 13 - 14 - try { 15 - const { session } = await atclient.callback(params); 16 - const key = decodeBase64(ENCRYPTION_PASSWORD); 17 - 18 - // encrypt the user DID 19 - const encrypted = await encryptString(key, session.did); 20 - const encoded = encodeBase64urlNoPadding(encrypted); 21 - 22 - // set encoded session DID as cookies for auth 23 - cookies.set("sid", encoded, { 24 - path: "/", 25 - maxAge: 60 * 60, 26 - httpOnly: true, 27 - sameSite: "lax" 28 - }); 29 - } catch (err) { 30 - error(500, { message: (err as Error).message }); 31 - } 32 - 33 - redirect(301, "/"); 34 - }
-1
static/cloud.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9"/></svg>
-1
static/save.svg
··· 1 - <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z"/><path d="M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7M7 3v4a1 1 0 0 0 1 1h7"/></g></svg>
-1
static/user-line.svg
··· 1 - <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><circle cx="12" cy="8" r="5"/><path d="M20 21a8 8 0 1 0-16 0m16 0a8 8 0 1 0-16 0"/></g></svg>