+11
-11
package.json
+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.12",
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
}
+291
-276
pnpm-lock.yaml
+291
-276
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.12
100
-
version: 1.6.12
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.5.1)(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.5.1)(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.5.1)(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==}
···
1038
1044
1039
1045
graceful-fs@4.2.11:
1040
1046
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
1041
-
1042
-
hls.js@1.6.12:
1043
-
resolution: {integrity: sha512-Pz+7IzvkbAht/zXvwLzA/stUHNqztqKvlLbfpq6ZYU68+gZ+CZMlsbQBPUviRap+3IQ41E39ke7Ia+yvhsehEQ==}
1044
1047
1045
1048
html-entities@2.3.3:
1046
1049
resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
···
1049
1052
resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
1050
1053
engines: {node: '>=12.13'}
1051
1054
1052
-
jiti@2.5.1:
1053
-
resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==}
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:
···
1170
1173
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
1171
1174
hasBin: true
1172
1175
1173
-
nanoid@5.1.5:
1174
-
resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==}
1176
+
nanoid@5.1.6:
1177
+
resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==}
1175
1178
engines: {node: ^18 || >=20}
1176
1179
hasBin: true
1177
1180
···
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
···
1530
1547
'@atcute/lexicons': 1.1.1
1531
1548
'@atcute/multibase': 1.1.5
1532
1549
'@atcute/uint8array': 1.0.4
1533
-
nanoid: 5.1.5
1550
+
nanoid: 5.1.6
1534
1551
1535
1552
'@atcute/tangled@1.0.6':
1536
1553
dependencies:
···
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.5.1
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.5.1)(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.5.1)(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
···
2275
2292
2276
2293
graceful-fs@4.2.11: {}
2277
2294
2278
-
hls.js@1.6.12: {}
2279
-
2280
2295
html-entities@2.3.3: {}
2281
2296
2282
2297
is-what@4.1.16: {}
2283
2298
2284
-
jiti@2.5.1: {}
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
···
2373
2388
2374
2389
nanoid@3.3.11: {}
2375
2390
2376
-
nanoid@5.1.5: {}
2391
+
nanoid@5.1.6: {}
2377
2392
2378
2393
node-releases@2.0.21: {}
2379
2394
···
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.5.1)(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.5.1)(lightningcss@1.30.1)(tsx@4.19.2)
2534
-
vitefu: 1.1.1(vite@7.1.7(@types/node@22.13.1)(jiti@2.5.1)(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.5.1)(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.5.1
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.5.1)(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.5.1)(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
public/headers/aurora.jpg
This is a binary file and will not be displayed.
public/headers/bridge.jpg
public/headers/bridge.jpg
This is a binary file and will not be displayed.
public/headers/bunny.jpg
public/headers/bunny.jpg
This is a binary file and will not be displayed.
public/headers/city.webp
public/headers/city.webp
This is a binary file and will not be displayed.
public/headers/forest.jpg
public/headers/forest.jpg
This is a binary file and will not be displayed.
public/headers/puppy.jpg
public/headers/puppy.jpg
This is a binary file and will not be displayed.
public/headers/water.webp
public/headers/water.webp
This is a binary file and will not be displayed.
+1
-1
src/components/account.tsx
+1
-1
src/components/account.tsx
···
111
111
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"
112
112
>
113
113
{agent() && avatar() ?
114
-
<img src={avatar()} class="dark:shadow-dark-800 size-5 rounded-full shadow-xs" />
114
+
<img src={avatar()} class="size-5 rounded-full" />
115
115
: <span class="iconify lucide--circle-user-round text-xl"></span>}
116
116
</button>
117
117
</>
+71
-76
src/components/backlinks.tsx
+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
+18
src/components/dropdown.tsx
+18
src/components/dropdown.tsx
···
59
59
);
60
60
};
61
61
62
+
export const ActionMenu = (props: {
63
+
label: string;
64
+
icon: string;
65
+
onClick: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>;
66
+
}) => {
67
+
return (
68
+
<button
69
+
onClick={props.onClick}
70
+
class="flex items-center gap-1.5 rounded-lg p-1 whitespace-nowrap hover:bg-neutral-200/50 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
71
+
>
72
+
<Show when={props.icon}>
73
+
<span class={"iconify shrink-0 " + props.icon}></span>
74
+
</Show>
75
+
<span class="whitespace-nowrap">{props.label}</span>
76
+
</button>
77
+
);
78
+
};
79
+
62
80
export const DropdownMenu = (props: {
63
81
icon: string;
64
82
buttonClass?: string;
+41
-41
src/components/json.tsx
+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
);
+16
-14
src/components/search.tsx
+16
-14
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, AppUrl } from "../utils/app-urls";
5
6
import { createDebouncedValue } from "../utils/hooks/debounced";
6
7
7
8
export const [showSearch, setShowSearch] = createSignal(false);
···
25
26
return (
26
27
<button
27
28
onclick={() => setShowSearch(!showSearch())}
28
-
class={`flex items-center gap-0.5 rounded-lg ${isTouchDevice ? "p-1 text-xl hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" : "dark:bg-dark-100 box-border h-7 border-[0.5px] border-neutral-300 bg-neutral-100 p-1.5 text-xs hover:bg-neutral-200 active:bg-neutral-300 dark:border-neutral-700 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"}`}
29
+
class={`flex items-center gap-0.5 rounded-lg ${isTouchDevice ? "p-1 text-xl hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" : "dark:bg-dark-100/70 box-border h-7 border-[0.5px] border-neutral-300 bg-neutral-100/70 p-1.5 text-xs hover:bg-neutral-200 active:bg-neutral-300 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"}`}
29
30
>
30
31
<span class="iconify lucide--search"></span>
31
32
<Show when={!isTouchDevice}>
···
68
69
setShowSearch(false);
69
70
if (input === "me" && localStorage.getItem("lastSignedIn") !== null) {
70
71
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
72
} else if (search()?.length) {
77
73
navigate(`/at://${search()![0].did}`);
74
+
} else if (input.startsWith("https://") || input.startsWith("http://")) {
75
+
const hostLength = input.indexOf("/", 8);
76
+
const host = input.slice(0, hostLength).replace("https://", "").replace("http://", "");
77
+
78
+
if (!(host in appList)) {
79
+
navigate(`/${input.replace("https://", "").replace("http://", "").replace("/", "")}`);
80
+
} else {
81
+
const app = appList[host as AppUrl];
82
+
const path = input.slice(hostLength + 1).split("/");
83
+
84
+
const uri = appHandleLink[app](path);
85
+
navigate(`/${uri}`);
86
+
}
78
87
} 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
-
);
88
+
navigate(`/at://${input.replace("at://", "")}`);
87
89
}
88
90
setShowSearch(false);
89
91
};
+13
-68
src/components/video-player.tsx
+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
+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_30%),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_30%),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="relative -mr-1 flex items-center gap-1">
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
+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,
+110
src/utils/app-urls.ts
+110
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 appList: Record<AppUrl, App> = {
13
+
"localhost:19006": App.Bluesky,
14
+
"blacksky.community": App.Bluesky,
15
+
"bsky.app": App.Bluesky,
16
+
"catsky.social": App.Bluesky,
17
+
"deer.aylac.top": App.Bluesky,
18
+
"deer-social-ayla.pages.dev": App.Bluesky,
19
+
"deer.social": App.Bluesky,
20
+
"main.bsky.dev": App.Bluesky,
21
+
"social.daniela.lol": App.Bluesky,
22
+
"tangled.org": App.Tangled,
23
+
"whtwnd.com": App.Whitewind,
24
+
"frontpage.fyi": App.Frontpage,
25
+
"pinksea.art": App.Pinksea,
26
+
"linkat.blue": App.Linkat,
27
+
};
28
+
29
+
export const appHandleLink: Record<App, (url: string[]) => string> = {
30
+
[App.Bluesky]: (path) => {
31
+
const baseType = path[0];
32
+
const user = path[1];
33
+
34
+
if (baseType === "profile") {
35
+
if (path[2]) {
36
+
const type = path[2];
37
+
const rkey = path[3];
38
+
39
+
if (type === "post") {
40
+
return `at://${user}/app.bsky.feed.post/${rkey}`;
41
+
} else if (type === "list") {
42
+
return `at://${user}/app.bsky.graph.list/${rkey}`;
43
+
} else if (type === "feed") {
44
+
return `at://${user}/app.bsky.feed.generator/${rkey}`;
45
+
} else if (type === "follows") {
46
+
return `at://${user}/app.bsky.graph.follow/${rkey}`;
47
+
}
48
+
} else {
49
+
return `at://${user}`;
50
+
}
51
+
} else if (baseType === "starter-pack") {
52
+
return `at://${user}/app.bsky.graph.starterpack/${path[2]}`;
53
+
}
54
+
return `at://${user}`;
55
+
},
56
+
[App.Tangled]: (path) => {
57
+
if (path[0] === "strings") {
58
+
return `at://${path[1]}/sh.tangled.string/${path[2]}`;
59
+
}
60
+
61
+
let query: string | undefined;
62
+
if (path[path.length - 1].includes("?")) {
63
+
const split = path[path.length - 1].split("?");
64
+
query = split[1];
65
+
path[path.length - 1] = split[0];
66
+
}
67
+
68
+
const user = path[0].replace("@", "");
69
+
70
+
if (path.length === 1) {
71
+
if (query === "tab=repos") {
72
+
return `at://${user}/sh.tangled.repo`;
73
+
} else if (query === "tab=starred") {
74
+
return `at://${user}/sh.tangled.feed.star`;
75
+
} else if (query === "tab=strings") {
76
+
return `at://${user}/sh.tangled.string`;
77
+
}
78
+
} else if (path.length === 2) {
79
+
// no way to convert the repo name to an rkey afaik
80
+
// same reason why there's nothing related to issues in here
81
+
return `at://${user}/sh.tangled.repo`;
82
+
}
83
+
84
+
return `at://${user}`;
85
+
},
86
+
[App.Whitewind]: (path) => {
87
+
if (path.length === 2) {
88
+
return `at://${path[0]}/com.whtwnd.blog.entry/${path[1]}`;
89
+
}
90
+
91
+
return `at://${path[0]}/com.whtwnd.blog.entry`;
92
+
},
93
+
[App.Frontpage]: (path) => {
94
+
if (path.length === 3) {
95
+
return `at://${path[1]}/fyi.unravel.frontpage.post/${path[2]}`;
96
+
} else if (path.length === 5) {
97
+
return `at://${path[3]}/fyi.unravel.frontpage.comment/${path[4]}`;
98
+
}
99
+
100
+
return `at://${path[0]}`;
101
+
},
102
+
[App.Pinksea]: (path) => {
103
+
if (path.length === 2) {
104
+
return `at://${path[0]}/com.shinolabs.pinksea.oekaki/${path[1]}`;
105
+
}
106
+
107
+
return `at://${path[0]}`;
108
+
},
109
+
[App.Linkat]: (path) => `at://${path[0]}/blue.linkat.board/self`,
110
+
};
+15
-7
src/views/collection.tsx
+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 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,
+9
-30
src/views/home.tsx
+9
-30
src/views/home.tsx
···
1
-
import { A } from "@solidjs/router";
2
-
3
-
const Home = () => {
1
+
export const Home = () => {
4
2
return (
5
3
<div class="flex w-full flex-col gap-4 break-words">
6
4
<div>
···
11
9
<div class="iconify lucide--search" />
12
10
<span>
13
11
Browse the public data on{" "}
14
-
<a
15
-
class="text-blue-400 hover:underline active:underline"
16
-
href="https://atproto.com"
17
-
target="_blank"
18
-
>
12
+
<a class="underline" href="https://atproto.com" target="_blank">
19
13
atproto
20
14
</a>
21
15
.
···
27
21
</div>
28
22
<div class="flex items-center gap-1">
29
23
<div class="iconify lucide--radio-tower" />
30
-
<div>
31
-
<A href="/jetstream" class="text-blue-400 hover:underline active:underline">
32
-
Jetstream
33
-
</A>{" "}
34
-
and{" "}
35
-
<A href="/firehose" class="text-blue-400 hover:underline active:underline">
36
-
firehose
37
-
</A>{" "}
38
-
streaming.
39
-
</div>
24
+
<span>Jetstream and firehose streaming.</span>
40
25
</div>
41
26
<div class="flex items-center gap-1">
42
27
<div class="iconify lucide--send-to-back" />
43
28
<span>
44
29
Backlinks support with{" "}
45
-
<A
46
-
href="https://constellation.microcosm.blue"
47
-
class="text-blue-400 hover:underline active:underline"
48
-
target="_blank"
49
-
>
30
+
<a href="https://constellation.microcosm.blue" class="underline" target="_blank">
50
31
constellation
51
-
</A>
32
+
</a>
52
33
.
53
34
</span>
54
35
</div>
···
58
39
</div>
59
40
</div>
60
41
<div class="flex gap-2 text-xl">
61
-
<A
42
+
<a
62
43
href="https://tangled.org/@pdsls.dev/pdsls/"
63
44
target="_blank"
64
45
class="flex rounded-full bg-neutral-200 p-1.5 transition-colors duration-300 hover:bg-neutral-700 hover:text-neutral-200 dark:bg-neutral-700 dark:hover:bg-neutral-200 dark:hover:text-neutral-700"
65
46
>
66
47
<span class="iconify i-tangled"></span>
67
-
</A>
68
-
<A
48
+
</a>
49
+
<a
69
50
href="https://bsky.app/profile/did:plc:6q5daed5gutiyerimlrnojnz"
70
51
target="_blank"
71
52
class="flex rounded-full bg-neutral-200 p-1.5 transition-colors duration-300 hover:bg-neutral-700 hover:text-neutral-200 dark:bg-neutral-700 dark:hover:bg-neutral-200 dark:hover:text-neutral-700"
72
53
>
73
54
<span class="iconify ri--bluesky"></span>
74
-
</A>
55
+
</a>
75
56
</div>
76
57
</div>
77
58
);
78
59
};
79
-
80
-
export { Home };
+1
-1
src/views/labels.tsx
+1
-1
src/views/labels.tsx
+155
src/views/logs.tsx
+155
src/views/logs.tsx
···
1
+
import {
2
+
CompatibleOperationOrTombstone,
3
+
defs,
4
+
IndexedEntry,
5
+
processIndexedEntryLog,
6
+
} from "@atcute/did-plc";
7
+
import { createResource, createSignal, For, Show } from "solid-js";
8
+
import Tooltip from "../components/tooltip.jsx";
9
+
import { localDateFromTimestamp } from "../utils/date.js";
10
+
import { createOperationHistory, DiffEntry, groupBy } from "../utils/plc-logs.js";
11
+
12
+
type PlcEvent = "handle" | "rotation_key" | "service" | "verification_method";
13
+
14
+
export const PlcLogView = (props: { did: string }) => {
15
+
const [activePlcEvent, setActivePlcEvent] = createSignal<PlcEvent | undefined>();
16
+
17
+
const fetchPlcLogs = async () => {
18
+
const res = await fetch(
19
+
`${localStorage.plcDirectory ?? "https://plc.directory"}/${props.did}/log/audit`,
20
+
);
21
+
const json = await res.json();
22
+
const logs = defs.indexedEntryLog.parse(json);
23
+
try {
24
+
await processIndexedEntryLog(props.did as any, logs);
25
+
} catch (e) {
26
+
console.error(e);
27
+
}
28
+
const opHistory = createOperationHistory(logs).reverse();
29
+
return Array.from(groupBy(opHistory, (item) => item.orig));
30
+
};
31
+
32
+
const [plcOps] =
33
+
createResource<[IndexedEntry<CompatibleOperationOrTombstone>, DiffEntry[]][]>(fetchPlcLogs);
34
+
35
+
const FilterButton = (props: { icon: string; event: PlcEvent }) => (
36
+
<button
37
+
classList={{
38
+
"flex items-center rounded-full p-1.5": true,
39
+
"bg-neutral-700 dark:bg-neutral-200": activePlcEvent() === props.event,
40
+
}}
41
+
onclick={() => setActivePlcEvent(activePlcEvent() === props.event ? undefined : props.event)}
42
+
>
43
+
<span
44
+
class={`${props.icon} ${activePlcEvent() === props.event ? "text-neutral-200 dark:text-neutral-900" : ""}`}
45
+
></span>
46
+
</button>
47
+
);
48
+
49
+
const DiffItem = (props: { diff: DiffEntry }) => {
50
+
const diff = props.diff;
51
+
let title = "Unknown log entry";
52
+
let icon = "lucide--circle-help";
53
+
let value = "";
54
+
55
+
if (diff.type === "identity_created") {
56
+
icon = "lucide--bell";
57
+
title = `Identity created`;
58
+
} else if (diff.type === "identity_tombstoned") {
59
+
icon = "lucide--skull";
60
+
title = `Identity tombstoned`;
61
+
} else if (diff.type === "handle_added" || diff.type === "handle_removed") {
62
+
icon = "lucide--at-sign";
63
+
title = diff.type === "handle_added" ? "Alias added" : "Alias removed";
64
+
value = diff.handle;
65
+
} else if (diff.type === "handle_changed") {
66
+
icon = "lucide--at-sign";
67
+
title = "Alias updated";
68
+
value = `${diff.prev_handle} โ ${diff.next_handle}`;
69
+
} else if (diff.type === "rotation_key_added" || diff.type === "rotation_key_removed") {
70
+
icon = "lucide--key-round";
71
+
title = diff.type === "rotation_key_added" ? "Rotation key added" : "Rotation key removed";
72
+
value = diff.rotation_key;
73
+
} else if (diff.type === "service_added" || diff.type === "service_removed") {
74
+
icon = "lucide--hard-drive";
75
+
title = `Service ${diff.service_id} ${diff.type === "service_added" ? "added" : "removed"}`;
76
+
value = `${diff.service_endpoint}`;
77
+
} else if (diff.type === "service_changed") {
78
+
icon = "lucide--hard-drive";
79
+
title = `Service ${diff.service_id} updated`;
80
+
value = `${diff.prev_service_endpoint} โ ${diff.next_service_endpoint}`;
81
+
} else if (
82
+
diff.type === "verification_method_added" ||
83
+
diff.type === "verification_method_removed"
84
+
) {
85
+
icon = "lucide--shield-check";
86
+
title = `Verification method ${diff.method_id} ${diff.type === "verification_method_added" ? "added" : "removed"}`;
87
+
value = `${diff.method_key}`;
88
+
} else if (diff.type === "verification_method_changed") {
89
+
icon = "lucide--shield-check";
90
+
title = `Verification method ${diff.method_id} updated`;
91
+
value = `${diff.prev_method_key} โ ${diff.next_method_key}`;
92
+
}
93
+
94
+
return (
95
+
<div class="grid grid-cols-[min-content_1fr] items-center gap-x-1">
96
+
<div class={icon + ` iconify shrink-0`} />
97
+
<p
98
+
classList={{
99
+
"font-semibold": true,
100
+
"text-neutral-400 line-through dark:text-neutral-600": diff.orig.nullified,
101
+
}}
102
+
>
103
+
{title}
104
+
</p>
105
+
<div></div>
106
+
{value}
107
+
</div>
108
+
);
109
+
};
110
+
111
+
return (
112
+
<div class="flex w-full flex-col gap-2 wrap-anywhere">
113
+
<div class="flex items-center justify-between">
114
+
<div class="flex items-center gap-1">
115
+
<div class="iconify lucide--filter" />
116
+
<div class="dark:shadow-dark-800 dark:bg-dark-300 flex w-fit items-center rounded-full border-[0.5px] border-neutral-300 bg-neutral-50 shadow-xs dark:border-neutral-700">
117
+
<FilterButton icon="iconify lucide--at-sign" event="handle" />
118
+
<FilterButton icon="iconify lucide--key-round" event="rotation_key" />
119
+
<FilterButton icon="iconify lucide--hard-drive" event="service" />
120
+
<FilterButton icon="iconify lucide--shield-check" event="verification_method" />
121
+
</div>
122
+
</div>
123
+
<Tooltip text="Audit log">
124
+
<a
125
+
href={`${localStorage.plcDirectory ?? "https://plc.directory"}/${props.did}/log/audit`}
126
+
target="_blank"
127
+
class="-mr-1 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"
128
+
>
129
+
<span class="iconify lucide--external-link"></span>
130
+
</a>
131
+
</Tooltip>
132
+
</div>
133
+
<div class="flex flex-col gap-1 text-sm">
134
+
<For each={plcOps()}>
135
+
{([entry, diffs]) => (
136
+
<Show
137
+
when={!activePlcEvent() || diffs.find((d) => d.type.startsWith(activePlcEvent()!))}
138
+
>
139
+
<div class="flex flex-col">
140
+
<span class="text-neutral-500 dark:text-neutral-400">
141
+
{localDateFromTimestamp(new Date(entry.createdAt).getTime())}
142
+
</span>
143
+
{diffs.map((diff) => (
144
+
<Show when={!activePlcEvent() || diff.type.startsWith(activePlcEvent()!)}>
145
+
<DiffItem diff={diff} />
146
+
</Show>
147
+
))}
148
+
</div>
149
+
</Show>
150
+
)}
151
+
</For>
152
+
</div>
153
+
</div>
154
+
);
155
+
};
+3
-3
src/views/pds.tsx
+3
-3
src/views/pds.tsx
···
49
49
const [openInfo, setOpenInfo] = createSignal(false);
50
50
51
51
return (
52
-
<div class="flex items-center gap-1">
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>
···
105
105
106
106
return (
107
107
<Show when={repos() || response()}>
108
-
<div class="flex w-full flex-col">
108
+
<div class="flex w-full flex-col px-2">
109
109
<Show when={version()}>
110
110
{(version) => (
111
111
<div class="flex items-baseline gap-x-1">
+111
-32
src/views/record.tsx
+111
-32
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, setValidRecord, setValidSchema, validRecord } from "../components/navbar.jsx";
13
+
import { pds, setCID } 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>();
31
+
const [validRecord, setValidRecord] = createSignal<boolean | undefined>(undefined);
32
+
const [validSchema, setValidSchema] = createSignal<boolean | undefined>(undefined);
30
33
const did = params.repo;
31
34
let rpc: Client;
32
35
···
34
37
setCID(undefined);
35
38
setValidRecord(undefined);
36
39
setValidSchema(undefined);
40
+
setLexiconUri(undefined);
37
41
const pds = await resolvePDS(did);
38
42
rpc = new Client({ handler: new CredentialManager({ service: pds }) });
39
43
const res = await rpc.get("com.atproto.repo.getRecord", {
···
50
54
}
51
55
setCID(res.data.cid);
52
56
setExternalLink(checkUri(res.data.uri, res.data.value));
57
+
resolveLexicon(params.collection as Nsid);
53
58
verify(res.data);
54
59
55
60
return res.data;
···
90
95
console.error(err);
91
96
setValidRecord(false);
92
97
}
98
+
};
99
+
100
+
const resolveLexicon = async (nsid: Nsid) => {
101
+
try {
102
+
const res = await resolveLexiconAuthority(nsid);
103
+
setLexiconUri(`at://${res}/com.atproto.lexicon.schema/${nsid}`);
104
+
} catch {}
93
105
};
94
106
95
107
const [record, { refetch }] = createResource(fetchRecord);
···
117
129
return template(parsedUri, record);
118
130
};
119
131
132
+
const RecordTab = (props: {
133
+
tab: "record" | "backlinks" | "info";
134
+
label: string;
135
+
error?: boolean;
136
+
}) => (
137
+
<div class="flex items-center gap-0.5">
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 && location.hash !== `#${props.tab}`) ||
143
+
(!location.hash && props.tab !== "record"),
144
+
}}
145
+
href={`/at://${did}/${params.collection}/${params.rkey}#${props.tab}`}
146
+
>
147
+
{props.label}
148
+
</A>
149
+
<Show when={props.error && (validRecord() === false || validSchema() === false)}>
150
+
<span class="iconify lucide--x text-red-500 dark:text-red-400"></span>
151
+
</Show>
152
+
</div>
153
+
);
154
+
120
155
return (
121
156
<Show when={record()} keyed>
122
157
<div class="flex w-full flex-col items-center">
123
-
<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">
124
-
<div class="flex gap-3 text-sm">
125
-
<A
126
-
classList={{
127
-
"flex items-center gap-1 border-b-2": true,
128
-
"border-transparent hover:border-neutral-400 dark:hover:border-neutral-600":
129
-
!!location.hash && location.hash !== "#record",
130
-
}}
131
-
href={`/at://${did}/${params.collection}/${params.rkey}#record`}
132
-
>
133
-
<div class="iconify lucide--file-json" />
134
-
Record
135
-
</A>
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 !== "#backlinks",
141
-
}}
142
-
href={`/at://${did}/${params.collection}/${params.rkey}#backlinks`}
143
-
>
144
-
<div class="iconify lucide--send-to-back" />
145
-
Backlinks
146
-
</A>
158
+
<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">
159
+
<div class="flex gap-3">
160
+
<RecordTab tab="record" label="Record" />
161
+
<RecordTab tab="backlinks" label="Backlinks" />
162
+
<RecordTab tab="info" label="Info" error />
147
163
</div>
148
164
<div class="flex gap-1">
149
165
<Show when={agent() && agent()?.sub === record()?.uri.split("/")[2]}>
···
203
219
</div>
204
220
</div>
205
221
<Show when={!location.hash || location.hash === "#record"}>
206
-
<Show when={validRecord() === false}>
207
-
<div class="mb-2 break-words text-red-500 dark:text-red-400">{notice()}</div>
208
-
</Show>
209
-
<div class="w-max max-w-screen px-4 font-mono text-xs wrap-anywhere whitespace-pre-wrap sm:text-sm md:max-w-[48rem]">
222
+
<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]">
210
223
<JSONValue data={record()?.value as any} repo={record()!.uri.split("/")[2]} />
211
224
</div>
212
225
</Show>
···
217
230
<div class="iconify lucide--loader-circle animate-spin self-center text-xl" />
218
231
}
219
232
>
220
-
<Backlinks target={`at://${did}/${params.collection}/${params.rkey}`} />
233
+
<div class="w-full px-2">
234
+
<Backlinks target={`at://${did}/${params.collection}/${params.rkey}`} />
235
+
</div>
221
236
</Suspense>
222
237
</ErrorBoundary>
238
+
</Show>
239
+
<Show when={location.hash === "#info"}>
240
+
<div class="flex w-full flex-col gap-2 px-2 text-sm">
241
+
<div>
242
+
<div class="flex items-center gap-1">
243
+
<span class="iconify lucide--at-sign"></span>
244
+
<p class="font-semibold">AT URI</p>
245
+
</div>
246
+
<div class="truncate text-xs">{record()?.uri}</div>
247
+
</div>
248
+
<Show when={record()?.cid}>
249
+
<div>
250
+
<div class="flex items-center gap-1">
251
+
<span class="iconify lucide--box"></span>
252
+
<p class="font-semibold">CID</p>
253
+
</div>
254
+
<div class="truncate text-left text-xs" dir="rtl">
255
+
{record()?.cid}
256
+
</div>
257
+
</div>
258
+
</Show>
259
+
<div>
260
+
<div class="flex items-center gap-1">
261
+
<span class="iconify lucide--lock-keyhole"></span>
262
+
<p class="font-semibold">Record verification</p>
263
+
<span
264
+
classList={{
265
+
"iconify lucide--check text-green-500 dark:text-green-400":
266
+
validRecord() === true,
267
+
"iconify lucide--x text-red-500 dark:text-red-400": validRecord() === false,
268
+
"iconify lucide--loader-circle animate-spin": validRecord() === undefined,
269
+
}}
270
+
></span>
271
+
</div>
272
+
<Show when={validRecord() === false}>
273
+
<div class="break-words">{notice()}</div>
274
+
</Show>
275
+
</div>
276
+
<Show when={validSchema() !== undefined}>
277
+
<div class="flex items-center gap-1">
278
+
<span class="iconify lucide--file-check"></span>
279
+
<p class="font-semibold">Schema validation</p>
280
+
<span
281
+
class={`iconify ${validSchema() ? "lucide--check text-green-500 dark:text-green-400" : "lucide--x text-red-500 dark:text-red-400"}`}
282
+
></span>
283
+
</div>
284
+
</Show>
285
+
<Show when={lexiconUri()}>
286
+
<div>
287
+
<div class="flex items-center gap-1">
288
+
<span class="iconify lucide--scroll-text"></span>
289
+
<p class="font-semibold">Lexicon document</p>
290
+
</div>
291
+
<div class="truncate text-xs">
292
+
<A
293
+
href={`/${lexiconUri()}`}
294
+
class="text-blue-400 hover:underline active:underline"
295
+
>
296
+
{lexiconUri()}
297
+
</A>
298
+
</div>
299
+
</div>
300
+
</Show>
301
+
</div>
223
302
</Show>
224
303
</div>
225
304
</Show>
+159
-329
src/views/repo.tsx
+159
-329
src/views/repo.tsx
···
1
1
import { Client, CredentialManager } from "@atcute/client";
2
2
import { parsePublicMultikey } from "@atcute/crypto";
3
-
import {
4
-
CompatibleOperationOrTombstone,
5
-
defs,
6
-
IndexedEntry,
7
-
processIndexedEntryLog,
8
-
} from "@atcute/did-plc";
9
3
import { DidDocument } from "@atcute/identity";
10
-
import { ActorIdentifier, Handle } from "@atcute/lexicons";
4
+
import { ActorIdentifier, Did, Handle } from "@atcute/lexicons";
11
5
import { A, useLocation, useNavigate, useParams } from "@solidjs/router";
12
6
import { createResource, createSignal, ErrorBoundary, For, Show, Suspense } from "solid-js";
7
+
import { createStore } from "solid-js/store";
13
8
import { Backlinks } from "../components/backlinks.jsx";
14
-
import { Button } from "../components/button.jsx";
9
+
import { ActionMenu, DropdownMenu, MenuProvider, NavMenu } from "../components/dropdown.jsx";
15
10
import { TextInput } from "../components/text-input.jsx";
16
11
import Tooltip from "../components/tooltip.jsx";
17
-
import { didDocCache, resolveHandle, resolvePDS } from "../utils/api.js";
18
-
import { localDateFromTimestamp } from "../utils/date.js";
19
-
import { createOperationHistory, DiffEntry, groupBy } from "../utils/plc-logs.js";
12
+
import { didDocCache, resolveHandle, resolvePDS, validateHandle } from "../utils/api.js";
20
13
import { BlobView } from "./blob.jsx";
21
-
22
-
type Tab = "collections" | "backlinks" | "identity" | "blobs";
23
-
type PlcEvent = "handle" | "rotation_key" | "service" | "verification_method";
24
-
25
-
const PlcLogView = (props: {
26
-
did: string;
27
-
plcOps: [IndexedEntry<CompatibleOperationOrTombstone>, DiffEntry[]][];
28
-
}) => {
29
-
const [activePlcEvent, setActivePlcEvent] = createSignal<PlcEvent | undefined>();
30
-
31
-
const FilterButton = (props: { icon: string; event: PlcEvent }) => (
32
-
<button
33
-
classList={{
34
-
"flex items-center rounded-full p-1.5": true,
35
-
"bg-neutral-700 dark:bg-neutral-200": activePlcEvent() === props.event,
36
-
}}
37
-
onclick={() => setActivePlcEvent(activePlcEvent() === props.event ? undefined : props.event)}
38
-
>
39
-
<span
40
-
class={`${props.icon} ${activePlcEvent() === props.event ? "text-neutral-200 dark:text-neutral-900" : ""}`}
41
-
></span>
42
-
</button>
43
-
);
44
-
45
-
const DiffItem = (props: { diff: DiffEntry }) => {
46
-
const diff = props.diff;
47
-
let title = "Unknown log entry";
48
-
let icon = "lucide--circle-help";
49
-
let value = "";
50
-
51
-
if (diff.type === "identity_created") {
52
-
icon = "lucide--bell";
53
-
title = `Identity created`;
54
-
} else if (diff.type === "identity_tombstoned") {
55
-
icon = "lucide--skull";
56
-
title = `Identity tombstoned`;
57
-
} else if (diff.type === "handle_added" || diff.type === "handle_removed") {
58
-
icon = "lucide--at-sign";
59
-
title = diff.type === "handle_added" ? "Alias added" : "Alias removed";
60
-
value = diff.handle;
61
-
} else if (diff.type === "handle_changed") {
62
-
icon = "lucide--at-sign";
63
-
title = "Alias updated";
64
-
value = `${diff.prev_handle} โ ${diff.next_handle}`;
65
-
} else if (diff.type === "rotation_key_added" || diff.type === "rotation_key_removed") {
66
-
icon = "lucide--key-round";
67
-
title = diff.type === "rotation_key_added" ? "Rotation key added" : "Rotation key removed";
68
-
value = diff.rotation_key;
69
-
} else if (diff.type === "service_added" || diff.type === "service_removed") {
70
-
icon = "lucide--hard-drive";
71
-
title = `Service ${diff.service_id} ${diff.type === "service_added" ? "added" : "removed"}`;
72
-
value = `${diff.service_endpoint}`;
73
-
} else if (diff.type === "service_changed") {
74
-
icon = "lucide--hard-drive";
75
-
title = `Service ${diff.service_id} updated`;
76
-
value = `${diff.prev_service_endpoint} โ ${diff.next_service_endpoint}`;
77
-
} else if (
78
-
diff.type === "verification_method_added" ||
79
-
diff.type === "verification_method_removed"
80
-
) {
81
-
icon = "lucide--shield-check";
82
-
title = `Verification method ${diff.method_id} ${diff.type === "verification_method_added" ? "added" : "removed"}`;
83
-
value = `${diff.method_key}`;
84
-
} else if (diff.type === "verification_method_changed") {
85
-
icon = "lucide--shield-check";
86
-
title = `Verification method ${diff.method_id} updated`;
87
-
value = `${diff.prev_method_key} โ ${diff.next_method_key}`;
88
-
}
89
-
90
-
return (
91
-
<div class="grid grid-cols-[min-content_1fr] items-center gap-x-1">
92
-
<div class={icon + ` iconify shrink-0`} />
93
-
<p
94
-
classList={{
95
-
"font-semibold": true,
96
-
"text-neutral-400 line-through dark:text-neutral-600": diff.orig.nullified,
97
-
}}
98
-
>
99
-
{title}
100
-
</p>
101
-
<div></div>
102
-
{value}
103
-
</div>
104
-
);
105
-
};
106
-
107
-
return (
108
-
<>
109
-
<div class="flex items-center justify-between">
110
-
<div class="flex items-center gap-1">
111
-
<div class="iconify lucide--filter" />
112
-
<div class="dark:shadow-dark-800 dark:bg-dark-300 flex w-fit items-center rounded-full border-[0.5px] border-neutral-300 bg-neutral-50 shadow-xs dark:border-neutral-700">
113
-
<FilterButton icon="iconify lucide--at-sign" event="handle" />
114
-
<FilterButton icon="iconify lucide--key-round" event="rotation_key" />
115
-
<FilterButton icon="iconify lucide--hard-drive" event="service" />
116
-
<FilterButton icon="iconify lucide--shield-check" event="verification_method" />
117
-
</div>
118
-
</div>
119
-
<Tooltip text="Audit log">
120
-
<a
121
-
href={`${localStorage.plcDirectory ?? "https://plc.directory"}/${props.did}/log/audit`}
122
-
target="_blank"
123
-
class="-mr-1 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"
124
-
>
125
-
<span class="iconify lucide--external-link"></span>
126
-
</a>
127
-
</Tooltip>
128
-
</div>
129
-
<div class="flex flex-col gap-1 text-sm">
130
-
<For each={props.plcOps}>
131
-
{([entry, diffs]) => (
132
-
<Show
133
-
when={!activePlcEvent() || diffs.find((d) => d.type.startsWith(activePlcEvent()!))}
134
-
>
135
-
<div class="flex flex-col">
136
-
<span class="text-neutral-500 dark:text-neutral-400">
137
-
{localDateFromTimestamp(new Date(entry.createdAt).getTime())}
138
-
</span>
139
-
{diffs.map((diff) => (
140
-
<Show when={!activePlcEvent() || diff.type.startsWith(activePlcEvent()!)}>
141
-
<DiffItem diff={diff} />
142
-
</Show>
143
-
))}
144
-
</div>
145
-
</Show>
146
-
)}
147
-
</For>
148
-
</div>
149
-
</>
150
-
);
151
-
};
14
+
import { PlcLogView } from "./logs.jsx";
152
15
153
-
const RepoView = () => {
16
+
export const RepoView = () => {
154
17
const params = useParams();
155
18
const location = useLocation();
156
19
const navigate = useNavigate();
···
159
22
const [didDoc, setDidDoc] = createSignal<DidDocument>();
160
23
const [nsids, setNsids] = createSignal<Record<string, { hidden: boolean; nsids: string[] }>>();
161
24
const [filter, setFilter] = createSignal<string>();
162
-
const [plcOps, setPlcOps] =
163
-
createSignal<[IndexedEntry<CompatibleOperationOrTombstone>, DiffEntry[]][]>();
164
-
const [showPlcLogs, setShowPlcLogs] = createSignal(false);
165
-
const [loading, setLoading] = createSignal(false);
166
-
const [notice, setNotice] = createSignal<string>();
25
+
const [validHandles, setValidHandles] = createStore<Record<string, boolean>>({});
167
26
let rpc: Client;
168
27
let pds: string;
169
28
const did = params.repo;
170
29
171
-
const RepoTab = (props: { tab: Tab; label: string; icon: string }) => (
172
-
<A class="group flex flex-1 justify-center" href={`/at://${params.repo}#${props.tab}`}>
30
+
const RepoTab = (props: {
31
+
tab: "collections" | "backlinks" | "identity" | "blobs" | "logs";
32
+
label: string;
33
+
}) => (
34
+
<A class="group flex justify-center" href={`/at://${params.repo}#${props.tab}`}>
173
35
<span
174
36
classList={{
175
-
"flex gap-1 items-center border-b-2": true,
37
+
"flex flex-1 items-center border-b-2": true,
176
38
"border-transparent group-hover:border-neutral-400 dark:group-hover:border-neutral-600":
177
39
(location.hash !== `#${props.tab}` && !!location.hash) ||
178
40
(!location.hash && props.tab !== "collections"),
179
41
}}
180
42
>
181
-
<span class={"iconify " + props.icon}></span>
182
43
{props.label}
183
44
</span>
184
45
</A>
···
196
57
}
197
58
}
198
59
setDidDoc(didDocCache[did] as DidDocument);
60
+
validateHandles();
199
61
200
62
rpc = new Client({ handler: new CredentialManager({ service: pds }) });
201
63
const res = await rpc.get("com.atproto.repo.describeRepo", {
···
218
80
console.error(res.data.error);
219
81
switch (res.data.error) {
220
82
case "RepoDeactivated":
221
-
setError("This repository has been deactivated");
83
+
setError("Deactivated");
222
84
break;
223
85
case "RepoTakendown":
224
-
setError("This repository has been taken down");
86
+
setError("Takendown");
225
87
break;
226
88
default:
227
-
setError("This repository is unreachable");
89
+
setError("Unreachable");
228
90
}
229
91
navigate(`/at://${params.repo}#identity`);
230
92
}
···
233
95
};
234
96
235
97
const [repo] = createResource(fetchRepo);
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
+
};
236
108
237
109
const downloadRepo = async () => {
238
110
try {
···
258
130
setDownloading(false);
259
131
};
260
132
261
-
const toggleCollection = (authority: string) => {
262
-
setNsids({
263
-
...nsids(),
264
-
[authority]: { ...nsids()![authority], hidden: !nsids()![authority].hidden },
265
-
});
266
-
};
267
-
268
133
return (
269
134
<Show when={repo()}>
270
135
<div class="flex w-full flex-col gap-2 break-words">
271
-
<Show when={error()}>
272
-
<div class="rounded-lg bg-red-100 p-2 text-sm text-red-700 dark:bg-red-200 dark:text-red-600">
273
-
{error()}
274
-
</div>
275
-
</Show>
276
136
<div
277
-
class={`dark:shadow-dark-800 dark:bg-dark-300 flex ${error() ? "justify-around" : "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`}
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`}
278
138
>
279
-
<Show when={!error()}>
280
-
<RepoTab tab="collections" label="Collections" icon="lucide--folder-open" />
139
+
<div class="flex gap-2 sm:gap-4">
140
+
<Show when={!error()}>
141
+
<RepoTab tab="collections" label="Collections" />
142
+
</Show>
143
+
<RepoTab tab="identity" label="Identity" />
144
+
<Show when={did.startsWith("did:plc")}>
145
+
<RepoTab tab="logs" label="Logs" />
146
+
</Show>
147
+
<Show when={!error()}>
148
+
<RepoTab tab="blobs" label="Blobs" />
149
+
</Show>
150
+
<RepoTab tab="backlinks" label="Backlinks" />
151
+
</div>
152
+
<div class="flex gap-1">
153
+
<Show when={error()}>
154
+
<div class="flex items-center gap-1 text-red-500 dark:text-red-400">
155
+
<span class="iconify lucide--alert-triangle"></span>
156
+
<span>{error()}</span>
157
+
</div>
158
+
</Show>
159
+
<MenuProvider>
160
+
<DropdownMenu
161
+
icon="lucide--ellipsis-vertical"
162
+
buttonClass="rounded-sm p-1"
163
+
menuClass="top-8 p-2 text-sm"
164
+
>
165
+
<NavMenu
166
+
href={`/jetstream?dids=${params.repo}`}
167
+
label="Jetstream"
168
+
icon="lucide--radio-tower"
169
+
/>
170
+
<Show when={error()?.length === 0 || error() === undefined}>
171
+
<ActionMenu
172
+
label="Export Repo"
173
+
icon={downloading() ? "lucide--loader-circle animate-spin" : "lucide--download"}
174
+
onClick={() => downloadRepo()}
175
+
/>
176
+
</Show>
177
+
</DropdownMenu>
178
+
</MenuProvider>
179
+
</div>
180
+
</div>
181
+
<div class="flex w-full flex-col gap-2 px-2">
182
+
<Show when={location.hash === "#logs"}>
183
+
<ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}>
184
+
<Suspense
185
+
fallback={
186
+
<div class="iconify lucide--loader-circle mt-2 animate-spin self-center text-xl" />
187
+
}
188
+
>
189
+
<PlcLogView did={did} />
190
+
</Suspense>
191
+
</ErrorBoundary>
281
192
</Show>
282
-
<RepoTab tab="identity" label="Identity" icon="lucide--id-card" />
283
-
<Show when={!error()}>
284
-
<RepoTab tab="blobs" label="Blobs" icon="lucide--file-digit" />
193
+
<Show when={location.hash === "#backlinks"}>
194
+
<ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}>
195
+
<Suspense
196
+
fallback={
197
+
<div class="iconify lucide--loader-circle mt-2 animate-spin self-center text-xl" />
198
+
}
199
+
>
200
+
<Backlinks target={did} />
201
+
</Suspense>
202
+
</ErrorBoundary>
285
203
</Show>
286
-
<RepoTab tab="backlinks" label="Backlinks" icon="lucide--send-to-back" />
287
-
</div>
288
-
<Show when={location.hash === "#backlinks"}>
289
-
<ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}>
290
-
<Suspense
291
-
fallback={
292
-
<div class="iconify lucide--loader-circle animate-spin self-center text-xl" />
293
-
}
294
-
>
295
-
<Backlinks target={did} />
296
-
</Suspense>
297
-
</ErrorBoundary>
298
-
</Show>
299
-
<Show when={location.hash === "#blobs"}>
300
-
<ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}>
301
-
<Suspense
302
-
fallback={
303
-
<div class="iconify lucide--loader-circle animate-spin self-center text-xl" />
304
-
}
305
-
>
306
-
<BlobView pds={pds!} repo={did} />
307
-
</Suspense>
308
-
</ErrorBoundary>
309
-
</Show>
310
-
<Show when={nsids() && (!location.hash || location.hash === "#collections")}>
311
-
<div class="flex items-center gap-1">
312
-
<Tooltip text="Jetstream">
313
-
<A
314
-
href={`/jetstream?dids=${params.repo}`}
315
-
class="-ml-1 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"
204
+
<Show when={location.hash === "#blobs"}>
205
+
<ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}>
206
+
<Suspense
207
+
fallback={
208
+
<div class="iconify lucide--loader-circle mt-2 animate-spin self-center text-xl" />
209
+
}
316
210
>
317
-
<span class="iconify lucide--radio-tower text-lg"></span>
318
-
</A>
319
-
</Tooltip>
211
+
<BlobView pds={pds!} repo={did} />
212
+
</Suspense>
213
+
</ErrorBoundary>
214
+
</Show>
215
+
<Show when={nsids() && (!location.hash || location.hash === "#collections")}>
320
216
<TextInput
321
217
name="filter"
322
218
placeholder="Filter collections"
323
-
onInput={(e) => setFilter(e.currentTarget.value)}
219
+
onInput={(e) => setFilter(e.currentTarget.value.toLowerCase())}
324
220
class="grow"
325
221
/>
326
-
</div>
327
-
<div class="flex flex-col font-mono">
328
-
<div class="grid grid-cols-[min-content_1fr] items-center gap-x-2 overflow-hidden text-sm">
222
+
<div class="flex flex-col overflow-hidden font-mono text-sm">
329
223
<For
330
224
each={Object.keys(nsids() ?? {}).filter((authority) =>
331
225
filter() ?
···
334
228
)}
335
229
>
336
230
{(authority) => (
337
-
<>
338
-
<button onclick={() => toggleCollection(authority)} class="flex items-center">
339
-
<span
340
-
classList={{
341
-
"iconify lucide--chevron-down text-lg transition-transform": true,
342
-
"-rotate-90": nsids()?.[authority].hidden,
343
-
}}
344
-
></span>
345
-
</button>
346
-
<button
347
-
class="bg-transparent text-left wrap-anywhere"
348
-
onclick={() => toggleCollection(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
+
)}
349
236
>
350
-
{authority}
351
-
</button>
352
-
<Show when={!nsids()?.[authority].hidden}>
353
-
<div></div>
354
-
<div class="flex flex-col">
355
-
<For
356
-
each={nsids()?.[authority].nsids.filter((nsid) =>
357
-
filter() ?
358
-
nsid.startsWith(filter()!.split(".").slice(2).join("."))
359
-
: true,
360
-
)}
237
+
{(nsid) => (
238
+
<A
239
+
href={`/at://${did}/${authority}.${nsid}`}
240
+
class="hover:underline active:underline"
361
241
>
362
-
{(nsid) => (
363
-
<A
364
-
href={`/at://${did}/${authority}.${nsid}`}
365
-
class="text-blue-400 hover:underline active:underline"
366
-
>
367
-
{authority}.{nsid}
368
-
</A>
369
-
)}
370
-
</For>
371
-
</div>
372
-
</Show>
373
-
</>
242
+
<span>{authority}</span>
243
+
<span class="text-neutral-500 dark:text-neutral-400">.{nsid}</span>
244
+
</A>
245
+
)}
246
+
</For>
247
+
</div>
374
248
)}
375
249
</For>
376
250
</div>
377
-
</div>
378
-
</Show>
379
-
<Show when={location.hash === "#identity"}>
380
-
<Show when={didDoc()}>
381
-
{(didDocument) => (
382
-
<div class="flex flex-col gap-y-2 wrap-anywhere">
383
-
<div class="flex flex-col gap-y-1">
251
+
</Show>
252
+
<Show when={location.hash === "#identity"}>
253
+
<Show when={didDoc()}>
254
+
{(didDocument) => (
255
+
<div class="flex flex-col gap-y-1 wrap-anywhere">
384
256
<div class="flex items-baseline justify-between gap-2">
385
257
<div>
386
258
<div class="flex items-center gap-1">
···
410
282
</div>
411
283
<ul>
412
284
<For each={didDocument().alsoKnownAs}>
413
-
{(alias) => <li class="text-sm">{alias}</li>}
285
+
{(alias) => (
286
+
<li class="flex items-center gap-1 text-sm">
287
+
<span>{alias}</span>
288
+
<Show when={alias.startsWith("at://")}>
289
+
<Tooltip
290
+
text={
291
+
validHandles[alias] === true ? "Valid handle"
292
+
: validHandles[alias] === undefined ?
293
+
"Validating"
294
+
: "Invalid handle"
295
+
}
296
+
>
297
+
<span
298
+
classList={{
299
+
"iconify lucide--circle-check": validHandles[alias] === true,
300
+
"iconify lucide--circle-x text-red-500 dark:text-red-400":
301
+
validHandles[alias] === false,
302
+
"iconify lucide--loader-circle animate-spin":
303
+
validHandles[alias] === undefined,
304
+
}}
305
+
></span>
306
+
</Tooltip>
307
+
</Show>
308
+
</li>
309
+
)}
414
310
</For>
415
311
</ul>
416
312
</div>
···
425
321
<li class="flex flex-col text-sm">
426
322
<span>#{service.id.split("#")[1]}</span>
427
323
<a
428
-
class="w-fit text-blue-400 hover:underline active:underline"
324
+
class="w-fit underline"
429
325
href={service.serviceEndpoint.toString()}
430
326
target="_blank"
431
327
>
···
447
343
<Show when={verif.publicKeyMultibase}>
448
344
{(key) => (
449
345
<li class="flex flex-col text-sm">
450
-
<span class="flex justify-between gap-1">
451
-
<span>#{verif.id.split("#")[1]}</span>
452
-
<span class="flex items-center gap-0.5">
453
-
<div class="iconify lucide--key-round" />
454
-
<ErrorBoundary fallback={<>unknown</>}>
455
-
{parsePublicMultikey(key()).type}
456
-
</ErrorBoundary>
457
-
</span>
346
+
<span>#{verif.id.split("#")[1]}</span>
347
+
<span class="flex items-center gap-0.5">
348
+
<div class="iconify lucide--key-round" />
349
+
<ErrorBoundary fallback={<>unknown</>}>
350
+
{parsePublicMultikey(key()).type}
351
+
</ErrorBoundary>
458
352
</span>
459
353
<span class="truncate">{key()}</span>
460
354
</li>
···
465
359
</ul>
466
360
</div>
467
361
</div>
468
-
<div class="flex justify-between">
469
-
<Show when={did.startsWith("did:plc")}>
470
-
<div class="flex items-center gap-1">
471
-
<Button
472
-
onClick={async () => {
473
-
if (!plcOps()) {
474
-
setLoading(true);
475
-
const response = await fetch(
476
-
`${localStorage.plcDirectory ?? "https://plc.directory"}/${did}/log/audit`,
477
-
);
478
-
const json = await response.json();
479
-
try {
480
-
const logs = defs.indexedEntryLog.parse(json);
481
-
try {
482
-
await processIndexedEntryLog(did as any, logs);
483
-
} catch (e) {
484
-
console.error(e);
485
-
}
486
-
const opHistory = createOperationHistory(logs).reverse();
487
-
setPlcOps(Array.from(groupBy(opHistory, (item) => item.orig)));
488
-
setLoading(false);
489
-
} catch (e: any) {
490
-
setNotice(e);
491
-
console.error(e);
492
-
setLoading(false);
493
-
}
494
-
}
495
-
496
-
setShowPlcLogs(!showPlcLogs());
497
-
}}
498
-
>
499
-
<span class="iconify lucide--logs text-sm"></span>
500
-
{showPlcLogs() ? "Hide" : "Show"} PLC Logs
501
-
</Button>
502
-
<Show when={loading()}>
503
-
<div class="iconify lucide--loader-circle animate-spin text-xl" />
504
-
</Show>
505
-
</div>
506
-
</Show>
507
-
<Show when={error()?.length === 0 || error() === undefined}>
508
-
<div
509
-
classList={{
510
-
"flex items-center gap-1": true,
511
-
"flex-row-reverse": did.startsWith("did:web"),
512
-
}}
513
-
>
514
-
<Show when={downloading()}>
515
-
<div class="iconify lucide--loader-circle animate-spin text-xl" />
516
-
</Show>
517
-
<Button onClick={() => downloadRepo()}>
518
-
<span class="iconify lucide--download text-sm"></span>
519
-
Export Repo
520
-
</Button>
521
-
</div>
522
-
</Show>
523
-
</div>
524
-
<Show when={showPlcLogs()}>
525
-
<Show when={notice()}>
526
-
<div>{notice()}</div>
527
-
</Show>
528
-
<PlcLogView plcOps={plcOps() ?? []} did={did} />
529
-
</Show>
530
-
</div>
531
-
)}
362
+
)}
363
+
</Show>
532
364
</Show>
533
-
</Show>
365
+
</div>
534
366
</div>
535
367
</Show>
536
368
);
537
369
};
538
-
539
-
export { RepoView };