+3
.gitignore
+3
.gitignore
-2
.npmrc
-2
.npmrc
+1
-1
.vscode/settings.json
+1
-1
.vscode/settings.json
+14
LICENSE
+14
LICENSE
···
1
+
BSD Zero Clause License
2
+
3
+
Copyright (c) 2025 Mary
4
+
5
+
Permission to use, copy, modify, and/or distribute this software for any
6
+
purpose with or without fee is hereby granted.
7
+
8
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14
+
PERFORMANCE OF THIS SOFTWARE.
+32
-28
package.json
+32
-28
package.json
···
4
4
"dev": "vite",
5
5
"build": "tsc -b && vite build",
6
6
"preview": "vite preview",
7
-
"fmt": "prettier --cache --write ."
7
+
"fmt": "PRETTIER_EXPERIMENTAL_CLI=1 prettier --cache --write ."
8
8
},
9
9
"dependencies": {
10
-
"@atcute/bluesky": "^1.0.14",
11
-
"@atcute/car": "^3.0.0",
12
-
"@atcute/cbor": "^2.2.0",
13
-
"@atcute/cid": "^2.2.0",
14
-
"@atcute/client": "^2.0.8",
15
-
"@atcute/crypto": "^2.2.0",
16
-
"@atcute/did-plc": "^0.1.1",
17
-
"@atcute/identity": "^0.1.1",
18
-
"@atcute/identity-resolver": "^0.1.2",
19
-
"@atcute/multibase": "^1.1.2",
20
-
"@atcute/tid": "^1.0.2",
21
-
"@badrap/valita": "^0.4.3",
22
-
"@mary/array-fns": "npm:@jsr/mary__array-fns@^0.1.4",
23
-
"@mary/events": "npm:@jsr/mary__events@^0.1.0",
10
+
"@atcute/atproto": "^3.1.9",
11
+
"@atcute/bluesky": "^3.2.13",
12
+
"@atcute/car": "^5.0.0",
13
+
"@atcute/cbor": "^2.2.8",
14
+
"@atcute/cid": "^2.2.6",
15
+
"@atcute/client": "^4.1.1",
16
+
"@atcute/crypto": "^2.3.0",
17
+
"@atcute/did-plc": "^0.2.0",
18
+
"@atcute/identity": "^1.1.3",
19
+
"@atcute/identity-resolver": "^1.2.0",
20
+
"@atcute/lexicons": "^1.2.5",
21
+
"@atcute/multibase": "^1.1.6",
22
+
"@atcute/repo": "^0.1.0",
23
+
"@atcute/tid": "^1.0.3",
24
+
"@badrap/valita": "^0.4.6",
25
+
"@mary/array-fns": "jsr:^0.1.5",
26
+
"@mary/ds-queue": "jsr:^0.1.3",
27
+
"@mary/events": "jsr:^0.2.0",
24
28
"@mary/solid-freeze": "npm:@externdefs/solid-freeze@^0.1.1",
25
-
"@mary/tar": "npm:@jsr/mary__tar@^0.2.4",
26
-
"nanoid": "^5.1.5",
29
+
"@mary/tar": "jsr:^0.3.1",
30
+
"nanoid": "^5.1.6",
27
31
"native-file-system-adapter": "^3.0.1",
28
-
"solid-js": "^1.9.5"
32
+
"solid-js": "^1.9.10"
29
33
},
30
34
"devDependencies": {
31
35
"@tailwindcss/forms": "^0.5.10",
32
-
"@types/node": "^22.13.12",
33
-
"autoprefixer": "^10.4.21",
34
-
"prettier": "^3.5.3",
35
-
"prettier-plugin-tailwindcss": "^0.6.11",
36
-
"tailwindcss": "^3.4.17",
37
-
"terser": "^5.39.0",
38
-
"typescript": "5.8.2",
39
-
"vite": "^6.2.2",
40
-
"vite-plugin-solid": "^2.11.6",
41
-
"wrangler": "^4.4.0"
36
+
"@types/node": "^22.19.2",
37
+
"autoprefixer": "^10.4.22",
38
+
"prettier": "^3.7.4",
39
+
"prettier-plugin-tailwindcss": "^0.6.14",
40
+
"tailwindcss": "^3.4.18",
41
+
"terser": "^5.44.1",
42
+
"typescript": "~5.9.3",
43
+
"vite": "^7.2.7",
44
+
"vite-plugin-solid": "^2.11.10",
45
+
"wrangler": "^4.53.0"
42
46
}
43
47
}
+1051
-1175
pnpm-lock.yaml
+1051
-1175
pnpm-lock.yaml
···
8
8
9
9
.:
10
10
dependencies:
11
+
'@atcute/atproto':
12
+
specifier: ^3.1.9
13
+
version: 3.1.9
11
14
'@atcute/bluesky':
12
-
specifier: ^1.0.14
13
-
version: 1.0.14(@atcute/client@2.0.8)
15
+
specifier: ^3.2.13
16
+
version: 3.2.13
14
17
'@atcute/car':
15
-
specifier: ^3.0.0
16
-
version: 3.0.0
18
+
specifier: ^5.0.0
19
+
version: 5.0.0
17
20
'@atcute/cbor':
18
-
specifier: ^2.2.0
19
-
version: 2.2.0
21
+
specifier: ^2.2.8
22
+
version: 2.2.8
20
23
'@atcute/cid':
21
-
specifier: ^2.2.0
22
-
version: 2.2.0
24
+
specifier: ^2.2.6
25
+
version: 2.2.6
23
26
'@atcute/client':
24
-
specifier: ^2.0.8
25
-
version: 2.0.8
27
+
specifier: ^4.1.1
28
+
version: 4.1.1
26
29
'@atcute/crypto':
27
-
specifier: ^2.2.0
28
-
version: 2.2.0
30
+
specifier: ^2.3.0
31
+
version: 2.3.0
29
32
'@atcute/did-plc':
30
-
specifier: ^0.1.1
31
-
version: 0.1.1
33
+
specifier: ^0.2.0
34
+
version: 0.2.0
32
35
'@atcute/identity':
33
-
specifier: ^0.1.1
34
-
version: 0.1.1
36
+
specifier: ^1.1.3
37
+
version: 1.1.3
35
38
'@atcute/identity-resolver':
36
-
specifier: ^0.1.2
37
-
version: 0.1.2(@atcute/identity@0.1.1)
39
+
specifier: ^1.2.0
40
+
version: 1.2.0(@atcute/identity@1.1.3)
41
+
'@atcute/lexicons':
42
+
specifier: ^1.2.5
43
+
version: 1.2.5
38
44
'@atcute/multibase':
39
-
specifier: ^1.1.2
40
-
version: 1.1.2
45
+
specifier: ^1.1.6
46
+
version: 1.1.6
47
+
'@atcute/repo':
48
+
specifier: ^0.1.0
49
+
version: 0.1.0
41
50
'@atcute/tid':
42
-
specifier: ^1.0.2
43
-
version: 1.0.2
51
+
specifier: ^1.0.3
52
+
version: 1.0.3
44
53
'@badrap/valita':
45
-
specifier: ^0.4.3
46
-
version: 0.4.3
54
+
specifier: ^0.4.6
55
+
version: 0.4.6
47
56
'@mary/array-fns':
48
-
specifier: npm:@jsr/mary__array-fns@^0.1.4
49
-
version: '@jsr/mary__array-fns@0.1.4'
57
+
specifier: jsr:^0.1.5
58
+
version: '@jsr/mary__array-fns@0.1.5'
59
+
'@mary/ds-queue':
60
+
specifier: jsr:^0.1.3
61
+
version: '@jsr/mary__ds-queue@0.1.3'
50
62
'@mary/events':
51
-
specifier: npm:@jsr/mary__events@^0.1.0
52
-
version: '@jsr/mary__events@0.1.0'
63
+
specifier: jsr:^0.2.0
64
+
version: '@jsr/mary__events@0.2.0'
53
65
'@mary/solid-freeze':
54
66
specifier: npm:@externdefs/solid-freeze@^0.1.1
55
-
version: '@externdefs/solid-freeze@0.1.1(solid-js@1.9.5)'
67
+
version: '@externdefs/solid-freeze@0.1.1(solid-js@1.9.10)'
56
68
'@mary/tar':
57
-
specifier: npm:@jsr/mary__tar@^0.2.4
58
-
version: '@jsr/mary__tar@0.2.4'
69
+
specifier: jsr:^0.3.1
70
+
version: '@jsr/mary__tar@0.3.1'
59
71
nanoid:
60
-
specifier: ^5.1.5
61
-
version: 5.1.5
72
+
specifier: ^5.1.6
73
+
version: 5.1.6
62
74
native-file-system-adapter:
63
75
specifier: ^3.0.1
64
76
version: 3.0.1
65
77
solid-js:
66
-
specifier: ^1.9.5
67
-
version: 1.9.5
78
+
specifier: ^1.9.10
79
+
version: 1.9.10
68
80
devDependencies:
69
81
'@tailwindcss/forms':
70
82
specifier: ^0.5.10
71
-
version: 0.5.10(tailwindcss@3.4.17)
83
+
version: 0.5.10(tailwindcss@3.4.18)
72
84
'@types/node':
73
-
specifier: ^22.13.12
74
-
version: 22.13.12
85
+
specifier: ^22.19.2
86
+
version: 22.19.2
75
87
autoprefixer:
76
-
specifier: ^10.4.21
77
-
version: 10.4.21(postcss@8.5.3)
88
+
specifier: ^10.4.22
89
+
version: 10.4.22(postcss@8.5.6)
78
90
prettier:
79
-
specifier: ^3.5.3
80
-
version: 3.5.3
91
+
specifier: ^3.7.4
92
+
version: 3.7.4
81
93
prettier-plugin-tailwindcss:
82
-
specifier: ^0.6.11
83
-
version: 0.6.11(prettier@3.5.3)
94
+
specifier: ^0.6.14
95
+
version: 0.6.14(prettier@3.7.4)
84
96
tailwindcss:
85
-
specifier: ^3.4.17
86
-
version: 3.4.17
97
+
specifier: ^3.4.18
98
+
version: 3.4.18
87
99
terser:
88
-
specifier: ^5.39.0
89
-
version: 5.39.0
100
+
specifier: ^5.44.1
101
+
version: 5.44.1
90
102
typescript:
91
-
specifier: 5.8.2
92
-
version: 5.8.2
103
+
specifier: ~5.9.3
104
+
version: 5.9.3
93
105
vite:
94
-
specifier: ^6.2.2
95
-
version: 6.2.2(@types/node@22.13.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.0)
106
+
specifier: ^7.2.7
107
+
version: 7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1)
96
108
vite-plugin-solid:
97
-
specifier: ^2.11.6
98
-
version: 2.11.6(solid-js@1.9.5)(vite@6.2.2(@types/node@22.13.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.0))
109
+
specifier: ^2.11.10
110
+
version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1))
99
111
wrangler:
100
-
specifier: ^4.4.0
101
-
version: 4.4.0
112
+
specifier: ^4.53.0
113
+
version: 4.53.0
102
114
103
115
packages:
104
116
···
106
118
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
107
119
engines: {node: '>=10'}
108
120
109
-
'@ampproject/remapping@2.3.0':
110
-
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
111
-
engines: {node: '>=6.0.0'}
121
+
'@atcute/atproto@3.1.9':
122
+
resolution: {integrity: sha512-DyWwHCTdR4hY2BPNbLXgVmm7lI+fceOwWbE4LXbGvbvVtSn+ejSVFaAv01Ra3kWDha0whsOmbJL8JP0QPpf1+w==}
112
123
113
-
'@atcute/bluesky@1.0.14':
114
-
resolution: {integrity: sha512-1ZBfvYsC/Tq7bqKSDzBcQRPDFguFodewow8z+MNRjS6DO9tLUWiKjm1DmR6sJfLQ2ktxU57IZPjvsvVfBdwJ6w==}
115
-
peerDependencies:
116
-
'@atcute/client': ^1.0.0 || ^2.0.0
124
+
'@atcute/bluesky@3.2.13':
125
+
resolution: {integrity: sha512-ZG/mqsCjVU6zvH6XsRw+oQglrsdu5R7mnncMO+Ux0KWbX2xJw4ZMFHfs7ZTC69dVPK9r/yle7YbpygZTOWDM9A==}
117
126
118
-
'@atcute/car@3.0.0':
119
-
resolution: {integrity: sha512-DBcA1i+PwejbfdE2KNhxnMwl9fgEAQ6QIRz3sHKJkNXnKIzOX+pnQtADR03Yxif139fI5BoPmJilzNP09o3AfQ==}
127
+
'@atcute/car@5.0.0':
128
+
resolution: {integrity: sha512-OIY2xTXv8lSpZsDSn/UYQtJSMvDw5Hi4Q+uyvmiqSM+fht08QRAEq/nxa5YFciPZ3nfDFnZ3//EgJw7QhkSXLQ==}
120
129
121
-
'@atcute/cbor@2.2.0':
122
-
resolution: {integrity: sha512-W3ttcDJHiB5N6MbfEpJbTINZSjg0KB8gpBds8UWOGmybqUnuz43HZkFSpF/Vom0KilYg6QWU/ZM4X8SXZE+kow==}
130
+
'@atcute/cbor@2.2.8':
131
+
resolution: {integrity: sha512-UzOAN9BuN6JCXgn0ryV8qZuRJUDrNqrbLd6EFM8jc6RYssjRyGRxNy6RZ1NU/07Hd8Tq/0pz8+nQiMu5Zai5uw==}
123
132
124
-
'@atcute/cid@2.2.0':
125
-
resolution: {integrity: sha512-ty+WjGcTfi1JJtcRNz6bsJMqT69lEIl4Ts7vl4U8SBHbxjbb6Tk/pcnQZVClKRYduRoZ1XhS9n5qOSIbIMctDA==}
133
+
'@atcute/cid@2.2.6':
134
+
resolution: {integrity: sha512-bTAHHbJ24p+E//V4KCS4xdmd39o211jJswvqQOevj7vk+5IYcgDLx1ryZWZ1sEPOo9x875li/kj5gpKL14RDwQ==}
126
135
127
-
'@atcute/client@2.0.8':
128
-
resolution: {integrity: sha512-OTfiWwjB4mOTlp2InGStvoQ+PIA5lvih9cTYU8BvOhzNcCBUpt4l860MKZExHjvQ9Tt1kjq/ED9zRiUjsAgIxw==}
136
+
'@atcute/client@4.1.1':
137
+
resolution: {integrity: sha512-FROCbTTCeL5u4tO/n72jDEKyKqjdlXMB56Ehve3W/gnnLGCYWvN42sS7tvL1Mgu6sbO3yZwsXKDrmM2No4XpjA==}
129
138
130
-
'@atcute/crypto@2.2.0':
131
-
resolution: {integrity: sha512-Q/64Qn1AI8J0ZNy4hPDPpW/3poKf4OWRUxIYceCDI+btEOcIG5YMlhEQeZd6ojnI3oBMXy03sbOktekaBYRK9Q==}
139
+
'@atcute/crypto@2.3.0':
140
+
resolution: {integrity: sha512-w5pkJKCjbNMQu+F4JRHbR3ROQyhi1wbn+GSC6WDQamcYHkZmEZk1/eoI354bIQOOfkEM6aFLv718iskrkon4GQ==}
132
141
133
-
'@atcute/did-plc@0.1.1':
134
-
resolution: {integrity: sha512-Yk18GUxWaEvHfH1CfPB4n2OOWVMcMIn1jKkeLzSykhLSbLcobCcA17LDY13pRG1b8PFdPIGUALKdquCTEk1CmA==}
142
+
'@atcute/did-plc@0.2.0':
143
+
resolution: {integrity: sha512-1sGek8GRM/Ph7nLVRREm8FqM7g4shGckItvdVwJcRbUa8Rh0zOsXQa0QyYWAC0k40BhkqO9FwKXhJEaXCmF5oQ==}
135
144
136
-
'@atcute/identity-resolver@0.1.2':
137
-
resolution: {integrity: sha512-fP2VbHD04kVcCdNi/Kszo6jFzqM7Pg3p33oGhfp2zVkwFKaVBlwCaFRWEga/Xvu/IDLwNdASGWnLqoA34SFeSg==}
145
+
'@atcute/identity-resolver@1.2.0':
146
+
resolution: {integrity: sha512-5UbSJfdV3JIkF8ksXz7g4nKBWasf2wROvzM66cfvTIWydWFO6/oS1KZd+zo9Eokje5Scf5+jsY9ZfgVARLepXg==}
138
147
peerDependencies:
139
-
'@atcute/identity': ^0.1.0
148
+
'@atcute/identity': ^1.0.0
140
149
141
-
'@atcute/identity@0.1.1':
142
-
resolution: {integrity: sha512-TijKOgvvOfp/QoMAqaiKLn+FnQi5XrxsWLVcVnvr5JoKlgF2yppNvVo0y62XEXZbgDuEMSav1v1tEjC4Hn7MzQ==}
150
+
'@atcute/identity@1.1.3':
151
+
resolution: {integrity: sha512-oIqPoI8TwWeQxvcLmFEZLdN2XdWcaLVtlm8pNk0E72As9HNzzD9pwKPrLr3rmTLRIoULPPFmq9iFNsTeCIU9ng==}
143
152
144
-
'@atcute/multibase@1.1.2':
145
-
resolution: {integrity: sha512-KFX+c7a/u2jSNcRw0rLaUHG/XEKf1A1c8XF5soHnsb1JMCShihf/anfZ1kJ4no/IlIp9HEHV3PQRQO2sWL6ASQ==}
153
+
'@atcute/lexicons@1.2.5':
154
+
resolution: {integrity: sha512-9yO9WdgxW8jZ7SbzUycH710z+JmsQ9W9n5S6i6eghYju32kkluFmgBeS47r8e8p2+Dv4DemS7o/3SUGsX9FR5Q==}
146
155
147
-
'@atcute/tid@1.0.2':
148
-
resolution: {integrity: sha512-ahmjroNyeDPJhtuf3+HTJropaH04HmJ8fhntDu73Gpz/RkAF7+nkz6kcP2QTgfvMCgMPAJUdskAAP82GPDTY9w==}
156
+
'@atcute/mst@0.1.0':
157
+
resolution: {integrity: sha512-h+iDToKEnBpigk2DOHjSqY63vJtjYKUIztqu1CZ0P+I54wV2SrgoqAXAT1xrW6A1Iup8cjTv+U2H5WVG4KxPLw==}
158
+
159
+
'@atcute/multibase@1.1.6':
160
+
resolution: {integrity: sha512-HBxuCgYLKPPxETV0Rot4VP9e24vKl8JdzGCZOVsDaOXJgbRZoRIF67Lp0H/OgnJeH/Xpva8Z5ReoTNJE5dn3kg==}
149
161
150
-
'@atcute/uint8array@1.0.1':
151
-
resolution: {integrity: sha512-AAnlFKyfDRgb9GNZJbhQ6OuMhbmNPirQyapb8KnmcEhxQZ3+tt+4NcwqekEegY4MpNqSTYeeTdyxq0wGZv1JHg==}
162
+
'@atcute/repo@0.1.0':
163
+
resolution: {integrity: sha512-INiYAuma8dydBu7cqd2WVpcXh3mzhIepYBUqFWAK5MqMulPRLTRCc/9GW3G9pxYrOdlvLCVamG2Jf8XK0nuFEw==}
164
+
165
+
'@atcute/tid@1.0.3':
166
+
resolution: {integrity: sha512-wfMJx1IMdnu0CZgWl0uR4JO2s6PGT1YPhpytD4ZHzEYKKQVuqV6Eb/7vieaVo1eYNMp2FrY67FZObeR7utRl2w==}
167
+
168
+
'@atcute/uint8array@1.0.6':
169
+
resolution: {integrity: sha512-ucfRBQc7BFT8n9eCyGOzDHEMKF/nZwhS2pPao4Xtab1ML3HdFYcX2DM1tadCzas85QTGxHe5urnUAAcNKGRi9A==}
170
+
171
+
'@atcute/util-fetch@1.0.4':
172
+
resolution: {integrity: sha512-sIU9Qk0dE8PLEXSfhy+gIJV+HpiiknMytCI2SqLlqd0vgZUtEKI/EQfP+23LHWvP+CLCzVDOa6cpH045OlmNBg==}
152
173
153
-
'@atcute/util-fetch@1.0.1':
154
-
resolution: {integrity: sha512-Clc0E/5ufyGBVfYBUwWNlHONlZCoblSr4Ho50l1LhmRPGB1Wu/AQ9Sz+rsBg7fdaW/auve8ulmwhRhnX2cGRow==}
174
+
'@atcute/varint@1.0.3':
175
+
resolution: {integrity: sha512-fdvMPyBB+McDT+Ai5e9RwEbwYV4yjZ60S2Dn5PTjGqUyxvoCH1z42viuheDZRUDkmfQehXJTZ5az7dSozVNtog==}
155
176
156
-
'@atcute/varint@1.0.2':
157
-
resolution: {integrity: sha512-0O31hePzzr4O3NGWHUKKOyta6CGSL+AtN8iir8grGxu9jXyI7DBARlw6PbgKA6uTAvsXdpmRmF8MX+p0TsLnNg==}
177
+
'@babel/code-frame@7.27.1':
178
+
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
179
+
engines: {node: '>=6.9.0'}
158
180
159
-
'@babel/code-frame@7.26.2':
160
-
resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
181
+
'@babel/compat-data@7.28.5':
182
+
resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==}
161
183
engines: {node: '>=6.9.0'}
162
184
163
-
'@babel/compat-data@7.26.8':
164
-
resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==}
185
+
'@babel/core@7.28.5':
186
+
resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==}
165
187
engines: {node: '>=6.9.0'}
166
188
167
-
'@babel/core@7.26.10':
168
-
resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==}
189
+
'@babel/generator@7.28.5':
190
+
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
169
191
engines: {node: '>=6.9.0'}
170
192
171
-
'@babel/generator@7.26.10':
172
-
resolution: {integrity: sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==}
193
+
'@babel/helper-compilation-targets@7.27.2':
194
+
resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
173
195
engines: {node: '>=6.9.0'}
174
196
175
-
'@babel/helper-compilation-targets@7.26.5':
176
-
resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==}
197
+
'@babel/helper-globals@7.28.0':
198
+
resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
177
199
engines: {node: '>=6.9.0'}
178
200
179
201
'@babel/helper-module-imports@7.18.6':
180
202
resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==}
181
203
engines: {node: '>=6.9.0'}
182
204
183
-
'@babel/helper-module-imports@7.25.9':
184
-
resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==}
205
+
'@babel/helper-module-imports@7.27.1':
206
+
resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
185
207
engines: {node: '>=6.9.0'}
186
208
187
-
'@babel/helper-module-transforms@7.26.0':
188
-
resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==}
209
+
'@babel/helper-module-transforms@7.28.3':
210
+
resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
189
211
engines: {node: '>=6.9.0'}
190
212
peerDependencies:
191
213
'@babel/core': ^7.0.0
192
214
193
-
'@babel/helper-plugin-utils@7.26.5':
194
-
resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==}
215
+
'@babel/helper-plugin-utils@7.27.1':
216
+
resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
195
217
engines: {node: '>=6.9.0'}
196
218
197
-
'@babel/helper-string-parser@7.25.9':
198
-
resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
219
+
'@babel/helper-string-parser@7.27.1':
220
+
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
199
221
engines: {node: '>=6.9.0'}
200
222
201
-
'@babel/helper-validator-identifier@7.25.9':
202
-
resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
223
+
'@babel/helper-validator-identifier@7.28.5':
224
+
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
203
225
engines: {node: '>=6.9.0'}
204
226
205
-
'@babel/helper-validator-option@7.25.9':
206
-
resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}
227
+
'@babel/helper-validator-option@7.27.1':
228
+
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
207
229
engines: {node: '>=6.9.0'}
208
230
209
-
'@babel/helpers@7.26.10':
210
-
resolution: {integrity: sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==}
231
+
'@babel/helpers@7.28.4':
232
+
resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
211
233
engines: {node: '>=6.9.0'}
212
234
213
-
'@babel/parser@7.26.10':
214
-
resolution: {integrity: sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==}
235
+
'@babel/parser@7.28.5':
236
+
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
215
237
engines: {node: '>=6.0.0'}
216
238
hasBin: true
217
239
218
-
'@babel/plugin-syntax-jsx@7.25.9':
219
-
resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==}
240
+
'@babel/plugin-syntax-jsx@7.27.1':
241
+
resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==}
220
242
engines: {node: '>=6.9.0'}
221
243
peerDependencies:
222
244
'@babel/core': ^7.0.0-0
223
245
224
-
'@babel/template@7.26.9':
225
-
resolution: {integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==}
246
+
'@babel/template@7.27.2':
247
+
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
226
248
engines: {node: '>=6.9.0'}
227
249
228
-
'@babel/traverse@7.26.10':
229
-
resolution: {integrity: sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==}
250
+
'@babel/traverse@7.28.5':
251
+
resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
230
252
engines: {node: '>=6.9.0'}
231
253
232
-
'@babel/types@7.26.10':
233
-
resolution: {integrity: sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==}
254
+
'@babel/types@7.28.5':
255
+
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
234
256
engines: {node: '>=6.9.0'}
235
257
236
-
'@badrap/valita@0.4.3':
237
-
resolution: {integrity: sha512-C9iZSrVlTb610dxZ2oatK5LwefaHv0Q9eYfVDH3co846x7WinhCfc8jCDTE55yM8WxlmOfX2ckKmsSr7KzZ/gg==}
258
+
'@badrap/valita@0.4.6':
259
+
resolution: {integrity: sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==}
238
260
engines: {node: '>= 18'}
239
261
240
-
'@cloudflare/kv-asset-handler@0.4.0':
241
-
resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==}
262
+
'@cloudflare/kv-asset-handler@0.4.1':
263
+
resolution: {integrity: sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==}
242
264
engines: {node: '>=18.0.0'}
243
265
244
-
'@cloudflare/unenv-preset@2.3.0':
245
-
resolution: {integrity: sha512-AaKYnbFpHaVDZGh3Hjy3oLYd12+LZw9aupAOudYJ+tjekahxcIqlSAr0zK9kPOdtgn10tzaqH7QJFUWcLE+k7g==}
266
+
'@cloudflare/unenv-preset@2.7.13':
267
+
resolution: {integrity: sha512-NulO1H8R/DzsJguLC0ndMuk4Ufv0KSlN+E54ay9rn9ZCQo0kpAPwwh3LhgpZ96a3Dr6L9LqW57M4CqC34iLOvw==}
246
268
peerDependencies:
247
-
unenv: 2.0.0-rc.15
248
-
workerd: ^1.20250311.0
269
+
unenv: 2.0.0-rc.24
270
+
workerd: ^1.20251202.0
249
271
peerDependenciesMeta:
250
272
workerd:
251
273
optional: true
252
274
253
-
'@cloudflare/workerd-darwin-64@1.20250320.0':
254
-
resolution: {integrity: sha512-wS2fcowxgbrKtfahU0Mtt/0XYjnuAjZd+2FsTZ3GDgxlywVTTl8SeApM11cjYo7QNdGh56HEGYMsYojya5sHHQ==}
275
+
'@cloudflare/workerd-darwin-64@1.20251202.0':
276
+
resolution: {integrity: sha512-/uvEAWEukTWb1geHhbjGUeZqcSSSyYzp0mvoPUBl+l0ont4NVGao3fgwM0q8wtKvgoKCHSG6zcG23wj9Opj3Nw==}
255
277
engines: {node: '>=16'}
256
278
cpu: [x64]
257
279
os: [darwin]
258
280
259
-
'@cloudflare/workerd-darwin-arm64@1.20250320.0':
260
-
resolution: {integrity: sha512-QMqFay2buv3pPE+mi30QenX/cmlaB72sXTspk5e4LwEEgsxpoS8BryeIOeo8ScGDyt0NBfOutCRFTTiZLSqyzQ==}
281
+
'@cloudflare/workerd-darwin-arm64@1.20251202.0':
282
+
resolution: {integrity: sha512-f52xRvcI9cWRd6400EZStRtXiRC5XKEud7K5aFIbbUv0VeINltujFQQ9nHWtsF6g1quIXWkjhh5u01gPAYNNXA==}
261
283
engines: {node: '>=16'}
262
284
cpu: [arm64]
263
285
os: [darwin]
264
286
265
-
'@cloudflare/workerd-linux-64@1.20250320.0':
266
-
resolution: {integrity: sha512-PBkmZdNtSIBRiFUhEMhkDoR5WX0bZWE+nSys0/v6DeFU3Pc6KiH+2VPGqWOLVH85uzL1wWFpAJk9ptsWwTC9Ww==}
287
+
'@cloudflare/workerd-linux-64@1.20251202.0':
288
+
resolution: {integrity: sha512-HYXinF5RBH7oXbsFUMmwKCj+WltpYbf5mRKUBG5v3EuPhUjSIFB84U+58pDyfBJjcynHdy3EtvTWcvh/+lcgow==}
267
289
engines: {node: '>=16'}
268
290
cpu: [x64]
269
291
os: [linux]
270
292
271
-
'@cloudflare/workerd-linux-arm64@1.20250320.0':
272
-
resolution: {integrity: sha512-nHSMsNbUwaOJRYuHYK4EcZreOP3FlFqD47FUxGP6k1tjYs4l4z86XJMONbY8vE9WZ9BWPAzZX/xzSalB0DhGIA==}
293
+
'@cloudflare/workerd-linux-arm64@1.20251202.0':
294
+
resolution: {integrity: sha512-++L02Jdoxz7hEA9qDaQjbVU1RzQS+S+eqIi22DkPe2Tgiq2M3UfNpeu+75k5L9DGRIkZPYvwMBMbcmKvQqdIIg==}
273
295
engines: {node: '>=16'}
274
296
cpu: [arm64]
275
297
os: [linux]
276
298
277
-
'@cloudflare/workerd-windows-64@1.20250320.0':
278
-
resolution: {integrity: sha512-Uj5z/PyGqO8xuVCkS19exmQ5yGcC1RbB3nUaf6j5rlft7lBTBkjC+l7NAhEiRxNKaZuT2Lfy+r4vAEPsiotegw==}
299
+
'@cloudflare/workerd-windows-64@1.20251202.0':
300
+
resolution: {integrity: sha512-gzeU6eDydTi7ib+Q9DD/c0hpXtqPucnHk2tfGU03mljPObYxzMkkPGgB5qxpksFvub3y4K0ChjqYxGJB4F+j3g==}
279
301
engines: {node: '>=16'}
280
302
cpu: [x64]
281
303
os: [win32]
···
284
306
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
285
307
engines: {node: '>=12'}
286
308
287
-
'@emnapi/runtime@1.3.1':
288
-
resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==}
309
+
'@emnapi/runtime@1.7.1':
310
+
resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==}
289
311
290
-
'@esbuild/aix-ppc64@0.24.2':
291
-
resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
312
+
'@esbuild/aix-ppc64@0.25.12':
313
+
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
292
314
engines: {node: '>=18'}
293
315
cpu: [ppc64]
294
316
os: [aix]
295
317
296
-
'@esbuild/aix-ppc64@0.25.1':
297
-
resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==}
318
+
'@esbuild/aix-ppc64@0.27.0':
319
+
resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==}
298
320
engines: {node: '>=18'}
299
321
cpu: [ppc64]
300
322
os: [aix]
301
323
302
-
'@esbuild/android-arm64@0.24.2':
303
-
resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
324
+
'@esbuild/android-arm64@0.25.12':
325
+
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
304
326
engines: {node: '>=18'}
305
327
cpu: [arm64]
306
328
os: [android]
307
329
308
-
'@esbuild/android-arm64@0.25.1':
309
-
resolution: {integrity: sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==}
330
+
'@esbuild/android-arm64@0.27.0':
331
+
resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==}
310
332
engines: {node: '>=18'}
311
333
cpu: [arm64]
312
334
os: [android]
313
335
314
-
'@esbuild/android-arm@0.24.2':
315
-
resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
336
+
'@esbuild/android-arm@0.25.12':
337
+
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
316
338
engines: {node: '>=18'}
317
339
cpu: [arm]
318
340
os: [android]
319
341
320
-
'@esbuild/android-arm@0.25.1':
321
-
resolution: {integrity: sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==}
342
+
'@esbuild/android-arm@0.27.0':
343
+
resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==}
322
344
engines: {node: '>=18'}
323
345
cpu: [arm]
324
346
os: [android]
325
347
326
-
'@esbuild/android-x64@0.24.2':
327
-
resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
348
+
'@esbuild/android-x64@0.25.12':
349
+
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
328
350
engines: {node: '>=18'}
329
351
cpu: [x64]
330
352
os: [android]
331
353
332
-
'@esbuild/android-x64@0.25.1':
333
-
resolution: {integrity: sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==}
354
+
'@esbuild/android-x64@0.27.0':
355
+
resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==}
334
356
engines: {node: '>=18'}
335
357
cpu: [x64]
336
358
os: [android]
337
359
338
-
'@esbuild/darwin-arm64@0.24.2':
339
-
resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
360
+
'@esbuild/darwin-arm64@0.25.12':
361
+
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
340
362
engines: {node: '>=18'}
341
363
cpu: [arm64]
342
364
os: [darwin]
343
365
344
-
'@esbuild/darwin-arm64@0.25.1':
345
-
resolution: {integrity: sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==}
366
+
'@esbuild/darwin-arm64@0.27.0':
367
+
resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==}
346
368
engines: {node: '>=18'}
347
369
cpu: [arm64]
348
370
os: [darwin]
349
371
350
-
'@esbuild/darwin-x64@0.24.2':
351
-
resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
372
+
'@esbuild/darwin-x64@0.25.12':
373
+
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
352
374
engines: {node: '>=18'}
353
375
cpu: [x64]
354
376
os: [darwin]
355
377
356
-
'@esbuild/darwin-x64@0.25.1':
357
-
resolution: {integrity: sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==}
378
+
'@esbuild/darwin-x64@0.27.0':
379
+
resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==}
358
380
engines: {node: '>=18'}
359
381
cpu: [x64]
360
382
os: [darwin]
361
383
362
-
'@esbuild/freebsd-arm64@0.24.2':
363
-
resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
384
+
'@esbuild/freebsd-arm64@0.25.12':
385
+
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
364
386
engines: {node: '>=18'}
365
387
cpu: [arm64]
366
388
os: [freebsd]
367
389
368
-
'@esbuild/freebsd-arm64@0.25.1':
369
-
resolution: {integrity: sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==}
390
+
'@esbuild/freebsd-arm64@0.27.0':
391
+
resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==}
370
392
engines: {node: '>=18'}
371
393
cpu: [arm64]
372
394
os: [freebsd]
373
395
374
-
'@esbuild/freebsd-x64@0.24.2':
375
-
resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
396
+
'@esbuild/freebsd-x64@0.25.12':
397
+
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
376
398
engines: {node: '>=18'}
377
399
cpu: [x64]
378
400
os: [freebsd]
379
401
380
-
'@esbuild/freebsd-x64@0.25.1':
381
-
resolution: {integrity: sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==}
402
+
'@esbuild/freebsd-x64@0.27.0':
403
+
resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==}
382
404
engines: {node: '>=18'}
383
405
cpu: [x64]
384
406
os: [freebsd]
385
407
386
-
'@esbuild/linux-arm64@0.24.2':
387
-
resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
408
+
'@esbuild/linux-arm64@0.25.12':
409
+
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
388
410
engines: {node: '>=18'}
389
411
cpu: [arm64]
390
412
os: [linux]
391
413
392
-
'@esbuild/linux-arm64@0.25.1':
393
-
resolution: {integrity: sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==}
414
+
'@esbuild/linux-arm64@0.27.0':
415
+
resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==}
394
416
engines: {node: '>=18'}
395
417
cpu: [arm64]
396
418
os: [linux]
397
419
398
-
'@esbuild/linux-arm@0.24.2':
399
-
resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
420
+
'@esbuild/linux-arm@0.25.12':
421
+
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
400
422
engines: {node: '>=18'}
401
423
cpu: [arm]
402
424
os: [linux]
403
425
404
-
'@esbuild/linux-arm@0.25.1':
405
-
resolution: {integrity: sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==}
426
+
'@esbuild/linux-arm@0.27.0':
427
+
resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==}
406
428
engines: {node: '>=18'}
407
429
cpu: [arm]
408
430
os: [linux]
409
431
410
-
'@esbuild/linux-ia32@0.24.2':
411
-
resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
432
+
'@esbuild/linux-ia32@0.25.12':
433
+
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
412
434
engines: {node: '>=18'}
413
435
cpu: [ia32]
414
436
os: [linux]
415
437
416
-
'@esbuild/linux-ia32@0.25.1':
417
-
resolution: {integrity: sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==}
438
+
'@esbuild/linux-ia32@0.27.0':
439
+
resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==}
418
440
engines: {node: '>=18'}
419
441
cpu: [ia32]
420
442
os: [linux]
421
443
422
-
'@esbuild/linux-loong64@0.24.2':
423
-
resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
444
+
'@esbuild/linux-loong64@0.25.12':
445
+
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
424
446
engines: {node: '>=18'}
425
447
cpu: [loong64]
426
448
os: [linux]
427
449
428
-
'@esbuild/linux-loong64@0.25.1':
429
-
resolution: {integrity: sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==}
450
+
'@esbuild/linux-loong64@0.27.0':
451
+
resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==}
430
452
engines: {node: '>=18'}
431
453
cpu: [loong64]
432
454
os: [linux]
433
455
434
-
'@esbuild/linux-mips64el@0.24.2':
435
-
resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
456
+
'@esbuild/linux-mips64el@0.25.12':
457
+
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
436
458
engines: {node: '>=18'}
437
459
cpu: [mips64el]
438
460
os: [linux]
439
461
440
-
'@esbuild/linux-mips64el@0.25.1':
441
-
resolution: {integrity: sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==}
462
+
'@esbuild/linux-mips64el@0.27.0':
463
+
resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==}
442
464
engines: {node: '>=18'}
443
465
cpu: [mips64el]
444
466
os: [linux]
445
467
446
-
'@esbuild/linux-ppc64@0.24.2':
447
-
resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
468
+
'@esbuild/linux-ppc64@0.25.12':
469
+
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
448
470
engines: {node: '>=18'}
449
471
cpu: [ppc64]
450
472
os: [linux]
451
473
452
-
'@esbuild/linux-ppc64@0.25.1':
453
-
resolution: {integrity: sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==}
474
+
'@esbuild/linux-ppc64@0.27.0':
475
+
resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==}
454
476
engines: {node: '>=18'}
455
477
cpu: [ppc64]
456
478
os: [linux]
457
479
458
-
'@esbuild/linux-riscv64@0.24.2':
459
-
resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
480
+
'@esbuild/linux-riscv64@0.25.12':
481
+
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
460
482
engines: {node: '>=18'}
461
483
cpu: [riscv64]
462
484
os: [linux]
463
485
464
-
'@esbuild/linux-riscv64@0.25.1':
465
-
resolution: {integrity: sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==}
486
+
'@esbuild/linux-riscv64@0.27.0':
487
+
resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==}
466
488
engines: {node: '>=18'}
467
489
cpu: [riscv64]
468
490
os: [linux]
469
491
470
-
'@esbuild/linux-s390x@0.24.2':
471
-
resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
492
+
'@esbuild/linux-s390x@0.25.12':
493
+
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
472
494
engines: {node: '>=18'}
473
495
cpu: [s390x]
474
496
os: [linux]
475
497
476
-
'@esbuild/linux-s390x@0.25.1':
477
-
resolution: {integrity: sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==}
498
+
'@esbuild/linux-s390x@0.27.0':
499
+
resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==}
478
500
engines: {node: '>=18'}
479
501
cpu: [s390x]
480
502
os: [linux]
481
503
482
-
'@esbuild/linux-x64@0.24.2':
483
-
resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
504
+
'@esbuild/linux-x64@0.25.12':
505
+
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
484
506
engines: {node: '>=18'}
485
507
cpu: [x64]
486
508
os: [linux]
487
509
488
-
'@esbuild/linux-x64@0.25.1':
489
-
resolution: {integrity: sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==}
510
+
'@esbuild/linux-x64@0.27.0':
511
+
resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==}
490
512
engines: {node: '>=18'}
491
513
cpu: [x64]
492
514
os: [linux]
493
515
494
-
'@esbuild/netbsd-arm64@0.24.2':
495
-
resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==}
516
+
'@esbuild/netbsd-arm64@0.25.12':
517
+
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
496
518
engines: {node: '>=18'}
497
519
cpu: [arm64]
498
520
os: [netbsd]
499
521
500
-
'@esbuild/netbsd-arm64@0.25.1':
501
-
resolution: {integrity: sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==}
522
+
'@esbuild/netbsd-arm64@0.27.0':
523
+
resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==}
502
524
engines: {node: '>=18'}
503
525
cpu: [arm64]
504
526
os: [netbsd]
505
527
506
-
'@esbuild/netbsd-x64@0.24.2':
507
-
resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
528
+
'@esbuild/netbsd-x64@0.25.12':
529
+
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
508
530
engines: {node: '>=18'}
509
531
cpu: [x64]
510
532
os: [netbsd]
511
533
512
-
'@esbuild/netbsd-x64@0.25.1':
513
-
resolution: {integrity: sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==}
534
+
'@esbuild/netbsd-x64@0.27.0':
535
+
resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==}
514
536
engines: {node: '>=18'}
515
537
cpu: [x64]
516
538
os: [netbsd]
517
539
518
-
'@esbuild/openbsd-arm64@0.24.2':
519
-
resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
540
+
'@esbuild/openbsd-arm64@0.25.12':
541
+
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
520
542
engines: {node: '>=18'}
521
543
cpu: [arm64]
522
544
os: [openbsd]
523
545
524
-
'@esbuild/openbsd-arm64@0.25.1':
525
-
resolution: {integrity: sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==}
546
+
'@esbuild/openbsd-arm64@0.27.0':
547
+
resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==}
526
548
engines: {node: '>=18'}
527
549
cpu: [arm64]
528
550
os: [openbsd]
529
551
530
-
'@esbuild/openbsd-x64@0.24.2':
531
-
resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
552
+
'@esbuild/openbsd-x64@0.25.12':
553
+
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
532
554
engines: {node: '>=18'}
533
555
cpu: [x64]
534
556
os: [openbsd]
535
557
536
-
'@esbuild/openbsd-x64@0.25.1':
537
-
resolution: {integrity: sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==}
558
+
'@esbuild/openbsd-x64@0.27.0':
559
+
resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==}
538
560
engines: {node: '>=18'}
539
561
cpu: [x64]
540
562
os: [openbsd]
541
563
542
-
'@esbuild/sunos-x64@0.24.2':
543
-
resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
564
+
'@esbuild/openharmony-arm64@0.25.12':
565
+
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
566
+
engines: {node: '>=18'}
567
+
cpu: [arm64]
568
+
os: [openharmony]
569
+
570
+
'@esbuild/openharmony-arm64@0.27.0':
571
+
resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==}
572
+
engines: {node: '>=18'}
573
+
cpu: [arm64]
574
+
os: [openharmony]
575
+
576
+
'@esbuild/sunos-x64@0.25.12':
577
+
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
544
578
engines: {node: '>=18'}
545
579
cpu: [x64]
546
580
os: [sunos]
547
581
548
-
'@esbuild/sunos-x64@0.25.1':
549
-
resolution: {integrity: sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==}
582
+
'@esbuild/sunos-x64@0.27.0':
583
+
resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==}
550
584
engines: {node: '>=18'}
551
585
cpu: [x64]
552
586
os: [sunos]
553
587
554
-
'@esbuild/win32-arm64@0.24.2':
555
-
resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
588
+
'@esbuild/win32-arm64@0.25.12':
589
+
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
556
590
engines: {node: '>=18'}
557
591
cpu: [arm64]
558
592
os: [win32]
559
593
560
-
'@esbuild/win32-arm64@0.25.1':
561
-
resolution: {integrity: sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==}
594
+
'@esbuild/win32-arm64@0.27.0':
595
+
resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==}
562
596
engines: {node: '>=18'}
563
597
cpu: [arm64]
564
598
os: [win32]
565
599
566
-
'@esbuild/win32-ia32@0.24.2':
567
-
resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
600
+
'@esbuild/win32-ia32@0.25.12':
601
+
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
568
602
engines: {node: '>=18'}
569
603
cpu: [ia32]
570
604
os: [win32]
571
605
572
-
'@esbuild/win32-ia32@0.25.1':
573
-
resolution: {integrity: sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==}
606
+
'@esbuild/win32-ia32@0.27.0':
607
+
resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==}
574
608
engines: {node: '>=18'}
575
609
cpu: [ia32]
576
610
os: [win32]
577
611
578
-
'@esbuild/win32-x64@0.24.2':
579
-
resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
612
+
'@esbuild/win32-x64@0.25.12':
613
+
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
580
614
engines: {node: '>=18'}
581
615
cpu: [x64]
582
616
os: [win32]
583
617
584
-
'@esbuild/win32-x64@0.25.1':
585
-
resolution: {integrity: sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==}
618
+
'@esbuild/win32-x64@0.27.0':
619
+
resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==}
586
620
engines: {node: '>=18'}
587
621
cpu: [x64]
588
622
os: [win32]
···
591
625
resolution: {integrity: sha512-duvZBfJB9oOLphx04ckKF534hP186xIBFaw4GHJ5fGeZY5syZs59UeumV5NC6aiEU9hVhAFMOnDDGkQrFqHrnQ==}
592
626
peerDependencies:
593
627
solid-js: ^1.8.5
594
-
595
-
'@fastify/busboy@2.1.1':
596
-
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
597
-
engines: {node: '>=14'}
598
628
599
629
'@img/sharp-darwin-arm64@0.33.5':
600
630
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
···
701
731
cpu: [x64]
702
732
os: [win32]
703
733
704
-
'@isaacs/cliui@8.0.2':
705
-
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
706
-
engines: {node: '>=12'}
734
+
'@jridgewell/gen-mapping@0.3.13':
735
+
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
707
736
708
-
'@jridgewell/gen-mapping@0.3.8':
709
-
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
710
-
engines: {node: '>=6.0.0'}
737
+
'@jridgewell/remapping@2.3.5':
738
+
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
711
739
712
740
'@jridgewell/resolve-uri@3.1.2':
713
741
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
714
742
engines: {node: '>=6.0.0'}
715
743
716
-
'@jridgewell/set-array@1.2.1':
717
-
resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
718
-
engines: {node: '>=6.0.0'}
744
+
'@jridgewell/source-map@0.3.11':
745
+
resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==}
719
746
720
-
'@jridgewell/source-map@0.3.6':
721
-
resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==}
747
+
'@jridgewell/sourcemap-codec@1.5.5':
748
+
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
722
749
723
-
'@jridgewell/sourcemap-codec@1.5.0':
724
-
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
725
-
726
-
'@jridgewell/trace-mapping@0.3.25':
727
-
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
750
+
'@jridgewell/trace-mapping@0.3.31':
751
+
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
728
752
729
753
'@jridgewell/trace-mapping@0.3.9':
730
754
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
731
755
732
-
'@jsr/mary__array-fns@0.1.4':
733
-
resolution: {integrity: sha512-+HbGYR9Ll5blEmAvVAoPejyGj01YeBbVmJ59qxaMDKt5i3F90ohYLA5a78y6AULDlet1IxYB+a/cMN+A0vGnDg==, tarball: https://npm.jsr.io/~/11/@jsr/mary__array-fns/0.1.4.tgz}
756
+
'@jsr/mary__array-fns@0.1.5':
757
+
resolution: {integrity: sha512-gI4scq/Hh9GtFUJfS8cvZf5nr+cs7udvrEpMv75grws5/0LIwBycKeeJcNi4+xNl6x4CGW6Fp46puhtJiQOpMg==, tarball: https://npm.jsr.io/~/11/@jsr/mary__array-fns/0.1.5.tgz}
758
+
759
+
'@jsr/mary__ds-queue@0.1.3':
760
+
resolution: {integrity: sha512-gGqIHXiAmhUUtonNI6YVvL7VlXjEHUpGdc7RGU8BLP4XnFvqovDTH5y9VlBZmvozTWgTIMoZF6/1//sMrvYKtQ==, tarball: https://npm.jsr.io/~/11/@jsr/mary__ds-queue/0.1.3.tgz}
734
761
735
-
'@jsr/mary__events@0.1.0':
736
-
resolution: {integrity: sha512-oS6jVOaXTaNEa6avRncwrEtUYaBKrq/HEybPa9Z3aoeMs+RSly0vn0KcOj/fy2H6iTBkeh3wa8+/9nFjhKyKIg==, tarball: https://npm.jsr.io/~/11/@jsr/mary__events/0.1.0.tgz}
762
+
'@jsr/mary__events@0.2.0':
763
+
resolution: {integrity: sha512-WcBRbtuTno3zcfXKd7SEeKr1lAJF+CQ8BCv+PEEMmNKNqFurkEksGxRB3UDPZxIxjJ7sAqMVTL26wRuMpAcIeA==, tarball: https://npm.jsr.io/~/11/@jsr/mary__events/0.2.0.tgz}
737
764
738
-
'@jsr/mary__tar@0.2.4':
739
-
resolution: {integrity: sha512-jFjPcZj8DRSukPLZOt6+h74cVFdfdTMG9gzbW67YByCJTD52PEpe2sNcfCSw4mQ8hZBNgwiufCPyYL8hR9yicA==, tarball: https://npm.jsr.io/~/11/@jsr/mary__tar/0.2.4.tgz}
765
+
'@jsr/mary__tar@0.3.1':
766
+
resolution: {integrity: sha512-T803kucwCLVOXFJGzVbpkT5vRK6fARy5HL6xMiLK5hJFck72bsAeluENlRnvD0kFPSlFNp/5EJWfTHnpDK0qYA==, tarball: https://npm.jsr.io/~/11/@jsr/mary__tar/0.3.1.tgz}
740
767
741
-
'@noble/secp256k1@2.2.3':
742
-
resolution: {integrity: sha512-l7r5oEQym9Us7EAigzg30/PQAvynhMt2uoYtT3t26eGDVm9Yii5mZ5jWSWmZ/oSIR2Et0xfc6DXrG0bZ787V3w==}
768
+
'@noble/secp256k1@3.0.0':
769
+
resolution: {integrity: sha512-NJBaR352KyIvj3t6sgT/+7xrNyF9Xk9QlLSIqUGVUYlsnDTAUqY8LOmwpcgEx4AMJXRITQ5XEVHD+mMaPfr3mg==}
743
770
744
771
'@nodelib/fs.scandir@2.1.5':
745
772
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
···
753
780
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
754
781
engines: {node: '>= 8'}
755
782
756
-
'@pkgjs/parseargs@0.11.0':
757
-
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
758
-
engines: {node: '>=14'}
783
+
'@poppinss/colors@4.1.5':
784
+
resolution: {integrity: sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==}
785
+
786
+
'@poppinss/dumper@0.6.5':
787
+
resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==}
788
+
789
+
'@poppinss/exception@1.2.2':
790
+
resolution: {integrity: sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==}
759
791
760
-
'@rollup/rollup-android-arm-eabi@4.37.0':
761
-
resolution: {integrity: sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ==}
792
+
'@rollup/rollup-android-arm-eabi@4.53.3':
793
+
resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==}
762
794
cpu: [arm]
763
795
os: [android]
764
796
765
-
'@rollup/rollup-android-arm64@4.37.0':
766
-
resolution: {integrity: sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA==}
797
+
'@rollup/rollup-android-arm64@4.53.3':
798
+
resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==}
767
799
cpu: [arm64]
768
800
os: [android]
769
801
770
-
'@rollup/rollup-darwin-arm64@4.37.0':
771
-
resolution: {integrity: sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA==}
802
+
'@rollup/rollup-darwin-arm64@4.53.3':
803
+
resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==}
772
804
cpu: [arm64]
773
805
os: [darwin]
774
806
775
-
'@rollup/rollup-darwin-x64@4.37.0':
776
-
resolution: {integrity: sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ==}
807
+
'@rollup/rollup-darwin-x64@4.53.3':
808
+
resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==}
777
809
cpu: [x64]
778
810
os: [darwin]
779
811
780
-
'@rollup/rollup-freebsd-arm64@4.37.0':
781
-
resolution: {integrity: sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA==}
812
+
'@rollup/rollup-freebsd-arm64@4.53.3':
813
+
resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==}
782
814
cpu: [arm64]
783
815
os: [freebsd]
784
816
785
-
'@rollup/rollup-freebsd-x64@4.37.0':
786
-
resolution: {integrity: sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA==}
817
+
'@rollup/rollup-freebsd-x64@4.53.3':
818
+
resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==}
787
819
cpu: [x64]
788
820
os: [freebsd]
789
821
790
-
'@rollup/rollup-linux-arm-gnueabihf@4.37.0':
791
-
resolution: {integrity: sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w==}
822
+
'@rollup/rollup-linux-arm-gnueabihf@4.53.3':
823
+
resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==}
792
824
cpu: [arm]
793
825
os: [linux]
794
826
795
-
'@rollup/rollup-linux-arm-musleabihf@4.37.0':
796
-
resolution: {integrity: sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag==}
827
+
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
828
+
resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==}
797
829
cpu: [arm]
798
830
os: [linux]
799
831
800
-
'@rollup/rollup-linux-arm64-gnu@4.37.0':
801
-
resolution: {integrity: sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA==}
832
+
'@rollup/rollup-linux-arm64-gnu@4.53.3':
833
+
resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==}
802
834
cpu: [arm64]
803
835
os: [linux]
804
836
805
-
'@rollup/rollup-linux-arm64-musl@4.37.0':
806
-
resolution: {integrity: sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ==}
837
+
'@rollup/rollup-linux-arm64-musl@4.53.3':
838
+
resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==}
807
839
cpu: [arm64]
808
840
os: [linux]
809
841
810
-
'@rollup/rollup-linux-loongarch64-gnu@4.37.0':
811
-
resolution: {integrity: sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA==}
842
+
'@rollup/rollup-linux-loong64-gnu@4.53.3':
843
+
resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==}
812
844
cpu: [loong64]
813
845
os: [linux]
814
846
815
-
'@rollup/rollup-linux-powerpc64le-gnu@4.37.0':
816
-
resolution: {integrity: sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ==}
847
+
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
848
+
resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==}
817
849
cpu: [ppc64]
818
850
os: [linux]
819
851
820
-
'@rollup/rollup-linux-riscv64-gnu@4.37.0':
821
-
resolution: {integrity: sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw==}
852
+
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
853
+
resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==}
822
854
cpu: [riscv64]
823
855
os: [linux]
824
856
825
-
'@rollup/rollup-linux-riscv64-musl@4.37.0':
826
-
resolution: {integrity: sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA==}
857
+
'@rollup/rollup-linux-riscv64-musl@4.53.3':
858
+
resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==}
827
859
cpu: [riscv64]
828
860
os: [linux]
829
861
830
-
'@rollup/rollup-linux-s390x-gnu@4.37.0':
831
-
resolution: {integrity: sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A==}
862
+
'@rollup/rollup-linux-s390x-gnu@4.53.3':
863
+
resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==}
832
864
cpu: [s390x]
833
865
os: [linux]
834
866
835
-
'@rollup/rollup-linux-x64-gnu@4.37.0':
836
-
resolution: {integrity: sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ==}
867
+
'@rollup/rollup-linux-x64-gnu@4.53.3':
868
+
resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==}
837
869
cpu: [x64]
838
870
os: [linux]
839
871
840
-
'@rollup/rollup-linux-x64-musl@4.37.0':
841
-
resolution: {integrity: sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w==}
872
+
'@rollup/rollup-linux-x64-musl@4.53.3':
873
+
resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==}
842
874
cpu: [x64]
843
875
os: [linux]
844
876
845
-
'@rollup/rollup-win32-arm64-msvc@4.37.0':
846
-
resolution: {integrity: sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg==}
877
+
'@rollup/rollup-openharmony-arm64@4.53.3':
878
+
resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==}
879
+
cpu: [arm64]
880
+
os: [openharmony]
881
+
882
+
'@rollup/rollup-win32-arm64-msvc@4.53.3':
883
+
resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==}
847
884
cpu: [arm64]
848
885
os: [win32]
849
886
850
-
'@rollup/rollup-win32-ia32-msvc@4.37.0':
851
-
resolution: {integrity: sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA==}
887
+
'@rollup/rollup-win32-ia32-msvc@4.53.3':
888
+
resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==}
852
889
cpu: [ia32]
853
890
os: [win32]
854
891
855
-
'@rollup/rollup-win32-x64-msvc@4.37.0':
856
-
resolution: {integrity: sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA==}
892
+
'@rollup/rollup-win32-x64-gnu@4.53.3':
893
+
resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==}
894
+
cpu: [x64]
895
+
os: [win32]
896
+
897
+
'@rollup/rollup-win32-x64-msvc@4.53.3':
898
+
resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==}
857
899
cpu: [x64]
858
900
os: [win32]
859
901
902
+
'@sindresorhus/is@7.1.1':
903
+
resolution: {integrity: sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ==}
904
+
engines: {node: '>=18'}
905
+
906
+
'@speed-highlight/core@1.2.12':
907
+
resolution: {integrity: sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA==}
908
+
909
+
'@standard-schema/spec@1.0.0':
910
+
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
911
+
860
912
'@tailwindcss/forms@0.5.10':
861
913
resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==}
862
914
peerDependencies:
···
865
917
'@types/babel__core@7.20.5':
866
918
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
867
919
868
-
'@types/babel__generator@7.6.8':
869
-
resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==}
920
+
'@types/babel__generator@7.27.0':
921
+
resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
870
922
871
923
'@types/babel__template@7.4.4':
872
924
resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
873
925
874
-
'@types/babel__traverse@7.20.6':
875
-
resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==}
926
+
'@types/babel__traverse@7.28.0':
927
+
resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
876
928
877
-
'@types/estree@1.0.6':
878
-
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
929
+
'@types/estree@1.0.8':
930
+
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
879
931
880
-
'@types/node@22.13.12':
881
-
resolution: {integrity: sha512-ixiWrCSRi33uqBMRuICcKECW7rtgY43TbsHDpM2XK7lXispd48opW+0IXrBVxv9NMhaz/Ue9kyj6r3NTVyXm8A==}
932
+
'@types/node@22.19.2':
933
+
resolution: {integrity: sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==}
882
934
883
935
acorn-walk@8.3.2:
884
936
resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
···
889
941
engines: {node: '>=0.4.0'}
890
942
hasBin: true
891
943
892
-
acorn@8.14.1:
893
-
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
944
+
acorn@8.15.0:
945
+
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
894
946
engines: {node: '>=0.4.0'}
895
947
hasBin: true
896
948
897
-
ansi-regex@5.0.1:
898
-
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
899
-
engines: {node: '>=8'}
900
-
901
-
ansi-regex@6.1.0:
902
-
resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
903
-
engines: {node: '>=12'}
904
-
905
-
ansi-styles@4.3.0:
906
-
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
907
-
engines: {node: '>=8'}
908
-
909
-
ansi-styles@6.2.1:
910
-
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
911
-
engines: {node: '>=12'}
912
-
913
949
any-promise@1.3.0:
914
950
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
915
951
···
920
956
arg@5.0.2:
921
957
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
922
958
923
-
as-table@1.0.55:
924
-
resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==}
925
-
926
-
autoprefixer@10.4.21:
927
-
resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==}
959
+
autoprefixer@10.4.22:
960
+
resolution: {integrity: sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==}
928
961
engines: {node: ^10 || ^12 || >=14}
929
962
hasBin: true
930
963
peerDependencies:
931
964
postcss: ^8.1.0
932
965
933
-
babel-plugin-jsx-dom-expressions@0.39.7:
934
-
resolution: {integrity: sha512-8GzVmFla7jaTNWW8W+lTMl9YGva4/06CtwJjySnkYtt8G1v9weCzc2SuF1DfrudcCNb2Doetc1FRg33swBYZCA==}
966
+
babel-plugin-jsx-dom-expressions@0.40.3:
967
+
resolution: {integrity: sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w==}
935
968
peerDependencies:
936
969
'@babel/core': ^7.20.12
937
970
938
-
babel-preset-solid@1.9.5:
939
-
resolution: {integrity: sha512-85I3osODJ1LvZbv8wFozROV1vXq32BubqHXAGu73A//TRs3NLI1OFP83AQBUTSQHwgZQmARjHlJciym3we+V+w==}
971
+
babel-preset-solid@1.9.10:
972
+
resolution: {integrity: sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ==}
940
973
peerDependencies:
941
974
'@babel/core': ^7.0.0
975
+
solid-js: ^1.9.10
976
+
peerDependenciesMeta:
977
+
solid-js:
978
+
optional: true
942
979
943
-
balanced-match@1.0.2:
944
-
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
980
+
baseline-browser-mapping@2.9.5:
981
+
resolution: {integrity: sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==}
982
+
hasBin: true
945
983
946
984
binary-extensions@2.3.0:
947
985
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
···
949
987
950
988
blake3-wasm@2.1.5:
951
989
resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
952
-
953
-
brace-expansion@2.0.1:
954
-
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
955
990
956
991
braces@3.0.3:
957
992
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
958
993
engines: {node: '>=8'}
959
994
960
-
browserslist@4.24.4:
961
-
resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==}
995
+
browserslist@4.28.1:
996
+
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
962
997
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
963
998
hasBin: true
964
999
···
969
1004
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
970
1005
engines: {node: '>= 6'}
971
1006
972
-
caniuse-lite@1.0.30001707:
973
-
resolution: {integrity: sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==}
1007
+
caniuse-lite@1.0.30001760:
1008
+
resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==}
974
1009
975
1010
chokidar@3.6.0:
976
1011
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
···
1000
1035
convert-source-map@2.0.0:
1001
1036
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
1002
1037
1003
-
cookie@0.5.0:
1004
-
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
1005
-
engines: {node: '>= 0.6'}
1006
-
1007
-
cross-spawn@7.0.6:
1008
-
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
1009
-
engines: {node: '>= 8'}
1038
+
cookie@1.1.1:
1039
+
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
1040
+
engines: {node: '>=18'}
1010
1041
1011
1042
cssesc@3.0.0:
1012
1043
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
1013
1044
engines: {node: '>=4'}
1014
1045
hasBin: true
1015
1046
1016
-
csstype@3.1.3:
1017
-
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
1047
+
csstype@3.2.3:
1048
+
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
1018
1049
1019
-
data-uri-to-buffer@2.0.2:
1020
-
resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==}
1021
-
1022
-
debug@4.4.0:
1023
-
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
1050
+
debug@4.4.3:
1051
+
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
1024
1052
engines: {node: '>=6.0'}
1025
1053
peerDependencies:
1026
1054
supports-color: '*'
···
1028
1056
supports-color:
1029
1057
optional: true
1030
1058
1031
-
defu@6.1.4:
1032
-
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
1033
-
1034
-
detect-libc@2.0.3:
1035
-
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
1059
+
detect-libc@2.1.2:
1060
+
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
1036
1061
engines: {node: '>=8'}
1037
1062
1038
1063
didyoumean@1.2.2:
···
1041
1066
dlv@1.1.3:
1042
1067
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
1043
1068
1044
-
eastasianwidth@0.2.0:
1045
-
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
1069
+
electron-to-chromium@1.5.267:
1070
+
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
1046
1071
1047
-
electron-to-chromium@1.5.123:
1048
-
resolution: {integrity: sha512-refir3NlutEZqlKaBLK0tzlVLe5P2wDKS7UQt/3SpibizgsRAPOsqQC3ffw1nlv3ze5gjRQZYHoPymgVZkplFA==}
1072
+
entities@6.0.1:
1073
+
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
1074
+
engines: {node: '>=0.12'}
1049
1075
1050
-
emoji-regex@8.0.0:
1051
-
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
1052
-
1053
-
emoji-regex@9.2.2:
1054
-
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
1076
+
error-stack-parser-es@1.0.5:
1077
+
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
1055
1078
1056
-
entities@4.5.0:
1057
-
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
1058
-
engines: {node: '>=0.12'}
1059
-
1060
-
esbuild@0.24.2:
1061
-
resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
1079
+
esbuild@0.25.12:
1080
+
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
1062
1081
engines: {node: '>=18'}
1063
1082
hasBin: true
1064
1083
1065
-
esbuild@0.25.1:
1066
-
resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==}
1084
+
esbuild@0.27.0:
1085
+
resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==}
1067
1086
engines: {node: '>=18'}
1068
1087
hasBin: true
1069
1088
···
1071
1090
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
1072
1091
engines: {node: '>=6'}
1073
1092
1093
+
esm-env@1.2.2:
1094
+
resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
1095
+
1074
1096
exit-hook@2.2.1:
1075
1097
resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==}
1076
1098
engines: {node: '>=6'}
1077
-
1078
-
exsolve@1.0.4:
1079
-
resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==}
1080
1099
1081
1100
fast-glob@3.3.3:
1082
1101
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
···
1085
1104
fastq@1.19.1:
1086
1105
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
1087
1106
1107
+
fdir@6.5.0:
1108
+
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
1109
+
engines: {node: '>=12.0.0'}
1110
+
peerDependencies:
1111
+
picomatch: ^3 || ^4
1112
+
peerDependenciesMeta:
1113
+
picomatch:
1114
+
optional: true
1115
+
1088
1116
fetch-blob@3.2.0:
1089
1117
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
1090
1118
engines: {node: ^12.20 || >= 14.13}
···
1093
1121
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
1094
1122
engines: {node: '>=8'}
1095
1123
1096
-
foreground-child@3.3.1:
1097
-
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
1098
-
engines: {node: '>=14'}
1099
-
1100
-
fraction.js@4.3.7:
1101
-
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
1124
+
fraction.js@5.3.4:
1125
+
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
1102
1126
1103
1127
fsevents@2.3.3:
1104
1128
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
···
1111
1135
gensync@1.0.0-beta.2:
1112
1136
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
1113
1137
engines: {node: '>=6.9.0'}
1114
-
1115
-
get-source@2.0.12:
1116
-
resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==}
1117
1138
1118
1139
glob-parent@5.1.2:
1119
1140
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
···
1126
1147
glob-to-regexp@0.4.1:
1127
1148
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
1128
1149
1129
-
glob@10.4.5:
1130
-
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
1131
-
hasBin: true
1132
-
1133
-
globals@11.12.0:
1134
-
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
1135
-
engines: {node: '>=4'}
1136
-
1137
1150
hasown@2.0.2:
1138
1151
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
1139
1152
engines: {node: '>= 0.4'}
···
1141
1154
html-entities@2.3.3:
1142
1155
resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
1143
1156
1144
-
is-arrayish@0.3.2:
1145
-
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
1157
+
is-arrayish@0.3.4:
1158
+
resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==}
1146
1159
1147
1160
is-binary-path@2.1.0:
1148
1161
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
···
1156
1169
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
1157
1170
engines: {node: '>=0.10.0'}
1158
1171
1159
-
is-fullwidth-code-point@3.0.0:
1160
-
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
1161
-
engines: {node: '>=8'}
1162
-
1163
1172
is-glob@4.0.3:
1164
1173
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
1165
1174
engines: {node: '>=0.10.0'}
···
1172
1181
resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
1173
1182
engines: {node: '>=12.13'}
1174
1183
1175
-
isexe@2.0.0:
1176
-
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
1177
-
1178
-
jackspeak@3.4.3:
1179
-
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
1180
-
1181
1184
jiti@1.21.7:
1182
1185
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
1183
1186
hasBin: true
···
1195
1198
engines: {node: '>=6'}
1196
1199
hasBin: true
1197
1200
1201
+
kleur@4.1.5:
1202
+
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
1203
+
engines: {node: '>=6'}
1204
+
1198
1205
lilconfig@3.1.3:
1199
1206
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
1200
1207
engines: {node: '>=14'}
···
1202
1209
lines-and-columns@1.2.4:
1203
1210
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
1204
1211
1205
-
lru-cache@10.4.3:
1206
-
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
1207
-
1208
1212
lru-cache@5.1.1:
1209
1213
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
1210
1214
···
1229
1233
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
1230
1234
hasBin: true
1231
1235
1232
-
miniflare@4.20250320.0:
1233
-
resolution: {integrity: sha512-dD9gpO/nWaLURbBXctB/FOJEDexPlSbplIApb5Ea3xGuSSh+3Iq/cfbgh3IdgueIGMJb6vvTiOWpiPA5naX6vg==}
1236
+
miniflare@4.20251202.1:
1237
+
resolution: {integrity: sha512-cRp2QNgnt9wpLMoNs4MOzzomyfe9UTS9sPRxIpUvxMl+mweCZ0FHpWWQvCnU7wWlfAP8VGZrHwqSsV5ERA6ahQ==}
1234
1238
engines: {node: '>=18.0.0'}
1235
1239
hasBin: true
1236
1240
1237
-
minimatch@9.0.5:
1238
-
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
1239
-
engines: {node: '>=16 || 14 >=14.17'}
1240
-
1241
-
minipass@7.1.2:
1242
-
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
1243
-
engines: {node: '>=16 || 14 >=14.17'}
1244
-
1245
1241
ms@2.1.3:
1246
1242
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
1247
1243
1248
-
mustache@4.2.0:
1249
-
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
1250
-
hasBin: true
1251
-
1252
1244
mz@2.7.0:
1253
1245
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
1254
1246
···
1257
1249
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
1258
1250
hasBin: true
1259
1251
1260
-
nanoid@5.1.5:
1261
-
resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==}
1252
+
nanoid@5.1.6:
1253
+
resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==}
1262
1254
engines: {node: ^18 || >=20}
1263
1255
hasBin: true
1264
1256
···
1269
1261
node-domexception@1.0.0:
1270
1262
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
1271
1263
engines: {node: '>=10.5.0'}
1264
+
deprecated: Use your platform's native DOMException instead
1272
1265
1273
-
node-releases@2.0.19:
1274
-
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
1266
+
node-releases@2.0.27:
1267
+
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
1275
1268
1276
1269
normalize-path@3.0.0:
1277
1270
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
···
1289
1282
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
1290
1283
engines: {node: '>= 6'}
1291
1284
1292
-
ohash@2.0.11:
1293
-
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
1294
-
1295
-
package-json-from-dist@1.0.1:
1296
-
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
1297
-
1298
-
parse5@7.2.1:
1299
-
resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==}
1300
-
1301
-
path-key@3.1.1:
1302
-
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
1303
-
engines: {node: '>=8'}
1285
+
parse5@7.3.0:
1286
+
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
1304
1287
1305
1288
path-parse@1.0.7:
1306
1289
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
1307
1290
1308
-
path-scurry@1.11.1:
1309
-
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
1310
-
engines: {node: '>=16 || 14 >=14.18'}
1311
-
1312
1291
path-to-regexp@6.3.0:
1313
1292
resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
1314
1293
···
1322
1301
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
1323
1302
engines: {node: '>=8.6'}
1324
1303
1304
+
picomatch@4.0.3:
1305
+
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
1306
+
engines: {node: '>=12'}
1307
+
1325
1308
pify@2.3.0:
1326
1309
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
1327
1310
engines: {node: '>=0.10.0'}
1328
1311
1329
-
pirates@4.0.6:
1330
-
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
1312
+
pirates@4.0.7:
1313
+
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
1331
1314
engines: {node: '>= 6'}
1332
1315
1333
1316
postcss-import@15.1.0:
···
1336
1319
peerDependencies:
1337
1320
postcss: ^8.0.0
1338
1321
1339
-
postcss-js@4.0.1:
1340
-
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
1322
+
postcss-js@4.1.0:
1323
+
resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==}
1341
1324
engines: {node: ^12 || ^14 || >= 16}
1342
1325
peerDependencies:
1343
1326
postcss: ^8.4.21
1344
1327
1345
-
postcss-load-config@4.0.2:
1346
-
resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
1347
-
engines: {node: '>= 14'}
1328
+
postcss-load-config@6.0.1:
1329
+
resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
1330
+
engines: {node: '>= 18'}
1348
1331
peerDependencies:
1332
+
jiti: '>=1.21.0'
1349
1333
postcss: '>=8.0.9'
1350
-
ts-node: '>=9.0.0'
1334
+
tsx: ^4.8.1
1335
+
yaml: ^2.4.2
1351
1336
peerDependenciesMeta:
1337
+
jiti:
1338
+
optional: true
1352
1339
postcss:
1353
1340
optional: true
1354
-
ts-node:
1341
+
tsx:
1342
+
optional: true
1343
+
yaml:
1355
1344
optional: true
1356
1345
1357
1346
postcss-nested@6.2.0:
···
1367
1356
postcss-value-parser@4.2.0:
1368
1357
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
1369
1358
1370
-
postcss@8.5.3:
1371
-
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
1359
+
postcss@8.5.6:
1360
+
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
1372
1361
engines: {node: ^10 || ^12 || >=14}
1373
1362
1374
-
prettier-plugin-tailwindcss@0.6.11:
1375
-
resolution: {integrity: sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==}
1363
+
prettier-plugin-tailwindcss@0.6.14:
1364
+
resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==}
1376
1365
engines: {node: '>=14.21.3'}
1377
1366
peerDependencies:
1378
1367
'@ianvs/prettier-plugin-sort-imports': '*'
1368
+
'@prettier/plugin-hermes': '*'
1369
+
'@prettier/plugin-oxc': '*'
1379
1370
'@prettier/plugin-pug': '*'
1380
1371
'@shopify/prettier-plugin-liquid': '*'
1381
1372
'@trivago/prettier-plugin-sort-imports': '*'
···
1394
1385
prettier-plugin-svelte: '*'
1395
1386
peerDependenciesMeta:
1396
1387
'@ianvs/prettier-plugin-sort-imports':
1388
+
optional: true
1389
+
'@prettier/plugin-hermes':
1390
+
optional: true
1391
+
'@prettier/plugin-oxc':
1397
1392
optional: true
1398
1393
'@prettier/plugin-pug':
1399
1394
optional: true
···
1426
1421
prettier-plugin-svelte:
1427
1422
optional: true
1428
1423
1429
-
prettier@3.5.3:
1430
-
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
1424
+
prettier@3.7.4:
1425
+
resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==}
1431
1426
engines: {node: '>=14'}
1432
1427
hasBin: true
1433
-
1434
-
printable-characters@1.0.42:
1435
-
resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==}
1436
1428
1437
1429
queue-microtask@1.2.3:
1438
1430
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
···
1444
1436
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
1445
1437
engines: {node: '>=8.10.0'}
1446
1438
1447
-
resolve@1.22.10:
1448
-
resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
1439
+
resolve@1.22.11:
1440
+
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
1449
1441
engines: {node: '>= 0.4'}
1450
1442
hasBin: true
1451
1443
···
1453
1445
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
1454
1446
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
1455
1447
1456
-
rollup@4.37.0:
1457
-
resolution: {integrity: sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg==}
1448
+
rollup@4.53.3:
1449
+
resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==}
1458
1450
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
1459
1451
hasBin: true
1460
1452
···
1465
1457
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
1466
1458
hasBin: true
1467
1459
1468
-
semver@7.7.1:
1469
-
resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
1460
+
semver@7.7.3:
1461
+
resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
1470
1462
engines: {node: '>=10'}
1471
1463
hasBin: true
1472
1464
1473
-
seroval-plugins@1.2.1:
1474
-
resolution: {integrity: sha512-H5vs53+39+x4Udwp4J5rNZfgFuA+Lt+uU+09w1gYBVWomtAl98B+E9w7yC05Xc81/HgLvJdlyqJbU0fJCKCmdw==}
1465
+
seroval-plugins@1.3.3:
1466
+
resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==}
1475
1467
engines: {node: '>=10'}
1476
1468
peerDependencies:
1477
1469
seroval: ^1.0
1478
1470
1479
-
seroval@1.2.1:
1480
-
resolution: {integrity: sha512-yBxFFs3zmkvKNmR0pFSU//rIsYjuX418TnlDmc2weaq5XFDqDIV/NOMPBoLrbxjLH42p4UzRuXHryXh9dYcKcw==}
1471
+
seroval@1.3.2:
1472
+
resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==}
1481
1473
engines: {node: '>=10'}
1482
1474
1483
1475
sharp@0.33.5:
1484
1476
resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
1485
1477
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
1486
1478
1487
-
shebang-command@2.0.0:
1488
-
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
1489
-
engines: {node: '>=8'}
1490
-
1491
-
shebang-regex@3.0.0:
1492
-
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
1493
-
engines: {node: '>=8'}
1479
+
simple-swizzle@0.2.4:
1480
+
resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
1494
1481
1495
-
signal-exit@4.1.0:
1496
-
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
1497
-
engines: {node: '>=14'}
1498
-
1499
-
simple-swizzle@0.2.2:
1500
-
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
1501
-
1502
-
solid-js@1.9.5:
1503
-
resolution: {integrity: sha512-ogI3DaFcyn6UhYhrgcyRAMbu/buBJitYQASZz5WzfQVPP10RD2AbCoRZ517psnezrasyCbWzIxZ6kVqet768xw==}
1482
+
solid-js@1.9.10:
1483
+
resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==}
1504
1484
1505
1485
solid-refresh@0.6.3:
1506
1486
resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==}
···
1518
1498
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
1519
1499
engines: {node: '>=0.10.0'}
1520
1500
1521
-
stacktracey@2.1.8:
1522
-
resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==}
1523
-
1524
1501
stoppable@1.1.0:
1525
1502
resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==}
1526
1503
engines: {node: '>=4', npm: '>=6'}
1527
1504
1528
-
string-width@4.2.3:
1529
-
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
1530
-
engines: {node: '>=8'}
1531
-
1532
-
string-width@5.1.2:
1533
-
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
1534
-
engines: {node: '>=12'}
1535
-
1536
-
strip-ansi@6.0.1:
1537
-
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
1538
-
engines: {node: '>=8'}
1539
-
1540
-
strip-ansi@7.1.0:
1541
-
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
1542
-
engines: {node: '>=12'}
1543
-
1544
-
sucrase@3.35.0:
1545
-
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
1505
+
sucrase@3.35.1:
1506
+
resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==}
1546
1507
engines: {node: '>=16 || 14 >=14.17'}
1547
1508
hasBin: true
1509
+
1510
+
supports-color@10.2.2:
1511
+
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
1512
+
engines: {node: '>=18'}
1548
1513
1549
1514
supports-preserve-symlinks-flag@1.0.0:
1550
1515
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
1551
1516
engines: {node: '>= 0.4'}
1552
1517
1553
-
tailwindcss@3.4.17:
1554
-
resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==}
1518
+
tailwindcss@3.4.18:
1519
+
resolution: {integrity: sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==}
1555
1520
engines: {node: '>=14.0.0'}
1556
1521
hasBin: true
1557
1522
1558
-
terser@5.39.0:
1559
-
resolution: {integrity: sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==}
1523
+
terser@5.44.1:
1524
+
resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==}
1560
1525
engines: {node: '>=10'}
1561
1526
hasBin: true
1562
1527
···
1567
1532
thenify@3.3.1:
1568
1533
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
1569
1534
1535
+
tinyglobby@0.2.15:
1536
+
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
1537
+
engines: {node: '>=12.0.0'}
1538
+
1570
1539
to-regex-range@5.0.1:
1571
1540
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
1572
1541
engines: {node: '>=8.0'}
···
1577
1546
tslib@2.8.1:
1578
1547
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
1579
1548
1580
-
typescript@5.8.2:
1581
-
resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
1549
+
typescript@5.9.3:
1550
+
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
1582
1551
engines: {node: '>=14.17'}
1583
1552
hasBin: true
1584
1553
1585
-
ufo@1.5.4:
1586
-
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
1554
+
undici-types@6.21.0:
1555
+
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
1587
1556
1588
-
undici-types@6.20.0:
1589
-
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
1557
+
undici@7.14.0:
1558
+
resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==}
1559
+
engines: {node: '>=20.18.1'}
1590
1560
1591
-
undici@5.29.0:
1592
-
resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==}
1593
-
engines: {node: '>=14.0'}
1594
-
1595
-
unenv@2.0.0-rc.15:
1596
-
resolution: {integrity: sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA==}
1561
+
unenv@2.0.0-rc.24:
1562
+
resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==}
1597
1563
1598
-
update-browserslist-db@1.1.3:
1599
-
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
1564
+
update-browserslist-db@1.2.2:
1565
+
resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==}
1600
1566
hasBin: true
1601
1567
peerDependencies:
1602
1568
browserslist: '>= 4.21.0'
···
1604
1570
util-deprecate@1.0.2:
1605
1571
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
1606
1572
1607
-
validate-html-nesting@1.2.2:
1608
-
resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==}
1609
-
1610
-
vite-plugin-solid@2.11.6:
1611
-
resolution: {integrity: sha512-Sl5CTqJTGyEeOsmdH6BOgalIZlwH3t4/y0RQuFLMGnvWMBvxb4+lq7x3BSiAw6etf0QexfNJW7HSOO/Qf7pigg==}
1573
+
vite-plugin-solid@2.11.10:
1574
+
resolution: {integrity: sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw==}
1612
1575
peerDependencies:
1613
1576
'@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.*
1614
1577
solid-js: ^1.7.2
1615
-
vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
1578
+
vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
1616
1579
peerDependenciesMeta:
1617
1580
'@testing-library/jest-dom':
1618
1581
optional: true
1619
1582
1620
-
vite@6.2.2:
1621
-
resolution: {integrity: sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==}
1622
-
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
1583
+
vite@7.2.7:
1584
+
resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==}
1585
+
engines: {node: ^20.19.0 || >=22.12.0}
1623
1586
hasBin: true
1624
1587
peerDependencies:
1625
-
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
1588
+
'@types/node': ^20.19.0 || >=22.12.0
1626
1589
jiti: '>=1.21.0'
1627
-
less: '*'
1590
+
less: ^4.0.0
1628
1591
lightningcss: ^1.21.0
1629
-
sass: '*'
1630
-
sass-embedded: '*'
1631
-
stylus: '*'
1632
-
sugarss: '*'
1592
+
sass: ^1.70.0
1593
+
sass-embedded: ^1.70.0
1594
+
stylus: '>=0.54.8'
1595
+
sugarss: ^5.0.0
1633
1596
terser: ^5.16.0
1634
1597
tsx: ^4.8.1
1635
1598
yaml: ^2.4.2
···
1657
1620
yaml:
1658
1621
optional: true
1659
1622
1660
-
vitefu@1.0.6:
1661
-
resolution: {integrity: sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==}
1623
+
vitefu@1.1.1:
1624
+
resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==}
1662
1625
peerDependencies:
1663
-
vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
1626
+
vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
1664
1627
peerDependenciesMeta:
1665
1628
vite:
1666
1629
optional: true
···
1669
1632
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
1670
1633
engines: {node: '>= 8'}
1671
1634
1672
-
which@2.0.2:
1673
-
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
1674
-
engines: {node: '>= 8'}
1675
-
hasBin: true
1676
-
1677
-
workerd@1.20250320.0:
1678
-
resolution: {integrity: sha512-XrjREboPo1AZNF3kSEly/H1Ejmpu2Mk/Wzsxprn7MHUmBnQNASFtvQdN0ef0bN+MaNdCWUawpsDLpNWNOyK4FA==}
1635
+
workerd@1.20251202.0:
1636
+
resolution: {integrity: sha512-p08YfrUMHkjCECNdT36r+6DpJIZX4kixbZ4n6GMUcLR5Gh18fakSCsiQrh72iOm4M9QHv/rM7P8YvCrUPWT5sg==}
1679
1637
engines: {node: '>=16'}
1680
1638
hasBin: true
1681
1639
1682
-
wrangler@4.4.0:
1683
-
resolution: {integrity: sha512-VmHBpocMk/GTEER+jJzkQeGNx5i/qJJKoUse5zvKmJOnELG/dhEQBJoaWxllwOfaPhIbnqeXdtrN/B+dfQAsFA==}
1684
-
engines: {node: '>=18.0.0'}
1640
+
wrangler@4.53.0:
1641
+
resolution: {integrity: sha512-/wvnHlRnlHsqaeIgGbmcEJE5NFYdTUWHCKow+U5Tv2XwQXI9vXUqBwCLAGy/BwqyS5nnycRt2kppqCzgHgyb7Q==}
1642
+
engines: {node: '>=20.0.0'}
1685
1643
hasBin: true
1686
1644
peerDependencies:
1687
-
'@cloudflare/workers-types': ^4.20250320.0
1645
+
'@cloudflare/workers-types': ^4.20251202.0
1688
1646
peerDependenciesMeta:
1689
1647
'@cloudflare/workers-types':
1690
1648
optional: true
1691
1649
1692
-
wrap-ansi@7.0.0:
1693
-
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
1694
-
engines: {node: '>=10'}
1695
-
1696
-
wrap-ansi@8.1.0:
1697
-
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
1698
-
engines: {node: '>=12'}
1699
-
1700
1650
ws@8.18.0:
1701
1651
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
1702
1652
engines: {node: '>=10.0.0'}
···
1712
1662
yallist@3.1.1:
1713
1663
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
1714
1664
1715
-
yaml@2.7.0:
1716
-
resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==}
1717
-
engines: {node: '>= 14'}
1718
-
hasBin: true
1665
+
youch-core@0.3.3:
1666
+
resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==}
1719
1667
1720
-
youch@3.2.3:
1721
-
resolution: {integrity: sha512-ZBcWz/uzZaQVdCvfV4uk616Bbpf2ee+F/AvuKDR5EwX/Y4v06xWdtMluqTD7+KlZdM93lLm9gMZYo0sKBS0pgw==}
1668
+
youch@4.1.0-beta.10:
1669
+
resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==}
1722
1670
1723
1671
zod@3.22.3:
1724
1672
resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==}
···
1727
1675
1728
1676
'@alloc/quick-lru@5.2.0': {}
1729
1677
1730
-
'@ampproject/remapping@2.3.0':
1678
+
'@atcute/atproto@3.1.9':
1731
1679
dependencies:
1732
-
'@jridgewell/gen-mapping': 0.3.8
1733
-
'@jridgewell/trace-mapping': 0.3.25
1680
+
'@atcute/lexicons': 1.2.5
1734
1681
1735
-
'@atcute/bluesky@1.0.14(@atcute/client@2.0.8)':
1682
+
'@atcute/bluesky@3.2.13':
1736
1683
dependencies:
1737
-
'@atcute/client': 2.0.8
1684
+
'@atcute/atproto': 3.1.9
1685
+
'@atcute/lexicons': 1.2.5
1738
1686
1739
-
'@atcute/car@3.0.0':
1687
+
'@atcute/car@5.0.0':
1740
1688
dependencies:
1741
-
'@atcute/cbor': 2.2.0
1742
-
'@atcute/cid': 2.2.0
1743
-
'@atcute/varint': 1.0.2
1689
+
'@atcute/cbor': 2.2.8
1690
+
'@atcute/cid': 2.2.6
1691
+
'@atcute/uint8array': 1.0.6
1692
+
'@atcute/varint': 1.0.3
1744
1693
1745
-
'@atcute/cbor@2.2.0':
1694
+
'@atcute/cbor@2.2.8':
1746
1695
dependencies:
1747
-
'@atcute/cid': 2.2.0
1748
-
'@atcute/multibase': 1.1.2
1749
-
'@atcute/uint8array': 1.0.1
1696
+
'@atcute/cid': 2.2.6
1697
+
'@atcute/multibase': 1.1.6
1698
+
'@atcute/uint8array': 1.0.6
1750
1699
1751
-
'@atcute/cid@2.2.0':
1700
+
'@atcute/cid@2.2.6':
1752
1701
dependencies:
1753
-
'@atcute/multibase': 1.1.2
1754
-
'@atcute/uint8array': 1.0.1
1702
+
'@atcute/multibase': 1.1.6
1703
+
'@atcute/uint8array': 1.0.6
1755
1704
1756
-
'@atcute/client@2.0.8': {}
1705
+
'@atcute/client@4.1.1':
1706
+
dependencies:
1707
+
'@atcute/identity': 1.1.3
1708
+
'@atcute/lexicons': 1.2.5
1757
1709
1758
-
'@atcute/crypto@2.2.0':
1710
+
'@atcute/crypto@2.3.0':
1759
1711
dependencies:
1760
-
'@atcute/multibase': 1.1.2
1761
-
'@atcute/uint8array': 1.0.1
1762
-
'@noble/secp256k1': 2.2.3
1712
+
'@atcute/multibase': 1.1.6
1713
+
'@atcute/uint8array': 1.0.6
1714
+
'@noble/secp256k1': 3.0.0
1763
1715
1764
-
'@atcute/did-plc@0.1.1':
1716
+
'@atcute/did-plc@0.2.0':
1765
1717
dependencies:
1766
-
'@atcute/cbor': 2.2.0
1767
-
'@atcute/cid': 2.2.0
1768
-
'@atcute/crypto': 2.2.0
1769
-
'@atcute/multibase': 1.1.2
1770
-
'@atcute/uint8array': 1.0.1
1771
-
'@badrap/valita': 0.4.3
1718
+
'@atcute/cbor': 2.2.8
1719
+
'@atcute/cid': 2.2.6
1720
+
'@atcute/crypto': 2.3.0
1721
+
'@atcute/identity': 1.1.3
1722
+
'@atcute/lexicons': 1.2.5
1723
+
'@atcute/multibase': 1.1.6
1724
+
'@atcute/uint8array': 1.0.6
1725
+
'@badrap/valita': 0.4.6
1772
1726
1773
-
'@atcute/identity-resolver@0.1.2(@atcute/identity@0.1.1)':
1727
+
'@atcute/identity-resolver@1.2.0(@atcute/identity@1.1.3)':
1774
1728
dependencies:
1775
-
'@atcute/identity': 0.1.1
1776
-
'@atcute/util-fetch': 1.0.1
1777
-
'@badrap/valita': 0.4.3
1729
+
'@atcute/identity': 1.1.3
1730
+
'@atcute/lexicons': 1.2.5
1731
+
'@atcute/util-fetch': 1.0.4
1732
+
'@badrap/valita': 0.4.6
1778
1733
1779
-
'@atcute/identity@0.1.1':
1734
+
'@atcute/identity@1.1.3':
1780
1735
dependencies:
1781
-
'@badrap/valita': 0.4.3
1736
+
'@atcute/lexicons': 1.2.5
1737
+
'@badrap/valita': 0.4.6
1782
1738
1783
-
'@atcute/multibase@1.1.2':
1739
+
'@atcute/lexicons@1.2.5':
1784
1740
dependencies:
1785
-
'@atcute/uint8array': 1.0.1
1741
+
'@standard-schema/spec': 1.0.0
1742
+
esm-env: 1.2.2
1786
1743
1787
-
'@atcute/tid@1.0.2': {}
1744
+
'@atcute/mst@0.1.0':
1745
+
dependencies:
1746
+
'@atcute/cbor': 2.2.8
1747
+
'@atcute/cid': 2.2.6
1748
+
'@atcute/uint8array': 1.0.6
1788
1749
1789
-
'@atcute/uint8array@1.0.1': {}
1750
+
'@atcute/multibase@1.1.6':
1751
+
dependencies:
1752
+
'@atcute/uint8array': 1.0.6
1790
1753
1791
-
'@atcute/util-fetch@1.0.1':
1754
+
'@atcute/repo@0.1.0':
1792
1755
dependencies:
1793
-
'@badrap/valita': 0.4.3
1756
+
'@atcute/car': 5.0.0
1757
+
'@atcute/cbor': 2.2.8
1758
+
'@atcute/cid': 2.2.6
1759
+
'@atcute/crypto': 2.3.0
1760
+
'@atcute/lexicons': 1.2.5
1761
+
'@atcute/mst': 0.1.0
1762
+
'@atcute/uint8array': 1.0.6
1763
+
1764
+
'@atcute/tid@1.0.3': {}
1765
+
1766
+
'@atcute/uint8array@1.0.6': {}
1767
+
1768
+
'@atcute/util-fetch@1.0.4':
1769
+
dependencies:
1770
+
'@badrap/valita': 0.4.6
1794
1771
1795
-
'@atcute/varint@1.0.2': {}
1772
+
'@atcute/varint@1.0.3': {}
1796
1773
1797
-
'@babel/code-frame@7.26.2':
1774
+
'@babel/code-frame@7.27.1':
1798
1775
dependencies:
1799
-
'@babel/helper-validator-identifier': 7.25.9
1776
+
'@babel/helper-validator-identifier': 7.28.5
1800
1777
js-tokens: 4.0.0
1801
1778
picocolors: 1.1.1
1802
1779
1803
-
'@babel/compat-data@7.26.8': {}
1780
+
'@babel/compat-data@7.28.5': {}
1804
1781
1805
-
'@babel/core@7.26.10':
1782
+
'@babel/core@7.28.5':
1806
1783
dependencies:
1807
-
'@ampproject/remapping': 2.3.0
1808
-
'@babel/code-frame': 7.26.2
1809
-
'@babel/generator': 7.26.10
1810
-
'@babel/helper-compilation-targets': 7.26.5
1811
-
'@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10)
1812
-
'@babel/helpers': 7.26.10
1813
-
'@babel/parser': 7.26.10
1814
-
'@babel/template': 7.26.9
1815
-
'@babel/traverse': 7.26.10
1816
-
'@babel/types': 7.26.10
1784
+
'@babel/code-frame': 7.27.1
1785
+
'@babel/generator': 7.28.5
1786
+
'@babel/helper-compilation-targets': 7.27.2
1787
+
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
1788
+
'@babel/helpers': 7.28.4
1789
+
'@babel/parser': 7.28.5
1790
+
'@babel/template': 7.27.2
1791
+
'@babel/traverse': 7.28.5
1792
+
'@babel/types': 7.28.5
1793
+
'@jridgewell/remapping': 2.3.5
1817
1794
convert-source-map: 2.0.0
1818
-
debug: 4.4.0
1795
+
debug: 4.4.3
1819
1796
gensync: 1.0.0-beta.2
1820
1797
json5: 2.2.3
1821
1798
semver: 6.3.1
1822
1799
transitivePeerDependencies:
1823
1800
- supports-color
1824
1801
1825
-
'@babel/generator@7.26.10':
1802
+
'@babel/generator@7.28.5':
1826
1803
dependencies:
1827
-
'@babel/parser': 7.26.10
1828
-
'@babel/types': 7.26.10
1829
-
'@jridgewell/gen-mapping': 0.3.8
1830
-
'@jridgewell/trace-mapping': 0.3.25
1804
+
'@babel/parser': 7.28.5
1805
+
'@babel/types': 7.28.5
1806
+
'@jridgewell/gen-mapping': 0.3.13
1807
+
'@jridgewell/trace-mapping': 0.3.31
1831
1808
jsesc: 3.1.0
1832
1809
1833
-
'@babel/helper-compilation-targets@7.26.5':
1810
+
'@babel/helper-compilation-targets@7.27.2':
1834
1811
dependencies:
1835
-
'@babel/compat-data': 7.26.8
1836
-
'@babel/helper-validator-option': 7.25.9
1837
-
browserslist: 4.24.4
1812
+
'@babel/compat-data': 7.28.5
1813
+
'@babel/helper-validator-option': 7.27.1
1814
+
browserslist: 4.28.1
1838
1815
lru-cache: 5.1.1
1839
1816
semver: 6.3.1
1840
1817
1818
+
'@babel/helper-globals@7.28.0': {}
1819
+
1841
1820
'@babel/helper-module-imports@7.18.6':
1842
1821
dependencies:
1843
-
'@babel/types': 7.26.10
1822
+
'@babel/types': 7.28.5
1844
1823
1845
-
'@babel/helper-module-imports@7.25.9':
1824
+
'@babel/helper-module-imports@7.27.1':
1846
1825
dependencies:
1847
-
'@babel/traverse': 7.26.10
1848
-
'@babel/types': 7.26.10
1826
+
'@babel/traverse': 7.28.5
1827
+
'@babel/types': 7.28.5
1849
1828
transitivePeerDependencies:
1850
1829
- supports-color
1851
1830
1852
-
'@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)':
1831
+
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)':
1853
1832
dependencies:
1854
-
'@babel/core': 7.26.10
1855
-
'@babel/helper-module-imports': 7.25.9
1856
-
'@babel/helper-validator-identifier': 7.25.9
1857
-
'@babel/traverse': 7.26.10
1833
+
'@babel/core': 7.28.5
1834
+
'@babel/helper-module-imports': 7.27.1
1835
+
'@babel/helper-validator-identifier': 7.28.5
1836
+
'@babel/traverse': 7.28.5
1858
1837
transitivePeerDependencies:
1859
1838
- supports-color
1860
1839
1861
-
'@babel/helper-plugin-utils@7.26.5': {}
1840
+
'@babel/helper-plugin-utils@7.27.1': {}
1862
1841
1863
-
'@babel/helper-string-parser@7.25.9': {}
1842
+
'@babel/helper-string-parser@7.27.1': {}
1864
1843
1865
-
'@babel/helper-validator-identifier@7.25.9': {}
1844
+
'@babel/helper-validator-identifier@7.28.5': {}
1866
1845
1867
-
'@babel/helper-validator-option@7.25.9': {}
1846
+
'@babel/helper-validator-option@7.27.1': {}
1868
1847
1869
-
'@babel/helpers@7.26.10':
1848
+
'@babel/helpers@7.28.4':
1870
1849
dependencies:
1871
-
'@babel/template': 7.26.9
1872
-
'@babel/types': 7.26.10
1850
+
'@babel/template': 7.27.2
1851
+
'@babel/types': 7.28.5
1873
1852
1874
-
'@babel/parser@7.26.10':
1853
+
'@babel/parser@7.28.5':
1875
1854
dependencies:
1876
-
'@babel/types': 7.26.10
1855
+
'@babel/types': 7.28.5
1877
1856
1878
-
'@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.10)':
1857
+
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)':
1879
1858
dependencies:
1880
-
'@babel/core': 7.26.10
1881
-
'@babel/helper-plugin-utils': 7.26.5
1859
+
'@babel/core': 7.28.5
1860
+
'@babel/helper-plugin-utils': 7.27.1
1882
1861
1883
-
'@babel/template@7.26.9':
1862
+
'@babel/template@7.27.2':
1884
1863
dependencies:
1885
-
'@babel/code-frame': 7.26.2
1886
-
'@babel/parser': 7.26.10
1887
-
'@babel/types': 7.26.10
1864
+
'@babel/code-frame': 7.27.1
1865
+
'@babel/parser': 7.28.5
1866
+
'@babel/types': 7.28.5
1888
1867
1889
-
'@babel/traverse@7.26.10':
1868
+
'@babel/traverse@7.28.5':
1890
1869
dependencies:
1891
-
'@babel/code-frame': 7.26.2
1892
-
'@babel/generator': 7.26.10
1893
-
'@babel/parser': 7.26.10
1894
-
'@babel/template': 7.26.9
1895
-
'@babel/types': 7.26.10
1896
-
debug: 4.4.0
1897
-
globals: 11.12.0
1870
+
'@babel/code-frame': 7.27.1
1871
+
'@babel/generator': 7.28.5
1872
+
'@babel/helper-globals': 7.28.0
1873
+
'@babel/parser': 7.28.5
1874
+
'@babel/template': 7.27.2
1875
+
'@babel/types': 7.28.5
1876
+
debug: 4.4.3
1898
1877
transitivePeerDependencies:
1899
1878
- supports-color
1900
1879
1901
-
'@babel/types@7.26.10':
1880
+
'@babel/types@7.28.5':
1902
1881
dependencies:
1903
-
'@babel/helper-string-parser': 7.25.9
1904
-
'@babel/helper-validator-identifier': 7.25.9
1882
+
'@babel/helper-string-parser': 7.27.1
1883
+
'@babel/helper-validator-identifier': 7.28.5
1905
1884
1906
-
'@badrap/valita@0.4.3': {}
1885
+
'@badrap/valita@0.4.6': {}
1907
1886
1908
-
'@cloudflare/kv-asset-handler@0.4.0':
1887
+
'@cloudflare/kv-asset-handler@0.4.1':
1909
1888
dependencies:
1910
1889
mime: 3.0.0
1911
1890
1912
-
'@cloudflare/unenv-preset@2.3.0(unenv@2.0.0-rc.15)(workerd@1.20250320.0)':
1891
+
'@cloudflare/unenv-preset@2.7.13(unenv@2.0.0-rc.24)(workerd@1.20251202.0)':
1913
1892
dependencies:
1914
-
unenv: 2.0.0-rc.15
1893
+
unenv: 2.0.0-rc.24
1915
1894
optionalDependencies:
1916
-
workerd: 1.20250320.0
1895
+
workerd: 1.20251202.0
1917
1896
1918
-
'@cloudflare/workerd-darwin-64@1.20250320.0':
1897
+
'@cloudflare/workerd-darwin-64@1.20251202.0':
1919
1898
optional: true
1920
1899
1921
-
'@cloudflare/workerd-darwin-arm64@1.20250320.0':
1900
+
'@cloudflare/workerd-darwin-arm64@1.20251202.0':
1922
1901
optional: true
1923
1902
1924
-
'@cloudflare/workerd-linux-64@1.20250320.0':
1903
+
'@cloudflare/workerd-linux-64@1.20251202.0':
1925
1904
optional: true
1926
1905
1927
-
'@cloudflare/workerd-linux-arm64@1.20250320.0':
1906
+
'@cloudflare/workerd-linux-arm64@1.20251202.0':
1928
1907
optional: true
1929
1908
1930
-
'@cloudflare/workerd-windows-64@1.20250320.0':
1909
+
'@cloudflare/workerd-windows-64@1.20251202.0':
1931
1910
optional: true
1932
1911
1933
1912
'@cspotcode/source-map-support@0.8.1':
1934
1913
dependencies:
1935
1914
'@jridgewell/trace-mapping': 0.3.9
1936
1915
1937
-
'@emnapi/runtime@1.3.1':
1916
+
'@emnapi/runtime@1.7.1':
1938
1917
dependencies:
1939
1918
tslib: 2.8.1
1940
1919
optional: true
1941
1920
1942
-
'@esbuild/aix-ppc64@0.24.2':
1921
+
'@esbuild/aix-ppc64@0.25.12':
1922
+
optional: true
1923
+
1924
+
'@esbuild/aix-ppc64@0.27.0':
1943
1925
optional: true
1944
1926
1945
-
'@esbuild/aix-ppc64@0.25.1':
1927
+
'@esbuild/android-arm64@0.25.12':
1928
+
optional: true
1929
+
1930
+
'@esbuild/android-arm64@0.27.0':
1946
1931
optional: true
1947
1932
1948
-
'@esbuild/android-arm64@0.24.2':
1933
+
'@esbuild/android-arm@0.25.12':
1949
1934
optional: true
1950
1935
1951
-
'@esbuild/android-arm64@0.25.1':
1936
+
'@esbuild/android-arm@0.27.0':
1952
1937
optional: true
1953
1938
1954
-
'@esbuild/android-arm@0.24.2':
1939
+
'@esbuild/android-x64@0.25.12':
1955
1940
optional: true
1956
1941
1957
-
'@esbuild/android-arm@0.25.1':
1942
+
'@esbuild/android-x64@0.27.0':
1958
1943
optional: true
1959
1944
1960
-
'@esbuild/android-x64@0.24.2':
1945
+
'@esbuild/darwin-arm64@0.25.12':
1961
1946
optional: true
1962
1947
1963
-
'@esbuild/android-x64@0.25.1':
1948
+
'@esbuild/darwin-arm64@0.27.0':
1964
1949
optional: true
1965
1950
1966
-
'@esbuild/darwin-arm64@0.24.2':
1951
+
'@esbuild/darwin-x64@0.25.12':
1967
1952
optional: true
1968
1953
1969
-
'@esbuild/darwin-arm64@0.25.1':
1954
+
'@esbuild/darwin-x64@0.27.0':
1970
1955
optional: true
1971
1956
1972
-
'@esbuild/darwin-x64@0.24.2':
1957
+
'@esbuild/freebsd-arm64@0.25.12':
1973
1958
optional: true
1974
1959
1975
-
'@esbuild/darwin-x64@0.25.1':
1960
+
'@esbuild/freebsd-arm64@0.27.0':
1976
1961
optional: true
1977
1962
1978
-
'@esbuild/freebsd-arm64@0.24.2':
1963
+
'@esbuild/freebsd-x64@0.25.12':
1979
1964
optional: true
1980
1965
1981
-
'@esbuild/freebsd-arm64@0.25.1':
1966
+
'@esbuild/freebsd-x64@0.27.0':
1982
1967
optional: true
1983
1968
1984
-
'@esbuild/freebsd-x64@0.24.2':
1969
+
'@esbuild/linux-arm64@0.25.12':
1985
1970
optional: true
1986
1971
1987
-
'@esbuild/freebsd-x64@0.25.1':
1972
+
'@esbuild/linux-arm64@0.27.0':
1988
1973
optional: true
1989
1974
1990
-
'@esbuild/linux-arm64@0.24.2':
1975
+
'@esbuild/linux-arm@0.25.12':
1991
1976
optional: true
1992
1977
1993
-
'@esbuild/linux-arm64@0.25.1':
1978
+
'@esbuild/linux-arm@0.27.0':
1994
1979
optional: true
1995
1980
1996
-
'@esbuild/linux-arm@0.24.2':
1981
+
'@esbuild/linux-ia32@0.25.12':
1997
1982
optional: true
1998
1983
1999
-
'@esbuild/linux-arm@0.25.1':
1984
+
'@esbuild/linux-ia32@0.27.0':
2000
1985
optional: true
2001
1986
2002
-
'@esbuild/linux-ia32@0.24.2':
1987
+
'@esbuild/linux-loong64@0.25.12':
2003
1988
optional: true
2004
1989
2005
-
'@esbuild/linux-ia32@0.25.1':
1990
+
'@esbuild/linux-loong64@0.27.0':
2006
1991
optional: true
2007
1992
2008
-
'@esbuild/linux-loong64@0.24.2':
1993
+
'@esbuild/linux-mips64el@0.25.12':
2009
1994
optional: true
2010
1995
2011
-
'@esbuild/linux-loong64@0.25.1':
1996
+
'@esbuild/linux-mips64el@0.27.0':
2012
1997
optional: true
2013
1998
2014
-
'@esbuild/linux-mips64el@0.24.2':
1999
+
'@esbuild/linux-ppc64@0.25.12':
2015
2000
optional: true
2016
2001
2017
-
'@esbuild/linux-mips64el@0.25.1':
2002
+
'@esbuild/linux-ppc64@0.27.0':
2018
2003
optional: true
2019
2004
2020
-
'@esbuild/linux-ppc64@0.24.2':
2005
+
'@esbuild/linux-riscv64@0.25.12':
2021
2006
optional: true
2022
2007
2023
-
'@esbuild/linux-ppc64@0.25.1':
2008
+
'@esbuild/linux-riscv64@0.27.0':
2024
2009
optional: true
2025
2010
2026
-
'@esbuild/linux-riscv64@0.24.2':
2011
+
'@esbuild/linux-s390x@0.25.12':
2027
2012
optional: true
2028
2013
2029
-
'@esbuild/linux-riscv64@0.25.1':
2014
+
'@esbuild/linux-s390x@0.27.0':
2030
2015
optional: true
2031
2016
2032
-
'@esbuild/linux-s390x@0.24.2':
2017
+
'@esbuild/linux-x64@0.25.12':
2033
2018
optional: true
2034
2019
2035
-
'@esbuild/linux-s390x@0.25.1':
2020
+
'@esbuild/linux-x64@0.27.0':
2036
2021
optional: true
2037
2022
2038
-
'@esbuild/linux-x64@0.24.2':
2023
+
'@esbuild/netbsd-arm64@0.25.12':
2039
2024
optional: true
2040
2025
2041
-
'@esbuild/linux-x64@0.25.1':
2026
+
'@esbuild/netbsd-arm64@0.27.0':
2042
2027
optional: true
2043
2028
2044
-
'@esbuild/netbsd-arm64@0.24.2':
2029
+
'@esbuild/netbsd-x64@0.25.12':
2045
2030
optional: true
2046
2031
2047
-
'@esbuild/netbsd-arm64@0.25.1':
2032
+
'@esbuild/netbsd-x64@0.27.0':
2048
2033
optional: true
2049
2034
2050
-
'@esbuild/netbsd-x64@0.24.2':
2035
+
'@esbuild/openbsd-arm64@0.25.12':
2051
2036
optional: true
2052
2037
2053
-
'@esbuild/netbsd-x64@0.25.1':
2038
+
'@esbuild/openbsd-arm64@0.27.0':
2054
2039
optional: true
2055
2040
2056
-
'@esbuild/openbsd-arm64@0.24.2':
2041
+
'@esbuild/openbsd-x64@0.25.12':
2057
2042
optional: true
2058
2043
2059
-
'@esbuild/openbsd-arm64@0.25.1':
2044
+
'@esbuild/openbsd-x64@0.27.0':
2060
2045
optional: true
2061
2046
2062
-
'@esbuild/openbsd-x64@0.24.2':
2047
+
'@esbuild/openharmony-arm64@0.25.12':
2063
2048
optional: true
2064
2049
2065
-
'@esbuild/openbsd-x64@0.25.1':
2050
+
'@esbuild/openharmony-arm64@0.27.0':
2066
2051
optional: true
2067
2052
2068
-
'@esbuild/sunos-x64@0.24.2':
2053
+
'@esbuild/sunos-x64@0.25.12':
2069
2054
optional: true
2070
2055
2071
-
'@esbuild/sunos-x64@0.25.1':
2056
+
'@esbuild/sunos-x64@0.27.0':
2072
2057
optional: true
2073
2058
2074
-
'@esbuild/win32-arm64@0.24.2':
2059
+
'@esbuild/win32-arm64@0.25.12':
2075
2060
optional: true
2076
2061
2077
-
'@esbuild/win32-arm64@0.25.1':
2062
+
'@esbuild/win32-arm64@0.27.0':
2078
2063
optional: true
2079
2064
2080
-
'@esbuild/win32-ia32@0.24.2':
2065
+
'@esbuild/win32-ia32@0.25.12':
2081
2066
optional: true
2082
2067
2083
-
'@esbuild/win32-ia32@0.25.1':
2068
+
'@esbuild/win32-ia32@0.27.0':
2084
2069
optional: true
2085
2070
2086
-
'@esbuild/win32-x64@0.24.2':
2071
+
'@esbuild/win32-x64@0.25.12':
2087
2072
optional: true
2088
2073
2089
-
'@esbuild/win32-x64@0.25.1':
2074
+
'@esbuild/win32-x64@0.27.0':
2090
2075
optional: true
2091
2076
2092
-
'@externdefs/solid-freeze@0.1.1(solid-js@1.9.5)':
2077
+
'@externdefs/solid-freeze@0.1.1(solid-js@1.9.10)':
2093
2078
dependencies:
2094
-
solid-js: 1.9.5
2095
-
2096
-
'@fastify/busboy@2.1.1': {}
2079
+
solid-js: 1.9.10
2097
2080
2098
2081
'@img/sharp-darwin-arm64@0.33.5':
2099
2082
optionalDependencies:
···
2161
2144
2162
2145
'@img/sharp-wasm32@0.33.5':
2163
2146
dependencies:
2164
-
'@emnapi/runtime': 1.3.1
2147
+
'@emnapi/runtime': 1.7.1
2165
2148
optional: true
2166
2149
2167
2150
'@img/sharp-win32-ia32@0.33.5':
···
2170
2153
'@img/sharp-win32-x64@0.33.5':
2171
2154
optional: true
2172
2155
2173
-
'@isaacs/cliui@8.0.2':
2156
+
'@jridgewell/gen-mapping@0.3.13':
2174
2157
dependencies:
2175
-
string-width: 5.1.2
2176
-
string-width-cjs: string-width@4.2.3
2177
-
strip-ansi: 7.1.0
2178
-
strip-ansi-cjs: strip-ansi@6.0.1
2179
-
wrap-ansi: 8.1.0
2180
-
wrap-ansi-cjs: wrap-ansi@7.0.0
2158
+
'@jridgewell/sourcemap-codec': 1.5.5
2159
+
'@jridgewell/trace-mapping': 0.3.31
2181
2160
2182
-
'@jridgewell/gen-mapping@0.3.8':
2161
+
'@jridgewell/remapping@2.3.5':
2183
2162
dependencies:
2184
-
'@jridgewell/set-array': 1.2.1
2185
-
'@jridgewell/sourcemap-codec': 1.5.0
2186
-
'@jridgewell/trace-mapping': 0.3.25
2163
+
'@jridgewell/gen-mapping': 0.3.13
2164
+
'@jridgewell/trace-mapping': 0.3.31
2187
2165
2188
2166
'@jridgewell/resolve-uri@3.1.2': {}
2189
2167
2190
-
'@jridgewell/set-array@1.2.1': {}
2191
-
2192
-
'@jridgewell/source-map@0.3.6':
2168
+
'@jridgewell/source-map@0.3.11':
2193
2169
dependencies:
2194
-
'@jridgewell/gen-mapping': 0.3.8
2195
-
'@jridgewell/trace-mapping': 0.3.25
2170
+
'@jridgewell/gen-mapping': 0.3.13
2171
+
'@jridgewell/trace-mapping': 0.3.31
2196
2172
2197
-
'@jridgewell/sourcemap-codec@1.5.0': {}
2173
+
'@jridgewell/sourcemap-codec@1.5.5': {}
2198
2174
2199
-
'@jridgewell/trace-mapping@0.3.25':
2175
+
'@jridgewell/trace-mapping@0.3.31':
2200
2176
dependencies:
2201
2177
'@jridgewell/resolve-uri': 3.1.2
2202
-
'@jridgewell/sourcemap-codec': 1.5.0
2178
+
'@jridgewell/sourcemap-codec': 1.5.5
2203
2179
2204
2180
'@jridgewell/trace-mapping@0.3.9':
2205
2181
dependencies:
2206
2182
'@jridgewell/resolve-uri': 3.1.2
2207
-
'@jridgewell/sourcemap-codec': 1.5.0
2183
+
'@jridgewell/sourcemap-codec': 1.5.5
2208
2184
2209
-
'@jsr/mary__array-fns@0.1.4': {}
2185
+
'@jsr/mary__array-fns@0.1.5': {}
2186
+
2187
+
'@jsr/mary__ds-queue@0.1.3': {}
2210
2188
2211
-
'@jsr/mary__events@0.1.0': {}
2189
+
'@jsr/mary__events@0.2.0': {}
2212
2190
2213
-
'@jsr/mary__tar@0.2.4': {}
2191
+
'@jsr/mary__tar@0.3.1': {}
2214
2192
2215
-
'@noble/secp256k1@2.2.3': {}
2193
+
'@noble/secp256k1@3.0.0': {}
2216
2194
2217
2195
'@nodelib/fs.scandir@2.1.5':
2218
2196
dependencies:
···
2226
2204
'@nodelib/fs.scandir': 2.1.5
2227
2205
fastq: 1.19.1
2228
2206
2229
-
'@pkgjs/parseargs@0.11.0':
2207
+
'@poppinss/colors@4.1.5':
2208
+
dependencies:
2209
+
kleur: 4.1.5
2210
+
2211
+
'@poppinss/dumper@0.6.5':
2212
+
dependencies:
2213
+
'@poppinss/colors': 4.1.5
2214
+
'@sindresorhus/is': 7.1.1
2215
+
supports-color: 10.2.2
2216
+
2217
+
'@poppinss/exception@1.2.2': {}
2218
+
2219
+
'@rollup/rollup-android-arm-eabi@4.53.3':
2230
2220
optional: true
2231
2221
2232
-
'@rollup/rollup-android-arm-eabi@4.37.0':
2222
+
'@rollup/rollup-android-arm64@4.53.3':
2233
2223
optional: true
2234
2224
2235
-
'@rollup/rollup-android-arm64@4.37.0':
2225
+
'@rollup/rollup-darwin-arm64@4.53.3':
2236
2226
optional: true
2237
2227
2238
-
'@rollup/rollup-darwin-arm64@4.37.0':
2228
+
'@rollup/rollup-darwin-x64@4.53.3':
2239
2229
optional: true
2240
2230
2241
-
'@rollup/rollup-darwin-x64@4.37.0':
2231
+
'@rollup/rollup-freebsd-arm64@4.53.3':
2242
2232
optional: true
2243
2233
2244
-
'@rollup/rollup-freebsd-arm64@4.37.0':
2234
+
'@rollup/rollup-freebsd-x64@4.53.3':
2245
2235
optional: true
2246
2236
2247
-
'@rollup/rollup-freebsd-x64@4.37.0':
2237
+
'@rollup/rollup-linux-arm-gnueabihf@4.53.3':
2248
2238
optional: true
2249
2239
2250
-
'@rollup/rollup-linux-arm-gnueabihf@4.37.0':
2240
+
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
2251
2241
optional: true
2252
2242
2253
-
'@rollup/rollup-linux-arm-musleabihf@4.37.0':
2243
+
'@rollup/rollup-linux-arm64-gnu@4.53.3':
2254
2244
optional: true
2255
2245
2256
-
'@rollup/rollup-linux-arm64-gnu@4.37.0':
2246
+
'@rollup/rollup-linux-arm64-musl@4.53.3':
2257
2247
optional: true
2258
2248
2259
-
'@rollup/rollup-linux-arm64-musl@4.37.0':
2249
+
'@rollup/rollup-linux-loong64-gnu@4.53.3':
2260
2250
optional: true
2261
2251
2262
-
'@rollup/rollup-linux-loongarch64-gnu@4.37.0':
2252
+
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
2263
2253
optional: true
2264
2254
2265
-
'@rollup/rollup-linux-powerpc64le-gnu@4.37.0':
2255
+
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
2256
+
optional: true
2257
+
2258
+
'@rollup/rollup-linux-riscv64-musl@4.53.3':
2266
2259
optional: true
2267
2260
2268
-
'@rollup/rollup-linux-riscv64-gnu@4.37.0':
2261
+
'@rollup/rollup-linux-s390x-gnu@4.53.3':
2269
2262
optional: true
2270
2263
2271
-
'@rollup/rollup-linux-riscv64-musl@4.37.0':
2264
+
'@rollup/rollup-linux-x64-gnu@4.53.3':
2272
2265
optional: true
2273
2266
2274
-
'@rollup/rollup-linux-s390x-gnu@4.37.0':
2267
+
'@rollup/rollup-linux-x64-musl@4.53.3':
2275
2268
optional: true
2276
2269
2277
-
'@rollup/rollup-linux-x64-gnu@4.37.0':
2270
+
'@rollup/rollup-openharmony-arm64@4.53.3':
2278
2271
optional: true
2279
2272
2280
-
'@rollup/rollup-linux-x64-musl@4.37.0':
2273
+
'@rollup/rollup-win32-arm64-msvc@4.53.3':
2281
2274
optional: true
2282
2275
2283
-
'@rollup/rollup-win32-arm64-msvc@4.37.0':
2276
+
'@rollup/rollup-win32-ia32-msvc@4.53.3':
2284
2277
optional: true
2285
2278
2286
-
'@rollup/rollup-win32-ia32-msvc@4.37.0':
2279
+
'@rollup/rollup-win32-x64-gnu@4.53.3':
2287
2280
optional: true
2288
2281
2289
-
'@rollup/rollup-win32-x64-msvc@4.37.0':
2282
+
'@rollup/rollup-win32-x64-msvc@4.53.3':
2290
2283
optional: true
2291
2284
2292
-
'@tailwindcss/forms@0.5.10(tailwindcss@3.4.17)':
2285
+
'@sindresorhus/is@7.1.1': {}
2286
+
2287
+
'@speed-highlight/core@1.2.12': {}
2288
+
2289
+
'@standard-schema/spec@1.0.0': {}
2290
+
2291
+
'@tailwindcss/forms@0.5.10(tailwindcss@3.4.18)':
2293
2292
dependencies:
2294
2293
mini-svg-data-uri: 1.4.4
2295
-
tailwindcss: 3.4.17
2294
+
tailwindcss: 3.4.18
2296
2295
2297
2296
'@types/babel__core@7.20.5':
2298
2297
dependencies:
2299
-
'@babel/parser': 7.26.10
2300
-
'@babel/types': 7.26.10
2301
-
'@types/babel__generator': 7.6.8
2298
+
'@babel/parser': 7.28.5
2299
+
'@babel/types': 7.28.5
2300
+
'@types/babel__generator': 7.27.0
2302
2301
'@types/babel__template': 7.4.4
2303
-
'@types/babel__traverse': 7.20.6
2302
+
'@types/babel__traverse': 7.28.0
2304
2303
2305
-
'@types/babel__generator@7.6.8':
2304
+
'@types/babel__generator@7.27.0':
2306
2305
dependencies:
2307
-
'@babel/types': 7.26.10
2306
+
'@babel/types': 7.28.5
2308
2307
2309
2308
'@types/babel__template@7.4.4':
2310
2309
dependencies:
2311
-
'@babel/parser': 7.26.10
2312
-
'@babel/types': 7.26.10
2310
+
'@babel/parser': 7.28.5
2311
+
'@babel/types': 7.28.5
2313
2312
2314
-
'@types/babel__traverse@7.20.6':
2313
+
'@types/babel__traverse@7.28.0':
2315
2314
dependencies:
2316
-
'@babel/types': 7.26.10
2315
+
'@babel/types': 7.28.5
2317
2316
2318
-
'@types/estree@1.0.6': {}
2317
+
'@types/estree@1.0.8': {}
2319
2318
2320
-
'@types/node@22.13.12':
2319
+
'@types/node@22.19.2':
2321
2320
dependencies:
2322
-
undici-types: 6.20.0
2321
+
undici-types: 6.21.0
2323
2322
2324
2323
acorn-walk@8.3.2: {}
2325
2324
2326
2325
acorn@8.14.0: {}
2327
2326
2328
-
acorn@8.14.1: {}
2329
-
2330
-
ansi-regex@5.0.1: {}
2331
-
2332
-
ansi-regex@6.1.0: {}
2333
-
2334
-
ansi-styles@4.3.0:
2335
-
dependencies:
2336
-
color-convert: 2.0.1
2337
-
2338
-
ansi-styles@6.2.1: {}
2327
+
acorn@8.15.0: {}
2339
2328
2340
2329
any-promise@1.3.0: {}
2341
2330
···
2346
2335
2347
2336
arg@5.0.2: {}
2348
2337
2349
-
as-table@1.0.55:
2350
-
dependencies:
2351
-
printable-characters: 1.0.42
2352
-
2353
-
autoprefixer@10.4.21(postcss@8.5.3):
2338
+
autoprefixer@10.4.22(postcss@8.5.6):
2354
2339
dependencies:
2355
-
browserslist: 4.24.4
2356
-
caniuse-lite: 1.0.30001707
2357
-
fraction.js: 4.3.7
2340
+
browserslist: 4.28.1
2341
+
caniuse-lite: 1.0.30001760
2342
+
fraction.js: 5.3.4
2358
2343
normalize-range: 0.1.2
2359
2344
picocolors: 1.1.1
2360
-
postcss: 8.5.3
2345
+
postcss: 8.5.6
2361
2346
postcss-value-parser: 4.2.0
2362
2347
2363
-
babel-plugin-jsx-dom-expressions@0.39.7(@babel/core@7.26.10):
2348
+
babel-plugin-jsx-dom-expressions@0.40.3(@babel/core@7.28.5):
2364
2349
dependencies:
2365
-
'@babel/core': 7.26.10
2350
+
'@babel/core': 7.28.5
2366
2351
'@babel/helper-module-imports': 7.18.6
2367
-
'@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.10)
2368
-
'@babel/types': 7.26.10
2352
+
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
2353
+
'@babel/types': 7.28.5
2369
2354
html-entities: 2.3.3
2370
-
parse5: 7.2.1
2371
-
validate-html-nesting: 1.2.2
2355
+
parse5: 7.3.0
2372
2356
2373
-
babel-preset-solid@1.9.5(@babel/core@7.26.10):
2357
+
babel-preset-solid@1.9.10(@babel/core@7.28.5)(solid-js@1.9.10):
2374
2358
dependencies:
2375
-
'@babel/core': 7.26.10
2376
-
babel-plugin-jsx-dom-expressions: 0.39.7(@babel/core@7.26.10)
2359
+
'@babel/core': 7.28.5
2360
+
babel-plugin-jsx-dom-expressions: 0.40.3(@babel/core@7.28.5)
2361
+
optionalDependencies:
2362
+
solid-js: 1.9.10
2377
2363
2378
-
balanced-match@1.0.2: {}
2364
+
baseline-browser-mapping@2.9.5: {}
2379
2365
2380
2366
binary-extensions@2.3.0: {}
2381
2367
2382
2368
blake3-wasm@2.1.5: {}
2383
-
2384
-
brace-expansion@2.0.1:
2385
-
dependencies:
2386
-
balanced-match: 1.0.2
2387
2369
2388
2370
braces@3.0.3:
2389
2371
dependencies:
2390
2372
fill-range: 7.1.1
2391
2373
2392
-
browserslist@4.24.4:
2374
+
browserslist@4.28.1:
2393
2375
dependencies:
2394
-
caniuse-lite: 1.0.30001707
2395
-
electron-to-chromium: 1.5.123
2396
-
node-releases: 2.0.19
2397
-
update-browserslist-db: 1.1.3(browserslist@4.24.4)
2376
+
baseline-browser-mapping: 2.9.5
2377
+
caniuse-lite: 1.0.30001760
2378
+
electron-to-chromium: 1.5.267
2379
+
node-releases: 2.0.27
2380
+
update-browserslist-db: 1.2.2(browserslist@4.28.1)
2398
2381
2399
2382
buffer-from@1.1.2: {}
2400
2383
2401
2384
camelcase-css@2.0.1: {}
2402
2385
2403
-
caniuse-lite@1.0.30001707: {}
2386
+
caniuse-lite@1.0.30001760: {}
2404
2387
2405
2388
chokidar@3.6.0:
2406
2389
dependencies:
···
2423
2406
color-string@1.9.1:
2424
2407
dependencies:
2425
2408
color-name: 1.1.4
2426
-
simple-swizzle: 0.2.2
2427
-
optional: true
2409
+
simple-swizzle: 0.2.4
2428
2410
2429
2411
color@4.2.3:
2430
2412
dependencies:
2431
2413
color-convert: 2.0.1
2432
2414
color-string: 1.9.1
2433
-
optional: true
2434
2415
2435
2416
commander@2.20.3: {}
2436
2417
···
2438
2419
2439
2420
convert-source-map@2.0.0: {}
2440
2421
2441
-
cookie@0.5.0: {}
2442
-
2443
-
cross-spawn@7.0.6:
2444
-
dependencies:
2445
-
path-key: 3.1.1
2446
-
shebang-command: 2.0.0
2447
-
which: 2.0.2
2422
+
cookie@1.1.1: {}
2448
2423
2449
2424
cssesc@3.0.0: {}
2450
2425
2451
-
csstype@3.1.3: {}
2426
+
csstype@3.2.3: {}
2452
2427
2453
-
data-uri-to-buffer@2.0.2: {}
2454
-
2455
-
debug@4.4.0:
2428
+
debug@4.4.3:
2456
2429
dependencies:
2457
2430
ms: 2.1.3
2458
2431
2459
-
defu@6.1.4: {}
2460
-
2461
-
detect-libc@2.0.3:
2462
-
optional: true
2432
+
detect-libc@2.1.2: {}
2463
2433
2464
2434
didyoumean@1.2.2: {}
2465
2435
2466
2436
dlv@1.1.3: {}
2467
2437
2468
-
eastasianwidth@0.2.0: {}
2438
+
electron-to-chromium@1.5.267: {}
2469
2439
2470
-
electron-to-chromium@1.5.123: {}
2440
+
entities@6.0.1: {}
2471
2441
2472
-
emoji-regex@8.0.0: {}
2442
+
error-stack-parser-es@1.0.5: {}
2473
2443
2474
-
emoji-regex@9.2.2: {}
2475
-
2476
-
entities@4.5.0: {}
2477
-
2478
-
esbuild@0.24.2:
2444
+
esbuild@0.25.12:
2479
2445
optionalDependencies:
2480
-
'@esbuild/aix-ppc64': 0.24.2
2481
-
'@esbuild/android-arm': 0.24.2
2482
-
'@esbuild/android-arm64': 0.24.2
2483
-
'@esbuild/android-x64': 0.24.2
2484
-
'@esbuild/darwin-arm64': 0.24.2
2485
-
'@esbuild/darwin-x64': 0.24.2
2486
-
'@esbuild/freebsd-arm64': 0.24.2
2487
-
'@esbuild/freebsd-x64': 0.24.2
2488
-
'@esbuild/linux-arm': 0.24.2
2489
-
'@esbuild/linux-arm64': 0.24.2
2490
-
'@esbuild/linux-ia32': 0.24.2
2491
-
'@esbuild/linux-loong64': 0.24.2
2492
-
'@esbuild/linux-mips64el': 0.24.2
2493
-
'@esbuild/linux-ppc64': 0.24.2
2494
-
'@esbuild/linux-riscv64': 0.24.2
2495
-
'@esbuild/linux-s390x': 0.24.2
2496
-
'@esbuild/linux-x64': 0.24.2
2497
-
'@esbuild/netbsd-arm64': 0.24.2
2498
-
'@esbuild/netbsd-x64': 0.24.2
2499
-
'@esbuild/openbsd-arm64': 0.24.2
2500
-
'@esbuild/openbsd-x64': 0.24.2
2501
-
'@esbuild/sunos-x64': 0.24.2
2502
-
'@esbuild/win32-arm64': 0.24.2
2503
-
'@esbuild/win32-ia32': 0.24.2
2504
-
'@esbuild/win32-x64': 0.24.2
2446
+
'@esbuild/aix-ppc64': 0.25.12
2447
+
'@esbuild/android-arm': 0.25.12
2448
+
'@esbuild/android-arm64': 0.25.12
2449
+
'@esbuild/android-x64': 0.25.12
2450
+
'@esbuild/darwin-arm64': 0.25.12
2451
+
'@esbuild/darwin-x64': 0.25.12
2452
+
'@esbuild/freebsd-arm64': 0.25.12
2453
+
'@esbuild/freebsd-x64': 0.25.12
2454
+
'@esbuild/linux-arm': 0.25.12
2455
+
'@esbuild/linux-arm64': 0.25.12
2456
+
'@esbuild/linux-ia32': 0.25.12
2457
+
'@esbuild/linux-loong64': 0.25.12
2458
+
'@esbuild/linux-mips64el': 0.25.12
2459
+
'@esbuild/linux-ppc64': 0.25.12
2460
+
'@esbuild/linux-riscv64': 0.25.12
2461
+
'@esbuild/linux-s390x': 0.25.12
2462
+
'@esbuild/linux-x64': 0.25.12
2463
+
'@esbuild/netbsd-arm64': 0.25.12
2464
+
'@esbuild/netbsd-x64': 0.25.12
2465
+
'@esbuild/openbsd-arm64': 0.25.12
2466
+
'@esbuild/openbsd-x64': 0.25.12
2467
+
'@esbuild/openharmony-arm64': 0.25.12
2468
+
'@esbuild/sunos-x64': 0.25.12
2469
+
'@esbuild/win32-arm64': 0.25.12
2470
+
'@esbuild/win32-ia32': 0.25.12
2471
+
'@esbuild/win32-x64': 0.25.12
2505
2472
2506
-
esbuild@0.25.1:
2473
+
esbuild@0.27.0:
2507
2474
optionalDependencies:
2508
-
'@esbuild/aix-ppc64': 0.25.1
2509
-
'@esbuild/android-arm': 0.25.1
2510
-
'@esbuild/android-arm64': 0.25.1
2511
-
'@esbuild/android-x64': 0.25.1
2512
-
'@esbuild/darwin-arm64': 0.25.1
2513
-
'@esbuild/darwin-x64': 0.25.1
2514
-
'@esbuild/freebsd-arm64': 0.25.1
2515
-
'@esbuild/freebsd-x64': 0.25.1
2516
-
'@esbuild/linux-arm': 0.25.1
2517
-
'@esbuild/linux-arm64': 0.25.1
2518
-
'@esbuild/linux-ia32': 0.25.1
2519
-
'@esbuild/linux-loong64': 0.25.1
2520
-
'@esbuild/linux-mips64el': 0.25.1
2521
-
'@esbuild/linux-ppc64': 0.25.1
2522
-
'@esbuild/linux-riscv64': 0.25.1
2523
-
'@esbuild/linux-s390x': 0.25.1
2524
-
'@esbuild/linux-x64': 0.25.1
2525
-
'@esbuild/netbsd-arm64': 0.25.1
2526
-
'@esbuild/netbsd-x64': 0.25.1
2527
-
'@esbuild/openbsd-arm64': 0.25.1
2528
-
'@esbuild/openbsd-x64': 0.25.1
2529
-
'@esbuild/sunos-x64': 0.25.1
2530
-
'@esbuild/win32-arm64': 0.25.1
2531
-
'@esbuild/win32-ia32': 0.25.1
2532
-
'@esbuild/win32-x64': 0.25.1
2475
+
'@esbuild/aix-ppc64': 0.27.0
2476
+
'@esbuild/android-arm': 0.27.0
2477
+
'@esbuild/android-arm64': 0.27.0
2478
+
'@esbuild/android-x64': 0.27.0
2479
+
'@esbuild/darwin-arm64': 0.27.0
2480
+
'@esbuild/darwin-x64': 0.27.0
2481
+
'@esbuild/freebsd-arm64': 0.27.0
2482
+
'@esbuild/freebsd-x64': 0.27.0
2483
+
'@esbuild/linux-arm': 0.27.0
2484
+
'@esbuild/linux-arm64': 0.27.0
2485
+
'@esbuild/linux-ia32': 0.27.0
2486
+
'@esbuild/linux-loong64': 0.27.0
2487
+
'@esbuild/linux-mips64el': 0.27.0
2488
+
'@esbuild/linux-ppc64': 0.27.0
2489
+
'@esbuild/linux-riscv64': 0.27.0
2490
+
'@esbuild/linux-s390x': 0.27.0
2491
+
'@esbuild/linux-x64': 0.27.0
2492
+
'@esbuild/netbsd-arm64': 0.27.0
2493
+
'@esbuild/netbsd-x64': 0.27.0
2494
+
'@esbuild/openbsd-arm64': 0.27.0
2495
+
'@esbuild/openbsd-x64': 0.27.0
2496
+
'@esbuild/openharmony-arm64': 0.27.0
2497
+
'@esbuild/sunos-x64': 0.27.0
2498
+
'@esbuild/win32-arm64': 0.27.0
2499
+
'@esbuild/win32-ia32': 0.27.0
2500
+
'@esbuild/win32-x64': 0.27.0
2533
2501
2534
2502
escalade@3.2.0: {}
2535
2503
2536
-
exit-hook@2.2.1: {}
2504
+
esm-env@1.2.2: {}
2537
2505
2538
-
exsolve@1.0.4: {}
2506
+
exit-hook@2.2.1: {}
2539
2507
2540
2508
fast-glob@3.3.3:
2541
2509
dependencies:
···
2548
2516
fastq@1.19.1:
2549
2517
dependencies:
2550
2518
reusify: 1.1.0
2519
+
2520
+
fdir@6.5.0(picomatch@4.0.3):
2521
+
optionalDependencies:
2522
+
picomatch: 4.0.3
2551
2523
2552
2524
fetch-blob@3.2.0:
2553
2525
dependencies:
···
2559
2531
dependencies:
2560
2532
to-regex-range: 5.0.1
2561
2533
2562
-
foreground-child@3.3.1:
2563
-
dependencies:
2564
-
cross-spawn: 7.0.6
2565
-
signal-exit: 4.1.0
2566
-
2567
-
fraction.js@4.3.7: {}
2534
+
fraction.js@5.3.4: {}
2568
2535
2569
2536
fsevents@2.3.3:
2570
2537
optional: true
···
2573
2540
2574
2541
gensync@1.0.0-beta.2: {}
2575
2542
2576
-
get-source@2.0.12:
2577
-
dependencies:
2578
-
data-uri-to-buffer: 2.0.2
2579
-
source-map: 0.6.1
2580
-
2581
2543
glob-parent@5.1.2:
2582
2544
dependencies:
2583
2545
is-glob: 4.0.3
···
2588
2550
2589
2551
glob-to-regexp@0.4.1: {}
2590
2552
2591
-
glob@10.4.5:
2592
-
dependencies:
2593
-
foreground-child: 3.3.1
2594
-
jackspeak: 3.4.3
2595
-
minimatch: 9.0.5
2596
-
minipass: 7.1.2
2597
-
package-json-from-dist: 1.0.1
2598
-
path-scurry: 1.11.1
2599
-
2600
-
globals@11.12.0: {}
2601
-
2602
2553
hasown@2.0.2:
2603
2554
dependencies:
2604
2555
function-bind: 1.1.2
2605
2556
2606
2557
html-entities@2.3.3: {}
2607
2558
2608
-
is-arrayish@0.3.2:
2609
-
optional: true
2559
+
is-arrayish@0.3.4: {}
2610
2560
2611
2561
is-binary-path@2.1.0:
2612
2562
dependencies:
···
2618
2568
2619
2569
is-extglob@2.1.1: {}
2620
2570
2621
-
is-fullwidth-code-point@3.0.0: {}
2622
-
2623
2571
is-glob@4.0.3:
2624
2572
dependencies:
2625
2573
is-extglob: 2.1.1
···
2628
2576
2629
2577
is-what@4.1.16: {}
2630
2578
2631
-
isexe@2.0.0: {}
2632
-
2633
-
jackspeak@3.4.3:
2634
-
dependencies:
2635
-
'@isaacs/cliui': 8.0.2
2636
-
optionalDependencies:
2637
-
'@pkgjs/parseargs': 0.11.0
2638
-
2639
2579
jiti@1.21.7: {}
2640
2580
2641
2581
js-tokens@4.0.0: {}
···
2644
2584
2645
2585
json5@2.2.3: {}
2646
2586
2587
+
kleur@4.1.5: {}
2588
+
2647
2589
lilconfig@3.1.3: {}
2648
2590
2649
2591
lines-and-columns@1.2.4: {}
2650
-
2651
-
lru-cache@10.4.3: {}
2652
2592
2653
2593
lru-cache@5.1.1:
2654
2594
dependencies:
···
2669
2609
2670
2610
mini-svg-data-uri@1.4.4: {}
2671
2611
2672
-
miniflare@4.20250320.0:
2612
+
miniflare@4.20251202.1:
2673
2613
dependencies:
2674
2614
'@cspotcode/source-map-support': 0.8.1
2675
2615
acorn: 8.14.0
2676
2616
acorn-walk: 8.3.2
2677
2617
exit-hook: 2.2.1
2678
2618
glob-to-regexp: 0.4.1
2619
+
sharp: 0.33.5
2679
2620
stoppable: 1.1.0
2680
-
undici: 5.29.0
2681
-
workerd: 1.20250320.0
2621
+
undici: 7.14.0
2622
+
workerd: 1.20251202.0
2682
2623
ws: 8.18.0
2683
-
youch: 3.2.3
2624
+
youch: 4.1.0-beta.10
2684
2625
zod: 3.22.3
2685
2626
transitivePeerDependencies:
2686
2627
- bufferutil
2687
2628
- utf-8-validate
2688
2629
2689
-
minimatch@9.0.5:
2690
-
dependencies:
2691
-
brace-expansion: 2.0.1
2692
-
2693
-
minipass@7.1.2: {}
2694
-
2695
2630
ms@2.1.3: {}
2696
-
2697
-
mustache@4.2.0: {}
2698
2631
2699
2632
mz@2.7.0:
2700
2633
dependencies:
···
2704
2637
2705
2638
nanoid@3.3.11: {}
2706
2639
2707
-
nanoid@5.1.5: {}
2640
+
nanoid@5.1.6: {}
2708
2641
2709
2642
native-file-system-adapter@3.0.1:
2710
2643
optionalDependencies:
···
2713
2646
node-domexception@1.0.0:
2714
2647
optional: true
2715
2648
2716
-
node-releases@2.0.19: {}
2649
+
node-releases@2.0.27: {}
2717
2650
2718
2651
normalize-path@3.0.0: {}
2719
2652
···
2723
2656
2724
2657
object-hash@3.0.0: {}
2725
2658
2726
-
ohash@2.0.11: {}
2727
-
2728
-
package-json-from-dist@1.0.1: {}
2729
-
2730
-
parse5@7.2.1:
2659
+
parse5@7.3.0:
2731
2660
dependencies:
2732
-
entities: 4.5.0
2733
-
2734
-
path-key@3.1.1: {}
2661
+
entities: 6.0.1
2735
2662
2736
2663
path-parse@1.0.7: {}
2737
-
2738
-
path-scurry@1.11.1:
2739
-
dependencies:
2740
-
lru-cache: 10.4.3
2741
-
minipass: 7.1.2
2742
2664
2743
2665
path-to-regexp@6.3.0: {}
2744
2666
···
2748
2670
2749
2671
picomatch@2.3.1: {}
2750
2672
2673
+
picomatch@4.0.3: {}
2674
+
2751
2675
pify@2.3.0: {}
2752
2676
2753
-
pirates@4.0.6: {}
2677
+
pirates@4.0.7: {}
2754
2678
2755
-
postcss-import@15.1.0(postcss@8.5.3):
2679
+
postcss-import@15.1.0(postcss@8.5.6):
2756
2680
dependencies:
2757
-
postcss: 8.5.3
2681
+
postcss: 8.5.6
2758
2682
postcss-value-parser: 4.2.0
2759
2683
read-cache: 1.0.0
2760
-
resolve: 1.22.10
2684
+
resolve: 1.22.11
2761
2685
2762
-
postcss-js@4.0.1(postcss@8.5.3):
2686
+
postcss-js@4.1.0(postcss@8.5.6):
2763
2687
dependencies:
2764
2688
camelcase-css: 2.0.1
2765
-
postcss: 8.5.3
2689
+
postcss: 8.5.6
2766
2690
2767
-
postcss-load-config@4.0.2(postcss@8.5.3):
2691
+
postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6):
2768
2692
dependencies:
2769
2693
lilconfig: 3.1.3
2770
-
yaml: 2.7.0
2771
2694
optionalDependencies:
2772
-
postcss: 8.5.3
2695
+
jiti: 1.21.7
2696
+
postcss: 8.5.6
2773
2697
2774
-
postcss-nested@6.2.0(postcss@8.5.3):
2698
+
postcss-nested@6.2.0(postcss@8.5.6):
2775
2699
dependencies:
2776
-
postcss: 8.5.3
2700
+
postcss: 8.5.6
2777
2701
postcss-selector-parser: 6.1.2
2778
2702
2779
2703
postcss-selector-parser@6.1.2:
···
2783
2707
2784
2708
postcss-value-parser@4.2.0: {}
2785
2709
2786
-
postcss@8.5.3:
2710
+
postcss@8.5.6:
2787
2711
dependencies:
2788
2712
nanoid: 3.3.11
2789
2713
picocolors: 1.1.1
2790
2714
source-map-js: 1.2.1
2791
2715
2792
-
prettier-plugin-tailwindcss@0.6.11(prettier@3.5.3):
2716
+
prettier-plugin-tailwindcss@0.6.14(prettier@3.7.4):
2793
2717
dependencies:
2794
-
prettier: 3.5.3
2718
+
prettier: 3.7.4
2795
2719
2796
-
prettier@3.5.3: {}
2797
-
2798
-
printable-characters@1.0.42: {}
2720
+
prettier@3.7.4: {}
2799
2721
2800
2722
queue-microtask@1.2.3: {}
2801
2723
···
2807
2729
dependencies:
2808
2730
picomatch: 2.3.1
2809
2731
2810
-
resolve@1.22.10:
2732
+
resolve@1.22.11:
2811
2733
dependencies:
2812
2734
is-core-module: 2.16.1
2813
2735
path-parse: 1.0.7
···
2815
2737
2816
2738
reusify@1.1.0: {}
2817
2739
2818
-
rollup@4.37.0:
2740
+
rollup@4.53.3:
2819
2741
dependencies:
2820
-
'@types/estree': 1.0.6
2742
+
'@types/estree': 1.0.8
2821
2743
optionalDependencies:
2822
-
'@rollup/rollup-android-arm-eabi': 4.37.0
2823
-
'@rollup/rollup-android-arm64': 4.37.0
2824
-
'@rollup/rollup-darwin-arm64': 4.37.0
2825
-
'@rollup/rollup-darwin-x64': 4.37.0
2826
-
'@rollup/rollup-freebsd-arm64': 4.37.0
2827
-
'@rollup/rollup-freebsd-x64': 4.37.0
2828
-
'@rollup/rollup-linux-arm-gnueabihf': 4.37.0
2829
-
'@rollup/rollup-linux-arm-musleabihf': 4.37.0
2830
-
'@rollup/rollup-linux-arm64-gnu': 4.37.0
2831
-
'@rollup/rollup-linux-arm64-musl': 4.37.0
2832
-
'@rollup/rollup-linux-loongarch64-gnu': 4.37.0
2833
-
'@rollup/rollup-linux-powerpc64le-gnu': 4.37.0
2834
-
'@rollup/rollup-linux-riscv64-gnu': 4.37.0
2835
-
'@rollup/rollup-linux-riscv64-musl': 4.37.0
2836
-
'@rollup/rollup-linux-s390x-gnu': 4.37.0
2837
-
'@rollup/rollup-linux-x64-gnu': 4.37.0
2838
-
'@rollup/rollup-linux-x64-musl': 4.37.0
2839
-
'@rollup/rollup-win32-arm64-msvc': 4.37.0
2840
-
'@rollup/rollup-win32-ia32-msvc': 4.37.0
2841
-
'@rollup/rollup-win32-x64-msvc': 4.37.0
2744
+
'@rollup/rollup-android-arm-eabi': 4.53.3
2745
+
'@rollup/rollup-android-arm64': 4.53.3
2746
+
'@rollup/rollup-darwin-arm64': 4.53.3
2747
+
'@rollup/rollup-darwin-x64': 4.53.3
2748
+
'@rollup/rollup-freebsd-arm64': 4.53.3
2749
+
'@rollup/rollup-freebsd-x64': 4.53.3
2750
+
'@rollup/rollup-linux-arm-gnueabihf': 4.53.3
2751
+
'@rollup/rollup-linux-arm-musleabihf': 4.53.3
2752
+
'@rollup/rollup-linux-arm64-gnu': 4.53.3
2753
+
'@rollup/rollup-linux-arm64-musl': 4.53.3
2754
+
'@rollup/rollup-linux-loong64-gnu': 4.53.3
2755
+
'@rollup/rollup-linux-ppc64-gnu': 4.53.3
2756
+
'@rollup/rollup-linux-riscv64-gnu': 4.53.3
2757
+
'@rollup/rollup-linux-riscv64-musl': 4.53.3
2758
+
'@rollup/rollup-linux-s390x-gnu': 4.53.3
2759
+
'@rollup/rollup-linux-x64-gnu': 4.53.3
2760
+
'@rollup/rollup-linux-x64-musl': 4.53.3
2761
+
'@rollup/rollup-openharmony-arm64': 4.53.3
2762
+
'@rollup/rollup-win32-arm64-msvc': 4.53.3
2763
+
'@rollup/rollup-win32-ia32-msvc': 4.53.3
2764
+
'@rollup/rollup-win32-x64-gnu': 4.53.3
2765
+
'@rollup/rollup-win32-x64-msvc': 4.53.3
2842
2766
fsevents: 2.3.3
2843
2767
2844
2768
run-parallel@1.2.0:
···
2847
2771
2848
2772
semver@6.3.1: {}
2849
2773
2850
-
semver@7.7.1:
2851
-
optional: true
2774
+
semver@7.7.3: {}
2852
2775
2853
-
seroval-plugins@1.2.1(seroval@1.2.1):
2776
+
seroval-plugins@1.3.3(seroval@1.3.2):
2854
2777
dependencies:
2855
-
seroval: 1.2.1
2778
+
seroval: 1.3.2
2856
2779
2857
-
seroval@1.2.1: {}
2780
+
seroval@1.3.2: {}
2858
2781
2859
2782
sharp@0.33.5:
2860
2783
dependencies:
2861
2784
color: 4.2.3
2862
-
detect-libc: 2.0.3
2863
-
semver: 7.7.1
2785
+
detect-libc: 2.1.2
2786
+
semver: 7.7.3
2864
2787
optionalDependencies:
2865
2788
'@img/sharp-darwin-arm64': 0.33.5
2866
2789
'@img/sharp-darwin-x64': 0.33.5
···
2881
2804
'@img/sharp-wasm32': 0.33.5
2882
2805
'@img/sharp-win32-ia32': 0.33.5
2883
2806
'@img/sharp-win32-x64': 0.33.5
2884
-
optional: true
2885
2807
2886
-
shebang-command@2.0.0:
2808
+
simple-swizzle@0.2.4:
2887
2809
dependencies:
2888
-
shebang-regex: 3.0.0
2810
+
is-arrayish: 0.3.4
2889
2811
2890
-
shebang-regex@3.0.0: {}
2891
-
2892
-
signal-exit@4.1.0: {}
2893
-
2894
-
simple-swizzle@0.2.2:
2812
+
solid-js@1.9.10:
2895
2813
dependencies:
2896
-
is-arrayish: 0.3.2
2897
-
optional: true
2814
+
csstype: 3.2.3
2815
+
seroval: 1.3.2
2816
+
seroval-plugins: 1.3.3(seroval@1.3.2)
2898
2817
2899
-
solid-js@1.9.5:
2818
+
solid-refresh@0.6.3(solid-js@1.9.10):
2900
2819
dependencies:
2901
-
csstype: 3.1.3
2902
-
seroval: 1.2.1
2903
-
seroval-plugins: 1.2.1(seroval@1.2.1)
2904
-
2905
-
solid-refresh@0.6.3(solid-js@1.9.5):
2906
-
dependencies:
2907
-
'@babel/generator': 7.26.10
2908
-
'@babel/helper-module-imports': 7.25.9
2909
-
'@babel/types': 7.26.10
2910
-
solid-js: 1.9.5
2820
+
'@babel/generator': 7.28.5
2821
+
'@babel/helper-module-imports': 7.27.1
2822
+
'@babel/types': 7.28.5
2823
+
solid-js: 1.9.10
2911
2824
transitivePeerDependencies:
2912
2825
- supports-color
2913
2826
···
2920
2833
2921
2834
source-map@0.6.1: {}
2922
2835
2923
-
stacktracey@2.1.8:
2924
-
dependencies:
2925
-
as-table: 1.0.55
2926
-
get-source: 2.0.12
2927
-
2928
2836
stoppable@1.1.0: {}
2929
2837
2930
-
string-width@4.2.3:
2931
-
dependencies:
2932
-
emoji-regex: 8.0.0
2933
-
is-fullwidth-code-point: 3.0.0
2934
-
strip-ansi: 6.0.1
2935
-
2936
-
string-width@5.1.2:
2937
-
dependencies:
2938
-
eastasianwidth: 0.2.0
2939
-
emoji-regex: 9.2.2
2940
-
strip-ansi: 7.1.0
2941
-
2942
-
strip-ansi@6.0.1:
2943
-
dependencies:
2944
-
ansi-regex: 5.0.1
2945
-
2946
-
strip-ansi@7.1.0:
2838
+
sucrase@3.35.1:
2947
2839
dependencies:
2948
-
ansi-regex: 6.1.0
2949
-
2950
-
sucrase@3.35.0:
2951
-
dependencies:
2952
-
'@jridgewell/gen-mapping': 0.3.8
2840
+
'@jridgewell/gen-mapping': 0.3.13
2953
2841
commander: 4.1.1
2954
-
glob: 10.4.5
2955
2842
lines-and-columns: 1.2.4
2956
2843
mz: 2.7.0
2957
-
pirates: 4.0.6
2844
+
pirates: 4.0.7
2845
+
tinyglobby: 0.2.15
2958
2846
ts-interface-checker: 0.1.13
2847
+
2848
+
supports-color@10.2.2: {}
2959
2849
2960
2850
supports-preserve-symlinks-flag@1.0.0: {}
2961
2851
2962
-
tailwindcss@3.4.17:
2852
+
tailwindcss@3.4.18:
2963
2853
dependencies:
2964
2854
'@alloc/quick-lru': 5.2.0
2965
2855
arg: 5.0.2
···
2975
2865
normalize-path: 3.0.0
2976
2866
object-hash: 3.0.0
2977
2867
picocolors: 1.1.1
2978
-
postcss: 8.5.3
2979
-
postcss-import: 15.1.0(postcss@8.5.3)
2980
-
postcss-js: 4.0.1(postcss@8.5.3)
2981
-
postcss-load-config: 4.0.2(postcss@8.5.3)
2982
-
postcss-nested: 6.2.0(postcss@8.5.3)
2868
+
postcss: 8.5.6
2869
+
postcss-import: 15.1.0(postcss@8.5.6)
2870
+
postcss-js: 4.1.0(postcss@8.5.6)
2871
+
postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)
2872
+
postcss-nested: 6.2.0(postcss@8.5.6)
2983
2873
postcss-selector-parser: 6.1.2
2984
-
resolve: 1.22.10
2985
-
sucrase: 3.35.0
2874
+
resolve: 1.22.11
2875
+
sucrase: 3.35.1
2986
2876
transitivePeerDependencies:
2987
-
- ts-node
2877
+
- tsx
2878
+
- yaml
2988
2879
2989
-
terser@5.39.0:
2880
+
terser@5.44.1:
2990
2881
dependencies:
2991
-
'@jridgewell/source-map': 0.3.6
2992
-
acorn: 8.14.1
2882
+
'@jridgewell/source-map': 0.3.11
2883
+
acorn: 8.15.0
2993
2884
commander: 2.20.3
2994
2885
source-map-support: 0.5.21
2995
2886
···
3001
2892
dependencies:
3002
2893
any-promise: 1.3.0
3003
2894
2895
+
tinyglobby@0.2.15:
2896
+
dependencies:
2897
+
fdir: 6.5.0(picomatch@4.0.3)
2898
+
picomatch: 4.0.3
2899
+
3004
2900
to-regex-range@5.0.1:
3005
2901
dependencies:
3006
2902
is-number: 7.0.0
···
3010
2906
tslib@2.8.1:
3011
2907
optional: true
3012
2908
3013
-
typescript@5.8.2: {}
2909
+
typescript@5.9.3: {}
3014
2910
3015
-
ufo@1.5.4: {}
3016
-
3017
-
undici-types@6.20.0: {}
2911
+
undici-types@6.21.0: {}
3018
2912
3019
-
undici@5.29.0:
3020
-
dependencies:
3021
-
'@fastify/busboy': 2.1.1
2913
+
undici@7.14.0: {}
3022
2914
3023
-
unenv@2.0.0-rc.15:
2915
+
unenv@2.0.0-rc.24:
3024
2916
dependencies:
3025
-
defu: 6.1.4
3026
-
exsolve: 1.0.4
3027
-
ohash: 2.0.11
3028
2917
pathe: 2.0.3
3029
-
ufo: 1.5.4
3030
2918
3031
-
update-browserslist-db@1.1.3(browserslist@4.24.4):
2919
+
update-browserslist-db@1.2.2(browserslist@4.28.1):
3032
2920
dependencies:
3033
-
browserslist: 4.24.4
2921
+
browserslist: 4.28.1
3034
2922
escalade: 3.2.0
3035
2923
picocolors: 1.1.1
3036
2924
3037
2925
util-deprecate@1.0.2: {}
3038
2926
3039
-
validate-html-nesting@1.2.2: {}
3040
-
3041
-
vite-plugin-solid@2.11.6(solid-js@1.9.5)(vite@6.2.2(@types/node@22.13.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.0)):
2927
+
vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1)):
3042
2928
dependencies:
3043
-
'@babel/core': 7.26.10
2929
+
'@babel/core': 7.28.5
3044
2930
'@types/babel__core': 7.20.5
3045
-
babel-preset-solid: 1.9.5(@babel/core@7.26.10)
2931
+
babel-preset-solid: 1.9.10(@babel/core@7.28.5)(solid-js@1.9.10)
3046
2932
merge-anything: 5.1.7
3047
-
solid-js: 1.9.5
3048
-
solid-refresh: 0.6.3(solid-js@1.9.5)
3049
-
vite: 6.2.2(@types/node@22.13.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.0)
3050
-
vitefu: 1.0.6(vite@6.2.2(@types/node@22.13.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.0))
2933
+
solid-js: 1.9.10
2934
+
solid-refresh: 0.6.3(solid-js@1.9.10)
2935
+
vite: 7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1)
2936
+
vitefu: 1.1.1(vite@7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1))
3051
2937
transitivePeerDependencies:
3052
2938
- supports-color
3053
2939
3054
-
vite@6.2.2(@types/node@22.13.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.0):
2940
+
vite@7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1):
3055
2941
dependencies:
3056
-
esbuild: 0.25.1
3057
-
postcss: 8.5.3
3058
-
rollup: 4.37.0
2942
+
esbuild: 0.25.12
2943
+
fdir: 6.5.0(picomatch@4.0.3)
2944
+
picomatch: 4.0.3
2945
+
postcss: 8.5.6
2946
+
rollup: 4.53.3
2947
+
tinyglobby: 0.2.15
3059
2948
optionalDependencies:
3060
-
'@types/node': 22.13.12
2949
+
'@types/node': 22.19.2
3061
2950
fsevents: 2.3.3
3062
2951
jiti: 1.21.7
3063
-
terser: 5.39.0
3064
-
yaml: 2.7.0
2952
+
terser: 5.44.1
3065
2953
3066
-
vitefu@1.0.6(vite@6.2.2(@types/node@22.13.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.0)):
2954
+
vitefu@1.1.1(vite@7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1)):
3067
2955
optionalDependencies:
3068
-
vite: 6.2.2(@types/node@22.13.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.0)
2956
+
vite: 7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1)
3069
2957
3070
2958
web-streams-polyfill@3.3.3:
3071
2959
optional: true
3072
2960
3073
-
which@2.0.2:
3074
-
dependencies:
3075
-
isexe: 2.0.0
3076
-
3077
-
workerd@1.20250320.0:
2961
+
workerd@1.20251202.0:
3078
2962
optionalDependencies:
3079
-
'@cloudflare/workerd-darwin-64': 1.20250320.0
3080
-
'@cloudflare/workerd-darwin-arm64': 1.20250320.0
3081
-
'@cloudflare/workerd-linux-64': 1.20250320.0
3082
-
'@cloudflare/workerd-linux-arm64': 1.20250320.0
3083
-
'@cloudflare/workerd-windows-64': 1.20250320.0
2963
+
'@cloudflare/workerd-darwin-64': 1.20251202.0
2964
+
'@cloudflare/workerd-darwin-arm64': 1.20251202.0
2965
+
'@cloudflare/workerd-linux-64': 1.20251202.0
2966
+
'@cloudflare/workerd-linux-arm64': 1.20251202.0
2967
+
'@cloudflare/workerd-windows-64': 1.20251202.0
3084
2968
3085
-
wrangler@4.4.0:
2969
+
wrangler@4.53.0:
3086
2970
dependencies:
3087
-
'@cloudflare/kv-asset-handler': 0.4.0
3088
-
'@cloudflare/unenv-preset': 2.3.0(unenv@2.0.0-rc.15)(workerd@1.20250320.0)
2971
+
'@cloudflare/kv-asset-handler': 0.4.1
2972
+
'@cloudflare/unenv-preset': 2.7.13(unenv@2.0.0-rc.24)(workerd@1.20251202.0)
3089
2973
blake3-wasm: 2.1.5
3090
-
esbuild: 0.24.2
3091
-
miniflare: 4.20250320.0
2974
+
esbuild: 0.27.0
2975
+
miniflare: 4.20251202.1
3092
2976
path-to-regexp: 6.3.0
3093
-
unenv: 2.0.0-rc.15
3094
-
workerd: 1.20250320.0
2977
+
unenv: 2.0.0-rc.24
2978
+
workerd: 1.20251202.0
3095
2979
optionalDependencies:
3096
2980
fsevents: 2.3.3
3097
-
sharp: 0.33.5
3098
2981
transitivePeerDependencies:
3099
2982
- bufferutil
3100
2983
- utf-8-validate
3101
2984
3102
-
wrap-ansi@7.0.0:
3103
-
dependencies:
3104
-
ansi-styles: 4.3.0
3105
-
string-width: 4.2.3
3106
-
strip-ansi: 6.0.1
3107
-
3108
-
wrap-ansi@8.1.0:
3109
-
dependencies:
3110
-
ansi-styles: 6.2.1
3111
-
string-width: 5.1.2
3112
-
strip-ansi: 7.1.0
3113
-
3114
2985
ws@8.18.0: {}
3115
2986
3116
2987
yallist@3.1.1: {}
3117
2988
3118
-
yaml@2.7.0: {}
2989
+
youch-core@0.3.3:
2990
+
dependencies:
2991
+
'@poppinss/exception': 1.2.2
2992
+
error-stack-parser-es: 1.0.5
3119
2993
3120
-
youch@3.2.3:
2994
+
youch@4.1.0-beta.10:
3121
2995
dependencies:
3122
-
cookie: 0.5.0
3123
-
mustache: 4.2.0
3124
-
stacktracey: 2.1.8
2996
+
'@poppinss/colors': 4.1.5
2997
+
'@poppinss/dumper': 0.6.5
2998
+
'@speed-highlight/core': 1.2.12
2999
+
cookie: 1.1.1
3000
+
youch-core: 0.3.3
3125
3001
3126
3002
zod@3.22.3: {}
+2
-1
src/api/queries/did-doc.ts
+2
-1
src/api/queries/did-doc.ts
···
1
-
import type { AtprotoDid, DidDocument } from '@atcute/identity';
1
+
import type { DidDocument } from '@atcute/identity';
2
2
import {
3
3
CompositeDidDocumentResolver,
4
4
PlcDidDocumentResolver,
5
5
WebDidDocumentResolver,
6
6
} from '@atcute/identity-resolver';
7
+
import type { AtprotoDid } from '@atcute/lexicons/syntax';
7
8
8
9
const didDocumentResolver = new CompositeDidDocumentResolver({
9
10
methods: {
+1
-1
src/api/queries/handle.ts
+1
-1
src/api/queries/handle.ts
···
1
-
import { type AtprotoDid, type Handle, isHandle } from '@atcute/identity';
2
1
import { XrpcHandleResolver } from '@atcute/identity-resolver';
2
+
import { type AtprotoDid, type Handle, isHandle } from '@atcute/lexicons/syntax';
3
3
4
4
const handleResolver = new XrpcHandleResolver({
5
5
serviceUrl: import.meta.env.VITE_APPVIEW_URL,
+1
-1
src/api/queries/plc.ts
+1
-1
src/api/queries/plc.ts
···
1
1
import { defs } from '@atcute/did-plc';
2
-
import { Did } from '@atcute/identity';
2
+
import type { Did } from '@atcute/lexicons/syntax';
3
3
4
4
export const getPlcAuditLogs = async ({ did, signal }: { did: Did<'plc'>; signal?: AbortSignal }) => {
5
5
const origin = import.meta.env.VITE_PLC_DIRECTORY_URL;
+2
-2
src/api/types/plc.ts
+2
-2
src/api/types/plc.ts
···
1
1
import * as v from '@badrap/valita';
2
2
3
-
import { defs, UnsignedOperation } from '@atcute/did-plc';
3
+
import { defs, type UnsignedOperation } from '@atcute/did-plc';
4
4
5
-
import { ToValidator } from '../utils/valita';
5
+
import type { ToValidator } from '../utils/valita';
6
6
import { serviceUrlString } from './strings';
7
7
8
8
const _unsignedOperation = defs.unsignedOperation as ToValidator<UnsignedOperation>;
-53
src/api/utils/at-uri.ts
-53
src/api/utils/at-uri.ts
···
1
-
import { assert } from '~/lib/utils/invariant';
2
-
3
-
type Did<TMethod extends string = string> = `did:${TMethod}:${string}`;
4
-
5
-
type Nsid = `${string}.${string}.${string}`;
6
-
7
-
type RecordKey = string;
8
-
9
-
const DID_RE = /^did:([a-z]+):([a-zA-Z0-9._:%\-]*[a-zA-Z0-9._\-])$/;
10
-
11
-
const NSID_RE =
12
-
/^[a-zA-Z](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?:\.[a-zA-Z](?:[a-zA-Z0-9]{0,62})?)$/;
13
-
14
-
const RECORD_KEY_RE = /^(?!\.{1,2}$)[a-zA-Z0-9_~.:-]{1,512}$/;
15
-
16
-
const ATURI_RE =
17
-
/^at:\/\/([a-zA-Z0-9._:%-]+)(?:\/([a-zA-Z0-9-.]+)(?:\/([a-zA-Z0-9._~:@!$&%')(*+,;=-]+))?)?(?:#(\/[a-zA-Z0-9._~:@!$&%')(*+,;=\-[\]/\\]*))?$/;
18
-
19
-
const isDid = (input: unknown): input is Did => {
20
-
return typeof input === 'string' && input.length >= 7 && input.length <= 2048 && DID_RE.test(input);
21
-
};
22
-
23
-
const isNsid = (input: unknown): input is Nsid => {
24
-
return typeof input === 'string' && input.length >= 5 && input.length <= 317 && NSID_RE.test(input);
25
-
};
26
-
27
-
const isRecordKey = (input: unknown): input is RecordKey => {
28
-
return typeof input === 'string' && input.length >= 1 && input.length <= 512 && RECORD_KEY_RE.test(input);
29
-
};
30
-
31
-
export interface AddressedAtUri {
32
-
repo: Did;
33
-
collection: Nsid;
34
-
rkey: string;
35
-
fragment: string | undefined;
36
-
}
37
-
38
-
export const parseAddressedAtUri = (str: string): AddressedAtUri => {
39
-
const match = ATURI_RE.exec(str);
40
-
assert(match !== null, `invalid addressed-at-uri: ${str}`);
41
-
42
-
const [, r, c, k, f] = match;
43
-
assert(isDid(r), `invalid repo in addressed-at-uri: ${r}`);
44
-
assert(isNsid(c), `invalid collection in addressed-at-uri: ${c}`);
45
-
assert(isRecordKey(k), `invalid rkey in addressed-at-uri: ${k}`);
46
-
47
-
return {
48
-
repo: r,
49
-
collection: c,
50
-
rkey: k,
51
-
fragment: f,
52
-
};
53
-
};
+7
-12
src/api/utils/error.ts
+7
-12
src/api/utils/error.ts
···
1
-
import { XRPCError } from '@atcute/client';
2
-
3
-
export const formatXRPCError = (err: XRPCError): string => {
4
-
const name = err.kind;
5
-
return (name ? name + ': ' : '') + err.message;
6
-
};
1
+
import { ClientResponseError } from '@atcute/client';
7
2
8
3
export const formatQueryError = (err: unknown) => {
9
-
if (err instanceof XRPCError) {
10
-
const kind = err.kind;
4
+
if (err instanceof ClientResponseError) {
5
+
const error = err.error;
11
6
12
-
if (kind === 'InvalidToken' || kind === 'ExpiredToken') {
7
+
if (error === 'InvalidToken' || error === 'ExpiredToken') {
13
8
return `Account session is no longer valid`;
14
9
}
15
10
16
-
if (kind === 'UpstreamFailure') {
11
+
if (error === 'UpstreamFailure') {
17
12
return `Server appears to be experiencing issues, try again later`;
18
13
}
19
14
20
-
if (kind === 'InternalServerError') {
15
+
if (error === 'InternalServerError') {
21
16
return `Server is having issues processing this request, try again later`;
22
17
}
23
18
24
-
return formatXRPCError(err);
19
+
return err.message;
25
20
}
26
21
27
22
if (err instanceof Error) {
+69
src/api/utils/jwt.ts
+69
src/api/utils/jwt.ts
···
1
+
/**
2
+
* Decodes a JWT token
3
+
* @param token The token string
4
+
* @returns JSON object from the token
5
+
*/
6
+
export const decodeJwt = (token: string): unknown => {
7
+
const pos = 1;
8
+
const part = token.split('.')[1];
9
+
10
+
let decoded: string;
11
+
12
+
if (typeof part !== 'string') {
13
+
throw new Error('invalid token: missing part ' + (pos + 1));
14
+
}
15
+
16
+
try {
17
+
decoded = base64UrlDecode(part);
18
+
} catch (e) {
19
+
throw new Error('invalid token: invalid b64 for part ' + (pos + 1) + ' (' + (e as Error).message + ')');
20
+
}
21
+
22
+
try {
23
+
return JSON.parse(decoded);
24
+
} catch (e) {
25
+
throw new Error('invalid token: invalid json for part ' + (pos + 1) + ' (' + (e as Error).message + ')');
26
+
}
27
+
};
28
+
29
+
/**
30
+
* Decodes a URL-safe Base64 string
31
+
* @param str URL-safe Base64 that needed to be decoded
32
+
* @returns The actual string
33
+
*/
34
+
const base64UrlDecode = (str: string): string => {
35
+
let output = str.replace(/-/g, '+').replace(/_/g, '/');
36
+
37
+
switch (output.length % 4) {
38
+
case 0:
39
+
break;
40
+
case 2:
41
+
output += '==';
42
+
break;
43
+
case 3:
44
+
output += '=';
45
+
break;
46
+
default:
47
+
throw new Error('base64 string is not of the correct length');
48
+
}
49
+
50
+
try {
51
+
return b64DecodeUnicode(output);
52
+
} catch {
53
+
return atob(output);
54
+
}
55
+
};
56
+
57
+
const b64DecodeUnicode = (str: string): string => {
58
+
return decodeURIComponent(
59
+
atob(str).replace(/(.)/g, (_m, p) => {
60
+
let code = p.charCodeAt(0).toString(16).toUpperCase();
61
+
62
+
if (code.length < 2) {
63
+
code = '0' + code;
64
+
}
65
+
66
+
return '%' + code;
67
+
}),
68
+
);
69
+
};
-8
src/api/utils/strings.ts
-8
src/api/utils/strings.ts
···
1
-
import type { Records } from '@atcute/client/lexicons';
2
-
3
-
export const DID_OR_HANDLE_RE =
4
-
/^[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(?:\.[a-zA-Z]{2,})$|^did:[a-z]+:[a-zA-Z0-9._:%\-]*[a-zA-Z0-9._\-]$/;
5
-
6
-
export const makeAtUri = (repo: string, collection: keyof Records | (string & {}), rkey: string) => {
7
-
return `at://${repo}/${collection}/${rkey}`;
8
-
};
+72
src/components/accordion.tsx
+72
src/components/accordion.tsx
···
1
+
import { createSignal, type JSX, Show } from 'solid-js';
2
+
3
+
import ChevronRightIcon from '~/components/ic-icons/baseline-chevron-right';
4
+
5
+
export interface AccordionProps {
6
+
title: string;
7
+
children: JSX.Element;
8
+
defaultOpen?: boolean;
9
+
}
10
+
11
+
export const Accordion = (props: AccordionProps) => {
12
+
const [isOpen, setIsOpen] = createSignal(props.defaultOpen ?? false);
13
+
14
+
return (
15
+
<div class="border-b border-gray-200">
16
+
<button
17
+
type="button"
18
+
onClick={() => setIsOpen(!isOpen())}
19
+
class="flex w-full items-center gap-3 px-4 py-3 text-left hover:bg-gray-50"
20
+
>
21
+
<ChevronRightIcon
22
+
class={`h-5 w-5 text-gray-500 transition-transform` + (isOpen() ? ` rotate-90` : ``)}
23
+
/>
24
+
<span class="font-semibold">{props.title}</span>
25
+
</button>
26
+
27
+
<Show when={isOpen()}>
28
+
<div class="pb-4 pl-12 pr-4">{props.children}</div>
29
+
</Show>
30
+
</div>
31
+
);
32
+
};
33
+
34
+
export interface SubsectionProps {
35
+
title: string;
36
+
children: JSX.Element;
37
+
}
38
+
39
+
export const Subsection = (props: SubsectionProps) => {
40
+
return (
41
+
<div class="mb-4 last:mb-0">
42
+
<h4 class="mb-3 text-sm font-semibold text-gray-600">{props.title}</h4>
43
+
<div class="flex flex-col gap-3">{props.children}</div>
44
+
</div>
45
+
);
46
+
};
47
+
48
+
export interface StatusBadgeProps {
49
+
variant: 'idle' | 'pending' | 'success' | 'error';
50
+
children: JSX.Element;
51
+
}
52
+
53
+
export const StatusBadge = (props: StatusBadgeProps) => {
54
+
const variantStyles = () => {
55
+
switch (props.variant) {
56
+
case 'idle':
57
+
return 'bg-gray-100 text-gray-600';
58
+
case 'pending':
59
+
return 'bg-yellow-100 text-yellow-800';
60
+
case 'success':
61
+
return 'bg-green-100 text-green-800';
62
+
case 'error':
63
+
return 'bg-red-100 text-red-800';
64
+
}
65
+
};
66
+
67
+
return (
68
+
<span class={`inline-flex items-center rounded px-2 py-0.5 text-xs font-medium ${variantStyles()}`}>
69
+
{props.children}
70
+
</span>
71
+
);
72
+
};
+65
src/components/file-drop-zone.tsx
+65
src/components/file-drop-zone.tsx
···
1
+
import type { JSX } from 'solid-js';
2
+
3
+
import { createDropZone, type CreateDropZoneOptions } from '~/lib/hooks/dropzone';
4
+
5
+
import Button from './inputs/button';
6
+
7
+
interface FileDropZoneProps {
8
+
accept?: string;
9
+
disabled?: boolean;
10
+
onFiles: (files: File[]) => void;
11
+
dataTypes?: CreateDropZoneOptions['dataTypes'];
12
+
multiple?: boolean;
13
+
children?: JSX.Element;
14
+
}
15
+
16
+
const FileDropZone = (props: FileDropZoneProps) => {
17
+
const { ref: dropRef, isDropping } = createDropZone({
18
+
dataTypes: props.dataTypes,
19
+
multiple: props.multiple ?? false,
20
+
onDrop(files) {
21
+
if (files) {
22
+
props.onFiles(files);
23
+
}
24
+
},
25
+
});
26
+
27
+
const handleBrowse = () => {
28
+
const input = document.createElement('input');
29
+
input.type = 'file';
30
+
if (props.accept) {
31
+
input.accept = props.accept;
32
+
}
33
+
if (props.multiple) {
34
+
input.multiple = true;
35
+
}
36
+
input.oninput = () => {
37
+
const files = Array.from(input.files!);
38
+
if (files.length > 0) {
39
+
props.onFiles(files);
40
+
}
41
+
};
42
+
input.click();
43
+
};
44
+
45
+
return (
46
+
<fieldset
47
+
ref={dropRef}
48
+
disabled={props.disabled}
49
+
class={
50
+
`relative grid place-items-center rounded border border-gray-300 px-6 py-12 disabled:opacity-50` +
51
+
(props.disabled || !isDropping() ? ` bg-gray-100` : ` bg-green-100`)
52
+
}
53
+
>
54
+
<div class="flex flex-col items-center gap-4">
55
+
<Button variant="outline" onClick={handleBrowse}>
56
+
Browse files
57
+
</Button>
58
+
<p class="select-none font-medium text-gray-600">or drop your file here</p>
59
+
</div>
60
+
{props.children}
61
+
</fieldset>
62
+
);
63
+
};
64
+
65
+
export default FileDropZone;
+2
-3
src/components/inputs/multiline-input.tsx
+2
-3
src/components/inputs/multiline-input.tsx
···
1
-
import { createEffect, JSX } from 'solid-js';
1
+
import { createEffect, type JSX } from 'solid-js';
2
2
3
3
import { createId } from '~/lib/hooks/id';
4
4
5
-
import { BoundInputEvent } from './_types';
5
+
import type { BoundInputEvent } from './_types';
6
6
7
7
interface MultilineInputProps {
8
8
label: JSX.Element;
···
39
39
name={props.name}
40
40
required={props.required}
41
41
autocomplete={props.autocomplete}
42
-
// @ts-expect-error
43
42
autocorrect={props.autocorrect}
44
43
rows={22}
45
44
value={props.value}
+2
-2
src/components/inputs/radio-input.tsx
+2
-2
src/components/inputs/radio-input.tsx
···
1
-
import { JSX } from 'solid-js';
1
+
import type { JSX } from 'solid-js';
2
2
3
3
import { createId } from '~/lib/hooks/id';
4
4
5
-
import { BoundInputEvent } from './_types';
5
+
import type { BoundInputEvent } from './_types';
6
6
7
7
interface RadioInputProps<T extends string> {
8
8
label: JSX.Element;
+2
-2
src/components/inputs/select-input.tsx
+2
-2
src/components/inputs/select-input.tsx
···
1
-
import { createEffect, JSX } from 'solid-js';
1
+
import { createEffect, type JSX } from 'solid-js';
2
2
3
3
import { createId } from '~/lib/hooks/id';
4
4
5
-
import { BoundInputEvent } from './_types';
5
+
import type { BoundInputEvent } from './_types';
6
6
7
7
interface SelectInputProps<T extends string> {
8
8
label: JSX.Element;
+5
-3
src/components/inputs/text-input.tsx
+5
-3
src/components/inputs/text-input.tsx
···
1
-
import { createEffect, JSX } from 'solid-js';
1
+
import { createEffect, type JSX } from 'solid-js';
2
2
3
3
import { createId } from '~/lib/hooks/id';
4
4
5
-
import { BoundInputEvent } from './_types';
5
+
import type { BoundInputEvent } from './_types';
6
6
7
-
interface TextInputProps {
7
+
export interface TextInputProps {
8
8
label: JSX.Element;
9
9
blurb?: JSX.Element;
10
10
monospace?: boolean;
11
11
type?: 'text' | 'password' | 'url' | 'email';
12
12
name?: string;
13
13
required?: boolean;
14
+
disabled?: boolean;
14
15
autocomplete?: 'off' | 'on' | 'one-time-code' | 'username';
15
16
autocorrect?: 'off' | 'on';
16
17
pattern?: string;
···
55
56
id={fieldId}
56
57
name={props.name}
57
58
required={props.required}
59
+
disabled={props.disabled}
58
60
autocomplete={props.autocomplete}
59
61
pattern={props.pattern}
60
62
placeholder={props.placeholder}
+1
-1
src/components/inputs/toggle-input.tsx
+1
-1
src/components/inputs/toggle-input.tsx
+22
src/components/page-header.tsx
+22
src/components/page-header.tsx
···
1
+
import type { JSX } from 'solid-js';
2
+
3
+
interface PageHeaderProps {
4
+
title: string;
5
+
subtitle?: string;
6
+
children?: JSX.Element;
7
+
}
8
+
9
+
const PageHeader = (props: PageHeaderProps) => {
10
+
return (
11
+
<>
12
+
<div class="p-4">
13
+
<h1 class="text-lg font-bold text-purple-800">{props.title}</h1>
14
+
{props.subtitle && <p class="text-gray-600">{props.subtitle}</p>}
15
+
{props.children}
16
+
</div>
17
+
<hr class="mx-4 border-gray-300" />
18
+
</>
19
+
);
20
+
};
21
+
22
+
export default PageHeader;
+1
-1
src/components/wizard.tsx
+1
-1
src/components/wizard.tsx
+13
-12
src/components/wizards/bluesky-login-step.tsx
+13
-12
src/components/wizards/bluesky-login-step.tsx
···
1
1
import { batch, createSignal, Match, Show, Switch } from 'solid-js';
2
2
3
-
import { CredentialManager, XRPCError } from '@atcute/client';
4
-
import { type AtprotoDid, type DidDocument, getPdsEndpoint, isAtprotoDid, isHandle } from '@atcute/identity';
3
+
import { ClientResponseError, CredentialManager } from '@atcute/client';
4
+
import { getPdsEndpoint, isAtprotoDid, type DidDocument } from '@atcute/identity';
5
+
import { isHandle, type AtprotoDid } from '@atcute/lexicons/syntax';
5
6
6
7
import { getDidDocument } from '~/api/queries/did-doc';
7
8
import { resolveHandleViaAppView } from '~/api/queries/handle';
···
88
89
setIsTotpRequired(false);
89
90
});
90
91
},
91
-
onError(error) {
92
+
onError(err) {
92
93
let message: string | undefined;
93
94
94
-
if (error instanceof XRPCError) {
95
-
if (error.kind === 'AuthFactorTokenRequired') {
95
+
if (err instanceof ClientResponseError) {
96
+
if (err.error === 'AuthFactorTokenRequired') {
96
97
setOtp('');
97
98
setIsTotpRequired(true);
98
99
return;
99
100
}
100
101
101
-
if (error.kind === 'AuthenticationRequired') {
102
+
if (err.error === 'AuthenticationRequired') {
102
103
message = `Invalid identifier or password`;
103
-
} else if (error.kind === 'AccountTakedown') {
104
+
} else if (err.error === 'AccountTakedown') {
104
105
message = `Account has been taken down`;
105
-
} else if (error.message.includes('Token is invalid')) {
106
+
} else if (err.message.includes('Token is invalid')) {
106
107
message = `Invalid one-time confirmation code`;
107
108
setIsTotpRequired(true);
108
109
}
109
-
} else if (error instanceof InsufficientLoginError) {
110
-
message = error.message;
110
+
} else if (err instanceof InsufficientLoginError) {
111
+
message = err.message;
111
112
}
112
113
113
114
if (message !== undefined) {
114
115
setError(message);
115
116
} else {
116
-
console.error(error);
117
-
setError(`Something went wrong: ${error}`);
117
+
console.error(err);
118
+
setError(`Something went wrong: ${err}`);
118
119
}
119
120
},
120
121
});
+2
-2
src/globals/rpc.ts
+2
-2
src/globals/rpc.ts
···
1
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
1
+
import { Client, simpleFetchHandler } from '@atcute/client';
2
2
3
3
const APPVIEW_URL = import.meta.env.VITE_APPVIEW_URL;
4
4
5
-
export const appViewRpc = new XRPC({ handler: simpleFetchHandler({ service: APPVIEW_URL }) });
5
+
export const appViewRpc = new Client({ handler: simpleFetchHandler({ service: APPVIEW_URL }) });
+104
-4
src/lib/utils/confirmation-code.ts
+104
-4
src/lib/utils/confirmation-code.ts
···
1
-
import { customAlphabet } from 'nanoid';
1
+
import { sample } from '@mary/array-fns';
2
2
3
-
const generateCode = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', 10);
3
+
const words = [
4
+
'abroad',
5
+
'acorn',
6
+
'anaconda',
7
+
'anchovy',
8
+
'aorta',
9
+
'argue',
10
+
'ashy',
11
+
'astound',
12
+
'attest',
13
+
'babied',
14
+
'bobcat',
15
+
'bondless',
16
+
'bullion',
17
+
'bunny',
18
+
'celtic',
19
+
'chivalry',
20
+
'circling',
21
+
'civic',
22
+
'clobber',
23
+
'conform',
24
+
'cosmic',
25
+
'crier',
26
+
'curtly',
27
+
'depose',
28
+
'diagnosis',
29
+
'disfigure',
30
+
'drank',
31
+
'ducktail',
32
+
'eel',
33
+
'effort',
34
+
'equipment',
35
+
'eternal',
36
+
'exemplify',
37
+
'filtrate',
38
+
'fit',
39
+
'flaccid',
40
+
'fool',
41
+
'germinate',
42
+
'glade',
43
+
'graveness',
44
+
'gray',
45
+
'hydrant',
46
+
'italicize',
47
+
'landowner',
48
+
'lavender',
49
+
'mandatory',
50
+
'molecule',
51
+
'multitude',
52
+
'music',
53
+
'national',
54
+
'neatly',
55
+
'omnivore',
56
+
'other',
57
+
'overdrive',
58
+
'overhang',
59
+
'overlying',
60
+
'padded',
61
+
'pang',
62
+
'paralyses',
63
+
'partner',
64
+
'pedometer',
65
+
'plaything',
66
+
'pointy',
67
+
'prescribe',
68
+
'pueblo',
69
+
'pursuant',
70
+
'reprise',
71
+
'resilient',
72
+
'reusable',
73
+
'roster',
74
+
'scenic',
75
+
'selected',
76
+
'singer',
77
+
'slacker',
78
+
'smirk',
79
+
'smoked',
80
+
'smugly',
81
+
'startle',
82
+
'sternum',
83
+
'strut',
84
+
'subsystem',
85
+
'supper',
86
+
'swifter',
87
+
'tacking',
88
+
'traffic',
89
+
'tragedy',
90
+
'trapper',
91
+
'tummy',
92
+
'twiddle',
93
+
'unglazed',
94
+
'ungloved',
95
+
'unicorn',
96
+
'unissued',
97
+
'unmovable',
98
+
'unwary',
99
+
'uselessly',
100
+
'venus',
101
+
'vertebrae',
102
+
'wildly',
103
+
'wrecker',
104
+
];
4
105
5
106
export const generateConfirmationCode = () => {
6
-
const code = generateCode();
7
-
return `${code.slice(0, 5)}-${code.slice(5, 10)}`;
107
+
return sample(words, 3).join(' ');
8
108
};
+18
-6
src/lib/utils/promise-queue.ts
+18
-6
src/lib/utils/promise-queue.ts
···
1
+
import Queue from '@mary/ds-queue';
2
+
3
+
interface QueueTask {
4
+
deferred: PromiseWithResolvers<any>;
5
+
fn: () => any;
6
+
}
7
+
1
8
export class PromiseQueue {
2
-
#queue: { deferred: PromiseWithResolvers<any>; fn: () => any }[] = [];
9
+
#queue = new Queue<QueueTask>();
3
10
4
11
#max: number;
5
12
#current = 0;
···
11
18
add<T>(fn: () => Promise<T>): Promise<T> {
12
19
const deferred = Promise.withResolvers<T>();
13
20
14
-
this.#queue.push({ deferred, fn });
21
+
this.#queue.enqueue({ deferred, fn });
15
22
this.#run();
16
23
17
24
return deferred.promise;
18
25
}
19
26
20
27
async flush(): Promise<void> {
21
-
while (this.#queue.length > 0) {
22
-
await Promise.all(this.#queue.map((task) => task.deferred.promise));
28
+
while (this.#queue.size > 0) {
29
+
// type assertion here because JSR omits the [Symbol.iterator] method declaration
30
+
await Promise.all(
31
+
Array.from(this.#queue as any as Iterable<QueueTask>, (task) => task.deferred.promise),
32
+
);
23
33
}
24
34
}
25
35
26
36
#run() {
27
-
if (this.#queue.length > 0 && this.#current <= this.#max) {
28
-
const { deferred, fn } = this.#queue.shift()!;
37
+
let task: QueueTask | undefined;
38
+
39
+
if (this.#current < this.#max && (task = this.#queue.dequeue()) !== undefined) {
40
+
const { deferred, fn } = task;
29
41
this.#current++;
30
42
31
43
const promise = new Promise((r) => r(fn()));
+5
-6
src/lib/utils/search-params.ts
+5
-6
src/lib/utils/search-params.ts
···
1
1
import { batch, createSignal } from 'solid-js';
2
2
3
-
import { At } from '@atcute/client/lexicons';
4
-
import { isDid, isHandle } from '@atcute/identity';
3
+
import { isDid, isHandle } from '@atcute/lexicons/syntax';
5
4
6
-
import { UnwrapArray } from '~/api/utils/types';
5
+
import type { UnwrapArray } from '~/api/utils/types';
7
6
8
7
export interface ParamParser<T> {
9
8
parse: (value: string | string[] | null) => T | null;
···
223
222
224
223
export const asDID = createParser({
225
224
parse(value) {
226
-
if (typeof value === 'string' && isDid(value)) {
227
-
return value as At.DID;
225
+
if (isDid(value)) {
226
+
return value;
228
227
}
229
228
230
229
return null;
···
236
235
237
236
export const asHandle = createParser({
238
237
parse(value) {
239
-
if (typeof value === 'string' && isHandle(value)) {
238
+
if (isHandle(value)) {
240
239
return value;
241
240
}
242
241
+17
src/lib/utils/stream.ts
+17
src/lib/utils/stream.ts
···
1
+
export async function* iterateStream<T>(stream: ReadableStream<T>) {
2
+
const reader = stream.getReader();
3
+
4
+
try {
5
+
while (true) {
6
+
const { done, value } = await reader.read();
7
+
8
+
if (done) {
9
+
return;
10
+
}
11
+
12
+
yield value;
13
+
}
14
+
} finally {
15
+
reader.releaseLock();
16
+
}
17
+
}
+3
src/main.tsx
+3
src/main.tsx
···
22
22
if (Symbol.dispose === undefined) {
23
23
Object.defineProperty(Symbol, 'dispose', { value: Symbol.for(`Symbol.dispose`) });
24
24
}
25
+
if (Symbol.asyncDispose === undefined) {
26
+
Object.defineProperty(Symbol, 'asyncDispose', { value: Symbol.for(`Symbol.asyncDispose`) });
27
+
}
25
28
26
29
render(App, document.body);
+9
src/routes.ts
+9
src/routes.ts
···
22
22
path: '/crypto-generate',
23
23
component: lazy(() => import('./views/crypto/crypto-generate')),
24
24
},
25
+
{
26
+
path: '/crypto-info',
27
+
component: lazy(() => import('./views/crypto/crypto-info')),
28
+
},
25
29
26
30
{
27
31
path: '/did-lookup',
···
47
51
{
48
52
path: '/repo-archive-explore',
49
53
component: lazy(() => import('./views/repository/repo-archive-explore/page')),
54
+
},
55
+
56
+
{
57
+
path: '/account-migrate',
58
+
component: lazy(() => import('./views/account/account-migrate/page')),
50
59
},
51
60
52
61
{
+49
src/views/account/account-migrate/context.tsx
+49
src/views/account/account-migrate/context.tsx
···
1
+
import { createContext, createSignal, useContext, type JSX } from 'solid-js';
2
+
3
+
import type { CredentialManager } from '@atcute/client';
4
+
import type { DidDocument } from '@atcute/identity';
5
+
import type { AtprotoDid, Did } from '@atcute/lexicons/syntax';
6
+
7
+
export interface SourceAccount {
8
+
did: AtprotoDid;
9
+
didDoc: DidDocument;
10
+
pdsUrl: string;
11
+
manager: CredentialManager | null;
12
+
}
13
+
14
+
export interface DestinationAccount {
15
+
pdsUrl: string;
16
+
serviceDid: Did;
17
+
manager: CredentialManager | null;
18
+
}
19
+
20
+
export interface MigrationContextValue {
21
+
source: () => SourceAccount | null;
22
+
setSource: (account: SourceAccount | null) => void;
23
+
destination: () => DestinationAccount | null;
24
+
setDestination: (account: DestinationAccount | null) => void;
25
+
}
26
+
27
+
const MigrationContext = createContext<MigrationContextValue>();
28
+
29
+
export const MigrationProvider = (props: { children: JSX.Element }) => {
30
+
const [source, setSource] = createSignal<SourceAccount | null>(null);
31
+
const [destination, setDestination] = createSignal<DestinationAccount | null>(null);
32
+
33
+
const value: MigrationContextValue = {
34
+
source,
35
+
setSource,
36
+
destination,
37
+
setDestination,
38
+
};
39
+
40
+
return <MigrationContext.Provider value={value}>{props.children}</MigrationContext.Provider>;
41
+
};
42
+
43
+
export const useMigration = (): MigrationContextValue => {
44
+
const context = useContext(MigrationContext);
45
+
if (!context) {
46
+
throw new Error('useMigration must be used within a MigrationProvider');
47
+
}
48
+
return context;
49
+
};
+54
src/views/account/account-migrate/page.tsx
+54
src/views/account/account-migrate/page.tsx
···
1
+
import { createEffect, createSignal, onCleanup } from 'solid-js';
2
+
3
+
import { history } from '~/globals/navigation';
4
+
5
+
import { useTitle } from '~/lib/navigation/router';
6
+
7
+
import PageHeader from '~/components/page-header';
8
+
9
+
import { MigrationProvider } from './context';
10
+
11
+
import SourceAccountSection from './sections/source-account';
12
+
import DestinationAccountSection from './sections/destination-account';
13
+
import RepositorySection from './sections/repository';
14
+
import BlobsSection from './sections/blobs';
15
+
import PreferencesSection from './sections/preferences';
16
+
import IdentitySection from './sections/identity';
17
+
import AccountStatusSection from './sections/account-status';
18
+
19
+
const AccountMigratePage = () => {
20
+
const [hasStarted, setHasStarted] = createSignal(false);
21
+
22
+
createEffect(() => {
23
+
if (hasStarted()) {
24
+
const cleanup = history.block((tx) => {
25
+
if (window.confirm(`You have a migration in progress. Leave this page?`)) {
26
+
cleanup();
27
+
tx.retry();
28
+
}
29
+
});
30
+
31
+
onCleanup(cleanup);
32
+
}
33
+
});
34
+
35
+
useTitle(() => `Migrate account โ boat`);
36
+
37
+
return (
38
+
<MigrationProvider>
39
+
<PageHeader title="Migrate account" subtitle="Move your account data to another server" />
40
+
41
+
<div class="flex flex-col">
42
+
<SourceAccountSection onStarted={() => setHasStarted(true)} />
43
+
<DestinationAccountSection />
44
+
<RepositorySection />
45
+
<BlobsSection />
46
+
<PreferencesSection />
47
+
<IdentitySection />
48
+
<AccountStatusSection />
49
+
</div>
50
+
</MigrationProvider>
51
+
);
52
+
};
53
+
54
+
export default AccountMigratePage;
+207
src/views/account/account-migrate/sections/account-status.tsx
+207
src/views/account/account-migrate/sections/account-status.tsx
···
1
+
import { Show } from 'solid-js';
2
+
3
+
import { Client, type CredentialManager, ok } from '@atcute/client';
4
+
5
+
import { createMutation } from '~/lib/utils/mutation';
6
+
7
+
import { Accordion, StatusBadge, Subsection } from '~/components/accordion';
8
+
import Button from '~/components/inputs/button';
9
+
10
+
import { useMigration } from '../context';
11
+
12
+
interface AccountStatus {
13
+
activated: boolean;
14
+
validDid: boolean;
15
+
repoCommit: string;
16
+
repoRev: string;
17
+
repoBlocks: number;
18
+
indexedRecords: number;
19
+
privateStateValues: number;
20
+
expectedBlobs: number;
21
+
importedBlobs: number;
22
+
}
23
+
24
+
const AccountStatusSection = () => {
25
+
const { source, destination } = useMigration();
26
+
27
+
const checkSourceMutation = createMutation({
28
+
async mutationFn({ manager }: { manager: CredentialManager }) {
29
+
const sourceClient = new Client({ handler: manager });
30
+
return await ok(sourceClient.get('com.atproto.server.checkAccountStatus')) as AccountStatus;
31
+
},
32
+
onError(err) {
33
+
console.error(err);
34
+
},
35
+
});
36
+
37
+
const checkDestMutation = createMutation({
38
+
async mutationFn({ manager }: { manager: CredentialManager }) {
39
+
const destClient = new Client({ handler: manager });
40
+
return await ok(destClient.get('com.atproto.server.checkAccountStatus')) as AccountStatus;
41
+
},
42
+
onError(err) {
43
+
console.error(err);
44
+
},
45
+
});
46
+
47
+
const activateMutation = createMutation({
48
+
async mutationFn({ manager }: { manager: CredentialManager }) {
49
+
const destClient = new Client({ handler: manager });
50
+
await ok(destClient.post('com.atproto.server.activateAccount', { as: null }));
51
+
},
52
+
onSuccess() {
53
+
const dest = destination();
54
+
if (dest?.manager) {
55
+
checkDestMutation.mutate({ manager: dest.manager });
56
+
}
57
+
},
58
+
onError(err) {
59
+
console.error(err);
60
+
},
61
+
});
62
+
63
+
const deactivateMutation = createMutation({
64
+
async mutationFn({ manager }: { manager: CredentialManager }) {
65
+
if (!confirm('Are you sure you want to deactivate your source account? This will prevent the old PDS from serving your data.')) {
66
+
throw new Error('Cancelled');
67
+
}
68
+
const sourceClient = new Client({ handler: manager });
69
+
await ok(sourceClient.post('com.atproto.server.deactivateAccount', { as: null, input: {} }));
70
+
},
71
+
onSuccess() {
72
+
const src = source();
73
+
if (src?.manager) {
74
+
checkSourceMutation.mutate({ manager: src.manager });
75
+
}
76
+
},
77
+
onError(err) {
78
+
if (err instanceof Error && err.message === 'Cancelled') return;
79
+
console.error(err);
80
+
},
81
+
});
82
+
83
+
const renderStatus = (status: AccountStatus) => (
84
+
<div class="space-y-1 text-sm">
85
+
<p>
86
+
<span class="text-gray-500">Status:</span>{' '}
87
+
<StatusBadge variant={status.activated ? 'success' : 'idle'}>
88
+
{status.activated ? 'Active' : 'Deactivated'}
89
+
</StatusBadge>
90
+
</p>
91
+
<p>
92
+
<span class="text-gray-500">Records:</span>{' '}
93
+
<span class="font-mono">{status.indexedRecords}</span>
94
+
</p>
95
+
<p>
96
+
<span class="text-gray-500">Blobs:</span>{' '}
97
+
<span class="font-mono">{status.importedBlobs}/{status.expectedBlobs}</span>
98
+
</p>
99
+
<p>
100
+
<span class="text-gray-500">Repo blocks:</span>{' '}
101
+
<span class="font-mono">{status.repoBlocks}</span>
102
+
</p>
103
+
</div>
104
+
);
105
+
106
+
return (
107
+
<Accordion title="Account Status">
108
+
<Subsection title="Source account">
109
+
<Show
110
+
when={source()?.manager}
111
+
fallback={<p class="text-sm text-gray-500">Sign in to source account first.</p>}
112
+
>
113
+
{(manager) => (
114
+
<>
115
+
<div class="flex items-center gap-3">
116
+
<Button
117
+
variant="outline"
118
+
onClick={() => checkSourceMutation.mutate({ manager: manager() })}
119
+
disabled={checkSourceMutation.isPending}
120
+
>
121
+
{checkSourceMutation.isPending ? 'Checking...' : 'Check status'}
122
+
</Button>
123
+
</div>
124
+
125
+
<Show when={checkSourceMutation.isError}>
126
+
<p class="text-sm text-red-600">{`${checkSourceMutation.error}`}</p>
127
+
</Show>
128
+
129
+
<Show when={checkSourceMutation.data}>
130
+
{(status) => (
131
+
<>
132
+
{renderStatus(status())}
133
+
134
+
<Show when={status().activated}>
135
+
<div class="mt-3">
136
+
<Button
137
+
variant="secondary"
138
+
onClick={() => deactivateMutation.mutate({ manager: manager() })}
139
+
disabled={deactivateMutation.isPending}
140
+
>
141
+
{deactivateMutation.isPending ? 'Deactivating...' : 'Deactivate source account'}
142
+
</Button>
143
+
</div>
144
+
</Show>
145
+
</>
146
+
)}
147
+
</Show>
148
+
</>
149
+
)}
150
+
</Show>
151
+
</Subsection>
152
+
153
+
<Subsection title="Destination account">
154
+
<Show
155
+
when={destination()?.manager}
156
+
fallback={<p class="text-sm text-gray-500">Sign in to destination account first.</p>}
157
+
>
158
+
{(manager) => (
159
+
<>
160
+
<div class="flex items-center gap-3">
161
+
<Button
162
+
variant="outline"
163
+
onClick={() => checkDestMutation.mutate({ manager: manager() })}
164
+
disabled={checkDestMutation.isPending}
165
+
>
166
+
{checkDestMutation.isPending ? 'Checking...' : 'Check status'}
167
+
</Button>
168
+
</div>
169
+
170
+
<Show when={checkDestMutation.isError}>
171
+
<p class="text-sm text-red-600">{`${checkDestMutation.error}`}</p>
172
+
</Show>
173
+
174
+
<Show when={checkDestMutation.data}>
175
+
{(status) => (
176
+
<>
177
+
{renderStatus(status())}
178
+
179
+
<Show when={!status().activated}>
180
+
<div class="mt-3">
181
+
<Button
182
+
onClick={() => activateMutation.mutate({ manager: manager() })}
183
+
disabled={activateMutation.isPending}
184
+
>
185
+
{activateMutation.isPending ? 'Activating...' : 'Activate destination account'}
186
+
</Button>
187
+
</div>
188
+
</Show>
189
+
</>
190
+
)}
191
+
</Show>
192
+
</>
193
+
)}
194
+
</Show>
195
+
</Subsection>
196
+
197
+
<Show when={activateMutation.isError || deactivateMutation.isError}>
198
+
<p class="text-sm text-red-600">
199
+
{activateMutation.isError ? `Failed to activate: ${activateMutation.error}` : ''}
200
+
{deactivateMutation.isError ? `Failed to deactivate: ${deactivateMutation.error}` : ''}
201
+
</p>
202
+
</Show>
203
+
</Accordion>
204
+
);
205
+
};
206
+
207
+
export default AccountStatusSection;
+455
src/views/account/account-migrate/sections/blobs.tsx
+455
src/views/account/account-migrate/sections/blobs.tsx
···
1
+
import { showOpenFilePicker, showSaveFilePicker } from 'native-file-system-adapter';
2
+
import { createSignal, For, Show } from 'solid-js';
3
+
4
+
import { Client, ClientResponseError, type CredentialManager, ok, simpleFetchHandler } from '@atcute/client';
5
+
import { untar, writeTarEntry } from '@mary/tar';
6
+
7
+
import { createMutation } from '~/lib/utils/mutation';
8
+
9
+
import { Accordion, StatusBadge, Subsection } from '~/components/accordion';
10
+
import Button from '~/components/inputs/button';
11
+
12
+
import { useMigration, type SourceAccount } from '../context';
13
+
14
+
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
15
+
16
+
const BlobsSection = () => {
17
+
const { source, destination } = useMigration();
18
+
19
+
// Progress state (kept separate since mutations don't handle incremental updates)
20
+
const [exportProgress, setExportProgress] = createSignal<string>();
21
+
const [importProgress, setImportProgress] = createSignal<string>();
22
+
23
+
const exportMutation = createMutation({
24
+
async mutationFn({ source }: { source: SourceAccount }) {
25
+
const sourceClient = new Client({ handler: simpleFetchHandler({ service: source.pdsUrl }) });
26
+
27
+
setExportProgress('Retrieving list of blobs...');
28
+
29
+
// Get list of all blobs
30
+
let blobs: string[] = [];
31
+
let cursor: string | undefined;
32
+
do {
33
+
const data = await ok(
34
+
sourceClient.get('com.atproto.sync.listBlobs', {
35
+
params: { did: source.did, cursor, limit: 1_000 },
36
+
}),
37
+
);
38
+
cursor = data.cursor;
39
+
blobs = blobs.concat(data.cids);
40
+
setExportProgress(`Retrieving list of blobs (found ${blobs.length})`);
41
+
} while (cursor !== undefined);
42
+
43
+
if (blobs.length === 0) {
44
+
return { count: 0, cancelled: false };
45
+
}
46
+
47
+
setExportProgress('Waiting for file picker...');
48
+
49
+
const fd = await showSaveFilePicker({
50
+
suggestedName: `blobs-${source.did}-${new Date().toISOString()}.tar`,
51
+
// @ts-expect-error: ponyfill doesn't have the full typings
52
+
id: 'blob-export',
53
+
startIn: 'downloads',
54
+
types: [
55
+
{
56
+
description: 'Tarball archive',
57
+
accept: { 'application/tar': ['.tar'] },
58
+
},
59
+
],
60
+
}).catch((err) => {
61
+
if (err instanceof DOMException && err.name === 'AbortError') {
62
+
return undefined;
63
+
}
64
+
throw err;
65
+
});
66
+
67
+
if (!fd) {
68
+
return { count: 0, cancelled: true };
69
+
}
70
+
71
+
const writable = await fd.createWritable();
72
+
73
+
let downloaded = 0;
74
+
for (const cid of blobs) {
75
+
setExportProgress(`Downloading blobs (${downloaded}/${blobs.length})`);
76
+
77
+
const downloadBlob = async (): Promise<Uint8Array | undefined> => {
78
+
let attempts = 0;
79
+
while (true) {
80
+
if (attempts > 0) await sleep(2_000);
81
+
attempts++;
82
+
83
+
try {
84
+
const response = await sourceClient.get('com.atproto.sync.getBlob', {
85
+
as: 'bytes',
86
+
params: { did: source.did, cid },
87
+
});
88
+
89
+
if (response.ok) {
90
+
return response.data;
91
+
}
92
+
93
+
if (response.status === 400 && response.data.message === 'Blob not found') {
94
+
return undefined;
95
+
}
96
+
97
+
if (response.status === 429) {
98
+
await sleep(10_000);
99
+
}
100
+
101
+
if (attempts < 3) continue;
102
+
throw new ClientResponseError(response);
103
+
} catch (err) {
104
+
if (attempts < 3) continue;
105
+
throw err;
106
+
}
107
+
}
108
+
};
109
+
110
+
const data = await downloadBlob();
111
+
if (data !== undefined) {
112
+
const entry = writeTarEntry({ filename: `blobs/${cid}`, data });
113
+
await writable.write(entry);
114
+
}
115
+
116
+
downloaded++;
117
+
}
118
+
119
+
await writable.close();
120
+
return { count: blobs.length, cancelled: false };
121
+
},
122
+
onError(err) {
123
+
console.error(err);
124
+
},
125
+
onSettled() {
126
+
setExportProgress();
127
+
},
128
+
});
129
+
130
+
const importFromFileMutation = createMutation({
131
+
async mutationFn({ destManager }: { destManager: CredentialManager }) {
132
+
setImportProgress('Waiting for file picker...');
133
+
134
+
const [fd] = await showOpenFilePicker({
135
+
// @ts-expect-error: ponyfill doesn't have the full typings
136
+
id: 'blob-import',
137
+
types: [
138
+
{
139
+
description: 'Tarball archive',
140
+
accept: { 'application/tar': ['.tar'] },
141
+
},
142
+
],
143
+
}).catch((err) => {
144
+
if (err instanceof DOMException && err.name === 'AbortError') {
145
+
return [undefined];
146
+
}
147
+
throw err;
148
+
});
149
+
150
+
if (!fd) {
151
+
return { uploaded: 0, failed: 0, cancelled: true };
152
+
}
153
+
154
+
setImportProgress('Reading archive...');
155
+
const file = await fd.getFile();
156
+
157
+
const destClient = new Client({ handler: destManager });
158
+
159
+
let uploaded = 0;
160
+
let failed = 0;
161
+
162
+
for await (const entry of untar(file.stream())) {
163
+
if (entry.type !== 'file') continue;
164
+
165
+
const filename = entry.name;
166
+
// Extract CID from path like "blobs/bafk..."
167
+
const cid = filename.split('/').pop();
168
+
if (!cid) continue;
169
+
170
+
setImportProgress(`Uploading blobs (${uploaded} uploaded, ${failed} failed)`);
171
+
172
+
try {
173
+
const data = await entry.bytes();
174
+
await destClient.post('com.atproto.repo.uploadBlob', {
175
+
input: data,
176
+
headers: {
177
+
'content-type': 'application/octet-stream',
178
+
},
179
+
});
180
+
uploaded++;
181
+
} catch (err) {
182
+
console.error(`Failed to upload blob ${cid}:`, err);
183
+
failed++;
184
+
}
185
+
}
186
+
187
+
return { uploaded, failed, cancelled: false };
188
+
},
189
+
onError(err) {
190
+
console.error(err);
191
+
},
192
+
onSettled() {
193
+
setImportProgress();
194
+
},
195
+
});
196
+
197
+
const importFromSourceMutation = createMutation({
198
+
async mutationFn({ source, destManager }: { source: SourceAccount; destManager: CredentialManager }) {
199
+
setImportProgress('Checking for missing blobs...');
200
+
201
+
const sourceClient = new Client({ handler: simpleFetchHandler({ service: source.pdsUrl }) });
202
+
const destClient = new Client({ handler: destManager });
203
+
204
+
let uploaded = 0;
205
+
let failed = 0;
206
+
let cursor: string | undefined;
207
+
208
+
do {
209
+
const data = await ok(
210
+
destClient.get('com.atproto.repo.listMissingBlobs', {
211
+
params: { cursor, limit: 100 },
212
+
}),
213
+
);
214
+
cursor = data.cursor;
215
+
216
+
for (const blob of data.blobs) {
217
+
setImportProgress(`Uploading missing blobs (${uploaded} uploaded, ${failed} failed)`);
218
+
219
+
try {
220
+
const response = await sourceClient.get('com.atproto.sync.getBlob', {
221
+
as: 'stream',
222
+
params: { did: source.did, cid: blob.cid },
223
+
});
224
+
225
+
if (!response.ok) {
226
+
failed++;
227
+
continue;
228
+
}
229
+
230
+
const contentType = response.headers.get('content-type') || 'application/octet-stream';
231
+
232
+
await destClient.post('com.atproto.repo.uploadBlob', {
233
+
input: response.data,
234
+
headers: {
235
+
'content-type': contentType,
236
+
},
237
+
});
238
+
239
+
uploaded++;
240
+
} catch (err) {
241
+
console.error(`Failed to transfer blob ${blob.cid}:`, err);
242
+
failed++;
243
+
}
244
+
}
245
+
} while (cursor !== undefined);
246
+
247
+
return { uploaded, failed };
248
+
},
249
+
onError(err) {
250
+
console.error(err);
251
+
},
252
+
onSettled() {
253
+
setImportProgress();
254
+
},
255
+
});
256
+
257
+
const checkStatusMutation = createMutation({
258
+
async mutationFn({ destManager }: { destManager: CredentialManager }) {
259
+
const destClient = new Client({ handler: destManager });
260
+
const status = await ok(destClient.get('com.atproto.server.checkAccountStatus'));
261
+
262
+
let missingBlobs: string[] = [];
263
+
264
+
// Get list of missing blobs if any
265
+
if (status.expectedBlobs > status.importedBlobs) {
266
+
let cursor: string | undefined;
267
+
do {
268
+
const data = await ok(
269
+
destClient.get('com.atproto.repo.listMissingBlobs', {
270
+
params: { cursor, limit: 100 },
271
+
}),
272
+
);
273
+
cursor = data.cursor;
274
+
missingBlobs.push(...data.blobs.map((b) => b.cid));
275
+
} while (cursor !== undefined);
276
+
}
277
+
278
+
return {
279
+
expected: status.expectedBlobs,
280
+
imported: status.importedBlobs,
281
+
missingBlobs,
282
+
};
283
+
},
284
+
onError(err) {
285
+
console.error(err);
286
+
},
287
+
});
288
+
289
+
const isImporting = () => importFromFileMutation.isPending || importFromSourceMutation.isPending;
290
+
291
+
const getExportStatusText = () => {
292
+
const data = exportMutation.data;
293
+
if (data?.cancelled) return undefined;
294
+
if (data?.count === 0) return 'No blobs to export';
295
+
if (data) return `Exported ${data.count} blobs`;
296
+
return exportProgress();
297
+
};
298
+
299
+
const getImportStatusText = () => {
300
+
const fileData = importFromFileMutation.data;
301
+
const sourceData = importFromSourceMutation.data;
302
+
303
+
if (fileData && !fileData.cancelled) {
304
+
return (
305
+
`Uploaded ${fileData.uploaded} blobs` + (fileData.failed > 0 ? ` (${fileData.failed} failed)` : '')
306
+
);
307
+
}
308
+
if (sourceData) {
309
+
if (sourceData.uploaded === 0 && sourceData.failed === 0) return 'No missing blobs';
310
+
return (
311
+
`Uploaded ${sourceData.uploaded} blobs` +
312
+
(sourceData.failed > 0 ? ` (${sourceData.failed} failed)` : '')
313
+
);
314
+
}
315
+
return importProgress();
316
+
};
317
+
318
+
const getImportError = () => importFromFileMutation.error || importFromSourceMutation.error;
319
+
320
+
return (
321
+
<Accordion title="Blobs">
322
+
<Subsection title="Export from source">
323
+
<p class="text-sm text-gray-600">Download all blobs as a tarball for backup or manual import.</p>
324
+
325
+
<Show when={source()} fallback={<p class="text-sm text-gray-500">Resolve source account first.</p>}>
326
+
{(src) => (
327
+
<>
328
+
<div class="flex items-center gap-3">
329
+
<Button
330
+
onClick={() => exportMutation.mutate({ source: src() })}
331
+
disabled={exportMutation.isPending}
332
+
>
333
+
{exportMutation.isPending ? 'Exporting...' : 'Export to file'}
334
+
</Button>
335
+
<Show when={getExportStatusText()}>
336
+
{(text) => <span class="text-sm text-gray-600">{text()}</span>}
337
+
</Show>
338
+
</div>
339
+
340
+
<Show when={exportMutation.error}>
341
+
{(err) => <p class="text-sm text-red-600">{`${err()}`}</p>}
342
+
</Show>
343
+
</>
344
+
)}
345
+
</Show>
346
+
</Subsection>
347
+
348
+
<Subsection title="Import to destination">
349
+
<p class="text-sm text-gray-600">Upload blobs from a tarball or transfer directly from source.</p>
350
+
351
+
<Show
352
+
when={destination()?.manager}
353
+
fallback={<p class="text-sm text-gray-500">Sign in to destination account first.</p>}
354
+
>
355
+
{(destManager) => (
356
+
<>
357
+
<div class="flex flex-wrap items-center gap-3">
358
+
<Button
359
+
onClick={() => importFromFileMutation.mutate({ destManager: destManager() })}
360
+
disabled={isImporting()}
361
+
>
362
+
{isImporting() ? 'Importing...' : 'Import from file'}
363
+
</Button>
364
+
365
+
<Show when={source()}>
366
+
{(src) => (
367
+
<Button
368
+
variant="secondary"
369
+
onClick={() =>
370
+
importFromSourceMutation.mutate({ source: src(), destManager: destManager() })
371
+
}
372
+
disabled={isImporting()}
373
+
>
374
+
Transfer from source
375
+
</Button>
376
+
)}
377
+
</Show>
378
+
</div>
379
+
380
+
<Show when={getImportStatusText()}>
381
+
{(text) => <span class="text-sm text-gray-600">{text()}</span>}
382
+
</Show>
383
+
384
+
<Show when={getImportError()}>{(err) => <p class="text-sm text-red-600">{`${err()}`}</p>}</Show>
385
+
</>
386
+
)}
387
+
</Show>
388
+
</Subsection>
389
+
390
+
<Subsection title="Status">
391
+
<Show
392
+
when={destination()?.manager}
393
+
fallback={<p class="text-sm text-gray-500">Sign in to destination account first.</p>}
394
+
>
395
+
{(destManager) => (
396
+
<>
397
+
<div class="flex items-center gap-3">
398
+
<Button
399
+
variant="outline"
400
+
onClick={() => checkStatusMutation.mutate({ destManager: destManager() })}
401
+
disabled={checkStatusMutation.isPending}
402
+
>
403
+
{checkStatusMutation.isPending ? 'Checking...' : 'Check status'}
404
+
</Button>
405
+
406
+
<Show when={checkStatusMutation.data}>
407
+
{(status) => (
408
+
<span class="text-sm">
409
+
<StatusBadge variant={status().imported === status().expected ? 'success' : 'pending'}>
410
+
{status().imported}/{status().expected} blobs
411
+
</StatusBadge>
412
+
</span>
413
+
)}
414
+
</Show>
415
+
</div>
416
+
417
+
<Show when={checkStatusMutation.data?.missingBlobs.length}>
418
+
{(count) => (
419
+
<div class="mt-2 rounded border border-yellow-300 bg-yellow-50 p-3">
420
+
<p class="mb-2 text-sm font-medium text-yellow-800">{count()} missing blobs</p>
421
+
422
+
<Show when={source()}>
423
+
{(src) => (
424
+
<Button
425
+
variant="secondary"
426
+
onClick={() =>
427
+
importFromSourceMutation.mutate({ source: src(), destManager: destManager() })
428
+
}
429
+
disabled={isImporting()}
430
+
>
431
+
Transfer missing from source
432
+
</Button>
433
+
)}
434
+
</Show>
435
+
436
+
<details class="mt-2">
437
+
<summary class="cursor-pointer text-sm text-yellow-700">Show CIDs</summary>
438
+
<div class="mt-1 max-h-32 overflow-auto font-mono text-xs">
439
+
<For each={checkStatusMutation.data?.missingBlobs}>
440
+
{(cid) => <div class="truncate">{cid}</div>}
441
+
</For>
442
+
</div>
443
+
</details>
444
+
</div>
445
+
)}
446
+
</Show>
447
+
</>
448
+
)}
449
+
</Show>
450
+
</Subsection>
451
+
</Accordion>
452
+
);
453
+
};
454
+
455
+
export default BlobsSection;
+437
src/views/account/account-migrate/sections/destination-account.tsx
+437
src/views/account/account-migrate/sections/destination-account.tsx
···
1
+
import { createSignal, Show } from 'solid-js';
2
+
3
+
import {
4
+
type AtpAccessJwt,
5
+
Client,
6
+
ClientResponseError,
7
+
CredentialManager,
8
+
ok,
9
+
simpleFetchHandler,
10
+
} from '@atcute/client';
11
+
import type { Did, Handle } from '@atcute/lexicons/syntax';
12
+
13
+
import { formatTotpCode, TOTP_RE } from '~/api/utils/auth';
14
+
import { decodeJwt } from '~/api/utils/jwt';
15
+
import { isServiceUrlString } from '~/api/types/strings';
16
+
17
+
import { createMutation } from '~/lib/utils/mutation';
18
+
19
+
import { Accordion, StatusBadge, Subsection } from '~/components/accordion';
20
+
import Button from '~/components/inputs/button';
21
+
import TextInput from '~/components/inputs/text-input';
22
+
23
+
import { useMigration } from '../context';
24
+
25
+
class InsufficientLoginError extends Error {}
26
+
27
+
const DestinationAccountSection = () => {
28
+
const { source, destination, setDestination } = useMigration();
29
+
30
+
// Connect state
31
+
const [pdsUrl, setPdsUrl] = createSignal('');
32
+
const [connectError, setConnectError] = createSignal<string>();
33
+
34
+
// Create account state
35
+
const [newHandle, setNewHandle] = createSignal('');
36
+
const [newEmail, setNewEmail] = createSignal('');
37
+
const [newPassword, setNewPassword] = createSignal('');
38
+
const [inviteCode, setInviteCode] = createSignal('');
39
+
const [createError, setCreateError] = createSignal<string>();
40
+
41
+
// Login state
42
+
const [loginPassword, setLoginPassword] = createSignal('');
43
+
const [loginOtp, setLoginOtp] = createSignal('');
44
+
const [isLoginTotpRequired, setIsLoginTotpRequired] = createSignal(false);
45
+
const [loginError, setLoginError] = createSignal<string>();
46
+
47
+
const connectMutation = createMutation({
48
+
async mutationFn({ pdsUrl }: { pdsUrl: string }) {
49
+
const destClient = new Client({ handler: simpleFetchHandler({ service: pdsUrl }) });
50
+
const desc = await ok(destClient.get('com.atproto.server.describeServer'));
51
+
52
+
return { serviceDid: desc.did };
53
+
},
54
+
onMutate() {
55
+
setConnectError();
56
+
},
57
+
onSuccess({ serviceDid }) {
58
+
setDestination({ pdsUrl: pdsUrl(), serviceDid, manager: null });
59
+
},
60
+
onError(err) {
61
+
console.error(err);
62
+
setConnectError(`Failed to connect: ${err}`);
63
+
},
64
+
});
65
+
66
+
const createAccountMutation = createMutation({
67
+
async mutationFn({
68
+
sourceDid,
69
+
sourceManager,
70
+
destPdsUrl,
71
+
destServiceDid,
72
+
handle,
73
+
email,
74
+
password,
75
+
inviteCode,
76
+
}: {
77
+
sourceDid: Did;
78
+
sourceManager: CredentialManager;
79
+
destPdsUrl: string;
80
+
destServiceDid: string;
81
+
handle: Handle;
82
+
email: string;
83
+
password: string;
84
+
inviteCode: string;
85
+
}) {
86
+
// Get service auth token from old PDS
87
+
const sourceClient = new Client({ handler: sourceManager });
88
+
const authResp = await ok(
89
+
sourceClient.get('com.atproto.server.getServiceAuth', {
90
+
params: {
91
+
aud: destServiceDid as Did,
92
+
lxm: 'com.atproto.server.createAccount',
93
+
},
94
+
}),
95
+
);
96
+
const serviceJwt = authResp.token;
97
+
98
+
// Create account on new PDS with service auth
99
+
const destClient = new Client({ handler: simpleFetchHandler({ service: destPdsUrl }) });
100
+
const createResp = await destClient.post('com.atproto.server.createAccount', {
101
+
headers: { Authorization: `Bearer ${serviceJwt}` },
102
+
input: {
103
+
did: sourceDid,
104
+
handle: handle,
105
+
email: email,
106
+
password: password,
107
+
inviteCode: inviteCode || undefined,
108
+
},
109
+
});
110
+
111
+
if (!createResp.ok) {
112
+
throw new ClientResponseError(createResp);
113
+
}
114
+
115
+
if (createResp.data.did !== sourceDid) {
116
+
throw new Error(`Created account has different DID: ${createResp.data.did}`);
117
+
}
118
+
119
+
// Login to the new account
120
+
const manager = new CredentialManager({ service: destPdsUrl });
121
+
await manager.login({
122
+
identifier: sourceDid,
123
+
password: password,
124
+
});
125
+
126
+
return manager;
127
+
},
128
+
onMutate() {
129
+
setCreateError();
130
+
},
131
+
onSuccess(manager) {
132
+
setDestination({ ...destination()!, manager });
133
+
setNewPassword('');
134
+
},
135
+
onError(err) {
136
+
if (err instanceof ClientResponseError) {
137
+
if (err.error === 'InvalidInviteCode') {
138
+
setCreateError(`Invalid invite code`);
139
+
return;
140
+
}
141
+
if (err.error === 'HandleNotAvailable') {
142
+
setCreateError(`Handle is not available`);
143
+
return;
144
+
}
145
+
if (err.description) {
146
+
setCreateError(err.description);
147
+
return;
148
+
}
149
+
}
150
+
console.error(err);
151
+
setCreateError(`${err}`);
152
+
},
153
+
});
154
+
155
+
const loginMutation = createMutation({
156
+
async mutationFn({
157
+
pdsUrl,
158
+
did,
159
+
password,
160
+
otp,
161
+
}: {
162
+
pdsUrl: string;
163
+
did: string;
164
+
password: string;
165
+
otp: string;
166
+
}) {
167
+
const manager = new CredentialManager({ service: pdsUrl });
168
+
const session = await manager.login({
169
+
identifier: did,
170
+
password: password,
171
+
code: formatTotpCode(otp),
172
+
});
173
+
174
+
const decoded = decodeJwt(session.accessJwt) as AtpAccessJwt;
175
+
if (decoded.scope !== 'com.atproto.access') {
176
+
throw new InsufficientLoginError(`You need to sign in with a main password, not an app password`);
177
+
}
178
+
179
+
return manager;
180
+
},
181
+
onMutate() {
182
+
setLoginError();
183
+
},
184
+
onSuccess(manager) {
185
+
setDestination({ ...destination()!, manager });
186
+
setLoginPassword('');
187
+
setLoginOtp('');
188
+
setIsLoginTotpRequired(false);
189
+
},
190
+
onError(err) {
191
+
if (err instanceof ClientResponseError) {
192
+
if (err.error === 'AuthFactorTokenRequired') {
193
+
setLoginOtp('');
194
+
setIsLoginTotpRequired(true);
195
+
return;
196
+
}
197
+
if (err.error === 'AuthenticationRequired') {
198
+
setLoginError(`Invalid identifier or password`);
199
+
return;
200
+
}
201
+
if (err.description?.includes('Token is invalid')) {
202
+
setLoginError(`Invalid one-time confirmation code`);
203
+
setIsLoginTotpRequired(true);
204
+
return;
205
+
}
206
+
}
207
+
if (err instanceof InsufficientLoginError) {
208
+
setLoginError(err.message);
209
+
return;
210
+
}
211
+
console.error(err);
212
+
setLoginError(`${err}`);
213
+
},
214
+
});
215
+
216
+
const isConnected = () => destination() !== null;
217
+
const isAuthenticated = () => destination()?.manager != null;
218
+
const canCreateAccount = () => source()?.manager != null;
219
+
220
+
return (
221
+
<Accordion title="Destination Account">
222
+
<Subsection title="Connect to PDS">
223
+
<Show when={!isConnected()}>
224
+
<form
225
+
onSubmit={(ev) => {
226
+
ev.preventDefault();
227
+
connectMutation.mutate({ pdsUrl: pdsUrl() });
228
+
}}
229
+
class="flex flex-col gap-3"
230
+
>
231
+
<TextInput
232
+
label="PDS URL"
233
+
type="url"
234
+
placeholder="https://pds.example.com"
235
+
value={pdsUrl()}
236
+
required
237
+
onChange={(text, event) => {
238
+
setPdsUrl(text);
239
+
const input = event.currentTarget;
240
+
if (text !== '' && !isServiceUrlString(text)) {
241
+
input.setCustomValidity('Must be a valid URL');
242
+
} else {
243
+
input.setCustomValidity('');
244
+
}
245
+
}}
246
+
/>
247
+
248
+
<Show when={connectError()}>
249
+
<p class="text-sm text-red-600">{connectError()}</p>
250
+
</Show>
251
+
252
+
<div>
253
+
<Button type="submit" disabled={connectMutation.isPending}>
254
+
{connectMutation.isPending ? 'Connecting...' : 'Connect'}
255
+
</Button>
256
+
</div>
257
+
</form>
258
+
</Show>
259
+
260
+
<Show when={isConnected()}>
261
+
<div class="flex flex-col gap-2 text-sm">
262
+
<p>
263
+
<span class="text-gray-500">URL:</span>{' '}
264
+
<span class="font-mono">{destination()!.pdsUrl}</span>
265
+
</p>
266
+
<p>
267
+
<span class="text-gray-500">Service DID:</span>{' '}
268
+
<span class="font-mono">{destination()!.serviceDid}</span>
269
+
</p>
270
+
<div class="mt-1">
271
+
<button
272
+
type="button"
273
+
onClick={() => setDestination(null)}
274
+
class="text-sm text-purple-800 hover:underline"
275
+
>
276
+
Change PDS
277
+
</button>
278
+
</div>
279
+
</div>
280
+
</Show>
281
+
</Subsection>
282
+
283
+
<Show when={isConnected() && !isAuthenticated()}>
284
+
<Subsection title="Create new account">
285
+
<Show when={!canCreateAccount()}>
286
+
<p class="text-sm text-gray-600">
287
+
You need to authenticate to your source account first to create an account on the
288
+
destination PDS.
289
+
</p>
290
+
</Show>
291
+
292
+
<Show when={canCreateAccount()}>
293
+
<form
294
+
onSubmit={(ev) => {
295
+
ev.preventDefault();
296
+
const src = source()!;
297
+
const dest = destination()!;
298
+
createAccountMutation.mutate({
299
+
sourceDid: src.did,
300
+
sourceManager: src.manager!,
301
+
destPdsUrl: dest.pdsUrl,
302
+
destServiceDid: dest.serviceDid,
303
+
handle: newHandle() as Handle,
304
+
email: newEmail(),
305
+
password: newPassword(),
306
+
inviteCode: inviteCode(),
307
+
});
308
+
}}
309
+
class="flex flex-col gap-3"
310
+
>
311
+
<TextInput
312
+
label="Handle"
313
+
placeholder="alice.pds.example.com"
314
+
value={newHandle()}
315
+
required
316
+
onChange={setNewHandle}
317
+
/>
318
+
319
+
<TextInput
320
+
label="Email"
321
+
type="email"
322
+
placeholder="alice@example.com"
323
+
value={newEmail()}
324
+
required
325
+
onChange={setNewEmail}
326
+
/>
327
+
328
+
<TextInput
329
+
label="Password"
330
+
type="password"
331
+
value={newPassword()}
332
+
required
333
+
onChange={setNewPassword}
334
+
/>
335
+
336
+
<TextInput
337
+
label="Invite code (if required)"
338
+
placeholder="pds-example-com-xxxxx"
339
+
value={inviteCode()}
340
+
onChange={setInviteCode}
341
+
/>
342
+
343
+
<Show when={createError()}>
344
+
<p class="text-sm text-red-600">{createError()}</p>
345
+
</Show>
346
+
347
+
<div>
348
+
<Button type="submit" disabled={createAccountMutation.isPending}>
349
+
{createAccountMutation.isPending ? 'Creating...' : 'Create account'}
350
+
</Button>
351
+
</div>
352
+
</form>
353
+
</Show>
354
+
</Subsection>
355
+
356
+
<Subsection title="Or login to existing account">
357
+
<p class="mb-2 text-sm text-gray-600">
358
+
If you already have a deactivated account on the destination PDS.
359
+
</p>
360
+
361
+
<Show when={!source()}>
362
+
<p class="text-sm text-gray-600">
363
+
Resolve your source account first so we know which DID to use.
364
+
</p>
365
+
</Show>
366
+
367
+
<Show when={source()}>
368
+
<form
369
+
onSubmit={(ev) => {
370
+
ev.preventDefault();
371
+
const src = source()!;
372
+
const dest = destination()!;
373
+
loginMutation.mutate({
374
+
pdsUrl: dest.pdsUrl,
375
+
did: src.did,
376
+
password: loginPassword(),
377
+
otp: loginOtp(),
378
+
});
379
+
}}
380
+
class="flex flex-col gap-3"
381
+
>
382
+
<TextInput
383
+
label="Password"
384
+
type="password"
385
+
value={loginPassword()}
386
+
required
387
+
onChange={setLoginPassword}
388
+
/>
389
+
390
+
<Show when={isLoginTotpRequired()}>
391
+
<TextInput
392
+
label="One-time confirmation code"
393
+
blurb="A code has been sent to your email address."
394
+
type="text"
395
+
autocomplete="one-time-code"
396
+
pattern={TOTP_RE.source}
397
+
placeholder="AAAAA-BBBBB"
398
+
value={loginOtp()}
399
+
required
400
+
onChange={setLoginOtp}
401
+
monospace
402
+
/>
403
+
</Show>
404
+
405
+
<Show when={loginError()}>
406
+
<p class="text-sm text-red-600">{loginError()}</p>
407
+
</Show>
408
+
409
+
<div>
410
+
<Button type="submit" disabled={loginMutation.isPending}>
411
+
{loginMutation.isPending ? 'Signing in...' : 'Sign in'}
412
+
</Button>
413
+
</div>
414
+
</form>
415
+
</Show>
416
+
</Subsection>
417
+
</Show>
418
+
419
+
<Show when={isAuthenticated()}>
420
+
<Subsection title="Account status">
421
+
<div class="flex items-center gap-2">
422
+
<StatusBadge variant="success">Signed in</StatusBadge>
423
+
<button
424
+
type="button"
425
+
onClick={() => setDestination({ ...destination()!, manager: null })}
426
+
class="text-sm text-purple-800 hover:underline"
427
+
>
428
+
Sign out
429
+
</button>
430
+
</div>
431
+
</Subsection>
432
+
</Show>
433
+
</Accordion>
434
+
);
435
+
};
436
+
437
+
export default DestinationAccountSection;
+545
src/views/account/account-migrate/sections/identity.tsx
+545
src/views/account/account-migrate/sections/identity.tsx
···
1
+
import { createSignal, For, Index, Show } from 'solid-js';
2
+
3
+
import { Client, ClientResponseError, type CredentialManager, ok } from '@atcute/client';
4
+
import { type DidKeyString, Secp256k1PrivateKeyExportable } from '@atcute/crypto';
5
+
import type { Did } from '@atcute/lexicons/syntax';
6
+
7
+
import { getPlcAuditLogs } from '~/api/queries/plc';
8
+
import { formatTotpCode, TOTP_RE } from '~/api/utils/auth';
9
+
10
+
import { createMutation } from '~/lib/utils/mutation';
11
+
12
+
import { Accordion, StatusBadge, Subsection } from '~/components/accordion';
13
+
import Button from '~/components/inputs/button';
14
+
import TextInput from '~/components/inputs/text-input';
15
+
import ToggleInput from '~/components/inputs/toggle-input';
16
+
17
+
import { getPlcPayload } from '~/views/identity/plc-applicator/plc-utils';
18
+
19
+
import { useMigration } from '../context';
20
+
21
+
interface RecommendedCredentials {
22
+
alsoKnownAs?: string[];
23
+
rotationKeys?: string[];
24
+
verificationMethods?: Record<string, unknown>;
25
+
services?: Record<string, unknown>;
26
+
}
27
+
28
+
interface GeneratedKeypair {
29
+
publicDidKey: DidKeyString;
30
+
privateHex: string;
31
+
privateMultikey: string;
32
+
}
33
+
34
+
const IdentitySection = () => {
35
+
const { source, destination } = useMigration();
36
+
37
+
// Rotation key state
38
+
const [useGeneratedKey, setUseGeneratedKey] = createSignal(false);
39
+
const [customKeys, setCustomKeys] = createSignal<string[]>([]);
40
+
const [plcToken, setPlcToken] = createSignal('');
41
+
42
+
const requestTokenMutation = createMutation({
43
+
async mutationFn({ manager }: { manager: CredentialManager }) {
44
+
const client = new Client({ handler: manager });
45
+
await ok(client.post('com.atproto.identity.requestPlcOperationSignature', { as: null }));
46
+
},
47
+
onError(err) {
48
+
console.error(err);
49
+
},
50
+
});
51
+
52
+
const loadCredentialsMutation = createMutation({
53
+
async mutationFn({ manager }: { manager: CredentialManager }) {
54
+
const client = new Client({ handler: manager });
55
+
return (await ok(
56
+
client.get('com.atproto.identity.getRecommendedDidCredentials', {}),
57
+
)) as RecommendedCredentials;
58
+
},
59
+
onError(err) {
60
+
console.error(err);
61
+
},
62
+
});
63
+
64
+
// Analyze current rotation keys to find user-controlled keys that should be preserved
65
+
const analyzeRotationKeysMutation = createMutation({
66
+
async mutationFn({ did, sourceManager }: { did: Did<'plc'>; sourceManager: CredentialManager }, signal) {
67
+
// Get current rotation keys from PLC audit log
68
+
const auditLogs = await getPlcAuditLogs({ did, signal });
69
+
const latestEntry = auditLogs[auditLogs.length - 1];
70
+
const currentPayload = getPlcPayload(latestEntry);
71
+
const currentRotationKeys = currentPayload.rotationKeys ?? [];
72
+
73
+
// Get source PDS's recommended credentials to identify PDS-controlled keys
74
+
const sourceClient = new Client({ handler: sourceManager });
75
+
const sourcePdsCredentials = (await ok(
76
+
sourceClient.get('com.atproto.identity.getRecommendedDidCredentials', {}),
77
+
)) as RecommendedCredentials;
78
+
const sourcePdsKeys = new Set(sourcePdsCredentials.rotationKeys ?? []);
79
+
80
+
// Keys in current doc that aren't from source PDS are user-controlled
81
+
const userControlledKeys = currentRotationKeys.filter((key) => !sourcePdsKeys.has(key));
82
+
83
+
return {
84
+
currentRotationKeys,
85
+
sourcePdsKeys: sourcePdsCredentials.rotationKeys ?? [],
86
+
userControlledKeys,
87
+
};
88
+
},
89
+
onSuccess(data) {
90
+
// Pre-populate custom keys with user-controlled keys
91
+
if (data.userControlledKeys.length > 0) {
92
+
setCustomKeys(data.userControlledKeys);
93
+
}
94
+
},
95
+
onError(err) {
96
+
console.error(err);
97
+
},
98
+
});
99
+
100
+
const generateKeyMutation = createMutation({
101
+
async mutationFn() {
102
+
const keypair = await Secp256k1PrivateKeyExportable.createKeypair();
103
+
const [publicDidKey, privateHex, privateMultikey] = await Promise.all([
104
+
keypair.exportPublicKey('did'),
105
+
keypair.exportPrivateKey('rawHex'),
106
+
keypair.exportPrivateKey('multikey'),
107
+
]);
108
+
return { publicDidKey, privateHex, privateMultikey } as GeneratedKeypair;
109
+
},
110
+
onError(err) {
111
+
console.error(err);
112
+
},
113
+
});
114
+
115
+
const signAndSubmitMutation = createMutation({
116
+
async mutationFn({
117
+
sourceManager,
118
+
destManager,
119
+
token,
120
+
credentials,
121
+
generatedKey,
122
+
customKeys,
123
+
}: {
124
+
sourceManager: CredentialManager;
125
+
destManager: CredentialManager;
126
+
token: string;
127
+
credentials: RecommendedCredentials;
128
+
generatedKey?: GeneratedKeypair;
129
+
customKeys: string[];
130
+
}) {
131
+
const sourceClient = new Client({ handler: sourceManager });
132
+
const destClient = new Client({ handler: destManager });
133
+
134
+
// Prepend user keys to PDS-provided keys (so user keys appear first for recovery)
135
+
const pdsRotationKeys = credentials.rotationKeys ?? [];
136
+
const userKeys: string[] = [];
137
+
if (generatedKey) {
138
+
userKeys.push(generatedKey.publicDidKey);
139
+
}
140
+
userKeys.push(...customKeys.filter((k) => k.trim()));
141
+
const rotationKeys = [...userKeys, ...pdsRotationKeys];
142
+
143
+
// Sign the PLC operation on the source PDS
144
+
const signage = await ok(
145
+
sourceClient.post('com.atproto.identity.signPlcOperation', {
146
+
input: {
147
+
token: formatTotpCode(token),
148
+
alsoKnownAs: credentials.alsoKnownAs,
149
+
rotationKeys: rotationKeys,
150
+
services: credentials.services,
151
+
verificationMethods: credentials.verificationMethods,
152
+
},
153
+
}),
154
+
);
155
+
156
+
// Submit via the destination PDS
157
+
await ok(
158
+
destClient.post('com.atproto.identity.submitPlcOperation', {
159
+
as: null,
160
+
input: {
161
+
operation: signage.operation,
162
+
},
163
+
}),
164
+
);
165
+
},
166
+
onSuccess() {
167
+
setPlcToken('');
168
+
},
169
+
onError(err) {
170
+
console.error(err);
171
+
},
172
+
});
173
+
174
+
// Calculate rotation key counts
175
+
const pdsKeyCount = () => loadCredentialsMutation.data?.rotationKeys?.length ?? 0;
176
+
const totalKeyCount = () => {
177
+
const custom = customKeys().filter((k) => k.trim()).length;
178
+
const generated = useGeneratedKey() && generateKeyMutation.data ? 1 : 0;
179
+
return pdsKeyCount() + custom + generated;
180
+
};
181
+
const canAddCustomKey = () => totalKeyCount() < 5;
182
+
const isOverLimit = () => totalKeyCount() > 5;
183
+
184
+
const addCustomKey = () => {
185
+
if (canAddCustomKey()) {
186
+
setCustomKeys([...customKeys(), '']);
187
+
}
188
+
};
189
+
190
+
const removeCustomKey = (index: number) => {
191
+
setCustomKeys(customKeys().filter((_, i) => i !== index));
192
+
};
193
+
194
+
const updateCustomKey = (index: number, value: string) => {
195
+
setCustomKeys(customKeys().map((k, i) => (i === index ? value : k)));
196
+
};
197
+
198
+
const canSignAndSubmit = () => {
199
+
const src = source();
200
+
const dest = destination();
201
+
const creds = loadCredentialsMutation.data;
202
+
const token = plcToken().trim();
203
+
204
+
return !!(src?.manager && dest?.manager && creds && token && !isOverLimit());
205
+
};
206
+
207
+
const handleSignAndSubmit = () => {
208
+
const src = source();
209
+
const dest = destination();
210
+
const creds = loadCredentialsMutation.data;
211
+
const token = plcToken().trim();
212
+
213
+
if (!src?.manager || !dest?.manager || !creds || !token || isOverLimit()) return;
214
+
215
+
signAndSubmitMutation.mutate({
216
+
sourceManager: src.manager,
217
+
destManager: dest.manager,
218
+
token,
219
+
credentials: creds,
220
+
generatedKey: useGeneratedKey() ? generateKeyMutation.data : undefined,
221
+
customKeys: customKeys(),
222
+
});
223
+
};
224
+
225
+
const getSubmitErrorMessage = () => {
226
+
const err = signAndSubmitMutation.error;
227
+
if (err instanceof ClientResponseError) {
228
+
if (err.error === 'InvalidToken' || err.error === 'ExpiredToken') {
229
+
return 'Confirmation code has expired or is invalid';
230
+
}
231
+
}
232
+
return `${err}`;
233
+
};
234
+
235
+
return (
236
+
<Accordion title="Identity (PLC)">
237
+
<div class="mb-4 rounded border border-yellow-300 bg-yellow-50 p-3">
238
+
<p class="text-sm font-medium text-yellow-800">
239
+
This updates your DID document to point to the new PDS. This is the critical step that makes the
240
+
migration official.
241
+
</p>
242
+
</div>
243
+
244
+
<Subsection title="1. Preview new credentials">
245
+
<p class="text-sm text-gray-600">View what your DID document will look like after the migration.</p>
246
+
247
+
<Show
248
+
when={destination()?.manager}
249
+
fallback={<p class="text-sm text-gray-500">Sign in to destination account first.</p>}
250
+
>
251
+
{(manager) => (
252
+
<>
253
+
<div class="flex items-center gap-3">
254
+
<Button
255
+
variant="outline"
256
+
onClick={() => loadCredentialsMutation.mutate({ manager: manager() })}
257
+
disabled={loadCredentialsMutation.isPending}
258
+
>
259
+
{loadCredentialsMutation.isPending ? 'Loading...' : 'Load credentials'}
260
+
</Button>
261
+
262
+
<Show when={loadCredentialsMutation.isSuccess}>
263
+
<StatusBadge variant="success">Loaded</StatusBadge>
264
+
</Show>
265
+
</div>
266
+
267
+
<Show when={loadCredentialsMutation.isError}>
268
+
<p class="text-sm text-red-600">{`${loadCredentialsMutation.error}`}</p>
269
+
</Show>
270
+
271
+
<Show when={loadCredentialsMutation.data}>
272
+
{(creds) => (
273
+
<>
274
+
<div class="mt-2 text-sm">
275
+
<p class="text-gray-500">
276
+
Destination PDS rotation keys ({creds().rotationKeys?.length ?? 0}/5):
277
+
</p>
278
+
<div class="mt-1 flex flex-col gap-1">
279
+
<For each={creds().rotationKeys ?? []}>
280
+
{(key) => <code class="block truncate text-xs text-gray-700">{key}</code>}
281
+
</For>
282
+
</div>
283
+
</div>
284
+
285
+
<Show when={source()?.manager && source()}>
286
+
{(src) => (
287
+
<div class="mt-3 rounded border border-blue-200 bg-blue-50 p-3">
288
+
<div class="flex items-center justify-between">
289
+
<p class="text-sm font-medium text-blue-800">Analyze existing rotation keys</p>
290
+
<Button
291
+
variant="outline"
292
+
onClick={() =>
293
+
analyzeRotationKeysMutation.mutate({
294
+
did: src().did as Did<'plc'>,
295
+
sourceManager: src().manager!,
296
+
})
297
+
}
298
+
disabled={analyzeRotationKeysMutation.isPending}
299
+
>
300
+
{analyzeRotationKeysMutation.isPending ? 'Analyzing...' : 'Analyze'}
301
+
</Button>
302
+
</div>
303
+
<p class="mt-1 text-xs text-blue-600">
304
+
Check if you have any user-controlled rotation keys that should be preserved
305
+
during migration.
306
+
</p>
307
+
308
+
<Show when={analyzeRotationKeysMutation.error}>
309
+
<p class="mt-2 text-sm text-red-600">{`${analyzeRotationKeysMutation.error}`}</p>
310
+
</Show>
311
+
312
+
<Show when={analyzeRotationKeysMutation.data}>
313
+
{(analysis) => (
314
+
<div class="mt-2 text-sm">
315
+
<Show
316
+
when={analysis().userControlledKeys.length > 0}
317
+
fallback={
318
+
<p class="text-blue-700">
319
+
No user-controlled rotation keys found. Your current keys are all
320
+
managed by your source PDS.
321
+
</p>
322
+
}
323
+
>
324
+
<p class="font-medium text-blue-800">
325
+
Found {analysis().userControlledKeys.length} user-controlled key(s) to
326
+
preserve:
327
+
</p>
328
+
<div class="mt-1 flex flex-col gap-1">
329
+
<For each={analysis().userControlledKeys}>
330
+
{(key) => (
331
+
<code class="block truncate text-xs text-blue-700">{key}</code>
332
+
)}
333
+
</For>
334
+
</div>
335
+
<p class="mt-2 text-xs text-blue-600">
336
+
These keys have been added to the custom keys section below.
337
+
</p>
338
+
</Show>
339
+
</div>
340
+
)}
341
+
</Show>
342
+
</div>
343
+
)}
344
+
</Show>
345
+
346
+
<details class="mt-2">
347
+
<summary class="cursor-pointer text-sm text-gray-600">View full credentials</summary>
348
+
<pre class="mt-2 max-h-48 overflow-auto rounded border border-gray-200 bg-gray-50 p-2 font-mono text-xs">
349
+
{JSON.stringify(creds(), null, 2)}
350
+
</pre>
351
+
</details>
352
+
</>
353
+
)}
354
+
</Show>
355
+
</>
356
+
)}
357
+
</Show>
358
+
</Subsection>
359
+
360
+
<Subsection title="2. Rotation keys (optional)">
361
+
<p class="text-sm text-gray-600">
362
+
Add a rotation key to recover your account if your new PDS goes rogue. This will be prepended to the
363
+
PDS rotation keys shown above.
364
+
</p>
365
+
366
+
<ToggleInput
367
+
label="Generate a new rotation key"
368
+
checked={useGeneratedKey()}
369
+
onChange={(checked) => {
370
+
setUseGeneratedKey(checked);
371
+
// Auto-generate if checked and no key exists yet
372
+
if (checked && !generateKeyMutation.data && !generateKeyMutation.isPending) {
373
+
generateKeyMutation.mutate();
374
+
}
375
+
}}
376
+
/>
377
+
378
+
<Show when={useGeneratedKey() && generateKeyMutation.isPending}>
379
+
<p class="mt-2 text-sm text-gray-500">Generating key...</p>
380
+
</Show>
381
+
382
+
<Show when={useGeneratedKey() && generateKeyMutation.isError}>
383
+
<p class="mt-2 text-sm text-red-600">{`${generateKeyMutation.error}`}</p>
384
+
</Show>
385
+
386
+
<Show when={useGeneratedKey() && generateKeyMutation.data}>
387
+
{(keypair) => (
388
+
<div class="rounded border border-green-300 bg-green-50 p-3">
389
+
<p class="mb-2 text-sm font-semibold text-green-800">Save your rotation key private key!</p>
390
+
<p class="mb-3 text-xs text-green-700">
391
+
Store this securely. You'll need it to recover your account if your PDS becomes unavailable or
392
+
malicious.
393
+
</p>
394
+
395
+
<div class="flex flex-col gap-2 text-sm">
396
+
<div>
397
+
<p class="font-medium text-gray-600">Public key (did:key)</p>
398
+
<p class="break-all font-mono text-xs">{keypair().publicDidKey}</p>
399
+
</div>
400
+
<div>
401
+
<p class="font-medium text-gray-600">Private key (hex)</p>
402
+
<p class="break-all font-mono text-xs">{keypair().privateHex}</p>
403
+
</div>
404
+
<div>
405
+
<p class="font-medium text-gray-600">Private key (multikey)</p>
406
+
<p class="break-all font-mono text-xs">{keypair().privateMultikey}</p>
407
+
</div>
408
+
</div>
409
+
</div>
410
+
)}
411
+
</Show>
412
+
413
+
<div class="rounded border border-gray-200 bg-gray-50 p-3">
414
+
<p class="mb-2 text-sm font-medium text-gray-700">Custom rotation keys</p>
415
+
<p class="mb-3 text-xs text-gray-500">
416
+
Add existing rotation keys (did:key format) you already control.
417
+
</p>
418
+
419
+
<Index each={customKeys()}>
420
+
{(key, index) => (
421
+
<div class="mb-2 flex items-center gap-2">
422
+
<TextInput
423
+
label=""
424
+
placeholder="did:key:z..."
425
+
monospace
426
+
autocomplete="off"
427
+
value={key()}
428
+
onChange={(value) => updateCustomKey(index, value)}
429
+
/>
430
+
<button
431
+
type="button"
432
+
class="shrink-0 rounded px-2 py-1 text-sm text-red-600 hover:bg-red-50"
433
+
onClick={() => removeCustomKey(index)}
434
+
>
435
+
Remove
436
+
</button>
437
+
</div>
438
+
)}
439
+
</Index>
440
+
441
+
<Button variant="outline" onClick={addCustomKey} disabled={!canAddCustomKey()}>
442
+
Add rotation key
443
+
</Button>
444
+
445
+
<Show when={isOverLimit()}>
446
+
<p class="mt-2 text-sm text-red-600">
447
+
Too many rotation keys. PLC documents can only have up to 5 rotation keys total.
448
+
</p>
449
+
</Show>
450
+
451
+
<p class="mt-2 text-xs text-gray-500">
452
+
Total keys: {totalKeyCount()}/5 (PDS: {pdsKeyCount()}
453
+
{useGeneratedKey() && generateKeyMutation.data ? ', generated: 1' : ''}
454
+
{customKeys().filter((k) => k.trim()).length > 0
455
+
? `, custom: ${customKeys().filter((k) => k.trim()).length}`
456
+
: ''}
457
+
)
458
+
</p>
459
+
</div>
460
+
</Subsection>
461
+
462
+
<Subsection title="3. Request operation signature">
463
+
<p class="text-sm text-gray-600">Request a confirmation token via email from your source PDS.</p>
464
+
465
+
<Show
466
+
when={source()?.manager}
467
+
fallback={<p class="text-sm text-gray-500">Sign in to source account first.</p>}
468
+
>
469
+
{(manager) => (
470
+
<>
471
+
<div class="flex items-center gap-3">
472
+
<Button
473
+
onClick={() => requestTokenMutation.mutate({ manager: manager() })}
474
+
disabled={requestTokenMutation.isPending}
475
+
>
476
+
{requestTokenMutation.isPending ? 'Requesting...' : 'Request token'}
477
+
</Button>
478
+
479
+
<Show when={requestTokenMutation.isSuccess}>
480
+
<StatusBadge variant="success">Email sent</StatusBadge>
481
+
</Show>
482
+
</div>
483
+
484
+
<Show when={requestTokenMutation.isError}>
485
+
<p class="text-sm text-red-600">{`${requestTokenMutation.error}`}</p>
486
+
</Show>
487
+
488
+
<Show when={requestTokenMutation.isSuccess}>
489
+
<p class="text-sm text-gray-600">Check your email inbox for the confirmation code.</p>
490
+
</Show>
491
+
</>
492
+
)}
493
+
</Show>
494
+
</Subsection>
495
+
496
+
<Subsection title="4. Sign and submit">
497
+
<p class="text-sm text-gray-600">Enter the confirmation code and submit the PLC operation.</p>
498
+
499
+
<Show when={!source()?.manager || !destination()?.manager}>
500
+
<p class="text-sm text-gray-500">Sign in to both source and destination accounts first.</p>
501
+
</Show>
502
+
503
+
<Show when={!loadCredentialsMutation.data}>
504
+
<p class="text-sm text-gray-500">Load credentials first.</p>
505
+
</Show>
506
+
507
+
<Show when={useGeneratedKey() && !generateKeyMutation.data}>
508
+
<p class="text-sm text-gray-500">Generate your rotation key first.</p>
509
+
</Show>
510
+
511
+
<Show when={source()?.manager && destination()?.manager && loadCredentialsMutation.data}>
512
+
<TextInput
513
+
label="Confirmation code from email"
514
+
type="text"
515
+
autocomplete="one-time-code"
516
+
pattern={TOTP_RE.source}
517
+
placeholder="AAAAA-BBBBB"
518
+
value={plcToken()}
519
+
onChange={setPlcToken}
520
+
monospace
521
+
/>
522
+
523
+
<div class="flex items-center gap-3">
524
+
<Button
525
+
onClick={handleSignAndSubmit}
526
+
disabled={signAndSubmitMutation.isPending || !canSignAndSubmit()}
527
+
>
528
+
{signAndSubmitMutation.isPending ? 'Submitting...' : 'Sign and submit'}
529
+
</Button>
530
+
531
+
<Show when={signAndSubmitMutation.isSuccess}>
532
+
<StatusBadge variant="success">Identity updated successfully</StatusBadge>
533
+
</Show>
534
+
</div>
535
+
536
+
<Show when={signAndSubmitMutation.isError}>
537
+
<p class="text-sm text-red-600">{getSubmitErrorMessage()}</p>
538
+
</Show>
539
+
</Show>
540
+
</Subsection>
541
+
</Accordion>
542
+
);
543
+
};
544
+
545
+
export default IdentitySection;
+180
src/views/account/account-migrate/sections/preferences.tsx
+180
src/views/account/account-migrate/sections/preferences.tsx
···
1
+
import { showSaveFilePicker } from 'native-file-system-adapter';
2
+
import { createSignal, Show } from 'solid-js';
3
+
4
+
import { Client, type CredentialManager, ok } from '@atcute/client';
5
+
6
+
import { createMutation } from '~/lib/utils/mutation';
7
+
8
+
import { Accordion, StatusBadge, Subsection } from '~/components/accordion';
9
+
import Button from '~/components/inputs/button';
10
+
import MultilineInput from '~/components/inputs/multiline-input';
11
+
12
+
import { useMigration } from '../context';
13
+
14
+
const PreferencesSection = () => {
15
+
const { source, destination } = useMigration();
16
+
17
+
const [prefsInput, setPrefsInput] = createSignal('');
18
+
19
+
const exportMutation = createMutation({
20
+
async mutationFn({ sourceManager }: { sourceManager: CredentialManager }) {
21
+
const sourceClient = new Client({ handler: sourceManager });
22
+
const prefs = await ok(sourceClient.get('app.bsky.actor.getPreferences', { params: {} }));
23
+
return JSON.stringify(prefs, null, 2);
24
+
},
25
+
onSuccess(json) {
26
+
setPrefsInput(json);
27
+
},
28
+
onError(err) {
29
+
console.error(err);
30
+
},
31
+
});
32
+
33
+
const downloadPrefs = async () => {
34
+
const prefs = exportMutation.data;
35
+
if (!prefs) return;
36
+
37
+
try {
38
+
const fd = await showSaveFilePicker({
39
+
suggestedName: `preferences-${source()?.did}-${new Date().toISOString()}.json`,
40
+
// @ts-expect-error: ponyfill doesn't have the full typings
41
+
id: 'prefs-export',
42
+
startIn: 'downloads',
43
+
types: [
44
+
{
45
+
description: 'JSON file',
46
+
accept: { 'application/json': ['.json'] },
47
+
},
48
+
],
49
+
}).catch((err) => {
50
+
if (err instanceof DOMException && err.name === 'AbortError') {
51
+
return undefined;
52
+
}
53
+
throw err;
54
+
});
55
+
56
+
if (!fd) return;
57
+
58
+
const writable = await fd.createWritable();
59
+
await writable.write(prefs);
60
+
await writable.close();
61
+
} catch (err) {
62
+
console.error(err);
63
+
}
64
+
};
65
+
66
+
const importMutation = createMutation({
67
+
async mutationFn({ destManager, input }: { destManager: CredentialManager; input: string }) {
68
+
const prefs = JSON.parse(input);
69
+
70
+
// Validate that it has a preferences array
71
+
if (!prefs.preferences || !Array.isArray(prefs.preferences)) {
72
+
throw new Error('Invalid preferences format: missing preferences array');
73
+
}
74
+
75
+
const destClient = new Client({ handler: destManager });
76
+
await destClient.post('app.bsky.actor.putPreferences', {
77
+
as: null,
78
+
input: prefs,
79
+
});
80
+
},
81
+
onError(err) {
82
+
console.error(err);
83
+
},
84
+
});
85
+
86
+
const getImportErrorMessage = () => {
87
+
const err = importMutation.error;
88
+
if (err instanceof SyntaxError) {
89
+
return 'Invalid JSON format';
90
+
}
91
+
return `${err}`;
92
+
};
93
+
94
+
return (
95
+
<Accordion title="Preferences">
96
+
<Subsection title="Export from source">
97
+
<p class="text-sm text-gray-600">
98
+
Export your Bluesky preferences (muted words, content filters, saved feeds, etc).
99
+
</p>
100
+
101
+
<Show
102
+
when={source()?.manager}
103
+
fallback={<p class="text-sm text-gray-500">Sign in to source account first.</p>}
104
+
>
105
+
{(sourceManager) => (
106
+
<>
107
+
<div class="flex items-center gap-3">
108
+
<Button
109
+
onClick={() => exportMutation.mutate({ sourceManager: sourceManager() })}
110
+
disabled={exportMutation.isPending}
111
+
>
112
+
{exportMutation.isPending ? 'Exporting...' : 'Export preferences'}
113
+
</Button>
114
+
115
+
<Show when={exportMutation.data}>
116
+
<Button variant="secondary" onClick={downloadPrefs}>
117
+
Download as file
118
+
</Button>
119
+
</Show>
120
+
</div>
121
+
122
+
<Show when={exportMutation.error}>
123
+
{(err) => <p class="text-sm text-red-600">{`${err()}`}</p>}
124
+
</Show>
125
+
126
+
<Show when={exportMutation.data}>
127
+
{(prefs) => (
128
+
<details class="mt-2">
129
+
<summary class="cursor-pointer text-sm text-gray-600">
130
+
View exported preferences
131
+
</summary>
132
+
<pre class="mt-2 max-h-48 overflow-auto rounded border border-gray-200 bg-gray-50 p-2 font-mono text-xs">
133
+
{prefs()}
134
+
</pre>
135
+
</details>
136
+
)}
137
+
</Show>
138
+
</>
139
+
)}
140
+
</Show>
141
+
</Subsection>
142
+
143
+
<Subsection title="Import to destination">
144
+
<p class="text-sm text-gray-600">Paste preferences JSON or use the exported data above.</p>
145
+
146
+
<Show
147
+
when={destination()?.manager}
148
+
fallback={<p class="text-sm text-gray-500">Sign in to destination account first.</p>}
149
+
>
150
+
{(destManager) => (
151
+
<>
152
+
<MultilineInput label="Preferences JSON" value={prefsInput()} onChange={setPrefsInput} />
153
+
154
+
<div class="flex items-center gap-3">
155
+
<Button
156
+
onClick={() =>
157
+
importMutation.mutate({ destManager: destManager(), input: prefsInput().trim() })
158
+
}
159
+
disabled={importMutation.isPending || !prefsInput().trim()}
160
+
>
161
+
{importMutation.isPending ? 'Importing...' : 'Import preferences'}
162
+
</Button>
163
+
164
+
<Show when={importMutation.isSuccess}>
165
+
<StatusBadge variant="success">Preferences imported successfully</StatusBadge>
166
+
</Show>
167
+
</div>
168
+
169
+
<Show when={importMutation.error}>
170
+
<p class="text-sm text-red-600">{getImportErrorMessage()}</p>
171
+
</Show>
172
+
</>
173
+
)}
174
+
</Show>
175
+
</Subsection>
176
+
</Accordion>
177
+
);
178
+
};
179
+
180
+
export default PreferencesSection;
+291
src/views/account/account-migrate/sections/repository.tsx
+291
src/views/account/account-migrate/sections/repository.tsx
···
1
+
import { showOpenFilePicker, showSaveFilePicker } from 'native-file-system-adapter';
2
+
import { createSignal, Show } from 'solid-js';
3
+
4
+
import { Client, type CredentialManager, ok, simpleFetchHandler } from '@atcute/client';
5
+
import type { Did } from '@atcute/lexicons/syntax';
6
+
7
+
import { formatBytes } from '~/lib/utils/intl/bytes';
8
+
import { createMutation } from '~/lib/utils/mutation';
9
+
import { iterateStream } from '~/lib/utils/stream';
10
+
11
+
import { Accordion, StatusBadge, Subsection } from '~/components/accordion';
12
+
import Button from '~/components/inputs/button';
13
+
14
+
import { useMigration } from '../context';
15
+
16
+
const RepositorySection = () => {
17
+
const { source, destination } = useMigration();
18
+
19
+
// Export state
20
+
const [exportStatus, setExportStatus] = createSignal<string>();
21
+
22
+
// Import state
23
+
const [importStatus, setImportStatus] = createSignal<string>();
24
+
const [importedRecords, setImportedRecords] = createSignal<number>();
25
+
26
+
const exportMutation = createMutation({
27
+
async mutationFn({ pdsUrl, did }: { pdsUrl: string; did: Did }) {
28
+
setExportStatus('Waiting for file picker...');
29
+
30
+
const fd = await showSaveFilePicker({
31
+
suggestedName: `repo-${did}-${new Date().toISOString()}.car`,
32
+
// @ts-expect-error: ponyfill doesn't have the full typings
33
+
id: 'repo-export',
34
+
startIn: 'downloads',
35
+
types: [
36
+
{
37
+
description: 'CAR archive file',
38
+
accept: { 'application/vnd.ipld.car': ['.car'] },
39
+
},
40
+
],
41
+
}).catch((err) => {
42
+
if (err instanceof DOMException && err.name === 'AbortError') {
43
+
return undefined;
44
+
}
45
+
throw err;
46
+
});
47
+
48
+
if (!fd) {
49
+
setExportStatus();
50
+
return null;
51
+
}
52
+
53
+
const writable = await fd.createWritable();
54
+
55
+
setExportStatus('Downloading repository...');
56
+
57
+
const sourceClient = new Client({ handler: simpleFetchHandler({ service: pdsUrl }) });
58
+
const response = await sourceClient.get('com.atproto.sync.getRepo', {
59
+
as: 'stream',
60
+
params: { did },
61
+
});
62
+
63
+
if (!response.ok) {
64
+
throw new Error(`Failed to download repository: ${response.status}`);
65
+
}
66
+
67
+
let size = 0;
68
+
for await (const chunk of iterateStream(response.data)) {
69
+
size += chunk.length;
70
+
await writable.write(chunk);
71
+
setExportStatus(`Downloading repository... (${formatBytes(size)})`);
72
+
}
73
+
74
+
await writable.close();
75
+
setExportStatus(`Exported ${formatBytes(size)}`);
76
+
return size;
77
+
},
78
+
onMutate() {
79
+
setExportStatus();
80
+
},
81
+
onError(err) {
82
+
console.error(err);
83
+
setExportStatus();
84
+
},
85
+
});
86
+
87
+
const importFromFileMutation = createMutation({
88
+
async mutationFn({ manager }: { manager: CredentialManager }) {
89
+
setImportStatus('Waiting for file picker...');
90
+
91
+
const [fd] = await showOpenFilePicker({
92
+
// @ts-expect-error: ponyfill doesn't have the full typings
93
+
id: 'repo-import',
94
+
types: [
95
+
{
96
+
description: 'CAR archive file',
97
+
accept: { 'application/vnd.ipld.car': ['.car'] },
98
+
},
99
+
],
100
+
}).catch((err) => {
101
+
if (err instanceof DOMException && err.name === 'AbortError') {
102
+
return [undefined];
103
+
}
104
+
throw err;
105
+
});
106
+
107
+
if (!fd) {
108
+
setImportStatus();
109
+
return null;
110
+
}
111
+
112
+
const file = await fd.getFile();
113
+
114
+
setImportStatus(`Uploading repository (${formatBytes(file.size)})...`);
115
+
116
+
const destClient = new Client({ handler: manager });
117
+
const importResp = await destClient.post('com.atproto.repo.importRepo', {
118
+
as: null,
119
+
input: file,
120
+
headers: {
121
+
'content-type': 'application/vnd.ipld.car',
122
+
},
123
+
});
124
+
125
+
if (!importResp.ok) {
126
+
throw new Error(`Failed to import repository: ${importResp.status}`);
127
+
}
128
+
129
+
// Check account status to get record count
130
+
const status = await ok(destClient.get('com.atproto.server.checkAccountStatus', {}));
131
+
setImportedRecords(status.indexedRecords);
132
+
133
+
setImportStatus(`Imported successfully`);
134
+
return status.indexedRecords;
135
+
},
136
+
onMutate() {
137
+
setImportStatus();
138
+
setImportedRecords();
139
+
},
140
+
onError(err) {
141
+
console.error(err);
142
+
setImportStatus();
143
+
},
144
+
});
145
+
146
+
const importFromSourceMutation = createMutation({
147
+
async mutationFn({
148
+
sourcePdsUrl,
149
+
sourceDid,
150
+
destManager,
151
+
}: {
152
+
sourcePdsUrl: string;
153
+
sourceDid: Did;
154
+
destManager: CredentialManager;
155
+
}) {
156
+
setImportStatus('Downloading from source PDS...');
157
+
158
+
const sourceClient = new Client({ handler: simpleFetchHandler({ service: sourcePdsUrl }) });
159
+
const response = await sourceClient.get('com.atproto.sync.getRepo', {
160
+
as: 'bytes',
161
+
params: { did: sourceDid },
162
+
});
163
+
164
+
if (!response.ok) {
165
+
throw new Error(`Failed to download repository: ${response.status}`);
166
+
}
167
+
168
+
setImportStatus(`Uploading to destination (${formatBytes(response.data.length)})...`);
169
+
170
+
const destClient = new Client({ handler: destManager });
171
+
const importResp = await destClient.post('com.atproto.repo.importRepo', {
172
+
as: null,
173
+
input: response.data,
174
+
headers: {
175
+
'content-type': 'application/vnd.ipld.car',
176
+
},
177
+
});
178
+
179
+
if (!importResp.ok) {
180
+
throw new Error(`Failed to import repository: ${importResp.status}`);
181
+
}
182
+
183
+
// Check account status to get record count
184
+
const status = await ok(destClient.get('com.atproto.server.checkAccountStatus', {}));
185
+
setImportedRecords(status.indexedRecords);
186
+
187
+
setImportStatus(`Imported successfully`);
188
+
return status.indexedRecords;
189
+
},
190
+
onMutate() {
191
+
setImportStatus();
192
+
setImportedRecords();
193
+
},
194
+
onError(err) {
195
+
console.error(err);
196
+
setImportStatus();
197
+
},
198
+
});
199
+
200
+
const isExporting = () => exportMutation.isPending;
201
+
const isImporting = () => importFromFileMutation.isPending || importFromSourceMutation.isPending;
202
+
203
+
return (
204
+
<Accordion title="Repository">
205
+
<Subsection title="Export from source">
206
+
<p class="text-sm text-gray-600">
207
+
Download the repository as a CAR file for backup or manual import.
208
+
</p>
209
+
210
+
<Show when={source()} fallback={<p class="text-sm text-gray-500">Resolve source account first.</p>}>
211
+
{(src) => (
212
+
<>
213
+
<div class="flex items-center gap-3">
214
+
<Button
215
+
onClick={() => exportMutation.mutate({ pdsUrl: src().pdsUrl, did: src().did })}
216
+
disabled={isExporting()}
217
+
>
218
+
{isExporting() ? 'Exporting...' : 'Export to file'}
219
+
</Button>
220
+
<Show when={exportStatus()}>
221
+
<span class="text-sm text-gray-600">{exportStatus()}</span>
222
+
</Show>
223
+
</div>
224
+
225
+
<Show when={exportMutation.isError}>
226
+
<p class="text-sm text-red-600">{`${exportMutation.error}`}</p>
227
+
</Show>
228
+
</>
229
+
)}
230
+
</Show>
231
+
</Subsection>
232
+
233
+
<Subsection title="Import to destination">
234
+
<p class="text-sm text-gray-600">Upload a repository CAR file or transfer directly from source.</p>
235
+
236
+
<Show
237
+
when={destination()?.manager}
238
+
fallback={<p class="text-sm text-gray-500">Sign in to destination account first.</p>}
239
+
>
240
+
{(manager) => (
241
+
<>
242
+
<div class="flex flex-wrap items-center gap-3">
243
+
<Button
244
+
onClick={() => importFromFileMutation.mutate({ manager: manager() })}
245
+
disabled={isImporting()}
246
+
>
247
+
{isImporting() ? 'Importing...' : 'Import from file'}
248
+
</Button>
249
+
250
+
<Show when={source()}>
251
+
{(src) => (
252
+
<Button
253
+
variant="secondary"
254
+
onClick={() =>
255
+
importFromSourceMutation.mutate({
256
+
sourcePdsUrl: src().pdsUrl,
257
+
sourceDid: src().did,
258
+
destManager: manager(),
259
+
})
260
+
}
261
+
disabled={isImporting()}
262
+
>
263
+
Transfer from source
264
+
</Button>
265
+
)}
266
+
</Show>
267
+
</div>
268
+
269
+
<Show when={importStatus()}>
270
+
<div class="flex items-center gap-2">
271
+
<span class="text-sm text-gray-600">{importStatus()}</span>
272
+
<Show when={importedRecords() !== undefined}>
273
+
<StatusBadge variant="success">{importedRecords()} records</StatusBadge>
274
+
</Show>
275
+
</div>
276
+
</Show>
277
+
278
+
<Show when={importFromFileMutation.isError || importFromSourceMutation.isError}>
279
+
<p class="text-sm text-red-600">
280
+
{`${importFromFileMutation.error || importFromSourceMutation.error}`}
281
+
</p>
282
+
</Show>
283
+
</>
284
+
)}
285
+
</Show>
286
+
</Subsection>
287
+
</Accordion>
288
+
);
289
+
};
290
+
291
+
export default RepositorySection;
+265
src/views/account/account-migrate/sections/source-account.tsx
+265
src/views/account/account-migrate/sections/source-account.tsx
···
1
+
import { createSignal, Show } from 'solid-js';
2
+
3
+
import { type AtpAccessJwt, ClientResponseError, CredentialManager } from '@atcute/client';
4
+
import { getPdsEndpoint, isAtprotoDid } from '@atcute/identity';
5
+
import { isHandle, type AtprotoDid } from '@atcute/lexicons/syntax';
6
+
7
+
import { getDidDocument } from '~/api/queries/did-doc';
8
+
import { resolveHandleViaAppView } from '~/api/queries/handle';
9
+
import { formatTotpCode, TOTP_RE } from '~/api/utils/auth';
10
+
import { decodeJwt } from '~/api/utils/jwt';
11
+
12
+
import { createMutation } from '~/lib/utils/mutation';
13
+
14
+
import { Accordion, StatusBadge, Subsection } from '~/components/accordion';
15
+
import Button from '~/components/inputs/button';
16
+
import TextInput from '~/components/inputs/text-input';
17
+
18
+
import { useMigration } from '../context';
19
+
20
+
interface SourceAccountSectionProps {
21
+
onStarted?: () => void;
22
+
}
23
+
24
+
class InsufficientLoginError extends Error {}
25
+
26
+
const SourceAccountSection = (props: SourceAccountSectionProps) => {
27
+
const { source, setSource } = useMigration();
28
+
29
+
// Resolve state
30
+
const [identifier, setIdentifier] = createSignal('');
31
+
const [resolveError, setResolveError] = createSignal<string>();
32
+
33
+
// Auth state
34
+
const [password, setPassword] = createSignal('');
35
+
const [otp, setOtp] = createSignal('');
36
+
const [isTotpRequired, setIsTotpRequired] = createSignal(false);
37
+
const [authError, setAuthError] = createSignal<string>();
38
+
39
+
const resolveMutation = createMutation({
40
+
async mutationFn({ identifier }: { identifier: string }) {
41
+
let did: AtprotoDid;
42
+
if (isAtprotoDid(identifier)) {
43
+
did = identifier;
44
+
} else if (isHandle(identifier)) {
45
+
did = await resolveHandleViaAppView({ handle: identifier });
46
+
} else {
47
+
throw new Error(`${identifier} is not a valid DID or handle`);
48
+
}
49
+
50
+
const didDoc = await getDidDocument({ did });
51
+
const pdsUrl = getPdsEndpoint(didDoc);
52
+
53
+
if (!pdsUrl) {
54
+
throw new Error(`No PDS endpoint found in DID document`);
55
+
}
56
+
57
+
return { did, didDoc, pdsUrl };
58
+
},
59
+
onMutate() {
60
+
setResolveError();
61
+
},
62
+
onSuccess({ did, didDoc, pdsUrl }) {
63
+
setSource({ did, didDoc, pdsUrl, manager: null });
64
+
props.onStarted?.();
65
+
},
66
+
onError(err) {
67
+
if (err instanceof ClientResponseError) {
68
+
if (err.error === 'InvalidRequest' && err.description?.includes('resolve handle')) {
69
+
setResolveError(`Can't resolve handle, is it typed correctly?`);
70
+
return;
71
+
}
72
+
}
73
+
console.error(err);
74
+
setResolveError(`${err}`);
75
+
},
76
+
});
77
+
78
+
const authMutation = createMutation({
79
+
async mutationFn({ pdsUrl, did, password, otp }: { pdsUrl: string; did: string; password: string; otp: string }) {
80
+
const manager = new CredentialManager({ service: pdsUrl });
81
+
const session = await manager.login({
82
+
identifier: did,
83
+
password: password,
84
+
code: formatTotpCode(otp),
85
+
});
86
+
87
+
const decoded = decodeJwt(session.accessJwt) as AtpAccessJwt;
88
+
if (decoded.scope !== 'com.atproto.access') {
89
+
throw new InsufficientLoginError(`You need to sign in with a main password, not an app password`);
90
+
}
91
+
92
+
return manager;
93
+
},
94
+
onMutate() {
95
+
setAuthError();
96
+
},
97
+
onSuccess(manager) {
98
+
setSource({ ...source()!, manager });
99
+
setPassword('');
100
+
setOtp('');
101
+
setIsTotpRequired(false);
102
+
},
103
+
onError(err) {
104
+
if (err instanceof ClientResponseError) {
105
+
if (err.error === 'AuthFactorTokenRequired') {
106
+
setOtp('');
107
+
setIsTotpRequired(true);
108
+
return;
109
+
}
110
+
if (err.error === 'AuthenticationRequired') {
111
+
setAuthError(`Invalid identifier or password`);
112
+
return;
113
+
}
114
+
if (err.error === 'AccountTakedown') {
115
+
setAuthError(`Account has been taken down`);
116
+
return;
117
+
}
118
+
if (err.description?.includes('Token is invalid')) {
119
+
setAuthError(`Invalid one-time confirmation code`);
120
+
setIsTotpRequired(true);
121
+
return;
122
+
}
123
+
}
124
+
if (err instanceof InsufficientLoginError) {
125
+
setAuthError(err.message);
126
+
return;
127
+
}
128
+
console.error(err);
129
+
setAuthError(`${err}`);
130
+
},
131
+
});
132
+
133
+
const isResolved = () => source() !== null;
134
+
const isAuthenticated = () => source()?.manager != null;
135
+
136
+
return (
137
+
<Accordion title="Source Account" defaultOpen>
138
+
<Subsection title="Resolve identity">
139
+
<Show when={!isResolved()}>
140
+
<form
141
+
onSubmit={(ev) => {
142
+
ev.preventDefault();
143
+
resolveMutation.mutate({ identifier: identifier() });
144
+
}}
145
+
class="flex flex-col gap-3"
146
+
>
147
+
<TextInput
148
+
label="Handle or DID"
149
+
placeholder="alice.bsky.social"
150
+
value={identifier()}
151
+
required
152
+
autofocus
153
+
onChange={setIdentifier}
154
+
/>
155
+
156
+
<Show when={resolveError()}>
157
+
<p class="text-sm text-red-600">{resolveError()}</p>
158
+
</Show>
159
+
160
+
<div>
161
+
<Button type="submit" disabled={resolveMutation.isPending}>
162
+
{resolveMutation.isPending ? 'Resolving...' : 'Resolve'}
163
+
</Button>
164
+
</div>
165
+
</form>
166
+
</Show>
167
+
168
+
<Show when={isResolved()}>
169
+
<div class="flex flex-col gap-2 text-sm">
170
+
<p>
171
+
<span class="text-gray-500">DID:</span>{' '}
172
+
<span class="font-mono">{source()!.did}</span>
173
+
</p>
174
+
<p>
175
+
<span class="text-gray-500">PDS:</span>{' '}
176
+
<span class="font-mono">{source()!.pdsUrl}</span>
177
+
</p>
178
+
<div class="mt-1">
179
+
<button
180
+
type="button"
181
+
onClick={() => setSource(null)}
182
+
class="text-sm text-purple-800 hover:underline"
183
+
>
184
+
Change account
185
+
</button>
186
+
</div>
187
+
</div>
188
+
</Show>
189
+
</Subsection>
190
+
191
+
<Show when={isResolved()}>
192
+
<Subsection title="Authenticate">
193
+
<p class="text-sm text-gray-600">
194
+
Authentication is required for some operations like exporting preferences or signing PLC operations.
195
+
</p>
196
+
197
+
<Show when={!isAuthenticated()}>
198
+
<form
199
+
onSubmit={(ev) => {
200
+
ev.preventDefault();
201
+
const src = source()!;
202
+
authMutation.mutate({
203
+
pdsUrl: src.pdsUrl,
204
+
did: src.did,
205
+
password: password(),
206
+
otp: otp(),
207
+
});
208
+
}}
209
+
class="flex flex-col gap-3"
210
+
>
211
+
<TextInput
212
+
label="Main password"
213
+
blurb="Your credentials stay entirely within your browser."
214
+
type="password"
215
+
value={password()}
216
+
required
217
+
onChange={setPassword}
218
+
/>
219
+
220
+
<Show when={isTotpRequired()}>
221
+
<TextInput
222
+
label="One-time confirmation code"
223
+
blurb="A code has been sent to your email address."
224
+
type="text"
225
+
autocomplete="one-time-code"
226
+
pattern={TOTP_RE.source}
227
+
placeholder="AAAAA-BBBBB"
228
+
value={otp()}
229
+
required
230
+
onChange={setOtp}
231
+
monospace
232
+
/>
233
+
</Show>
234
+
235
+
<Show when={authError()}>
236
+
<p class="text-sm text-red-600">{authError()}</p>
237
+
</Show>
238
+
239
+
<div>
240
+
<Button type="submit" disabled={authMutation.isPending}>
241
+
{authMutation.isPending ? 'Signing in...' : 'Sign in'}
242
+
</Button>
243
+
</div>
244
+
</form>
245
+
</Show>
246
+
247
+
<Show when={isAuthenticated()}>
248
+
<div class="flex items-center gap-2">
249
+
<StatusBadge variant="success">Signed in</StatusBadge>
250
+
<button
251
+
type="button"
252
+
onClick={() => setSource({ ...source()!, manager: null })}
253
+
class="text-sm text-purple-800 hover:underline"
254
+
>
255
+
Sign out
256
+
</button>
257
+
</div>
258
+
</Show>
259
+
</Subsection>
260
+
</Show>
261
+
</Accordion>
262
+
);
263
+
};
264
+
265
+
export default SourceAccountSection;
+46
-33
src/views/blob/blob-export.tsx
+46
-33
src/views/blob/blob-export.tsx
···
1
1
import { FileSystemWritableFileStream, showSaveFilePicker } from 'native-file-system-adapter';
2
2
import { createSignal } from 'solid-js';
3
3
4
-
import { simpleFetchHandler, XRPC, XRPCError } from '@atcute/client';
5
-
import { type AtprotoDid, getPdsEndpoint, isAtprotoDid, isHandle } from '@atcute/identity';
4
+
import { Client, ClientResponseError, ok, simpleFetchHandler } from '@atcute/client';
5
+
import { getPdsEndpoint, isAtprotoDid } from '@atcute/identity';
6
+
import { isHandle, type AtprotoDid } from '@atcute/lexicons/syntax';
6
7
import { writeTarEntry } from '@mary/tar';
7
8
8
9
import { getDidDocument } from '~/api/queries/did-doc';
9
10
import { resolveHandleViaAppView, resolveHandleViaPds } from '~/api/queries/handle';
10
11
import { isServiceUrlString } from '~/api/types/strings';
11
-
import { DID_OR_HANDLE_RE } from '~/api/utils/strings';
12
12
13
13
import { useTitle } from '~/lib/navigation/router';
14
14
import { makeAbortable } from '~/lib/utils/abortable';
···
17
17
import Button from '~/components/inputs/button';
18
18
import TextInput from '~/components/inputs/text-input';
19
19
import Logger, { createLogger } from '~/components/logger';
20
+
import PageHeader from '~/components/page-header';
20
21
21
22
const BlobExportPage = () => {
22
23
const logger = createLogger();
···
65
66
service = endpoint;
66
67
}
67
68
68
-
const rpc = new XRPC({ handler: simpleFetchHandler({ service }) });
69
+
// const rpc = new XRPC({ handler: simpleFetchHandler({ service }) });
70
+
const client = new Client({ handler: simpleFetchHandler({ service }) });
69
71
70
72
// Grab a list of blobs
71
73
let blobs: string[] = [];
···
74
76
75
77
let cursor: string | undefined;
76
78
do {
77
-
const { data } = await rpc.get('com.atproto.sync.listBlobs', {
78
-
signal,
79
-
params: { did, cursor, limit: 1_000 },
80
-
});
79
+
const data = await ok(
80
+
client.get('com.atproto.sync.listBlobs', {
81
+
signal,
82
+
params: { did, cursor, limit: 1_000 },
83
+
}),
84
+
);
81
85
82
86
cursor = data.cursor;
83
87
blobs = blobs.concat(data.cids);
···
151
155
attempts++;
152
156
153
157
try {
154
-
const { data } = await rpc.get('com.atproto.sync.getBlob', {
158
+
const response = await client.get('com.atproto.sync.getBlob', {
155
159
signal,
160
+
as: 'bytes',
156
161
params: { did, cid },
157
162
});
158
163
159
-
return data;
160
-
} catch (err) {
161
-
if (attempts > 3) {
162
-
throw err;
164
+
if (response.ok) {
165
+
return response.data;
163
166
}
164
167
165
-
if (err instanceof XRPCError) {
166
-
if (err.status === 400) {
167
-
if (err.message === 'Blob not found') {
168
-
console.warn(`Blob ${cid} not found`);
169
-
return;
170
-
}
171
-
} else if (err.status === 429) {
172
-
const reset = err.headers?.['ratelimit-reset'];
168
+
if (response.status === 400) {
169
+
// If the PDS says it can't find the blob, stop right here.
170
+
if (response.data.message === 'Blob not found') {
171
+
logger.warn(`Blob ${cid} not found`);
172
+
return undefined;
173
+
}
174
+
} else if (response.status === 429) {
175
+
// Not exposed by CORS, hoping that someday it will
176
+
const reset = response.headers.get('ratelimit-reset');
173
177
174
-
if (reset !== undefined) {
175
-
logger.warn(`Ratelimit exceeded when downloading ${cid}, waiting`);
178
+
logger.warn(`Ratelimit exceeded when downloading ${cid}, waiting`);
176
179
177
-
const refreshAt = +reset * 1_000;
178
-
const delta = refreshAt - Date.now();
180
+
if (reset !== null) {
181
+
const refreshAt = +reset * 1_000;
182
+
const delta = refreshAt - Date.now();
179
183
180
-
await sleep(delta);
181
-
}
184
+
await sleep(delta);
185
+
} else {
186
+
await sleep(10_000);
182
187
}
183
188
}
189
+
190
+
if (attempts < 3) {
191
+
continue;
192
+
}
193
+
194
+
throw new ClientResponseError(response);
195
+
} catch (err) {
196
+
// Network errors, etc
197
+
if (attempts < 3) {
198
+
continue;
199
+
}
200
+
201
+
throw err;
184
202
}
185
203
}
186
204
};
···
212
230
213
231
return (
214
232
<>
215
-
<div class="p-4">
216
-
<h1 class="text-lg font-bold text-purple-800">Export blobs</h1>
217
-
<p class="text-gray-600">Download all blobs from an account into a tarball</p>
218
-
</div>
219
-
<hr class="mx-4 border-gray-300" />
233
+
<PageHeader title="Export blobs" subtitle="Download all blobs from an account into a tarball" />
220
234
221
235
<form
222
236
onSubmit={(ev) => {
···
267
281
type="text"
268
282
name="ident"
269
283
autocomplete="username"
270
-
pattern={/* @once */ DID_OR_HANDLE_RE.source}
271
284
placeholder="paul.bsky.social"
272
285
autofocus
273
286
/>
+10
-11
src/views/bluesky/threadgate-applicator/page.tsx
+10
-11
src/views/bluesky/threadgate-applicator/page.tsx
···
1
1
import { createEffect, createSignal, onCleanup } from 'solid-js';
2
2
3
+
import { AppBskyFeedDefs, AppBskyFeedThreadgate } from '@atcute/bluesky';
3
4
import { CredentialManager } from '@atcute/client';
4
-
import { AppBskyFeedDefs, AppBskyFeedThreadgate } from '@atcute/client/lexicons';
5
-
import { DidDocument } from '@atcute/identity';
5
+
import type { DidDocument } from '@atcute/identity';
6
6
7
-
import { UnwrapArray } from '~/api/utils/types';
7
+
import type { UnwrapArray } from '~/api/utils/types';
8
8
9
9
import { history } from '~/globals/navigation';
10
10
11
11
import { useTitle } from '~/lib/navigation/router';
12
12
13
+
import PageHeader from '~/components/page-header';
13
14
import { Wizard } from '~/components/wizard';
14
15
15
16
import Step1_HandleInput from './steps/step1_handle-input';
···
18
19
import Step4_Confirmation from './steps/step4_confirmation';
19
20
import Step5_Finished from './steps/step5_finished';
20
21
21
-
export interface ThreadgateState
22
-
extends Pick<AppBskyFeedThreadgate.Record, 'allow' | 'hiddenReplies' | 'createdAt'> {
22
+
export interface ThreadgateState extends Pick<
23
+
AppBskyFeedThreadgate.Main,
24
+
'allow' | 'hiddenReplies' | 'createdAt'
25
+
> {
23
26
uri: string;
24
27
}
25
28
26
-
export type ThreadgateRule = UnwrapArray<AppBskyFeedThreadgate.Record['allow']>;
29
+
export type ThreadgateRule = UnwrapArray<AppBskyFeedThreadgate.Main['allow']>;
27
30
28
31
export interface ThreadItem {
29
32
post: AppBskyFeedDefs.PostView;
···
78
81
79
82
return (
80
83
<>
81
-
<div class="p-4">
82
-
<h1 class="text-lg font-bold text-purple-800">Retroactive thread gating</h1>
83
-
<p class="text-gray-600">Set reply permissions on all of your past Bluesky posts</p>
84
-
</div>
85
-
<hr class="mx-4 border-gray-300" />
84
+
<PageHeader title="Retroactive thread gating" subtitle="Set reply permissions on all of your past Bluesky posts" />
86
85
87
86
<Wizard<ThreadgateApplicatorConstraints>
88
87
initialStep="Step1_HandleInput"
+18
-16
src/views/bluesky/threadgate-applicator/steps/step1_handle-input.tsx
+18
-16
src/views/bluesky/threadgate-applicator/steps/step1_handle-input.tsx
···
1
1
import { createSignal } from 'solid-js';
2
2
3
-
import type { AppBskyFeedThreadgate } from '@atcute/client/lexicons';
4
-
import { type AtprotoDid, isAtprotoDid, isHandle } from '@atcute/identity';
3
+
import type { AppBskyFeedThreadgate } from '@atcute/bluesky';
4
+
import { ok } from '@atcute/client';
5
+
import { isAtprotoDid } from '@atcute/identity';
6
+
import { isHandle, type AtprotoDid } from '@atcute/lexicons/syntax';
5
7
6
8
import { getDidDocument } from '~/api/queries/did-doc';
7
9
import { resolveHandleViaAppView } from '~/api/queries/handle';
8
-
import { DID_OR_HANDLE_RE } from '~/api/utils/strings';
9
10
10
11
import { appViewRpc } from '~/globals/rpc';
11
12
···
13
14
14
15
import Button from '~/components/inputs/button';
15
16
import TextInput from '~/components/inputs/text-input';
16
-
import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard';
17
+
import { Stage, StageActions, StageErrorView, type WizardStepProps } from '~/components/wizard';
17
18
18
-
import { ThreadgateApplicatorConstraints, ThreadgateState, ThreadItem } from '../page';
19
+
import type { ThreadgateApplicatorConstraints, ThreadgateState, ThreadItem } from '../page';
19
20
import { sortThreadgateState } from '../utils';
20
21
21
22
class NoThreadsError extends Error {}
···
50
51
51
52
let cursor: string | undefined;
52
53
do {
53
-
const { data } = await appViewRpc.get('app.bsky.feed.getAuthorFeed', {
54
-
signal,
55
-
params: {
56
-
actor: did,
57
-
filter: 'posts_no_replies',
58
-
limit: 100,
59
-
cursor,
60
-
},
61
-
});
54
+
const data = await ok(
55
+
appViewRpc.get('app.bsky.feed.getAuthorFeed', {
56
+
signal,
57
+
params: {
58
+
actor: did,
59
+
filter: 'posts_no_replies',
60
+
limit: 100,
61
+
cursor,
62
+
},
63
+
}),
64
+
);
62
65
63
66
cursor = data.cursor;
64
67
···
83
86
let threadgate: ThreadgateState | null = null;
84
87
85
88
if (tg?.record) {
86
-
const record = tg.record as AppBskyFeedThreadgate.Record;
89
+
const record = tg.record as AppBskyFeedThreadgate.Main;
87
90
88
91
const allow = record?.allow;
89
92
const hiddenReplies = record?.hiddenReplies;
···
153
156
placeholder="paul.bsky.social"
154
157
value={identifier()}
155
158
required
156
-
pattern={/* @once */ DID_OR_HANDLE_RE.source}
157
159
autofocus={isActive()}
158
160
onChange={setIdentifier}
159
161
/>
+19
-26
src/views/bluesky/threadgate-applicator/steps/step2_rules-input.tsx
+19
-26
src/views/bluesky/threadgate-applicator/steps/step2_rules-input.tsx
···
1
1
import { batch, createMemo, createSignal, For, Show } from 'solid-js';
2
2
3
-
import { AppBskyFeedThreadgate, Brand } from '@atcute/client/lexicons';
4
-
5
-
import { UnwrapArray } from '~/api/utils/types';
3
+
import { AppBskyFeedThreadgate } from '@atcute/bluesky';
4
+
import { ok } from '@atcute/client';
5
+
import type { $type } from '@atcute/lexicons';
6
6
7
7
import { appViewRpc } from '~/globals/rpc';
8
8
···
11
11
import { createQuery } from '~/lib/utils/query';
12
12
13
13
import RadioInput from '~/components/inputs/radio-input';
14
-
import { Stage, StageActions, WizardStepProps } from '~/components/wizard';
14
+
import { Stage, StageActions, type WizardStepProps } from '~/components/wizard';
15
15
16
16
import CircularProgressView from '~/components/circular-progress-view';
17
17
import Button from '~/components/inputs/button';
18
18
import ToggleInput from '~/components/inputs/toggle-input';
19
19
20
-
import { ThreadgateApplicatorConstraints } from '../page';
20
+
import type { ThreadgateApplicatorConstraints, ThreadgateRule } from '../page';
21
21
import { sortThreadgateAllow } from '../utils';
22
22
23
23
const enum FilterType {
···
30
30
NO_ONE = 'no_one',
31
31
CUSTOM = 'custom',
32
32
}
33
-
34
-
type ThreadRule = UnwrapArray<AppBskyFeedThreadgate.Record['allow']>;
35
33
36
34
const Step2_RulesInput = ({
37
35
data,
···
41
39
}: WizardStepProps<ThreadgateApplicatorConstraints, 'Step2_RulesInput'>) => {
42
40
const [filter, setFilter] = createSignal(FilterType.MISSING_ONLY);
43
41
44
-
const [threadRules, _setThreadRules] = createSignal<ThreadRule[] | undefined>([
42
+
const [threadRules, _setThreadRules] = createSignal<ThreadgateRule[] | undefined>([
45
43
{ $type: 'app.bsky.feed.threadgate#followingRule' },
46
44
{ $type: 'app.bsky.feed.threadgate#mentionRule' },
47
45
]);
···
64
62
() => data.profile.didDoc.id,
65
63
async (did, signal) => {
66
64
const lists = await accumulate(async (cursor) => {
67
-
const { data } = await appViewRpc.get('app.bsky.graph.getLists', {
68
-
signal,
69
-
params: {
70
-
actor: did,
71
-
cursor,
72
-
limit: 100,
73
-
},
74
-
});
65
+
const data = await ok(
66
+
appViewRpc.get('app.bsky.graph.getLists', {
67
+
signal,
68
+
params: {
69
+
actor: did,
70
+
cursor,
71
+
limit: 100,
72
+
},
73
+
}),
74
+
);
75
75
76
76
return {
77
77
cursor: data.cursor,
···
121
121
);
122
122
});
123
123
124
-
const hasThreadRule = (predicate: ThreadRule): boolean => {
124
+
const hasThreadRule = (predicate: ThreadgateRule): boolean => {
125
125
return !!threadRules()?.find((rule) => dequal(rule, predicate));
126
126
};
127
127
128
-
const setCustomThreadRules = (next: ThreadRule[] | undefined) => {
128
+
const setCustomThreadRules = (next: ThreadgateRule[] | undefined) => {
129
129
batch(() => {
130
130
_setThreadRules(next);
131
131
setThreadRulesPreset(ThreadRulePreset.CUSTOM);
···
226
226
}
227
227
>
228
228
{(list) => {
229
-
const rule: Brand.Union<AppBskyFeedThreadgate.ListRule> = {
229
+
const rule: $type.enforce<AppBskyFeedThreadgate.ListRule> = {
230
230
$type: 'app.bsky.feed.threadgate#listRule',
231
231
list: list.uri,
232
232
};
···
255
255
blurb={
256
256
<>
257
257
<span>This will apply to {filteredThreads().length} threads. </span>
258
-
{/* <button
259
-
type="button"
260
-
hidden={filteredThreads().length < 1}
261
-
class="font-medium text-purple-800 hover:underline"
262
-
>
263
-
View
264
-
</button> */}
265
258
</>
266
259
}
267
260
value={filter()}
+2
-2
src/views/bluesky/threadgate-applicator/steps/step3_authentication.tsx
+2
-2
src/views/bluesky/threadgate-applicator/steps/step3_authentication.tsx
···
2
2
3
3
import { CredentialManager } from '@atcute/client';
4
4
5
-
import { WizardStepProps } from '~/components/wizard';
5
+
import type { WizardStepProps } from '~/components/wizard';
6
6
import BlueskyLoginStep from '~/components/wizards/bluesky-login-step';
7
7
8
-
import { ThreadgateApplicatorConstraints } from '../page';
8
+
import type { ThreadgateApplicatorConstraints } from '../page';
9
9
10
10
const Step3_Authentication = ({
11
11
data,
+70
-52
src/views/bluesky/threadgate-applicator/steps/step4_confirmation.tsx
+70
-52
src/views/bluesky/threadgate-applicator/steps/step4_confirmation.tsx
···
1
1
import { createSignal, Show } from 'solid-js';
2
2
3
-
import { XRPC, XRPCError } from '@atcute/client';
4
-
import type { AppBskyFeedThreadgate, ComAtprotoRepoApplyWrites } from '@atcute/client/lexicons';
3
+
import type { ComAtprotoRepoApplyWrites } from '@atcute/atproto';
4
+
import type { AppBskyFeedThreadgate } from '@atcute/bluesky';
5
+
import { Client, ClientResponseError } from '@atcute/client';
6
+
import { parseCanonicalResourceUri } from '@atcute/lexicons';
5
7
import { chunked } from '@mary/array-fns';
6
-
7
-
import { parseAddressedAtUri } from '~/api/utils/at-uri';
8
8
9
9
import { dequal } from '~/lib/utils/dequal';
10
10
import { createMutation } from '~/lib/utils/mutation';
···
12
12
import Button from '~/components/inputs/button';
13
13
import ToggleInput from '~/components/inputs/toggle-input';
14
14
import Logger, { createLogger } from '~/components/logger';
15
-
import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard';
15
+
import { Stage, StageActions, StageErrorView, type WizardStepProps } from '~/components/wizard';
16
16
17
-
import { ThreadgateApplicatorConstraints } from '../page';
17
+
import type { ThreadgateApplicatorConstraints } from '../page';
18
18
19
19
const Step4_Confirmation = ({
20
20
data,
···
34
34
logger.log(`Preparing writes`);
35
35
36
36
const rules = data.rules;
37
-
const writes: ComAtprotoRepoApplyWrites.Input['writes'] = [];
37
+
const writes: ComAtprotoRepoApplyWrites.$input['writes'] = [];
38
38
39
39
const now = new Date().toISOString();
40
40
for (const { post, threadgate } of data.threads) {
41
41
if (threadgate === null) {
42
42
if (rules !== undefined) {
43
-
const { rkey } = parseAddressedAtUri(post.uri);
43
+
const postUri = parseCanonicalResourceUri(post.uri);
44
+
if (!postUri.ok) {
45
+
throw new Error(`failed to parse ${post.uri}`);
46
+
}
44
47
45
-
const record: AppBskyFeedThreadgate.Record = {
48
+
const record: AppBskyFeedThreadgate.Main = {
46
49
$type: 'app.bsky.feed.threadgate',
47
50
createdAt: now,
48
51
post: post.uri,
···
53
56
writes.push({
54
57
$type: 'com.atproto.repo.applyWrites#create',
55
58
collection: 'app.bsky.feed.threadgate',
56
-
rkey: rkey,
59
+
rkey: postUri.value.rkey,
57
60
value: record,
58
61
});
59
62
}
60
63
} else {
61
64
if (rules === undefined && !threadgate.hiddenReplies?.length) {
62
-
const { rkey } = parseAddressedAtUri(threadgate.uri);
65
+
const threadgateUri = parseCanonicalResourceUri(threadgate.uri);
66
+
if (!threadgateUri.ok) {
67
+
throw new Error(`failed to parse ${threadgate.uri}`);
68
+
}
63
69
64
70
writes.push({
65
71
$type: 'com.atproto.repo.applyWrites#delete',
66
72
collection: 'app.bsky.feed.threadgate',
67
-
rkey: rkey,
73
+
rkey: threadgateUri.value.rkey,
68
74
});
69
75
} else if (!dequal(threadgate.allow, rules)) {
70
-
const { rkey } = parseAddressedAtUri(threadgate.uri);
76
+
const threadgateUri = parseCanonicalResourceUri(threadgate.uri);
77
+
if (!threadgateUri.ok) {
78
+
throw new Error(`failed to parse ${threadgate.uri}`);
79
+
}
71
80
72
-
const record: AppBskyFeedThreadgate.Record = {
81
+
const record: AppBskyFeedThreadgate.Main = {
73
82
$type: 'app.bsky.feed.threadgate',
74
83
createdAt: threadgate.createdAt,
75
84
post: post.uri,
···
80
89
writes.push({
81
90
$type: 'com.atproto.repo.applyWrites#update',
82
91
collection: 'app.bsky.feed.threadgate',
83
-
rkey: rkey,
92
+
rkey: threadgateUri.value.rkey,
84
93
value: record,
85
94
});
86
95
}
···
90
99
logger.log(`${writes.length} write operations to apply`);
91
100
92
101
const did = data.profile.didDoc.id;
93
-
const rpc = new XRPC({ handler: data.manager });
94
-
95
-
const RATELIMIT_POINT_LIMIT = 150 * 3;
102
+
const client = new Client({ handler: data.manager });
96
103
97
104
{
98
105
using progress = logger.progress(`Applying writes`);
99
106
100
107
let written = 0;
101
108
for (const chunk of chunked(writes, 200)) {
102
-
try {
103
-
const { headers } = await rpc.call('com.atproto.repo.applyWrites', {
104
-
data: {
105
-
repo: did,
106
-
writes: chunk,
107
-
},
108
-
});
109
+
let attempts = 0;
109
110
110
-
written += chunk.length;
111
-
progress.update(`Applying writes (${written} applied)`);
111
+
while (true) {
112
+
if (attempts > 0) {
113
+
await sleep(2_000);
114
+
}
112
115
113
-
if ('ratelimit-remaining' in headers) {
114
-
const remaining = +headers['ratelimit-remaining'];
115
-
const reset = +headers['ratelimit-reset'] * 1_000;
116
+
attempts++;
116
117
117
-
if (remaining < RATELIMIT_POINT_LIMIT) {
118
-
// add some delay to be sure
119
-
const delta = reset - Date.now() + 5_000;
120
-
using _progress = logger.progress(`Reached ratelimit, waiting ${delta}ms`);
118
+
try {
119
+
const response = await client.post('com.atproto.repo.applyWrites', {
120
+
input: {
121
+
repo: did,
122
+
writes: chunk,
123
+
},
124
+
});
121
125
122
-
await new Promise((resolve) => setTimeout(resolve, delta));
126
+
if (response.ok) {
127
+
written += chunk.length;
128
+
progress.update(`Applying writes (${written} applied)`);
129
+
break;
123
130
}
124
-
}
125
-
} catch (err) {
126
-
if (!(err instanceof XRPCError) || err.kind !== 'RateLimitExceeded') {
127
-
throw err;
128
-
}
131
+
132
+
if (response.status === 429) {
133
+
// not exposed by CORS, hoping that someday it will
134
+
const reset = response.headers.get('ratelimit-reset');
135
+
136
+
using _progress = logger.progress(`Ratelimited, waiting`);
137
+
138
+
if (reset !== null) {
139
+
const refreshAt = +reset * 1_000;
140
+
const delta = refreshAt - Date.now();
129
141
130
-
const headers = err.headers;
131
-
if ('ratelimit-remaining' in headers) {
132
-
const remaining = +headers['ratelimit-remaining'];
133
-
const reset = +headers['ratelimit-reset'] * 1_000;
142
+
await sleep(delta);
143
+
} else {
144
+
await sleep(10_000);
145
+
}
146
+
}
134
147
135
-
if (remaining < RATELIMIT_POINT_LIMIT) {
136
-
// add some delay to be sure
137
-
const delta = reset - Date.now() + 5_000;
138
-
using _progress = logger.progress(`Ratelimited, waiting ${delta}ms`);
148
+
if (attempts < 3) {
149
+
continue;
150
+
}
139
151
140
-
await new Promise((resolve) => setTimeout(resolve, delta));
152
+
throw new ClientResponseError(response);
153
+
} catch (err) {
154
+
// Network errors, etc
155
+
if (attempts < 3) {
156
+
continue;
141
157
}
142
-
} else {
143
-
using _progress = logger.progress(`Ratelimited, waiting`);
144
158
145
-
await new Promise((resolve) => setTimeout(resolve, 60 * 1_000));
159
+
throw err;
146
160
}
147
161
}
148
162
}
···
202
216
};
203
217
204
218
export default Step4_Confirmation;
219
+
220
+
const sleep = (ms: number): Promise<void> => {
221
+
return new Promise((resolve) => setTimeout(resolve, ms));
222
+
};
+2
-2
src/views/bluesky/threadgate-applicator/steps/step5_finished.tsx
+2
-2
src/views/bluesky/threadgate-applicator/steps/step5_finished.tsx
···
1
-
import { Stage, WizardStepProps } from '~/components/wizard';
1
+
import { Stage, type WizardStepProps } from '~/components/wizard';
2
2
3
-
import { ThreadgateApplicatorConstraints } from '../page';
3
+
import type { ThreadgateApplicatorConstraints } from '../page';
4
4
5
5
export const Step5_Finished = ({}: WizardStepProps<ThreadgateApplicatorConstraints, 'Step5_Finished'>) => {
6
6
return (
+1
-1
src/views/bluesky/threadgate-applicator/utils.ts
+1
-1
src/views/bluesky/threadgate-applicator/utils.ts
+3
-6
src/views/crypto/crypto-generate.tsx
+3
-6
src/views/crypto/crypto-generate.tsx
···
6
6
7
7
import Button from '~/components/inputs/button';
8
8
import RadioInput from '~/components/inputs/radio-input';
9
+
import PageHeader from '~/components/page-header';
9
10
10
11
type KeyType = 'p256' | 'secp256k1';
11
12
···
26
27
27
28
return (
28
29
<>
29
-
<div class="p-4">
30
-
<h1 class="text-lg font-bold text-purple-800">Generate secret keys</h1>
31
-
<p class="text-gray-600">Create a new secp256k1/nistp256 keypair</p>
32
-
</div>
33
-
<hr class="mx-4 border-gray-300" />
30
+
<PageHeader title="Generate secret keys" subtitle="Create a new secp256k1/nistp256 keypair" />
34
31
35
32
<form
36
33
onSubmit={async (ev) => {
···
54
51
]);
55
52
56
53
const result: KeypairResult = {
57
-
type: keypair.type,
54
+
type: keypair.type as KeyType,
58
55
publicDidKey,
59
56
privateHex,
60
57
privateMultikey,
+255
src/views/crypto/crypto-info.tsx
+255
src/views/crypto/crypto-info.tsx
···
1
+
import { createMemo, createSignal, Match, Show, Switch } from 'solid-js';
2
+
3
+
import {
4
+
type DidKeyString,
5
+
P256PrivateKeyExportable,
6
+
P256PublicKey,
7
+
parseDidKey,
8
+
parsePrivateMultikey,
9
+
parsePublicMultikey,
10
+
Secp256k1PrivateKeyExportable,
11
+
Secp256k1PublicKey,
12
+
} from '@atcute/crypto';
13
+
import { fromBase16 } from '@atcute/multibase';
14
+
15
+
import { useTitle } from '~/lib/navigation/router';
16
+
17
+
import Button from '~/components/inputs/button';
18
+
import RadioInput from '~/components/inputs/radio-input';
19
+
import TextInput from '~/components/inputs/text-input';
20
+
import PageHeader from '~/components/page-header';
21
+
22
+
type KeyType = 'p256' | 'secp256k1';
23
+
type KeyFormat = 'did:key' | 'multikey' | 'hex';
24
+
25
+
interface KeyInfo {
26
+
keyType: KeyType;
27
+
isPrivate: boolean;
28
+
inputFormat: KeyFormat;
29
+
publicDidKey: DidKeyString;
30
+
publicMultikey: string;
31
+
privateHex?: string;
32
+
privateMultikey?: string;
33
+
}
34
+
35
+
const DID_KEY_REGEX = /^did:key:z[a-km-zA-HJ-NP-Z1-9]+$/;
36
+
const MULTIKEY_REGEX = /^z[a-km-zA-HJ-NP-Z1-9]+$/;
37
+
const HEX_REGEX = /^[0-9a-f]+$/;
38
+
39
+
const CryptoInfoPage = () => {
40
+
const [input, setInput] = createSignal('');
41
+
const [hexKeyType, setHexKeyType] = createSignal<KeyType>();
42
+
const [result, setResult] = createSignal<KeyInfo>();
43
+
const [error, setError] = createSignal<string>();
44
+
45
+
const detectedFormat = createMemo((): KeyFormat | undefined => {
46
+
const $input = input().trim();
47
+
48
+
if (DID_KEY_REGEX.test($input)) {
49
+
return 'did:key';
50
+
}
51
+
if (MULTIKEY_REGEX.test($input)) {
52
+
return 'multikey';
53
+
}
54
+
if (HEX_REGEX.test($input)) {
55
+
return 'hex';
56
+
}
57
+
});
58
+
59
+
const canSubmit = createMemo(() => {
60
+
const format = detectedFormat();
61
+
if (!format) {
62
+
return false;
63
+
}
64
+
if (format === 'hex' && !hexKeyType()) {
65
+
return false;
66
+
}
67
+
return true;
68
+
});
69
+
70
+
useTitle(() => `View crypto key info โ boat`);
71
+
72
+
return (
73
+
<>
74
+
<PageHeader title="View crypto key info" subtitle="Show basic metadata about a public or private key" />
75
+
76
+
<form
77
+
onSubmit={async (ev) => {
78
+
ev.preventDefault();
79
+
80
+
const $input = input().trim();
81
+
const format = detectedFormat();
82
+
83
+
setResult();
84
+
setError();
85
+
86
+
try {
87
+
let info: KeyInfo;
88
+
89
+
if (format === 'did:key') {
90
+
const parsed = parseDidKey($input);
91
+
const pubKey =
92
+
parsed.type === 'p256'
93
+
? await P256PublicKey.importRaw(parsed.publicKeyBytes)
94
+
: await Secp256k1PublicKey.importRaw(parsed.publicKeyBytes);
95
+
96
+
info = {
97
+
keyType: parsed.type,
98
+
isPrivate: false,
99
+
inputFormat: 'did:key',
100
+
publicDidKey: await pubKey.exportPublicKey('did'),
101
+
publicMultikey: await pubKey.exportPublicKey('multikey'),
102
+
};
103
+
} else if (format === 'multikey') {
104
+
// try parsing as private key first
105
+
try {
106
+
const parsed = parsePrivateMultikey($input);
107
+
const privKey =
108
+
parsed.type === 'p256'
109
+
? await P256PrivateKeyExportable.importRaw(parsed.privateKeyBytes)
110
+
: await Secp256k1PrivateKeyExportable.importRaw(parsed.privateKeyBytes);
111
+
112
+
info = {
113
+
keyType: parsed.type,
114
+
isPrivate: true,
115
+
inputFormat: 'multikey',
116
+
publicDidKey: await privKey.exportPublicKey('did'),
117
+
publicMultikey: await privKey.exportPublicKey('multikey'),
118
+
privateHex: await privKey.exportPrivateKey('rawHex'),
119
+
privateMultikey: await privKey.exportPrivateKey('multikey'),
120
+
};
121
+
} catch {
122
+
// try parsing as public key
123
+
const parsed = parsePublicMultikey($input);
124
+
const pubKey =
125
+
parsed.type === 'p256'
126
+
? await P256PublicKey.importRaw(parsed.publicKeyBytes)
127
+
: await Secp256k1PublicKey.importRaw(parsed.publicKeyBytes);
128
+
129
+
info = {
130
+
keyType: parsed.type,
131
+
isPrivate: false,
132
+
inputFormat: 'multikey',
133
+
publicDidKey: await pubKey.exportPublicKey('did'),
134
+
publicMultikey: await pubKey.exportPublicKey('multikey'),
135
+
};
136
+
}
137
+
} else if (format === 'hex') {
138
+
const keyType = hexKeyType()!;
139
+
const privateKeyBytes = fromBase16($input);
140
+
141
+
const privKey =
142
+
keyType === 'p256'
143
+
? await P256PrivateKeyExportable.importRaw(privateKeyBytes)
144
+
: await Secp256k1PrivateKeyExportable.importRaw(privateKeyBytes);
145
+
146
+
info = {
147
+
keyType: keyType,
148
+
isPrivate: true,
149
+
inputFormat: 'hex',
150
+
publicDidKey: await privKey.exportPublicKey('did'),
151
+
publicMultikey: await privKey.exportPublicKey('multikey'),
152
+
privateHex: await privKey.exportPrivateKey('rawHex'),
153
+
privateMultikey: await privKey.exportPrivateKey('multikey'),
154
+
};
155
+
} else {
156
+
throw new Error('Unknown key format');
157
+
}
158
+
159
+
setResult(info);
160
+
} catch (err) {
161
+
console.error(err);
162
+
setError(`Failed to parse key: ${err}`);
163
+
}
164
+
}}
165
+
class="flex flex-col gap-4 p-4"
166
+
>
167
+
<TextInput
168
+
label="Public or private key"
169
+
blurb="Accepts did:key, multikey, or hex format"
170
+
monospace
171
+
autocomplete="off"
172
+
autocorrect="off"
173
+
placeholder="did:key:z... or z... or a5973930f9d348..."
174
+
value={input()}
175
+
required
176
+
onChange={setInput}
177
+
/>
178
+
179
+
<Show when={detectedFormat() === 'hex'}>
180
+
<RadioInput
181
+
label="This is a..."
182
+
value={hexKeyType()}
183
+
required
184
+
options={[
185
+
{ value: 'secp256k1', label: `ES256K (secp256k1) private key` },
186
+
{ value: 'p256', label: `ES256 (p256) private key` },
187
+
]}
188
+
onChange={setHexKeyType}
189
+
/>
190
+
</Show>
191
+
192
+
<div>
193
+
<Button type="submit" disabled={!canSubmit()}>
194
+
Inspect
195
+
</Button>
196
+
</div>
197
+
</form>
198
+
199
+
<hr class="mx-4 border-gray-300" />
200
+
201
+
<Switch>
202
+
<Match when={error()}>
203
+
<div class="p-4 text-red-600">{error()}</div>
204
+
</Match>
205
+
206
+
<Match when={result()} keyed>
207
+
{(info) => (
208
+
<div class="flex flex-col gap-6 break-words p-4 text-gray-900">
209
+
<div>
210
+
<p class="font-semibold text-gray-600">Key type</p>
211
+
<span>
212
+
{/* @once */ info.keyType === 'p256'
213
+
? 'ES256 (p256)'
214
+
: 'ES256K (secp256k1)'}{' '}
215
+
{/* @once */ info.isPrivate ? 'private' : 'public'} key
216
+
</span>
217
+
</div>
218
+
219
+
<div>
220
+
<p class="font-semibold text-gray-600">Input encoding</p>
221
+
<span>{/* @once */ info.inputFormat}</span>
222
+
</div>
223
+
224
+
<div>
225
+
<p class="font-semibold text-gray-600">Public key (did:key)</p>
226
+
<span class="font-mono">{/* @once */ info.publicDidKey}</span>
227
+
</div>
228
+
229
+
<div>
230
+
<p class="font-semibold text-gray-600">Public key (multikey)</p>
231
+
<span class="font-mono">{/* @once */ info.publicMultikey}</span>
232
+
</div>
233
+
234
+
<Show when={info.privateHex}>
235
+
<div>
236
+
<p class="font-semibold text-gray-600">Private key (hex)</p>
237
+
<span class="font-mono">{/* @once */ info.privateHex}</span>
238
+
</div>
239
+
</Show>
240
+
241
+
<Show when={info.privateMultikey}>
242
+
<div>
243
+
<p class="font-semibold text-gray-600">Private key (multikey)</p>
244
+
<span class="font-mono">{/* @once */ info.privateMultikey}</span>
245
+
</div>
246
+
</Show>
247
+
</div>
248
+
)}
249
+
</Match>
250
+
</Switch>
251
+
</>
252
+
);
253
+
};
254
+
255
+
export default CryptoInfoPage;
+6
-8
src/views/frontpage.tsx
+6
-8
src/views/frontpage.tsx
···
1
-
import { Component, ComponentProps } from 'solid-js';
1
+
import type { Component, ComponentProps } from 'solid-js';
2
2
3
3
import { useTitle } from '~/lib/navigation/router';
4
+
5
+
import PageHeader from '~/components/page-header';
4
6
5
7
import HistoryIcon from '~/components/ic-icons/baseline-history';
6
8
import KeyIcon from '~/components/ic-icons/baseline-key';
···
102
104
{
103
105
name: `Migrate account`,
104
106
description: `Move your account data to another server`,
105
-
href: null,
107
+
href: '/account-migrate',
106
108
icon: MoveUpOutlinedIcon,
107
109
},
108
110
],
···
119
121
{
120
122
name: `View crypto key info`,
121
123
description: `Show basic metadata about a public or private key`,
122
-
href: null,
124
+
href: `/crypto-info`,
123
125
icon: KeyVisualizerIcon,
124
126
},
125
127
],
···
170
172
171
173
return (
172
174
<>
173
-
<div class="p-4">
174
-
<h1 class="text-lg font-bold text-purple-800">boat</h1>
175
-
<p class="text-gray-600">handy online tools for AT Protocol</p>
176
-
</div>
177
-
<hr class="mx-4 border-gray-300" />
175
+
<PageHeader title="boat" subtitle="handy online tools for AT Protocol" />
178
176
179
177
<div class="flex grow flex-col pb-2">{nodes}</div>
180
178
+20
-32
src/views/identity/did-lookup.tsx
+20
-32
src/views/identity/did-lookup.tsx
···
1
1
import { Match, Switch } from 'solid-js';
2
2
3
-
import { isAtprotoDid, isHandle, type AtprotoDid, type Did, type Handle } from '@atcute/identity';
3
+
import { isAtprotoDid } from '@atcute/identity';
4
+
import { isHandle, type AtprotoDid, type Did, type Handle } from '@atcute/lexicons/syntax';
4
5
5
6
import { getDidDocument } from '~/api/queries/did-doc';
6
7
import { resolveHandleViaAppView } from '~/api/queries/handle';
7
8
import { isServiceUrlString } from '~/api/types/strings';
8
-
import { DID_OR_HANDLE_RE } from '~/api/utils/strings';
9
9
10
10
import { useTitle } from '~/lib/navigation/router';
11
11
import { createQuery } from '~/lib/utils/query';
···
15
15
import ErrorView from '~/components/error-view';
16
16
import Button from '~/components/inputs/button';
17
17
import TextInput from '~/components/inputs/text-input';
18
+
import PageHeader from '~/components/page-header';
18
19
19
20
const DidLookupPage = () => {
20
21
const [params, setParams] = useSearchParams({
···
46
47
47
48
return (
48
49
<>
49
-
<div class="p-4">
50
-
<h1 class="text-lg font-bold text-purple-800">View identity info</h1>
51
-
<p class="text-gray-600">Look up an account's DID document</p>
52
-
</div>
53
-
<hr class="mx-4 border-gray-300" />
50
+
<PageHeader title="View identity info" subtitle="Look up an account's DID document" />
54
51
55
52
<form
56
53
onSubmit={(ev) => {
···
67
64
type="text"
68
65
name="ident"
69
66
autocomplete="username"
70
-
pattern={/* @once */ DID_OR_HANDLE_RE.source}
71
67
placeholder="paul.bsky.social"
72
68
autofocus
73
69
/>
···
101
97
102
98
<div>
103
99
<p class="font-semibold text-gray-600">Identifies as</p>
104
-
<ol class="list-disc pl-4">{doc.alsoKnownAs?.map((ident) => <li>{ident}</li>)}</ol>
100
+
<ol class="list-disc pl-4">
101
+
{doc.alsoKnownAs?.map((ident) => (
102
+
<li>{ident}</li>
103
+
))}
104
+
</ol>
105
105
</div>
106
106
107
107
<div>
···
130
130
131
131
<div class="mt-2 flex flex-wrap gap-2 empty:hidden">
132
132
{isPDS && isServiceUrl && (
133
-
<button
134
-
disabled
135
-
class="flex h-9 select-none items-center rounded border border-gray-300 px-4 text-sm font-semibold text-gray-800 hover:bg-gray-100 active:bg-gray-100 disabled:pointer-events-none disabled:opacity-50"
136
-
>
133
+
<Button variant="outline" disabled>
137
134
View PDS info
138
-
</button>
135
+
</Button>
139
136
)}
140
137
141
138
{isPDS && isServiceUrl && (
142
-
<button
143
-
disabled
144
-
class="flex h-9 select-none items-center rounded border border-gray-300 px-4 text-sm font-semibold text-gray-800 hover:bg-gray-100 active:bg-gray-100 disabled:pointer-events-none disabled:opacity-50"
145
-
>
139
+
<Button variant="outline" disabled>
146
140
Explore account repository
147
-
</button>
141
+
</Button>
148
142
)}
149
143
150
144
{isLabeler && isServiceUrl && (
151
-
<button
152
-
disabled
153
-
class="flex h-9 select-none items-center rounded border border-gray-300 px-4 text-sm font-semibold text-gray-800 hover:bg-gray-100 active:bg-gray-100 disabled:pointer-events-none disabled:opacity-50"
154
-
>
145
+
<Button variant="outline" disabled>
155
146
View emitted labels
156
-
</button>
147
+
</Button>
157
148
)}
158
149
</div>
159
150
</li>
···
182
173
</div>
183
174
184
175
<div class="flex flex-wrap gap-4 p-4 pt-2">
185
-
<button
176
+
<Button
177
+
variant="outline"
186
178
onClick={() => {
187
179
navigator.clipboard.writeText(JSON.stringify(doc, null, 2));
188
180
}}
189
-
class="flex h-9 select-none items-center rounded border border-gray-300 px-4 text-sm font-semibold text-gray-800 hover:bg-gray-100 active:bg-gray-100"
190
181
>
191
182
Copy DID document
192
-
</button>
183
+
</Button>
193
184
194
185
{isDidPlc && (
195
-
<a
196
-
href={`/plc-oplogs?q=${params.q!}`}
197
-
class="flex h-9 select-none items-center rounded border border-gray-300 px-4 text-sm font-semibold text-gray-800 hover:bg-gray-100 active:bg-gray-100"
198
-
>
186
+
<Button variant="outline" href={`/plc-oplogs?q=${params.q!}`}>
199
187
View PLC operation logs
200
-
</a>
188
+
</Button>
201
189
)}
202
190
</div>
203
191
</>
+7
-9
src/views/identity/plc-applicator/page.tsx
+7
-9
src/views/identity/plc-applicator/page.tsx
···
1
1
import { createEffect, createSignal, onCleanup } from 'solid-js';
2
2
3
+
import type { ComAtprotoIdentityGetRecommendedDidCredentials } from '@atcute/atproto';
3
4
import type { CredentialManager } from '@atcute/client';
4
-
import type { ComAtprotoIdentityGetRecommendedDidCredentials } from '@atcute/client/lexicons';
5
5
import type { P256PrivateKey, Secp256k1PrivateKey } from '@atcute/crypto';
6
6
import type { CompatibleOperation, IndexedEntry, IndexedEntryWithSigner } from '@atcute/did-plc';
7
-
import type { Did, DidDocument } from '@atcute/identity';
7
+
import type { DidDocument } from '@atcute/identity';
8
+
import type { Did } from '@atcute/lexicons/syntax';
8
9
9
-
import { UpdatePayload } from '~/api/types/plc';
10
+
import type { UpdatePayload } from '~/api/types/plc';
10
11
11
12
import { history } from '~/globals/navigation';
12
13
13
14
import { useTitle } from '~/lib/navigation/router';
14
15
16
+
import PageHeader from '~/components/page-header';
15
17
import { Wizard } from '~/components/wizard';
16
18
17
19
import Step1_HandleInput from './steps/step1_handle-input';
···
31
33
export interface PdsSigningMethod {
32
34
type: 'pds';
33
35
manager: CredentialManager;
34
-
recommendedDidDoc: ComAtprotoIdentityGetRecommendedDidCredentials.Output;
36
+
recommendedDidDoc: ComAtprotoIdentityGetRecommendedDidCredentials.$output;
35
37
}
36
38
37
39
export type Keypair = P256PrivateKey | Secp256k1PrivateKey;
···
100
102
101
103
return (
102
104
<>
103
-
<div class="p-4">
104
-
<h1 class="text-lg font-bold text-purple-800">Apply PLC operations</h1>
105
-
<p class="text-gray-600">Submit operations to your did:plc identity</p>
106
-
</div>
107
-
<hr class="mx-4 border-gray-300" />
105
+
<PageHeader title="Apply PLC operations" subtitle="Submit operations to your did:plc identity" />
108
106
109
107
<Wizard<PlcApplicatorConstraints>
110
108
initialStep="Step1_HandleInput"
+1
-1
src/views/identity/plc-applicator/plc-utils.ts
+1
-1
src/views/identity/plc-applicator/plc-utils.ts
+13
-12
src/views/identity/plc-applicator/steps/step1_handle-input.tsx
+13
-12
src/views/identity/plc-applicator/steps/step1_handle-input.tsx
···
1
1
import { createSignal } from 'solid-js';
2
2
3
-
import { XRPCError } from '@atcute/client';
3
+
import { ClientResponseError } from '@atcute/client';
4
4
import { processIndexedEntryLog } from '@atcute/did-plc';
5
-
import { type Did, isHandle, isPlcDid } from '@atcute/identity';
5
+
import { isPlcDid } from '@atcute/identity';
6
+
import { isHandle, type Did } from '@atcute/lexicons/syntax';
6
7
7
8
import { getDidDocument } from '~/api/queries/did-doc';
8
9
import { resolveHandleViaAppView } from '~/api/queries/handle';
9
10
import { getPlcAuditLogs } from '~/api/queries/plc';
10
-
import { DID_OR_HANDLE_RE } from '~/api/utils/strings';
11
11
12
12
import { createMutation } from '~/lib/utils/mutation';
13
13
14
14
import Button from '~/components/inputs/button';
15
15
import RadioInput from '~/components/inputs/radio-input';
16
16
import TextInput from '~/components/inputs/text-input';
17
-
import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard';
17
+
import { Stage, StageActions, StageErrorView, type WizardStepProps } from '~/components/wizard';
18
18
19
-
import { type PlcInformation, PlcApplicatorConstraints } from '../page';
19
+
import type { PlcApplicatorConstraints, PlcInformation } from '../page';
20
20
21
21
type Method = 'pds' | 'key';
22
22
···
70
70
onNext('Step2_PrivateKeyInput', { info });
71
71
}
72
72
},
73
-
onError(error) {
73
+
onError(err) {
74
74
let message: string | undefined;
75
75
76
-
if (error instanceof XRPCError) {
77
-
if (error.kind === 'InvalidRequest' && error.message.includes('resolve handle')) {
76
+
if (err instanceof ClientResponseError) {
77
+
if (err.error === 'InvalidRequest' && err.description?.includes('resolve handle')) {
78
78
message = `Can't seem to resolve handle, is it typed correctly?`;
79
79
}
80
-
} else if (error instanceof DidIsNotPlcError) {
81
-
message = error.message;
80
+
} else if (err instanceof DidIsNotPlcError) {
81
+
message = err.message;
82
82
}
83
83
84
84
if (message !== undefined) {
85
85
setError(message);
86
86
} else {
87
-
setError(`Something went wrong: ${error}`);
87
+
console.error(err);
88
+
89
+
setError(`Something went wrong: ${err}`);
88
90
}
89
91
},
90
92
});
···
105
107
placeholder="paul.bsky.social"
106
108
value={identifier()}
107
109
required
108
-
pattern={/* @once */ DID_OR_HANDLE_RE.source}
109
110
autofocus={isActive()}
110
111
onChange={setIdentifier}
111
112
/>
+16
-19
src/views/identity/plc-applicator/steps/step2_pds-authentication.tsx
+16
-19
src/views/identity/plc-applicator/steps/step2_pds-authentication.tsx
···
1
1
import { createSignal, Match, Show, Switch } from 'solid-js';
2
2
3
-
import { AtpAccessJwt, CredentialManager, XRPC, XRPCError } from '@atcute/client';
4
-
import { decodeJwt } from '@atcute/client/utils/jwt';
3
+
import { type AtpAccessJwt, Client, ClientResponseError, CredentialManager, ok } from '@atcute/client';
5
4
import { getPdsEndpoint } from '@atcute/identity';
6
5
7
6
import { formatTotpCode, TOTP_RE } from '~/api/utils/auth';
7
+
import { decodeJwt } from '~/api/utils/jwt';
8
8
9
9
import { createMutation } from '~/lib/utils/mutation';
10
10
11
11
import Button from '~/components/inputs/button';
12
12
import TextInput from '~/components/inputs/text-input';
13
-
import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard';
13
+
import { Stage, StageActions, StageErrorView, type WizardStepProps } from '~/components/wizard';
14
14
15
-
import { PlcApplicatorConstraints } from '../page';
15
+
import type { PlcApplicatorConstraints } from '../page';
16
16
17
17
class InsufficientLoginError extends Error {}
18
18
···
59
59
setPassword('');
60
60
setIsTotpRequired(false);
61
61
},
62
-
onError(error) {
62
+
onError(err) {
63
63
let message: string | undefined;
64
64
65
-
if (error instanceof XRPCError) {
66
-
if (error.kind === 'AuthFactorTokenRequired') {
65
+
if (err instanceof ClientResponseError) {
66
+
if (err.error === 'AuthFactorTokenRequired') {
67
67
setOtp('');
68
68
setIsTotpRequired(true);
69
69
return;
70
70
}
71
71
72
-
if (error.kind === 'AuthenticationRequired') {
72
+
if (err.error === 'AuthenticationRequired') {
73
73
message = `Invalid identifier or password`;
74
-
} else if (error.kind === 'AccountTakedown') {
74
+
} else if (err.error === 'AccountTakedown') {
75
75
message = `Account has been taken down`;
76
-
} else if (error.message.includes('Token is invalid')) {
76
+
} else if (err.description?.includes('Token is invalid')) {
77
77
message = `Invalid one-time confirmation code`;
78
78
setIsTotpRequired(true);
79
79
}
80
-
} else if (error instanceof InsufficientLoginError) {
81
-
message = error.message;
80
+
} else if (err instanceof InsufficientLoginError) {
81
+
message = err.message;
82
82
}
83
83
84
84
if (message !== undefined) {
85
85
setError(message);
86
86
} else {
87
-
console.error(error);
88
-
setError(`Something went wrong: ${error}`);
87
+
console.error(err);
88
+
setError(`Something went wrong: ${err}`);
89
89
}
90
90
},
91
91
});
92
92
93
93
const dispatchMutation = createMutation({
94
94
async mutationFn({ manager }: { manager: CredentialManager }) {
95
-
const rpc = new XRPC({ handler: manager });
96
-
const { data: recommendedDidDoc } = await rpc.get(
97
-
'com.atproto.identity.getRecommendedDidCredentials',
98
-
{},
99
-
);
95
+
const rpc = new Client({ handler: manager });
96
+
const recommendedDidDoc = await ok(rpc.get('com.atproto.identity.getRecommendedDidCredentials'));
100
97
101
98
return { recommendedDidDoc };
102
99
},
+3
-9
src/views/identity/plc-applicator/steps/step2_private-key-input.tsx
+3
-9
src/views/identity/plc-applicator/steps/step2_private-key-input.tsx
···
8
8
import Button from '~/components/inputs/button';
9
9
import RadioInput from '~/components/inputs/radio-input';
10
10
import TextInput from '~/components/inputs/text-input';
11
-
import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard';
11
+
import { Stage, StageActions, StageErrorView, type WizardStepProps } from '~/components/wizard';
12
12
13
13
import type { Keypair, PlcApplicatorConstraints, PrivateKeySigningMethod } from '../page';
14
14
···
97
97
});
98
98
},
99
99
onError(error) {
100
-
let message: string | undefined;
101
-
102
-
if (message !== undefined) {
103
-
setError(message);
104
-
} else {
105
-
console.error(error);
106
-
setError(`Something went wrong: ${error}`);
107
-
}
100
+
console.error(error);
101
+
setError(`Something went wrong: ${error}`);
108
102
},
109
103
});
110
104
+4
-4
src/views/identity/plc-applicator/steps/step3_operation-select.tsx
+4
-4
src/views/identity/plc-applicator/steps/step3_operation-select.tsx
···
7
7
type IndexedEntryWithSigner,
8
8
normalizeOp,
9
9
} from '@atcute/did-plc';
10
-
import type { Did } from '@atcute/identity';
10
+
import type { Did } from '@atcute/lexicons';
11
11
12
12
import Button from '~/components/inputs/button';
13
+
import RadioInput from '~/components/inputs/radio-input';
13
14
import SelectInput from '~/components/inputs/select-input';
14
-
import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard';
15
+
import { Stage, StageActions, StageErrorView, type WizardStepProps } from '~/components/wizard';
15
16
16
-
import { PlcApplicatorConstraints } from '../page';
17
-
import RadioInput from '~/components/inputs/radio-input';
17
+
import type { PlcApplicatorConstraints } from '../page';
18
18
19
19
const Step3_OperationSelect = ({
20
20
data,
+2
-2
src/views/identity/plc-applicator/steps/step4_payload-input.tsx
+2
-2
src/views/identity/plc-applicator/steps/step4_payload-input.tsx
···
4
4
5
5
import Button from '~/components/inputs/button';
6
6
import MultilineInput from '~/components/inputs/multiline-input';
7
-
import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard';
7
+
import { Stage, StageActions, StageErrorView, type WizardStepProps } from '~/components/wizard';
8
8
9
-
import { PlcApplicatorConstraints } from '../page';
9
+
import type { PlcApplicatorConstraints } from '../page';
10
10
import { getPlcPayload } from '../plc-utils';
11
11
12
12
export const Step4_PayloadInput = ({
+30
-25
src/views/identity/plc-applicator/steps/step5_pds-confirmation.tsx
+30
-25
src/views/identity/plc-applicator/steps/step5_pds-confirmation.tsx
···
1
1
import { createSignal } from 'solid-js';
2
2
3
-
import { XRPC, XRPCError } from '@atcute/client';
3
+
import { Client, ClientResponseError, ok } from '@atcute/client';
4
4
5
5
import { formatTotpCode, TOTP_RE } from '~/api/utils/auth';
6
6
···
9
9
import CheckIcon from '~/components/ic-icons/baseline-check';
10
10
import Button from '~/components/inputs/button';
11
11
import TextInput from '~/components/inputs/text-input';
12
-
import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard';
12
+
import { Stage, StageActions, StageErrorView, type WizardStepProps } from '~/components/wizard';
13
13
14
-
import { PlcApplicatorConstraints } from '../page';
14
+
import type { PlcApplicatorConstraints } from '../page';
15
15
16
16
export const Step5_PdsConfirmation = ({
17
17
data,
···
27
27
const requestMutation = createMutation({
28
28
async mutationFn() {
29
29
const manager = data.method.manager;
30
-
const rpc = new XRPC({ handler: manager });
30
+
const rpc = new Client({ handler: manager });
31
31
32
-
await rpc.call('com.atproto.identity.requestPlcOperationSignature', {});
32
+
await ok(rpc.post('com.atproto.identity.requestPlcOperationSignature', { as: null }));
33
33
},
34
34
onMutate() {
35
35
setRequestError();
···
49
49
const applyMutation = createMutation({
50
50
async mutationFn({ code }: { code: string }) {
51
51
const manager = data.method.manager;
52
-
const rpc = new XRPC({ handler: manager });
52
+
const client = new Client({ handler: manager });
53
53
54
54
const payload = data.payload;
55
55
56
-
const { data: signage } = await rpc.call('com.atproto.identity.signPlcOperation', {
57
-
data: {
58
-
token: formatTotpCode(code),
59
-
alsoKnownAs: payload.alsoKnownAs,
60
-
rotationKeys: payload.rotationKeys,
61
-
services: payload.services,
62
-
verificationMethods: payload.verificationMethods,
63
-
},
64
-
});
56
+
const signage = await ok(
57
+
client.post('com.atproto.identity.signPlcOperation', {
58
+
input: {
59
+
token: formatTotpCode(code),
60
+
alsoKnownAs: payload.alsoKnownAs,
61
+
rotationKeys: payload.rotationKeys,
62
+
services: payload.services,
63
+
verificationMethods: payload.verificationMethods,
64
+
},
65
+
}),
66
+
);
65
67
66
-
await rpc.call('com.atproto.identity.submitPlcOperation', {
67
-
data: {
68
-
operation: signage.operation,
69
-
},
70
-
});
68
+
await ok(
69
+
client.post('com.atproto.identity.submitPlcOperation', {
70
+
as: null,
71
+
input: {
72
+
operation: signage.operation,
73
+
},
74
+
}),
75
+
);
71
76
},
72
77
onMutate() {
73
78
setApplyError();
···
75
80
onSuccess() {
76
81
onNext('Step6_Finished', {});
77
82
},
78
-
onError(error) {
83
+
onError(err) {
79
84
let message: string | undefined;
80
85
81
-
if (error instanceof XRPCError) {
82
-
if (error.kind === 'InvalidToken' || error.kind === 'ExpiredToken') {
86
+
if (err instanceof ClientResponseError) {
87
+
if (err.error === 'InvalidToken' || err.error === 'ExpiredToken') {
83
88
message = `Confirmation code has expired`;
84
89
}
85
90
}
···
87
92
if (message !== undefined) {
88
93
setApplyError(message);
89
94
} else {
90
-
console.error(error);
91
-
setApplyError(`Something went wrong: ${error}`);
95
+
console.error(err);
96
+
setApplyError(`Something went wrong: ${err}`);
92
97
}
93
98
},
94
99
});
+5
-6
src/views/identity/plc-applicator/steps/step5_private-key-confirmation.tsx
+5
-6
src/views/identity/plc-applicator/steps/step5_private-key-confirmation.tsx
···
9
9
10
10
import Button from '~/components/inputs/button';
11
11
import TextInput from '~/components/inputs/text-input';
12
-
import { Stage, StageActions, StageErrorView, WizardStepProps } from '~/components/wizard';
12
+
import { Stage, StageActions, StageErrorView, type WizardStepProps } from '~/components/wizard';
13
13
14
-
import { PlcApplicatorConstraints } from '../page';
14
+
import type { PlcApplicatorConstraints } from '../page';
15
15
16
16
const Step5_PrivateKeyConfirmation = ({
17
17
data,
···
78
78
}}
79
79
>
80
80
<p class="text-pretty">
81
-
To continue with this submission, type in the following code{' '}
82
-
<code class="whitespace-nowrap font-bold">{code}</code> to the confirmation box below.
81
+
To continue with this submission, type in <code class="whitespace-nowrap font-bold">{code}</code> to
82
+
the confirmation box below.
83
83
</p>
84
84
85
85
<TextInput
86
-
label="Confirmation code"
86
+
label="Confirmation"
87
87
type="text"
88
88
autocomplete="one-time-code"
89
89
autocorrect="off"
90
90
required
91
91
pattern={code}
92
-
placeholder="AAAAA-BBBBB"
93
92
autofocus={isActive()}
94
93
monospace
95
94
/>
+2
-2
src/views/identity/plc-applicator/steps/step6_finished.tsx
+2
-2
src/views/identity/plc-applicator/steps/step6_finished.tsx
···
1
-
import { Stage, WizardStepProps } from '~/components/wizard';
1
+
import { Stage, type WizardStepProps } from '~/components/wizard';
2
2
3
-
import { PlcApplicatorConstraints } from '../page';
3
+
import type { PlcApplicatorConstraints } from '../page';
4
4
5
5
export const Step6_Finished = ({}: WizardStepProps<PlcApplicatorConstraints, 'Step6_Finished'>) => {
6
6
return (
+5
-9
src/views/identity/plc-oplogs.tsx
+5
-9
src/views/identity/plc-oplogs.tsx
···
1
-
import { createSignal, JSX, Match, onCleanup, Switch } from 'solid-js';
1
+
import { createSignal, Match, onCleanup, Switch, type JSX } from 'solid-js';
2
2
3
3
import type { IndexedEntry, Service } from '@atcute/did-plc';
4
-
import { type Did, type Handle, isHandle, isPlcDid } from '@atcute/identity';
4
+
import { isPlcDid } from '@atcute/identity';
5
+
import { isHandle, type Did, type Handle } from '@atcute/lexicons/syntax';
5
6
6
7
import { resolveHandleViaAppView } from '~/api/queries/handle';
7
-
import { DID_OR_HANDLE_RE } from '~/api/utils/strings';
8
8
9
9
import { getPlcAuditLogs } from '~/api/queries/plc';
10
10
import { useTitle } from '~/lib/navigation/router';
···
20
20
import ContentCopyIcon from '~/components/ic-icons/baseline-content-copy';
21
21
import Button from '~/components/inputs/button';
22
22
import TextInput from '~/components/inputs/text-input';
23
+
import PageHeader from '~/components/page-header';
23
24
24
25
const PlcOperationLogPage = () => {
25
26
const [params, setParams] = useSearchParams({
···
55
56
56
57
return (
57
58
<>
58
-
<div class="p-4">
59
-
<h1 class="text-lg font-bold text-purple-800">View PLC operation logs</h1>
60
-
<p class="text-gray-600">Show history of a did:plc identity</p>
61
-
</div>
62
-
<hr class="mx-4 border-gray-300" />
59
+
<PageHeader title="View PLC operation logs" subtitle="Show history of a did:plc identity" />
63
60
64
61
<form
65
62
onSubmit={(ev) => {
···
76
73
type="text"
77
74
name="ident"
78
75
autocomplete="username"
79
-
pattern={/* @once */ DID_OR_HANDLE_RE.source}
80
76
placeholder="paul.bsky.social"
81
77
autofocus
82
78
/>
+9
-6
src/views/repository/repo-archive-explore/page.tsx
+9
-6
src/views/repository/repo-archive-explore/page.tsx
···
1
1
import { Match, Switch } from 'solid-js';
2
2
3
-
import { iterateAtpRepo } from '@atcute/car';
3
+
import { fromStream } from '@atcute/repo';
4
4
5
5
import { createMutation } from '~/lib/utils/mutation';
6
6
7
-
import WelcomeView from './views/welcome';
8
-
9
-
import { Archive, RecordEntry } from './types';
7
+
import type { Archive, RecordEntry } from './types';
10
8
import ExploreView from './views/explore';
9
+
import WelcomeView from './views/welcome';
11
10
12
11
const ArchiveExplorePage = () => {
13
12
const mutation = createMutation({
14
13
async mutationFn({ file }: { file: File }): Promise<Archive> {
15
-
const buffer = new Uint8Array(await file.arrayBuffer());
14
+
const stream = file.stream();
15
+
await using repo = fromStream(stream);
16
16
17
17
const collections = new Map<string, RecordEntry[]>();
18
18
const archive: Archive = {
···
20
20
entries: [],
21
21
};
22
22
23
-
for (const entry of iterateAtpRepo(buffer)) {
23
+
for await (const entry of repo) {
24
24
let list = collections.get(entry.collection);
25
25
if (list === undefined) {
26
26
collections.set(entry.collection, (list = []));
···
41
41
}
42
42
43
43
return archive;
44
+
},
45
+
onError(err) {
46
+
console.error(err);
44
47
},
45
48
});
46
49
+1
-1
src/views/repository/repo-archive-explore/views/explore/record.tsx
+1
-1
src/views/repository/repo-archive-explore/views/explore/record.tsx
+9
-42
src/views/repository/repo-archive-explore/views/welcome.tsx
+9
-42
src/views/repository/repo-archive-explore/views/welcome.tsx
···
3
3
import type { MutationReturn } from '~/lib/utils/mutation';
4
4
5
5
import CircularProgress from '~/components/circular-progress';
6
+
import FileDropZone from '~/components/file-drop-zone';
7
+
import PageHeader from '~/components/page-header';
6
8
7
-
import { Archive } from '../types';
8
-
import { createDropZone } from '~/lib/hooks/dropzone';
9
+
import type { Archive } from '../types';
9
10
10
11
interface WelcomeViewProps {
11
12
mutation: MutationReturn<Archive, { file: File }>;
12
13
}
13
14
14
15
const WelcomeView = ({ mutation }: WelcomeViewProps) => {
15
-
const { ref: dropRef, isDropping } = createDropZone({
16
-
// Checked, the mime type for CAR files is blank.
17
-
dataTypes: [''],
18
-
multiple: false,
19
-
onDrop(files) {
20
-
if (files) {
21
-
mutation.mutate({ file: files[0] });
22
-
}
23
-
},
24
-
});
25
-
26
16
return (
27
17
<>
28
-
<div class="p-4">
29
-
<h1 class="text-lg font-bold text-purple-800">Explore archive</h1>
30
-
<p class="text-gray-600">Explore a repository archive</p>
31
-
</div>
32
-
<hr class="mx-4 border-gray-300" />
18
+
<PageHeader title="Explore archive" subtitle="Explore a repository archive" />
33
19
34
20
<div class="flex flex-col gap-4 p-4">
35
-
<fieldset
36
-
ref={dropRef}
37
-
class={
38
-
`grid place-items-center rounded border border-gray-300 px-6 py-12 disabled:opacity-50` +
39
-
(!isDropping() ? ` bg-gray-100` : ` bg-green-100`)
40
-
}
21
+
<FileDropZone
22
+
accept=".car,application/vnd.ipld.car"
23
+
dataTypes={['']}
24
+
onFiles={(files) => mutation.mutate({ file: files[0] })}
41
25
>
42
-
<div class="flex flex-col items-center gap-4">
43
-
<button
44
-
onClick={() => {
45
-
const input = document.createElement('input');
46
-
input.type = 'file';
47
-
input.accept = '.car,application/vnd.ipld.car';
48
-
input.oninput = () => mutation.mutate({ file: input.files![0] });
49
-
50
-
input.click();
51
-
}}
52
-
class="flex h-9 select-none items-center rounded border border-gray-400 px-4 text-sm font-semibold text-gray-800 hover:bg-gray-200 active:bg-gray-200 disabled:pointer-events-none"
53
-
>
54
-
Browse files
55
-
</button>
56
-
<p class="select-none font-medium text-gray-600">or drop your file here</p>
57
-
</div>
58
-
59
26
<div
60
27
hidden={!mutation.isPending}
61
28
class="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-gray-50"
···
63
30
<CircularProgress />
64
31
<span class="font-medium">Reading CAR file</span>
65
32
</div>
66
-
</fieldset>
33
+
</FileDropZone>
67
34
68
35
<Show when={mutation.error}>
69
36
<p class="whitespace-pre-wrap text-[0.8125rem] font-medium leading-5 text-red-800">
+23
-62
src/views/repository/repo-archive-unpack.tsx
+23
-62
src/views/repository/repo-archive-unpack.tsx
···
1
1
import { FileSystemWritableFileStream, showSaveFilePicker } from 'native-file-system-adapter';
2
2
import { createSignal } from 'solid-js';
3
3
4
-
import { iterateAtpRepo } from '@atcute/car';
4
+
import { fromStream } from '@atcute/repo';
5
5
import { writeTarEntry } from '@mary/tar';
6
6
7
-
import { createDropZone } from '~/lib/hooks/dropzone';
8
7
import { useTitle } from '~/lib/navigation/router';
9
8
import { makeAbortable } from '~/lib/utils/abortable';
10
9
10
+
import FileDropZone from '~/components/file-drop-zone';
11
11
import Logger, { createLogger } from '~/components/logger';
12
+
import PageHeader from '~/components/page-header';
12
13
13
14
// @ts-expect-error: new API
14
15
const yieldToScheduler: () => Promise<void> = window?.scheduler?.yield
···
16
17
window.scheduler.yield.bind(window.scheduler)
17
18
: undefined;
18
19
19
-
const yieldToIdle =
20
-
typeof requestIdleCallback === 'function'
21
-
? () => new Promise((resolve) => requestIdleCallback(resolve))
22
-
: () => new Promise((resolve) => setTimeout(resolve, 1));
23
-
24
20
const UnpackCarPage = () => {
25
21
const logger = createLogger();
26
22
27
23
const [getSignal, cleanup] = makeAbortable();
28
24
const [pending, setPending] = createSignal(false);
29
25
30
-
const { ref: dropRef, isDropping } = createDropZone({
31
-
// Checked, the mime type for CAR files is blank.
32
-
dataTypes: [''],
33
-
multiple: false,
34
-
onDrop(files) {
35
-
if (files) {
36
-
onFileDrop(files);
37
-
}
38
-
},
39
-
});
40
-
41
26
const mutate = async (file: File, signal: AbortSignal) => {
42
-
logger.info(`Starting extraction for ${file.name}`);
27
+
logger.log(`Starting extraction`);
43
28
44
-
const buf = await file.arrayBuffer();
45
-
const ui8 = new Uint8Array(buf);
29
+
const stream = file.stream();
30
+
await using repo = fromStream(stream);
46
31
47
-
let currentCollection: string | undefined;
48
32
let count = 0;
49
33
50
34
let writable: FileSystemWritableFileStream | undefined;
51
35
52
-
for (const { collection, rkey, record } of iterateAtpRepo(ui8)) {
36
+
using progress = logger.progress(`Unpacking records (${count} entries)`);
37
+
38
+
for await (const { collection, rkey, record } of repo) {
53
39
if (writable === undefined) {
54
40
using _progress = logger.progress(`Waiting for the user`);
55
41
···
87
73
88
74
signal.throwIfAborted();
89
75
90
-
if (currentCollection !== collection) {
91
-
logger.log(`Current progress: ${collection}`);
92
-
currentCollection = collection;
93
-
94
-
if (yieldToScheduler === undefined) {
95
-
await yieldToIdle();
96
-
}
97
-
}
98
-
99
76
const entry = writeTarEntry({
100
77
filename: `${collection}/${filenamify(rkey)}.json`,
101
78
data: JSON.stringify(record, null, 2),
102
79
});
103
80
104
-
writable.write(entry);
105
81
count++;
106
82
83
+
if (count % 100 !== 0) {
84
+
writable.write(entry);
85
+
} else {
86
+
await writable.write(entry);
87
+
}
88
+
89
+
progress.update(`Unpacking records (${count} entries)`);
90
+
107
91
if (yieldToScheduler !== undefined) {
108
92
await yieldToScheduler();
109
93
}
···
161
145
162
146
return (
163
147
<>
164
-
<div class="p-4">
165
-
<h1 class="text-lg font-bold text-purple-800">Unpack archive</h1>
166
-
<p class="text-gray-600">Extract a repository archive into a tarball</p>
167
-
</div>
168
-
<hr class="mx-4 border-gray-300" />
148
+
<PageHeader title="Unpack archive" subtitle="Extract a repository archive into a tarball" />
169
149
170
150
<div class="p-4">
171
-
<fieldset
172
-
ref={dropRef}
151
+
<FileDropZone
152
+
accept=".car,application/vnd.ipld.car"
153
+
dataTypes={['']}
173
154
disabled={pending()}
174
-
class={
175
-
`grid place-items-center rounded border border-gray-300 px-6 py-12 disabled:opacity-50` +
176
-
(pending() || !isDropping() ? ` bg-gray-100` : ` bg-green-100`)
177
-
}
178
-
>
179
-
<div class="flex flex-col items-center gap-4">
180
-
<button
181
-
onClick={() => {
182
-
const input = document.createElement('input');
183
-
input.type = 'file';
184
-
input.accept = '.car,application/vnd.ipld.car';
185
-
input.oninput = () => onFileDrop(Array.from(input.files!));
186
-
187
-
input.click();
188
-
}}
189
-
class="flex h-9 select-none items-center rounded border border-gray-400 px-4 text-sm font-semibold text-gray-800 hover:bg-gray-200 active:bg-gray-200 disabled:pointer-events-none"
190
-
>
191
-
Browse files
192
-
</button>
193
-
<p class="select-none font-medium text-gray-600">or drop your file here</p>
194
-
</div>
195
-
</fieldset>
155
+
onFiles={onFileDrop}
156
+
/>
196
157
</div>
197
158
<hr class="mx-4 border-gray-300" />
198
159
+5
-27
src/views/repository/repo-export.tsx
+5
-27
src/views/repository/repo-export.tsx
···
1
1
import { type FileSystemFileHandle, showSaveFilePicker } from 'native-file-system-adapter';
2
2
import { createSignal } from 'solid-js';
3
3
4
-
import { type AtprotoDid, getPdsEndpoint, isAtprotoDid, isHandle } from '@atcute/identity';
4
+
import { getPdsEndpoint, isAtprotoDid } from '@atcute/identity';
5
+
import { type AtprotoDid, isHandle } from '@atcute/lexicons/syntax';
5
6
6
7
import { getDidDocument } from '~/api/queries/did-doc';
7
8
import { resolveHandleViaAppView, resolveHandleViaPds } from '~/api/queries/handle';
8
9
import { isServiceUrlString } from '~/api/types/strings';
9
-
import { DID_OR_HANDLE_RE } from '~/api/utils/strings';
10
10
11
11
import { useTitle } from '~/lib/navigation/router';
12
12
import { makeAbortable } from '~/lib/utils/abortable';
13
13
import { formatBytes } from '~/lib/utils/intl/bytes';
14
+
import { iterateStream } from '~/lib/utils/stream';
14
15
15
16
import Button from '~/components/inputs/button';
16
17
import TextInput from '~/components/inputs/text-input';
17
18
import Logger, { createLogger } from '~/components/logger';
19
+
import PageHeader from '~/components/page-header';
18
20
19
21
const RepoExportPage = () => {
20
22
const logger = createLogger();
···
135
137
136
138
return (
137
139
<>
138
-
<div class="p-4">
139
-
<h1 class="text-lg font-bold text-purple-800">Export repository</h1>
140
-
<p class="text-gray-600">Download an archive of an account's repository</p>
141
-
</div>
142
-
<hr class="mx-4 border-gray-300" />
140
+
<PageHeader title="Export repository" subtitle="Download an archive of an account's repository" />
143
141
144
142
<form
145
143
onSubmit={(ev) => {
···
190
188
type="text"
191
189
name="ident"
192
190
autocomplete="username"
193
-
pattern={/* @once */ DID_OR_HANDLE_RE.source}
194
191
placeholder="paul.bsky.social"
195
192
autofocus
196
193
/>
···
223
220
};
224
221
225
222
export default RepoExportPage;
226
-
227
-
export async function* iterateStream<T>(stream: ReadableStream<T>) {
228
-
// Get a lock on the stream
229
-
const reader = stream.getReader();
230
-
231
-
try {
232
-
while (true) {
233
-
const { done, value } = await reader.read();
234
-
235
-
if (done) {
236
-
return;
237
-
}
238
-
239
-
yield value;
240
-
}
241
-
} finally {
242
-
reader.releaseLock();
243
-
}
244
-
}
+4
-2
tsconfig.app.json
+4
-2
tsconfig.app.json
···
1
1
{
2
2
"compilerOptions": {
3
3
"target": "ESNext",
4
-
"useDefineForClassFields": false,
5
4
"module": "ESNext",
6
5
"lib": ["ESNext", "DOM", "DOM.Iterable"],
7
-
"types": [],
6
+
"types": ["@atcute/atproto", "@atcute/bluesky"],
8
7
"skipLibCheck": true,
9
8
10
9
"moduleResolution": "Bundler",
11
10
"allowImportingTsExtensions": true,
12
11
"isolatedModules": true,
12
+
"verbatimModuleSyntax": true,
13
13
"moduleDetection": "force",
14
14
"noEmit": true,
15
+
15
16
"jsx": "preserve",
16
17
"jsxImportSource": "solid-js",
18
+
"useDefineForClassFields": false,
17
19
18
20
"strict": true,
19
21
"noUnusedLocals": true,