+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
-29
package.json
+32
-29
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": "^2.1.1",
11
-
"@atcute/car": "^3.0.4",
12
-
"@atcute/cbor": "^2.2.3",
13
-
"@atcute/cid": "^2.2.2",
14
-
"@atcute/client": "^3.1.0",
15
-
"@atcute/crypto": "^2.2.1",
16
-
"@atcute/did-plc": "^0.1.4",
17
-
"@atcute/identity": "^0.1.3",
18
-
"@atcute/identity-resolver": "^0.1.2",
19
-
"@atcute/multibase": "^1.1.3",
20
-
"@atcute/tid": "^1.0.2",
21
-
"@badrap/valita": "^0.4.4",
22
-
"@mary/array-fns": "npm:@jsr/mary__array-fns@^0.1.4",
23
-
"@mary/ds-queue": "npm:@jsr/mary__ds-queue@^0.1.2",
24
-
"@mary/events": "npm:@jsr/mary__events@^0.2.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",
25
28
"@mary/solid-freeze": "npm:@externdefs/solid-freeze@^0.1.1",
26
-
"@mary/tar": "npm:@jsr/mary__tar@^0.2.4",
27
-
"nanoid": "^5.1.5",
29
+
"@mary/tar": "jsr:^0.3.1",
30
+
"nanoid": "^5.1.6",
28
31
"native-file-system-adapter": "^3.0.1",
29
-
"solid-js": "^1.9.6"
32
+
"solid-js": "^1.9.10"
30
33
},
31
34
"devDependencies": {
32
35
"@tailwindcss/forms": "^0.5.10",
33
-
"@types/node": "^22.15.12",
34
-
"autoprefixer": "^10.4.21",
35
-
"prettier": "^3.5.3",
36
-
"prettier-plugin-tailwindcss": "^0.6.11",
37
-
"tailwindcss": "^3.4.17",
38
-
"terser": "^5.39.0",
39
-
"typescript": "~5.8.3",
40
-
"vite": "^6.3.5",
41
-
"vite-plugin-solid": "^2.11.6",
42
-
"wrangler": "^4.14.1"
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"
43
46
}
44
47
}
+987
-1150
pnpm-lock.yaml
+987
-1150
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: ^2.1.1
13
-
version: 2.1.1(@atcute/client@3.1.0)
15
+
specifier: ^3.2.13
16
+
version: 3.2.13
14
17
'@atcute/car':
15
-
specifier: ^3.0.4
16
-
version: 3.0.4
18
+
specifier: ^5.0.0
19
+
version: 5.0.0
17
20
'@atcute/cbor':
18
-
specifier: ^2.2.3
19
-
version: 2.2.3
21
+
specifier: ^2.2.8
22
+
version: 2.2.8
20
23
'@atcute/cid':
21
-
specifier: ^2.2.2
22
-
version: 2.2.2
24
+
specifier: ^2.2.6
25
+
version: 2.2.6
23
26
'@atcute/client':
24
-
specifier: ^3.1.0
25
-
version: 3.1.0
27
+
specifier: ^4.1.1
28
+
version: 4.1.1
26
29
'@atcute/crypto':
27
-
specifier: ^2.2.1
28
-
version: 2.2.1
30
+
specifier: ^2.3.0
31
+
version: 2.3.0
29
32
'@atcute/did-plc':
30
-
specifier: ^0.1.4
31
-
version: 0.1.4
33
+
specifier: ^0.2.0
34
+
version: 0.2.0
32
35
'@atcute/identity':
33
-
specifier: ^0.1.3
34
-
version: 0.1.3
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.3)
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.3
40
-
version: 1.1.3
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.4
46
-
version: 0.4.4
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'
50
59
'@mary/ds-queue':
51
-
specifier: npm:@jsr/mary__ds-queue@^0.1.2
52
-
version: '@jsr/mary__ds-queue@0.1.2'
60
+
specifier: jsr:^0.1.3
61
+
version: '@jsr/mary__ds-queue@0.1.3'
53
62
'@mary/events':
54
-
specifier: npm:@jsr/mary__events@^0.2.0
63
+
specifier: jsr:^0.2.0
55
64
version: '@jsr/mary__events@0.2.0'
56
65
'@mary/solid-freeze':
57
66
specifier: npm:@externdefs/solid-freeze@^0.1.1
58
-
version: '@externdefs/solid-freeze@0.1.1(solid-js@1.9.6)'
67
+
version: '@externdefs/solid-freeze@0.1.1(solid-js@1.9.10)'
59
68
'@mary/tar':
60
-
specifier: npm:@jsr/mary__tar@^0.2.4
61
-
version: '@jsr/mary__tar@0.2.4'
69
+
specifier: jsr:^0.3.1
70
+
version: '@jsr/mary__tar@0.3.1'
62
71
nanoid:
63
-
specifier: ^5.1.5
64
-
version: 5.1.5
72
+
specifier: ^5.1.6
73
+
version: 5.1.6
65
74
native-file-system-adapter:
66
75
specifier: ^3.0.1
67
76
version: 3.0.1
68
77
solid-js:
69
-
specifier: ^1.9.6
70
-
version: 1.9.6
78
+
specifier: ^1.9.10
79
+
version: 1.9.10
71
80
devDependencies:
72
81
'@tailwindcss/forms':
73
82
specifier: ^0.5.10
74
-
version: 0.5.10(tailwindcss@3.4.17)
83
+
version: 0.5.10(tailwindcss@3.4.18)
75
84
'@types/node':
76
-
specifier: ^22.15.12
77
-
version: 22.15.12
85
+
specifier: ^22.19.2
86
+
version: 22.19.2
78
87
autoprefixer:
79
-
specifier: ^10.4.21
80
-
version: 10.4.21(postcss@8.5.3)
88
+
specifier: ^10.4.22
89
+
version: 10.4.22(postcss@8.5.6)
81
90
prettier:
82
-
specifier: ^3.5.3
83
-
version: 3.5.3
91
+
specifier: ^3.7.4
92
+
version: 3.7.4
84
93
prettier-plugin-tailwindcss:
85
-
specifier: ^0.6.11
86
-
version: 0.6.11(prettier@3.5.3)
94
+
specifier: ^0.6.14
95
+
version: 0.6.14(prettier@3.7.4)
87
96
tailwindcss:
88
-
specifier: ^3.4.17
89
-
version: 3.4.17
97
+
specifier: ^3.4.18
98
+
version: 3.4.18
90
99
terser:
91
-
specifier: ^5.39.0
92
-
version: 5.39.0
100
+
specifier: ^5.44.1
101
+
version: 5.44.1
93
102
typescript:
94
-
specifier: ~5.8.3
95
-
version: 5.8.3
103
+
specifier: ~5.9.3
104
+
version: 5.9.3
96
105
vite:
97
-
specifier: ^6.3.5
98
-
version: 6.3.5(@types/node@22.15.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.1)
106
+
specifier: ^7.2.7
107
+
version: 7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1)
99
108
vite-plugin-solid:
100
-
specifier: ^2.11.6
101
-
version: 2.11.6(solid-js@1.9.6)(vite@6.3.5(@types/node@22.15.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.1))
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))
102
111
wrangler:
103
-
specifier: ^4.14.1
104
-
version: 4.14.1
112
+
specifier: ^4.53.0
113
+
version: 4.53.0
105
114
106
115
packages:
107
116
···
109
118
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
110
119
engines: {node: '>=10'}
111
120
112
-
'@ampproject/remapping@2.3.0':
113
-
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
114
-
engines: {node: '>=6.0.0'}
121
+
'@atcute/atproto@3.1.9':
122
+
resolution: {integrity: sha512-DyWwHCTdR4hY2BPNbLXgVmm7lI+fceOwWbE4LXbGvbvVtSn+ejSVFaAv01Ra3kWDha0whsOmbJL8JP0QPpf1+w==}
115
123
116
-
'@atcute/bluesky@2.1.1':
117
-
resolution: {integrity: sha512-wEZfFW58J6yC1SqHcVJOn4qbHENTTzjeCEWthRT5HvKovADLqk54HSMSAuXDMBUbintSTBr0khQNZQ3ZdgzDdQ==}
118
-
peerDependencies:
119
-
'@atcute/client': ^3.0.0
124
+
'@atcute/bluesky@3.2.13':
125
+
resolution: {integrity: sha512-ZG/mqsCjVU6zvH6XsRw+oQglrsdu5R7mnncMO+Ux0KWbX2xJw4ZMFHfs7ZTC69dVPK9r/yle7YbpygZTOWDM9A==}
120
126
121
-
'@atcute/car@3.0.4':
122
-
resolution: {integrity: sha512-T38qVn09cgaMCWka3tLWbuc/nPI5Sfjac/PwJIei2GnMldKSrZrAjeCvJAg8TWvsNab1kRZEy5uYqcBUJtzsWA==}
127
+
'@atcute/car@5.0.0':
128
+
resolution: {integrity: sha512-OIY2xTXv8lSpZsDSn/UYQtJSMvDw5Hi4Q+uyvmiqSM+fht08QRAEq/nxa5YFciPZ3nfDFnZ3//EgJw7QhkSXLQ==}
123
129
124
-
'@atcute/cbor@2.2.3':
125
-
resolution: {integrity: sha512-yvzaPI6ChNlqYN41qY8cVGCubgb6N/Y2kpNQnjC5waAZ4Xy2WH7ohuyiv0BQDvgzPT4ww1+9G+zBFxcfM2PH/Q==}
130
+
'@atcute/cbor@2.2.8':
131
+
resolution: {integrity: sha512-UzOAN9BuN6JCXgn0ryV8qZuRJUDrNqrbLd6EFM8jc6RYssjRyGRxNy6RZ1NU/07Hd8Tq/0pz8+nQiMu5Zai5uw==}
126
132
127
-
'@atcute/cid@2.2.2':
128
-
resolution: {integrity: sha512-deAGMqLAyplt7eIukhkjlsGubvrcMrtXkDKlUYZDo4WUdL7hSjBywtPXf6SbMK+Mjvst7l2+83OqTcY5AuuxtA==}
133
+
'@atcute/cid@2.2.6':
134
+
resolution: {integrity: sha512-bTAHHbJ24p+E//V4KCS4xdmd39o211jJswvqQOevj7vk+5IYcgDLx1ryZWZ1sEPOo9x875li/kj5gpKL14RDwQ==}
129
135
130
-
'@atcute/client@3.1.0':
131
-
resolution: {integrity: sha512-+rQPsHXSf0DUm8XoHoaH7Y2E8tIpbsW84djyPj7dqAyrFIjvGuJ1X1DvMufwbTIcmLerdy+dzl34iZcz/h3Vhg==}
136
+
'@atcute/client@4.1.1':
137
+
resolution: {integrity: sha512-FROCbTTCeL5u4tO/n72jDEKyKqjdlXMB56Ehve3W/gnnLGCYWvN42sS7tvL1Mgu6sbO3yZwsXKDrmM2No4XpjA==}
132
138
133
-
'@atcute/crypto@2.2.1':
134
-
resolution: {integrity: sha512-ILnwxEkH0PujlDqn3PWzvpTOqSOzy7XAsLFZgJ4PN1cnNg9hbtSoKiGdBHKJqvdljSDgA8aOFvvxBfl30EOu8A==}
139
+
'@atcute/crypto@2.3.0':
140
+
resolution: {integrity: sha512-w5pkJKCjbNMQu+F4JRHbR3ROQyhi1wbn+GSC6WDQamcYHkZmEZk1/eoI354bIQOOfkEM6aFLv718iskrkon4GQ==}
135
141
136
-
'@atcute/did-plc@0.1.4':
137
-
resolution: {integrity: sha512-VymkNnaEujOVoiBIPGE1M4Kjr1SB7zz+qJhxtHT6SrBWuXEFOOzjsoxkuBlcV/mm4ZTtjAxBpX3MIRRDKq19LQ==}
142
+
'@atcute/did-plc@0.2.0':
143
+
resolution: {integrity: sha512-1sGek8GRM/Ph7nLVRREm8FqM7g4shGckItvdVwJcRbUa8Rh0zOsXQa0QyYWAC0k40BhkqO9FwKXhJEaXCmF5oQ==}
138
144
139
-
'@atcute/identity-resolver@0.1.2':
140
-
resolution: {integrity: sha512-fP2VbHD04kVcCdNi/Kszo6jFzqM7Pg3p33oGhfp2zVkwFKaVBlwCaFRWEga/Xvu/IDLwNdASGWnLqoA34SFeSg==}
145
+
'@atcute/identity-resolver@1.2.0':
146
+
resolution: {integrity: sha512-5UbSJfdV3JIkF8ksXz7g4nKBWasf2wROvzM66cfvTIWydWFO6/oS1KZd+zo9Eokje5Scf5+jsY9ZfgVARLepXg==}
141
147
peerDependencies:
142
-
'@atcute/identity': ^0.1.0
148
+
'@atcute/identity': ^1.0.0
149
+
150
+
'@atcute/identity@1.1.3':
151
+
resolution: {integrity: sha512-oIqPoI8TwWeQxvcLmFEZLdN2XdWcaLVtlm8pNk0E72As9HNzzD9pwKPrLr3rmTLRIoULPPFmq9iFNsTeCIU9ng==}
152
+
153
+
'@atcute/lexicons@1.2.5':
154
+
resolution: {integrity: sha512-9yO9WdgxW8jZ7SbzUycH710z+JmsQ9W9n5S6i6eghYju32kkluFmgBeS47r8e8p2+Dv4DemS7o/3SUGsX9FR5Q==}
155
+
156
+
'@atcute/mst@0.1.0':
157
+
resolution: {integrity: sha512-h+iDToKEnBpigk2DOHjSqY63vJtjYKUIztqu1CZ0P+I54wV2SrgoqAXAT1xrW6A1Iup8cjTv+U2H5WVG4KxPLw==}
143
158
144
-
'@atcute/identity@0.1.3':
145
-
resolution: {integrity: sha512-ndlD8nypHt8G00wixbozKdSNL0O8HTzBjFGEXeAcBUCXSZPBjRWbqtgyJxhgUWnr7swgxgw1mSbZwRB5b7xCiQ==}
159
+
'@atcute/multibase@1.1.6':
160
+
resolution: {integrity: sha512-HBxuCgYLKPPxETV0Rot4VP9e24vKl8JdzGCZOVsDaOXJgbRZoRIF67Lp0H/OgnJeH/Xpva8Z5ReoTNJE5dn3kg==}
146
161
147
-
'@atcute/multibase@1.1.3':
148
-
resolution: {integrity: sha512-vQQO0tDuQPguBvHdgV3ryn7R8U6beQ50KA/juYm+dCeT/3hOK2stMbX+IaW8JEuwkT5lJsU8wDIOicQT4mB7Ag==}
162
+
'@atcute/repo@0.1.0':
163
+
resolution: {integrity: sha512-INiYAuma8dydBu7cqd2WVpcXh3mzhIepYBUqFWAK5MqMulPRLTRCc/9GW3G9pxYrOdlvLCVamG2Jf8XK0nuFEw==}
149
164
150
-
'@atcute/tid@1.0.2':
151
-
resolution: {integrity: sha512-ahmjroNyeDPJhtuf3+HTJropaH04HmJ8fhntDu73Gpz/RkAF7+nkz6kcP2QTgfvMCgMPAJUdskAAP82GPDTY9w==}
165
+
'@atcute/tid@1.0.3':
166
+
resolution: {integrity: sha512-wfMJx1IMdnu0CZgWl0uR4JO2s6PGT1YPhpytD4ZHzEYKKQVuqV6Eb/7vieaVo1eYNMp2FrY67FZObeR7utRl2w==}
152
167
153
-
'@atcute/uint8array@1.0.1':
154
-
resolution: {integrity: sha512-AAnlFKyfDRgb9GNZJbhQ6OuMhbmNPirQyapb8KnmcEhxQZ3+tt+4NcwqekEegY4MpNqSTYeeTdyxq0wGZv1JHg==}
168
+
'@atcute/uint8array@1.0.6':
169
+
resolution: {integrity: sha512-ucfRBQc7BFT8n9eCyGOzDHEMKF/nZwhS2pPao4Xtab1ML3HdFYcX2DM1tadCzas85QTGxHe5urnUAAcNKGRi9A==}
155
170
156
-
'@atcute/util-fetch@1.0.1':
157
-
resolution: {integrity: sha512-Clc0E/5ufyGBVfYBUwWNlHONlZCoblSr4Ho50l1LhmRPGB1Wu/AQ9Sz+rsBg7fdaW/auve8ulmwhRhnX2cGRow==}
171
+
'@atcute/util-fetch@1.0.4':
172
+
resolution: {integrity: sha512-sIU9Qk0dE8PLEXSfhy+gIJV+HpiiknMytCI2SqLlqd0vgZUtEKI/EQfP+23LHWvP+CLCzVDOa6cpH045OlmNBg==}
158
173
159
-
'@atcute/varint@1.0.2':
160
-
resolution: {integrity: sha512-0O31hePzzr4O3NGWHUKKOyta6CGSL+AtN8iir8grGxu9jXyI7DBARlw6PbgKA6uTAvsXdpmRmF8MX+p0TsLnNg==}
174
+
'@atcute/varint@1.0.3':
175
+
resolution: {integrity: sha512-fdvMPyBB+McDT+Ai5e9RwEbwYV4yjZ60S2Dn5PTjGqUyxvoCH1z42viuheDZRUDkmfQehXJTZ5az7dSozVNtog==}
161
176
162
177
'@babel/code-frame@7.27.1':
163
178
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
164
179
engines: {node: '>=6.9.0'}
165
180
166
-
'@babel/compat-data@7.27.1':
167
-
resolution: {integrity: sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==}
181
+
'@babel/compat-data@7.28.5':
182
+
resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==}
168
183
engines: {node: '>=6.9.0'}
169
184
170
-
'@babel/core@7.27.1':
171
-
resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==}
185
+
'@babel/core@7.28.5':
186
+
resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==}
187
+
engines: {node: '>=6.9.0'}
188
+
189
+
'@babel/generator@7.28.5':
190
+
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
172
191
engines: {node: '>=6.9.0'}
173
192
174
-
'@babel/generator@7.27.1':
175
-
resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==}
193
+
'@babel/helper-compilation-targets@7.27.2':
194
+
resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
176
195
engines: {node: '>=6.9.0'}
177
196
178
-
'@babel/helper-compilation-targets@7.27.1':
179
-
resolution: {integrity: sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g==}
197
+
'@babel/helper-globals@7.28.0':
198
+
resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
180
199
engines: {node: '>=6.9.0'}
181
200
182
201
'@babel/helper-module-imports@7.18.6':
···
187
206
resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
188
207
engines: {node: '>=6.9.0'}
189
208
190
-
'@babel/helper-module-transforms@7.27.1':
191
-
resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==}
209
+
'@babel/helper-module-transforms@7.28.3':
210
+
resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
192
211
engines: {node: '>=6.9.0'}
193
212
peerDependencies:
194
213
'@babel/core': ^7.0.0
···
201
220
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
202
221
engines: {node: '>=6.9.0'}
203
222
204
-
'@babel/helper-validator-identifier@7.27.1':
205
-
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
223
+
'@babel/helper-validator-identifier@7.28.5':
224
+
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
206
225
engines: {node: '>=6.9.0'}
207
226
208
227
'@babel/helper-validator-option@7.27.1':
209
228
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
210
229
engines: {node: '>=6.9.0'}
211
230
212
-
'@babel/helpers@7.27.1':
213
-
resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==}
231
+
'@babel/helpers@7.28.4':
232
+
resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
214
233
engines: {node: '>=6.9.0'}
215
234
216
-
'@babel/parser@7.27.1':
217
-
resolution: {integrity: sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==}
235
+
'@babel/parser@7.28.5':
236
+
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
218
237
engines: {node: '>=6.0.0'}
219
238
hasBin: true
220
239
···
224
243
peerDependencies:
225
244
'@babel/core': ^7.0.0-0
226
245
227
-
'@babel/template@7.27.1':
228
-
resolution: {integrity: sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==}
246
+
'@babel/template@7.27.2':
247
+
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
229
248
engines: {node: '>=6.9.0'}
230
249
231
-
'@babel/traverse@7.27.1':
232
-
resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==}
250
+
'@babel/traverse@7.28.5':
251
+
resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
233
252
engines: {node: '>=6.9.0'}
234
253
235
-
'@babel/types@7.27.1':
236
-
resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==}
254
+
'@babel/types@7.28.5':
255
+
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
237
256
engines: {node: '>=6.9.0'}
238
257
239
-
'@badrap/valita@0.4.4':
240
-
resolution: {integrity: sha512-GEhUCk9c4XbNxi+0YZHZsV4fYNd6HejfWuN4Ti4c02DauX+LyX5WY1Y3WfyZ8Pxxl0zqhs+MLtW98cMh86vv6g==}
258
+
'@badrap/valita@0.4.6':
259
+
resolution: {integrity: sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==}
241
260
engines: {node: '>= 18'}
242
261
243
-
'@cloudflare/kv-asset-handler@0.4.0':
244
-
resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==}
262
+
'@cloudflare/kv-asset-handler@0.4.1':
263
+
resolution: {integrity: sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==}
245
264
engines: {node: '>=18.0.0'}
246
265
247
-
'@cloudflare/unenv-preset@2.3.1':
248
-
resolution: {integrity: sha512-Xq57Qd+ADpt6hibcVBO0uLG9zzRgyRhfCUgBT9s+g3+3Ivg5zDyVgLFy40ES1VdNcu8rPNSivm9A+kGP5IVaPg==}
266
+
'@cloudflare/unenv-preset@2.7.13':
267
+
resolution: {integrity: sha512-NulO1H8R/DzsJguLC0ndMuk4Ufv0KSlN+E54ay9rn9ZCQo0kpAPwwh3LhgpZ96a3Dr6L9LqW57M4CqC34iLOvw==}
249
268
peerDependencies:
250
-
unenv: 2.0.0-rc.15
251
-
workerd: ^1.20250320.0
269
+
unenv: 2.0.0-rc.24
270
+
workerd: ^1.20251202.0
252
271
peerDependenciesMeta:
253
272
workerd:
254
273
optional: true
255
274
256
-
'@cloudflare/workerd-darwin-64@1.20250428.0':
257
-
resolution: {integrity: sha512-6nVe9oV4Hdec6ctzMtW80TiDvNTd2oFPi3VsKqSDVaJSJbL+4b6seyJ7G/UEPI+si6JhHBSLV2/9lNXNGLjClA==}
275
+
'@cloudflare/workerd-darwin-64@1.20251202.0':
276
+
resolution: {integrity: sha512-/uvEAWEukTWb1geHhbjGUeZqcSSSyYzp0mvoPUBl+l0ont4NVGao3fgwM0q8wtKvgoKCHSG6zcG23wj9Opj3Nw==}
258
277
engines: {node: '>=16'}
259
278
cpu: [x64]
260
279
os: [darwin]
261
280
262
-
'@cloudflare/workerd-darwin-arm64@1.20250428.0':
263
-
resolution: {integrity: sha512-/TB7bh7SIJ5f+6r4PHsAz7+9Qal/TK1cJuKFkUno1kqGlZbdrMwH0ATYwlWC/nBFeu2FB3NUolsTntEuy23hnQ==}
281
+
'@cloudflare/workerd-darwin-arm64@1.20251202.0':
282
+
resolution: {integrity: sha512-f52xRvcI9cWRd6400EZStRtXiRC5XKEud7K5aFIbbUv0VeINltujFQQ9nHWtsF6g1quIXWkjhh5u01gPAYNNXA==}
264
283
engines: {node: '>=16'}
265
284
cpu: [arm64]
266
285
os: [darwin]
267
286
268
-
'@cloudflare/workerd-linux-64@1.20250428.0':
269
-
resolution: {integrity: sha512-9eCbj+R3CKqpiXP6DfAA20DxKge+OTj7Hyw3ZewiEhWH9INIHiJwJQYybu4iq9kJEGjnGvxgguLFjSCWm26hgg==}
287
+
'@cloudflare/workerd-linux-64@1.20251202.0':
288
+
resolution: {integrity: sha512-HYXinF5RBH7oXbsFUMmwKCj+WltpYbf5mRKUBG5v3EuPhUjSIFB84U+58pDyfBJjcynHdy3EtvTWcvh/+lcgow==}
270
289
engines: {node: '>=16'}
271
290
cpu: [x64]
272
291
os: [linux]
273
292
274
-
'@cloudflare/workerd-linux-arm64@1.20250428.0':
275
-
resolution: {integrity: sha512-D9NRBnW46nl1EQsP13qfkYb5lbt4C6nxl38SBKY/NOcZAUoHzNB5K0GaK8LxvpkM7X/97ySojlMfR5jh5DNXYQ==}
293
+
'@cloudflare/workerd-linux-arm64@1.20251202.0':
294
+
resolution: {integrity: sha512-++L02Jdoxz7hEA9qDaQjbVU1RzQS+S+eqIi22DkPe2Tgiq2M3UfNpeu+75k5L9DGRIkZPYvwMBMbcmKvQqdIIg==}
276
295
engines: {node: '>=16'}
277
296
cpu: [arm64]
278
297
os: [linux]
279
298
280
-
'@cloudflare/workerd-windows-64@1.20250428.0':
281
-
resolution: {integrity: sha512-RQCRj28eitjKD0tmei6iFOuWqMuHMHdNGEigRmbkmuTlpbWHNAoHikgCzZQ/dkKDdatA76TmcpbyECNf31oaTA==}
299
+
'@cloudflare/workerd-windows-64@1.20251202.0':
300
+
resolution: {integrity: sha512-gzeU6eDydTi7ib+Q9DD/c0hpXtqPucnHk2tfGU03mljPObYxzMkkPGgB5qxpksFvub3y4K0ChjqYxGJB4F+j3g==}
282
301
engines: {node: '>=16'}
283
302
cpu: [x64]
284
303
os: [win32]
···
287
306
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
288
307
engines: {node: '>=12'}
289
308
290
-
'@emnapi/runtime@1.4.3':
291
-
resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==}
309
+
'@emnapi/runtime@1.7.1':
310
+
resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==}
292
311
293
-
'@esbuild/aix-ppc64@0.25.2':
294
-
resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==}
312
+
'@esbuild/aix-ppc64@0.25.12':
313
+
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
295
314
engines: {node: '>=18'}
296
315
cpu: [ppc64]
297
316
os: [aix]
298
317
299
-
'@esbuild/aix-ppc64@0.25.4':
300
-
resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==}
318
+
'@esbuild/aix-ppc64@0.27.0':
319
+
resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==}
301
320
engines: {node: '>=18'}
302
321
cpu: [ppc64]
303
322
os: [aix]
304
323
305
-
'@esbuild/android-arm64@0.25.2':
306
-
resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==}
324
+
'@esbuild/android-arm64@0.25.12':
325
+
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
307
326
engines: {node: '>=18'}
308
327
cpu: [arm64]
309
328
os: [android]
310
329
311
-
'@esbuild/android-arm64@0.25.4':
312
-
resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==}
330
+
'@esbuild/android-arm64@0.27.0':
331
+
resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==}
313
332
engines: {node: '>=18'}
314
333
cpu: [arm64]
315
334
os: [android]
316
335
317
-
'@esbuild/android-arm@0.25.2':
318
-
resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==}
336
+
'@esbuild/android-arm@0.25.12':
337
+
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
319
338
engines: {node: '>=18'}
320
339
cpu: [arm]
321
340
os: [android]
322
341
323
-
'@esbuild/android-arm@0.25.4':
324
-
resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==}
342
+
'@esbuild/android-arm@0.27.0':
343
+
resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==}
325
344
engines: {node: '>=18'}
326
345
cpu: [arm]
327
346
os: [android]
328
347
329
-
'@esbuild/android-x64@0.25.2':
330
-
resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==}
348
+
'@esbuild/android-x64@0.25.12':
349
+
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
331
350
engines: {node: '>=18'}
332
351
cpu: [x64]
333
352
os: [android]
334
353
335
-
'@esbuild/android-x64@0.25.4':
336
-
resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==}
354
+
'@esbuild/android-x64@0.27.0':
355
+
resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==}
337
356
engines: {node: '>=18'}
338
357
cpu: [x64]
339
358
os: [android]
340
359
341
-
'@esbuild/darwin-arm64@0.25.2':
342
-
resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==}
360
+
'@esbuild/darwin-arm64@0.25.12':
361
+
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
343
362
engines: {node: '>=18'}
344
363
cpu: [arm64]
345
364
os: [darwin]
346
365
347
-
'@esbuild/darwin-arm64@0.25.4':
348
-
resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==}
366
+
'@esbuild/darwin-arm64@0.27.0':
367
+
resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==}
349
368
engines: {node: '>=18'}
350
369
cpu: [arm64]
351
370
os: [darwin]
352
371
353
-
'@esbuild/darwin-x64@0.25.2':
354
-
resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==}
372
+
'@esbuild/darwin-x64@0.25.12':
373
+
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
355
374
engines: {node: '>=18'}
356
375
cpu: [x64]
357
376
os: [darwin]
358
377
359
-
'@esbuild/darwin-x64@0.25.4':
360
-
resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==}
378
+
'@esbuild/darwin-x64@0.27.0':
379
+
resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==}
361
380
engines: {node: '>=18'}
362
381
cpu: [x64]
363
382
os: [darwin]
364
383
365
-
'@esbuild/freebsd-arm64@0.25.2':
366
-
resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==}
384
+
'@esbuild/freebsd-arm64@0.25.12':
385
+
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
367
386
engines: {node: '>=18'}
368
387
cpu: [arm64]
369
388
os: [freebsd]
370
389
371
-
'@esbuild/freebsd-arm64@0.25.4':
372
-
resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==}
390
+
'@esbuild/freebsd-arm64@0.27.0':
391
+
resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==}
373
392
engines: {node: '>=18'}
374
393
cpu: [arm64]
375
394
os: [freebsd]
376
395
377
-
'@esbuild/freebsd-x64@0.25.2':
378
-
resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==}
396
+
'@esbuild/freebsd-x64@0.25.12':
397
+
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
379
398
engines: {node: '>=18'}
380
399
cpu: [x64]
381
400
os: [freebsd]
382
401
383
-
'@esbuild/freebsd-x64@0.25.4':
384
-
resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==}
402
+
'@esbuild/freebsd-x64@0.27.0':
403
+
resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==}
385
404
engines: {node: '>=18'}
386
405
cpu: [x64]
387
406
os: [freebsd]
388
407
389
-
'@esbuild/linux-arm64@0.25.2':
390
-
resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==}
408
+
'@esbuild/linux-arm64@0.25.12':
409
+
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
391
410
engines: {node: '>=18'}
392
411
cpu: [arm64]
393
412
os: [linux]
394
413
395
-
'@esbuild/linux-arm64@0.25.4':
396
-
resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==}
414
+
'@esbuild/linux-arm64@0.27.0':
415
+
resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==}
397
416
engines: {node: '>=18'}
398
417
cpu: [arm64]
399
418
os: [linux]
400
419
401
-
'@esbuild/linux-arm@0.25.2':
402
-
resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==}
420
+
'@esbuild/linux-arm@0.25.12':
421
+
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
403
422
engines: {node: '>=18'}
404
423
cpu: [arm]
405
424
os: [linux]
406
425
407
-
'@esbuild/linux-arm@0.25.4':
408
-
resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==}
426
+
'@esbuild/linux-arm@0.27.0':
427
+
resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==}
409
428
engines: {node: '>=18'}
410
429
cpu: [arm]
411
430
os: [linux]
412
431
413
-
'@esbuild/linux-ia32@0.25.2':
414
-
resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==}
432
+
'@esbuild/linux-ia32@0.25.12':
433
+
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
415
434
engines: {node: '>=18'}
416
435
cpu: [ia32]
417
436
os: [linux]
418
437
419
-
'@esbuild/linux-ia32@0.25.4':
420
-
resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==}
438
+
'@esbuild/linux-ia32@0.27.0':
439
+
resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==}
421
440
engines: {node: '>=18'}
422
441
cpu: [ia32]
423
442
os: [linux]
424
443
425
-
'@esbuild/linux-loong64@0.25.2':
426
-
resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==}
444
+
'@esbuild/linux-loong64@0.25.12':
445
+
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
427
446
engines: {node: '>=18'}
428
447
cpu: [loong64]
429
448
os: [linux]
430
449
431
-
'@esbuild/linux-loong64@0.25.4':
432
-
resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==}
450
+
'@esbuild/linux-loong64@0.27.0':
451
+
resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==}
433
452
engines: {node: '>=18'}
434
453
cpu: [loong64]
435
454
os: [linux]
436
455
437
-
'@esbuild/linux-mips64el@0.25.2':
438
-
resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==}
456
+
'@esbuild/linux-mips64el@0.25.12':
457
+
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
439
458
engines: {node: '>=18'}
440
459
cpu: [mips64el]
441
460
os: [linux]
442
461
443
-
'@esbuild/linux-mips64el@0.25.4':
444
-
resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==}
462
+
'@esbuild/linux-mips64el@0.27.0':
463
+
resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==}
445
464
engines: {node: '>=18'}
446
465
cpu: [mips64el]
447
466
os: [linux]
448
467
449
-
'@esbuild/linux-ppc64@0.25.2':
450
-
resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==}
468
+
'@esbuild/linux-ppc64@0.25.12':
469
+
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
451
470
engines: {node: '>=18'}
452
471
cpu: [ppc64]
453
472
os: [linux]
454
473
455
-
'@esbuild/linux-ppc64@0.25.4':
456
-
resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==}
474
+
'@esbuild/linux-ppc64@0.27.0':
475
+
resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==}
457
476
engines: {node: '>=18'}
458
477
cpu: [ppc64]
459
478
os: [linux]
460
479
461
-
'@esbuild/linux-riscv64@0.25.2':
462
-
resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==}
480
+
'@esbuild/linux-riscv64@0.25.12':
481
+
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
463
482
engines: {node: '>=18'}
464
483
cpu: [riscv64]
465
484
os: [linux]
466
485
467
-
'@esbuild/linux-riscv64@0.25.4':
468
-
resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==}
486
+
'@esbuild/linux-riscv64@0.27.0':
487
+
resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==}
469
488
engines: {node: '>=18'}
470
489
cpu: [riscv64]
471
490
os: [linux]
472
491
473
-
'@esbuild/linux-s390x@0.25.2':
474
-
resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==}
492
+
'@esbuild/linux-s390x@0.25.12':
493
+
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
475
494
engines: {node: '>=18'}
476
495
cpu: [s390x]
477
496
os: [linux]
478
497
479
-
'@esbuild/linux-s390x@0.25.4':
480
-
resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==}
498
+
'@esbuild/linux-s390x@0.27.0':
499
+
resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==}
481
500
engines: {node: '>=18'}
482
501
cpu: [s390x]
483
502
os: [linux]
484
503
485
-
'@esbuild/linux-x64@0.25.2':
486
-
resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==}
504
+
'@esbuild/linux-x64@0.25.12':
505
+
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
487
506
engines: {node: '>=18'}
488
507
cpu: [x64]
489
508
os: [linux]
490
509
491
-
'@esbuild/linux-x64@0.25.4':
492
-
resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==}
510
+
'@esbuild/linux-x64@0.27.0':
511
+
resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==}
493
512
engines: {node: '>=18'}
494
513
cpu: [x64]
495
514
os: [linux]
496
515
497
-
'@esbuild/netbsd-arm64@0.25.2':
498
-
resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==}
516
+
'@esbuild/netbsd-arm64@0.25.12':
517
+
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
499
518
engines: {node: '>=18'}
500
519
cpu: [arm64]
501
520
os: [netbsd]
502
521
503
-
'@esbuild/netbsd-arm64@0.25.4':
504
-
resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==}
522
+
'@esbuild/netbsd-arm64@0.27.0':
523
+
resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==}
505
524
engines: {node: '>=18'}
506
525
cpu: [arm64]
507
526
os: [netbsd]
508
527
509
-
'@esbuild/netbsd-x64@0.25.2':
510
-
resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==}
528
+
'@esbuild/netbsd-x64@0.25.12':
529
+
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
511
530
engines: {node: '>=18'}
512
531
cpu: [x64]
513
532
os: [netbsd]
514
533
515
-
'@esbuild/netbsd-x64@0.25.4':
516
-
resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==}
534
+
'@esbuild/netbsd-x64@0.27.0':
535
+
resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==}
517
536
engines: {node: '>=18'}
518
537
cpu: [x64]
519
538
os: [netbsd]
520
539
521
-
'@esbuild/openbsd-arm64@0.25.2':
522
-
resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==}
540
+
'@esbuild/openbsd-arm64@0.25.12':
541
+
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
523
542
engines: {node: '>=18'}
524
543
cpu: [arm64]
525
544
os: [openbsd]
526
545
527
-
'@esbuild/openbsd-arm64@0.25.4':
528
-
resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==}
546
+
'@esbuild/openbsd-arm64@0.27.0':
547
+
resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==}
529
548
engines: {node: '>=18'}
530
549
cpu: [arm64]
531
550
os: [openbsd]
532
551
533
-
'@esbuild/openbsd-x64@0.25.2':
534
-
resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==}
552
+
'@esbuild/openbsd-x64@0.25.12':
553
+
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
535
554
engines: {node: '>=18'}
536
555
cpu: [x64]
537
556
os: [openbsd]
538
557
539
-
'@esbuild/openbsd-x64@0.25.4':
540
-
resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==}
558
+
'@esbuild/openbsd-x64@0.27.0':
559
+
resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==}
541
560
engines: {node: '>=18'}
542
561
cpu: [x64]
543
562
os: [openbsd]
544
563
545
-
'@esbuild/sunos-x64@0.25.2':
546
-
resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==}
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==}
547
578
engines: {node: '>=18'}
548
579
cpu: [x64]
549
580
os: [sunos]
550
581
551
-
'@esbuild/sunos-x64@0.25.4':
552
-
resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==}
582
+
'@esbuild/sunos-x64@0.27.0':
583
+
resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==}
553
584
engines: {node: '>=18'}
554
585
cpu: [x64]
555
586
os: [sunos]
556
587
557
-
'@esbuild/win32-arm64@0.25.2':
558
-
resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==}
588
+
'@esbuild/win32-arm64@0.25.12':
589
+
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
559
590
engines: {node: '>=18'}
560
591
cpu: [arm64]
561
592
os: [win32]
562
593
563
-
'@esbuild/win32-arm64@0.25.4':
564
-
resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==}
594
+
'@esbuild/win32-arm64@0.27.0':
595
+
resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==}
565
596
engines: {node: '>=18'}
566
597
cpu: [arm64]
567
598
os: [win32]
568
599
569
-
'@esbuild/win32-ia32@0.25.2':
570
-
resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==}
600
+
'@esbuild/win32-ia32@0.25.12':
601
+
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
571
602
engines: {node: '>=18'}
572
603
cpu: [ia32]
573
604
os: [win32]
574
605
575
-
'@esbuild/win32-ia32@0.25.4':
576
-
resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==}
606
+
'@esbuild/win32-ia32@0.27.0':
607
+
resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==}
577
608
engines: {node: '>=18'}
578
609
cpu: [ia32]
579
610
os: [win32]
580
611
581
-
'@esbuild/win32-x64@0.25.2':
582
-
resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==}
612
+
'@esbuild/win32-x64@0.25.12':
613
+
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
583
614
engines: {node: '>=18'}
584
615
cpu: [x64]
585
616
os: [win32]
586
617
587
-
'@esbuild/win32-x64@0.25.4':
588
-
resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==}
618
+
'@esbuild/win32-x64@0.27.0':
619
+
resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==}
589
620
engines: {node: '>=18'}
590
621
cpu: [x64]
591
622
os: [win32]
···
594
625
resolution: {integrity: sha512-duvZBfJB9oOLphx04ckKF534hP186xIBFaw4GHJ5fGeZY5syZs59UeumV5NC6aiEU9hVhAFMOnDDGkQrFqHrnQ==}
595
626
peerDependencies:
596
627
solid-js: ^1.8.5
597
-
598
-
'@fastify/busboy@2.1.1':
599
-
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
600
-
engines: {node: '>=14'}
601
628
602
629
'@img/sharp-darwin-arm64@0.33.5':
603
630
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
···
704
731
cpu: [x64]
705
732
os: [win32]
706
733
707
-
'@isaacs/cliui@8.0.2':
708
-
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
709
-
engines: {node: '>=12'}
734
+
'@jridgewell/gen-mapping@0.3.13':
735
+
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
710
736
711
-
'@jridgewell/gen-mapping@0.3.8':
712
-
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
713
-
engines: {node: '>=6.0.0'}
737
+
'@jridgewell/remapping@2.3.5':
738
+
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
714
739
715
740
'@jridgewell/resolve-uri@3.1.2':
716
741
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
717
742
engines: {node: '>=6.0.0'}
718
743
719
-
'@jridgewell/set-array@1.2.1':
720
-
resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
721
-
engines: {node: '>=6.0.0'}
722
-
723
-
'@jridgewell/source-map@0.3.6':
724
-
resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==}
744
+
'@jridgewell/source-map@0.3.11':
745
+
resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==}
725
746
726
-
'@jridgewell/sourcemap-codec@1.5.0':
727
-
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
747
+
'@jridgewell/sourcemap-codec@1.5.5':
748
+
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
728
749
729
-
'@jridgewell/trace-mapping@0.3.25':
730
-
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
750
+
'@jridgewell/trace-mapping@0.3.31':
751
+
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
731
752
732
753
'@jridgewell/trace-mapping@0.3.9':
733
754
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
734
755
735
-
'@jsr/mary__array-fns@0.1.4':
736
-
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}
737
758
738
-
'@jsr/mary__ds-queue@0.1.2':
739
-
resolution: {integrity: sha512-AOZ/FXYHVWI05bNHgi/Ln0RCiWvOQuZ/fZ1AxkT27Ytbon8VNtLAYs7uOgVITJcbMrsdE6zJXh/bP9LF16sk/A==, tarball: https://npm.jsr.io/~/11/@jsr/mary__ds-queue/0.1.2.tgz}
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}
740
761
741
762
'@jsr/mary__events@0.2.0':
742
763
resolution: {integrity: sha512-WcBRbtuTno3zcfXKd7SEeKr1lAJF+CQ8BCv+PEEMmNKNqFurkEksGxRB3UDPZxIxjJ7sAqMVTL26wRuMpAcIeA==, tarball: https://npm.jsr.io/~/11/@jsr/mary__events/0.2.0.tgz}
743
764
744
-
'@jsr/mary__tar@0.2.4':
745
-
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}
746
767
747
-
'@noble/secp256k1@2.2.3':
748
-
resolution: {integrity: sha512-l7r5oEQym9Us7EAigzg30/PQAvynhMt2uoYtT3t26eGDVm9Yii5mZ5jWSWmZ/oSIR2Et0xfc6DXrG0bZ787V3w==}
768
+
'@noble/secp256k1@3.0.0':
769
+
resolution: {integrity: sha512-NJBaR352KyIvj3t6sgT/+7xrNyF9Xk9QlLSIqUGVUYlsnDTAUqY8LOmwpcgEx4AMJXRITQ5XEVHD+mMaPfr3mg==}
749
770
750
771
'@nodelib/fs.scandir@2.1.5':
751
772
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
···
759
780
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
760
781
engines: {node: '>= 8'}
761
782
762
-
'@pkgjs/parseargs@0.11.0':
763
-
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
764
-
engines: {node: '>=14'}
783
+
'@poppinss/colors@4.1.5':
784
+
resolution: {integrity: sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==}
765
785
766
-
'@rollup/rollup-android-arm-eabi@4.40.2':
767
-
resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==}
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==}
791
+
792
+
'@rollup/rollup-android-arm-eabi@4.53.3':
793
+
resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==}
768
794
cpu: [arm]
769
795
os: [android]
770
796
771
-
'@rollup/rollup-android-arm64@4.40.2':
772
-
resolution: {integrity: sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==}
797
+
'@rollup/rollup-android-arm64@4.53.3':
798
+
resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==}
773
799
cpu: [arm64]
774
800
os: [android]
775
801
776
-
'@rollup/rollup-darwin-arm64@4.40.2':
777
-
resolution: {integrity: sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==}
802
+
'@rollup/rollup-darwin-arm64@4.53.3':
803
+
resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==}
778
804
cpu: [arm64]
779
805
os: [darwin]
780
806
781
-
'@rollup/rollup-darwin-x64@4.40.2':
782
-
resolution: {integrity: sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==}
807
+
'@rollup/rollup-darwin-x64@4.53.3':
808
+
resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==}
783
809
cpu: [x64]
784
810
os: [darwin]
785
811
786
-
'@rollup/rollup-freebsd-arm64@4.40.2':
787
-
resolution: {integrity: sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==}
812
+
'@rollup/rollup-freebsd-arm64@4.53.3':
813
+
resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==}
788
814
cpu: [arm64]
789
815
os: [freebsd]
790
816
791
-
'@rollup/rollup-freebsd-x64@4.40.2':
792
-
resolution: {integrity: sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==}
817
+
'@rollup/rollup-freebsd-x64@4.53.3':
818
+
resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==}
793
819
cpu: [x64]
794
820
os: [freebsd]
795
821
796
-
'@rollup/rollup-linux-arm-gnueabihf@4.40.2':
797
-
resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==}
822
+
'@rollup/rollup-linux-arm-gnueabihf@4.53.3':
823
+
resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==}
798
824
cpu: [arm]
799
825
os: [linux]
800
826
801
-
'@rollup/rollup-linux-arm-musleabihf@4.40.2':
802
-
resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==}
827
+
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
828
+
resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==}
803
829
cpu: [arm]
804
830
os: [linux]
805
831
806
-
'@rollup/rollup-linux-arm64-gnu@4.40.2':
807
-
resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==}
832
+
'@rollup/rollup-linux-arm64-gnu@4.53.3':
833
+
resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==}
808
834
cpu: [arm64]
809
835
os: [linux]
810
836
811
-
'@rollup/rollup-linux-arm64-musl@4.40.2':
812
-
resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==}
837
+
'@rollup/rollup-linux-arm64-musl@4.53.3':
838
+
resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==}
813
839
cpu: [arm64]
814
840
os: [linux]
815
841
816
-
'@rollup/rollup-linux-loongarch64-gnu@4.40.2':
817
-
resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==}
842
+
'@rollup/rollup-linux-loong64-gnu@4.53.3':
843
+
resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==}
818
844
cpu: [loong64]
819
845
os: [linux]
820
846
821
-
'@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
822
-
resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==}
847
+
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
848
+
resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==}
823
849
cpu: [ppc64]
824
850
os: [linux]
825
851
826
-
'@rollup/rollup-linux-riscv64-gnu@4.40.2':
827
-
resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==}
852
+
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
853
+
resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==}
828
854
cpu: [riscv64]
829
855
os: [linux]
830
856
831
-
'@rollup/rollup-linux-riscv64-musl@4.40.2':
832
-
resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==}
857
+
'@rollup/rollup-linux-riscv64-musl@4.53.3':
858
+
resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==}
833
859
cpu: [riscv64]
834
860
os: [linux]
835
861
836
-
'@rollup/rollup-linux-s390x-gnu@4.40.2':
837
-
resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==}
862
+
'@rollup/rollup-linux-s390x-gnu@4.53.3':
863
+
resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==}
838
864
cpu: [s390x]
839
865
os: [linux]
840
866
841
-
'@rollup/rollup-linux-x64-gnu@4.40.2':
842
-
resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==}
867
+
'@rollup/rollup-linux-x64-gnu@4.53.3':
868
+
resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==}
843
869
cpu: [x64]
844
870
os: [linux]
845
871
846
-
'@rollup/rollup-linux-x64-musl@4.40.2':
847
-
resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==}
872
+
'@rollup/rollup-linux-x64-musl@4.53.3':
873
+
resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==}
848
874
cpu: [x64]
849
875
os: [linux]
850
876
851
-
'@rollup/rollup-win32-arm64-msvc@4.40.2':
852
-
resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==}
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==}
853
884
cpu: [arm64]
854
885
os: [win32]
855
886
856
-
'@rollup/rollup-win32-ia32-msvc@4.40.2':
857
-
resolution: {integrity: sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==}
887
+
'@rollup/rollup-win32-ia32-msvc@4.53.3':
888
+
resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==}
858
889
cpu: [ia32]
859
890
os: [win32]
860
891
861
-
'@rollup/rollup-win32-x64-msvc@4.40.2':
862
-
resolution: {integrity: sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==}
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==}
863
899
cpu: [x64]
864
900
os: [win32]
865
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
+
866
912
'@tailwindcss/forms@0.5.10':
867
913
resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==}
868
914
peerDependencies:
···
877
923
'@types/babel__template@7.4.4':
878
924
resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
879
925
880
-
'@types/babel__traverse@7.20.7':
881
-
resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==}
926
+
'@types/babel__traverse@7.28.0':
927
+
resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
882
928
883
-
'@types/estree@1.0.7':
884
-
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
929
+
'@types/estree@1.0.8':
930
+
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
885
931
886
-
'@types/node@22.15.12':
887
-
resolution: {integrity: sha512-K0fpC/ZVeb8G9rm7bH7vI0KAec4XHEhBam616nVJCV51bKzJ6oA3luG4WdKoaztxe70QaNjS/xBmcDLmr4PiGw==}
932
+
'@types/node@22.19.2':
933
+
resolution: {integrity: sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==}
888
934
889
935
acorn-walk@8.3.2:
890
936
resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
···
895
941
engines: {node: '>=0.4.0'}
896
942
hasBin: true
897
943
898
-
acorn@8.14.1:
899
-
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
944
+
acorn@8.15.0:
945
+
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
900
946
engines: {node: '>=0.4.0'}
901
947
hasBin: true
902
-
903
-
ansi-regex@5.0.1:
904
-
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
905
-
engines: {node: '>=8'}
906
-
907
-
ansi-regex@6.1.0:
908
-
resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
909
-
engines: {node: '>=12'}
910
-
911
-
ansi-styles@4.3.0:
912
-
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
913
-
engines: {node: '>=8'}
914
-
915
-
ansi-styles@6.2.1:
916
-
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
917
-
engines: {node: '>=12'}
918
948
919
949
any-promise@1.3.0:
920
950
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
···
926
956
arg@5.0.2:
927
957
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
928
958
929
-
as-table@1.0.55:
930
-
resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==}
931
-
932
-
autoprefixer@10.4.21:
933
-
resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==}
959
+
autoprefixer@10.4.22:
960
+
resolution: {integrity: sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==}
934
961
engines: {node: ^10 || ^12 || >=14}
935
962
hasBin: true
936
963
peerDependencies:
937
964
postcss: ^8.1.0
938
965
939
-
babel-plugin-jsx-dom-expressions@0.39.8:
940
-
resolution: {integrity: sha512-/MVOIIjonylDXnrWmG23ZX82m9mtKATsVHB7zYlPfDR9Vdd/NBE48if+wv27bSkBtyO7EPMUlcUc4J63QwuACQ==}
966
+
babel-plugin-jsx-dom-expressions@0.40.3:
967
+
resolution: {integrity: sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w==}
941
968
peerDependencies:
942
969
'@babel/core': ^7.20.12
943
970
944
-
babel-preset-solid@1.9.6:
945
-
resolution: {integrity: sha512-HXTK9f93QxoH8dYn1M2mJdOlWgMsR88Lg/ul6QCZGkNTktjTE5HAf93YxQumHoCudLEtZrU1cFCMFOVho6GqFg==}
971
+
babel-preset-solid@1.9.10:
972
+
resolution: {integrity: sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ==}
946
973
peerDependencies:
947
974
'@babel/core': ^7.0.0
975
+
solid-js: ^1.9.10
976
+
peerDependenciesMeta:
977
+
solid-js:
978
+
optional: true
948
979
949
-
balanced-match@1.0.2:
950
-
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
980
+
baseline-browser-mapping@2.9.5:
981
+
resolution: {integrity: sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==}
982
+
hasBin: true
951
983
952
984
binary-extensions@2.3.0:
953
985
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
···
956
988
blake3-wasm@2.1.5:
957
989
resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
958
990
959
-
brace-expansion@2.0.1:
960
-
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
961
-
962
991
braces@3.0.3:
963
992
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
964
993
engines: {node: '>=8'}
965
994
966
-
browserslist@4.24.5:
967
-
resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==}
995
+
browserslist@4.28.1:
996
+
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
968
997
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
969
998
hasBin: true
970
999
···
975
1004
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
976
1005
engines: {node: '>= 6'}
977
1006
978
-
caniuse-lite@1.0.30001717:
979
-
resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==}
1007
+
caniuse-lite@1.0.30001760:
1008
+
resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==}
980
1009
981
1010
chokidar@3.6.0:
982
1011
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
···
1006
1035
convert-source-map@2.0.0:
1007
1036
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
1008
1037
1009
-
cookie@0.7.2:
1010
-
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
1011
-
engines: {node: '>= 0.6'}
1012
-
1013
-
cross-spawn@7.0.6:
1014
-
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
1015
-
engines: {node: '>= 8'}
1038
+
cookie@1.1.1:
1039
+
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
1040
+
engines: {node: '>=18'}
1016
1041
1017
1042
cssesc@3.0.0:
1018
1043
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
1019
1044
engines: {node: '>=4'}
1020
1045
hasBin: true
1021
1046
1022
-
csstype@3.1.3:
1023
-
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
1047
+
csstype@3.2.3:
1048
+
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
1024
1049
1025
-
data-uri-to-buffer@2.0.2:
1026
-
resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==}
1027
-
1028
-
debug@4.4.0:
1029
-
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
1050
+
debug@4.4.3:
1051
+
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
1030
1052
engines: {node: '>=6.0'}
1031
1053
peerDependencies:
1032
1054
supports-color: '*'
···
1034
1056
supports-color:
1035
1057
optional: true
1036
1058
1037
-
defu@6.1.4:
1038
-
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
1039
-
1040
-
detect-libc@2.0.4:
1041
-
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
1059
+
detect-libc@2.1.2:
1060
+
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
1042
1061
engines: {node: '>=8'}
1043
1062
1044
1063
didyoumean@1.2.2:
···
1047
1066
dlv@1.1.3:
1048
1067
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
1049
1068
1050
-
eastasianwidth@0.2.0:
1051
-
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
1069
+
electron-to-chromium@1.5.267:
1070
+
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
1052
1071
1053
-
electron-to-chromium@1.5.150:
1054
-
resolution: {integrity: sha512-rOOkP2ZUMx1yL4fCxXQKDHQ8ZXwisb2OycOQVKHgvB3ZI4CvehOd4y2tfnnLDieJ3Zs1RL1Dlp3cMkyIn7nnXA==}
1055
-
1056
-
emoji-regex@8.0.0:
1057
-
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
1058
-
1059
-
emoji-regex@9.2.2:
1060
-
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
1061
-
1062
-
entities@6.0.0:
1063
-
resolution: {integrity: sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==}
1072
+
entities@6.0.1:
1073
+
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
1064
1074
engines: {node: '>=0.12'}
1065
1075
1066
-
esbuild@0.25.2:
1067
-
resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==}
1076
+
error-stack-parser-es@1.0.5:
1077
+
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
1078
+
1079
+
esbuild@0.25.12:
1080
+
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
1068
1081
engines: {node: '>=18'}
1069
1082
hasBin: true
1070
1083
1071
-
esbuild@0.25.4:
1072
-
resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
1084
+
esbuild@0.27.0:
1085
+
resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==}
1073
1086
engines: {node: '>=18'}
1074
1087
hasBin: true
1075
1088
···
1077
1090
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
1078
1091
engines: {node: '>=6'}
1079
1092
1093
+
esm-env@1.2.2:
1094
+
resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
1095
+
1080
1096
exit-hook@2.2.1:
1081
1097
resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==}
1082
1098
engines: {node: '>=6'}
1083
-
1084
-
exsolve@1.0.5:
1085
-
resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==}
1086
1099
1087
1100
fast-glob@3.3.3:
1088
1101
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
···
1091
1104
fastq@1.19.1:
1092
1105
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
1093
1106
1094
-
fdir@6.4.4:
1095
-
resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==}
1107
+
fdir@6.5.0:
1108
+
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
1109
+
engines: {node: '>=12.0.0'}
1096
1110
peerDependencies:
1097
1111
picomatch: ^3 || ^4
1098
1112
peerDependenciesMeta:
···
1107
1121
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
1108
1122
engines: {node: '>=8'}
1109
1123
1110
-
foreground-child@3.3.1:
1111
-
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
1112
-
engines: {node: '>=14'}
1113
-
1114
-
fraction.js@4.3.7:
1115
-
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
1124
+
fraction.js@5.3.4:
1125
+
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
1116
1126
1117
1127
fsevents@2.3.3:
1118
1128
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
···
1126
1136
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
1127
1137
engines: {node: '>=6.9.0'}
1128
1138
1129
-
get-source@2.0.12:
1130
-
resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==}
1131
-
1132
1139
glob-parent@5.1.2:
1133
1140
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
1134
1141
engines: {node: '>= 6'}
···
1140
1147
glob-to-regexp@0.4.1:
1141
1148
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
1142
1149
1143
-
glob@10.4.5:
1144
-
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
1145
-
hasBin: true
1146
-
1147
-
globals@11.12.0:
1148
-
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
1149
-
engines: {node: '>=4'}
1150
-
1151
1150
hasown@2.0.2:
1152
1151
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
1153
1152
engines: {node: '>= 0.4'}
···
1155
1154
html-entities@2.3.3:
1156
1155
resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
1157
1156
1158
-
is-arrayish@0.3.2:
1159
-
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
1157
+
is-arrayish@0.3.4:
1158
+
resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==}
1160
1159
1161
1160
is-binary-path@2.1.0:
1162
1161
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
···
1170
1169
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
1171
1170
engines: {node: '>=0.10.0'}
1172
1171
1173
-
is-fullwidth-code-point@3.0.0:
1174
-
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
1175
-
engines: {node: '>=8'}
1176
-
1177
1172
is-glob@4.0.3:
1178
1173
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
1179
1174
engines: {node: '>=0.10.0'}
···
1186
1181
resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
1187
1182
engines: {node: '>=12.13'}
1188
1183
1189
-
isexe@2.0.0:
1190
-
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
1191
-
1192
-
jackspeak@3.4.3:
1193
-
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
1194
-
1195
1184
jiti@1.21.7:
1196
1185
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
1197
1186
hasBin: true
···
1209
1198
engines: {node: '>=6'}
1210
1199
hasBin: true
1211
1200
1201
+
kleur@4.1.5:
1202
+
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
1203
+
engines: {node: '>=6'}
1204
+
1212
1205
lilconfig@3.1.3:
1213
1206
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
1214
1207
engines: {node: '>=14'}
1215
1208
1216
1209
lines-and-columns@1.2.4:
1217
1210
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
1218
-
1219
-
lru-cache@10.4.3:
1220
-
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
1221
1211
1222
1212
lru-cache@5.1.1:
1223
1213
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
···
1243
1233
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
1244
1234
hasBin: true
1245
1235
1246
-
miniflare@4.20250428.1:
1247
-
resolution: {integrity: sha512-M3qcJXjeAEimHrEeWXEhrJiC3YHB5M3QSqqK67pOTI+lHn0QyVG/2iFUjVJ/nv+i10uxeAEva8GRGeu+tKRCmQ==}
1236
+
miniflare@4.20251202.1:
1237
+
resolution: {integrity: sha512-cRp2QNgnt9wpLMoNs4MOzzomyfe9UTS9sPRxIpUvxMl+mweCZ0FHpWWQvCnU7wWlfAP8VGZrHwqSsV5ERA6ahQ==}
1248
1238
engines: {node: '>=18.0.0'}
1249
1239
hasBin: true
1250
1240
1251
-
minimatch@9.0.5:
1252
-
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
1253
-
engines: {node: '>=16 || 14 >=14.17'}
1254
-
1255
-
minipass@7.1.2:
1256
-
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
1257
-
engines: {node: '>=16 || 14 >=14.17'}
1258
-
1259
1241
ms@2.1.3:
1260
1242
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
1261
1243
1262
-
mustache@4.2.0:
1263
-
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
1264
-
hasBin: true
1265
-
1266
1244
mz@2.7.0:
1267
1245
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
1268
1246
···
1271
1249
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
1272
1250
hasBin: true
1273
1251
1274
-
nanoid@5.1.5:
1275
-
resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==}
1252
+
nanoid@5.1.6:
1253
+
resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==}
1276
1254
engines: {node: ^18 || >=20}
1277
1255
hasBin: true
1278
1256
···
1285
1263
engines: {node: '>=10.5.0'}
1286
1264
deprecated: Use your platform's native DOMException instead
1287
1265
1288
-
node-releases@2.0.19:
1289
-
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
1266
+
node-releases@2.0.27:
1267
+
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
1290
1268
1291
1269
normalize-path@3.0.0:
1292
1270
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
···
1304
1282
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
1305
1283
engines: {node: '>= 6'}
1306
1284
1307
-
ohash@2.0.11:
1308
-
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
1309
-
1310
-
package-json-from-dist@1.0.1:
1311
-
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
1312
-
1313
1285
parse5@7.3.0:
1314
1286
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
1315
1287
1316
-
path-key@3.1.1:
1317
-
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
1318
-
engines: {node: '>=8'}
1319
-
1320
1288
path-parse@1.0.7:
1321
1289
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
1322
-
1323
-
path-scurry@1.11.1:
1324
-
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
1325
-
engines: {node: '>=16 || 14 >=14.18'}
1326
1290
1327
1291
path-to-regexp@6.3.0:
1328
1292
resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
···
1337
1301
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
1338
1302
engines: {node: '>=8.6'}
1339
1303
1340
-
picomatch@4.0.2:
1341
-
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
1304
+
picomatch@4.0.3:
1305
+
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
1342
1306
engines: {node: '>=12'}
1343
1307
1344
1308
pify@2.3.0:
···
1355
1319
peerDependencies:
1356
1320
postcss: ^8.0.0
1357
1321
1358
-
postcss-js@4.0.1:
1359
-
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
1322
+
postcss-js@4.1.0:
1323
+
resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==}
1360
1324
engines: {node: ^12 || ^14 || >= 16}
1361
1325
peerDependencies:
1362
1326
postcss: ^8.4.21
1363
1327
1364
-
postcss-load-config@4.0.2:
1365
-
resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
1366
-
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'}
1367
1331
peerDependencies:
1332
+
jiti: '>=1.21.0'
1368
1333
postcss: '>=8.0.9'
1369
-
ts-node: '>=9.0.0'
1334
+
tsx: ^4.8.1
1335
+
yaml: ^2.4.2
1370
1336
peerDependenciesMeta:
1337
+
jiti:
1338
+
optional: true
1371
1339
postcss:
1372
1340
optional: true
1373
-
ts-node:
1341
+
tsx:
1342
+
optional: true
1343
+
yaml:
1374
1344
optional: true
1375
1345
1376
1346
postcss-nested@6.2.0:
···
1386
1356
postcss-value-parser@4.2.0:
1387
1357
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
1388
1358
1389
-
postcss@8.5.3:
1390
-
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
1359
+
postcss@8.5.6:
1360
+
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
1391
1361
engines: {node: ^10 || ^12 || >=14}
1392
1362
1393
-
prettier-plugin-tailwindcss@0.6.11:
1394
-
resolution: {integrity: sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==}
1363
+
prettier-plugin-tailwindcss@0.6.14:
1364
+
resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==}
1395
1365
engines: {node: '>=14.21.3'}
1396
1366
peerDependencies:
1397
1367
'@ianvs/prettier-plugin-sort-imports': '*'
1368
+
'@prettier/plugin-hermes': '*'
1369
+
'@prettier/plugin-oxc': '*'
1398
1370
'@prettier/plugin-pug': '*'
1399
1371
'@shopify/prettier-plugin-liquid': '*'
1400
1372
'@trivago/prettier-plugin-sort-imports': '*'
···
1414
1386
peerDependenciesMeta:
1415
1387
'@ianvs/prettier-plugin-sort-imports':
1416
1388
optional: true
1389
+
'@prettier/plugin-hermes':
1390
+
optional: true
1391
+
'@prettier/plugin-oxc':
1392
+
optional: true
1417
1393
'@prettier/plugin-pug':
1418
1394
optional: true
1419
1395
'@shopify/prettier-plugin-liquid':
···
1445
1421
prettier-plugin-svelte:
1446
1422
optional: true
1447
1423
1448
-
prettier@3.5.3:
1449
-
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
1424
+
prettier@3.7.4:
1425
+
resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==}
1450
1426
engines: {node: '>=14'}
1451
1427
hasBin: true
1452
-
1453
-
printable-characters@1.0.42:
1454
-
resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==}
1455
1428
1456
1429
queue-microtask@1.2.3:
1457
1430
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
···
1463
1436
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
1464
1437
engines: {node: '>=8.10.0'}
1465
1438
1466
-
resolve@1.22.10:
1467
-
resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
1439
+
resolve@1.22.11:
1440
+
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
1468
1441
engines: {node: '>= 0.4'}
1469
1442
hasBin: true
1470
1443
···
1472
1445
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
1473
1446
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
1474
1447
1475
-
rollup@4.40.2:
1476
-
resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==}
1448
+
rollup@4.53.3:
1449
+
resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==}
1477
1450
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
1478
1451
hasBin: true
1479
1452
···
1484
1457
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
1485
1458
hasBin: true
1486
1459
1487
-
semver@7.7.1:
1488
-
resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
1460
+
semver@7.7.3:
1461
+
resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
1489
1462
engines: {node: '>=10'}
1490
1463
hasBin: true
1491
1464
1492
-
seroval-plugins@1.2.1:
1493
-
resolution: {integrity: sha512-H5vs53+39+x4Udwp4J5rNZfgFuA+Lt+uU+09w1gYBVWomtAl98B+E9w7yC05Xc81/HgLvJdlyqJbU0fJCKCmdw==}
1465
+
seroval-plugins@1.3.3:
1466
+
resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==}
1494
1467
engines: {node: '>=10'}
1495
1468
peerDependencies:
1496
1469
seroval: ^1.0
1497
1470
1498
-
seroval@1.2.1:
1499
-
resolution: {integrity: sha512-yBxFFs3zmkvKNmR0pFSU//rIsYjuX418TnlDmc2weaq5XFDqDIV/NOMPBoLrbxjLH42p4UzRuXHryXh9dYcKcw==}
1471
+
seroval@1.3.2:
1472
+
resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==}
1500
1473
engines: {node: '>=10'}
1501
1474
1502
1475
sharp@0.33.5:
1503
1476
resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
1504
1477
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
1505
1478
1506
-
shebang-command@2.0.0:
1507
-
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
1508
-
engines: {node: '>=8'}
1479
+
simple-swizzle@0.2.4:
1480
+
resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
1509
1481
1510
-
shebang-regex@3.0.0:
1511
-
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
1512
-
engines: {node: '>=8'}
1513
-
1514
-
signal-exit@4.1.0:
1515
-
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
1516
-
engines: {node: '>=14'}
1517
-
1518
-
simple-swizzle@0.2.2:
1519
-
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
1520
-
1521
-
solid-js@1.9.6:
1522
-
resolution: {integrity: sha512-PoasAJvLk60hRtOTe9ulvALOdLjjqxuxcGZRolBQqxOnXrBXHGzqMT4ijNhGsDAYdOgEa8ZYaAE94PSldrFSkA==}
1482
+
solid-js@1.9.10:
1483
+
resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==}
1523
1484
1524
1485
solid-refresh@0.6.3:
1525
1486
resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==}
···
1537
1498
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
1538
1499
engines: {node: '>=0.10.0'}
1539
1500
1540
-
stacktracey@2.1.8:
1541
-
resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==}
1542
-
1543
1501
stoppable@1.1.0:
1544
1502
resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==}
1545
1503
engines: {node: '>=4', npm: '>=6'}
1546
1504
1547
-
string-width@4.2.3:
1548
-
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
1549
-
engines: {node: '>=8'}
1550
-
1551
-
string-width@5.1.2:
1552
-
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
1553
-
engines: {node: '>=12'}
1554
-
1555
-
strip-ansi@6.0.1:
1556
-
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
1557
-
engines: {node: '>=8'}
1558
-
1559
-
strip-ansi@7.1.0:
1560
-
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
1561
-
engines: {node: '>=12'}
1562
-
1563
-
sucrase@3.35.0:
1564
-
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
1505
+
sucrase@3.35.1:
1506
+
resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==}
1565
1507
engines: {node: '>=16 || 14 >=14.17'}
1566
1508
hasBin: true
1567
1509
1510
+
supports-color@10.2.2:
1511
+
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
1512
+
engines: {node: '>=18'}
1513
+
1568
1514
supports-preserve-symlinks-flag@1.0.0:
1569
1515
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
1570
1516
engines: {node: '>= 0.4'}
1571
1517
1572
-
tailwindcss@3.4.17:
1573
-
resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==}
1518
+
tailwindcss@3.4.18:
1519
+
resolution: {integrity: sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==}
1574
1520
engines: {node: '>=14.0.0'}
1575
1521
hasBin: true
1576
1522
1577
-
terser@5.39.0:
1578
-
resolution: {integrity: sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==}
1523
+
terser@5.44.1:
1524
+
resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==}
1579
1525
engines: {node: '>=10'}
1580
1526
hasBin: true
1581
1527
···
1586
1532
thenify@3.3.1:
1587
1533
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
1588
1534
1589
-
tinyglobby@0.2.13:
1590
-
resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==}
1535
+
tinyglobby@0.2.15:
1536
+
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
1591
1537
engines: {node: '>=12.0.0'}
1592
1538
1593
1539
to-regex-range@5.0.1:
···
1600
1546
tslib@2.8.1:
1601
1547
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
1602
1548
1603
-
typescript@5.8.3:
1604
-
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
1549
+
typescript@5.9.3:
1550
+
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
1605
1551
engines: {node: '>=14.17'}
1606
1552
hasBin: true
1607
1553
1608
-
ufo@1.6.1:
1609
-
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
1610
-
1611
1554
undici-types@6.21.0:
1612
1555
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
1613
1556
1614
-
undici@5.29.0:
1615
-
resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==}
1616
-
engines: {node: '>=14.0'}
1557
+
undici@7.14.0:
1558
+
resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==}
1559
+
engines: {node: '>=20.18.1'}
1617
1560
1618
-
unenv@2.0.0-rc.15:
1619
-
resolution: {integrity: sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA==}
1561
+
unenv@2.0.0-rc.24:
1562
+
resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==}
1620
1563
1621
-
update-browserslist-db@1.1.3:
1622
-
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
1564
+
update-browserslist-db@1.2.2:
1565
+
resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==}
1623
1566
hasBin: true
1624
1567
peerDependencies:
1625
1568
browserslist: '>= 4.21.0'
···
1627
1570
util-deprecate@1.0.2:
1628
1571
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
1629
1572
1630
-
validate-html-nesting@1.2.2:
1631
-
resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==}
1632
-
1633
-
vite-plugin-solid@2.11.6:
1634
-
resolution: {integrity: sha512-Sl5CTqJTGyEeOsmdH6BOgalIZlwH3t4/y0RQuFLMGnvWMBvxb4+lq7x3BSiAw6etf0QexfNJW7HSOO/Qf7pigg==}
1573
+
vite-plugin-solid@2.11.10:
1574
+
resolution: {integrity: sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw==}
1635
1575
peerDependencies:
1636
1576
'@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.*
1637
1577
solid-js: ^1.7.2
1638
-
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
1639
1579
peerDependenciesMeta:
1640
1580
'@testing-library/jest-dom':
1641
1581
optional: true
1642
1582
1643
-
vite@6.3.5:
1644
-
resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==}
1645
-
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}
1646
1586
hasBin: true
1647
1587
peerDependencies:
1648
-
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
1588
+
'@types/node': ^20.19.0 || >=22.12.0
1649
1589
jiti: '>=1.21.0'
1650
-
less: '*'
1590
+
less: ^4.0.0
1651
1591
lightningcss: ^1.21.0
1652
-
sass: '*'
1653
-
sass-embedded: '*'
1654
-
stylus: '*'
1655
-
sugarss: '*'
1592
+
sass: ^1.70.0
1593
+
sass-embedded: ^1.70.0
1594
+
stylus: '>=0.54.8'
1595
+
sugarss: ^5.0.0
1656
1596
terser: ^5.16.0
1657
1597
tsx: ^4.8.1
1658
1598
yaml: ^2.4.2
···
1680
1620
yaml:
1681
1621
optional: true
1682
1622
1683
-
vitefu@1.0.6:
1684
-
resolution: {integrity: sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==}
1623
+
vitefu@1.1.1:
1624
+
resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==}
1685
1625
peerDependencies:
1686
-
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
1687
1627
peerDependenciesMeta:
1688
1628
vite:
1689
1629
optional: true
···
1692
1632
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
1693
1633
engines: {node: '>= 8'}
1694
1634
1695
-
which@2.0.2:
1696
-
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
1697
-
engines: {node: '>= 8'}
1698
-
hasBin: true
1699
-
1700
-
workerd@1.20250428.0:
1701
-
resolution: {integrity: sha512-JJNWkHkwPQKQdvtM9UORijgYdcdJsihA4SfYjwh02IUQsdMyZ9jizV1sX9yWi9B9ptlohTW8UNHJEATuphGgdg==}
1635
+
workerd@1.20251202.0:
1636
+
resolution: {integrity: sha512-p08YfrUMHkjCECNdT36r+6DpJIZX4kixbZ4n6GMUcLR5Gh18fakSCsiQrh72iOm4M9QHv/rM7P8YvCrUPWT5sg==}
1702
1637
engines: {node: '>=16'}
1703
1638
hasBin: true
1704
1639
1705
-
wrangler@4.14.1:
1706
-
resolution: {integrity: sha512-EU7IThP7i68TBftJJSveogvWZ5k/WRijcJh3UclDWiWWhDZTPbL6LOJEFhHKqFzHOaC4Y2Aewt48rfTz0e7oCw==}
1707
-
engines: {node: '>=18.0.0'}
1640
+
wrangler@4.53.0:
1641
+
resolution: {integrity: sha512-/wvnHlRnlHsqaeIgGbmcEJE5NFYdTUWHCKow+U5Tv2XwQXI9vXUqBwCLAGy/BwqyS5nnycRt2kppqCzgHgyb7Q==}
1642
+
engines: {node: '>=20.0.0'}
1708
1643
hasBin: true
1709
1644
peerDependencies:
1710
-
'@cloudflare/workers-types': ^4.20250428.0
1645
+
'@cloudflare/workers-types': ^4.20251202.0
1711
1646
peerDependenciesMeta:
1712
1647
'@cloudflare/workers-types':
1713
1648
optional: true
1714
-
1715
-
wrap-ansi@7.0.0:
1716
-
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
1717
-
engines: {node: '>=10'}
1718
-
1719
-
wrap-ansi@8.1.0:
1720
-
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
1721
-
engines: {node: '>=12'}
1722
1649
1723
1650
ws@8.18.0:
1724
1651
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
···
1735
1662
yallist@3.1.1:
1736
1663
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
1737
1664
1738
-
yaml@2.7.1:
1739
-
resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==}
1740
-
engines: {node: '>= 14'}
1741
-
hasBin: true
1665
+
youch-core@0.3.3:
1666
+
resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==}
1742
1667
1743
-
youch@3.3.4:
1744
-
resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==}
1668
+
youch@4.1.0-beta.10:
1669
+
resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==}
1745
1670
1746
1671
zod@3.22.3:
1747
1672
resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==}
···
1750
1675
1751
1676
'@alloc/quick-lru@5.2.0': {}
1752
1677
1753
-
'@ampproject/remapping@2.3.0':
1678
+
'@atcute/atproto@3.1.9':
1754
1679
dependencies:
1755
-
'@jridgewell/gen-mapping': 0.3.8
1756
-
'@jridgewell/trace-mapping': 0.3.25
1680
+
'@atcute/lexicons': 1.2.5
1757
1681
1758
-
'@atcute/bluesky@2.1.1(@atcute/client@3.1.0)':
1682
+
'@atcute/bluesky@3.2.13':
1759
1683
dependencies:
1760
-
'@atcute/client': 3.1.0
1684
+
'@atcute/atproto': 3.1.9
1685
+
'@atcute/lexicons': 1.2.5
1761
1686
1762
-
'@atcute/car@3.0.4':
1687
+
'@atcute/car@5.0.0':
1763
1688
dependencies:
1764
-
'@atcute/cbor': 2.2.3
1765
-
'@atcute/cid': 2.2.2
1766
-
'@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
1767
1693
1768
-
'@atcute/cbor@2.2.3':
1694
+
'@atcute/cbor@2.2.8':
1769
1695
dependencies:
1770
-
'@atcute/cid': 2.2.2
1771
-
'@atcute/multibase': 1.1.3
1772
-
'@atcute/uint8array': 1.0.1
1696
+
'@atcute/cid': 2.2.6
1697
+
'@atcute/multibase': 1.1.6
1698
+
'@atcute/uint8array': 1.0.6
1773
1699
1774
-
'@atcute/cid@2.2.2':
1700
+
'@atcute/cid@2.2.6':
1775
1701
dependencies:
1776
-
'@atcute/multibase': 1.1.3
1777
-
'@atcute/uint8array': 1.0.1
1702
+
'@atcute/multibase': 1.1.6
1703
+
'@atcute/uint8array': 1.0.6
1778
1704
1779
-
'@atcute/client@3.1.0': {}
1705
+
'@atcute/client@4.1.1':
1706
+
dependencies:
1707
+
'@atcute/identity': 1.1.3
1708
+
'@atcute/lexicons': 1.2.5
1780
1709
1781
-
'@atcute/crypto@2.2.1':
1710
+
'@atcute/crypto@2.3.0':
1782
1711
dependencies:
1783
-
'@atcute/multibase': 1.1.3
1784
-
'@atcute/uint8array': 1.0.1
1785
-
'@noble/secp256k1': 2.2.3
1712
+
'@atcute/multibase': 1.1.6
1713
+
'@atcute/uint8array': 1.0.6
1714
+
'@noble/secp256k1': 3.0.0
1786
1715
1787
-
'@atcute/did-plc@0.1.4':
1716
+
'@atcute/did-plc@0.2.0':
1788
1717
dependencies:
1789
-
'@atcute/cbor': 2.2.3
1790
-
'@atcute/cid': 2.2.2
1791
-
'@atcute/crypto': 2.2.1
1792
-
'@atcute/multibase': 1.1.3
1793
-
'@atcute/uint8array': 1.0.1
1794
-
'@badrap/valita': 0.4.4
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
1795
1726
1796
-
'@atcute/identity-resolver@0.1.2(@atcute/identity@0.1.3)':
1727
+
'@atcute/identity-resolver@1.2.0(@atcute/identity@1.1.3)':
1797
1728
dependencies:
1798
-
'@atcute/identity': 0.1.3
1799
-
'@atcute/util-fetch': 1.0.1
1800
-
'@badrap/valita': 0.4.4
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
1801
1733
1802
-
'@atcute/identity@0.1.3':
1734
+
'@atcute/identity@1.1.3':
1803
1735
dependencies:
1804
-
'@badrap/valita': 0.4.4
1736
+
'@atcute/lexicons': 1.2.5
1737
+
'@badrap/valita': 0.4.6
1738
+
1739
+
'@atcute/lexicons@1.2.5':
1740
+
dependencies:
1741
+
'@standard-schema/spec': 1.0.0
1742
+
esm-env: 1.2.2
1743
+
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
1749
+
1750
+
'@atcute/multibase@1.1.6':
1751
+
dependencies:
1752
+
'@atcute/uint8array': 1.0.6
1805
1753
1806
-
'@atcute/multibase@1.1.3':
1754
+
'@atcute/repo@0.1.0':
1807
1755
dependencies:
1808
-
'@atcute/uint8array': 1.0.1
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
1809
1763
1810
-
'@atcute/tid@1.0.2': {}
1764
+
'@atcute/tid@1.0.3': {}
1811
1765
1812
-
'@atcute/uint8array@1.0.1': {}
1766
+
'@atcute/uint8array@1.0.6': {}
1813
1767
1814
-
'@atcute/util-fetch@1.0.1':
1768
+
'@atcute/util-fetch@1.0.4':
1815
1769
dependencies:
1816
-
'@badrap/valita': 0.4.4
1770
+
'@badrap/valita': 0.4.6
1817
1771
1818
-
'@atcute/varint@1.0.2': {}
1772
+
'@atcute/varint@1.0.3': {}
1819
1773
1820
1774
'@babel/code-frame@7.27.1':
1821
1775
dependencies:
1822
-
'@babel/helper-validator-identifier': 7.27.1
1776
+
'@babel/helper-validator-identifier': 7.28.5
1823
1777
js-tokens: 4.0.0
1824
1778
picocolors: 1.1.1
1825
1779
1826
-
'@babel/compat-data@7.27.1': {}
1780
+
'@babel/compat-data@7.28.5': {}
1827
1781
1828
-
'@babel/core@7.27.1':
1782
+
'@babel/core@7.28.5':
1829
1783
dependencies:
1830
-
'@ampproject/remapping': 2.3.0
1831
1784
'@babel/code-frame': 7.27.1
1832
-
'@babel/generator': 7.27.1
1833
-
'@babel/helper-compilation-targets': 7.27.1
1834
-
'@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1)
1835
-
'@babel/helpers': 7.27.1
1836
-
'@babel/parser': 7.27.1
1837
-
'@babel/template': 7.27.1
1838
-
'@babel/traverse': 7.27.1
1839
-
'@babel/types': 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
1840
1794
convert-source-map: 2.0.0
1841
-
debug: 4.4.0
1795
+
debug: 4.4.3
1842
1796
gensync: 1.0.0-beta.2
1843
1797
json5: 2.2.3
1844
1798
semver: 6.3.1
1845
1799
transitivePeerDependencies:
1846
1800
- supports-color
1847
1801
1848
-
'@babel/generator@7.27.1':
1802
+
'@babel/generator@7.28.5':
1849
1803
dependencies:
1850
-
'@babel/parser': 7.27.1
1851
-
'@babel/types': 7.27.1
1852
-
'@jridgewell/gen-mapping': 0.3.8
1853
-
'@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
1854
1808
jsesc: 3.1.0
1855
1809
1856
-
'@babel/helper-compilation-targets@7.27.1':
1810
+
'@babel/helper-compilation-targets@7.27.2':
1857
1811
dependencies:
1858
-
'@babel/compat-data': 7.27.1
1812
+
'@babel/compat-data': 7.28.5
1859
1813
'@babel/helper-validator-option': 7.27.1
1860
-
browserslist: 4.24.5
1814
+
browserslist: 4.28.1
1861
1815
lru-cache: 5.1.1
1862
1816
semver: 6.3.1
1863
1817
1818
+
'@babel/helper-globals@7.28.0': {}
1819
+
1864
1820
'@babel/helper-module-imports@7.18.6':
1865
1821
dependencies:
1866
-
'@babel/types': 7.27.1
1822
+
'@babel/types': 7.28.5
1867
1823
1868
1824
'@babel/helper-module-imports@7.27.1':
1869
1825
dependencies:
1870
-
'@babel/traverse': 7.27.1
1871
-
'@babel/types': 7.27.1
1826
+
'@babel/traverse': 7.28.5
1827
+
'@babel/types': 7.28.5
1872
1828
transitivePeerDependencies:
1873
1829
- supports-color
1874
1830
1875
-
'@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)':
1831
+
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)':
1876
1832
dependencies:
1877
-
'@babel/core': 7.27.1
1833
+
'@babel/core': 7.28.5
1878
1834
'@babel/helper-module-imports': 7.27.1
1879
-
'@babel/helper-validator-identifier': 7.27.1
1880
-
'@babel/traverse': 7.27.1
1835
+
'@babel/helper-validator-identifier': 7.28.5
1836
+
'@babel/traverse': 7.28.5
1881
1837
transitivePeerDependencies:
1882
1838
- supports-color
1883
1839
···
1885
1841
1886
1842
'@babel/helper-string-parser@7.27.1': {}
1887
1843
1888
-
'@babel/helper-validator-identifier@7.27.1': {}
1844
+
'@babel/helper-validator-identifier@7.28.5': {}
1889
1845
1890
1846
'@babel/helper-validator-option@7.27.1': {}
1891
1847
1892
-
'@babel/helpers@7.27.1':
1848
+
'@babel/helpers@7.28.4':
1893
1849
dependencies:
1894
-
'@babel/template': 7.27.1
1895
-
'@babel/types': 7.27.1
1850
+
'@babel/template': 7.27.2
1851
+
'@babel/types': 7.28.5
1896
1852
1897
-
'@babel/parser@7.27.1':
1853
+
'@babel/parser@7.28.5':
1898
1854
dependencies:
1899
-
'@babel/types': 7.27.1
1855
+
'@babel/types': 7.28.5
1900
1856
1901
-
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.1)':
1857
+
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)':
1902
1858
dependencies:
1903
-
'@babel/core': 7.27.1
1859
+
'@babel/core': 7.28.5
1904
1860
'@babel/helper-plugin-utils': 7.27.1
1905
1861
1906
-
'@babel/template@7.27.1':
1862
+
'@babel/template@7.27.2':
1907
1863
dependencies:
1908
1864
'@babel/code-frame': 7.27.1
1909
-
'@babel/parser': 7.27.1
1910
-
'@babel/types': 7.27.1
1865
+
'@babel/parser': 7.28.5
1866
+
'@babel/types': 7.28.5
1911
1867
1912
-
'@babel/traverse@7.27.1':
1868
+
'@babel/traverse@7.28.5':
1913
1869
dependencies:
1914
1870
'@babel/code-frame': 7.27.1
1915
-
'@babel/generator': 7.27.1
1916
-
'@babel/parser': 7.27.1
1917
-
'@babel/template': 7.27.1
1918
-
'@babel/types': 7.27.1
1919
-
debug: 4.4.0
1920
-
globals: 11.12.0
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
1921
1877
transitivePeerDependencies:
1922
1878
- supports-color
1923
1879
1924
-
'@babel/types@7.27.1':
1880
+
'@babel/types@7.28.5':
1925
1881
dependencies:
1926
1882
'@babel/helper-string-parser': 7.27.1
1927
-
'@babel/helper-validator-identifier': 7.27.1
1883
+
'@babel/helper-validator-identifier': 7.28.5
1928
1884
1929
-
'@badrap/valita@0.4.4': {}
1885
+
'@badrap/valita@0.4.6': {}
1930
1886
1931
-
'@cloudflare/kv-asset-handler@0.4.0':
1887
+
'@cloudflare/kv-asset-handler@0.4.1':
1932
1888
dependencies:
1933
1889
mime: 3.0.0
1934
1890
1935
-
'@cloudflare/unenv-preset@2.3.1(unenv@2.0.0-rc.15)(workerd@1.20250428.0)':
1891
+
'@cloudflare/unenv-preset@2.7.13(unenv@2.0.0-rc.24)(workerd@1.20251202.0)':
1936
1892
dependencies:
1937
-
unenv: 2.0.0-rc.15
1893
+
unenv: 2.0.0-rc.24
1938
1894
optionalDependencies:
1939
-
workerd: 1.20250428.0
1895
+
workerd: 1.20251202.0
1940
1896
1941
-
'@cloudflare/workerd-darwin-64@1.20250428.0':
1897
+
'@cloudflare/workerd-darwin-64@1.20251202.0':
1942
1898
optional: true
1943
1899
1944
-
'@cloudflare/workerd-darwin-arm64@1.20250428.0':
1900
+
'@cloudflare/workerd-darwin-arm64@1.20251202.0':
1945
1901
optional: true
1946
1902
1947
-
'@cloudflare/workerd-linux-64@1.20250428.0':
1903
+
'@cloudflare/workerd-linux-64@1.20251202.0':
1948
1904
optional: true
1949
1905
1950
-
'@cloudflare/workerd-linux-arm64@1.20250428.0':
1906
+
'@cloudflare/workerd-linux-arm64@1.20251202.0':
1951
1907
optional: true
1952
1908
1953
-
'@cloudflare/workerd-windows-64@1.20250428.0':
1909
+
'@cloudflare/workerd-windows-64@1.20251202.0':
1954
1910
optional: true
1955
1911
1956
1912
'@cspotcode/source-map-support@0.8.1':
1957
1913
dependencies:
1958
1914
'@jridgewell/trace-mapping': 0.3.9
1959
1915
1960
-
'@emnapi/runtime@1.4.3':
1916
+
'@emnapi/runtime@1.7.1':
1961
1917
dependencies:
1962
1918
tslib: 2.8.1
1963
1919
optional: true
1964
1920
1965
-
'@esbuild/aix-ppc64@0.25.2':
1921
+
'@esbuild/aix-ppc64@0.25.12':
1966
1922
optional: true
1967
1923
1968
-
'@esbuild/aix-ppc64@0.25.4':
1924
+
'@esbuild/aix-ppc64@0.27.0':
1969
1925
optional: true
1970
1926
1971
-
'@esbuild/android-arm64@0.25.2':
1927
+
'@esbuild/android-arm64@0.25.12':
1972
1928
optional: true
1973
1929
1974
-
'@esbuild/android-arm64@0.25.4':
1930
+
'@esbuild/android-arm64@0.27.0':
1975
1931
optional: true
1976
1932
1977
-
'@esbuild/android-arm@0.25.2':
1933
+
'@esbuild/android-arm@0.25.12':
1978
1934
optional: true
1979
1935
1980
-
'@esbuild/android-arm@0.25.4':
1936
+
'@esbuild/android-arm@0.27.0':
1981
1937
optional: true
1982
1938
1983
-
'@esbuild/android-x64@0.25.2':
1939
+
'@esbuild/android-x64@0.25.12':
1984
1940
optional: true
1985
1941
1986
-
'@esbuild/android-x64@0.25.4':
1942
+
'@esbuild/android-x64@0.27.0':
1987
1943
optional: true
1988
1944
1989
-
'@esbuild/darwin-arm64@0.25.2':
1945
+
'@esbuild/darwin-arm64@0.25.12':
1990
1946
optional: true
1991
1947
1992
-
'@esbuild/darwin-arm64@0.25.4':
1948
+
'@esbuild/darwin-arm64@0.27.0':
1993
1949
optional: true
1994
1950
1995
-
'@esbuild/darwin-x64@0.25.2':
1951
+
'@esbuild/darwin-x64@0.25.12':
1996
1952
optional: true
1997
1953
1998
-
'@esbuild/darwin-x64@0.25.4':
1954
+
'@esbuild/darwin-x64@0.27.0':
1999
1955
optional: true
2000
1956
2001
-
'@esbuild/freebsd-arm64@0.25.2':
1957
+
'@esbuild/freebsd-arm64@0.25.12':
2002
1958
optional: true
2003
1959
2004
-
'@esbuild/freebsd-arm64@0.25.4':
1960
+
'@esbuild/freebsd-arm64@0.27.0':
2005
1961
optional: true
2006
1962
2007
-
'@esbuild/freebsd-x64@0.25.2':
1963
+
'@esbuild/freebsd-x64@0.25.12':
2008
1964
optional: true
2009
1965
2010
-
'@esbuild/freebsd-x64@0.25.4':
1966
+
'@esbuild/freebsd-x64@0.27.0':
2011
1967
optional: true
2012
1968
2013
-
'@esbuild/linux-arm64@0.25.2':
1969
+
'@esbuild/linux-arm64@0.25.12':
2014
1970
optional: true
2015
1971
2016
-
'@esbuild/linux-arm64@0.25.4':
1972
+
'@esbuild/linux-arm64@0.27.0':
2017
1973
optional: true
2018
1974
2019
-
'@esbuild/linux-arm@0.25.2':
1975
+
'@esbuild/linux-arm@0.25.12':
2020
1976
optional: true
2021
1977
2022
-
'@esbuild/linux-arm@0.25.4':
1978
+
'@esbuild/linux-arm@0.27.0':
2023
1979
optional: true
2024
1980
2025
-
'@esbuild/linux-ia32@0.25.2':
1981
+
'@esbuild/linux-ia32@0.25.12':
2026
1982
optional: true
2027
1983
2028
-
'@esbuild/linux-ia32@0.25.4':
1984
+
'@esbuild/linux-ia32@0.27.0':
2029
1985
optional: true
2030
1986
2031
-
'@esbuild/linux-loong64@0.25.2':
1987
+
'@esbuild/linux-loong64@0.25.12':
2032
1988
optional: true
2033
1989
2034
-
'@esbuild/linux-loong64@0.25.4':
1990
+
'@esbuild/linux-loong64@0.27.0':
2035
1991
optional: true
2036
1992
2037
-
'@esbuild/linux-mips64el@0.25.2':
1993
+
'@esbuild/linux-mips64el@0.25.12':
2038
1994
optional: true
2039
1995
2040
-
'@esbuild/linux-mips64el@0.25.4':
1996
+
'@esbuild/linux-mips64el@0.27.0':
2041
1997
optional: true
2042
1998
2043
-
'@esbuild/linux-ppc64@0.25.2':
1999
+
'@esbuild/linux-ppc64@0.25.12':
2044
2000
optional: true
2045
2001
2046
-
'@esbuild/linux-ppc64@0.25.4':
2002
+
'@esbuild/linux-ppc64@0.27.0':
2047
2003
optional: true
2048
2004
2049
-
'@esbuild/linux-riscv64@0.25.2':
2005
+
'@esbuild/linux-riscv64@0.25.12':
2050
2006
optional: true
2051
2007
2052
-
'@esbuild/linux-riscv64@0.25.4':
2008
+
'@esbuild/linux-riscv64@0.27.0':
2053
2009
optional: true
2054
2010
2055
-
'@esbuild/linux-s390x@0.25.2':
2011
+
'@esbuild/linux-s390x@0.25.12':
2056
2012
optional: true
2057
2013
2058
-
'@esbuild/linux-s390x@0.25.4':
2014
+
'@esbuild/linux-s390x@0.27.0':
2059
2015
optional: true
2060
2016
2061
-
'@esbuild/linux-x64@0.25.2':
2017
+
'@esbuild/linux-x64@0.25.12':
2062
2018
optional: true
2063
2019
2064
-
'@esbuild/linux-x64@0.25.4':
2020
+
'@esbuild/linux-x64@0.27.0':
2065
2021
optional: true
2066
2022
2067
-
'@esbuild/netbsd-arm64@0.25.2':
2023
+
'@esbuild/netbsd-arm64@0.25.12':
2068
2024
optional: true
2069
2025
2070
-
'@esbuild/netbsd-arm64@0.25.4':
2026
+
'@esbuild/netbsd-arm64@0.27.0':
2071
2027
optional: true
2072
2028
2073
-
'@esbuild/netbsd-x64@0.25.2':
2029
+
'@esbuild/netbsd-x64@0.25.12':
2074
2030
optional: true
2075
2031
2076
-
'@esbuild/netbsd-x64@0.25.4':
2032
+
'@esbuild/netbsd-x64@0.27.0':
2077
2033
optional: true
2078
2034
2079
-
'@esbuild/openbsd-arm64@0.25.2':
2035
+
'@esbuild/openbsd-arm64@0.25.12':
2080
2036
optional: true
2081
2037
2082
-
'@esbuild/openbsd-arm64@0.25.4':
2038
+
'@esbuild/openbsd-arm64@0.27.0':
2083
2039
optional: true
2084
2040
2085
-
'@esbuild/openbsd-x64@0.25.2':
2041
+
'@esbuild/openbsd-x64@0.25.12':
2086
2042
optional: true
2087
2043
2088
-
'@esbuild/openbsd-x64@0.25.4':
2044
+
'@esbuild/openbsd-x64@0.27.0':
2089
2045
optional: true
2090
2046
2091
-
'@esbuild/sunos-x64@0.25.2':
2047
+
'@esbuild/openharmony-arm64@0.25.12':
2092
2048
optional: true
2093
2049
2094
-
'@esbuild/sunos-x64@0.25.4':
2050
+
'@esbuild/openharmony-arm64@0.27.0':
2095
2051
optional: true
2096
2052
2097
-
'@esbuild/win32-arm64@0.25.2':
2053
+
'@esbuild/sunos-x64@0.25.12':
2098
2054
optional: true
2099
2055
2100
-
'@esbuild/win32-arm64@0.25.4':
2056
+
'@esbuild/sunos-x64@0.27.0':
2101
2057
optional: true
2102
2058
2103
-
'@esbuild/win32-ia32@0.25.2':
2059
+
'@esbuild/win32-arm64@0.25.12':
2104
2060
optional: true
2105
2061
2106
-
'@esbuild/win32-ia32@0.25.4':
2062
+
'@esbuild/win32-arm64@0.27.0':
2107
2063
optional: true
2108
2064
2109
-
'@esbuild/win32-x64@0.25.2':
2065
+
'@esbuild/win32-ia32@0.25.12':
2066
+
optional: true
2067
+
2068
+
'@esbuild/win32-ia32@0.27.0':
2069
+
optional: true
2070
+
2071
+
'@esbuild/win32-x64@0.25.12':
2110
2072
optional: true
2111
2073
2112
-
'@esbuild/win32-x64@0.25.4':
2074
+
'@esbuild/win32-x64@0.27.0':
2113
2075
optional: true
2114
2076
2115
-
'@externdefs/solid-freeze@0.1.1(solid-js@1.9.6)':
2077
+
'@externdefs/solid-freeze@0.1.1(solid-js@1.9.10)':
2116
2078
dependencies:
2117
-
solid-js: 1.9.6
2118
-
2119
-
'@fastify/busboy@2.1.1': {}
2079
+
solid-js: 1.9.10
2120
2080
2121
2081
'@img/sharp-darwin-arm64@0.33.5':
2122
2082
optionalDependencies:
···
2184
2144
2185
2145
'@img/sharp-wasm32@0.33.5':
2186
2146
dependencies:
2187
-
'@emnapi/runtime': 1.4.3
2147
+
'@emnapi/runtime': 1.7.1
2188
2148
optional: true
2189
2149
2190
2150
'@img/sharp-win32-ia32@0.33.5':
···
2193
2153
'@img/sharp-win32-x64@0.33.5':
2194
2154
optional: true
2195
2155
2196
-
'@isaacs/cliui@8.0.2':
2156
+
'@jridgewell/gen-mapping@0.3.13':
2197
2157
dependencies:
2198
-
string-width: 5.1.2
2199
-
string-width-cjs: string-width@4.2.3
2200
-
strip-ansi: 7.1.0
2201
-
strip-ansi-cjs: strip-ansi@6.0.1
2202
-
wrap-ansi: 8.1.0
2203
-
wrap-ansi-cjs: wrap-ansi@7.0.0
2158
+
'@jridgewell/sourcemap-codec': 1.5.5
2159
+
'@jridgewell/trace-mapping': 0.3.31
2204
2160
2205
-
'@jridgewell/gen-mapping@0.3.8':
2161
+
'@jridgewell/remapping@2.3.5':
2206
2162
dependencies:
2207
-
'@jridgewell/set-array': 1.2.1
2208
-
'@jridgewell/sourcemap-codec': 1.5.0
2209
-
'@jridgewell/trace-mapping': 0.3.25
2163
+
'@jridgewell/gen-mapping': 0.3.13
2164
+
'@jridgewell/trace-mapping': 0.3.31
2210
2165
2211
2166
'@jridgewell/resolve-uri@3.1.2': {}
2212
2167
2213
-
'@jridgewell/set-array@1.2.1': {}
2214
-
2215
-
'@jridgewell/source-map@0.3.6':
2168
+
'@jridgewell/source-map@0.3.11':
2216
2169
dependencies:
2217
-
'@jridgewell/gen-mapping': 0.3.8
2218
-
'@jridgewell/trace-mapping': 0.3.25
2170
+
'@jridgewell/gen-mapping': 0.3.13
2171
+
'@jridgewell/trace-mapping': 0.3.31
2219
2172
2220
-
'@jridgewell/sourcemap-codec@1.5.0': {}
2173
+
'@jridgewell/sourcemap-codec@1.5.5': {}
2221
2174
2222
-
'@jridgewell/trace-mapping@0.3.25':
2175
+
'@jridgewell/trace-mapping@0.3.31':
2223
2176
dependencies:
2224
2177
'@jridgewell/resolve-uri': 3.1.2
2225
-
'@jridgewell/sourcemap-codec': 1.5.0
2178
+
'@jridgewell/sourcemap-codec': 1.5.5
2226
2179
2227
2180
'@jridgewell/trace-mapping@0.3.9':
2228
2181
dependencies:
2229
2182
'@jridgewell/resolve-uri': 3.1.2
2230
-
'@jridgewell/sourcemap-codec': 1.5.0
2183
+
'@jridgewell/sourcemap-codec': 1.5.5
2231
2184
2232
-
'@jsr/mary__array-fns@0.1.4': {}
2185
+
'@jsr/mary__array-fns@0.1.5': {}
2233
2186
2234
-
'@jsr/mary__ds-queue@0.1.2': {}
2187
+
'@jsr/mary__ds-queue@0.1.3': {}
2235
2188
2236
2189
'@jsr/mary__events@0.2.0': {}
2237
2190
2238
-
'@jsr/mary__tar@0.2.4': {}
2191
+
'@jsr/mary__tar@0.3.1': {}
2239
2192
2240
-
'@noble/secp256k1@2.2.3': {}
2193
+
'@noble/secp256k1@3.0.0': {}
2241
2194
2242
2195
'@nodelib/fs.scandir@2.1.5':
2243
2196
dependencies:
···
2251
2204
'@nodelib/fs.scandir': 2.1.5
2252
2205
fastq: 1.19.1
2253
2206
2254
-
'@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':
2255
2220
optional: true
2256
2221
2257
-
'@rollup/rollup-android-arm-eabi@4.40.2':
2222
+
'@rollup/rollup-android-arm64@4.53.3':
2258
2223
optional: true
2259
2224
2260
-
'@rollup/rollup-android-arm64@4.40.2':
2225
+
'@rollup/rollup-darwin-arm64@4.53.3':
2261
2226
optional: true
2262
2227
2263
-
'@rollup/rollup-darwin-arm64@4.40.2':
2228
+
'@rollup/rollup-darwin-x64@4.53.3':
2264
2229
optional: true
2265
2230
2266
-
'@rollup/rollup-darwin-x64@4.40.2':
2231
+
'@rollup/rollup-freebsd-arm64@4.53.3':
2267
2232
optional: true
2268
2233
2269
-
'@rollup/rollup-freebsd-arm64@4.40.2':
2234
+
'@rollup/rollup-freebsd-x64@4.53.3':
2235
+
optional: true
2236
+
2237
+
'@rollup/rollup-linux-arm-gnueabihf@4.53.3':
2270
2238
optional: true
2271
2239
2272
-
'@rollup/rollup-freebsd-x64@4.40.2':
2240
+
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
2273
2241
optional: true
2274
2242
2275
-
'@rollup/rollup-linux-arm-gnueabihf@4.40.2':
2243
+
'@rollup/rollup-linux-arm64-gnu@4.53.3':
2276
2244
optional: true
2277
2245
2278
-
'@rollup/rollup-linux-arm-musleabihf@4.40.2':
2246
+
'@rollup/rollup-linux-arm64-musl@4.53.3':
2279
2247
optional: true
2280
2248
2281
-
'@rollup/rollup-linux-arm64-gnu@4.40.2':
2249
+
'@rollup/rollup-linux-loong64-gnu@4.53.3':
2282
2250
optional: true
2283
2251
2284
-
'@rollup/rollup-linux-arm64-musl@4.40.2':
2252
+
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
2285
2253
optional: true
2286
2254
2287
-
'@rollup/rollup-linux-loongarch64-gnu@4.40.2':
2255
+
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
2288
2256
optional: true
2289
2257
2290
-
'@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
2258
+
'@rollup/rollup-linux-riscv64-musl@4.53.3':
2291
2259
optional: true
2292
2260
2293
-
'@rollup/rollup-linux-riscv64-gnu@4.40.2':
2261
+
'@rollup/rollup-linux-s390x-gnu@4.53.3':
2294
2262
optional: true
2295
2263
2296
-
'@rollup/rollup-linux-riscv64-musl@4.40.2':
2264
+
'@rollup/rollup-linux-x64-gnu@4.53.3':
2297
2265
optional: true
2298
2266
2299
-
'@rollup/rollup-linux-s390x-gnu@4.40.2':
2267
+
'@rollup/rollup-linux-x64-musl@4.53.3':
2300
2268
optional: true
2301
2269
2302
-
'@rollup/rollup-linux-x64-gnu@4.40.2':
2270
+
'@rollup/rollup-openharmony-arm64@4.53.3':
2303
2271
optional: true
2304
2272
2305
-
'@rollup/rollup-linux-x64-musl@4.40.2':
2273
+
'@rollup/rollup-win32-arm64-msvc@4.53.3':
2306
2274
optional: true
2307
2275
2308
-
'@rollup/rollup-win32-arm64-msvc@4.40.2':
2276
+
'@rollup/rollup-win32-ia32-msvc@4.53.3':
2309
2277
optional: true
2310
2278
2311
-
'@rollup/rollup-win32-ia32-msvc@4.40.2':
2279
+
'@rollup/rollup-win32-x64-gnu@4.53.3':
2312
2280
optional: true
2313
2281
2314
-
'@rollup/rollup-win32-x64-msvc@4.40.2':
2282
+
'@rollup/rollup-win32-x64-msvc@4.53.3':
2315
2283
optional: true
2316
2284
2317
-
'@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)':
2318
2292
dependencies:
2319
2293
mini-svg-data-uri: 1.4.4
2320
-
tailwindcss: 3.4.17
2294
+
tailwindcss: 3.4.18
2321
2295
2322
2296
'@types/babel__core@7.20.5':
2323
2297
dependencies:
2324
-
'@babel/parser': 7.27.1
2325
-
'@babel/types': 7.27.1
2298
+
'@babel/parser': 7.28.5
2299
+
'@babel/types': 7.28.5
2326
2300
'@types/babel__generator': 7.27.0
2327
2301
'@types/babel__template': 7.4.4
2328
-
'@types/babel__traverse': 7.20.7
2302
+
'@types/babel__traverse': 7.28.0
2329
2303
2330
2304
'@types/babel__generator@7.27.0':
2331
2305
dependencies:
2332
-
'@babel/types': 7.27.1
2306
+
'@babel/types': 7.28.5
2333
2307
2334
2308
'@types/babel__template@7.4.4':
2335
2309
dependencies:
2336
-
'@babel/parser': 7.27.1
2337
-
'@babel/types': 7.27.1
2310
+
'@babel/parser': 7.28.5
2311
+
'@babel/types': 7.28.5
2338
2312
2339
-
'@types/babel__traverse@7.20.7':
2313
+
'@types/babel__traverse@7.28.0':
2340
2314
dependencies:
2341
-
'@babel/types': 7.27.1
2315
+
'@babel/types': 7.28.5
2342
2316
2343
-
'@types/estree@1.0.7': {}
2317
+
'@types/estree@1.0.8': {}
2344
2318
2345
-
'@types/node@22.15.12':
2319
+
'@types/node@22.19.2':
2346
2320
dependencies:
2347
2321
undici-types: 6.21.0
2348
2322
···
2350
2324
2351
2325
acorn@8.14.0: {}
2352
2326
2353
-
acorn@8.14.1: {}
2354
-
2355
-
ansi-regex@5.0.1: {}
2356
-
2357
-
ansi-regex@6.1.0: {}
2358
-
2359
-
ansi-styles@4.3.0:
2360
-
dependencies:
2361
-
color-convert: 2.0.1
2362
-
2363
-
ansi-styles@6.2.1: {}
2327
+
acorn@8.15.0: {}
2364
2328
2365
2329
any-promise@1.3.0: {}
2366
2330
···
2371
2335
2372
2336
arg@5.0.2: {}
2373
2337
2374
-
as-table@1.0.55:
2375
-
dependencies:
2376
-
printable-characters: 1.0.42
2377
-
2378
-
autoprefixer@10.4.21(postcss@8.5.3):
2338
+
autoprefixer@10.4.22(postcss@8.5.6):
2379
2339
dependencies:
2380
-
browserslist: 4.24.5
2381
-
caniuse-lite: 1.0.30001717
2382
-
fraction.js: 4.3.7
2340
+
browserslist: 4.28.1
2341
+
caniuse-lite: 1.0.30001760
2342
+
fraction.js: 5.3.4
2383
2343
normalize-range: 0.1.2
2384
2344
picocolors: 1.1.1
2385
-
postcss: 8.5.3
2345
+
postcss: 8.5.6
2386
2346
postcss-value-parser: 4.2.0
2387
2347
2388
-
babel-plugin-jsx-dom-expressions@0.39.8(@babel/core@7.27.1):
2348
+
babel-plugin-jsx-dom-expressions@0.40.3(@babel/core@7.28.5):
2389
2349
dependencies:
2390
-
'@babel/core': 7.27.1
2350
+
'@babel/core': 7.28.5
2391
2351
'@babel/helper-module-imports': 7.18.6
2392
-
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.1)
2393
-
'@babel/types': 7.27.1
2352
+
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
2353
+
'@babel/types': 7.28.5
2394
2354
html-entities: 2.3.3
2395
2355
parse5: 7.3.0
2396
-
validate-html-nesting: 1.2.2
2397
2356
2398
-
babel-preset-solid@1.9.6(@babel/core@7.27.1):
2357
+
babel-preset-solid@1.9.10(@babel/core@7.28.5)(solid-js@1.9.10):
2399
2358
dependencies:
2400
-
'@babel/core': 7.27.1
2401
-
babel-plugin-jsx-dom-expressions: 0.39.8(@babel/core@7.27.1)
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
2402
2363
2403
-
balanced-match@1.0.2: {}
2364
+
baseline-browser-mapping@2.9.5: {}
2404
2365
2405
2366
binary-extensions@2.3.0: {}
2406
2367
2407
2368
blake3-wasm@2.1.5: {}
2408
2369
2409
-
brace-expansion@2.0.1:
2410
-
dependencies:
2411
-
balanced-match: 1.0.2
2412
-
2413
2370
braces@3.0.3:
2414
2371
dependencies:
2415
2372
fill-range: 7.1.1
2416
2373
2417
-
browserslist@4.24.5:
2374
+
browserslist@4.28.1:
2418
2375
dependencies:
2419
-
caniuse-lite: 1.0.30001717
2420
-
electron-to-chromium: 1.5.150
2421
-
node-releases: 2.0.19
2422
-
update-browserslist-db: 1.1.3(browserslist@4.24.5)
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)
2423
2381
2424
2382
buffer-from@1.1.2: {}
2425
2383
2426
2384
camelcase-css@2.0.1: {}
2427
2385
2428
-
caniuse-lite@1.0.30001717: {}
2386
+
caniuse-lite@1.0.30001760: {}
2429
2387
2430
2388
chokidar@3.6.0:
2431
2389
dependencies:
···
2448
2406
color-string@1.9.1:
2449
2407
dependencies:
2450
2408
color-name: 1.1.4
2451
-
simple-swizzle: 0.2.2
2452
-
optional: true
2409
+
simple-swizzle: 0.2.4
2453
2410
2454
2411
color@4.2.3:
2455
2412
dependencies:
2456
2413
color-convert: 2.0.1
2457
2414
color-string: 1.9.1
2458
-
optional: true
2459
2415
2460
2416
commander@2.20.3: {}
2461
2417
···
2463
2419
2464
2420
convert-source-map@2.0.0: {}
2465
2421
2466
-
cookie@0.7.2: {}
2467
-
2468
-
cross-spawn@7.0.6:
2469
-
dependencies:
2470
-
path-key: 3.1.1
2471
-
shebang-command: 2.0.0
2472
-
which: 2.0.2
2422
+
cookie@1.1.1: {}
2473
2423
2474
2424
cssesc@3.0.0: {}
2475
2425
2476
-
csstype@3.1.3: {}
2426
+
csstype@3.2.3: {}
2477
2427
2478
-
data-uri-to-buffer@2.0.2: {}
2479
-
2480
-
debug@4.4.0:
2428
+
debug@4.4.3:
2481
2429
dependencies:
2482
2430
ms: 2.1.3
2483
2431
2484
-
defu@6.1.4: {}
2485
-
2486
-
detect-libc@2.0.4:
2487
-
optional: true
2432
+
detect-libc@2.1.2: {}
2488
2433
2489
2434
didyoumean@1.2.2: {}
2490
2435
2491
2436
dlv@1.1.3: {}
2492
2437
2493
-
eastasianwidth@0.2.0: {}
2438
+
electron-to-chromium@1.5.267: {}
2494
2439
2495
-
electron-to-chromium@1.5.150: {}
2440
+
entities@6.0.1: {}
2496
2441
2497
-
emoji-regex@8.0.0: {}
2442
+
error-stack-parser-es@1.0.5: {}
2498
2443
2499
-
emoji-regex@9.2.2: {}
2500
-
2501
-
entities@6.0.0: {}
2502
-
2503
-
esbuild@0.25.2:
2444
+
esbuild@0.25.12:
2504
2445
optionalDependencies:
2505
-
'@esbuild/aix-ppc64': 0.25.2
2506
-
'@esbuild/android-arm': 0.25.2
2507
-
'@esbuild/android-arm64': 0.25.2
2508
-
'@esbuild/android-x64': 0.25.2
2509
-
'@esbuild/darwin-arm64': 0.25.2
2510
-
'@esbuild/darwin-x64': 0.25.2
2511
-
'@esbuild/freebsd-arm64': 0.25.2
2512
-
'@esbuild/freebsd-x64': 0.25.2
2513
-
'@esbuild/linux-arm': 0.25.2
2514
-
'@esbuild/linux-arm64': 0.25.2
2515
-
'@esbuild/linux-ia32': 0.25.2
2516
-
'@esbuild/linux-loong64': 0.25.2
2517
-
'@esbuild/linux-mips64el': 0.25.2
2518
-
'@esbuild/linux-ppc64': 0.25.2
2519
-
'@esbuild/linux-riscv64': 0.25.2
2520
-
'@esbuild/linux-s390x': 0.25.2
2521
-
'@esbuild/linux-x64': 0.25.2
2522
-
'@esbuild/netbsd-arm64': 0.25.2
2523
-
'@esbuild/netbsd-x64': 0.25.2
2524
-
'@esbuild/openbsd-arm64': 0.25.2
2525
-
'@esbuild/openbsd-x64': 0.25.2
2526
-
'@esbuild/sunos-x64': 0.25.2
2527
-
'@esbuild/win32-arm64': 0.25.2
2528
-
'@esbuild/win32-ia32': 0.25.2
2529
-
'@esbuild/win32-x64': 0.25.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
2530
2472
2531
-
esbuild@0.25.4:
2473
+
esbuild@0.27.0:
2532
2474
optionalDependencies:
2533
-
'@esbuild/aix-ppc64': 0.25.4
2534
-
'@esbuild/android-arm': 0.25.4
2535
-
'@esbuild/android-arm64': 0.25.4
2536
-
'@esbuild/android-x64': 0.25.4
2537
-
'@esbuild/darwin-arm64': 0.25.4
2538
-
'@esbuild/darwin-x64': 0.25.4
2539
-
'@esbuild/freebsd-arm64': 0.25.4
2540
-
'@esbuild/freebsd-x64': 0.25.4
2541
-
'@esbuild/linux-arm': 0.25.4
2542
-
'@esbuild/linux-arm64': 0.25.4
2543
-
'@esbuild/linux-ia32': 0.25.4
2544
-
'@esbuild/linux-loong64': 0.25.4
2545
-
'@esbuild/linux-mips64el': 0.25.4
2546
-
'@esbuild/linux-ppc64': 0.25.4
2547
-
'@esbuild/linux-riscv64': 0.25.4
2548
-
'@esbuild/linux-s390x': 0.25.4
2549
-
'@esbuild/linux-x64': 0.25.4
2550
-
'@esbuild/netbsd-arm64': 0.25.4
2551
-
'@esbuild/netbsd-x64': 0.25.4
2552
-
'@esbuild/openbsd-arm64': 0.25.4
2553
-
'@esbuild/openbsd-x64': 0.25.4
2554
-
'@esbuild/sunos-x64': 0.25.4
2555
-
'@esbuild/win32-arm64': 0.25.4
2556
-
'@esbuild/win32-ia32': 0.25.4
2557
-
'@esbuild/win32-x64': 0.25.4
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
2558
2501
2559
2502
escalade@3.2.0: {}
2560
2503
2561
-
exit-hook@2.2.1: {}
2504
+
esm-env@1.2.2: {}
2562
2505
2563
-
exsolve@1.0.5: {}
2506
+
exit-hook@2.2.1: {}
2564
2507
2565
2508
fast-glob@3.3.3:
2566
2509
dependencies:
···
2574
2517
dependencies:
2575
2518
reusify: 1.1.0
2576
2519
2577
-
fdir@6.4.4(picomatch@4.0.2):
2520
+
fdir@6.5.0(picomatch@4.0.3):
2578
2521
optionalDependencies:
2579
-
picomatch: 4.0.2
2522
+
picomatch: 4.0.3
2580
2523
2581
2524
fetch-blob@3.2.0:
2582
2525
dependencies:
···
2588
2531
dependencies:
2589
2532
to-regex-range: 5.0.1
2590
2533
2591
-
foreground-child@3.3.1:
2592
-
dependencies:
2593
-
cross-spawn: 7.0.6
2594
-
signal-exit: 4.1.0
2595
-
2596
-
fraction.js@4.3.7: {}
2534
+
fraction.js@5.3.4: {}
2597
2535
2598
2536
fsevents@2.3.3:
2599
2537
optional: true
···
2602
2540
2603
2541
gensync@1.0.0-beta.2: {}
2604
2542
2605
-
get-source@2.0.12:
2606
-
dependencies:
2607
-
data-uri-to-buffer: 2.0.2
2608
-
source-map: 0.6.1
2609
-
2610
2543
glob-parent@5.1.2:
2611
2544
dependencies:
2612
2545
is-glob: 4.0.3
···
2617
2550
2618
2551
glob-to-regexp@0.4.1: {}
2619
2552
2620
-
glob@10.4.5:
2621
-
dependencies:
2622
-
foreground-child: 3.3.1
2623
-
jackspeak: 3.4.3
2624
-
minimatch: 9.0.5
2625
-
minipass: 7.1.2
2626
-
package-json-from-dist: 1.0.1
2627
-
path-scurry: 1.11.1
2628
-
2629
-
globals@11.12.0: {}
2630
-
2631
2553
hasown@2.0.2:
2632
2554
dependencies:
2633
2555
function-bind: 1.1.2
2634
2556
2635
2557
html-entities@2.3.3: {}
2636
2558
2637
-
is-arrayish@0.3.2:
2638
-
optional: true
2559
+
is-arrayish@0.3.4: {}
2639
2560
2640
2561
is-binary-path@2.1.0:
2641
2562
dependencies:
···
2647
2568
2648
2569
is-extglob@2.1.1: {}
2649
2570
2650
-
is-fullwidth-code-point@3.0.0: {}
2651
-
2652
2571
is-glob@4.0.3:
2653
2572
dependencies:
2654
2573
is-extglob: 2.1.1
···
2657
2576
2658
2577
is-what@4.1.16: {}
2659
2578
2660
-
isexe@2.0.0: {}
2661
-
2662
-
jackspeak@3.4.3:
2663
-
dependencies:
2664
-
'@isaacs/cliui': 8.0.2
2665
-
optionalDependencies:
2666
-
'@pkgjs/parseargs': 0.11.0
2667
-
2668
2579
jiti@1.21.7: {}
2669
2580
2670
2581
js-tokens@4.0.0: {}
···
2673
2584
2674
2585
json5@2.2.3: {}
2675
2586
2587
+
kleur@4.1.5: {}
2588
+
2676
2589
lilconfig@3.1.3: {}
2677
2590
2678
2591
lines-and-columns@1.2.4: {}
2679
2592
2680
-
lru-cache@10.4.3: {}
2681
-
2682
2593
lru-cache@5.1.1:
2683
2594
dependencies:
2684
2595
yallist: 3.1.1
···
2698
2609
2699
2610
mini-svg-data-uri@1.4.4: {}
2700
2611
2701
-
miniflare@4.20250428.1:
2612
+
miniflare@4.20251202.1:
2702
2613
dependencies:
2703
2614
'@cspotcode/source-map-support': 0.8.1
2704
2615
acorn: 8.14.0
2705
2616
acorn-walk: 8.3.2
2706
2617
exit-hook: 2.2.1
2707
2618
glob-to-regexp: 0.4.1
2619
+
sharp: 0.33.5
2708
2620
stoppable: 1.1.0
2709
-
undici: 5.29.0
2710
-
workerd: 1.20250428.0
2621
+
undici: 7.14.0
2622
+
workerd: 1.20251202.0
2711
2623
ws: 8.18.0
2712
-
youch: 3.3.4
2624
+
youch: 4.1.0-beta.10
2713
2625
zod: 3.22.3
2714
2626
transitivePeerDependencies:
2715
2627
- bufferutil
2716
2628
- utf-8-validate
2717
2629
2718
-
minimatch@9.0.5:
2719
-
dependencies:
2720
-
brace-expansion: 2.0.1
2721
-
2722
-
minipass@7.1.2: {}
2723
-
2724
2630
ms@2.1.3: {}
2725
2631
2726
-
mustache@4.2.0: {}
2727
-
2728
2632
mz@2.7.0:
2729
2633
dependencies:
2730
2634
any-promise: 1.3.0
···
2733
2637
2734
2638
nanoid@3.3.11: {}
2735
2639
2736
-
nanoid@5.1.5: {}
2640
+
nanoid@5.1.6: {}
2737
2641
2738
2642
native-file-system-adapter@3.0.1:
2739
2643
optionalDependencies:
···
2742
2646
node-domexception@1.0.0:
2743
2647
optional: true
2744
2648
2745
-
node-releases@2.0.19: {}
2649
+
node-releases@2.0.27: {}
2746
2650
2747
2651
normalize-path@3.0.0: {}
2748
2652
···
2752
2656
2753
2657
object-hash@3.0.0: {}
2754
2658
2755
-
ohash@2.0.11: {}
2756
-
2757
-
package-json-from-dist@1.0.1: {}
2758
-
2759
2659
parse5@7.3.0:
2760
2660
dependencies:
2761
-
entities: 6.0.0
2762
-
2763
-
path-key@3.1.1: {}
2661
+
entities: 6.0.1
2764
2662
2765
2663
path-parse@1.0.7: {}
2766
-
2767
-
path-scurry@1.11.1:
2768
-
dependencies:
2769
-
lru-cache: 10.4.3
2770
-
minipass: 7.1.2
2771
2664
2772
2665
path-to-regexp@6.3.0: {}
2773
2666
···
2777
2670
2778
2671
picomatch@2.3.1: {}
2779
2672
2780
-
picomatch@4.0.2: {}
2673
+
picomatch@4.0.3: {}
2781
2674
2782
2675
pify@2.3.0: {}
2783
2676
2784
2677
pirates@4.0.7: {}
2785
2678
2786
-
postcss-import@15.1.0(postcss@8.5.3):
2679
+
postcss-import@15.1.0(postcss@8.5.6):
2787
2680
dependencies:
2788
-
postcss: 8.5.3
2681
+
postcss: 8.5.6
2789
2682
postcss-value-parser: 4.2.0
2790
2683
read-cache: 1.0.0
2791
-
resolve: 1.22.10
2684
+
resolve: 1.22.11
2792
2685
2793
-
postcss-js@4.0.1(postcss@8.5.3):
2686
+
postcss-js@4.1.0(postcss@8.5.6):
2794
2687
dependencies:
2795
2688
camelcase-css: 2.0.1
2796
-
postcss: 8.5.3
2689
+
postcss: 8.5.6
2797
2690
2798
-
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):
2799
2692
dependencies:
2800
2693
lilconfig: 3.1.3
2801
-
yaml: 2.7.1
2802
2694
optionalDependencies:
2803
-
postcss: 8.5.3
2695
+
jiti: 1.21.7
2696
+
postcss: 8.5.6
2804
2697
2805
-
postcss-nested@6.2.0(postcss@8.5.3):
2698
+
postcss-nested@6.2.0(postcss@8.5.6):
2806
2699
dependencies:
2807
-
postcss: 8.5.3
2700
+
postcss: 8.5.6
2808
2701
postcss-selector-parser: 6.1.2
2809
2702
2810
2703
postcss-selector-parser@6.1.2:
···
2814
2707
2815
2708
postcss-value-parser@4.2.0: {}
2816
2709
2817
-
postcss@8.5.3:
2710
+
postcss@8.5.6:
2818
2711
dependencies:
2819
2712
nanoid: 3.3.11
2820
2713
picocolors: 1.1.1
2821
2714
source-map-js: 1.2.1
2822
2715
2823
-
prettier-plugin-tailwindcss@0.6.11(prettier@3.5.3):
2716
+
prettier-plugin-tailwindcss@0.6.14(prettier@3.7.4):
2824
2717
dependencies:
2825
-
prettier: 3.5.3
2826
-
2827
-
prettier@3.5.3: {}
2718
+
prettier: 3.7.4
2828
2719
2829
-
printable-characters@1.0.42: {}
2720
+
prettier@3.7.4: {}
2830
2721
2831
2722
queue-microtask@1.2.3: {}
2832
2723
···
2838
2729
dependencies:
2839
2730
picomatch: 2.3.1
2840
2731
2841
-
resolve@1.22.10:
2732
+
resolve@1.22.11:
2842
2733
dependencies:
2843
2734
is-core-module: 2.16.1
2844
2735
path-parse: 1.0.7
···
2846
2737
2847
2738
reusify@1.1.0: {}
2848
2739
2849
-
rollup@4.40.2:
2740
+
rollup@4.53.3:
2850
2741
dependencies:
2851
-
'@types/estree': 1.0.7
2742
+
'@types/estree': 1.0.8
2852
2743
optionalDependencies:
2853
-
'@rollup/rollup-android-arm-eabi': 4.40.2
2854
-
'@rollup/rollup-android-arm64': 4.40.2
2855
-
'@rollup/rollup-darwin-arm64': 4.40.2
2856
-
'@rollup/rollup-darwin-x64': 4.40.2
2857
-
'@rollup/rollup-freebsd-arm64': 4.40.2
2858
-
'@rollup/rollup-freebsd-x64': 4.40.2
2859
-
'@rollup/rollup-linux-arm-gnueabihf': 4.40.2
2860
-
'@rollup/rollup-linux-arm-musleabihf': 4.40.2
2861
-
'@rollup/rollup-linux-arm64-gnu': 4.40.2
2862
-
'@rollup/rollup-linux-arm64-musl': 4.40.2
2863
-
'@rollup/rollup-linux-loongarch64-gnu': 4.40.2
2864
-
'@rollup/rollup-linux-powerpc64le-gnu': 4.40.2
2865
-
'@rollup/rollup-linux-riscv64-gnu': 4.40.2
2866
-
'@rollup/rollup-linux-riscv64-musl': 4.40.2
2867
-
'@rollup/rollup-linux-s390x-gnu': 4.40.2
2868
-
'@rollup/rollup-linux-x64-gnu': 4.40.2
2869
-
'@rollup/rollup-linux-x64-musl': 4.40.2
2870
-
'@rollup/rollup-win32-arm64-msvc': 4.40.2
2871
-
'@rollup/rollup-win32-ia32-msvc': 4.40.2
2872
-
'@rollup/rollup-win32-x64-msvc': 4.40.2
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
2873
2766
fsevents: 2.3.3
2874
2767
2875
2768
run-parallel@1.2.0:
···
2878
2771
2879
2772
semver@6.3.1: {}
2880
2773
2881
-
semver@7.7.1:
2882
-
optional: true
2774
+
semver@7.7.3: {}
2883
2775
2884
-
seroval-plugins@1.2.1(seroval@1.2.1):
2776
+
seroval-plugins@1.3.3(seroval@1.3.2):
2885
2777
dependencies:
2886
-
seroval: 1.2.1
2778
+
seroval: 1.3.2
2887
2779
2888
-
seroval@1.2.1: {}
2780
+
seroval@1.3.2: {}
2889
2781
2890
2782
sharp@0.33.5:
2891
2783
dependencies:
2892
2784
color: 4.2.3
2893
-
detect-libc: 2.0.4
2894
-
semver: 7.7.1
2785
+
detect-libc: 2.1.2
2786
+
semver: 7.7.3
2895
2787
optionalDependencies:
2896
2788
'@img/sharp-darwin-arm64': 0.33.5
2897
2789
'@img/sharp-darwin-x64': 0.33.5
···
2912
2804
'@img/sharp-wasm32': 0.33.5
2913
2805
'@img/sharp-win32-ia32': 0.33.5
2914
2806
'@img/sharp-win32-x64': 0.33.5
2915
-
optional: true
2916
-
2917
-
shebang-command@2.0.0:
2918
-
dependencies:
2919
-
shebang-regex: 3.0.0
2920
-
2921
-
shebang-regex@3.0.0: {}
2922
-
2923
-
signal-exit@4.1.0: {}
2924
2807
2925
-
simple-swizzle@0.2.2:
2808
+
simple-swizzle@0.2.4:
2926
2809
dependencies:
2927
-
is-arrayish: 0.3.2
2928
-
optional: true
2810
+
is-arrayish: 0.3.4
2929
2811
2930
-
solid-js@1.9.6:
2812
+
solid-js@1.9.10:
2931
2813
dependencies:
2932
-
csstype: 3.1.3
2933
-
seroval: 1.2.1
2934
-
seroval-plugins: 1.2.1(seroval@1.2.1)
2814
+
csstype: 3.2.3
2815
+
seroval: 1.3.2
2816
+
seroval-plugins: 1.3.3(seroval@1.3.2)
2935
2817
2936
-
solid-refresh@0.6.3(solid-js@1.9.6):
2818
+
solid-refresh@0.6.3(solid-js@1.9.10):
2937
2819
dependencies:
2938
-
'@babel/generator': 7.27.1
2820
+
'@babel/generator': 7.28.5
2939
2821
'@babel/helper-module-imports': 7.27.1
2940
-
'@babel/types': 7.27.1
2941
-
solid-js: 1.9.6
2822
+
'@babel/types': 7.28.5
2823
+
solid-js: 1.9.10
2942
2824
transitivePeerDependencies:
2943
2825
- supports-color
2944
2826
···
2950
2832
source-map: 0.6.1
2951
2833
2952
2834
source-map@0.6.1: {}
2953
-
2954
-
stacktracey@2.1.8:
2955
-
dependencies:
2956
-
as-table: 1.0.55
2957
-
get-source: 2.0.12
2958
2835
2959
2836
stoppable@1.1.0: {}
2960
2837
2961
-
string-width@4.2.3:
2838
+
sucrase@3.35.1:
2962
2839
dependencies:
2963
-
emoji-regex: 8.0.0
2964
-
is-fullwidth-code-point: 3.0.0
2965
-
strip-ansi: 6.0.1
2966
-
2967
-
string-width@5.1.2:
2968
-
dependencies:
2969
-
eastasianwidth: 0.2.0
2970
-
emoji-regex: 9.2.2
2971
-
strip-ansi: 7.1.0
2972
-
2973
-
strip-ansi@6.0.1:
2974
-
dependencies:
2975
-
ansi-regex: 5.0.1
2976
-
2977
-
strip-ansi@7.1.0:
2978
-
dependencies:
2979
-
ansi-regex: 6.1.0
2980
-
2981
-
sucrase@3.35.0:
2982
-
dependencies:
2983
-
'@jridgewell/gen-mapping': 0.3.8
2840
+
'@jridgewell/gen-mapping': 0.3.13
2984
2841
commander: 4.1.1
2985
-
glob: 10.4.5
2986
2842
lines-and-columns: 1.2.4
2987
2843
mz: 2.7.0
2988
2844
pirates: 4.0.7
2845
+
tinyglobby: 0.2.15
2989
2846
ts-interface-checker: 0.1.13
2847
+
2848
+
supports-color@10.2.2: {}
2990
2849
2991
2850
supports-preserve-symlinks-flag@1.0.0: {}
2992
2851
2993
-
tailwindcss@3.4.17:
2852
+
tailwindcss@3.4.18:
2994
2853
dependencies:
2995
2854
'@alloc/quick-lru': 5.2.0
2996
2855
arg: 5.0.2
···
3006
2865
normalize-path: 3.0.0
3007
2866
object-hash: 3.0.0
3008
2867
picocolors: 1.1.1
3009
-
postcss: 8.5.3
3010
-
postcss-import: 15.1.0(postcss@8.5.3)
3011
-
postcss-js: 4.0.1(postcss@8.5.3)
3012
-
postcss-load-config: 4.0.2(postcss@8.5.3)
3013
-
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)
3014
2873
postcss-selector-parser: 6.1.2
3015
-
resolve: 1.22.10
3016
-
sucrase: 3.35.0
2874
+
resolve: 1.22.11
2875
+
sucrase: 3.35.1
3017
2876
transitivePeerDependencies:
3018
-
- ts-node
2877
+
- tsx
2878
+
- yaml
3019
2879
3020
-
terser@5.39.0:
2880
+
terser@5.44.1:
3021
2881
dependencies:
3022
-
'@jridgewell/source-map': 0.3.6
3023
-
acorn: 8.14.1
2882
+
'@jridgewell/source-map': 0.3.11
2883
+
acorn: 8.15.0
3024
2884
commander: 2.20.3
3025
2885
source-map-support: 0.5.21
3026
2886
···
3032
2892
dependencies:
3033
2893
any-promise: 1.3.0
3034
2894
3035
-
tinyglobby@0.2.13:
2895
+
tinyglobby@0.2.15:
3036
2896
dependencies:
3037
-
fdir: 6.4.4(picomatch@4.0.2)
3038
-
picomatch: 4.0.2
2897
+
fdir: 6.5.0(picomatch@4.0.3)
2898
+
picomatch: 4.0.3
3039
2899
3040
2900
to-regex-range@5.0.1:
3041
2901
dependencies:
···
3046
2906
tslib@2.8.1:
3047
2907
optional: true
3048
2908
3049
-
typescript@5.8.3: {}
3050
-
3051
-
ufo@1.6.1: {}
2909
+
typescript@5.9.3: {}
3052
2910
3053
2911
undici-types@6.21.0: {}
3054
2912
3055
-
undici@5.29.0:
3056
-
dependencies:
3057
-
'@fastify/busboy': 2.1.1
2913
+
undici@7.14.0: {}
3058
2914
3059
-
unenv@2.0.0-rc.15:
2915
+
unenv@2.0.0-rc.24:
3060
2916
dependencies:
3061
-
defu: 6.1.4
3062
-
exsolve: 1.0.5
3063
-
ohash: 2.0.11
3064
2917
pathe: 2.0.3
3065
-
ufo: 1.6.1
3066
2918
3067
-
update-browserslist-db@1.1.3(browserslist@4.24.5):
2919
+
update-browserslist-db@1.2.2(browserslist@4.28.1):
3068
2920
dependencies:
3069
-
browserslist: 4.24.5
2921
+
browserslist: 4.28.1
3070
2922
escalade: 3.2.0
3071
2923
picocolors: 1.1.1
3072
2924
3073
2925
util-deprecate@1.0.2: {}
3074
2926
3075
-
validate-html-nesting@1.2.2: {}
3076
-
3077
-
vite-plugin-solid@2.11.6(solid-js@1.9.6)(vite@6.3.5(@types/node@22.15.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.1)):
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)):
3078
2928
dependencies:
3079
-
'@babel/core': 7.27.1
2929
+
'@babel/core': 7.28.5
3080
2930
'@types/babel__core': 7.20.5
3081
-
babel-preset-solid: 1.9.6(@babel/core@7.27.1)
2931
+
babel-preset-solid: 1.9.10(@babel/core@7.28.5)(solid-js@1.9.10)
3082
2932
merge-anything: 5.1.7
3083
-
solid-js: 1.9.6
3084
-
solid-refresh: 0.6.3(solid-js@1.9.6)
3085
-
vite: 6.3.5(@types/node@22.15.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.1)
3086
-
vitefu: 1.0.6(vite@6.3.5(@types/node@22.15.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.1))
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))
3087
2937
transitivePeerDependencies:
3088
2938
- supports-color
3089
2939
3090
-
vite@6.3.5(@types/node@22.15.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.1):
2940
+
vite@7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1):
3091
2941
dependencies:
3092
-
esbuild: 0.25.4
3093
-
fdir: 6.4.4(picomatch@4.0.2)
3094
-
picomatch: 4.0.2
3095
-
postcss: 8.5.3
3096
-
rollup: 4.40.2
3097
-
tinyglobby: 0.2.13
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
3098
2948
optionalDependencies:
3099
-
'@types/node': 22.15.12
2949
+
'@types/node': 22.19.2
3100
2950
fsevents: 2.3.3
3101
2951
jiti: 1.21.7
3102
-
terser: 5.39.0
3103
-
yaml: 2.7.1
2952
+
terser: 5.44.1
3104
2953
3105
-
vitefu@1.0.6(vite@6.3.5(@types/node@22.15.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.1)):
2954
+
vitefu@1.1.1(vite@7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1)):
3106
2955
optionalDependencies:
3107
-
vite: 6.3.5(@types/node@22.15.12)(jiti@1.21.7)(terser@5.39.0)(yaml@2.7.1)
2956
+
vite: 7.2.7(@types/node@22.19.2)(jiti@1.21.7)(terser@5.44.1)
3108
2957
3109
2958
web-streams-polyfill@3.3.3:
3110
2959
optional: true
3111
2960
3112
-
which@2.0.2:
3113
-
dependencies:
3114
-
isexe: 2.0.0
3115
-
3116
-
workerd@1.20250428.0:
2961
+
workerd@1.20251202.0:
3117
2962
optionalDependencies:
3118
-
'@cloudflare/workerd-darwin-64': 1.20250428.0
3119
-
'@cloudflare/workerd-darwin-arm64': 1.20250428.0
3120
-
'@cloudflare/workerd-linux-64': 1.20250428.0
3121
-
'@cloudflare/workerd-linux-arm64': 1.20250428.0
3122
-
'@cloudflare/workerd-windows-64': 1.20250428.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
3123
2968
3124
-
wrangler@4.14.1:
2969
+
wrangler@4.53.0:
3125
2970
dependencies:
3126
-
'@cloudflare/kv-asset-handler': 0.4.0
3127
-
'@cloudflare/unenv-preset': 2.3.1(unenv@2.0.0-rc.15)(workerd@1.20250428.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)
3128
2973
blake3-wasm: 2.1.5
3129
-
esbuild: 0.25.2
3130
-
miniflare: 4.20250428.1
2974
+
esbuild: 0.27.0
2975
+
miniflare: 4.20251202.1
3131
2976
path-to-regexp: 6.3.0
3132
-
unenv: 2.0.0-rc.15
3133
-
workerd: 1.20250428.0
2977
+
unenv: 2.0.0-rc.24
2978
+
workerd: 1.20251202.0
3134
2979
optionalDependencies:
3135
2980
fsevents: 2.3.3
3136
-
sharp: 0.33.5
3137
2981
transitivePeerDependencies:
3138
2982
- bufferutil
3139
2983
- utf-8-validate
3140
2984
3141
-
wrap-ansi@7.0.0:
3142
-
dependencies:
3143
-
ansi-styles: 4.3.0
3144
-
string-width: 4.2.3
3145
-
strip-ansi: 6.0.1
3146
-
3147
-
wrap-ansi@8.1.0:
3148
-
dependencies:
3149
-
ansi-styles: 6.2.1
3150
-
string-width: 5.1.2
3151
-
strip-ansi: 7.1.0
3152
-
3153
2985
ws@8.18.0: {}
3154
2986
3155
2987
yallist@3.1.1: {}
3156
2988
3157
-
yaml@2.7.1: {}
2989
+
youch-core@0.3.3:
2990
+
dependencies:
2991
+
'@poppinss/exception': 1.2.2
2992
+
error-stack-parser-es: 1.0.5
3158
2993
3159
-
youch@3.3.4:
2994
+
youch@4.1.0-beta.10:
3160
2995
dependencies:
3161
-
cookie: 0.7.2
3162
-
mustache: 4.2.0
3163
-
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
3164
3001
3165
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>;
-49
src/api/utils/at-uri.ts
-49
src/api/utils/at-uri.ts
···
1
-
import type { At } from '@atcute/client/lexicons';
2
-
3
-
import { assert } from '~/lib/utils/invariant';
4
-
5
-
const DID_RE = /^did:([a-z]+):([a-zA-Z0-9._:%\-]*[a-zA-Z0-9._\-])$/;
6
-
7
-
const NSID_RE =
8
-
/^[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})?)$/;
9
-
10
-
const RECORD_KEY_RE = /^(?!\.{1,2}$)[a-zA-Z0-9_~.:-]{1,512}$/;
11
-
12
-
const ATURI_RE =
13
-
/^at:\/\/([a-zA-Z0-9._:%-]+)(?:\/([a-zA-Z0-9-.]+)(?:\/([a-zA-Z0-9._~:@!$&%')(*+,;=-]+))?)?(?:#(\/[a-zA-Z0-9._~:@!$&%')(*+,;=\-[\]/\\]*))?$/;
14
-
15
-
const isDid = (input: unknown): input is At.Did => {
16
-
return typeof input === 'string' && input.length >= 7 && input.length <= 2048 && DID_RE.test(input);
17
-
};
18
-
19
-
const isNsid = (input: unknown): input is At.Nsid => {
20
-
return typeof input === 'string' && input.length >= 5 && input.length <= 317 && NSID_RE.test(input);
21
-
};
22
-
23
-
const isRecordKey = (input: unknown): input is At.RecordKey => {
24
-
return typeof input === 'string' && input.length >= 1 && input.length <= 512 && RECORD_KEY_RE.test(input);
25
-
};
26
-
27
-
export interface AddressedAtUri {
28
-
repo: At.Did;
29
-
collection: At.Nsid;
30
-
rkey: At.RecordKey;
31
-
fragment: string | undefined;
32
-
}
33
-
34
-
export const parseAddressedAtUri = (str: string): AddressedAtUri => {
35
-
const match = ATURI_RE.exec(str);
36
-
assert(match !== null, `invalid addressed-at-uri: ${str}`);
37
-
38
-
const [, r, c, k, f] = match;
39
-
assert(isDid(r), `invalid repo in addressed-at-uri: ${r}`);
40
-
assert(isNsid(c), `invalid collection in addressed-at-uri: ${c}`);
41
-
assert(isRecordKey(k), `invalid rkey in addressed-at-uri: ${k}`);
42
-
43
-
return {
44
-
repo: r,
45
-
collection: c,
46
-
rkey: k,
47
-
fragment: f,
48
-
};
49
-
};
+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
};
+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;
+4
-8
src/views/blob/blob-export.tsx
+4
-8
src/views/blob/blob-export.tsx
···
2
2
import { createSignal } from 'solid-js';
3
3
4
4
import { Client, ClientResponseError, ok, simpleFetchHandler } from '@atcute/client';
5
-
import { type AtprotoDid, getPdsEndpoint, isAtprotoDid, isHandle } from '@atcute/identity';
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();
···
229
230
230
231
return (
231
232
<>
232
-
<div class="p-4">
233
-
<h1 class="text-lg font-bold text-purple-800">Export blobs</h1>
234
-
<p class="text-gray-600">Download all blobs from an account into a tarball</p>
235
-
</div>
236
-
<hr class="mx-4 border-gray-300" />
233
+
<PageHeader title="Export blobs" subtitle="Download all blobs from an account into a tarball" />
237
234
238
235
<form
239
236
onSubmit={(ev) => {
···
284
281
type="text"
285
282
name="ident"
286
283
autocomplete="username"
287
-
pattern={/* @once */ DID_OR_HANDLE_RE.source}
288
284
placeholder="paul.bsky.social"
289
285
autofocus
290
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
-
}
+2
-1
tsconfig.app.json
+2
-1
tsconfig.app.json
···
3
3
"target": "ESNext",
4
4
"module": "ESNext",
5
5
"lib": ["ESNext", "DOM", "DOM.Iterable"],
6
-
"types": [],
6
+
"types": ["@atcute/atproto", "@atcute/bluesky"],
7
7
"skipLibCheck": true,
8
8
9
9
"moduleResolution": "Bundler",
10
10
"allowImportingTsExtensions": true,
11
11
"isolatedModules": true,
12
+
"verbatimModuleSyntax": true,
12
13
"moduleDetection": "force",
13
14
"noEmit": true,
14
15