an appview-less Bluesky client using Constellation and PDS Queries reddwarf.app
frontend spa bluesky reddwarf microcosm

sanitize and display fedi content

rimar1337 bfa92e50 0bbbb07d

Changed files
+118 -47
src
+89 -41
package-lock.json
··· 16 16 "@tanstack/react-router": "^1.130.2", 17 17 "@tanstack/react-router-devtools": "^1.131.5", 18 18 "@tanstack/router-plugin": "^1.121.2", 19 + "dompurify": "^3.3.0", 19 20 "i": "^0.3.7", 20 21 "idb-keyval": "^6.2.2", 21 22 "jotai": "^2.13.1", ··· 369 370 "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", 370 371 "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", 371 372 "license": "MIT", 372 - "peer": true, 373 373 "dependencies": { 374 374 "@ampproject/remapping": "^2.2.0", 375 375 "@babel/code-frame": "^7.27.1", ··· 877 877 } 878 878 ], 879 879 "license": "MIT", 880 - "peer": true, 881 880 "engines": { 882 881 "node": ">=18" 883 882 }, ··· 901 900 } 902 901 ], 903 902 "license": "MIT", 904 - "peer": true, 905 903 "engines": { 906 904 "node": ">=18" 907 905 } ··· 1490 1488 "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", 1491 1489 "dev": true, 1492 1490 "license": "Apache-2.0", 1491 + "peer": true, 1493 1492 "dependencies": { 1494 1493 "@eslint/object-schema": "^2.1.6", 1495 1494 "debug": "^4.3.1", ··· 1505 1504 "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", 1506 1505 "dev": true, 1507 1506 "license": "Apache-2.0", 1507 + "peer": true, 1508 1508 "dependencies": { 1509 1509 "@eslint/core": "^0.16.0" 1510 1510 }, ··· 1518 1518 "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", 1519 1519 "dev": true, 1520 1520 "license": "Apache-2.0", 1521 + "peer": true, 1521 1522 "dependencies": { 1522 1523 "@types/json-schema": "^7.0.15" 1523 1524 }, ··· 1531 1532 "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", 1532 1533 "dev": true, 1533 1534 "license": "MIT", 1535 + "peer": true, 1534 1536 "dependencies": { 1535 1537 "ajv": "^6.12.4", 1536 1538 "debug": "^4.3.2", ··· 1555 1557 "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", 1556 1558 "dev": true, 1557 1559 "license": "MIT", 1560 + "peer": true, 1558 1561 "engines": { 1559 1562 "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1560 1563 }, ··· 1568 1571 "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", 1569 1572 "dev": true, 1570 1573 "license": "Apache-2.0", 1574 + "peer": true, 1571 1575 "engines": { 1572 1576 "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1573 1577 } ··· 1578 1582 "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", 1579 1583 "dev": true, 1580 1584 "license": "Apache-2.0", 1585 + "peer": true, 1581 1586 "dependencies": { 1582 1587 "@eslint/core": "^0.16.0", 1583 1588 "levn": "^0.4.1" ··· 1592 1597 "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", 1593 1598 "dev": true, 1594 1599 "license": "Apache-2.0", 1600 + "peer": true, 1595 1601 "engines": { 1596 1602 "node": ">=18.18.0" 1597 1603 } ··· 1602 1608 "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", 1603 1609 "dev": true, 1604 1610 "license": "Apache-2.0", 1611 + "peer": true, 1605 1612 "dependencies": { 1606 1613 "@humanfs/core": "^0.19.1", 1607 1614 "@humanwhocodes/retry": "^0.4.0" ··· 1616 1623 "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 1617 1624 "dev": true, 1618 1625 "license": "Apache-2.0", 1626 + "peer": true, 1619 1627 "engines": { 1620 1628 "node": ">=12.22" 1621 1629 }, ··· 1630 1638 "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", 1631 1639 "dev": true, 1632 1640 "license": "Apache-2.0", 1641 + "peer": true, 1633 1642 "engines": { 1634 1643 "node": ">=18.18" 1635 1644 }, ··· 2357 2366 "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", 2358 2367 "dev": true, 2359 2368 "license": "MIT", 2360 - "peer": true, 2361 2369 "dependencies": { 2362 2370 "@babel/core": "^7.21.3", 2363 2371 "@svgr/babel-preset": "8.1.0", ··· 2832 2840 "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.85.6.tgz", 2833 2841 "integrity": "sha512-VUAag4ERjh+qlmg0wNivQIVCZUrYndqYu3/wPCVZd4r0E+1IqotbeyGTc+ICroL/PqbpSaGZg02zSWYfcvxbdA==", 2834 2842 "license": "MIT", 2835 - "peer": true, 2836 2843 "dependencies": { 2837 2844 "@tanstack/query-core": "5.85.6" 2838 2845 }, ··· 2866 2873 "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.131.28.tgz", 2867 2874 "integrity": "sha512-vWExhrqHJuT9v+6/2DCQ4pVvPaYoLazMNw8WXiLNuzBXh1FuEoIGaW3jw3DEP0OJCmMiWtTi34NzQnakkQZlQg==", 2868 2875 "license": "MIT", 2869 - "peer": true, 2870 2876 "dependencies": { 2871 2877 "@tanstack/history": "1.131.2", 2872 2878 "@tanstack/react-store": "^0.7.0", ··· 2931 2937 "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.131.28.tgz", 2932 2938 "integrity": "sha512-f+vdfr3WKSS/BcqgI5s4vZg9xYb7NkvIolkaMELrbz3l+khkw1aTjx8wqCHRY4dqwIAxq+iZBZtMWXA7pztGJg==", 2933 2939 "license": "MIT", 2934 - "peer": true, 2935 2940 "dependencies": { 2936 2941 "@tanstack/history": "1.131.2", 2937 2942 "@tanstack/store": "^0.7.0", ··· 3104 3109 "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", 3105 3110 "dev": true, 3106 3111 "license": "MIT", 3107 - "peer": true, 3108 3112 "dependencies": { 3109 3113 "@babel/code-frame": "^7.10.4", 3110 3114 "@babel/runtime": "^7.12.5", ··· 3227 3231 "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", 3228 3232 "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", 3229 3233 "dev": true, 3230 - "license": "MIT" 3234 + "license": "MIT", 3235 + "peer": true 3231 3236 }, 3232 3237 "node_modules/@types/node": { 3233 3238 "version": "24.3.0", ··· 3235 3240 "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", 3236 3241 "devOptional": true, 3237 3242 "license": "MIT", 3238 - "peer": true, 3239 3243 "dependencies": { 3240 3244 "undici-types": "~7.10.0" 3241 3245 } ··· 3245 3249 "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz", 3246 3250 "integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==", 3247 3251 "license": "MIT", 3248 - "peer": true, 3249 3252 "dependencies": { 3250 3253 "csstype": "^3.0.2" 3251 3254 } ··· 3255 3258 "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz", 3256 3259 "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", 3257 3260 "license": "MIT", 3258 - "peer": true, 3259 3261 "peerDependencies": { 3260 3262 "@types/react": "^19.0.0" 3261 3263 } 3264 + }, 3265 + "node_modules/@types/trusted-types": { 3266 + "version": "2.0.7", 3267 + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", 3268 + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", 3269 + "license": "MIT", 3270 + "optional": true 3262 3271 }, 3263 3272 "node_modules/@typescript-eslint/eslint-plugin": { 3264 3273 "version": "8.46.1", ··· 3266 3275 "integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==", 3267 3276 "dev": true, 3268 3277 "license": "MIT", 3269 - "peer": true, 3270 3278 "dependencies": { 3271 3279 "@eslint-community/regexpp": "^4.10.0", 3272 3280 "@typescript-eslint/scope-manager": "8.46.1", ··· 3307 3315 "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", 3308 3316 "dev": true, 3309 3317 "license": "MIT", 3310 - "peer": true, 3311 3318 "dependencies": { 3312 3319 "@typescript-eslint/scope-manager": "8.46.1", 3313 3320 "@typescript-eslint/types": "8.46.1", ··· 3690 3697 "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", 3691 3698 "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", 3692 3699 "license": "MIT", 3693 - "peer": true, 3694 3700 "bin": { 3695 3701 "acorn": "bin/acorn" 3696 3702 }, ··· 3704 3710 "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 3705 3711 "dev": true, 3706 3712 "license": "MIT", 3713 + "peer": true, 3707 3714 "peerDependencies": { 3708 3715 "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 3709 3716 } ··· 3724 3731 "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 3725 3732 "dev": true, 3726 3733 "license": "MIT", 3734 + "peer": true, 3727 3735 "dependencies": { 3728 3736 "fast-deep-equal": "^3.1.1", 3729 3737 "fast-json-stable-stringify": "^2.0.0", ··· 4118 4126 } 4119 4127 ], 4120 4128 "license": "MIT", 4121 - "peer": true, 4122 4129 "dependencies": { 4123 4130 "caniuse-lite": "^1.0.30001737", 4124 4131 "electron-to-chromium": "^1.5.211", ··· 4276 4283 "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 4277 4284 "dev": true, 4278 4285 "license": "MIT", 4286 + "peer": true, 4279 4287 "dependencies": { 4280 4288 "ansi-styles": "^4.1.0", 4281 4289 "supports-color": "^7.1.0" ··· 4293 4301 "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 4294 4302 "dev": true, 4295 4303 "license": "MIT", 4304 + "peer": true, 4296 4305 "dependencies": { 4297 4306 "color-convert": "^2.0.1" 4298 4307 }, ··· 4373 4382 "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 4374 4383 "dev": true, 4375 4384 "license": "MIT", 4385 + "peer": true, 4376 4386 "dependencies": { 4377 4387 "color-name": "~1.1.4" 4378 4388 }, ··· 4385 4395 "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 4386 4396 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 4387 4397 "dev": true, 4388 - "license": "MIT" 4398 + "license": "MIT", 4399 + "peer": true 4389 4400 }, 4390 4401 "node_modules/compare-versions": { 4391 4402 "version": "6.1.1", ··· 4464 4475 "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 4465 4476 "dev": true, 4466 4477 "license": "MIT", 4478 + "peer": true, 4467 4479 "dependencies": { 4468 4480 "path-key": "^3.1.0", 4469 4481 "shebang-command": "^2.0.0", ··· 4491 4503 "version": "3.1.3", 4492 4504 "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", 4493 4505 "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", 4494 - "license": "MIT", 4495 - "peer": true 4506 + "license": "MIT" 4496 4507 }, 4497 4508 "node_modules/custom-media-element": { 4498 4509 "version": "1.4.5", ··· 4635 4646 "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 4636 4647 "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 4637 4648 "dev": true, 4638 - "license": "MIT" 4649 + "license": "MIT", 4650 + "peer": true 4639 4651 }, 4640 4652 "node_modules/define-data-property": { 4641 4653 "version": "1.1.4", ··· 4721 4733 "dev": true, 4722 4734 "license": "MIT" 4723 4735 }, 4736 + "node_modules/dompurify": { 4737 + "version": "3.3.0", 4738 + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.0.tgz", 4739 + "integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==", 4740 + "license": "(MPL-2.0 OR Apache-2.0)", 4741 + "optionalDependencies": { 4742 + "@types/trusted-types": "^2.0.7" 4743 + } 4744 + }, 4724 4745 "node_modules/dot-case": { 4725 4746 "version": "3.0.4", 4726 4747 "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", ··· 5029 5050 "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 5030 5051 "dev": true, 5031 5052 "license": "MIT", 5053 + "peer": true, 5032 5054 "engines": { 5033 5055 "node": ">=10" 5034 5056 }, ··· 5320 5342 "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", 5321 5343 "dev": true, 5322 5344 "license": "BSD-2-Clause", 5345 + "peer": true, 5323 5346 "dependencies": { 5324 5347 "esrecurse": "^4.3.0", 5325 5348 "estraverse": "^5.2.0" ··· 5350 5373 "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 5351 5374 "dev": true, 5352 5375 "license": "ISC", 5376 + "peer": true, 5353 5377 "dependencies": { 5354 5378 "is-glob": "^4.0.3" 5355 5379 }, ··· 5363 5387 "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", 5364 5388 "dev": true, 5365 5389 "license": "BSD-2-Clause", 5390 + "peer": true, 5366 5391 "dependencies": { 5367 5392 "acorn": "^8.15.0", 5368 5393 "acorn-jsx": "^5.3.2", ··· 5394 5419 "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", 5395 5420 "dev": true, 5396 5421 "license": "BSD-3-Clause", 5422 + "peer": true, 5397 5423 "dependencies": { 5398 5424 "estraverse": "^5.1.0" 5399 5425 }, ··· 5407 5433 "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 5408 5434 "dev": true, 5409 5435 "license": "BSD-2-Clause", 5436 + "peer": true, 5410 5437 "dependencies": { 5411 5438 "estraverse": "^5.2.0" 5412 5439 }, ··· 5495 5522 "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 5496 5523 "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 5497 5524 "dev": true, 5498 - "license": "MIT" 5525 + "license": "MIT", 5526 + "peer": true 5499 5527 }, 5500 5528 "node_modules/fast-levenshtein": { 5501 5529 "version": "2.0.6", 5502 5530 "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 5503 5531 "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 5504 5532 "dev": true, 5505 - "license": "MIT" 5533 + "license": "MIT", 5534 + "peer": true 5506 5535 }, 5507 5536 "node_modules/fastq": { 5508 5537 "version": "1.19.1", ··· 5520 5549 "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", 5521 5550 "dev": true, 5522 5551 "license": "MIT", 5552 + "peer": true, 5523 5553 "dependencies": { 5524 5554 "flat-cache": "^4.0.0" 5525 5555 }, ··· 5545 5575 "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 5546 5576 "dev": true, 5547 5577 "license": "MIT", 5578 + "peer": true, 5548 5579 "dependencies": { 5549 5580 "locate-path": "^6.0.0", 5550 5581 "path-exists": "^4.0.0" ··· 5562 5593 "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", 5563 5594 "dev": true, 5564 5595 "license": "MIT", 5596 + "peer": true, 5565 5597 "dependencies": { 5566 5598 "flatted": "^3.2.9", 5567 5599 "keyv": "^4.5.4" ··· 5575 5607 "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", 5576 5608 "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", 5577 5609 "dev": true, 5578 - "license": "ISC" 5610 + "license": "ISC", 5611 + "peer": true 5579 5612 }, 5580 5613 "node_modules/for-each": { 5581 5614 "version": "0.3.5", ··· 5754 5787 "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", 5755 5788 "dev": true, 5756 5789 "license": "MIT", 5790 + "peer": true, 5757 5791 "engines": { 5758 5792 "node": ">=18" 5759 5793 }, ··· 5831 5865 "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 5832 5866 "dev": true, 5833 5867 "license": "MIT", 5868 + "peer": true, 5834 5869 "engines": { 5835 5870 "node": ">=8" 5836 5871 } ··· 6043 6078 "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", 6044 6079 "dev": true, 6045 6080 "license": "MIT", 6081 + "peer": true, 6046 6082 "engines": { 6047 6083 "node": ">= 4" 6048 6084 } ··· 6085 6121 "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 6086 6122 "dev": true, 6087 6123 "license": "MIT", 6124 + "peer": true, 6088 6125 "engines": { 6089 6126 "node": ">=0.8.19" 6090 6127 } ··· 6590 6627 "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 6591 6628 "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 6592 6629 "dev": true, 6593 - "license": "ISC" 6630 + "license": "ISC", 6631 + "peer": true 6594 6632 }, 6595 6633 "node_modules/iso-datestring-validator": { 6596 6634 "version": "2.2.2", ··· 6688 6726 "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", 6689 6727 "dev": true, 6690 6728 "license": "MIT", 6691 - "peer": true, 6692 6729 "dependencies": { 6693 6730 "cssstyle": "^4.2.1", 6694 6731 "data-urls": "^5.0.0", ··· 6740 6777 "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 6741 6778 "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", 6742 6779 "dev": true, 6743 - "license": "MIT" 6780 + "license": "MIT", 6781 + "peer": true 6744 6782 }, 6745 6783 "node_modules/json-parse-even-better-errors": { 6746 6784 "version": "2.3.1", ··· 6754 6792 "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 6755 6793 "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 6756 6794 "dev": true, 6757 - "license": "MIT" 6795 + "license": "MIT", 6796 + "peer": true 6758 6797 }, 6759 6798 "node_modules/json-stable-stringify-without-jsonify": { 6760 6799 "version": "1.0.1", 6761 6800 "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 6762 6801 "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", 6763 6802 "dev": true, 6764 - "license": "MIT" 6803 + "license": "MIT", 6804 + "peer": true 6765 6805 }, 6766 6806 "node_modules/json5": { 6767 6807 "version": "2.2.3", ··· 6797 6837 "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", 6798 6838 "dev": true, 6799 6839 "license": "MIT", 6840 + "peer": true, 6800 6841 "dependencies": { 6801 6842 "json-buffer": "3.0.1" 6802 6843 } ··· 6814 6855 "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 6815 6856 "dev": true, 6816 6857 "license": "MIT", 6858 + "peer": true, 6817 6859 "dependencies": { 6818 6860 "prelude-ls": "^1.2.1", 6819 6861 "type-check": "~0.4.0" ··· 7099 7141 "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 7100 7142 "dev": true, 7101 7143 "license": "MIT", 7144 + "peer": true, 7102 7145 "dependencies": { 7103 7146 "p-locate": "^5.0.0" 7104 7147 }, ··· 7120 7163 "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 7121 7164 "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 7122 7165 "dev": true, 7123 - "license": "MIT" 7166 + "license": "MIT", 7167 + "peer": true 7124 7168 }, 7125 7169 "node_modules/loose-envify": { 7126 7170 "version": "1.4.0", ··· 9580 9624 "version": "4.0.3", 9581 9625 "inBundle": true, 9582 9626 "license": "MIT", 9583 - "peer": true, 9584 9627 "engines": { 9585 9628 "node": ">=12" 9586 9629 }, ··· 9914 9957 "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", 9915 9958 "dev": true, 9916 9959 "license": "MIT", 9960 + "peer": true, 9917 9961 "dependencies": { 9918 9962 "deep-is": "^0.1.3", 9919 9963 "fast-levenshtein": "^2.0.6", ··· 9950 9994 "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 9951 9995 "dev": true, 9952 9996 "license": "MIT", 9997 + "peer": true, 9953 9998 "dependencies": { 9954 9999 "yocto-queue": "^0.1.0" 9955 10000 }, ··· 9966 10011 "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 9967 10012 "dev": true, 9968 10013 "license": "MIT", 10014 + "peer": true, 9969 10015 "dependencies": { 9970 10016 "p-limit": "^3.0.2" 9971 10017 }, ··· 10040 10086 "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 10041 10087 "dev": true, 10042 10088 "license": "MIT", 10089 + "peer": true, 10043 10090 "engines": { 10044 10091 "node": ">=8" 10045 10092 } ··· 10050 10097 "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 10051 10098 "dev": true, 10052 10099 "license": "MIT", 10100 + "peer": true, 10053 10101 "engines": { 10054 10102 "node": ">=8" 10055 10103 } ··· 10178 10226 "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 10179 10227 "dev": true, 10180 10228 "license": "MIT", 10229 + "peer": true, 10181 10230 "engines": { 10182 10231 "node": ">= 0.8.0" 10183 10232 } ··· 10282 10331 "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", 10283 10332 "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", 10284 10333 "license": "MIT", 10285 - "peer": true, 10286 10334 "engines": { 10287 10335 "node": ">=0.10.0" 10288 10336 } ··· 10292 10340 "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", 10293 10341 "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", 10294 10342 "license": "MIT", 10295 - "peer": true, 10296 10343 "dependencies": { 10297 10344 "scheduler": "^0.26.0" 10298 10345 }, ··· 10647 10694 "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz", 10648 10695 "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", 10649 10696 "license": "MIT", 10650 - "peer": true, 10651 10697 "engines": { 10652 10698 "node": ">=10" 10653 10699 } ··· 10719 10765 "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 10720 10766 "dev": true, 10721 10767 "license": "MIT", 10768 + "peer": true, 10722 10769 "dependencies": { 10723 10770 "shebang-regex": "^3.0.0" 10724 10771 }, ··· 10732 10779 "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 10733 10780 "dev": true, 10734 10781 "license": "MIT", 10782 + "peer": true, 10735 10783 "engines": { 10736 10784 "node": ">=8" 10737 10785 } ··· 10835 10883 "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.9.tgz", 10836 10884 "integrity": "sha512-A0ZBPJQldAeGCTW0YRYJmt7RCeh5rbFfPZ2aOttgYnctHE7HgKeHCBB/PVc2P7eOfmNXqMFFFoYYdm3S4dcbkA==", 10837 10885 "license": "MIT", 10838 - "peer": true, 10839 10886 "dependencies": { 10840 10887 "csstype": "^3.1.0", 10841 10888 "seroval": "~1.3.0", ··· 11005 11052 "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 11006 11053 "dev": true, 11007 11054 "license": "MIT", 11055 + "peer": true, 11008 11056 "engines": { 11009 11057 "node": ">=8" 11010 11058 }, ··· 11044 11092 "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 11045 11093 "dev": true, 11046 11094 "license": "MIT", 11095 + "peer": true, 11047 11096 "dependencies": { 11048 11097 "has-flag": "^4.0.0" 11049 11098 }, ··· 11143 11192 "version": "1.3.3", 11144 11193 "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", 11145 11194 "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", 11146 - "license": "MIT", 11147 - "peer": true 11195 + "license": "MIT" 11148 11196 }, 11149 11197 "node_modules/tiny-warning": { 11150 11198 "version": "1.0.3", ··· 11204 11252 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", 11205 11253 "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", 11206 11254 "license": "MIT", 11207 - "peer": true, 11208 11255 "engines": { 11209 11256 "node": ">=12" 11210 11257 }, ··· 11402 11449 "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 11403 11450 "dev": true, 11404 11451 "license": "MIT", 11452 + "peer": true, 11405 11453 "dependencies": { 11406 11454 "prelude-ls": "^1.2.1" 11407 11455 }, ··· 11493 11541 "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", 11494 11542 "dev": true, 11495 11543 "license": "Apache-2.0", 11496 - "peer": true, 11497 11544 "bin": { 11498 11545 "tsc": "bin/tsc", 11499 11546 "tsserver": "bin/tsserver" ··· 11830 11877 "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 11831 11878 "dev": true, 11832 11879 "license": "BSD-2-Clause", 11880 + "peer": true, 11833 11881 "dependencies": { 11834 11882 "punycode": "^2.1.0" 11835 11883 } ··· 11857 11905 "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", 11858 11906 "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", 11859 11907 "license": "MIT", 11860 - "peer": true, 11861 11908 "dependencies": { 11862 11909 "esbuild": "^0.25.0", 11863 11910 "fdir": "^6.4.4", ··· 11972 12019 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", 11973 12020 "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", 11974 12021 "license": "MIT", 11975 - "peer": true, 11976 12022 "engines": { 11977 12023 "node": ">=12" 11978 12024 }, ··· 12154 12200 "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 12155 12201 "dev": true, 12156 12202 "license": "ISC", 12203 + "peer": true, 12157 12204 "dependencies": { 12158 12205 "isexe": "^2.0.0" 12159 12206 }, ··· 12285 12332 "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", 12286 12333 "dev": true, 12287 12334 "license": "MIT", 12335 + "peer": true, 12288 12336 "engines": { 12289 12337 "node": ">=0.10.0" 12290 12338 } ··· 12339 12387 "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 12340 12388 "dev": true, 12341 12389 "license": "MIT", 12390 + "peer": true, 12342 12391 "engines": { 12343 12392 "node": ">=10" 12344 12393 }, ··· 12357 12406 "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", 12358 12407 "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", 12359 12408 "license": "MIT", 12360 - "peer": true, 12361 12409 "funding": { 12362 12410 "url": "https://github.com/sponsors/colinhacks" 12363 12411 }
+1
package.json
··· 20 20 "@tanstack/react-router": "^1.130.2", 21 21 "@tanstack/react-router-devtools": "^1.131.5", 22 22 "@tanstack/router-plugin": "^1.121.2", 23 + "dompurify": "^3.3.0", 23 24 "i": "^0.3.7", 24 25 "idb-keyval": "^6.2.2", 25 26 "jotai": "^2.13.1",
+20 -6
src/components/UniversalPostRenderer.tsx
··· 1 1 import { useNavigate } from "@tanstack/react-router"; 2 + import DOMPurify from "dompurify"; 2 3 import { useAtom } from "jotai"; 3 4 import * as React from "react"; 4 5 import { type SVGProps } from "react"; ··· 1202 1203 : undefined; 1203 1204 1204 1205 const emergencySalt = randomString(); 1206 + const fedi = (post.record as { bridgyOriginalText?: string }) 1207 + .bridgyOriginalText; 1205 1208 1206 1209 /* fuck you */ 1207 1210 const isMainItem = false; ··· 1484 1487 }} 1485 1488 className="text-gray-900 dark:text-gray-100" 1486 1489 > 1487 - {renderTextWithFacets({ 1488 - text: (post.record as { text?: string }).text ?? "", 1489 - facets: (post.record.facets as Facet[]) ?? [], 1490 - navigate: navigate, 1491 - })} 1492 - {} 1490 + {fedi ? ( 1491 + <> 1492 + <span className="dangerousFediContent" 1493 + dangerouslySetInnerHTML={{ 1494 + __html: DOMPurify.sanitize(fedi), 1495 + }} 1496 + /> 1497 + </> 1498 + ) : ( 1499 + <> 1500 + {renderTextWithFacets({ 1501 + text: (post.record as { text?: string }).text ?? "", 1502 + facets: (post.record.facets as Facet[]) ?? [], 1503 + navigate: navigate, 1504 + })} 1505 + </> 1506 + )} 1493 1507 </div> 1494 1508 {post.embed && depth < 1 ? ( 1495 1509 <PostEmbeds
+8
src/styles/app.css
··· 71 71 .scroll-none { 72 72 scrollbar-width: none; 73 73 } 74 + 75 + .dangerousFediContent { 76 + & a[href]{ 77 + text-decoration: none; 78 + color: rgb(29, 122, 242); 79 + word-break: break-all; 80 + } 81 + }