forked from pdsls.dev/pdsls
atproto explorer

Compare changes

Choose any two refs to compare.

+11 -11
package.json
··· 11 11 "devDependencies": { 12 12 "@iconify-json/lucide": "^1.2.68", 13 13 "@iconify/tailwind4": "^1.0.6", 14 - "@tailwindcss/vite": "^4.1.13", 14 + "@tailwindcss/vite": "^4.1.14", 15 15 "prettier": "^3.6.2", 16 16 "prettier-plugin-organize-imports": "^4.3.0", 17 17 "prettier-plugin-tailwindcss": "^0.6.14", 18 - "tailwindcss": "^4.1.13", 19 - "typescript": "^5.9.2", 20 - "vite": "^7.1.7", 21 - "vite-plugin-solid": "^2.11.8" 18 + "tailwindcss": "^4.1.14", 19 + "typescript": "^5.9.3", 20 + "vite": "^7.1.8", 21 + "vite-plugin-solid": "^2.11.9" 22 22 }, 23 23 "dependencies": { 24 24 "@atcute/atproto": "^3.1.4", 25 - "@atcute/bluesky": "^3.2.2", 25 + "@atcute/bluesky": "^3.2.3", 26 26 "@atcute/car": "^3.1.1", 27 27 "@atcute/cbor": "^2.2.5", 28 28 "@atcute/cid": "^2.2.3", ··· 33 33 "@atcute/identity-resolver": "^1.1.3", 34 34 "@atcute/leaflet": "^1.0.8", 35 35 "@atcute/lexicon-doc": "^1.1.1", 36 + "@atcute/lexicon-resolver": "^0.1.0", 36 37 "@atcute/lexicons": "^1.1.1", 37 38 "@atcute/oauth-browser-client": "^1.0.26", 38 39 "@atcute/tangled": "^1.0.6", 39 40 "@atcute/tid": "^1.0.2", 40 41 "@atcute/uint8array": "^1.0.4", 41 - "@codemirror/commands": "^6.8.1", 42 + "@codemirror/commands": "^6.9.0", 42 43 "@codemirror/lang-json": "^6.0.2", 43 - "@codemirror/lint": "^6.8.5", 44 + "@codemirror/lint": "^6.9.0", 44 45 "@codemirror/state": "^6.5.2", 45 - "@codemirror/view": "^6.38.3", 46 + "@codemirror/view": "^6.38.4", 46 47 "@fsegurai/codemirror-theme-basic-dark": "^6.2.2", 47 48 "@fsegurai/codemirror-theme-basic-light": "^6.2.2", 48 49 "@mary/exif-rm": "jsr:^0.2.2", ··· 50 51 "@solidjs/meta": "^0.29.4", 51 52 "@solidjs/router": "^0.15.3", 52 53 "codemirror": "^6.0.2", 53 - "hls.js": "^1.6.13", 54 54 "solid-js": "^1.9.9" 55 55 }, 56 - "packageManager": "pnpm@10.12.2+sha512.a32540185b964ee30bb4e979e405adc6af59226b438ee4cc19f9e8773667a66d302f5bfee60a39d3cac69e35e4b96e708a71dd002b7e9359c4112a1722ac323f" 56 + "packageManager": "pnpm@10.17.1+sha512.17c560fca4867ae9473a3899ad84a88334914f379be46d455cbf92e5cf4b39d34985d452d2583baf19967fa76cb5c17bc9e245529d0b98745721aa7200ecaf7a" 57 57 }
+287 -272
pnpm-lock.yaml
··· 12 12 specifier: ^3.1.4 13 13 version: 3.1.4 14 14 '@atcute/bluesky': 15 - specifier: ^3.2.2 16 - version: 3.2.2 15 + specifier: ^3.2.3 16 + version: 3.2.3 17 17 '@atcute/car': 18 18 specifier: ^3.1.1 19 19 version: 3.1.1 ··· 44 44 '@atcute/lexicon-doc': 45 45 specifier: ^1.1.1 46 46 version: 1.1.1 47 + '@atcute/lexicon-resolver': 48 + specifier: ^0.1.0 49 + version: 0.1.0(@atcute/identity-resolver@1.1.3(@atcute/identity@1.1.0))(@atcute/identity@1.1.0) 47 50 '@atcute/lexicons': 48 51 specifier: ^1.1.1 49 52 version: 1.1.1 ··· 60 63 specifier: ^1.0.4 61 64 version: 1.0.4 62 65 '@codemirror/commands': 63 - specifier: ^6.8.1 64 - version: 6.8.1 66 + specifier: ^6.9.0 67 + version: 6.9.0 65 68 '@codemirror/lang-json': 66 69 specifier: ^6.0.2 67 70 version: 6.0.2 68 71 '@codemirror/lint': 69 - specifier: ^6.8.5 70 - version: 6.8.5 72 + specifier: ^6.9.0 73 + version: 6.9.0 71 74 '@codemirror/state': 72 75 specifier: ^6.5.2 73 76 version: 6.5.2 74 77 '@codemirror/view': 75 - specifier: ^6.38.3 76 - version: 6.38.3 78 + specifier: ^6.38.4 79 + version: 6.38.4 77 80 '@fsegurai/codemirror-theme-basic-dark': 78 81 specifier: ^6.2.2 79 - version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.3)(@lezer/highlight@1.2.1) 82 + version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.4)(@lezer/highlight@1.2.1) 80 83 '@fsegurai/codemirror-theme-basic-light': 81 84 specifier: ^6.2.2 82 - version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.3)(@lezer/highlight@1.2.1) 85 + version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.4)(@lezer/highlight@1.2.1) 83 86 '@mary/exif-rm': 84 87 specifier: jsr:^0.2.2 85 88 version: '@jsr/mary__exif-rm@0.2.2' ··· 95 98 codemirror: 96 99 specifier: ^6.0.2 97 100 version: 6.0.2 98 - hls.js: 99 - specifier: ^1.6.13 100 - version: 1.6.13 101 101 solid-js: 102 102 specifier: ^1.9.9 103 103 version: 1.9.9 ··· 107 107 version: 1.2.68 108 108 '@iconify/tailwind4': 109 109 specifier: ^1.0.6 110 - version: 1.0.6(tailwindcss@4.1.13) 110 + version: 1.0.6(tailwindcss@4.1.14) 111 111 '@tailwindcss/vite': 112 - specifier: ^4.1.13 113 - version: 4.1.13(vite@7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2)) 112 + specifier: ^4.1.14 113 + version: 4.1.14(vite@7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)) 114 114 prettier: 115 115 specifier: ^3.6.2 116 116 version: 3.6.2 117 117 prettier-plugin-organize-imports: 118 118 specifier: ^4.3.0 119 - version: 4.3.0(prettier@3.6.2)(typescript@5.9.2) 119 + version: 4.3.0(prettier@3.6.2)(typescript@5.9.3) 120 120 prettier-plugin-tailwindcss: 121 121 specifier: ^0.6.14 122 - version: 0.6.14(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.2))(prettier@3.6.2) 122 + version: 0.6.14(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3))(prettier@3.6.2) 123 123 tailwindcss: 124 - specifier: ^4.1.13 125 - version: 4.1.13 124 + specifier: ^4.1.14 125 + version: 4.1.14 126 126 typescript: 127 - specifier: ^5.9.2 128 - version: 5.9.2 127 + specifier: ^5.9.3 128 + version: 5.9.3 129 129 vite: 130 - specifier: ^7.1.7 131 - version: 7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2) 130 + specifier: ^7.1.8 131 + version: 7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2) 132 132 vite-plugin-solid: 133 - specifier: ^2.11.8 134 - version: 2.11.8(solid-js@1.9.9)(vite@7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2)) 133 + specifier: ^2.11.9 134 + version: 2.11.9(solid-js@1.9.9)(vite@7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)) 135 135 136 136 packages: 137 137 ··· 144 144 '@atcute/atproto@3.1.4': 145 145 resolution: {integrity: sha512-v0/ue7mZYtjYw4vWbtda51bLwW88mqsUQB8F/UZNO18ANAQWmKq1HDceVqjvruaLe2QPqE43XM3WkEyZ2FhOrA==} 146 146 147 - '@atcute/bluesky@3.2.2': 148 - resolution: {integrity: sha512-L8RrMNeRLGvSHMq2KDIAGXrpuNGA87YOXpXHY1yhmovVCjQ5n55FrR6JoQaxhprdXdKKQiefxNwQQQybDrfgFQ==} 147 + '@atcute/bluesky@3.2.3': 148 + resolution: {integrity: sha512-IdPQQ54F1BLhW5z49k81ZUC/GQl/tVygZ+CzLHYvQySHA6GJRcvPzwEf8aV21u0SZOJF+yF4CWEGNgtryyxPmg==} 149 149 150 150 '@atcute/car@3.1.1': 151 151 resolution: {integrity: sha512-yhez/LqIl0zHubG6z/G/gqWYHmg7wJ5L4jNkbXj5FvZ4eOvmzsw8+ojbdq6wfMU4p5NhP0pUJNLkTZHbYSPmLg==} ··· 178 178 179 179 '@atcute/lexicon-doc@1.1.1': 180 180 resolution: {integrity: sha512-/6M4K34ICZWa9rRiM9YWSsDZs0Vjv05SFJBb03mD+x14W01gIVLPK2UXiP0yIodgzWHhPQ79LLdyMJ8LirC84w==} 181 + 182 + '@atcute/lexicon-resolver@0.1.0': 183 + resolution: {integrity: sha512-j63pB+PcxQX+hSIOqb4Lorlavv3yjUncgElPHdq3mUeKjZNJbpRZu5uZ0kdcP76sVjoyl52LyS5E2OSGKbK2Zg==} 184 + peerDependencies: 185 + '@atcute/identity': ^1.1.0 186 + '@atcute/identity-resolver': ^1.1.3 181 187 182 188 '@atcute/lexicons@1.1.1': 183 189 resolution: {integrity: sha512-k6qy5p3j9fJJ6ekaMPfEfp3ni4TW/XNuH9ZmsuwC0fi0tOjp+Fa8ZQakHwnqOzFt/cVBfGcmYE/lKNAbeTjgUg==} ··· 288 294 resolution: {integrity: sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==} 289 295 engines: {node: '>= 18'} 290 296 291 - '@codemirror/autocomplete@6.18.7': 292 - resolution: {integrity: sha512-8EzdeIoWPJDsMBwz3zdzwXnUpCzMiCyz5/A3FIPpriaclFCGDkAzK13sMcnsu5rowqiyeQN2Vs2TsOcoDPZirQ==} 297 + '@codemirror/autocomplete@6.19.0': 298 + resolution: {integrity: sha512-61Hfv3cF07XvUxNeC3E7jhG8XNi1Yom1G0lRC936oLnlF+jrbrv8rc/J98XlYzcsAoTVupfsf5fLej1aI8kyIg==} 293 299 294 - '@codemirror/commands@6.8.1': 295 - resolution: {integrity: sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==} 300 + '@codemirror/commands@6.9.0': 301 + resolution: {integrity: sha512-454TVgjhO6cMufsyyGN70rGIfJxJEjcqjBG2x2Y03Y/+Fm99d3O/Kv1QDYWuG6hvxsgmjXmBuATikIIYvERX+w==} 296 302 297 303 '@codemirror/lang-json@6.0.2': 298 304 resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} ··· 300 306 '@codemirror/language@6.11.3': 301 307 resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==} 302 308 303 - '@codemirror/lint@6.8.5': 304 - resolution: {integrity: sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==} 309 + '@codemirror/lint@6.9.0': 310 + resolution: {integrity: sha512-wZxW+9XDytH3SKvS8cQzMyQCaaazH8XL1EMHleHe00wVzsv7NBQKVW2yzEHrRhmM7ZOhVdItPbvlRBvMp9ej7A==} 305 311 306 312 '@codemirror/search@6.5.11': 307 313 resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==} ··· 309 315 '@codemirror/state@6.5.2': 310 316 resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==} 311 317 312 - '@codemirror/view@6.38.3': 313 - resolution: {integrity: sha512-x2t87+oqwB1mduiQZ6huIghjMt4uZKFEdj66IcXw7+a5iBEvv9lh7EWDRHI7crnD4BMGpnyq/RzmCGbiEZLcvQ==} 318 + '@codemirror/view@6.38.4': 319 + resolution: {integrity: sha512-hduz0suCcUSC/kM8Fq3A9iLwInJDl8fD1xLpTIk+5xkNm8z/FT7UsIa9sOXrkpChh+XXc18RzswE8QqELsVl+g==} 314 320 315 321 '@esbuild/aix-ppc64@0.23.1': 316 322 resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} ··· 683 689 '@noble/secp256k1@2.3.0': 684 690 resolution: {integrity: sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw==} 685 691 686 - '@rollup/rollup-android-arm-eabi@4.52.0': 687 - resolution: {integrity: sha512-VxDYCDqOaR7NXzAtvRx7G1u54d2kEHopb28YH/pKzY6y0qmogP3gG7CSiWsq9WvDFxOQMpNEyjVAHZFXfH3o/A==} 692 + '@rollup/rollup-android-arm-eabi@4.52.3': 693 + resolution: {integrity: sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==} 688 694 cpu: [arm] 689 695 os: [android] 690 696 691 - '@rollup/rollup-android-arm64@4.52.0': 692 - resolution: {integrity: sha512-pqDirm8koABIKvzL59YI9W9DWbRlTX7RWhN+auR8HXJxo89m4mjqbah7nJZjeKNTNYopqL+yGg+0mhCpf3xZtQ==} 697 + '@rollup/rollup-android-arm64@4.52.3': 698 + resolution: {integrity: sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==} 693 699 cpu: [arm64] 694 700 os: [android] 695 701 696 - '@rollup/rollup-darwin-arm64@4.52.0': 697 - resolution: {integrity: sha512-YCdWlY/8ltN6H78HnMsRHYlPiKvqKagBP1r+D7SSylxX+HnsgXGCmLiV3Y4nSyY9hW8qr8U9LDUx/Lo7M6MfmQ==} 702 + '@rollup/rollup-darwin-arm64@4.52.3': 703 + resolution: {integrity: sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==} 698 704 cpu: [arm64] 699 705 os: [darwin] 700 706 701 - '@rollup/rollup-darwin-x64@4.52.0': 702 - resolution: {integrity: sha512-z4nw6y1j+OOSGzuVbSWdIp1IUks9qNw4dc7z7lWuWDKojY38VMWBlEN7F9jk5UXOkUcp97vA1N213DF+Lz8BRg==} 707 + '@rollup/rollup-darwin-x64@4.52.3': 708 + resolution: {integrity: sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==} 703 709 cpu: [x64] 704 710 os: [darwin] 705 711 706 - '@rollup/rollup-freebsd-arm64@4.52.0': 707 - resolution: {integrity: sha512-Q/dv9Yvyr5rKlK8WQJZVrp5g2SOYeZUs9u/t2f9cQ2E0gJjYB/BWoedXfUT0EcDJefi2zzVfhcOj8drWCzTviw==} 712 + '@rollup/rollup-freebsd-arm64@4.52.3': 713 + resolution: {integrity: sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==} 708 714 cpu: [arm64] 709 715 os: [freebsd] 710 716 711 - '@rollup/rollup-freebsd-x64@4.52.0': 712 - resolution: {integrity: sha512-kdBsLs4Uile/fbjZVvCRcKB4q64R+1mUq0Yd7oU1CMm1Av336ajIFqNFovByipciuUQjBCPMxwJhCgfG2re3rg==} 717 + '@rollup/rollup-freebsd-x64@4.52.3': 718 + resolution: {integrity: sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==} 713 719 cpu: [x64] 714 720 os: [freebsd] 715 721 716 - '@rollup/rollup-linux-arm-gnueabihf@4.52.0': 717 - resolution: {integrity: sha512-aL6hRwu0k7MTUESgkg7QHY6CoqPgr6gdQXRJI1/VbFlUMwsSzPGSR7sG5d+MCbYnJmJwThc2ol3nixj1fvI/zQ==} 722 + '@rollup/rollup-linux-arm-gnueabihf@4.52.3': 723 + resolution: {integrity: sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==} 718 724 cpu: [arm] 719 725 os: [linux] 720 726 721 - '@rollup/rollup-linux-arm-musleabihf@4.52.0': 722 - resolution: {integrity: sha512-BTs0M5s1EJejgIBJhCeiFo7GZZ2IXWkFGcyZhxX4+8usnIo5Mti57108vjXFIQmmJaRyDwmV59Tw64Ap1dkwMw==} 727 + '@rollup/rollup-linux-arm-musleabihf@4.52.3': 728 + resolution: {integrity: sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==} 723 729 cpu: [arm] 724 730 os: [linux] 725 731 726 - '@rollup/rollup-linux-arm64-gnu@4.52.0': 727 - resolution: {integrity: sha512-uj672IVOU9m08DBGvoPKPi/J8jlVgjh12C9GmjjBxCTQc3XtVmRkRKyeHSmIKQpvJ7fIm1EJieBUcnGSzDVFyw==} 732 + '@rollup/rollup-linux-arm64-gnu@4.52.3': 733 + resolution: {integrity: sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==} 728 734 cpu: [arm64] 729 735 os: [linux] 730 736 731 - '@rollup/rollup-linux-arm64-musl@4.52.0': 732 - resolution: {integrity: sha512-/+IVbeDMDCtB/HP/wiWsSzduD10SEGzIZX2945KSgZRNi4TSkjHqRJtNTVtVb8IRwhJ65ssI56krlLik+zFWkw==} 737 + '@rollup/rollup-linux-arm64-musl@4.52.3': 738 + resolution: {integrity: sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==} 733 739 cpu: [arm64] 734 740 os: [linux] 735 741 736 - '@rollup/rollup-linux-loong64-gnu@4.52.0': 737 - resolution: {integrity: sha512-U1vVzvSWtSMWKKrGoROPBXMh3Vwn93TA9V35PldokHGqiUbF6erSzox/5qrSMKp6SzakvyjcPiVF8yB1xKr9Pg==} 742 + '@rollup/rollup-linux-loong64-gnu@4.52.3': 743 + resolution: {integrity: sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==} 738 744 cpu: [loong64] 739 745 os: [linux] 740 746 741 - '@rollup/rollup-linux-ppc64-gnu@4.52.0': 742 - resolution: {integrity: sha512-X/4WfuBAdQRH8cK3DYl8zC00XEE6aM472W+QCycpQJeLWVnHfkv7RyBFVaTqNUMsTgIX8ihMjCvFF9OUgeABzw==} 747 + '@rollup/rollup-linux-ppc64-gnu@4.52.3': 748 + resolution: {integrity: sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==} 743 749 cpu: [ppc64] 744 750 os: [linux] 745 751 746 - '@rollup/rollup-linux-riscv64-gnu@4.52.0': 747 - resolution: {integrity: sha512-xIRYc58HfWDBZoLmWfWXg2Sq8VCa2iJ32B7mqfWnkx5mekekl0tMe7FHpY8I72RXEcUkaWawRvl3qA55og+cwQ==} 752 + '@rollup/rollup-linux-riscv64-gnu@4.52.3': 753 + resolution: {integrity: sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==} 748 754 cpu: [riscv64] 749 755 os: [linux] 750 756 751 - '@rollup/rollup-linux-riscv64-musl@4.52.0': 752 - resolution: {integrity: sha512-mbsoUey05WJIOz8U1WzNdf+6UMYGwE3fZZnQqsM22FZ3wh1N887HT6jAOjXs6CNEK3Ntu2OBsyQDXfIjouI4dw==} 757 + '@rollup/rollup-linux-riscv64-musl@4.52.3': 758 + resolution: {integrity: sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==} 753 759 cpu: [riscv64] 754 760 os: [linux] 755 761 756 - '@rollup/rollup-linux-s390x-gnu@4.52.0': 757 - resolution: {integrity: sha512-qP6aP970bucEi5KKKR4AuPFd8aTx9EF6BvutvYxmZuWLJHmnq4LvBfp0U+yFDMGwJ+AIJEH5sIP+SNypauMWzg==} 762 + '@rollup/rollup-linux-s390x-gnu@4.52.3': 763 + resolution: {integrity: sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==} 758 764 cpu: [s390x] 759 765 os: [linux] 760 766 761 - '@rollup/rollup-linux-x64-gnu@4.52.0': 762 - resolution: {integrity: sha512-nmSVN+F2i1yKZ7rJNKO3G7ZzmxJgoQBQZ/6c4MuS553Grmr7WqR7LLDcYG53Z2m9409z3JLt4sCOhLdbKQ3HmA==} 767 + '@rollup/rollup-linux-x64-gnu@4.52.3': 768 + resolution: {integrity: sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==} 763 769 cpu: [x64] 764 770 os: [linux] 765 771 766 - '@rollup/rollup-linux-x64-musl@4.52.0': 767 - resolution: {integrity: sha512-2d0qRo33G6TfQVjaMR71P+yJVGODrt5V6+T0BDYH4EMfGgdC/2HWDVjSSFw888GSzAZUwuska3+zxNUCDco6rQ==} 772 + '@rollup/rollup-linux-x64-musl@4.52.3': 773 + resolution: {integrity: sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==} 768 774 cpu: [x64] 769 775 os: [linux] 770 776 771 - '@rollup/rollup-openharmony-arm64@4.52.0': 772 - resolution: {integrity: sha512-A1JalX4MOaFAAyGgpO7XP5khquv/7xKzLIyLmhNrbiCxWpMlnsTYr8dnsWM7sEeotNmxvSOEL7F65j0HXFcFsw==} 777 + '@rollup/rollup-openharmony-arm64@4.52.3': 778 + resolution: {integrity: sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==} 773 779 cpu: [arm64] 774 780 os: [openharmony] 775 781 776 - '@rollup/rollup-win32-arm64-msvc@4.52.0': 777 - resolution: {integrity: sha512-YQugafP/rH0eOOHGjmNgDURrpYHrIX0yuojOI8bwCyXwxC9ZdTd3vYkmddPX0oHONLXu9Rb1dDmT0VNpjkzGGw==} 782 + '@rollup/rollup-win32-arm64-msvc@4.52.3': 783 + resolution: {integrity: sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==} 778 784 cpu: [arm64] 779 785 os: [win32] 780 786 781 - '@rollup/rollup-win32-ia32-msvc@4.52.0': 782 - resolution: {integrity: sha512-zYdUYhi3Qe2fndujBqL5FjAFzvNeLxtIqfzNEVKD1I7C37/chv1VxhscWSQHTNfjPCrBFQMnynwA3kpZpZ8w4A==} 787 + '@rollup/rollup-win32-ia32-msvc@4.52.3': 788 + resolution: {integrity: sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==} 783 789 cpu: [ia32] 784 790 os: [win32] 785 791 786 - '@rollup/rollup-win32-x64-gnu@4.52.0': 787 - resolution: {integrity: sha512-fGk03kQylNaCOQ96HDMeT7E2n91EqvCDd3RwvT5k+xNdFCeMGnj5b5hEgTGrQuyidqSsD3zJDQ21QIaxXqTBJw==} 792 + '@rollup/rollup-win32-x64-gnu@4.52.3': 793 + resolution: {integrity: sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==} 788 794 cpu: [x64] 789 795 os: [win32] 790 796 791 - '@rollup/rollup-win32-x64-msvc@4.52.0': 792 - resolution: {integrity: sha512-6iKDCVSIUQ8jPMoIV0OytRKniaYyy5EbY/RRydmLW8ZR3cEBhxbWl5ro0rkUNe0ef6sScvhbY79HrjRm8i3vDQ==} 797 + '@rollup/rollup-win32-x64-msvc@4.52.3': 798 + resolution: {integrity: sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==} 793 799 cpu: [x64] 794 800 os: [win32] 795 801 ··· 806 812 peerDependencies: 807 813 solid-js: ^1.8.6 808 814 809 - '@tailwindcss/node@4.1.13': 810 - resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==} 815 + '@tailwindcss/node@4.1.14': 816 + resolution: {integrity: sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==} 811 817 812 - '@tailwindcss/oxide-android-arm64@4.1.13': 813 - resolution: {integrity: sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==} 818 + '@tailwindcss/oxide-android-arm64@4.1.14': 819 + resolution: {integrity: sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==} 814 820 engines: {node: '>= 10'} 815 821 cpu: [arm64] 816 822 os: [android] 817 823 818 - '@tailwindcss/oxide-darwin-arm64@4.1.13': 819 - resolution: {integrity: sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==} 824 + '@tailwindcss/oxide-darwin-arm64@4.1.14': 825 + resolution: {integrity: sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==} 820 826 engines: {node: '>= 10'} 821 827 cpu: [arm64] 822 828 os: [darwin] 823 829 824 - '@tailwindcss/oxide-darwin-x64@4.1.13': 825 - resolution: {integrity: sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==} 830 + '@tailwindcss/oxide-darwin-x64@4.1.14': 831 + resolution: {integrity: sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==} 826 832 engines: {node: '>= 10'} 827 833 cpu: [x64] 828 834 os: [darwin] 829 835 830 - '@tailwindcss/oxide-freebsd-x64@4.1.13': 831 - resolution: {integrity: sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==} 836 + '@tailwindcss/oxide-freebsd-x64@4.1.14': 837 + resolution: {integrity: sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==} 832 838 engines: {node: '>= 10'} 833 839 cpu: [x64] 834 840 os: [freebsd] 835 841 836 - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': 837 - resolution: {integrity: sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==} 842 + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14': 843 + resolution: {integrity: sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==} 838 844 engines: {node: '>= 10'} 839 845 cpu: [arm] 840 846 os: [linux] 841 847 842 - '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': 843 - resolution: {integrity: sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==} 848 + '@tailwindcss/oxide-linux-arm64-gnu@4.1.14': 849 + resolution: {integrity: sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==} 844 850 engines: {node: '>= 10'} 845 851 cpu: [arm64] 846 852 os: [linux] 847 853 848 - '@tailwindcss/oxide-linux-arm64-musl@4.1.13': 849 - resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==} 854 + '@tailwindcss/oxide-linux-arm64-musl@4.1.14': 855 + resolution: {integrity: sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==} 850 856 engines: {node: '>= 10'} 851 857 cpu: [arm64] 852 858 os: [linux] 853 859 854 - '@tailwindcss/oxide-linux-x64-gnu@4.1.13': 855 - resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==} 860 + '@tailwindcss/oxide-linux-x64-gnu@4.1.14': 861 + resolution: {integrity: sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==} 856 862 engines: {node: '>= 10'} 857 863 cpu: [x64] 858 864 os: [linux] 859 865 860 - '@tailwindcss/oxide-linux-x64-musl@4.1.13': 861 - resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==} 866 + '@tailwindcss/oxide-linux-x64-musl@4.1.14': 867 + resolution: {integrity: sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==} 862 868 engines: {node: '>= 10'} 863 869 cpu: [x64] 864 870 os: [linux] 865 871 866 - '@tailwindcss/oxide-wasm32-wasi@4.1.13': 867 - resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==} 872 + '@tailwindcss/oxide-wasm32-wasi@4.1.14': 873 + resolution: {integrity: sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==} 868 874 engines: {node: '>=14.0.0'} 869 875 cpu: [wasm32] 870 876 bundledDependencies: ··· 875 881 - '@emnapi/wasi-threads' 876 882 - tslib 877 883 878 - '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': 879 - resolution: {integrity: sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==} 884 + '@tailwindcss/oxide-win32-arm64-msvc@4.1.14': 885 + resolution: {integrity: sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==} 880 886 engines: {node: '>= 10'} 881 887 cpu: [arm64] 882 888 os: [win32] 883 889 884 - '@tailwindcss/oxide-win32-x64-msvc@4.1.13': 885 - resolution: {integrity: sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==} 890 + '@tailwindcss/oxide-win32-x64-msvc@4.1.14': 891 + resolution: {integrity: sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==} 886 892 engines: {node: '>= 10'} 887 893 cpu: [x64] 888 894 os: [win32] 889 895 890 - '@tailwindcss/oxide@4.1.13': 891 - resolution: {integrity: sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==} 896 + '@tailwindcss/oxide@4.1.14': 897 + resolution: {integrity: sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==} 892 898 engines: {node: '>= 10'} 893 899 894 - '@tailwindcss/vite@4.1.13': 895 - resolution: {integrity: sha512-0PmqLQ010N58SbMTJ7BVJ4I2xopiQn/5i6nlb4JmxzQf8zcS5+m2Cv6tqh+sfDwtIdjoEnOvwsGQ1hkUi8QEHQ==} 900 + '@tailwindcss/vite@4.1.14': 901 + resolution: {integrity: sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==} 896 902 peerDependencies: 897 903 vite: ^5.2.0 || ^6 || ^7 898 904 ··· 933 939 solid-js: 934 940 optional: true 935 941 936 - baseline-browser-mapping@2.8.6: 937 - resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==} 942 + baseline-browser-mapping@2.8.10: 943 + resolution: {integrity: sha512-uLfgBi+7IBNay8ECBO2mVMGZAc1VgZWEChxm4lv+TobGdG82LnXMjuNGo/BSSZZL4UmkWhxEHP2f5ziLNwGWMA==} 938 944 hasBin: true 939 945 940 - browserslist@4.26.2: 941 - resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==} 946 + browserslist@4.26.3: 947 + resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} 942 948 engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 943 949 hasBin: true 944 950 945 - caniuse-lite@1.0.30001743: 946 - resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==} 951 + caniuse-lite@1.0.30001746: 952 + resolution: {integrity: sha512-eA7Ys/DGw+pnkWWSE/id29f2IcPHVoE8wxtvE5JdvD2V28VTDPy1yEeo11Guz0sJ4ZeGRcm3uaTcAqK1LXaphA==} 947 953 948 954 chownr@3.0.0: 949 955 resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} ··· 976 982 supports-color: 977 983 optional: true 978 984 979 - detect-libc@2.1.0: 980 - resolution: {integrity: sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==} 985 + detect-libc@2.1.1: 986 + resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==} 981 987 engines: {node: '>=8'} 982 988 983 - electron-to-chromium@1.5.222: 984 - resolution: {integrity: sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==} 989 + electron-to-chromium@1.5.228: 990 + resolution: {integrity: sha512-nxkiyuqAn4MJ1QbobwqJILiDtu/jk14hEAWaMiJmNPh1Z+jqoFlBFZjdXwLWGeVSeu9hGLg6+2G9yJaW8rBIFA==} 985 991 986 992 enhanced-resolve@5.18.3: 987 993 resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} ··· 1039 1045 graceful-fs@4.2.11: 1040 1046 resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 1041 1047 1042 - hls.js@1.6.13: 1043 - resolution: {integrity: sha512-hNEzjZNHf5bFrUNvdS4/1RjIanuJ6szpWNfTaX5I6WfGynWXGT7K/YQLYtemSvFExzeMdgdE4SsyVLJbd5PcZA==} 1044 - 1045 1048 html-entities@2.3.3: 1046 1049 resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} 1047 1050 ··· 1049 1052 resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} 1050 1053 engines: {node: '>=12.13'} 1051 1054 1052 - jiti@2.6.0: 1053 - resolution: {integrity: sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==} 1055 + jiti@2.6.1: 1056 + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} 1054 1057 hasBin: true 1055 1058 1056 1059 js-tokens@4.0.0: ··· 1286 1289 resolve-pkg-maps@1.0.0: 1287 1290 resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} 1288 1291 1289 - rollup@4.52.0: 1290 - resolution: {integrity: sha512-+IuescNkTJQgX7AkIDtITipZdIGcWF0pnVvZTWStiazUmcGA2ag8dfg0urest2XlXUi9kuhfQ+qmdc5Stc3z7g==} 1292 + rollup@4.52.3: 1293 + resolution: {integrity: sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==} 1291 1294 engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1292 1295 hasBin: true 1293 1296 ··· 1320 1323 style-mod@4.1.2: 1321 1324 resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} 1322 1325 1323 - tailwindcss@4.1.13: 1324 - resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==} 1326 + tailwindcss@4.1.14: 1327 + resolution: {integrity: sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==} 1325 1328 1326 - tapable@2.2.3: 1327 - resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} 1329 + tapable@2.3.0: 1330 + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} 1328 1331 engines: {node: '>=6'} 1329 1332 1330 - tar@7.4.4: 1331 - resolution: {integrity: sha512-O1z7ajPkjTgEgmTGz0v9X4eqeEXTDREPTO77pVC1Nbs86feBU1Zhdg+edzavPmYW1olxkwsqA2v4uOw6E8LeDg==} 1333 + tar@7.5.1: 1334 + resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} 1332 1335 engines: {node: '>=18'} 1333 1336 1334 1337 tinyexec@1.0.1: ··· 1343 1346 engines: {node: '>=18.0.0'} 1344 1347 hasBin: true 1345 1348 1346 - typescript@5.9.2: 1347 - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} 1349 + typescript@5.9.3: 1350 + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} 1348 1351 engines: {node: '>=14.17'} 1349 1352 hasBin: true 1350 1353 ··· 1363 1366 validate-html-nesting@1.2.3: 1364 1367 resolution: {integrity: sha512-kdkWdCl6eCeLlRShJKbjVOU2kFKxMF8Ghu50n+crEoyx+VKm3FxAxF9z4DCy6+bbTOqNW0+jcIYRnjoIRzigRw==} 1365 1368 1366 - vite-plugin-solid@2.11.8: 1367 - resolution: {integrity: sha512-hFrCxBfv3B1BmFqnJF4JOCYpjrmi/zwyeKjcomQ0khh8HFyQ8SbuBWQ7zGojfrz6HUOBFrJBNySDi/JgAHytWg==} 1369 + vite-plugin-solid@2.11.9: 1370 + resolution: {integrity: sha512-bTA6p+bspXZsuulSd2y6aTzegF8xGaJYcq1Uyh/mv+W4DQtzCgL9nN6n2fsTaxp/dMk+ZHHKgGndlNeooqHLKw==} 1368 1371 peerDependencies: 1369 1372 '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* 1370 1373 solid-js: ^1.7.2 ··· 1373 1376 '@testing-library/jest-dom': 1374 1377 optional: true 1375 1378 1376 - vite@7.1.7: 1377 - resolution: {integrity: sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==} 1379 + vite@7.1.8: 1380 + resolution: {integrity: sha512-oBXvfSHEOL8jF+R9Am7h59Up07kVVGH1NrFGFoEG6bPDZP3tGpQhvkBpy5x7U6+E6wZCu9OihsWgJqDbQIm8LQ==} 1378 1381 engines: {node: ^20.19.0 || >=22.12.0} 1379 1382 hasBin: true 1380 1383 peerDependencies: ··· 1448 1451 dependencies: 1449 1452 '@atcute/lexicons': 1.1.1 1450 1453 1451 - '@atcute/bluesky@3.2.2': 1454 + '@atcute/bluesky@3.2.3': 1452 1455 dependencies: 1453 1456 '@atcute/atproto': 3.1.4 1454 1457 '@atcute/lexicons': 1.1.1 ··· 1515 1518 dependencies: 1516 1519 '@badrap/valita': 0.4.6 1517 1520 1521 + '@atcute/lexicon-resolver@0.1.0(@atcute/identity-resolver@1.1.3(@atcute/identity@1.1.0))(@atcute/identity@1.1.0)': 1522 + dependencies: 1523 + '@atcute/car': 3.1.1 1524 + '@atcute/cbor': 2.2.5 1525 + '@atcute/cid': 2.2.3 1526 + '@atcute/crypto': 2.2.4 1527 + '@atcute/identity': 1.1.0 1528 + '@atcute/identity-resolver': 1.1.3(@atcute/identity@1.1.0) 1529 + '@atcute/lexicon-doc': 1.1.1 1530 + '@atcute/lexicons': 1.1.1 1531 + '@atcute/uint8array': 1.0.4 1532 + '@atcute/util-fetch': 1.0.2 1533 + '@badrap/valita': 0.4.6 1534 + 1518 1535 '@atcute/lexicons@1.1.1': 1519 1536 dependencies: 1520 1537 esm-env: 1.2.2 ··· 1587 1604 dependencies: 1588 1605 '@babel/compat-data': 7.28.4 1589 1606 '@babel/helper-validator-option': 7.27.1 1590 - browserslist: 4.26.2 1607 + browserslist: 4.26.3 1591 1608 lru-cache: 5.1.1 1592 1609 semver: 6.3.1 1593 1610 ··· 1660 1677 1661 1678 '@badrap/valita@0.4.6': {} 1662 1679 1663 - '@codemirror/autocomplete@6.18.7': 1680 + '@codemirror/autocomplete@6.19.0': 1664 1681 dependencies: 1665 1682 '@codemirror/language': 6.11.3 1666 1683 '@codemirror/state': 6.5.2 1667 - '@codemirror/view': 6.38.3 1684 + '@codemirror/view': 6.38.4 1668 1685 '@lezer/common': 1.2.3 1669 1686 1670 - '@codemirror/commands@6.8.1': 1687 + '@codemirror/commands@6.9.0': 1671 1688 dependencies: 1672 1689 '@codemirror/language': 6.11.3 1673 1690 '@codemirror/state': 6.5.2 1674 - '@codemirror/view': 6.38.3 1691 + '@codemirror/view': 6.38.4 1675 1692 '@lezer/common': 1.2.3 1676 1693 1677 1694 '@codemirror/lang-json@6.0.2': ··· 1682 1699 '@codemirror/language@6.11.3': 1683 1700 dependencies: 1684 1701 '@codemirror/state': 6.5.2 1685 - '@codemirror/view': 6.38.3 1702 + '@codemirror/view': 6.38.4 1686 1703 '@lezer/common': 1.2.3 1687 1704 '@lezer/highlight': 1.2.1 1688 1705 '@lezer/lr': 1.4.2 1689 1706 style-mod: 4.1.2 1690 1707 1691 - '@codemirror/lint@6.8.5': 1708 + '@codemirror/lint@6.9.0': 1692 1709 dependencies: 1693 1710 '@codemirror/state': 6.5.2 1694 - '@codemirror/view': 6.38.3 1711 + '@codemirror/view': 6.38.4 1695 1712 crelt: 1.0.6 1696 1713 1697 1714 '@codemirror/search@6.5.11': 1698 1715 dependencies: 1699 1716 '@codemirror/state': 6.5.2 1700 - '@codemirror/view': 6.38.3 1717 + '@codemirror/view': 6.38.4 1701 1718 crelt: 1.0.6 1702 1719 1703 1720 '@codemirror/state@6.5.2': 1704 1721 dependencies: 1705 1722 '@marijn/find-cluster-break': 1.0.2 1706 1723 1707 - '@codemirror/view@6.38.3': 1724 + '@codemirror/view@6.38.4': 1708 1725 dependencies: 1709 1726 '@codemirror/state': 6.5.2 1710 1727 crelt: 1.0.6 ··· 1861 1878 '@esbuild/win32-x64@0.25.10': 1862 1879 optional: true 1863 1880 1864 - '@fsegurai/codemirror-theme-basic-dark@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.3)(@lezer/highlight@1.2.1)': 1881 + '@fsegurai/codemirror-theme-basic-dark@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.4)(@lezer/highlight@1.2.1)': 1865 1882 dependencies: 1866 1883 '@codemirror/language': 6.11.3 1867 1884 '@codemirror/state': 6.5.2 1868 - '@codemirror/view': 6.38.3 1885 + '@codemirror/view': 6.38.4 1869 1886 '@lezer/highlight': 1.2.1 1870 1887 1871 - '@fsegurai/codemirror-theme-basic-light@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.3)(@lezer/highlight@1.2.1)': 1888 + '@fsegurai/codemirror-theme-basic-light@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.4)(@lezer/highlight@1.2.1)': 1872 1889 dependencies: 1873 1890 '@codemirror/language': 6.11.3 1874 1891 '@codemirror/state': 6.5.2 1875 - '@codemirror/view': 6.38.3 1892 + '@codemirror/view': 6.38.4 1876 1893 '@lezer/highlight': 1.2.1 1877 1894 1878 1895 '@iconify-json/lucide@1.2.68': 1879 1896 dependencies: 1880 1897 '@iconify/types': 2.0.0 1881 1898 1882 - '@iconify/tailwind4@1.0.6(tailwindcss@4.1.13)': 1899 + '@iconify/tailwind4@1.0.6(tailwindcss@4.1.14)': 1883 1900 dependencies: 1884 1901 '@iconify/types': 2.0.0 1885 1902 '@iconify/utils': 2.3.0 1886 - tailwindcss: 4.1.13 1903 + tailwindcss: 4.1.14 1887 1904 transitivePeerDependencies: 1888 1905 - supports-color 1889 1906 ··· 1947 1964 1948 1965 '@noble/secp256k1@2.3.0': {} 1949 1966 1950 - '@rollup/rollup-android-arm-eabi@4.52.0': 1967 + '@rollup/rollup-android-arm-eabi@4.52.3': 1951 1968 optional: true 1952 1969 1953 - '@rollup/rollup-android-arm64@4.52.0': 1970 + '@rollup/rollup-android-arm64@4.52.3': 1954 1971 optional: true 1955 1972 1956 - '@rollup/rollup-darwin-arm64@4.52.0': 1973 + '@rollup/rollup-darwin-arm64@4.52.3': 1957 1974 optional: true 1958 1975 1959 - '@rollup/rollup-darwin-x64@4.52.0': 1976 + '@rollup/rollup-darwin-x64@4.52.3': 1960 1977 optional: true 1961 1978 1962 - '@rollup/rollup-freebsd-arm64@4.52.0': 1979 + '@rollup/rollup-freebsd-arm64@4.52.3': 1963 1980 optional: true 1964 1981 1965 - '@rollup/rollup-freebsd-x64@4.52.0': 1982 + '@rollup/rollup-freebsd-x64@4.52.3': 1966 1983 optional: true 1967 1984 1968 - '@rollup/rollup-linux-arm-gnueabihf@4.52.0': 1985 + '@rollup/rollup-linux-arm-gnueabihf@4.52.3': 1969 1986 optional: true 1970 1987 1971 - '@rollup/rollup-linux-arm-musleabihf@4.52.0': 1988 + '@rollup/rollup-linux-arm-musleabihf@4.52.3': 1972 1989 optional: true 1973 1990 1974 - '@rollup/rollup-linux-arm64-gnu@4.52.0': 1991 + '@rollup/rollup-linux-arm64-gnu@4.52.3': 1975 1992 optional: true 1976 1993 1977 - '@rollup/rollup-linux-arm64-musl@4.52.0': 1994 + '@rollup/rollup-linux-arm64-musl@4.52.3': 1978 1995 optional: true 1979 1996 1980 - '@rollup/rollup-linux-loong64-gnu@4.52.0': 1997 + '@rollup/rollup-linux-loong64-gnu@4.52.3': 1981 1998 optional: true 1982 1999 1983 - '@rollup/rollup-linux-ppc64-gnu@4.52.0': 2000 + '@rollup/rollup-linux-ppc64-gnu@4.52.3': 1984 2001 optional: true 1985 2002 1986 - '@rollup/rollup-linux-riscv64-gnu@4.52.0': 2003 + '@rollup/rollup-linux-riscv64-gnu@4.52.3': 1987 2004 optional: true 1988 2005 1989 - '@rollup/rollup-linux-riscv64-musl@4.52.0': 2006 + '@rollup/rollup-linux-riscv64-musl@4.52.3': 1990 2007 optional: true 1991 2008 1992 - '@rollup/rollup-linux-s390x-gnu@4.52.0': 2009 + '@rollup/rollup-linux-s390x-gnu@4.52.3': 1993 2010 optional: true 1994 2011 1995 - '@rollup/rollup-linux-x64-gnu@4.52.0': 2012 + '@rollup/rollup-linux-x64-gnu@4.52.3': 1996 2013 optional: true 1997 2014 1998 - '@rollup/rollup-linux-x64-musl@4.52.0': 2015 + '@rollup/rollup-linux-x64-musl@4.52.3': 1999 2016 optional: true 2000 2017 2001 - '@rollup/rollup-openharmony-arm64@4.52.0': 2018 + '@rollup/rollup-openharmony-arm64@4.52.3': 2002 2019 optional: true 2003 2020 2004 - '@rollup/rollup-win32-arm64-msvc@4.52.0': 2021 + '@rollup/rollup-win32-arm64-msvc@4.52.3': 2005 2022 optional: true 2006 2023 2007 - '@rollup/rollup-win32-ia32-msvc@4.52.0': 2024 + '@rollup/rollup-win32-ia32-msvc@4.52.3': 2008 2025 optional: true 2009 2026 2010 - '@rollup/rollup-win32-x64-gnu@4.52.0': 2027 + '@rollup/rollup-win32-x64-gnu@4.52.3': 2011 2028 optional: true 2012 2029 2013 - '@rollup/rollup-win32-x64-msvc@4.52.0': 2030 + '@rollup/rollup-win32-x64-msvc@4.52.3': 2014 2031 optional: true 2015 2032 2016 2033 '@skyware/firehose@0.5.2': ··· 2027 2044 dependencies: 2028 2045 solid-js: 1.9.9 2029 2046 2030 - '@tailwindcss/node@4.1.13': 2047 + '@tailwindcss/node@4.1.14': 2031 2048 dependencies: 2032 2049 '@jridgewell/remapping': 2.3.5 2033 2050 enhanced-resolve: 5.18.3 2034 - jiti: 2.6.0 2051 + jiti: 2.6.1 2035 2052 lightningcss: 1.30.1 2036 2053 magic-string: 0.30.19 2037 2054 source-map-js: 1.2.1 2038 - tailwindcss: 4.1.13 2055 + tailwindcss: 4.1.14 2039 2056 2040 - '@tailwindcss/oxide-android-arm64@4.1.13': 2057 + '@tailwindcss/oxide-android-arm64@4.1.14': 2041 2058 optional: true 2042 2059 2043 - '@tailwindcss/oxide-darwin-arm64@4.1.13': 2060 + '@tailwindcss/oxide-darwin-arm64@4.1.14': 2044 2061 optional: true 2045 2062 2046 - '@tailwindcss/oxide-darwin-x64@4.1.13': 2063 + '@tailwindcss/oxide-darwin-x64@4.1.14': 2047 2064 optional: true 2048 2065 2049 - '@tailwindcss/oxide-freebsd-x64@4.1.13': 2066 + '@tailwindcss/oxide-freebsd-x64@4.1.14': 2050 2067 optional: true 2051 2068 2052 - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': 2069 + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14': 2053 2070 optional: true 2054 2071 2055 - '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': 2072 + '@tailwindcss/oxide-linux-arm64-gnu@4.1.14': 2056 2073 optional: true 2057 2074 2058 - '@tailwindcss/oxide-linux-arm64-musl@4.1.13': 2075 + '@tailwindcss/oxide-linux-arm64-musl@4.1.14': 2059 2076 optional: true 2060 2077 2061 - '@tailwindcss/oxide-linux-x64-gnu@4.1.13': 2078 + '@tailwindcss/oxide-linux-x64-gnu@4.1.14': 2062 2079 optional: true 2063 2080 2064 - '@tailwindcss/oxide-linux-x64-musl@4.1.13': 2081 + '@tailwindcss/oxide-linux-x64-musl@4.1.14': 2065 2082 optional: true 2066 2083 2067 - '@tailwindcss/oxide-wasm32-wasi@4.1.13': 2084 + '@tailwindcss/oxide-wasm32-wasi@4.1.14': 2068 2085 optional: true 2069 2086 2070 - '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': 2087 + '@tailwindcss/oxide-win32-arm64-msvc@4.1.14': 2071 2088 optional: true 2072 2089 2073 - '@tailwindcss/oxide-win32-x64-msvc@4.1.13': 2090 + '@tailwindcss/oxide-win32-x64-msvc@4.1.14': 2074 2091 optional: true 2075 2092 2076 - '@tailwindcss/oxide@4.1.13': 2093 + '@tailwindcss/oxide@4.1.14': 2077 2094 dependencies: 2078 - detect-libc: 2.1.0 2079 - tar: 7.4.4 2095 + detect-libc: 2.1.1 2096 + tar: 7.5.1 2080 2097 optionalDependencies: 2081 - '@tailwindcss/oxide-android-arm64': 4.1.13 2082 - '@tailwindcss/oxide-darwin-arm64': 4.1.13 2083 - '@tailwindcss/oxide-darwin-x64': 4.1.13 2084 - '@tailwindcss/oxide-freebsd-x64': 4.1.13 2085 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.13 2086 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.13 2087 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.13 2088 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.13 2089 - '@tailwindcss/oxide-linux-x64-musl': 4.1.13 2090 - '@tailwindcss/oxide-wasm32-wasi': 4.1.13 2091 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13 2092 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.13 2098 + '@tailwindcss/oxide-android-arm64': 4.1.14 2099 + '@tailwindcss/oxide-darwin-arm64': 4.1.14 2100 + '@tailwindcss/oxide-darwin-x64': 4.1.14 2101 + '@tailwindcss/oxide-freebsd-x64': 4.1.14 2102 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.14 2103 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.14 2104 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.14 2105 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.14 2106 + '@tailwindcss/oxide-linux-x64-musl': 4.1.14 2107 + '@tailwindcss/oxide-wasm32-wasi': 4.1.14 2108 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.14 2109 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.14 2093 2110 2094 - '@tailwindcss/vite@4.1.13(vite@7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2))': 2111 + '@tailwindcss/vite@4.1.14(vite@7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2))': 2095 2112 dependencies: 2096 - '@tailwindcss/node': 4.1.13 2097 - '@tailwindcss/oxide': 4.1.13 2098 - tailwindcss: 4.1.13 2099 - vite: 7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2) 2113 + '@tailwindcss/node': 4.1.14 2114 + '@tailwindcss/oxide': 4.1.14 2115 + tailwindcss: 4.1.14 2116 + vite: 7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2) 2100 2117 2101 2118 '@types/babel__core@7.20.5': 2102 2119 dependencies: ··· 2145 2162 optionalDependencies: 2146 2163 solid-js: 1.9.9 2147 2164 2148 - baseline-browser-mapping@2.8.6: {} 2165 + baseline-browser-mapping@2.8.10: {} 2149 2166 2150 - browserslist@4.26.2: 2167 + browserslist@4.26.3: 2151 2168 dependencies: 2152 - baseline-browser-mapping: 2.8.6 2153 - caniuse-lite: 1.0.30001743 2154 - electron-to-chromium: 1.5.222 2169 + baseline-browser-mapping: 2.8.10 2170 + caniuse-lite: 1.0.30001746 2171 + electron-to-chromium: 1.5.228 2155 2172 node-releases: 2.0.21 2156 - update-browserslist-db: 1.1.3(browserslist@4.26.2) 2173 + update-browserslist-db: 1.1.3(browserslist@4.26.3) 2157 2174 2158 - caniuse-lite@1.0.30001743: {} 2175 + caniuse-lite@1.0.30001746: {} 2159 2176 2160 2177 chownr@3.0.0: {} 2161 2178 2162 2179 codemirror@6.0.2: 2163 2180 dependencies: 2164 - '@codemirror/autocomplete': 6.18.7 2165 - '@codemirror/commands': 6.8.1 2181 + '@codemirror/autocomplete': 6.19.0 2182 + '@codemirror/commands': 6.9.0 2166 2183 '@codemirror/language': 6.11.3 2167 - '@codemirror/lint': 6.8.5 2184 + '@codemirror/lint': 6.9.0 2168 2185 '@codemirror/search': 6.5.11 2169 2186 '@codemirror/state': 6.5.2 2170 - '@codemirror/view': 6.38.3 2187 + '@codemirror/view': 6.38.4 2171 2188 2172 2189 confbox@0.1.8: {} 2173 2190 ··· 2183 2200 dependencies: 2184 2201 ms: 2.1.3 2185 2202 2186 - detect-libc@2.1.0: {} 2203 + detect-libc@2.1.1: {} 2187 2204 2188 - electron-to-chromium@1.5.222: {} 2205 + electron-to-chromium@1.5.228: {} 2189 2206 2190 2207 enhanced-resolve@5.18.3: 2191 2208 dependencies: 2192 2209 graceful-fs: 4.2.11 2193 - tapable: 2.2.3 2210 + tapable: 2.3.0 2194 2211 2195 2212 entities@6.0.1: {} 2196 2213 ··· 2274 2291 globals@15.15.0: {} 2275 2292 2276 2293 graceful-fs@4.2.11: {} 2277 - 2278 - hls.js@1.6.13: {} 2279 2294 2280 2295 html-entities@2.3.3: {} 2281 2296 2282 2297 is-what@4.1.16: {} 2283 2298 2284 - jiti@2.6.0: {} 2299 + jiti@2.6.1: {} 2285 2300 2286 2301 js-tokens@4.0.0: {} 2287 2302 ··· 2323 2338 2324 2339 lightningcss@1.30.1: 2325 2340 dependencies: 2326 - detect-libc: 2.1.0 2341 + detect-libc: 2.1.1 2327 2342 optionalDependencies: 2328 2343 lightningcss-darwin-arm64: 1.30.1 2329 2344 lightningcss-darwin-x64: 1.30.1 ··· 2407 2422 picocolors: 1.1.1 2408 2423 source-map-js: 1.2.1 2409 2424 2410 - prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.2): 2425 + prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3): 2411 2426 dependencies: 2412 2427 prettier: 3.6.2 2413 - typescript: 5.9.2 2428 + typescript: 5.9.3 2414 2429 2415 - prettier-plugin-tailwindcss@0.6.14(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.2))(prettier@3.6.2): 2430 + prettier-plugin-tailwindcss@0.6.14(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3))(prettier@3.6.2): 2416 2431 dependencies: 2417 2432 prettier: 3.6.2 2418 2433 optionalDependencies: 2419 - prettier-plugin-organize-imports: 4.3.0(prettier@3.6.2)(typescript@5.9.2) 2434 + prettier-plugin-organize-imports: 4.3.0(prettier@3.6.2)(typescript@5.9.3) 2420 2435 2421 2436 prettier@3.6.2: {} 2422 2437 ··· 2425 2440 resolve-pkg-maps@1.0.0: 2426 2441 optional: true 2427 2442 2428 - rollup@4.52.0: 2443 + rollup@4.52.3: 2429 2444 dependencies: 2430 2445 '@types/estree': 1.0.8 2431 2446 optionalDependencies: 2432 - '@rollup/rollup-android-arm-eabi': 4.52.0 2433 - '@rollup/rollup-android-arm64': 4.52.0 2434 - '@rollup/rollup-darwin-arm64': 4.52.0 2435 - '@rollup/rollup-darwin-x64': 4.52.0 2436 - '@rollup/rollup-freebsd-arm64': 4.52.0 2437 - '@rollup/rollup-freebsd-x64': 4.52.0 2438 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.0 2439 - '@rollup/rollup-linux-arm-musleabihf': 4.52.0 2440 - '@rollup/rollup-linux-arm64-gnu': 4.52.0 2441 - '@rollup/rollup-linux-arm64-musl': 4.52.0 2442 - '@rollup/rollup-linux-loong64-gnu': 4.52.0 2443 - '@rollup/rollup-linux-ppc64-gnu': 4.52.0 2444 - '@rollup/rollup-linux-riscv64-gnu': 4.52.0 2445 - '@rollup/rollup-linux-riscv64-musl': 4.52.0 2446 - '@rollup/rollup-linux-s390x-gnu': 4.52.0 2447 - '@rollup/rollup-linux-x64-gnu': 4.52.0 2448 - '@rollup/rollup-linux-x64-musl': 4.52.0 2449 - '@rollup/rollup-openharmony-arm64': 4.52.0 2450 - '@rollup/rollup-win32-arm64-msvc': 4.52.0 2451 - '@rollup/rollup-win32-ia32-msvc': 4.52.0 2452 - '@rollup/rollup-win32-x64-gnu': 4.52.0 2453 - '@rollup/rollup-win32-x64-msvc': 4.52.0 2447 + '@rollup/rollup-android-arm-eabi': 4.52.3 2448 + '@rollup/rollup-android-arm64': 4.52.3 2449 + '@rollup/rollup-darwin-arm64': 4.52.3 2450 + '@rollup/rollup-darwin-x64': 4.52.3 2451 + '@rollup/rollup-freebsd-arm64': 4.52.3 2452 + '@rollup/rollup-freebsd-x64': 4.52.3 2453 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.3 2454 + '@rollup/rollup-linux-arm-musleabihf': 4.52.3 2455 + '@rollup/rollup-linux-arm64-gnu': 4.52.3 2456 + '@rollup/rollup-linux-arm64-musl': 4.52.3 2457 + '@rollup/rollup-linux-loong64-gnu': 4.52.3 2458 + '@rollup/rollup-linux-ppc64-gnu': 4.52.3 2459 + '@rollup/rollup-linux-riscv64-gnu': 4.52.3 2460 + '@rollup/rollup-linux-riscv64-musl': 4.52.3 2461 + '@rollup/rollup-linux-s390x-gnu': 4.52.3 2462 + '@rollup/rollup-linux-x64-gnu': 4.52.3 2463 + '@rollup/rollup-linux-x64-musl': 4.52.3 2464 + '@rollup/rollup-openharmony-arm64': 4.52.3 2465 + '@rollup/rollup-win32-arm64-msvc': 4.52.3 2466 + '@rollup/rollup-win32-ia32-msvc': 4.52.3 2467 + '@rollup/rollup-win32-x64-gnu': 4.52.3 2468 + '@rollup/rollup-win32-x64-msvc': 4.52.3 2454 2469 fsevents: 2.3.3 2455 2470 2456 2471 semver@6.3.1: {} ··· 2480 2495 2481 2496 style-mod@4.1.2: {} 2482 2497 2483 - tailwindcss@4.1.13: {} 2498 + tailwindcss@4.1.14: {} 2484 2499 2485 - tapable@2.2.3: {} 2500 + tapable@2.3.0: {} 2486 2501 2487 - tar@7.4.4: 2502 + tar@7.5.1: 2488 2503 dependencies: 2489 2504 '@isaacs/fs-minipass': 4.0.1 2490 2505 chownr: 3.0.0 ··· 2507 2522 fsevents: 2.3.3 2508 2523 optional: true 2509 2524 2510 - typescript@5.9.2: {} 2525 + typescript@5.9.3: {} 2511 2526 2512 2527 ufo@1.6.1: {} 2513 2528 2514 2529 undici-types@6.20.0: 2515 2530 optional: true 2516 2531 2517 - update-browserslist-db@1.1.3(browserslist@4.26.2): 2532 + update-browserslist-db@1.1.3(browserslist@4.26.3): 2518 2533 dependencies: 2519 - browserslist: 4.26.2 2534 + browserslist: 4.26.3 2520 2535 escalade: 3.2.0 2521 2536 picocolors: 1.1.1 2522 2537 2523 2538 validate-html-nesting@1.2.3: {} 2524 2539 2525 - vite-plugin-solid@2.11.8(solid-js@1.9.9)(vite@7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2)): 2540 + vite-plugin-solid@2.11.9(solid-js@1.9.9)(vite@7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)): 2526 2541 dependencies: 2527 2542 '@babel/core': 7.28.4 2528 2543 '@types/babel__core': 7.20.5 ··· 2530 2545 merge-anything: 5.1.7 2531 2546 solid-js: 1.9.9 2532 2547 solid-refresh: 0.6.3(solid-js@1.9.9) 2533 - vite: 7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2) 2534 - vitefu: 1.1.1(vite@7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2)) 2548 + vite: 7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2) 2549 + vitefu: 1.1.1(vite@7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)) 2535 2550 transitivePeerDependencies: 2536 2551 - supports-color 2537 2552 2538 - vite@7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2): 2553 + vite@7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2): 2539 2554 dependencies: 2540 2555 esbuild: 0.25.10 2541 2556 fdir: 6.5.0(picomatch@4.0.3) 2542 2557 picomatch: 4.0.3 2543 2558 postcss: 8.5.6 2544 - rollup: 4.52.0 2559 + rollup: 4.52.3 2545 2560 tinyglobby: 0.2.15 2546 2561 optionalDependencies: 2547 2562 '@types/node': 22.13.1 2548 2563 fsevents: 2.3.3 2549 - jiti: 2.6.0 2564 + jiti: 2.6.1 2550 2565 lightningcss: 1.30.1 2551 2566 tsx: 4.19.2 2552 2567 2553 - vitefu@1.1.1(vite@7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2)): 2568 + vitefu@1.1.1(vite@7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)): 2554 2569 optionalDependencies: 2555 - vite: 7.1.7(@types/node@22.13.1)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.19.2) 2570 + vite: 7.1.8(@types/node@22.13.1)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2) 2556 2571 2557 2572 w3c-keyname@2.2.8: {} 2558 2573
public/headers/aurora.jpg

