the statusphere demo reworked into a vite/react app in a monorepo

setup basic html views

+276 -20
+5 -9
package.json
··· 33 "kysely": "^0.27.4", 34 "multiformats": "^9.9.0", 35 "pino": "^9.3.2", 36 - "pino-http": "^10.0.0" 37 }, 38 "devDependencies": { 39 "@atproto/lex-cli": "^0.4.1", ··· 45 "pino-pretty": "^11.0.0", 46 "rimraf": "^5.0.0", 47 "supertest": "^7.0.0", 48 "tsup": "^8.0.2", 49 "tsx": "^4.7.2", 50 "typescript": "^5.4.4", ··· 52 "vitest": "^2.0.0" 53 }, 54 "lint-staged": { 55 - "*.{js,ts,cjs,mjs,d.cts,d.mts,json,jsonc}": [ 56 - "biome check --apply --no-errors-on-unmatched" 57 - ] 58 }, 59 "tsup": { 60 - "entry": [ 61 - "src", 62 - "!src/**/__tests__/**", 63 - "!src/**/*.test.*" 64 - ], 65 "splitting": false, 66 "sourcemap": true, 67 "clean": true
··· 33 "kysely": "^0.27.4", 34 "multiformats": "^9.9.0", 35 "pino": "^9.3.2", 36 + "pino-http": "^10.0.0", 37 + "uhtml": "^4.5.9" 38 }, 39 "devDependencies": { 40 "@atproto/lex-cli": "^0.4.1", ··· 46 "pino-pretty": "^11.0.0", 47 "rimraf": "^5.0.0", 48 "supertest": "^7.0.0", 49 + "ts-node": "^10.9.2", 50 "tsup": "^8.0.2", 51 "tsx": "^4.7.2", 52 "typescript": "^5.4.4", ··· 54 "vitest": "^2.0.0" 55 }, 56 "lint-staged": { 57 + "*.{js,ts,cjs,mjs,d.cts,d.mts,json,jsonc}": ["biome check --apply --no-errors-on-unmatched"] 58 }, 59 "tsup": { 60 + "entry": ["src", "!src/**/__tests__/**", "!src/**/*.test.*"], 61 "splitting": false, 62 "sourcemap": true, 63 "clean": true
+209 -7
pnpm-lock.yaml
··· 53 pino-http: 54 specifier: ^10.0.0 55 version: 10.2.0 56 57 devDependencies: 58 '@atproto/lex-cli': ··· 82 supertest: 83 specifier: ^7.0.0 84 version: 7.0.0 85 tsup: 86 specifier: ^8.0.2 87 version: 8.2.4(tsx@4.16.5)(typescript@5.5.4) ··· 96 version: 4.3.2(typescript@5.5.4) 97 vitest: 98 specifier: ^2.0.0 99 - version: 2.0.5 100 101 packages: 102 ··· 338 requiresBuild: true 339 dev: false 340 optional: true 341 342 /@esbuild/aix-ppc64@0.21.5: 343 resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} ··· 819 '@jridgewell/sourcemap-codec': 1.5.0 820 dev: true 821 822 /@noble/curves@1.4.2: 823 resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} 824 dependencies: ··· 858 dev: true 859 optional: true 860 861 /@rollup/rollup-android-arm-eabi@4.20.0: 862 resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==} 863 cpu: [arm] ··· 995 path-browserify: 1.0.1 996 dev: true 997 998 /@types/better-sqlite3@7.6.11: 999 resolution: {integrity: sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==} 1000 dependencies: ··· 1124 tinyrainbow: 1.2.0 1125 dev: true 1126 1127 /abort-controller@3.0.0: 1128 resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} 1129 engines: {node: '>=6.5'} ··· 1137 mime-types: 2.1.35 1138 negotiator: 0.6.3 1139 dev: false 1140 1141 /ansi-escapes@7.0.0: 1142 resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} ··· 1177 dependencies: 1178 normalize-path: 3.0.0 1179 picomatch: 2.3.1 1180 dev: true 1181 1182 /array-flatten@1.1.1: ··· 1488 vary: 1.1.2 1489 dev: false 1490 1491 /cross-spawn@7.0.3: 1492 resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 1493 engines: {node: '>= 8'} ··· 1496 shebang-command: 2.0.0 1497 which: 2.0.2 1498 dev: true 1499 1500 /dateformat@4.6.3: 1501 resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} ··· 1576 wrappy: 1.0.2 1577 dev: true 1578 1579 /dir-glob@3.0.1: 1580 resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 1581 engines: {node: '>=8'} ··· 1583 path-type: 4.0.0 1584 dev: true 1585 1586 /dotenv@16.4.5: 1587 resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} 1588 engines: {node: '>=12'} ··· 1617 resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} 1618 dependencies: 1619 once: 1.4.0 1620 1621 /envalid@8.0.0: 1622 resolution: {integrity: sha512-PGeYJnJB5naN0ME6SH8nFcDj9HVbLpYIfg1p5lAyM9T4cH2lwtu2fLbozC/bq+HUUOIFxhX/LP0/GmlqPHT4tQ==} ··· 1918 1919 /function-bind@1.1.2: 1920 resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 1921 1922 /get-caller-file@2.0.5: 1923 resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} ··· 2044 engines: {node: '>=8'} 2045 dev: true 2046 2047 /http-errors@2.0.0: 2048 resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} 2049 engines: {node: '>= 0.8'} ··· 2247 resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} 2248 dependencies: 2249 '@jridgewell/sourcemap-codec': 1.5.0 2250 dev: true 2251 2252 /media-typer@0.3.0: ··· 3245 code-block-writer: 11.0.3 3246 dev: true 3247 3248 /tsconfck@3.1.1(typescript@5.5.4): 3249 resolution: {integrity: sha512-00eoI6WY57SvZEVjm13stEVE90VkEdJAFGgpFLTsZbJyW/LwFQ7uQxJHWpZ2hzSWgCPKc9AnBnNP+0X7o3hAmQ==} 3250 engines: {node: ^18 || >=20} ··· 3336 hasBin: true 3337 dev: true 3338 3339 /uint8arrays@3.0.0: 3340 resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==} 3341 dependencies: ··· 3359 engines: {node: '>= 0.4.0'} 3360 dev: false 3361 3362 /varint@6.0.0: 3363 resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} 3364 dev: false ··· 3368 engines: {node: '>= 0.8'} 3369 dev: false 3370 3371 - /vite-node@2.0.5: 3372 resolution: {integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==} 3373 engines: {node: ^18.0.0 || >=20.0.0} 3374 hasBin: true ··· 3377 debug: 4.3.6 3378 pathe: 1.1.2 3379 tinyrainbow: 1.2.0 3380 - vite: 5.3.5 3381 transitivePeerDependencies: 3382 - '@types/node' 3383 - less ··· 3405 - typescript 3406 dev: true 3407 3408 - /vite@5.3.5: 3409 resolution: {integrity: sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==} 3410 engines: {node: ^18.0.0 || >=20.0.0} 3411 hasBin: true ··· 3433 terser: 3434 optional: true 3435 dependencies: 3436 esbuild: 0.21.5 3437 postcss: 8.4.41 3438 rollup: 4.20.0 ··· 3440 fsevents: 2.3.3 3441 dev: true 3442 3443 - /vitest@2.0.5: 3444 resolution: {integrity: sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==} 3445 engines: {node: ^18.0.0 || >=20.0.0} 3446 hasBin: true ··· 3466 optional: true 3467 dependencies: 3468 '@ampproject/remapping': 2.3.0 3469 '@vitest/expect': 2.0.5 3470 '@vitest/pretty-format': 2.0.5 3471 '@vitest/runner': 2.0.5 ··· 3481 tinybench: 2.9.0 3482 tinypool: 1.0.0 3483 tinyrainbow: 1.2.0 3484 - vite: 5.3.5 3485 - vite-node: 2.0.5 3486 why-is-node-running: 2.3.0 3487 transitivePeerDependencies: 3488 - less ··· 3574 3575 /yesno@0.4.0: 3576 resolution: {integrity: sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA==} 3577 dev: true 3578 3579 /zod@3.23.8:
··· 53 pino-http: 54 specifier: ^10.0.0 55 version: 10.2.0 56 + uhtml: 57 + specifier: ^4.5.9 58 + version: 4.5.9 59 60 devDependencies: 61 '@atproto/lex-cli': ··· 85 supertest: 86 specifier: ^7.0.0 87 version: 7.0.0 88 + ts-node: 89 + specifier: ^10.9.2 90 + version: 10.9.2(@types/node@22.1.0)(typescript@5.5.4) 91 tsup: 92 specifier: ^8.0.2 93 version: 8.2.4(tsx@4.16.5)(typescript@5.5.4) ··· 102 version: 4.3.2(typescript@5.5.4) 103 vitest: 104 specifier: ^2.0.0 105 + version: 2.0.5(@types/node@22.1.0) 106 107 packages: 108 ··· 344 requiresBuild: true 345 dev: false 346 optional: true 347 + 348 + /@cspotcode/source-map-support@0.8.1: 349 + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} 350 + engines: {node: '>=12'} 351 + dependencies: 352 + '@jridgewell/trace-mapping': 0.3.9 353 + dev: true 354 355 /@esbuild/aix-ppc64@0.21.5: 356 resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} ··· 832 '@jridgewell/sourcemap-codec': 1.5.0 833 dev: true 834 835 + /@jridgewell/trace-mapping@0.3.9: 836 + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} 837 + dependencies: 838 + '@jridgewell/resolve-uri': 3.1.2 839 + '@jridgewell/sourcemap-codec': 1.5.0 840 + dev: true 841 + 842 /@noble/curves@1.4.2: 843 resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} 844 dependencies: ··· 878 dev: true 879 optional: true 880 881 + /@preact/signals-core@1.8.0: 882 + resolution: {integrity: sha512-OBvUsRZqNmjzCZXWLxkZfhcgT+Fk8DDcT/8vD6a1xhDemodyy87UJRJfASMuSD8FaAIeGgGm85ydXhm7lr4fyA==} 883 + requiresBuild: true 884 + dev: false 885 + optional: true 886 + 887 /@rollup/rollup-android-arm-eabi@4.20.0: 888 resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==} 889 cpu: [arm] ··· 1021 path-browserify: 1.0.1 1022 dev: true 1023 1024 + /@tsconfig/node10@1.0.11: 1025 + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} 1026 + dev: true 1027 + 1028 + /@tsconfig/node12@1.0.11: 1029 + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} 1030 + dev: true 1031 + 1032 + /@tsconfig/node14@1.0.3: 1033 + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} 1034 + dev: true 1035 + 1036 + /@tsconfig/node16@1.0.4: 1037 + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} 1038 + dev: true 1039 + 1040 /@types/better-sqlite3@7.6.11: 1041 resolution: {integrity: sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==} 1042 dependencies: ··· 1166 tinyrainbow: 1.2.0 1167 dev: true 1168 1169 + /@webreflection/signal@2.1.2: 1170 + resolution: {integrity: sha512-0dW0fstQQkIt588JwhDiPS4xgeeQcQnBHn6MVInrBzmFlnLtzoSJL9G7JqdAlZVVi19tfb8R1QisZIT31cgiug==} 1171 + requiresBuild: true 1172 + dev: false 1173 + optional: true 1174 + 1175 + /@webreflection/uparser@0.3.3: 1176 + resolution: {integrity: sha512-XxGfo8jr2eVuvP5lrmwjgMAM7QjtZ0ngFD+dd9Fd3GStcEb4QhLlTiqZYF5O3l5k4sU/V6ZiPrVCzCWXWFEmCw==} 1177 + dependencies: 1178 + domconstants: 1.1.6 1179 + dev: false 1180 + 1181 /abort-controller@3.0.0: 1182 resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} 1183 engines: {node: '>=6.5'} ··· 1191 mime-types: 2.1.35 1192 negotiator: 0.6.3 1193 dev: false 1194 + 1195 + /acorn-walk@8.3.3: 1196 + resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} 1197 + engines: {node: '>=0.4.0'} 1198 + dependencies: 1199 + acorn: 8.12.1 1200 + dev: true 1201 + 1202 + /acorn@8.12.1: 1203 + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} 1204 + engines: {node: '>=0.4.0'} 1205 + hasBin: true 1206 + dev: true 1207 1208 /ansi-escapes@7.0.0: 1209 resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} ··· 1244 dependencies: 1245 normalize-path: 3.0.0 1246 picomatch: 2.3.1 1247 + dev: true 1248 + 1249 + /arg@4.1.3: 1250 + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} 1251 dev: true 1252 1253 /array-flatten@1.1.1: ··· 1559 vary: 1.1.2 1560 dev: false 1561 1562 + /create-require@1.1.1: 1563 + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} 1564 + dev: true 1565 + 1566 /cross-spawn@7.0.3: 1567 resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 1568 engines: {node: '>= 8'} ··· 1571 shebang-command: 2.0.0 1572 which: 2.0.2 1573 dev: true 1574 + 1575 + /custom-function@1.0.6: 1576 + resolution: {integrity: sha512-styyvwOki/EYr+VBe7/m9xAjq6uKx87SpDKIpFRdTQnofBDSZpBEFc9qJLmaJihjjTeEpAIJ+nz+9fUXj+BPNQ==} 1577 + dev: false 1578 1579 /dateformat@4.6.3: 1580 resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} ··· 1655 wrappy: 1.0.2 1656 dev: true 1657 1658 + /diff@4.0.2: 1659 + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} 1660 + engines: {node: '>=0.3.1'} 1661 + dev: true 1662 + 1663 /dir-glob@3.0.1: 1664 resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 1665 engines: {node: '>=8'} ··· 1667 path-type: 4.0.0 1668 dev: true 1669 1670 + /dom-serializer@2.0.0: 1671 + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} 1672 + dependencies: 1673 + domelementtype: 2.3.0 1674 + domhandler: 5.0.3 1675 + entities: 4.5.0 1676 + dev: false 1677 + 1678 + /domconstants@1.1.6: 1679 + resolution: {integrity: sha512-CuaDrThJ4VM+LyZ4ax8n52k0KbLJZtffyGkuj1WhpTRRcSfcy/9DfOBa68jenhX96oNUTunblSJEUNC4baFdmQ==} 1680 + dev: false 1681 + 1682 + /domelementtype@2.3.0: 1683 + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} 1684 + dev: false 1685 + 1686 + /domhandler@5.0.3: 1687 + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} 1688 + engines: {node: '>= 4'} 1689 + dependencies: 1690 + domelementtype: 2.3.0 1691 + dev: false 1692 + 1693 + /domutils@3.1.0: 1694 + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} 1695 + dependencies: 1696 + dom-serializer: 2.0.0 1697 + domelementtype: 2.3.0 1698 + domhandler: 5.0.3 1699 + dev: false 1700 + 1701 /dotenv@16.4.5: 1702 resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} 1703 engines: {node: '>=12'} ··· 1732 resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} 1733 dependencies: 1734 once: 1.4.0 1735 + 1736 + /entities@4.5.0: 1737 + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} 1738 + engines: {node: '>=0.12'} 1739 + dev: false 1740 1741 /envalid@8.0.0: 1742 resolution: {integrity: sha512-PGeYJnJB5naN0ME6SH8nFcDj9HVbLpYIfg1p5lAyM9T4cH2lwtu2fLbozC/bq+HUUOIFxhX/LP0/GmlqPHT4tQ==} ··· 2038 2039 /function-bind@1.1.2: 2040 resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 2041 + 2042 + /gc-hook@0.3.1: 2043 + resolution: {integrity: sha512-E5M+O/h2o7eZzGhzRZGex6hbB3k4NWqO0eA+OzLRLXxhdbYPajZnynPwAtphnh+cRHPwsj5Z80dqZlfI4eK55A==} 2044 + dev: false 2045 2046 /get-caller-file@2.0.5: 2047 resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} ··· 2168 engines: {node: '>=8'} 2169 dev: true 2170 2171 + /html-escaper@3.0.3: 2172 + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} 2173 + dev: false 2174 + 2175 + /htmlparser2@9.1.0: 2176 + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} 2177 + dependencies: 2178 + domelementtype: 2.3.0 2179 + domhandler: 5.0.3 2180 + domutils: 3.1.0 2181 + entities: 4.5.0 2182 + dev: false 2183 + 2184 /http-errors@2.0.0: 2185 resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} 2186 engines: {node: '>= 0.8'} ··· 2384 resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} 2385 dependencies: 2386 '@jridgewell/sourcemap-codec': 1.5.0 2387 + dev: true 2388 + 2389 + /make-error@1.3.6: 2390 + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} 2391 dev: true 2392 2393 /media-typer@0.3.0: ··· 3386 code-block-writer: 11.0.3 3387 dev: true 3388 3389 + /ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4): 3390 + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} 3391 + hasBin: true 3392 + peerDependencies: 3393 + '@swc/core': '>=1.2.50' 3394 + '@swc/wasm': '>=1.2.50' 3395 + '@types/node': '*' 3396 + typescript: '>=2.7' 3397 + peerDependenciesMeta: 3398 + '@swc/core': 3399 + optional: true 3400 + '@swc/wasm': 3401 + optional: true 3402 + dependencies: 3403 + '@cspotcode/source-map-support': 0.8.1 3404 + '@tsconfig/node10': 1.0.11 3405 + '@tsconfig/node12': 1.0.11 3406 + '@tsconfig/node14': 1.0.3 3407 + '@tsconfig/node16': 1.0.4 3408 + '@types/node': 22.1.0 3409 + acorn: 8.12.1 3410 + acorn-walk: 8.3.3 3411 + arg: 4.1.3 3412 + create-require: 1.1.1 3413 + diff: 4.0.2 3414 + make-error: 1.3.6 3415 + typescript: 5.5.4 3416 + v8-compile-cache-lib: 3.0.1 3417 + yn: 3.1.1 3418 + dev: true 3419 + 3420 /tsconfck@3.1.1(typescript@5.5.4): 3421 resolution: {integrity: sha512-00eoI6WY57SvZEVjm13stEVE90VkEdJAFGgpFLTsZbJyW/LwFQ7uQxJHWpZ2hzSWgCPKc9AnBnNP+0X7o3hAmQ==} 3422 engines: {node: ^18 || >=20} ··· 3508 hasBin: true 3509 dev: true 3510 3511 + /udomdiff@1.1.0: 3512 + resolution: {integrity: sha512-aqjTs5x/wsShZBkVagdafJkP8S3UMGhkHKszsu1cszjjZ7iOp86+Qb3QOFYh01oWjPMy5ZTuxD6hw5uTKxd+VA==} 3513 + dev: false 3514 + 3515 + /uhtml@4.5.9: 3516 + resolution: {integrity: sha512-WAfIK/E3ZJpaFl0MSzGSB54r7I8Vc8ZyUlOsN8GnLnEaxuioOUyKAS6q/N/xQ5GD9vFFBnx6q+3N3Eq9KNCvTQ==} 3517 + dependencies: 3518 + '@webreflection/uparser': 0.3.3 3519 + custom-function: 1.0.6 3520 + domconstants: 1.1.6 3521 + gc-hook: 0.3.1 3522 + html-escaper: 3.0.3 3523 + htmlparser2: 9.1.0 3524 + udomdiff: 1.1.0 3525 + optionalDependencies: 3526 + '@preact/signals-core': 1.8.0 3527 + '@webreflection/signal': 2.1.2 3528 + dev: false 3529 + 3530 /uint8arrays@3.0.0: 3531 resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==} 3532 dependencies: ··· 3550 engines: {node: '>= 0.4.0'} 3551 dev: false 3552 3553 + /v8-compile-cache-lib@3.0.1: 3554 + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} 3555 + dev: true 3556 + 3557 /varint@6.0.0: 3558 resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} 3559 dev: false ··· 3563 engines: {node: '>= 0.8'} 3564 dev: false 3565 3566 + /vite-node@2.0.5(@types/node@22.1.0): 3567 resolution: {integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==} 3568 engines: {node: ^18.0.0 || >=20.0.0} 3569 hasBin: true ··· 3572 debug: 4.3.6 3573 pathe: 1.1.2 3574 tinyrainbow: 1.2.0 3575 + vite: 5.3.5(@types/node@22.1.0) 3576 transitivePeerDependencies: 3577 - '@types/node' 3578 - less ··· 3600 - typescript 3601 dev: true 3602 3603 + /vite@5.3.5(@types/node@22.1.0): 3604 resolution: {integrity: sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==} 3605 engines: {node: ^18.0.0 || >=20.0.0} 3606 hasBin: true ··· 3628 terser: 3629 optional: true 3630 dependencies: 3631 + '@types/node': 22.1.0 3632 esbuild: 0.21.5 3633 postcss: 8.4.41 3634 rollup: 4.20.0 ··· 3636 fsevents: 2.3.3 3637 dev: true 3638 3639 + /vitest@2.0.5(@types/node@22.1.0): 3640 resolution: {integrity: sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==} 3641 engines: {node: ^18.0.0 || >=20.0.0} 3642 hasBin: true ··· 3662 optional: true 3663 dependencies: 3664 '@ampproject/remapping': 2.3.0 3665 + '@types/node': 22.1.0 3666 '@vitest/expect': 2.0.5 3667 '@vitest/pretty-format': 2.0.5 3668 '@vitest/runner': 2.0.5 ··· 3678 tinybench: 2.9.0 3679 tinypool: 1.0.0 3680 tinyrainbow: 1.2.0 3681 + vite: 5.3.5(@types/node@22.1.0) 3682 + vite-node: 2.0.5(@types/node@22.1.0) 3683 why-is-node-running: 2.3.0 3684 transitivePeerDependencies: 3685 - less ··· 3771 3772 /yesno@0.4.0: 3773 resolution: {integrity: sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA==} 3774 + dev: true 3775 + 3776 + /yn@3.1.1: 3777 + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} 3778 + engines: {node: '>=6'} 3779 dev: true 3780 3781 /zod@3.23.8:
+2 -1
src/firehose/ingester.ts
··· 1 - import type { Database } from '#/db' 2 import { Firehose } from '#/firehose/firehose' 3 4 export class Ingester { ··· 19 text: post.text as string, 20 indexedAt: new Date().toISOString(), 21 }) 22 .execute() 23 } 24 }
··· 1 + import type { Database } from '#/db/index' 2 import { Firehose } from '#/firehose/firehose' 3 4 export class Ingester { ··· 19 text: post.text as string, 20 indexedAt: new Date().toISOString(), 21 }) 22 + .onConflict((oc) => oc.doNothing()) 23 .execute() 24 } 25 }
+32
src/pages/home.ts
···
··· 1 + import { AtUri } from '@atproto/syntax' 2 + import type { Post } from '#/db/schema' 3 + import { html } from '../view' 4 + import { shell } from './shell' 5 + 6 + export function home(posts: Post[]) { 7 + return shell({ 8 + title: 'Home', 9 + content: content(posts), 10 + }) 11 + } 12 + 13 + function content(posts: Post[]) { 14 + return html`<div> 15 + <h1>Welcome to My Page</h1> 16 + <p>It's pretty special here.</p> 17 + <ul> 18 + ${posts.map((post) => { 19 + return html`<li> 20 + <a href="${toBskyLink(post.uri)}" target="_blank">🔗</a> 21 + ${post.text} 22 + </li>` 23 + })} 24 + </ul> 25 + <a href="/">Give me more</a> 26 + </div>` 27 + } 28 + 29 + function toBskyLink(uriStr: string) { 30 + const uri = new AtUri(uriStr) 31 + return `https://bsky.app/profile/${uri.host}/post/${uri.rkey}` 32 + }
+12
src/pages/shell.ts
···
··· 1 + import { type Hole, html } from '../view' 2 + 3 + export function shell({ title, content }: { title: string; content: Hole }) { 4 + return html`<html> 5 + <head> 6 + <title>${title}</title> 7 + </head> 8 + <body> 9 + ${content} 10 + </body> 11 + </html>` 12 + }
+3 -2
src/routes/index.ts
··· 1 import express from 'express' 2 import type { AppContext } from '#/config' 3 import { handler } from './util' 4 5 export const createRouter = (ctx: AppContext) => { ··· 9 '/', 10 handler(async (req, res) => { 11 const posts = await ctx.db.selectFrom('post').selectAll().orderBy('indexedAt', 'desc').limit(10).execute() 12 - const postTexts = posts.map((row) => row.text) 13 - res.json(postTexts) 14 }), 15 ) 16
··· 1 import express from 'express' 2 import type { AppContext } from '#/config' 3 + import { home } from '#/pages/home' 4 + import { page } from '#/view' 5 import { handler } from './util' 6 7 export const createRouter = (ctx: AppContext) => { ··· 11 '/', 12 handler(async (req, res) => { 13 const posts = await ctx.db.selectFrom('post').selectAll().orderBy('indexedAt', 'desc').limit(10).execute() 14 + return res.type('html').send(page(home(posts))) 15 }), 16 ) 17
+12
src/view.ts
···
··· 1 + // @ts-ignore 2 + import ssr from 'uhtml/ssr' 3 + import type initSSR from 'uhtml/types/init-ssr' 4 + import type { Hole } from 'uhtml/types/keyed' 5 + 6 + export type { Hole } 7 + 8 + export const { html }: ReturnType<typeof initSSR> = ssr() 9 + 10 + export function page(hole: Hole) { 11 + return `<!DOCTYPE html>\n${hole.toDOM().toString()}` 12 + }
+1 -1
tsconfig.json
··· 6 "paths": { 7 "#/*": ["src/*"] 8 }, 9 - "moduleResolution": "Node", 10 "outDir": "dist", 11 "importsNotUsedAsValues": "remove", 12 "strict": true,
··· 6 "paths": { 7 "#/*": ["src/*"] 8 }, 9 + "moduleResolution": "Node10", 10 "outDir": "dist", 11 "importsNotUsedAsValues": "remove", 12 "strict": true,