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

setup basic html views

+276 -20
+5 -9
package.json
··· 33 33 "kysely": "^0.27.4", 34 34 "multiformats": "^9.9.0", 35 35 "pino": "^9.3.2", 36 - "pino-http": "^10.0.0" 36 + "pino-http": "^10.0.0", 37 + "uhtml": "^4.5.9" 37 38 }, 38 39 "devDependencies": { 39 40 "@atproto/lex-cli": "^0.4.1", ··· 45 46 "pino-pretty": "^11.0.0", 46 47 "rimraf": "^5.0.0", 47 48 "supertest": "^7.0.0", 49 + "ts-node": "^10.9.2", 48 50 "tsup": "^8.0.2", 49 51 "tsx": "^4.7.2", 50 52 "typescript": "^5.4.4", ··· 52 54 "vitest": "^2.0.0" 53 55 }, 54 56 "lint-staged": { 55 - "*.{js,ts,cjs,mjs,d.cts,d.mts,json,jsonc}": [ 56 - "biome check --apply --no-errors-on-unmatched" 57 - ] 57 + "*.{js,ts,cjs,mjs,d.cts,d.mts,json,jsonc}": ["biome check --apply --no-errors-on-unmatched"] 58 58 }, 59 59 "tsup": { 60 - "entry": [ 61 - "src", 62 - "!src/**/__tests__/**", 63 - "!src/**/*.test.*" 64 - ], 60 + "entry": ["src", "!src/**/__tests__/**", "!src/**/*.test.*"], 65 61 "splitting": false, 66 62 "sourcemap": true, 67 63 "clean": true
+209 -7
pnpm-lock.yaml
··· 53 53 pino-http: 54 54 specifier: ^10.0.0 55 55 version: 10.2.0 56 + uhtml: 57 + specifier: ^4.5.9 58 + version: 4.5.9 56 59 57 60 devDependencies: 58 61 '@atproto/lex-cli': ··· 82 85 supertest: 83 86 specifier: ^7.0.0 84 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) 85 91 tsup: 86 92 specifier: ^8.0.2 87 93 version: 8.2.4(tsx@4.16.5)(typescript@5.5.4) ··· 96 102 version: 4.3.2(typescript@5.5.4) 97 103 vitest: 98 104 specifier: ^2.0.0 99 - version: 2.0.5 105 + version: 2.0.5(@types/node@22.1.0) 100 106 101 107 packages: 102 108 ··· 338 344 requiresBuild: true 339 345 dev: false 340 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 341 354 342 355 /@esbuild/aix-ppc64@0.21.5: 343 356 resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} ··· 819 832 '@jridgewell/sourcemap-codec': 1.5.0 820 833 dev: true 821 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 + 822 842 /@noble/curves@1.4.2: 823 843 resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} 824 844 dependencies: ··· 858 878 dev: true 859 879 optional: true 860 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 + 861 887 /@rollup/rollup-android-arm-eabi@4.20.0: 862 888 resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==} 863 889 cpu: [arm] ··· 995 1021 path-browserify: 1.0.1 996 1022 dev: true 997 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 + 998 1040 /@types/better-sqlite3@7.6.11: 999 1041 resolution: {integrity: sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==} 1000 1042 dependencies: ··· 1124 1166 tinyrainbow: 1.2.0 1125 1167 dev: true 1126 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 + 1127 1181 /abort-controller@3.0.0: 1128 1182 resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} 1129 1183 engines: {node: '>=6.5'} ··· 1137 1191 mime-types: 2.1.35 1138 1192 negotiator: 0.6.3 1139 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 1140 1207 1141 1208 /ansi-escapes@7.0.0: 1142 1209 resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} ··· 1177 1244 dependencies: 1178 1245 normalize-path: 3.0.0 1179 1246 picomatch: 2.3.1 1247 + dev: true 1248 + 1249 + /arg@4.1.3: 1250 + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} 1180 1251 dev: true 1181 1252 1182 1253 /array-flatten@1.1.1: ··· 1488 1559 vary: 1.1.2 1489 1560 dev: false 1490 1561 1562 + /create-require@1.1.1: 1563 + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} 1564 + dev: true 1565 + 1491 1566 /cross-spawn@7.0.3: 1492 1567 resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 1493 1568 engines: {node: '>= 8'} ··· 1496 1571 shebang-command: 2.0.0 1497 1572 which: 2.0.2 1498 1573 dev: true 1574 + 1575 + /custom-function@1.0.6: 1576 + resolution: {integrity: sha512-styyvwOki/EYr+VBe7/m9xAjq6uKx87SpDKIpFRdTQnofBDSZpBEFc9qJLmaJihjjTeEpAIJ+nz+9fUXj+BPNQ==} 1577 + dev: false 1499 1578 1500 1579 /dateformat@4.6.3: 1501 1580 resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} ··· 1576 1655 wrappy: 1.0.2 1577 1656 dev: true 1578 1657 1658 + /diff@4.0.2: 1659 + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} 1660 + engines: {node: '>=0.3.1'} 1661 + dev: true 1662 + 1579 1663 /dir-glob@3.0.1: 1580 1664 resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 1581 1665 engines: {node: '>=8'} ··· 1583 1667 path-type: 4.0.0 1584 1668 dev: true 1585 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 + 1586 1701 /dotenv@16.4.5: 1587 1702 resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} 1588 1703 engines: {node: '>=12'} ··· 1617 1732 resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} 1618 1733 dependencies: 1619 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 1620 1740 1621 1741 /envalid@8.0.0: 1622 1742 resolution: {integrity: sha512-PGeYJnJB5naN0ME6SH8nFcDj9HVbLpYIfg1p5lAyM9T4cH2lwtu2fLbozC/bq+HUUOIFxhX/LP0/GmlqPHT4tQ==} ··· 1918 2038 1919 2039 /function-bind@1.1.2: 1920 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 1921 2045 1922 2046 /get-caller-file@2.0.5: 1923 2047 resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} ··· 2044 2168 engines: {node: '>=8'} 2045 2169 dev: true 2046 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 + 2047 2184 /http-errors@2.0.0: 2048 2185 resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} 2049 2186 engines: {node: '>= 0.8'} ··· 2247 2384 resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} 2248 2385 dependencies: 2249 2386 '@jridgewell/sourcemap-codec': 1.5.0 2387 + dev: true 2388 + 2389 + /make-error@1.3.6: 2390 + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} 2250 2391 dev: true 2251 2392 2252 2393 /media-typer@0.3.0: ··· 3245 3386 code-block-writer: 11.0.3 3246 3387 dev: true 3247 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 + 3248 3420 /tsconfck@3.1.1(typescript@5.5.4): 3249 3421 resolution: {integrity: sha512-00eoI6WY57SvZEVjm13stEVE90VkEdJAFGgpFLTsZbJyW/LwFQ7uQxJHWpZ2hzSWgCPKc9AnBnNP+0X7o3hAmQ==} 3250 3422 engines: {node: ^18 || >=20} ··· 3336 3508 hasBin: true 3337 3509 dev: true 3338 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 + 3339 3530 /uint8arrays@3.0.0: 3340 3531 resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==} 3341 3532 dependencies: ··· 3359 3550 engines: {node: '>= 0.4.0'} 3360 3551 dev: false 3361 3552 3553 + /v8-compile-cache-lib@3.0.1: 3554 + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} 3555 + dev: true 3556 + 3362 3557 /varint@6.0.0: 3363 3558 resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} 3364 3559 dev: false ··· 3368 3563 engines: {node: '>= 0.8'} 3369 3564 dev: false 3370 3565 3371 - /vite-node@2.0.5: 3566 + /vite-node@2.0.5(@types/node@22.1.0): 3372 3567 resolution: {integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==} 3373 3568 engines: {node: ^18.0.0 || >=20.0.0} 3374 3569 hasBin: true ··· 3377 3572 debug: 4.3.6 3378 3573 pathe: 1.1.2 3379 3574 tinyrainbow: 1.2.0 3380 - vite: 5.3.5 3575 + vite: 5.3.5(@types/node@22.1.0) 3381 3576 transitivePeerDependencies: 3382 3577 - '@types/node' 3383 3578 - less ··· 3405 3600 - typescript 3406 3601 dev: true 3407 3602 3408 - /vite@5.3.5: 3603 + /vite@5.3.5(@types/node@22.1.0): 3409 3604 resolution: {integrity: sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==} 3410 3605 engines: {node: ^18.0.0 || >=20.0.0} 3411 3606 hasBin: true ··· 3433 3628 terser: 3434 3629 optional: true 3435 3630 dependencies: 3631 + '@types/node': 22.1.0 3436 3632 esbuild: 0.21.5 3437 3633 postcss: 8.4.41 3438 3634 rollup: 4.20.0 ··· 3440 3636 fsevents: 2.3.3 3441 3637 dev: true 3442 3638 3443 - /vitest@2.0.5: 3639 + /vitest@2.0.5(@types/node@22.1.0): 3444 3640 resolution: {integrity: sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==} 3445 3641 engines: {node: ^18.0.0 || >=20.0.0} 3446 3642 hasBin: true ··· 3466 3662 optional: true 3467 3663 dependencies: 3468 3664 '@ampproject/remapping': 2.3.0 3665 + '@types/node': 22.1.0 3469 3666 '@vitest/expect': 2.0.5 3470 3667 '@vitest/pretty-format': 2.0.5 3471 3668 '@vitest/runner': 2.0.5 ··· 3481 3678 tinybench: 2.9.0 3482 3679 tinypool: 1.0.0 3483 3680 tinyrainbow: 1.2.0 3484 - vite: 5.3.5 3485 - vite-node: 2.0.5 3681 + vite: 5.3.5(@types/node@22.1.0) 3682 + vite-node: 2.0.5(@types/node@22.1.0) 3486 3683 why-is-node-running: 2.3.0 3487 3684 transitivePeerDependencies: 3488 3685 - less ··· 3574 3771 3575 3772 /yesno@0.4.0: 3576 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'} 3577 3779 dev: true 3578 3780 3579 3781 /zod@3.23.8:
+2 -1
src/firehose/ingester.ts
··· 1 - import type { Database } from '#/db' 1 + import type { Database } from '#/db/index' 2 2 import { Firehose } from '#/firehose/firehose' 3 3 4 4 export class Ingester { ··· 19 19 text: post.text as string, 20 20 indexedAt: new Date().toISOString(), 21 21 }) 22 + .onConflict((oc) => oc.doNothing()) 22 23 .execute() 23 24 } 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 1 import express from 'express' 2 2 import type { AppContext } from '#/config' 3 + import { home } from '#/pages/home' 4 + import { page } from '#/view' 3 5 import { handler } from './util' 4 6 5 7 export const createRouter = (ctx: AppContext) => { ··· 9 11 '/', 10 12 handler(async (req, res) => { 11 13 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 + return res.type('html').send(page(home(posts))) 14 15 }), 15 16 ) 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 6 "paths": { 7 7 "#/*": ["src/*"] 8 8 }, 9 - "moduleResolution": "Node", 9 + "moduleResolution": "Node10", 10 10 "outDir": "dist", 11 11 "importsNotUsedAsValues": "remove", 12 12 "strict": true,