A repo for my personal website

Blog item stuff done, now I need to import my blog posts; I also need to get the code to sort them by createdAt

+580 -5
+564 -1
package-lock.json
··· 9 9 "version": "1.0.0", 10 10 "license": "MIT", 11 11 "dependencies": { 12 - "crypto-js": "^4.2.0" 12 + "@ts-stack/markdown": "^1.5.0", 13 + "crypto-js": "^4.2.0", 14 + "dompurify": "^3.2.6", 15 + "jsdom": "^26.1.0", 16 + "marked": "^16.2.0" 13 17 }, 14 18 "devDependencies": { 15 19 "@types/crypto-js": "^4.2.2", 20 + "@types/marked": "^5.0.2", 21 + "@types/node": "^24.3.0", 16 22 "netlify-cli": "^23.3.1", 17 23 "npm": "^11.5.2", 18 24 "typescript": "^4.1.3" 19 25 } 20 26 }, 27 + "node_modules/@asamuzakjp/css-color": { 28 + "version": "3.2.0", 29 + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", 30 + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", 31 + "license": "MIT", 32 + "dependencies": { 33 + "@csstools/css-calc": "^2.1.3", 34 + "@csstools/css-color-parser": "^3.0.9", 35 + "@csstools/css-parser-algorithms": "^3.0.4", 36 + "@csstools/css-tokenizer": "^3.0.3", 37 + "lru-cache": "^10.4.3" 38 + } 39 + }, 40 + "node_modules/@csstools/color-helpers": { 41 + "version": "5.1.0", 42 + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", 43 + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", 44 + "funding": [ 45 + { 46 + "type": "github", 47 + "url": "https://github.com/sponsors/csstools" 48 + }, 49 + { 50 + "type": "opencollective", 51 + "url": "https://opencollective.com/csstools" 52 + } 53 + ], 54 + "license": "MIT-0", 55 + "engines": { 56 + "node": ">=18" 57 + } 58 + }, 59 + "node_modules/@csstools/css-calc": { 60 + "version": "2.1.4", 61 + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", 62 + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", 63 + "funding": [ 64 + { 65 + "type": "github", 66 + "url": "https://github.com/sponsors/csstools" 67 + }, 68 + { 69 + "type": "opencollective", 70 + "url": "https://opencollective.com/csstools" 71 + } 72 + ], 73 + "license": "MIT", 74 + "engines": { 75 + "node": ">=18" 76 + }, 77 + "peerDependencies": { 78 + "@csstools/css-parser-algorithms": "^3.0.5", 79 + "@csstools/css-tokenizer": "^3.0.4" 80 + } 81 + }, 82 + "node_modules/@csstools/css-color-parser": { 83 + "version": "3.1.0", 84 + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", 85 + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", 86 + "funding": [ 87 + { 88 + "type": "github", 89 + "url": "https://github.com/sponsors/csstools" 90 + }, 91 + { 92 + "type": "opencollective", 93 + "url": "https://opencollective.com/csstools" 94 + } 95 + ], 96 + "license": "MIT", 97 + "dependencies": { 98 + "@csstools/color-helpers": "^5.1.0", 99 + "@csstools/css-calc": "^2.1.4" 100 + }, 101 + "engines": { 102 + "node": ">=18" 103 + }, 104 + "peerDependencies": { 105 + "@csstools/css-parser-algorithms": "^3.0.5", 106 + "@csstools/css-tokenizer": "^3.0.4" 107 + } 108 + }, 109 + "node_modules/@csstools/css-parser-algorithms": { 110 + "version": "3.0.5", 111 + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", 112 + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", 113 + "funding": [ 114 + { 115 + "type": "github", 116 + "url": "https://github.com/sponsors/csstools" 117 + }, 118 + { 119 + "type": "opencollective", 120 + "url": "https://opencollective.com/csstools" 121 + } 122 + ], 123 + "license": "MIT", 124 + "engines": { 125 + "node": ">=18" 126 + }, 127 + "peerDependencies": { 128 + "@csstools/css-tokenizer": "^3.0.4" 129 + } 130 + }, 131 + "node_modules/@csstools/css-tokenizer": { 132 + "version": "3.0.4", 133 + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", 134 + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", 135 + "funding": [ 136 + { 137 + "type": "github", 138 + "url": "https://github.com/sponsors/csstools" 139 + }, 140 + { 141 + "type": "opencollective", 142 + "url": "https://opencollective.com/csstools" 143 + } 144 + ], 145 + "license": "MIT", 146 + "engines": { 147 + "node": ">=18" 148 + } 149 + }, 150 + "node_modules/@ts-stack/markdown": { 151 + "version": "1.5.0", 152 + "resolved": "https://registry.npmjs.org/@ts-stack/markdown/-/markdown-1.5.0.tgz", 153 + "integrity": "sha512-ntVX2Kmb2jyTdH94plJohokvDVPvp6CwXHqsa9NVZTK8cOmHDCYNW0j6thIadUVRTStJhxhfdeovLd0owqDxLw==", 154 + "license": "MIT", 155 + "dependencies": { 156 + "tslib": "^2.3.0" 157 + } 158 + }, 21 159 "node_modules/@types/crypto-js": { 22 160 "version": "4.2.2", 23 161 "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", ··· 25 163 "dev": true, 26 164 "license": "MIT" 27 165 }, 166 + "node_modules/@types/marked": { 167 + "version": "5.0.2", 168 + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-5.0.2.tgz", 169 + "integrity": "sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg==", 170 + "dev": true, 171 + "license": "MIT" 172 + }, 173 + "node_modules/@types/node": { 174 + "version": "24.3.0", 175 + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", 176 + "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", 177 + "dev": true, 178 + "license": "MIT", 179 + "dependencies": { 180 + "undici-types": "~7.10.0" 181 + } 182 + }, 183 + "node_modules/@types/trusted-types": { 184 + "version": "2.0.7", 185 + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", 186 + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", 187 + "license": "MIT", 188 + "optional": true 189 + }, 190 + "node_modules/agent-base": { 191 + "version": "7.1.4", 192 + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", 193 + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", 194 + "license": "MIT", 195 + "engines": { 196 + "node": ">= 14" 197 + } 198 + }, 28 199 "node_modules/crypto-js": { 29 200 "version": "4.2.0", 30 201 "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", 31 202 "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", 203 + "license": "MIT" 204 + }, 205 + "node_modules/cssstyle": { 206 + "version": "4.6.0", 207 + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", 208 + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", 209 + "license": "MIT", 210 + "dependencies": { 211 + "@asamuzakjp/css-color": "^3.2.0", 212 + "rrweb-cssom": "^0.8.0" 213 + }, 214 + "engines": { 215 + "node": ">=18" 216 + } 217 + }, 218 + "node_modules/data-urls": { 219 + "version": "5.0.0", 220 + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", 221 + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", 222 + "license": "MIT", 223 + "dependencies": { 224 + "whatwg-mimetype": "^4.0.0", 225 + "whatwg-url": "^14.0.0" 226 + }, 227 + "engines": { 228 + "node": ">=18" 229 + } 230 + }, 231 + "node_modules/debug": { 232 + "version": "4.4.1", 233 + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", 234 + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", 235 + "license": "MIT", 236 + "dependencies": { 237 + "ms": "^2.1.3" 238 + }, 239 + "engines": { 240 + "node": ">=6.0" 241 + }, 242 + "peerDependenciesMeta": { 243 + "supports-color": { 244 + "optional": true 245 + } 246 + } 247 + }, 248 + "node_modules/decimal.js": { 249 + "version": "10.6.0", 250 + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", 251 + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", 252 + "license": "MIT" 253 + }, 254 + "node_modules/dompurify": { 255 + "version": "3.2.6", 256 + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz", 257 + "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", 258 + "license": "(MPL-2.0 OR Apache-2.0)", 259 + "optionalDependencies": { 260 + "@types/trusted-types": "^2.0.7" 261 + } 262 + }, 263 + "node_modules/entities": { 264 + "version": "6.0.1", 265 + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", 266 + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", 267 + "license": "BSD-2-Clause", 268 + "engines": { 269 + "node": ">=0.12" 270 + }, 271 + "funding": { 272 + "url": "https://github.com/fb55/entities?sponsor=1" 273 + } 274 + }, 275 + "node_modules/html-encoding-sniffer": { 276 + "version": "4.0.0", 277 + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", 278 + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", 279 + "license": "MIT", 280 + "dependencies": { 281 + "whatwg-encoding": "^3.1.1" 282 + }, 283 + "engines": { 284 + "node": ">=18" 285 + } 286 + }, 287 + "node_modules/http-proxy-agent": { 288 + "version": "7.0.2", 289 + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", 290 + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", 291 + "license": "MIT", 292 + "dependencies": { 293 + "agent-base": "^7.1.0", 294 + "debug": "^4.3.4" 295 + }, 296 + "engines": { 297 + "node": ">= 14" 298 + } 299 + }, 300 + "node_modules/https-proxy-agent": { 301 + "version": "7.0.6", 302 + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", 303 + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", 304 + "license": "MIT", 305 + "dependencies": { 306 + "agent-base": "^7.1.2", 307 + "debug": "4" 308 + }, 309 + "engines": { 310 + "node": ">= 14" 311 + } 312 + }, 313 + "node_modules/iconv-lite": { 314 + "version": "0.6.3", 315 + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 316 + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 317 + "license": "MIT", 318 + "dependencies": { 319 + "safer-buffer": ">= 2.1.2 < 3.0.0" 320 + }, 321 + "engines": { 322 + "node": ">=0.10.0" 323 + } 324 + }, 325 + "node_modules/is-potential-custom-element-name": { 326 + "version": "1.0.1", 327 + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", 328 + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", 329 + "license": "MIT" 330 + }, 331 + "node_modules/jsdom": { 332 + "version": "26.1.0", 333 + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", 334 + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", 335 + "license": "MIT", 336 + "dependencies": { 337 + "cssstyle": "^4.2.1", 338 + "data-urls": "^5.0.0", 339 + "decimal.js": "^10.5.0", 340 + "html-encoding-sniffer": "^4.0.0", 341 + "http-proxy-agent": "^7.0.2", 342 + "https-proxy-agent": "^7.0.6", 343 + "is-potential-custom-element-name": "^1.0.1", 344 + "nwsapi": "^2.2.16", 345 + "parse5": "^7.2.1", 346 + "rrweb-cssom": "^0.8.0", 347 + "saxes": "^6.0.0", 348 + "symbol-tree": "^3.2.4", 349 + "tough-cookie": "^5.1.1", 350 + "w3c-xmlserializer": "^5.0.0", 351 + "webidl-conversions": "^7.0.0", 352 + "whatwg-encoding": "^3.1.1", 353 + "whatwg-mimetype": "^4.0.0", 354 + "whatwg-url": "^14.1.1", 355 + "ws": "^8.18.0", 356 + "xml-name-validator": "^5.0.0" 357 + }, 358 + "engines": { 359 + "node": ">=18" 360 + }, 361 + "peerDependencies": { 362 + "canvas": "^3.0.0" 363 + }, 364 + "peerDependenciesMeta": { 365 + "canvas": { 366 + "optional": true 367 + } 368 + } 369 + }, 370 + "node_modules/lru-cache": { 371 + "version": "10.4.3", 372 + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", 373 + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", 374 + "license": "ISC" 375 + }, 376 + "node_modules/marked": { 377 + "version": "16.2.0", 378 + "resolved": "https://registry.npmjs.org/marked/-/marked-16.2.0.tgz", 379 + "integrity": "sha512-LbbTuye+0dWRz2TS9KJ7wsnD4KAtpj0MVkWc90XvBa6AslXsT0hTBVH5k32pcSyHH1fst9XEFJunXHktVy0zlg==", 380 + "license": "MIT", 381 + "bin": { 382 + "marked": "bin/marked.js" 383 + }, 384 + "engines": { 385 + "node": ">= 20" 386 + } 387 + }, 388 + "node_modules/ms": { 389 + "version": "2.1.3", 390 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 391 + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 32 392 "license": "MIT" 33 393 }, 34 394 "node_modules/netlify-cli": { ··· 17351 17711 "inBundle": true, 17352 17712 "license": "ISC" 17353 17713 }, 17714 + "node_modules/nwsapi": { 17715 + "version": "2.2.21", 17716 + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", 17717 + "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==", 17718 + "license": "MIT" 17719 + }, 17720 + "node_modules/parse5": { 17721 + "version": "7.3.0", 17722 + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", 17723 + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", 17724 + "license": "MIT", 17725 + "dependencies": { 17726 + "entities": "^6.0.0" 17727 + }, 17728 + "funding": { 17729 + "url": "https://github.com/inikulin/parse5?sponsor=1" 17730 + } 17731 + }, 17732 + "node_modules/punycode": { 17733 + "version": "2.3.1", 17734 + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 17735 + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 17736 + "license": "MIT", 17737 + "engines": { 17738 + "node": ">=6" 17739 + } 17740 + }, 17741 + "node_modules/rrweb-cssom": { 17742 + "version": "0.8.0", 17743 + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", 17744 + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", 17745 + "license": "MIT" 17746 + }, 17747 + "node_modules/safer-buffer": { 17748 + "version": "2.1.2", 17749 + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 17750 + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 17751 + "license": "MIT" 17752 + }, 17753 + "node_modules/saxes": { 17754 + "version": "6.0.0", 17755 + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", 17756 + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", 17757 + "license": "ISC", 17758 + "dependencies": { 17759 + "xmlchars": "^2.2.0" 17760 + }, 17761 + "engines": { 17762 + "node": ">=v12.22.7" 17763 + } 17764 + }, 17765 + "node_modules/symbol-tree": { 17766 + "version": "3.2.4", 17767 + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", 17768 + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", 17769 + "license": "MIT" 17770 + }, 17771 + "node_modules/tldts": { 17772 + "version": "6.1.86", 17773 + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", 17774 + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", 17775 + "license": "MIT", 17776 + "dependencies": { 17777 + "tldts-core": "^6.1.86" 17778 + }, 17779 + "bin": { 17780 + "tldts": "bin/cli.js" 17781 + } 17782 + }, 17783 + "node_modules/tldts-core": { 17784 + "version": "6.1.86", 17785 + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", 17786 + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", 17787 + "license": "MIT" 17788 + }, 17789 + "node_modules/tough-cookie": { 17790 + "version": "5.1.2", 17791 + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", 17792 + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", 17793 + "license": "BSD-3-Clause", 17794 + "dependencies": { 17795 + "tldts": "^6.1.32" 17796 + }, 17797 + "engines": { 17798 + "node": ">=16" 17799 + } 17800 + }, 17801 + "node_modules/tr46": { 17802 + "version": "5.1.1", 17803 + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", 17804 + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", 17805 + "license": "MIT", 17806 + "dependencies": { 17807 + "punycode": "^2.3.1" 17808 + }, 17809 + "engines": { 17810 + "node": ">=18" 17811 + } 17812 + }, 17813 + "node_modules/tslib": { 17814 + "version": "2.8.1", 17815 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 17816 + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 17817 + "license": "0BSD" 17818 + }, 17354 17819 "node_modules/typescript": { 17355 17820 "version": "4.9.5", 17356 17821 "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", ··· 17364 17829 "engines": { 17365 17830 "node": ">=4.2.0" 17366 17831 } 17832 + }, 17833 + "node_modules/undici-types": { 17834 + "version": "7.10.0", 17835 + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", 17836 + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", 17837 + "dev": true, 17838 + "license": "MIT" 17839 + }, 17840 + "node_modules/w3c-xmlserializer": { 17841 + "version": "5.0.0", 17842 + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", 17843 + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", 17844 + "license": "MIT", 17845 + "dependencies": { 17846 + "xml-name-validator": "^5.0.0" 17847 + }, 17848 + "engines": { 17849 + "node": ">=18" 17850 + } 17851 + }, 17852 + "node_modules/webidl-conversions": { 17853 + "version": "7.0.0", 17854 + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", 17855 + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", 17856 + "license": "BSD-2-Clause", 17857 + "engines": { 17858 + "node": ">=12" 17859 + } 17860 + }, 17861 + "node_modules/whatwg-encoding": { 17862 + "version": "3.1.1", 17863 + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", 17864 + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", 17865 + "license": "MIT", 17866 + "dependencies": { 17867 + "iconv-lite": "0.6.3" 17868 + }, 17869 + "engines": { 17870 + "node": ">=18" 17871 + } 17872 + }, 17873 + "node_modules/whatwg-mimetype": { 17874 + "version": "4.0.0", 17875 + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", 17876 + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", 17877 + "license": "MIT", 17878 + "engines": { 17879 + "node": ">=18" 17880 + } 17881 + }, 17882 + "node_modules/whatwg-url": { 17883 + "version": "14.2.0", 17884 + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", 17885 + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", 17886 + "license": "MIT", 17887 + "dependencies": { 17888 + "tr46": "^5.1.0", 17889 + "webidl-conversions": "^7.0.0" 17890 + }, 17891 + "engines": { 17892 + "node": ">=18" 17893 + } 17894 + }, 17895 + "node_modules/ws": { 17896 + "version": "8.18.3", 17897 + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", 17898 + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", 17899 + "license": "MIT", 17900 + "engines": { 17901 + "node": ">=10.0.0" 17902 + }, 17903 + "peerDependencies": { 17904 + "bufferutil": "^4.0.1", 17905 + "utf-8-validate": ">=5.0.2" 17906 + }, 17907 + "peerDependenciesMeta": { 17908 + "bufferutil": { 17909 + "optional": true 17910 + }, 17911 + "utf-8-validate": { 17912 + "optional": true 17913 + } 17914 + } 17915 + }, 17916 + "node_modules/xml-name-validator": { 17917 + "version": "5.0.0", 17918 + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", 17919 + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", 17920 + "license": "Apache-2.0", 17921 + "engines": { 17922 + "node": ">=18" 17923 + } 17924 + }, 17925 + "node_modules/xmlchars": { 17926 + "version": "2.2.0", 17927 + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", 17928 + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", 17929 + "license": "MIT" 17367 17930 } 17368 17931 } 17369 17932 }
+7 -1
package.json
··· 17 17 "license": "MIT", 18 18 "devDependencies": { 19 19 "@types/crypto-js": "^4.2.2", 20 + "@types/marked": "^5.0.2", 21 + "@types/node": "^24.3.0", 20 22 "netlify-cli": "^23.3.1", 21 23 "npm": "^11.5.2", 22 24 "typescript": "^4.1.3" 23 25 }, 24 26 "dependencies": { 25 - "crypto-js": "^4.2.0" 27 + "@ts-stack/markdown": "^1.5.0", 28 + "crypto-js": "^4.2.0", 29 + "dompurify": "^3.2.6", 30 + "jsdom": "^26.1.0", 31 + "marked": "^16.2.0" 26 32 } 27 33 }
+1 -1
public/blog/item/index.html
··· 2 2 <html> 3 3 <head> 4 4 <link rel="stylesheet" href="/style.css" /> 5 - <script type="text/javascript" src="/blog-item.js"></script> 5 + <script type="module" src="/blog-item.js"></script> 6 6 </head> 7 7 <body> 8 8 <div id="nav-links">
+3
src/blog-item.ts
··· 1 + import { marked } from 'https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js'; 2 + 1 3 window.onload = () => { 2 4 fetch('https://bsky.social/xrpc/com.atproto.repo.getRecord?repo=cass.cityboundforest.com&collection=com.cityboundforest.blog&rkey=' + window.location.hash.replace('#', ''), { 3 5 headers: { ··· 7 9 return res.json(); 8 10 }).then((data: { value: { content: string, title: string } }) => { 9 11 document.getElementById('title')!.innerText = data.value.title; 12 + document.getElementById('blog-content')!.innerHTML += marked.parse(data.value.content); 10 13 }); 11 14 };
+3
src/marked-cdn.d.ts
··· 1 + declare module 'https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js' { 2 + export * from 'marked'; 3 + }
+2 -2
tsconfig.json
··· 2 2 "compilerOptions": { 3 3 "allowJs": true, 4 4 "checkJs": true, 5 - 6 5 "outDir": "dist", 7 6 "sourceMap": true, 8 7 "target": "ES6", 9 8 "noImplicitAny": true, 10 9 "noImplicitReturns": true, 11 10 "strict": true, 12 - "types": ["crypto-js"] 11 + "types": ["crypto-js", "@types/marked"], 12 + "moduleResolution": "node" 13 13 } 14 14 }