A website for the ATmosphereConf

chore: Remove database and iron-session

authored by daffl.xyz and committed by bmann.ca f670c9a8 91e6871c

+2
.env.template
··· 1 + PORT=4321 2 + PUBLIC_URL=
+9
astro.config.mjs
··· 1 1 import { defineConfig } from "astro/config"; 2 2 import tailwindcss from "@tailwindcss/vite"; 3 + import node from "@astrojs/node"; 3 4 4 5 export default defineConfig({ 6 + output: "server", 7 + adapter: node({ 8 + mode: "standalone", 9 + }), 10 + server: { 11 + host: "127.0.0.1", 12 + port: 4321, 13 + }, 5 14 vite: { 6 15 plugins: [tailwindcss()], 7 16 },
+528 -14
package-lock.json
··· 8 8 "name": "astro-atproto-starter", 9 9 "version": "0.0.1", 10 10 "dependencies": { 11 + "@astrojs/node": "^9.5.0", 11 12 "@astrojs/tailwind": "^6.0.2", 13 + "@atproto/api": "^0.17.4", 14 + "@atproto/oauth-client-node": "^0.3.10", 12 15 "@tailwindcss/vite": "^4.1.16", 13 16 "astro": "^5.15.1", 14 17 "daisyui": "^5.3.9", 18 + "dotenv": "^17.2.3", 15 19 "tailwindcss": "^4.1.16" 16 20 } 17 21 }, ··· 56 60 "vfile": "^6.0.3" 57 61 } 58 62 }, 63 + "node_modules/@astrojs/node": { 64 + "version": "9.5.0", 65 + "resolved": "https://registry.npmjs.org/@astrojs/node/-/node-9.5.0.tgz", 66 + "integrity": "sha512-x1whLIatmCefaqJA8FjfI+P6FStF+bqmmrib0OUGM1M3cZhAXKLgPx6UF2AzQ3JgpXgCWYM24MHtraPvZhhyLQ==", 67 + "license": "MIT", 68 + "dependencies": { 69 + "@astrojs/internal-helpers": "0.7.4", 70 + "send": "^1.2.0", 71 + "server-destroy": "^1.0.1" 72 + }, 73 + "peerDependencies": { 74 + "astro": "^5.14.3" 75 + } 76 + }, 59 77 "node_modules/@astrojs/prism": { 60 78 "version": "3.3.0", 61 79 "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.3.0.tgz", ··· 99 117 }, 100 118 "engines": { 101 119 "node": "18.20.8 || ^20.3.0 || >=22.0.0" 120 + } 121 + }, 122 + "node_modules/@atproto-labs/did-resolver": { 123 + "version": "0.2.2", 124 + "resolved": "https://registry.npmjs.org/@atproto-labs/did-resolver/-/did-resolver-0.2.2.tgz", 125 + "integrity": "sha512-ca2B7xR43tVoQ8XxBvha58DXwIH8cIyKQl6lpOKGkPUrJuFoO4iCLlDiSDi2Ueh+yE1rMDPP/qveHdajgDX3WQ==", 126 + "license": "MIT", 127 + "dependencies": { 128 + "@atproto-labs/fetch": "0.2.3", 129 + "@atproto-labs/pipe": "0.1.1", 130 + "@atproto-labs/simple-store": "0.3.0", 131 + "@atproto-labs/simple-store-memory": "0.1.4", 132 + "@atproto/did": "0.2.1", 133 + "zod": "^3.23.8" 134 + } 135 + }, 136 + "node_modules/@atproto-labs/fetch": { 137 + "version": "0.2.3", 138 + "resolved": "https://registry.npmjs.org/@atproto-labs/fetch/-/fetch-0.2.3.tgz", 139 + "integrity": "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw==", 140 + "license": "MIT", 141 + "dependencies": { 142 + "@atproto-labs/pipe": "0.1.1" 143 + } 144 + }, 145 + "node_modules/@atproto-labs/fetch-node": { 146 + "version": "0.2.0", 147 + "resolved": "https://registry.npmjs.org/@atproto-labs/fetch-node/-/fetch-node-0.2.0.tgz", 148 + "integrity": "sha512-Krq09nH/aeoiU2s9xdHA0FjTEFWG9B5FFenipv1iRixCcPc7V3DhTNDawxG9gI8Ny0k4dBVS9WTRN/IDzBx86Q==", 149 + "license": "MIT", 150 + "dependencies": { 151 + "@atproto-labs/fetch": "0.2.3", 152 + "@atproto-labs/pipe": "0.1.1", 153 + "ipaddr.js": "^2.1.0", 154 + "undici": "^6.14.1" 155 + }, 156 + "engines": { 157 + "node": ">=18.7.0" 158 + } 159 + }, 160 + "node_modules/@atproto-labs/handle-resolver": { 161 + "version": "0.3.2", 162 + "resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver/-/handle-resolver-0.3.2.tgz", 163 + "integrity": "sha512-KIerCzh3qb+zZoqWbIvTlvBY0XPq0r56kwViaJY/LTe/3oPO2JaqlYKS/F4dByWBhHK6YoUOJ0sWrh6PMJl40A==", 164 + "license": "MIT", 165 + "dependencies": { 166 + "@atproto-labs/simple-store": "0.3.0", 167 + "@atproto-labs/simple-store-memory": "0.1.4", 168 + "@atproto/did": "0.2.1", 169 + "zod": "^3.23.8" 170 + } 171 + }, 172 + "node_modules/@atproto-labs/handle-resolver-node": { 173 + "version": "0.1.21", 174 + "resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver-node/-/handle-resolver-node-0.1.21.tgz", 175 + "integrity": "sha512-fuJy5Px5pGF3lJX/ATdurbT8tbmaFWtf+PPxAQDFy7ot2no3t+iaAgymhyxYymrssOuWs6BwOP8tyF3VrfdwtQ==", 176 + "license": "MIT", 177 + "dependencies": { 178 + "@atproto-labs/fetch-node": "0.2.0", 179 + "@atproto-labs/handle-resolver": "0.3.2", 180 + "@atproto/did": "0.2.1" 181 + }, 182 + "engines": { 183 + "node": ">=18.7.0" 184 + } 185 + }, 186 + "node_modules/@atproto-labs/identity-resolver": { 187 + "version": "0.3.2", 188 + "resolved": "https://registry.npmjs.org/@atproto-labs/identity-resolver/-/identity-resolver-0.3.2.tgz", 189 + "integrity": "sha512-MYxO9pe0WsFyi5HFdKAwqIqHfiF2kBPoVhAIuH/4PYHzGr799ED47xLhNMxR3ZUYrJm5+TQzWXypGZ0Btw1Ffw==", 190 + "license": "MIT", 191 + "dependencies": { 192 + "@atproto-labs/did-resolver": "0.2.2", 193 + "@atproto-labs/handle-resolver": "0.3.2" 194 + } 195 + }, 196 + "node_modules/@atproto-labs/pipe": { 197 + "version": "0.1.1", 198 + "resolved": "https://registry.npmjs.org/@atproto-labs/pipe/-/pipe-0.1.1.tgz", 199 + "integrity": "sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg==", 200 + "license": "MIT" 201 + }, 202 + "node_modules/@atproto-labs/simple-store": { 203 + "version": "0.3.0", 204 + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store/-/simple-store-0.3.0.tgz", 205 + "integrity": "sha512-nOb6ONKBRJHRlukW1sVawUkBqReLlLx6hT35VS3imaNPwiXDxLnTK7lxw3Lrl9k5yugSBDQAkZAq3MPTEFSUBQ==", 206 + "license": "MIT" 207 + }, 208 + "node_modules/@atproto-labs/simple-store-memory": { 209 + "version": "0.1.4", 210 + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.4.tgz", 211 + "integrity": "sha512-3mKY4dP8I7yKPFj9VKpYyCRzGJOi5CEpOLPlRhoJyLmgs3J4RzDrjn323Oakjz2Aj2JzRU/AIvWRAZVhpYNJHw==", 212 + "license": "MIT", 213 + "dependencies": { 214 + "@atproto-labs/simple-store": "0.3.0", 215 + "lru-cache": "^10.2.0" 216 + } 217 + }, 218 + "node_modules/@atproto/api": { 219 + "version": "0.17.4", 220 + "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.17.4.tgz", 221 + "integrity": "sha512-MRa0WdxyDiGF7fVKd/2ldvonsHQjsaLUOGw/PHrZ7J01lqlw/jaXLS25FNNYzjPGmGpnIyDCIg4Uucd/OblI9w==", 222 + "license": "MIT", 223 + "dependencies": { 224 + "@atproto/common-web": "^0.4.3", 225 + "@atproto/lexicon": "^0.5.1", 226 + "@atproto/syntax": "^0.4.1", 227 + "@atproto/xrpc": "^0.7.5", 228 + "await-lock": "^2.2.2", 229 + "multiformats": "^9.9.0", 230 + "tlds": "^1.234.0", 231 + "zod": "^3.23.8" 232 + } 233 + }, 234 + "node_modules/@atproto/common-web": { 235 + "version": "0.4.3", 236 + "resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.3.tgz", 237 + "integrity": "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg==", 238 + "license": "MIT", 239 + "dependencies": { 240 + "graphemer": "^1.4.0", 241 + "multiformats": "^9.9.0", 242 + "uint8arrays": "3.0.0", 243 + "zod": "^3.23.8" 244 + } 245 + }, 246 + "node_modules/@atproto/did": { 247 + "version": "0.2.1", 248 + "resolved": "https://registry.npmjs.org/@atproto/did/-/did-0.2.1.tgz", 249 + "integrity": "sha512-1i5BTU2GnBaaeYWhxUOnuEKFVq9euT5+dQPFabHpa927BlJ54PmLGyBBaOI7/NbLmN5HWwBa18SBkMpg3jGZRA==", 250 + "license": "MIT", 251 + "dependencies": { 252 + "zod": "^3.23.8" 253 + } 254 + }, 255 + "node_modules/@atproto/jwk": { 256 + "version": "0.6.0", 257 + "resolved": "https://registry.npmjs.org/@atproto/jwk/-/jwk-0.6.0.tgz", 258 + "integrity": "sha512-bDoJPvt7TrQVi/rBfBrSSpGykhtIriKxeYCYQTiPRKFfyRhbgpElF0wPXADjIswnbzZdOwbY63az4E/CFVT3Tw==", 259 + "license": "MIT", 260 + "dependencies": { 261 + "multiformats": "^9.9.0", 262 + "zod": "^3.23.8" 263 + } 264 + }, 265 + "node_modules/@atproto/jwk-jose": { 266 + "version": "0.1.11", 267 + "resolved": "https://registry.npmjs.org/@atproto/jwk-jose/-/jwk-jose-0.1.11.tgz", 268 + "integrity": "sha512-i4Fnr2sTBYmMmHXl7NJh8GrCH+tDQEVWrcDMDnV5DjJfkgT17wIqvojIw9SNbSL4Uf0OtfEv6AgG0A+mgh8b5Q==", 269 + "license": "MIT", 270 + "dependencies": { 271 + "@atproto/jwk": "0.6.0", 272 + "jose": "^5.2.0" 273 + } 274 + }, 275 + "node_modules/@atproto/jwk-webcrypto": { 276 + "version": "0.2.0", 277 + "resolved": "https://registry.npmjs.org/@atproto/jwk-webcrypto/-/jwk-webcrypto-0.2.0.tgz", 278 + "integrity": "sha512-UmgRrrEAkWvxwhlwe30UmDOdTEFidlIzBC7C3cCbeJMcBN1x8B3KH+crXrsTqfWQBG58mXgt8wgSK3Kxs2LhFg==", 279 + "license": "MIT", 280 + "dependencies": { 281 + "@atproto/jwk": "0.6.0", 282 + "@atproto/jwk-jose": "0.1.11", 283 + "zod": "^3.23.8" 284 + } 285 + }, 286 + "node_modules/@atproto/lexicon": { 287 + "version": "0.5.1", 288 + "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.5.1.tgz", 289 + "integrity": "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A==", 290 + "license": "MIT", 291 + "dependencies": { 292 + "@atproto/common-web": "^0.4.3", 293 + "@atproto/syntax": "^0.4.1", 294 + "iso-datestring-validator": "^2.2.2", 295 + "multiformats": "^9.9.0", 296 + "zod": "^3.23.8" 297 + } 298 + }, 299 + "node_modules/@atproto/oauth-client": { 300 + "version": "0.5.8", 301 + "resolved": "https://registry.npmjs.org/@atproto/oauth-client/-/oauth-client-0.5.8.tgz", 302 + "integrity": "sha512-7YEym6d97+Dd73qGdkQTXi5La8xvCQxwRUDzzlR/NVAARa9a4YP7MCmqBJVeP2anT0By+DSAPyPDLTsxcjIcCg==", 303 + "license": "MIT", 304 + "dependencies": { 305 + "@atproto-labs/did-resolver": "0.2.2", 306 + "@atproto-labs/fetch": "0.2.3", 307 + "@atproto-labs/handle-resolver": "0.3.2", 308 + "@atproto-labs/identity-resolver": "0.3.2", 309 + "@atproto-labs/simple-store": "0.3.0", 310 + "@atproto-labs/simple-store-memory": "0.1.4", 311 + "@atproto/did": "0.2.1", 312 + "@atproto/jwk": "0.6.0", 313 + "@atproto/oauth-types": "0.5.0", 314 + "@atproto/xrpc": "0.7.5", 315 + "core-js": "^3", 316 + "multiformats": "^9.9.0", 317 + "zod": "^3.23.8" 318 + } 319 + }, 320 + "node_modules/@atproto/oauth-client-node": { 321 + "version": "0.3.10", 322 + "resolved": "https://registry.npmjs.org/@atproto/oauth-client-node/-/oauth-client-node-0.3.10.tgz", 323 + "integrity": "sha512-6khKlJqu1Ed5rt3rzcTD5hymB6JUjKdOHWYXwiphw4inkAIo6GxLCighI4eGOqZorYk2j8ueeTNB6KsgH0kcRw==", 324 + "license": "MIT", 325 + "dependencies": { 326 + "@atproto-labs/did-resolver": "0.2.2", 327 + "@atproto-labs/handle-resolver-node": "0.1.21", 328 + "@atproto-labs/simple-store": "0.3.0", 329 + "@atproto/did": "0.2.1", 330 + "@atproto/jwk": "0.6.0", 331 + "@atproto/jwk-jose": "0.1.11", 332 + "@atproto/jwk-webcrypto": "0.2.0", 333 + "@atproto/oauth-client": "0.5.8", 334 + "@atproto/oauth-types": "0.5.0" 335 + }, 336 + "engines": { 337 + "node": ">=18.7.0" 338 + } 339 + }, 340 + "node_modules/@atproto/oauth-types": { 341 + "version": "0.5.0", 342 + "resolved": "https://registry.npmjs.org/@atproto/oauth-types/-/oauth-types-0.5.0.tgz", 343 + "integrity": "sha512-33xz7HcXhbl+XRqbIMVu3GE02iK1nKe2oMWENASsfZEYbCz2b9ZOarOFuwi7g4LKqpGowGp0iRKsQHFcq4SDaQ==", 344 + "license": "MIT", 345 + "dependencies": { 346 + "@atproto/did": "0.2.1", 347 + "@atproto/jwk": "0.6.0", 348 + "zod": "^3.23.8" 349 + } 350 + }, 351 + "node_modules/@atproto/syntax": { 352 + "version": "0.4.1", 353 + "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.1.tgz", 354 + "integrity": "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw==", 355 + "license": "MIT" 356 + }, 357 + "node_modules/@atproto/xrpc": { 358 + "version": "0.7.5", 359 + "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.5.tgz", 360 + "integrity": "sha512-MUYNn5d2hv8yVegRL0ccHvTHAVj5JSnW07bkbiaz96UH45lvYNRVwt44z+yYVnb0/mvBzyD3/ZQ55TRGt7fHkA==", 361 + "license": "MIT", 362 + "dependencies": { 363 + "@atproto/lexicon": "^0.5.1", 364 + "zod": "^3.23.8" 102 365 } 103 366 }, 104 367 "node_modules/@babel/helper-string-parser": { ··· 2047 2310 "postcss": "^8.1.0" 2048 2311 } 2049 2312 }, 2313 + "node_modules/await-lock": { 2314 + "version": "2.2.2", 2315 + "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", 2316 + "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==", 2317 + "license": "MIT" 2318 + }, 2050 2319 "node_modules/axobject-query": { 2051 2320 "version": "4.1.0", 2052 2321 "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", ··· 2340 2609 "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", 2341 2610 "license": "MIT" 2342 2611 }, 2612 + "node_modules/core-js": { 2613 + "version": "3.46.0", 2614 + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", 2615 + "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", 2616 + "hasInstallScript": true, 2617 + "license": "MIT", 2618 + "funding": { 2619 + "type": "opencollective", 2620 + "url": "https://opencollective.com/core-js" 2621 + } 2622 + }, 2343 2623 "node_modules/crossws": { 2344 2624 "version": "0.3.5", 2345 2625 "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", ··· 2419 2699 "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", 2420 2700 "license": "MIT" 2421 2701 }, 2702 + "node_modules/depd": { 2703 + "version": "2.0.0", 2704 + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 2705 + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 2706 + "license": "MIT", 2707 + "engines": { 2708 + "node": ">= 0.8" 2709 + } 2710 + }, 2422 2711 "node_modules/dequal": { 2423 2712 "version": "2.0.3", 2424 2713 "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", ··· 2495 2784 "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", 2496 2785 "license": "MIT" 2497 2786 }, 2787 + "node_modules/dotenv": { 2788 + "version": "17.2.3", 2789 + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", 2790 + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", 2791 + "license": "BSD-2-Clause", 2792 + "engines": { 2793 + "node": ">=12" 2794 + }, 2795 + "funding": { 2796 + "url": "https://dotenvx.com" 2797 + } 2798 + }, 2498 2799 "node_modules/dset": { 2499 2800 "version": "3.1.4", 2500 2801 "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", ··· 2504 2805 "node": ">=4" 2505 2806 } 2506 2807 }, 2808 + "node_modules/ee-first": { 2809 + "version": "1.1.1", 2810 + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 2811 + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", 2812 + "license": "MIT" 2813 + }, 2507 2814 "node_modules/electron-to-chromium": { 2508 2815 "version": "1.5.240", 2509 2816 "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.240.tgz", ··· 2515 2822 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", 2516 2823 "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", 2517 2824 "license": "MIT" 2825 + }, 2826 + "node_modules/encodeurl": { 2827 + "version": "2.0.0", 2828 + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 2829 + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", 2830 + "license": "MIT", 2831 + "engines": { 2832 + "node": ">= 0.8" 2833 + } 2518 2834 }, 2519 2835 "node_modules/enhanced-resolve": { 2520 2836 "version": "5.18.3", ··· 2597 2913 "node": ">=6" 2598 2914 } 2599 2915 }, 2916 + "node_modules/escape-html": { 2917 + "version": "1.0.3", 2918 + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 2919 + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", 2920 + "license": "MIT" 2921 + }, 2600 2922 "node_modules/escape-string-regexp": { 2601 2923 "version": "5.0.0", 2602 2924 "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", ··· 2616 2938 "license": "MIT", 2617 2939 "dependencies": { 2618 2940 "@types/estree": "^1.0.0" 2941 + } 2942 + }, 2943 + "node_modules/etag": { 2944 + "version": "1.8.1", 2945 + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 2946 + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 2947 + "license": "MIT", 2948 + "engines": { 2949 + "node": ">= 0.6" 2619 2950 } 2620 2951 }, 2621 2952 "node_modules/eventemitter3": { ··· 2702 3033 "url": "https://github.com/sponsors/rawify" 2703 3034 } 2704 3035 }, 3036 + "node_modules/fresh": { 3037 + "version": "2.0.0", 3038 + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", 3039 + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", 3040 + "license": "MIT", 3041 + "engines": { 3042 + "node": ">= 0.8" 3043 + } 3044 + }, 2705 3045 "node_modules/fsevents": { 2706 3046 "version": "2.3.3", 2707 3047 "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", ··· 2739 3079 "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 2740 3080 "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 2741 3081 "license": "ISC" 3082 + }, 3083 + "node_modules/graphemer": { 3084 + "version": "1.4.0", 3085 + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", 3086 + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 3087 + "license": "MIT" 2742 3088 }, 2743 3089 "node_modules/h3": { 2744 3090 "version": "1.15.4", ··· 2966 3312 "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", 2967 3313 "license": "BSD-2-Clause" 2968 3314 }, 3315 + "node_modules/http-errors": { 3316 + "version": "2.0.0", 3317 + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 3318 + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 3319 + "license": "MIT", 3320 + "dependencies": { 3321 + "depd": "2.0.0", 3322 + "inherits": "2.0.4", 3323 + "setprototypeof": "1.2.0", 3324 + "statuses": "2.0.1", 3325 + "toidentifier": "1.0.1" 3326 + }, 3327 + "engines": { 3328 + "node": ">= 0.8" 3329 + } 3330 + }, 3331 + "node_modules/http-errors/node_modules/statuses": { 3332 + "version": "2.0.1", 3333 + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 3334 + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 3335 + "license": "MIT", 3336 + "engines": { 3337 + "node": ">= 0.8" 3338 + } 3339 + }, 2969 3340 "node_modules/import-meta-resolve": { 2970 3341 "version": "4.2.0", 2971 3342 "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", ··· 2974 3345 "funding": { 2975 3346 "type": "github", 2976 3347 "url": "https://github.com/sponsors/wooorm" 3348 + } 3349 + }, 3350 + "node_modules/inherits": { 3351 + "version": "2.0.4", 3352 + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 3353 + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 3354 + "license": "ISC" 3355 + }, 3356 + "node_modules/ipaddr.js": { 3357 + "version": "2.2.0", 3358 + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", 3359 + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", 3360 + "license": "MIT", 3361 + "engines": { 3362 + "node": ">= 10" 2977 3363 } 2978 3364 }, 2979 3365 "node_modules/iron-webcrypto": { ··· 3054 3440 "url": "https://github.com/sponsors/sindresorhus" 3055 3441 } 3056 3442 }, 3443 + "node_modules/iso-datestring-validator": { 3444 + "version": "2.2.2", 3445 + "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", 3446 + "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==", 3447 + "license": "MIT" 3448 + }, 3057 3449 "node_modules/jiti": { 3058 3450 "version": "2.6.1", 3059 3451 "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", ··· 3061 3453 "license": "MIT", 3062 3454 "bin": { 3063 3455 "jiti": "lib/jiti-cli.mjs" 3456 + } 3457 + }, 3458 + "node_modules/jose": { 3459 + "version": "5.10.0", 3460 + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", 3461 + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", 3462 + "license": "MIT", 3463 + "funding": { 3464 + "url": "https://github.com/sponsors/panva" 3064 3465 } 3065 3466 }, 3066 3467 "node_modules/js-yaml": { ··· 4185 4586 ], 4186 4587 "license": "MIT" 4187 4588 }, 4589 + "node_modules/mime-db": { 4590 + "version": "1.54.0", 4591 + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", 4592 + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", 4593 + "license": "MIT", 4594 + "engines": { 4595 + "node": ">= 0.6" 4596 + } 4597 + }, 4598 + "node_modules/mime-types": { 4599 + "version": "3.0.1", 4600 + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", 4601 + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", 4602 + "license": "MIT", 4603 + "dependencies": { 4604 + "mime-db": "^1.54.0" 4605 + }, 4606 + "engines": { 4607 + "node": ">= 0.6" 4608 + } 4609 + }, 4188 4610 "node_modules/mrmime": { 4189 4611 "version": "2.0.1", 4190 4612 "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", ··· 4199 4621 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 4200 4622 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 4201 4623 "license": "MIT" 4624 + }, 4625 + "node_modules/multiformats": { 4626 + "version": "9.9.0", 4627 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 4628 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 4629 + "license": "(Apache-2.0 AND MIT)" 4202 4630 }, 4203 4631 "node_modules/nanoid": { 4204 4632 "version": "3.3.11", ··· 4292 4720 "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", 4293 4721 "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", 4294 4722 "license": "MIT" 4723 + }, 4724 + "node_modules/on-finished": { 4725 + "version": "2.4.1", 4726 + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 4727 + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 4728 + "license": "MIT", 4729 + "dependencies": { 4730 + "ee-first": "1.1.1" 4731 + }, 4732 + "engines": { 4733 + "node": ">= 0.8" 4734 + } 4295 4735 }, 4296 4736 "node_modules/oniguruma-parser": { 4297 4737 "version": "0.12.1", ··· 4520 4960 "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", 4521 4961 "license": "MIT" 4522 4962 }, 4963 + "node_modules/range-parser": { 4964 + "version": "1.2.1", 4965 + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 4966 + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 4967 + "license": "MIT", 4968 + "engines": { 4969 + "node": ">= 0.6" 4970 + } 4971 + }, 4523 4972 "node_modules/readdirp": { 4524 4973 "version": "4.1.2", 4525 4974 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", ··· 4819 5268 "node": ">=10" 4820 5269 } 4821 5270 }, 5271 + "node_modules/send": { 5272 + "version": "1.2.0", 5273 + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", 5274 + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", 5275 + "license": "MIT", 5276 + "dependencies": { 5277 + "debug": "^4.3.5", 5278 + "encodeurl": "^2.0.0", 5279 + "escape-html": "^1.0.3", 5280 + "etag": "^1.8.1", 5281 + "fresh": "^2.0.0", 5282 + "http-errors": "^2.0.0", 5283 + "mime-types": "^3.0.1", 5284 + "ms": "^2.1.3", 5285 + "on-finished": "^2.4.1", 5286 + "range-parser": "^1.2.1", 5287 + "statuses": "^2.0.1" 5288 + }, 5289 + "engines": { 5290 + "node": ">= 18" 5291 + } 5292 + }, 5293 + "node_modules/server-destroy": { 5294 + "version": "1.0.1", 5295 + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", 5296 + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", 5297 + "license": "ISC" 5298 + }, 5299 + "node_modules/setprototypeof": { 5300 + "version": "1.2.0", 5301 + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 5302 + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 5303 + "license": "ISC" 5304 + }, 4822 5305 "node_modules/sharp": { 4823 5306 "version": "0.34.4", 4824 5307 "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", ··· 4913 5396 "funding": { 4914 5397 "type": "github", 4915 5398 "url": "https://github.com/sponsors/wooorm" 5399 + } 5400 + }, 5401 + "node_modules/statuses": { 5402 + "version": "2.0.2", 5403 + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", 5404 + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", 5405 + "license": "MIT", 5406 + "engines": { 5407 + "node": ">= 0.8" 4916 5408 } 4917 5409 }, 4918 5410 "node_modules/string-width": { ··· 5008 5500 "url": "https://github.com/sponsors/SuperchupuDev" 5009 5501 } 5010 5502 }, 5503 + "node_modules/tlds": { 5504 + "version": "1.261.0", 5505 + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz", 5506 + "integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==", 5507 + "license": "MIT", 5508 + "bin": { 5509 + "tlds": "bin.js" 5510 + } 5511 + }, 5512 + "node_modules/toidentifier": { 5513 + "version": "1.0.1", 5514 + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 5515 + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 5516 + "license": "MIT", 5517 + "engines": { 5518 + "node": ">=0.6" 5519 + } 5520 + }, 5011 5521 "node_modules/trim-lines": { 5012 5522 "version": "3.0.1", 5013 5523 "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", ··· 5066 5576 "url": "https://github.com/sponsors/sindresorhus" 5067 5577 } 5068 5578 }, 5069 - "node_modules/typescript": { 5070 - "version": "5.9.3", 5071 - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", 5072 - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", 5073 - "license": "Apache-2.0", 5074 - "peer": true, 5075 - "bin": { 5076 - "tsc": "bin/tsc", 5077 - "tsserver": "bin/tsserver" 5078 - }, 5079 - "engines": { 5080 - "node": ">=14.17" 5081 - } 5082 - }, 5083 5579 "node_modules/ufo": { 5084 5580 "version": "1.6.1", 5085 5581 "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", 5086 5582 "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", 5087 5583 "license": "MIT" 5088 5584 }, 5585 + "node_modules/uint8arrays": { 5586 + "version": "3.0.0", 5587 + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", 5588 + "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", 5589 + "license": "MIT", 5590 + "dependencies": { 5591 + "multiformats": "^9.4.2" 5592 + } 5593 + }, 5089 5594 "node_modules/ultrahtml": { 5090 5595 "version": "1.6.0", 5091 5596 "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz", ··· 5097 5602 "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", 5098 5603 "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", 5099 5604 "license": "MIT" 5605 + }, 5606 + "node_modules/undici": { 5607 + "version": "6.22.0", 5608 + "resolved": "https://registry.npmjs.org/undici/-/undici-6.22.0.tgz", 5609 + "integrity": "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==", 5610 + "license": "MIT", 5611 + "engines": { 5612 + "node": ">=18.17" 5613 + } 5100 5614 }, 5101 5615 "node_modules/undici-types": { 5102 5616 "version": "7.16.0",
+4
package.json
··· 9 9 "astro": "astro" 10 10 }, 11 11 "dependencies": { 12 + "@astrojs/node": "^9.5.0", 12 13 "@astrojs/tailwind": "^6.0.2", 14 + "@atproto/api": "^0.17.4", 15 + "@atproto/oauth-client-node": "^0.3.10", 13 16 "@tailwindcss/vite": "^4.1.16", 14 17 "astro": "^5.15.1", 15 18 "daisyui": "^5.3.9", 19 + "dotenv": "^17.2.3", 16 20 "tailwindcss": "^4.1.16" 17 21 } 18 22 }
+17
src/lib/context.ts
··· 1 + import { NodeOAuthClient } from '@atproto/oauth-client-node' 2 + import { createOAuthClient } from './oauth' 3 + 4 + export type AppContext = { 5 + oauthClient: NodeOAuthClient 6 + } 7 + 8 + let _ctx: AppContext | null = null 9 + 10 + export async function getAppContext(): Promise<AppContext> { 11 + if (_ctx) return _ctx 12 + 13 + const oauthClient = await createOAuthClient() 14 + 15 + _ctx = { oauthClient } 16 + return _ctx 17 + }
+4
src/lib/env.ts
··· 1 + export const env = { 2 + PORT: Number(process.env.PORT) || 4321, 3 + PUBLIC_URL: process.env.PUBLIC_URL || undefined, 4 + }
+21
src/lib/oauth.ts
··· 1 + import { 2 + atprotoLoopbackClientMetadata, 3 + NodeOAuthClient, 4 + } from "@atproto/oauth-client-node"; 5 + import { env } from "./env"; 6 + import { SessionStore, StateStore } from "./storage"; 7 + 8 + export async function createOAuthClient() { 9 + const clientMetadata = atprotoLoopbackClientMetadata( 10 + `http://localhost?${new URLSearchParams([ 11 + ["redirect_uri", `http://127.0.0.1:${env.PORT}/api/oauth/callback`], 12 + ["scope", `atproto transition:generic`], 13 + ])}`, 14 + ); 15 + 16 + return new NodeOAuthClient({ 17 + clientMetadata, 18 + stateStore: new StateStore(), 19 + sessionStore: new SessionStore(), 20 + }); 21 + }
+61
src/lib/session.ts
··· 1 + import type { AstroCookies } from 'astro' 2 + 3 + export type SessionData = { did?: string } 4 + 5 + const COOKIE_NAME = 'sid' 6 + 7 + // Simple cookie-based session using Web Crypto API 8 + export class Session { 9 + private data: SessionData = {} 10 + private cookies: AstroCookies 11 + 12 + constructor(cookies: AstroCookies, data: SessionData = {}) { 13 + this.cookies = cookies 14 + this.data = data 15 + } 16 + 17 + get did() { 18 + return this.data.did 19 + } 20 + 21 + set did(value: string | undefined) { 22 + this.data.did = value 23 + } 24 + 25 + async save() { 26 + const jsonData = JSON.stringify(this.data) 27 + // For simplicity, we'll just base64 encode the data 28 + // In production, you'd want proper encryption 29 + const encoded = btoa(jsonData) 30 + 31 + this.cookies.set(COOKIE_NAME, encoded, { 32 + httpOnly: true, 33 + secure: false, 34 + sameSite: 'lax', 35 + path: '/', 36 + maxAge: 60 * 60 * 24 * 30, // 30 days 37 + }) 38 + } 39 + 40 + destroy() { 41 + this.data = {} 42 + this.cookies.delete(COOKIE_NAME, { path: '/' }) 43 + } 44 + } 45 + 46 + export function getSession(cookies: AstroCookies): Session { 47 + const cookie = cookies.get(COOKIE_NAME) 48 + 49 + if (!cookie?.value) { 50 + return new Session(cookies) 51 + } 52 + 53 + try { 54 + const decoded = atob(cookie.value) 55 + const data = JSON.parse(decoded) as SessionData 56 + return new Session(cookies, data) 57 + } catch (err) { 58 + console.warn('Failed to decode session:', err) 59 + return new Session(cookies) 60 + } 61 + }
+41
src/lib/storage.ts
··· 1 + import type { 2 + NodeSavedSession, 3 + NodeSavedSessionStore, 4 + NodeSavedState, 5 + NodeSavedStateStore, 6 + } from '@atproto/oauth-client-node' 7 + 8 + // In-memory storage for OAuth state and sessions 9 + // For production, you'd want to use a proper database or distributed cache 10 + 11 + export class StateStore implements NodeSavedStateStore { 12 + private store = new Map<string, NodeSavedState>() 13 + 14 + async get(key: string): Promise<NodeSavedState | undefined> { 15 + return this.store.get(key) 16 + } 17 + 18 + async set(key: string, val: NodeSavedState) { 19 + this.store.set(key, val) 20 + } 21 + 22 + async del(key: string) { 23 + this.store.delete(key) 24 + } 25 + } 26 + 27 + export class SessionStore implements NodeSavedSessionStore { 28 + private store = new Map<string, NodeSavedSession>() 29 + 30 + async get(key: string): Promise<NodeSavedSession | undefined> { 31 + return this.store.get(key) 32 + } 33 + 34 + async set(key: string, val: NodeSavedSession) { 35 + this.store.set(key, val) 36 + } 37 + 38 + async del(key: string) { 39 + this.store.delete(key) 40 + } 41 + }
+24
src/pages/api/login.ts
··· 1 + import type { APIRoute } from 'astro' 2 + import { getAppContext } from '../../lib/context' 3 + 4 + export const POST: APIRoute = async ({ request, redirect }) => { 5 + try { 6 + const ctx = await getAppContext() 7 + const formData = await request.formData() 8 + const handle = formData.get('handle') 9 + 10 + if (!handle || typeof handle !== 'string') { 11 + return new Response('Invalid handle', { status: 400 }) 12 + } 13 + 14 + const url = await ctx.oauthClient.authorize(handle, { 15 + scope: 'atproto transition:generic', 16 + }) 17 + 18 + return redirect(url.toString()) 19 + } catch (err) { 20 + console.error('OAuth authorize failed:', err) 21 + const error = err instanceof Error ? err.message : 'unexpected error' 22 + return new Response(`Login failed: ${error}`, { status: 500 }) 23 + } 24 + }
+26
src/pages/api/logout.ts
··· 1 + import type { APIRoute } from 'astro' 2 + import { getAppContext } from '../../lib/context' 3 + import { getSession } from '../../lib/session' 4 + 5 + export const POST: APIRoute = async (context) => { 6 + try { 7 + const ctx = await getAppContext() 8 + const session = getSession(context.cookies) 9 + 10 + if (session.did) { 11 + try { 12 + const oauthSession = await ctx.oauthClient.restore(session.did) 13 + if (oauthSession) await oauthSession.signOut() 14 + } catch (err) { 15 + console.warn('Failed to revoke credentials:', err) 16 + } 17 + } 18 + 19 + session.destroy() 20 + 21 + return context.redirect('/') 22 + } catch (err) { 23 + console.error('Logout failed:', err) 24 + return new Response('Logout failed', { status: 500 }) 25 + } 26 + }
+31
src/pages/api/oauth/callback.ts
··· 1 + import type { APIRoute } from 'astro' 2 + import { getAppContext } from '../../../lib/context' 3 + import { getSession } from '../../../lib/session' 4 + 5 + export const GET: APIRoute = async (context) => { 6 + try { 7 + const ctx = await getAppContext() 8 + const url = new URL(context.request.url) 9 + const params = new URLSearchParams(url.search) 10 + 11 + const session = getSession(context.cookies) 12 + 13 + if (session.did) { 14 + try { 15 + const oauthSession = await ctx.oauthClient.restore(session.did) 16 + if (oauthSession) await oauthSession.signOut() 17 + } catch (err) { 18 + console.warn('OAuth restore failed during callback:', err) 19 + } 20 + } 21 + 22 + const oauth = await ctx.oauthClient.callback(params) 23 + session.did = oauth.session.did 24 + await session.save() 25 + 26 + return context.redirect('/') 27 + } catch (err) { 28 + console.error('OAuth callback failed:', err) 29 + return context.redirect('/?error=login_failed') 30 + } 31 + }
+74 -14
src/pages/index.astro
··· 1 1 --- 2 2 import "../styles.css"; 3 + import { getSession } from "../lib/session"; 4 + import { getAppContext } from "../lib/context"; 5 + import { Agent } from "@atproto/api"; 6 + 7 + const session = getSession(Astro.cookies); 8 + const ctx = await getAppContext(); 9 + 10 + let agent: Agent | null = null; 11 + let profile: any = null; 12 + 13 + if (session.did) { 14 + try { 15 + const oauthSession = await ctx.oauthClient.restore(session.did); 16 + if (oauthSession) { 17 + agent = new Agent(oauthSession); 18 + 19 + try { 20 + const profileResponse = await agent.com.atproto.repo.getRecord({ 21 + repo: agent.assertDid, 22 + collection: "app.bsky.actor.profile", 23 + rkey: "self", 24 + }); 25 + profile = profileResponse.data; 26 + } catch (err) { 27 + console.warn("Failed to fetch profile:", err); 28 + } 29 + } 30 + } catch (err) { 31 + console.warn("OAuth restore failed:", err); 32 + session.destroy(); 33 + } 34 + } 35 + 36 + const displayName = profile?.value?.displayName || agent?.assertDid || "User"; 37 + const handle = agent?.assertDid || ""; 3 38 --- 4 39 5 40 <html lang="en" data-theme="dracula"> ··· 14 49 <div class="min-h-screen flex items-center justify-center"> 15 50 <div class="card w-96 bg-base-100 shadow-xl"> 16 51 <div class="card-body"> 17 - <h2 class="card-title justify-center mb-6">Login</h2> 18 - <form> 19 - <div class="join join-vertical w-full"> 20 - <input 21 - type="text" 22 - placeholder="Username" 23 - class="input input-bordered join-item" 24 - name="username" 25 - /> 26 - <button type="submit" class="btn btn-primary join-item"> 27 - Login 28 - </button> 29 - </div> 30 - </form> 52 + { 53 + agent ? ( 54 + <> 55 + <h2 class="card-title justify-center mb-4">Welcome!</h2> 56 + <div class="space-y-4"> 57 + <div class="text-center"> 58 + <p class="text-lg font-semibold">{displayName}</p> 59 + <p class="text-sm opacity-70">{handle}</p> 60 + </div> 61 + <form method="POST" action="/api/logout" class="w-full"> 62 + <button type="submit" class="btn btn-error w-full"> 63 + Logout 64 + </button> 65 + </form> 66 + </div> 67 + </> 68 + ) : ( 69 + <> 70 + <h2 class="card-title justify-center mb-6">ATProto Login</h2> 71 + <form method="POST" action="/api/login"> 72 + <div class="join join-vertical w-full"> 73 + <input 74 + type="text" 75 + placeholder="Enter your handle (e.g. alice.bsky.social)" 76 + class="input input-bordered join-item" 77 + name="handle" 78 + required 79 + /> 80 + <button 81 + type="submit" 82 + class="btn btn-primary btn-wide join-item" 83 + > 84 + Login 85 + </button> 86 + </div> 87 + </form> 88 + </> 89 + ) 90 + } 31 91 </div> 32 92 </div> 33 93 </div>