This is a binary file and will not be displayed.

public/headers/bridge.jpg

This is a binary file and will not be displayed.

public/headers/bunny.jpg

This is a binary file and will not be displayed.

public/headers/city.webp

This is a binary file and will not be displayed.

public/headers/forest.jpg

This is a binary file and will not be displayed.

public/headers/puppy.jpg

This is a binary file and will not be displayed.

public/headers/water.webp

This is a binary file and will not be displayed.

+71 -76
src/components/backlinks.tsx
··· 24 24 const Backlinks = (props: { target: string }) => { 25 25 const fetchBacklinks = async () => { 26 26 const res = await getAllBacklinks(props.target); 27 - setBacklinks(linksBySource(res.links)); 28 - return res; 27 + return linksBySource(res.links); 29 28 }; 30 29 31 30 const [response] = createResource(fetchBacklinks); 32 - const [backlinks, setBacklinks] = createSignal<any>(); 33 31 34 32 const [show, setShow] = createSignal<{ 35 33 collection: string; ··· 38 36 } | null>(); 39 37 40 38 return ( 41 - <Show when={response()}> 42 - <div class="flex w-full flex-col gap-1 text-sm wrap-anywhere"> 43 - <For each={backlinks()}> 44 - {({ collection, path, counts }) => ( 39 + <div class="flex w-full flex-col gap-1 text-sm wrap-anywhere"> 40 + <Show when={response()?.length === 0}> 41 + <p>No backlinks found.</p> 42 + </Show> 43 + <For each={response()}> 44 + {({ collection, path, counts }) => ( 45 + <div> 45 46 <div> 46 - <div> 47 - <div title="Collection containing linking records" class="flex items-center gap-1"> 48 - <span class="iconify lucide--book-text shrink-0"></span> 49 - {collection} 50 - </div> 51 - <div title="Record path where the link is found" class="flex items-center gap-1"> 52 - <span class="iconify lucide--route shrink-0"></span> 53 - {path.slice(1)} 54 - </div> 47 + <div title="Collection containing linking records" class="flex items-center gap-1"> 48 + <span class="iconify lucide--book-text shrink-0"></span> 49 + {collection} 50 + </div> 51 + <div title="Record path where the link is found" class="flex items-center gap-1"> 52 + <span class="iconify lucide--route shrink-0"></span> 53 + {path.slice(1)} 55 54 </div> 56 - <div class="ml-4.5"> 57 - <p> 58 - <button 59 - class="text-blue-400 hover:underline active:underline" 60 - title="Show linking records" 61 - onclick={() => 62 - ( 63 - show()?.collection === collection && 64 - show()?.path === path && 65 - !show()?.showDids 66 - ) ? 67 - setShow(null) 68 - : setShow({ collection, path, showDids: false }) 69 - } 70 - > 71 - {counts.records} record{counts.records < 2 ? "" : "s"} 72 - </button> 73 - {" from "} 74 - <button 75 - class="text-blue-400 hover:underline active:underline" 76 - title="Show linking DIDs" 77 - onclick={() => 78 - ( 79 - show()?.collection === collection && 80 - show()?.path === path && 81 - show()?.showDids 82 - ) ? 83 - setShow(null) 84 - : setShow({ collection, path, showDids: true }) 85 - } 86 - > 87 - {counts.distinct_dids} DID 88 - {counts.distinct_dids < 2 ? "" : "s"} 89 - </button> 90 - </p> 91 - <Show when={show()?.collection === collection && show()?.path === path}> 92 - <Show when={show()?.showDids}> 93 - {/* putting this in the `dids` prop directly failed to re-render. idk how to solidjs. */} 94 - <p class="w-full font-semibold">Distinct identities</p> 95 - <BacklinkItems 96 - target={props.target} 97 - collection={collection} 98 - path={path} 99 - dids={true} 100 - /> 101 - </Show> 102 - <Show when={!show()?.showDids}> 103 - <p class="w-full font-semibold">Records</p> 104 - <BacklinkItems 105 - target={props.target} 106 - collection={collection} 107 - path={path} 108 - dids={false} 109 - /> 110 - </Show> 55 + </div> 56 + <div class="ml-4.5"> 57 + <p> 58 + <button 59 + class="text-blue-400 hover:underline active:underline" 60 + title="Show linking records" 61 + onclick={() => 62 + ( 63 + show()?.collection === collection && 64 + show()?.path === path && 65 + !show()?.showDids 66 + ) ? 67 + setShow(null) 68 + : setShow({ collection, path, showDids: false }) 69 + } 70 + > 71 + {counts.records} record{counts.records < 2 ? "" : "s"} 72 + </button> 73 + {" from "} 74 + <button 75 + class="text-blue-400 hover:underline active:underline" 76 + title="Show linking DIDs" 77 + onclick={() => 78 + show()?.collection === collection && show()?.path === path && show()?.showDids ? 79 + setShow(null) 80 + : setShow({ collection, path, showDids: true }) 81 + } 82 + > 83 + {counts.distinct_dids} DID 84 + {counts.distinct_dids < 2 ? "" : "s"} 85 + </button> 86 + </p> 87 + <Show when={show()?.collection === collection && show()?.path === path}> 88 + <Show when={show()?.showDids}> 89 + {/* putting this in the `dids` prop directly failed to re-render. idk how to solidjs. */} 90 + <p class="w-full font-semibold">Distinct identities</p> 91 + <BacklinkItems 92 + target={props.target} 93 + collection={collection} 94 + path={path} 95 + dids={true} 96 + /> 97 + </Show> 98 + <Show when={!show()?.showDids}> 99 + <p class="w-full font-semibold">Records</p> 100 + <BacklinkItems 101 + target={props.target} 102 + collection={collection} 103 + path={path} 104 + dids={false} 105 + /> 111 106 </Show> 112 - </div> 107 + </Show> 113 108 </div> 114 - )} 115 - </For> 116 - </div> 117 - </Show> 109 + </div> 110 + )} 111 + </For> 112 + </div> 118 113 ); 119 114 }; 120 115
+6 -3
src/components/create.tsx
··· 172 172 ></span> 173 173 <span>{props.create ? "Creating" : "Editing"} record</span> 174 174 </div> 175 - <button onclick={() => setOpenDialog(false)} class="flex items-center"> 176 - <span class="iconify lucide--x text-lg hover:text-neutral-500 dark:hover:text-neutral-400"></span> 175 + <button 176 + onclick={() => setOpenDialog(false)} 177 + class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 178 + > 179 + <span class="iconify lucide--x"></span> 177 180 </button> 178 181 </div> 179 182 <form ref={formRef} class="flex flex-col gap-y-2"> ··· 186 189 <TextInput 187 190 id="collection" 188 191 name="collection" 189 - placeholder="Optional (default: record type)" 192 + placeholder="Optional (default: $type)" 190 193 class="w-[15rem]" 191 194 /> 192 195 </div>
+41 -41
src/components/json.tsx
··· 1 - import { A } from "@solidjs/router"; 2 - import { createEffect, createSignal, For, Show } from "solid-js"; 1 + import { A, useParams } from "@solidjs/router"; 2 + import { createEffect, createSignal, ErrorBoundary, For, Show } from "solid-js"; 3 3 import { hideMedia } from "../views/settings"; 4 4 import { pds } from "./navbar"; 5 5 import Tooltip from "./tooltip"; ··· 47 47 ["http:", "https:", "web+at:"].includes(new URL(part).protocol) && 48 48 part.split("\n").length === 1 49 49 ) ? 50 - <a 51 - class="text-blue-400 hover:underline active:underline" 52 - href={part} 53 - target="_blank" 54 - rel="noopener noreferrer" 55 - > 50 + <a class="underline" href={part} target="_blank" rel="noopener noreferrer"> 56 51 {part} 57 52 </a> 58 53 : part} ··· 77 72 }; 78 73 79 74 const JSONObject = ({ data, repo }: { data: { [x: string]: JSONType }; repo: string }) => { 80 - const [hide, setHide] = createSignal(localStorage.hideMedia === "true"); 75 + const params = useParams(); 76 + const [hide, setHide] = createSignal( 77 + localStorage.hideMedia === "true" || params.rkey === undefined, 78 + ); 81 79 82 - createEffect(() => setHide(hideMedia())); 80 + createEffect(() => { 81 + if (hideMedia()) setHide(hideMedia()); 82 + }); 83 83 84 84 const Obj = ({ key, value }: { key: string; value: JSONType }) => { 85 85 const [show, setShow] = createSignal(true); ··· 130 130 if (blob.$type === "blob") { 131 131 return ( 132 132 <> 133 - <span class="flex gap-x-1"> 134 - <Show when={blob.mimeType.startsWith("image/") && !hide()}> 135 - <a 136 - href={`https://cdn.bsky.app/img/feed_thumbnail/plain/${repo}/${blob.ref.$link}@jpeg`} 137 - target="_blank" 138 - > 133 + <Show when={pds() && params.rkey}> 134 + <span class="flex gap-x-1"> 135 + <Show when={blob.mimeType.startsWith("image/") && !hide()}> 139 136 <img 140 - class="max-h-[16rem] w-full max-w-[16rem]" 141 - src={`https://cdn.bsky.app/img/feed_thumbnail/plain/${repo}/${blob.ref.$link}@jpeg`} 137 + class="max-h-[16rem] w-fit max-w-[16rem]" 138 + src={`https://${pds()}/xrpc/com.atproto.sync.getBlob?did=${repo}&cid=${blob.ref.$link}`} 142 139 /> 143 - </a> 144 - </Show> 145 - <Show when={blob.mimeType === "video/mp4" && !hide()}> 146 - <VideoPlayer did={repo} cid={blob.ref.$link} /> 147 - </Show> 148 - <span 149 - classList={{ "flex items-center justify-between gap-1": true, "flex-col": !hide() }} 150 - > 151 - <Show when={blob.mimeType.startsWith("image/") || blob.mimeType === "video/mp4"}> 152 - <Tooltip text={hide() ? "Show" : "Hide"}> 153 - <button 154 - onclick={() => setHide(!hide())} 155 - class={`${!hide() ? "-mt-1 -ml-0.5" : ""} flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600`} 156 - > 157 - <span 158 - class={`iconify text-base ${hide() ? "lucide--eye-off" : "lucide--eye"}`} 159 - ></span> 160 - </button> 161 - </Tooltip> 140 + </Show> 141 + <Show when={blob.mimeType === "video/mp4" && !hide()}> 142 + <ErrorBoundary fallback={() => <span>Failed to load video</span>}> 143 + <VideoPlayer did={repo} cid={blob.ref.$link} /> 144 + </ErrorBoundary> 162 145 </Show> 163 - <Show when={pds()}> 164 - <Tooltip text="Blob PDS link"> 146 + <span 147 + classList={{ 148 + "flex items-center justify-between gap-1": true, 149 + "flex-col": !hide(), 150 + }} 151 + > 152 + <Show when={blob.mimeType.startsWith("image/") || blob.mimeType === "video/mp4"}> 153 + <Tooltip text={hide() ? "Show" : "Hide"}> 154 + <button 155 + onclick={() => setHide(!hide())} 156 + class={`${!hide() ? "-mt-1 -ml-0.5" : ""} flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600`} 157 + > 158 + <span 159 + class={`iconify text-base ${hide() ? "lucide--eye-off" : "lucide--eye"}`} 160 + ></span> 161 + </button> 162 + </Tooltip> 163 + </Show> 164 + <Tooltip text="Blob on PDS"> 165 165 <a 166 166 href={`https://${pds()}/xrpc/com.atproto.sync.getBlob?did=${repo}&cid=${blob.ref.$link}`} 167 167 target="_blank" ··· 170 170 <span class="iconify lucide--external-link text-base"></span> 171 171 </a> 172 172 </Tooltip> 173 - </Show> 173 + </span> 174 174 </span> 175 - </span> 175 + </Show> 176 176 {rawObj} 177 177 </> 178 178 );
+1 -44
src/components/navbar.tsx
··· 5 5 import Tooltip from "./tooltip"; 6 6 7 7 export const [pds, setPDS] = createSignal<string>(); 8 - export const [cid, setCID] = createSignal<string>(); 9 8 export const [isLabeler, setIsLabeler] = createSignal(false); 10 9 11 - const swapIcons: Record<string, string> = { 12 - "did:plc:vwzwgnygau7ed7b7wt5ux7y2": "lucide--microchip", 13 - "did:plc:oisofpd7lj26yvgiivf3lxsi": "lucide--bone", 14 - "did:plc:uu5axsmbm2or2dngy4gwchec": "lucide--train-track", 15 - "did:plc:7x6rtuenkuvxq3zsvffp2ide": "lucide--rabbit", 16 - "did:plc:ia76kvnndjutgedggx2ibrem": "lucide--rabbit", 17 - "did:plc:hvakvedv6byxhufjl23mfmsd": "lucide--rat", 18 - "did:plc:ezhjhbzqt32bqprrn6qjlkri": "lucide--film", 19 - "did:plc:6v6jqsy7swpzuu53rmzaybjy": "lucide--fish", 20 - "did:plc:hx53snho72xoj7zqt5uice4u": "lucide--rose", 21 - "did:plc:wzsilnxf24ehtmmc3gssy5bu": "lucide--music-2", 22 - "did:plc:bnqkww7bjxaacajzvu5gswdf": "lucide--gem", 23 - "did:plc:hdhoaan3xa3jiuq4fg4mefid": "lucide--sparkles", 24 - }; 25 - 26 10 const NavBar = (props: { params: Params }) => { 27 11 const location = useLocation(); 28 12 const [handle, setHandle] = createSignal(props.params.repo); 29 - const [fullCid, setFullCid] = createSignal(false); 30 13 const [showHandle, setShowHandle] = createSignal(localStorage.showHandle === "true"); 31 - 32 - createEffect(() => { 33 - if (cid() !== undefined) setFullCid(false); 34 - }); 35 14 36 15 createEffect(async () => { 37 16 if (pds() !== undefined && props.params.repo) { ··· 81 60 label="Copy AT URI" 82 61 /> 83 62 </Show> 84 - <Show when={props.params.rkey && cid()}> 85 - <CopyMenu copyContent={cid()!} label="Copy CID" /> 86 - </Show> 87 63 </DropdownMenu> 88 64 </MenuProvider> 89 65 </div> ··· 113 89 }} 114 90 > 115 91 <span 116 - class={ 117 - `iconify shrink-0 text-base transition-transform duration-400 ${showHandle() ? "rotate-y-180" : ""} ` + 118 - (swapIcons[props.params.repo] ?? "lucide--arrow-left-right") 119 - } 92 + class={`iconify shrink-0 text-base transition-transform duration-400 ${showHandle() ? "rotate-y-180" : ""} lucide--arrow-left-right`} 120 93 ></span> 121 94 </button> 122 95 </Tooltip> ··· 167 140 </div> 168 141 </Show> 169 142 </div> 170 - <Show when={props.params.rkey && cid()}> 171 - {(cid) => ( 172 - <div class="mt-1 flex gap-2"> 173 - <Tooltip text="CID"> 174 - <span class="iconify lucide--box text-base"></span> 175 - </Tooltip> 176 - <button 177 - dir="rtl" 178 - classList={{ "bg-transparent text-left": true, truncate: !fullCid() }} 179 - onclick={() => setFullCid(!fullCid())} 180 - > 181 - {cid()} 182 - </button> 183 - </div> 184 - )} 185 - </Show> 186 143 </nav> 187 144 ); 188 145 };
+66 -18
src/components/search.tsx
··· 2 2 import { A, useLocation, useNavigate } from "@solidjs/router"; 3 3 import { createResource, createSignal, For, onCleanup, onMount, Show } from "solid-js"; 4 4 import { isTouchDevice } from "../layout"; 5 + import { appHandleLink, appList, appName, AppUrl } from "../utils/app-urls"; 5 6 import { createDebouncedValue } from "../utils/hooks/debounced"; 7 + import { Modal } from "./modal"; 6 8 7 9 export const [showSearch, setShowSearch] = createSignal(false); 8 10 ··· 66 68 input = input.trim().replace(/^@/, ""); 67 69 if (!input.length) return; 68 70 setShowSearch(false); 69 - if (input === "me" && localStorage.getItem("lastSignedIn") !== null) { 70 - navigate(`/at://${localStorage.getItem("lastSignedIn")}`); 71 - } else if ( 72 - !input.startsWith("https://bsky.app/") && 73 - (input.startsWith("https://") || input.startsWith("http://")) 74 - ) { 75 - navigate(`/${input.replace("https://", "").replace("http://", "").replace("/", "")}`); 76 - } else if (search()?.length) { 71 + if (search()?.length) { 77 72 navigate(`/at://${search()![0].did}`); 73 + } else if (input.startsWith("https://") || input.startsWith("http://")) { 74 + const hostLength = input.indexOf("/", 8); 75 + const host = input.slice(0, hostLength).replace("https://", "").replace("http://", ""); 76 + 77 + if (!(host in appList)) { 78 + navigate(`/${input.replace("https://", "").replace("http://", "").replace("/", "")}`); 79 + } else { 80 + const app = appList[host as AppUrl]; 81 + const path = input.slice(hostLength + 1).split("/"); 82 + 83 + const uri = appHandleLink[app](path); 84 + navigate(`/${uri}`); 85 + } 78 86 } else { 79 - const uri = input 80 - .replace("at://", "") 81 - .replace("https://bsky.app/profile/", "") 82 - .replace("/post/", "/app.bsky.feed.post/"); 83 - const uriParts = uri.split("/"); 84 - navigate( 85 - `/at://${uriParts[0]}${uriParts.length > 1 ? `/${uriParts.slice(1).join("/")}` : ""}`, 86 - ); 87 + navigate(`/at://${input.replace("at://", "")}`); 87 88 } 88 - setShowSearch(false); 89 89 }; 90 90 91 91 return ( ··· 114 114 value={input() ?? ""} 115 115 onInput={(e) => setInput(e.currentTarget.value)} 116 116 /> 117 - <Show when={input()}> 117 + <Show when={input()} fallback={ListUrlsTooltip()}> 118 118 <button 119 119 type="button" 120 120 class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-600 dark:active:bg-neutral-500" ··· 144 144 </div> 145 145 </Show> 146 146 </form> 147 + ); 148 + }; 149 + 150 + const ListUrlsTooltip = () => { 151 + const [openList, setOpenList] = createSignal(false); 152 + 153 + let urls: Record<string, AppUrl[]> = {}; 154 + for (const [appUrl, appView] of Object.entries(appList)) { 155 + if (!urls[appView]) urls[appView] = [appUrl as AppUrl]; 156 + else urls[appView].push(appUrl as AppUrl); 157 + } 158 + 159 + return ( 160 + <> 161 + <Modal open={openList()} onClose={() => setOpenList(false)}> 162 + <div class="dark:bg-dark-300 dark:shadow-dark-800 absolute top-16 left-[50%] w-[26rem] -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 dark:border-neutral-700 starting:opacity-0"> 163 + <div class="mb-2 flex items-center gap-1 font-semibold"> 164 + <span class="iconify lucide--link"></span> 165 + <span>Supported URLs</span> 166 + </div> 167 + <div class="mb-2 text-sm text-neutral-500 dark:text-neutral-400"> 168 + Links that will be parsed automatically, as long as all the data necessary is on the 169 + URL. 170 + </div> 171 + <div class="flex flex-col gap-2 text-sm"> 172 + <For each={Object.entries(appName)}> 173 + {([appView, name]) => { 174 + return ( 175 + <div> 176 + <p class="font-semibold">{name}</p> 177 + <div class="grid grid-cols-2 gap-x-4 text-neutral-600 dark:text-neutral-400"> 178 + <For each={urls[appView]}>{(url) => <span>{url}</span>}</For> 179 + </div> 180 + </div> 181 + ); 182 + }} 183 + </For> 184 + </div> 185 + </div> 186 + </Modal> 187 + <button 188 + type="button" 189 + class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-600 dark:active:bg-neutral-500" 190 + onClick={() => setOpenList(true)} 191 + > 192 + <span class="iconify lucide--help-circle"></span> 193 + </button> 194 + </> 147 195 ); 148 196 }; 149 197
+13 -68
src/components/video-player.tsx
··· 1 - // courtesy of the best ๐Ÿ‡, my lovely sister mary 2 - import Hls from "hls.js"; 3 - import { createEffect, createSignal, onCleanup, Show } from "solid-js"; 1 + import { onMount } from "solid-js"; 2 + import { pds } from "./navbar"; 4 3 5 4 export interface VideoPlayerProps { 6 - /** Expected to be static */ 7 5 did: string; 8 6 cid: string; 9 7 } 10 8 11 9 const VideoPlayer = ({ did, cid }: VideoPlayerProps) => { 12 - const [playing, setPlaying] = createSignal(false); 13 - const [error, setError] = createSignal(false); 10 + let video!: HTMLVideoElement; 14 11 15 - const hls = new Hls({ 16 - capLevelToPlayerSize: true, 17 - startLevel: 1, 18 - xhrSetup(xhr, urlString) { 19 - const url = new URL(urlString); 20 - 21 - // Just in case it fails, we'll remove `session_id` everywhere 22 - url.searchParams.delete("session_id"); 23 - 24 - xhr.open("get", url.toString()); 25 - }, 12 + onMount(async () => { 13 + // thanks bf <3 14 + const res = await fetch(`https://${pds()}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}`); 15 + if (!res.ok) throw new Error(res.statusText); 16 + const blob = await res.blob(); 17 + const url = URL.createObjectURL(blob); 18 + if (video) video.src = url; 26 19 }); 27 20 28 - onCleanup(() => hls.destroy()); 29 - 30 - hls.loadSource(`https://video.cdn.bsky.app/hls/${did}/${cid}/playlist.m3u8`); 31 - hls.on(Hls.Events.ERROR, () => setError(true)); 32 - 33 21 return ( 34 - <div class="max-w-xs"> 35 - <Show when={!error()}> 36 - <video 37 - ref={(node) => { 38 - hls.attachMedia(node); 39 - 40 - createEffect(() => { 41 - if (!playing()) { 42 - return; 43 - } 44 - 45 - const observer = new IntersectionObserver( 46 - (entries) => { 47 - const entry = entries[0]; 48 - if (!entry.isIntersecting) { 49 - node.pause(); 50 - } 51 - }, 52 - { threshold: 0.5 }, 53 - ); 54 - 55 - onCleanup(() => observer.disconnect()); 56 - 57 - observer.observe(node); 58 - }); 59 - }} 60 - controls 61 - playsinline 62 - onPlay={() => setPlaying(true)} 63 - onPause={() => setPlaying(false)} 64 - onLoadedMetadata={(ev) => { 65 - const video = ev.currentTarget; 66 - 67 - const hasAudio = 68 - // @ts-expect-error: Mozilla-specific 69 - video.mozHasAudio || 70 - // @ts-expect-error: WebKit/Blink-specific 71 - !!video.webkitAudioDecodedByteCount || 72 - // @ts-expect-error: WebKit-specific 73 - !!(video.audioTracks && video.audioTracks.length); 74 - 75 - video.loop = !hasAudio || video.duration <= 6; 76 - }} 77 - /> 78 - </Show> 79 - </div> 22 + <video ref={video} class="max-h-[20rem] max-w-[20rem]" controls playsinline> 23 + <source type="video/mp4" /> 24 + </video> 80 25 ); 81 26 }; 82 27
+17 -5
src/layout.tsx
··· 19 19 text?: string; 20 20 }>({ show: false }); 21 21 22 + const headers: Record<string, string> = { 23 + "did:plc:ia76kvnndjutgedggx2ibrem": "bunny.jpg", 24 + "did:plc:oisofpd7lj26yvgiivf3lxsi": "puppy.jpg", 25 + "did:plc:vwzwgnygau7ed7b7wt5ux7y2": "water.webp", 26 + "did:plc:uu5axsmbm2or2dngy4gwchec": "city.webp", 27 + "did:plc:aokggmp5jzj4nc5jifhiplqc": "bridge.jpg", 28 + "did:plc:bnqkww7bjxaacajzvu5gswdf": "forest.jpg", 29 + "did:plc:p2cp5gopk7mgjegy6wadk3ep": "aurora.jpg", 30 + }; 31 + 22 32 const Layout = (props: RouteSectionProps<unknown>) => { 23 33 const location = useLocation(); 24 34 const navigate = useNavigate(); ··· 56 66 </Show> 57 67 </MetaProvider> 58 68 <header 59 - classList={{ 60 - "dark:shadow-dark-800 dark:bg-dark-300 mb-4 flex w-full items-center justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-2 shadow-xs dark:border-neutral-700": true, 61 - "bg-[linear-gradient(to_left,transparent_0%,#fafafa_80%),linear-gradient(to_bottom,#5BCEFA90_0%,#5BCEFA90_20%,#F5A9B890_20%,#F5A9B890_40%,#FFFFFF90_40%,#FFFFFF90_60%,#F5A9B890_60%,#F5A9B890_80%,#5BCEFA90_80%,#5BCEFA90_100%)] dark:bg-[linear-gradient(to_left,transparent_0%,#2d2d2d_80%),linear-gradient(to_bottom,#5BCEFA90_0%,#5BCEFA90_20%,#F5A9B890_20%,#F5A9B890_40%,#FFFFFF90_40%,#FFFFFF90_60%,#F5A9B890_60%,#F5A9B890_80%,#5BCEFA90_80%,#5BCEFA90_100%)]": 62 - localStorage.getItem("hrt") === "true", 69 + class={`dark:shadow-dark-800 dark:bg-dark-300 mb-4 flex w-full items-center justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 bg-size-[95%] bg-right bg-no-repeat p-2 shadow-xs [--header-bg:#fafafa] dark:border-neutral-700 dark:[--header-bg:#2d2d2d] ${localStorage.getItem("hrt") === "true" ? "bg-[linear-gradient(to_left,transparent_10%,var(--header-bg)_85%),linear-gradient(to_bottom,#5BCEFA90_0%,#5BCEFA90_20%,#F5A9B890_20%,#F5A9B890_40%,#FFFFFF90_40%,#FFFFFF90_60%,#F5A9B890_60%,#F5A9B890_80%,#5BCEFA90_80%,#5BCEFA90_100%)]" : ""}`} 70 + style={{ 71 + "background-image": 72 + props.params.repo in headers ? 73 + `linear-gradient(to left, transparent 10%, var(--header-bg) 85%), url(/headers/${headers[props.params.repo]})` 74 + : undefined, 63 75 }} 64 76 > 65 77 <A ··· 70 82 <span class="iconify tabler--binary-tree-filled text-[#76c4e5]"></span> 71 83 <span>PDSls</span> 72 84 </A> 73 - <div class="dark:bg-dark-300/50 relative -mr-1 flex items-center gap-1 rounded-lg bg-neutral-50/50"> 85 + <div class="dark:bg-dark-300/60 relative -mr-1 flex items-center gap-1 rounded-lg bg-neutral-50/60"> 74 86 <Show when={location.pathname !== "/"}> 75 87 <SearchButton /> 76 88 </Show>
+11 -1
src/utils/api.ts
··· 13 13 PlcDidDocumentResolver, 14 14 WellKnownHandleResolver, 15 15 } from "@atcute/identity-resolver"; 16 + import { DohJsonLexiconAuthorityResolver } from "@atcute/lexicon-resolver"; 16 17 import { Did, Handle } from "@atcute/lexicons"; 17 - import { isHandle } from "@atcute/lexicons/syntax"; 18 + import { isHandle, Nsid } from "@atcute/lexicons/syntax"; 18 19 import { createStore } from "solid-js/store"; 19 20 import { setPDS } from "../components/navbar"; 20 21 ··· 35 36 }, 36 37 }); 37 38 39 + const authorityResolver = new DohJsonLexiconAuthorityResolver({ 40 + dohUrl: "https://mozilla.cloudflare-dns.com/dns-query", 41 + }); 42 + 38 43 const didPDSCache: Record<string, string> = {}; 39 44 const [labelerCache, setLabelerCache] = createStore<Record<string, string>>({}); 40 45 const didDocCache: Record<string, DidDocument> = {}; ··· 99 104 return pds; 100 105 }; 101 106 107 + const resolveLexiconAuthority = async (nsid: Nsid) => { 108 + return await authorityResolver.resolve(nsid); 109 + }; 110 + 102 111 interface LinkData { 103 112 links: { 104 113 [key: string]: { ··· 162 171 labelerCache, 163 172 resolveDidDoc, 164 173 resolveHandle, 174 + resolveLexiconAuthority, 165 175 resolvePDS, 166 176 validateHandle, 167 177 type LinkData,
+119
src/utils/app-urls.ts
··· 1 + export type AppUrl = `${string}.${string}` | `localhost:${number}`; 2 + 3 + export enum App { 4 + Bluesky, 5 + Tangled, 6 + Whitewind, 7 + Frontpage, 8 + Pinksea, 9 + Linkat, 10 + } 11 + 12 + export const appName = { 13 + [App.Bluesky]: "Bluesky", 14 + [App.Tangled]: "Tangled", 15 + [App.Whitewind]: "Whitewind", 16 + [App.Frontpage]: "Frontpage", 17 + [App.Pinksea]: "Pinksea", 18 + [App.Linkat]: "Linkat", 19 + }; 20 + 21 + export const appList: Record<AppUrl, App> = { 22 + "localhost:19006": App.Bluesky, 23 + "blacksky.community": App.Bluesky, 24 + "bsky.app": App.Bluesky, 25 + "catsky.social": App.Bluesky, 26 + "deer.aylac.top": App.Bluesky, 27 + "deer-social-ayla.pages.dev": App.Bluesky, 28 + "deer.social": App.Bluesky, 29 + "main.bsky.dev": App.Bluesky, 30 + "social.daniela.lol": App.Bluesky, 31 + "tangled.org": App.Tangled, 32 + "whtwnd.com": App.Whitewind, 33 + "frontpage.fyi": App.Frontpage, 34 + "pinksea.art": App.Pinksea, 35 + "linkat.blue": App.Linkat, 36 + }; 37 + 38 + export const appHandleLink: Record<App, (url: string[]) => string> = { 39 + [App.Bluesky]: (path) => { 40 + const baseType = path[0]; 41 + const user = path[1]; 42 + 43 + if (baseType === "profile") { 44 + if (path[2]) { 45 + const type = path[2]; 46 + const rkey = path[3]; 47 + 48 + if (type === "post") { 49 + return `at://${user}/app.bsky.feed.post/${rkey}`; 50 + } else if (type === "list") { 51 + return `at://${user}/app.bsky.graph.list/${rkey}`; 52 + } else if (type === "feed") { 53 + return `at://${user}/app.bsky.feed.generator/${rkey}`; 54 + } else if (type === "follows") { 55 + return `at://${user}/app.bsky.graph.follow/${rkey}`; 56 + } 57 + } else { 58 + return `at://${user}`; 59 + } 60 + } else if (baseType === "starter-pack") { 61 + return `at://${user}/app.bsky.graph.starterpack/${path[2]}`; 62 + } 63 + return `at://${user}`; 64 + }, 65 + [App.Tangled]: (path) => { 66 + if (path[0] === "strings") { 67 + return `at://${path[1]}/sh.tangled.string/${path[2]}`; 68 + } 69 + 70 + let query: string | undefined; 71 + if (path[path.length - 1].includes("?")) { 72 + const split = path[path.length - 1].split("?"); 73 + query = split[1]; 74 + path[path.length - 1] = split[0]; 75 + } 76 + 77 + const user = path[0].replace("@", ""); 78 + 79 + if (path.length === 1) { 80 + if (query === "tab=repos") { 81 + return `at://${user}/sh.tangled.repo`; 82 + } else if (query === "tab=starred") { 83 + return `at://${user}/sh.tangled.feed.star`; 84 + } else if (query === "tab=strings") { 85 + return `at://${user}/sh.tangled.string`; 86 + } 87 + } else if (path.length === 2) { 88 + // no way to convert the repo name to an rkey afaik 89 + // same reason why there's nothing related to issues in here 90 + return `at://${user}/sh.tangled.repo`; 91 + } 92 + 93 + return `at://${user}`; 94 + }, 95 + [App.Whitewind]: (path) => { 96 + if (path.length === 2) { 97 + return `at://${path[0]}/com.whtwnd.blog.entry/${path[1]}`; 98 + } 99 + 100 + return `at://${path[0]}/com.whtwnd.blog.entry`; 101 + }, 102 + [App.Frontpage]: (path) => { 103 + if (path.length === 3) { 104 + return `at://${path[1]}/fyi.unravel.frontpage.post/${path[2]}`; 105 + } else if (path.length === 5) { 106 + return `at://${path[3]}/fyi.unravel.frontpage.comment/${path[4]}`; 107 + } 108 + 109 + return `at://${path[0]}`; 110 + }, 111 + [App.Pinksea]: (path) => { 112 + if (path.length === 2) { 113 + return `at://${path[0]}/com.shinolabs.pinksea.oekaki/${path[1]}`; 114 + } 115 + 116 + return `at://${path[0]}`; 117 + }, 118 + [App.Linkat]: (path) => `at://${path[0]}/blue.linkat.board/self`, 119 + };
+15 -7
src/views/collection.tsx
··· 18 18 19 19 interface AtprotoRecord { 20 20 rkey: string; 21 + cid: string; 21 22 record: InferXRPCBodyOutput<ComAtprotoRepoGetRecord.mainSchema["output"]>; 22 23 timestamp: number | undefined; 23 24 toDelete: boolean; ··· 40 41 41 42 return ( 42 43 <span 43 - class="relative flex items-baseline rounded px-0.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 44 + class="relative flex w-full min-w-0 items-baseline rounded px-0.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 44 45 ref={rkeyRef} 45 46 onmouseover={() => setHover(true)} 46 47 onmouseleave={() => setHover(false)} 47 48 > 48 - <span class="text-sm text-blue-400 sm:text-base">{props.record.rkey}</span> 49 - <Show when={props.record.timestamp && props.record.timestamp <= Date.now()}> 50 - <span class="ml-1 text-xs text-neutral-500 dark:text-neutral-400"> 51 - {localDateFromTimestamp(props.record.timestamp!)} 49 + <span class="flex items-baseline truncate"> 50 + <span class="shrink-0 text-sm text-blue-400 sm:text-base">{props.record.rkey}</span> 51 + <span class="ml-1 truncate text-xs text-neutral-500 dark:text-neutral-400" dir="rtl"> 52 + {props.record.cid} 52 53 </span> 53 - </Show> 54 + <Show when={props.record.timestamp && props.record.timestamp <= Date.now()}> 55 + <span class="ml-1 shrink-0 text-xs"> 56 + {localDateFromTimestamp(props.record.timestamp!)} 57 + </span> 58 + </Show> 59 + </span> 54 60 <Show when={hover()}> 55 61 <span 56 62 ref={previewRef} ··· 99 105 const rkey = record.uri.split("/").pop()!; 100 106 tmpRecords.push({ 101 107 rkey: rkey, 108 + cid: record.cid, 102 109 record: record, 103 110 timestamp: TID.validate(rkey) ? TID.parse(rkey).timestamp / 1000 : undefined, 104 111 toDelete: false, ··· 277 284 </A> 278 285 </Tooltip> 279 286 <TextInput 287 + name="Filter" 280 288 placeholder="Filter by substring" 281 289 onInput={(e) => setFilter(e.currentTarget.value)} 282 290 class="grow" ··· 318 326 </Show> 319 327 </div> 320 328 </StickyOverlay> 321 - <div class="flex max-w-full flex-col font-mono"> 329 + <div class="flex max-w-full flex-col px-2 font-mono"> 322 330 <For 323 331 each={records.filter((rec) => 324 332 filter() ? JSON.stringify(rec.record.value).includes(filter()!) : true,
+2 -10
src/views/home.tsx
··· 9 9 <div class="iconify lucide--search" /> 10 10 <span> 11 11 Browse the public data on{" "} 12 - <a 13 - class="text-blue-400 hover:underline active:underline" 14 - href="https://atproto.com" 15 - target="_blank" 16 - > 12 + <a class="underline" href="https://atproto.com" target="_blank"> 17 13 atproto 18 14 </a> 19 15 . ··· 31 27 <div class="iconify lucide--send-to-back" /> 32 28 <span> 33 29 Backlinks support with{" "} 34 - <a 35 - href="https://constellation.microcosm.blue" 36 - class="text-blue-400 hover:underline active:underline" 37 - target="_blank" 38 - > 30 + <a href="https://constellation.microcosm.blue" class="underline" target="_blank"> 39 31 constellation 40 32 </a> 41 33 .
+1 -1
src/views/pds.tsx
··· 52 52 <div class="flex items-center"> 53 53 <A 54 54 href={`/at://${repo.did}`} 55 - class="grow truncate rounded py-0.5 font-mono text-blue-400 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 55 + class="grow truncate rounded py-0.5 font-mono hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 56 56 > 57 57 {repo.did} 58 58 </A>
+99 -58
src/views/record.tsx
··· 1 1 import { Client, CredentialManager } from "@atcute/client"; 2 2 import { lexiconDoc } from "@atcute/lexicon-doc"; 3 - import { ActorIdentifier, is, ResourceUri } from "@atcute/lexicons"; 3 + import { ActorIdentifier, is, Nsid, ResourceUri } from "@atcute/lexicons"; 4 4 import { A, useLocation, useNavigate, useParams } from "@solidjs/router"; 5 5 import { createResource, createSignal, ErrorBoundary, Show, Suspense } from "solid-js"; 6 6 import { Backlinks } from "../components/backlinks.jsx"; ··· 10 10 import { JSONValue } from "../components/json.jsx"; 11 11 import { agent } from "../components/login.jsx"; 12 12 import { Modal } from "../components/modal.jsx"; 13 - import { pds, setCID } from "../components/navbar.jsx"; 13 + import { pds } from "../components/navbar.jsx"; 14 14 import Tooltip from "../components/tooltip.jsx"; 15 15 import { setNotif } from "../layout.jsx"; 16 - import { didDocCache, resolvePDS } from "../utils/api.js"; 16 + import { didDocCache, resolveLexiconAuthority, resolvePDS } from "../utils/api.js"; 17 17 import { AtUri, uriTemplates } from "../utils/templates.js"; 18 18 import { lexicons } from "../utils/types/lexicons.js"; 19 19 import { verifyRecord } from "../utils/verify.js"; ··· 27 27 const [externalLink, setExternalLink] = createSignal< 28 28 { label: string; link: string; icon?: string } | undefined 29 29 >(); 30 + const [lexiconUri, setLexiconUri] = createSignal<string>(); 30 31 const [validRecord, setValidRecord] = createSignal<boolean | undefined>(undefined); 31 32 const [validSchema, setValidSchema] = createSignal<boolean | undefined>(undefined); 32 33 const did = params.repo; 33 34 let rpc: Client; 34 35 35 36 const fetchRecord = async () => { 36 - setCID(undefined); 37 37 setValidRecord(undefined); 38 38 setValidSchema(undefined); 39 + setLexiconUri(undefined); 39 40 const pds = await resolvePDS(did); 40 41 rpc = new Client({ handler: new CredentialManager({ service: pds }) }); 41 42 const res = await rpc.get("com.atproto.repo.getRecord", { ··· 50 51 setNotice(res.data.error); 51 52 throw new Error(res.data.error); 52 53 } 53 - setCID(res.data.cid); 54 54 setExternalLink(checkUri(res.data.uri, res.data.value)); 55 + resolveLexicon(params.collection as Nsid); 55 56 verify(res.data); 56 57 57 58 return res.data; ··· 94 95 } 95 96 }; 96 97 98 + const resolveLexicon = async (nsid: Nsid) => { 99 + try { 100 + const res = await resolveLexiconAuthority(nsid); 101 + setLexiconUri(`at://${res}/com.atproto.lexicon.schema/${nsid}`); 102 + } catch {} 103 + }; 104 + 97 105 const [record, { refetch }] = createResource(fetchRecord); 98 106 99 107 const deleteRecord = async () => { ··· 119 127 return template(parsedUri, record); 120 128 }; 121 129 130 + const RecordTab = (props: { 131 + tab: "record" | "backlinks" | "info"; 132 + label: string; 133 + error?: boolean; 134 + }) => ( 135 + <div class="flex items-center gap-0.5"> 136 + <A 137 + classList={{ 138 + "flex items-center gap-1 border-b-2": true, 139 + "border-transparent hover:border-neutral-400 dark:hover:border-neutral-600": 140 + (!!location.hash && location.hash !== `#${props.tab}`) || 141 + (!location.hash && props.tab !== "record"), 142 + }} 143 + href={`/at://${did}/${params.collection}/${params.rkey}#${props.tab}`} 144 + > 145 + {props.label} 146 + </A> 147 + <Show when={props.error && (validRecord() === false || validSchema() === false)}> 148 + <span class="iconify lucide--x text-red-500 dark:text-red-400"></span> 149 + </Show> 150 + </div> 151 + ); 152 + 122 153 return ( 123 154 <Show when={record()} keyed> 124 155 <div class="flex w-full flex-col items-center"> 125 - <div class="dark:shadow-dark-800 dark:bg-dark-300 mb-3 flex w-full justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 px-2 py-1.5 shadow-xs dark:border-neutral-700"> 126 - <div class="flex gap-3 text-sm"> 127 - <A 128 - classList={{ 129 - "flex items-center gap-1 border-b-2": true, 130 - "border-transparent hover:border-neutral-400 dark:hover:border-neutral-600": 131 - !!location.hash && location.hash !== "#record", 132 - }} 133 - href={`/at://${did}/${params.collection}/${params.rkey}#record`} 134 - > 135 - <div class="iconify lucide--file-json" /> 136 - Record 137 - </A> 138 - <A 139 - classList={{ 140 - "flex items-center gap-1 border-b-2": true, 141 - "border-transparent hover:border-neutral-400 dark:hover:border-neutral-600": 142 - location.hash !== "#backlinks", 143 - }} 144 - href={`/at://${did}/${params.collection}/${params.rkey}#backlinks`} 145 - > 146 - <div class="iconify lucide--send-to-back" /> 147 - Backlinks 148 - </A> 156 + <div class="dark:shadow-dark-800 dark:bg-dark-300 mb-3 flex w-full justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 px-2 py-1.5 text-sm shadow-xs dark:border-neutral-700"> 157 + <div class="flex gap-3"> 158 + <RecordTab tab="record" label="Record" /> 159 + <RecordTab tab="backlinks" label="Backlinks" /> 160 + <RecordTab tab="info" label="Info" error /> 149 161 </div> 150 162 <div class="flex gap-1"> 151 - <div class="mr-1 flex gap-3"> 152 - <Tooltip 153 - text={ 154 - validRecord() === undefined ? "Validating" 155 - : validRecord() === false ? 156 - "Invalid record" 157 - : "Valid record" 158 - } 159 - > 160 - <span 161 - classList={{ 162 - "iconify lucide--lock-keyhole": validRecord() === true, 163 - "iconify lucide--lock-keyhole-open text-red-500 dark:text-red-400": 164 - validRecord() === false, 165 - "iconify lucide--loader-circle animate-spin": validRecord() === undefined, 166 - }} 167 - ></span> 168 - </Tooltip> 169 - <Show when={validSchema() !== undefined}> 170 - <Tooltip text={validSchema() ? "Valid schema" : "Invalid schema"}> 171 - <span 172 - class={`iconify ${validSchema() ? "lucide--file-check" : "lucide--file-x text-red-500 dark:text-red-400"}`} 173 - ></span> 174 - </Tooltip> 175 - </Show> 176 - </div> 177 163 <Show when={agent() && agent()?.sub === record()?.uri.split("/")[2]}> 178 164 <RecordEditor create={false} record={record()?.value} refetch={refetch} /> 179 165 <Tooltip text="Delete"> ··· 210 196 label="Copy record" 211 197 icon="lucide--copy" 212 198 /> 199 + <Show when={record()?.cid}> 200 + {(cid) => <CopyMenu copyContent={cid()} label="Copy CID" icon="lucide--copy" />} 201 + </Show> 202 + <Show when={lexiconUri()}> 203 + <NavMenu 204 + href={`/${lexiconUri()}`} 205 + icon="lucide--scroll-text" 206 + label="Lexicon schema" 207 + /> 208 + </Show> 213 209 <Show when={externalLink()}> 214 210 {(externalLink) => ( 215 211 <NavMenu ··· 231 227 </div> 232 228 </div> 233 229 <Show when={!location.hash || location.hash === "#record"}> 234 - <Show when={validRecord() === false}> 235 - <div class="mb-2 break-words text-red-500 dark:text-red-400">{notice()}</div> 236 - </Show> 237 230 <div class="w-max max-w-screen min-w-full px-4 font-mono text-xs wrap-anywhere whitespace-pre-wrap sm:px-2 sm:text-sm md:max-w-[48rem]"> 238 231 <JSONValue data={record()?.value as any} repo={record()!.uri.split("/")[2]} /> 239 232 </div> ··· 250 243 </div> 251 244 </Suspense> 252 245 </ErrorBoundary> 246 + </Show> 247 + <Show when={location.hash === "#info"}> 248 + <div class="flex w-full flex-col gap-2 px-2 text-sm"> 249 + <div> 250 + <div class="flex items-center gap-1"> 251 + <span class="iconify lucide--at-sign"></span> 252 + <p class="font-semibold">AT URI</p> 253 + </div> 254 + <div class="truncate text-xs">{record()?.uri}</div> 255 + </div> 256 + <Show when={record()?.cid}> 257 + <div> 258 + <div class="flex items-center gap-1"> 259 + <span class="iconify lucide--box"></span> 260 + <p class="font-semibold">CID</p> 261 + </div> 262 + <div class="truncate text-left text-xs" dir="rtl"> 263 + {record()?.cid} 264 + </div> 265 + </div> 266 + </Show> 267 + <div> 268 + <div class="flex items-center gap-1"> 269 + <span class="iconify lucide--lock-keyhole"></span> 270 + <p class="font-semibold">Record verification</p> 271 + <span 272 + classList={{ 273 + "iconify lucide--check text-green-500 dark:text-green-400": 274 + validRecord() === true, 275 + "iconify lucide--x text-red-500 dark:text-red-400": validRecord() === false, 276 + "iconify lucide--loader-circle animate-spin": validRecord() === undefined, 277 + }} 278 + ></span> 279 + </div> 280 + <Show when={validRecord() === false}> 281 + <div class="break-words">{notice()}</div> 282 + </Show> 283 + </div> 284 + <Show when={validSchema() !== undefined}> 285 + <div class="flex items-center gap-1"> 286 + <span class="iconify lucide--file-check"></span> 287 + <p class="font-semibold">Schema validation</p> 288 + <span 289 + class={`iconify ${validSchema() ? "lucide--check text-green-500 dark:text-green-400" : "lucide--x text-red-500 dark:text-red-400"}`} 290 + ></span> 291 + </div> 292 + </Show> 293 + </div> 253 294 </Show> 254 295 </div> 255 296 </Show>
+52 -88
src/views/repo.tsx
··· 3 3 import { DidDocument } from "@atcute/identity"; 4 4 import { ActorIdentifier, Did, Handle } from "@atcute/lexicons"; 5 5 import { A, useLocation, useNavigate, useParams } from "@solidjs/router"; 6 - import { 7 - createEffect, 8 - createResource, 9 - createSignal, 10 - ErrorBoundary, 11 - For, 12 - Show, 13 - Suspense, 14 - } from "solid-js"; 6 + import { createResource, createSignal, ErrorBoundary, For, Show, Suspense } from "solid-js"; 15 7 import { createStore } from "solid-js/store"; 16 8 import { Backlinks } from "../components/backlinks.jsx"; 17 9 import { ActionMenu, DropdownMenu, MenuProvider, NavMenu } from "../components/dropdown.jsx"; ··· 21 13 import { BlobView } from "./blob.jsx"; 22 14 import { PlcLogView } from "./logs.jsx"; 23 15 24 - type Tab = "collections" | "backlinks" | "identity" | "blobs" | "logs"; 25 - const RepoView = () => { 16 + export const RepoView = () => { 26 17 const params = useParams(); 27 18 const location = useLocation(); 28 19 const navigate = useNavigate(); ··· 36 27 let pds: string; 37 28 const did = params.repo; 38 29 39 - const RepoTab = (props: { tab: Tab; label: string }) => ( 30 + const RepoTab = (props: { 31 + tab: "collections" | "backlinks" | "identity" | "blobs" | "logs"; 32 + label: string; 33 + }) => ( 40 34 <A class="group flex justify-center" href={`/at://${params.repo}#${props.tab}`}> 41 35 <span 42 36 classList={{ ··· 63 57 } 64 58 } 65 59 setDidDoc(didDocCache[did] as DidDocument); 60 + validateHandles(); 66 61 67 62 rpc = new Client({ handler: new CredentialManager({ service: pds }) }); 68 63 const res = await rpc.get("com.atproto.repo.describeRepo", { ··· 101 96 102 97 const [repo] = createResource(fetchRepo); 103 98 99 + const validateHandles = async () => { 100 + for (const alias of didDoc()?.alsoKnownAs ?? []) { 101 + if (alias.startsWith("at://")) 102 + setValidHandles( 103 + alias, 104 + await validateHandle(alias.replace("at://", "") as Handle, did as Did), 105 + ); 106 + } 107 + }; 108 + 104 109 const downloadRepo = async () => { 105 110 try { 106 111 setDownloading(true); ··· 125 130 setDownloading(false); 126 131 }; 127 132 128 - const toggleCollection = (authority: string) => { 129 - setNsids({ 130 - ...nsids(), 131 - [authority]: { ...nsids()![authority], hidden: !nsids()![authority].hidden }, 132 - }); 133 - }; 134 - 135 - createEffect(async () => { 136 - for (const alias of didDoc()?.alsoKnownAs ?? []) { 137 - if (alias.startsWith("at://")) 138 - setValidHandles( 139 - alias, 140 - await validateHandle(alias.replace("at://", "") as Handle, did as Did), 141 - ); 142 - } 143 - }); 144 - 145 133 return ( 146 134 <Show when={repo()}> 147 135 <div class="flex w-full flex-col gap-2 break-words"> 148 136 <div 149 - class={`dark:shadow-dark-800 dark:bg-dark-300 flex justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 px-2 py-1.5 shadow-xs dark:border-neutral-700`} 137 + class={`dark:shadow-dark-800 dark:bg-dark-300 flex justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 px-2 py-1.5 text-sm shadow-xs dark:border-neutral-700`} 150 138 > 151 - <div class="flex gap-2 text-sm sm:gap-4"> 139 + <div class="flex gap-2 sm:gap-4"> 152 140 <Show when={!error()}> 153 141 <RepoTab tab="collections" label="Collections" /> 154 142 </Show> ··· 195 183 <ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}> 196 184 <Suspense 197 185 fallback={ 198 - <div class="iconify lucide--loader-circle animate-spin self-center text-xl" /> 186 + <div class="iconify lucide--loader-circle mt-2 animate-spin self-center text-xl" /> 199 187 } 200 188 > 201 189 <PlcLogView did={did} /> ··· 206 194 <ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}> 207 195 <Suspense 208 196 fallback={ 209 - <div class="iconify lucide--loader-circle animate-spin self-center text-xl" /> 197 + <div class="iconify lucide--loader-circle mt-2 animate-spin self-center text-xl" /> 210 198 } 211 199 > 212 200 <Backlinks target={did} /> ··· 217 205 <ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}> 218 206 <Suspense 219 207 fallback={ 220 - <div class="iconify lucide--loader-circle animate-spin self-center text-xl" /> 208 + <div class="iconify lucide--loader-circle mt-2 animate-spin self-center text-xl" /> 221 209 } 222 210 > 223 211 <BlobView pds={pds!} repo={did} /> ··· 228 216 <TextInput 229 217 name="filter" 230 218 placeholder="Filter collections" 231 - onInput={(e) => setFilter(e.currentTarget.value)} 219 + onInput={(e) => setFilter(e.currentTarget.value.toLowerCase())} 232 220 class="grow" 233 221 /> 234 - <div class="flex flex-col font-mono"> 235 - <div class="grid grid-cols-[min-content_1fr] items-center gap-x-2 overflow-hidden text-sm"> 236 - <For 237 - each={Object.keys(nsids() ?? {}).filter((authority) => 238 - filter() ? 239 - authority.startsWith(filter()!) || filter()?.startsWith(authority) 240 - : true, 241 - )} 242 - > 243 - {(authority) => ( 244 - <> 245 - <button onclick={() => toggleCollection(authority)} class="flex items-center"> 246 - <span 247 - classList={{ 248 - "iconify lucide--chevron-down text-lg transition-transform": true, 249 - "-rotate-90": nsids()?.[authority].hidden, 250 - }} 251 - ></span> 252 - </button> 253 - <button 254 - class="bg-transparent text-left wrap-anywhere" 255 - onclick={() => toggleCollection(authority)} 256 - > 257 - {authority} 258 - </button> 259 - <Show when={!nsids()?.[authority].hidden}> 260 - <div></div> 261 - <div class="flex flex-col"> 262 - <For 263 - each={nsids()?.[authority].nsids.filter((nsid) => 264 - filter() ? 265 - nsid.startsWith(filter()!.split(".").slice(2).join(".")) 266 - : true, 267 - )} 268 - > 269 - {(nsid) => ( 270 - <A 271 - href={`/at://${did}/${authority}.${nsid}`} 272 - class="text-blue-400 hover:underline active:underline" 273 - > 274 - {authority}.{nsid} 275 - </A> 276 - )} 277 - </For> 278 - </div> 279 - </Show> 280 - </> 281 - )} 282 - </For> 283 - </div> 222 + <div class="flex flex-col overflow-hidden font-mono text-sm"> 223 + <For 224 + each={Object.keys(nsids() ?? {}).filter((authority) => 225 + filter() ? 226 + authority.startsWith(filter()!) || filter()?.startsWith(authority) 227 + : true, 228 + )} 229 + > 230 + {(authority) => ( 231 + <div class="dark:hover:bg-dark-200 flex flex-col rounded-lg p-1 hover:bg-neutral-200"> 232 + <For 233 + each={nsids()?.[authority].nsids.filter((nsid) => 234 + filter() ? nsid.startsWith(filter()!.split(".").slice(2).join(".")) : true, 235 + )} 236 + > 237 + {(nsid) => ( 238 + <A 239 + href={`/at://${did}/${authority}.${nsid}`} 240 + class="hover:underline active:underline" 241 + > 242 + <span>{authority}</span> 243 + <span class="text-neutral-500 dark:text-neutral-400">.{nsid}</span> 244 + </A> 245 + )} 246 + </For> 247 + </div> 248 + )} 249 + </For> 284 250 </div> 285 251 </Show> 286 252 <Show when={location.hash === "#identity"}> ··· 355 321 <li class="flex flex-col text-sm"> 356 322 <span>#{service.id.split("#")[1]}</span> 357 323 <a 358 - class="w-fit text-blue-400 hover:underline active:underline" 324 + class="w-fit underline" 359 325 href={service.serviceEndpoint.toString()} 360 326 target="_blank" 361 327 > ··· 401 367 </Show> 402 368 ); 403 369 }; 404 - 405 - export { RepoView };