+42
-237
package-lock.json
+42
-237
package-lock.json
···
11
11
"dependencies": {
12
12
"@atcute/bluesky": "^1.0.7",
13
13
"@atcute/client": "^2.0.2",
14
-
"@atproto/oauth-client-browser": "^0.2.0",
14
+
"@atcute/oauth-browser-client": "^1.0.1",
15
15
"solid-js": "^1.8.11"
16
16
},
17
17
"devDependencies": {
18
18
"@tailwindcss/forms": "^0.5.7",
19
+
"@types/node": "^22.7.5",
19
20
"autoprefixer": "^10.4.19",
20
21
"postcss": "^8.4.39",
21
22
"prettier": "^3.3.3",
···
64
65
}
65
66
},
66
67
"node_modules/@atcute/client": {
67
-
"version": "2.0.2",
68
-
"resolved": "https://registry.npmjs.org/@atcute/client/-/client-2.0.2.tgz",
69
-
"integrity": "sha512-bTGoo8cs0B0gXLwI8YYaFayjDIlo8V1wxgng3HkA+jyz22wCh8aL0/4F9Tt4GDKXGCgf+/6IHg1M6uGOX8JVSw==",
68
+
"version": "2.0.3",
69
+
"resolved": "https://registry.npmjs.org/@atcute/client/-/client-2.0.3.tgz",
70
+
"integrity": "sha512-j9GryA5l+4F0BTQWa6/1XmsuSPSq+bqNCY3mrHUGD592hMqUZxgpYDLgRWL+719V287AW/56AwvFYlbjlENp7A==",
70
71
"license": "MIT"
71
72
},
72
-
"node_modules/@atproto-labs/did-resolver": {
73
-
"version": "0.1.4",
74
-
"resolved": "https://registry.npmjs.org/@atproto-labs/did-resolver/-/did-resolver-0.1.4.tgz",
75
-
"integrity": "sha512-5d+LHScS2ueYsFRjMOC3c1EwM2ui1yBVbBA0yY3MH7aydbljm5D28scsOVuymIhHwPFwcGvZbMON4PVSfpBbbQ==",
73
+
"node_modules/@atcute/oauth-browser-client": {
74
+
"version": "1.0.1",
75
+
"resolved": "https://registry.npmjs.org/@atcute/oauth-browser-client/-/oauth-browser-client-1.0.1.tgz",
76
+
"integrity": "sha512-vMHf2P+R4tv4qG5cB5YHgOhZf3HNkZhV1DIWXBsRgbfBqoIRWSVTPt2NOunOk0aHtY1NvzU0RTr/j6OnKps/WA==",
76
77
"license": "MIT",
77
78
"dependencies": {
78
-
"@atproto-labs/fetch": "0.1.1",
79
-
"@atproto-labs/pipe": "0.1.0",
80
-
"@atproto-labs/simple-store": "0.1.1",
81
-
"@atproto-labs/simple-store-memory": "0.1.1",
82
-
"@atproto/did": "0.1.2",
83
-
"zod": "^3.23.8"
79
+
"@atcute/client": "^2.0.3",
80
+
"nanoid": "^5.0.7"
84
81
}
85
82
},
86
-
"node_modules/@atproto-labs/fetch": {
87
-
"version": "0.1.1",
88
-
"resolved": "https://registry.npmjs.org/@atproto-labs/fetch/-/fetch-0.1.1.tgz",
89
-
"integrity": "sha512-X1zO1MDoJzEurbWXMAe1H8EZ995Xam/aXdxhGVrXmOMyPDuvBa1oxwh/kQNZRCKcMQUbiwkk+Jfq6ZkTuvGbww==",
83
+
"node_modules/@atcute/oauth-browser-client/node_modules/nanoid": {
84
+
"version": "5.0.7",
85
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz",
86
+
"integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==",
87
+
"funding": [
88
+
{
89
+
"type": "github",
90
+
"url": "https://github.com/sponsors/ai"
91
+
}
92
+
],
90
93
"license": "MIT",
91
-
"dependencies": {
92
-
"@atproto-labs/pipe": "0.1.0"
94
+
"bin": {
95
+
"nanoid": "bin/nanoid.js"
93
96
},
94
-
"optionalDependencies": {
95
-
"zod": "^3.23.8"
96
-
}
97
-
},
98
-
"node_modules/@atproto-labs/handle-resolver": {
99
-
"version": "0.1.3",
100
-
"resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver/-/handle-resolver-0.1.3.tgz",
101
-
"integrity": "sha512-pUn8uqQNqMpecQjO0UWmdKhKX1NnXdLBXHRgID2g4kmhpz3hkbbec+h34uSk6wLfZnwPFaVQnGdEkyMq/tNToQ==",
102
-
"license": "MIT",
103
-
"dependencies": {
104
-
"@atproto-labs/simple-store": "0.1.1",
105
-
"@atproto-labs/simple-store-memory": "0.1.1",
106
-
"@atproto/did": "0.1.2",
107
-
"zod": "^3.23.8"
108
-
}
109
-
},
110
-
"node_modules/@atproto-labs/identity-resolver": {
111
-
"version": "0.1.4",
112
-
"resolved": "https://registry.npmjs.org/@atproto-labs/identity-resolver/-/identity-resolver-0.1.4.tgz",
113
-
"integrity": "sha512-uaRJsYFCRZQcw0c7S+RuziSVm5qHcK3N6uqsXz8NzYoJAE55Ah4DkQMj0rfapZmb0jyBau04RC/WoI4PSim+Aw==",
114
-
"license": "MIT",
115
-
"dependencies": {
116
-
"@atproto-labs/did-resolver": "0.1.4",
117
-
"@atproto-labs/handle-resolver": "0.1.3",
118
-
"@atproto/syntax": "0.3.0"
119
-
}
120
-
},
121
-
"node_modules/@atproto-labs/pipe": {
122
-
"version": "0.1.0",
123
-
"resolved": "https://registry.npmjs.org/@atproto-labs/pipe/-/pipe-0.1.0.tgz",
124
-
"integrity": "sha512-ghOqHFyJlQVFPESzlVHjKroP0tPzbmG5Jms0dNI9yLDEfL8xp4OFPWLX4f6T8mRq69wWs4nIDM3sSsFbFqLa1w==",
125
-
"license": "MIT"
126
-
},
127
-
"node_modules/@atproto-labs/simple-store": {
128
-
"version": "0.1.1",
129
-
"resolved": "https://registry.npmjs.org/@atproto-labs/simple-store/-/simple-store-0.1.1.tgz",
130
-
"integrity": "sha512-WKILW2b3QbAYKh+w5U2x6p5FqqLl0nAeLwGeDY+KjX01K4Dq3vQTR9b/qNp0jZm48CabPQVrqCv0PPU9LgRRRg==",
131
-
"license": "MIT"
132
-
},
133
-
"node_modules/@atproto-labs/simple-store-memory": {
134
-
"version": "0.1.1",
135
-
"resolved": "https://registry.npmjs.org/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.1.tgz",
136
-
"integrity": "sha512-PCRqhnZ8NBNBvLku53O56T0lsVOtclfIrQU/rwLCc4+p45/SBPrRYNBi6YFq5rxZbK6Njos9MCmILV/KLQxrWA==",
137
-
"license": "MIT",
138
-
"dependencies": {
139
-
"@atproto-labs/simple-store": "0.1.1",
140
-
"lru-cache": "^10.2.0"
141
-
}
142
-
},
143
-
"node_modules/@atproto/common-web": {
144
-
"version": "0.3.1",
145
-
"resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.3.1.tgz",
146
-
"integrity": "sha512-N7wiTnus5vAr+lT//0y8m/FaHHLJ9LpGuEwkwDAeV3LCiPif4m/FS8x/QOYrx1PdZQwKso95RAPzCGWQBH5j6Q==",
147
-
"license": "MIT",
148
-
"dependencies": {
149
-
"graphemer": "^1.4.0",
150
-
"multiformats": "^9.9.0",
151
-
"uint8arrays": "3.0.0",
152
-
"zod": "^3.23.8"
153
-
}
154
-
},
155
-
"node_modules/@atproto/did": {
156
-
"version": "0.1.2",
157
-
"resolved": "https://registry.npmjs.org/@atproto/did/-/did-0.1.2.tgz",
158
-
"integrity": "sha512-gmY1SyAuqfmsFbIXkUIScfnULqn39FoUNz4oE0fUuMu9in6PEyoxlmD2lAo7Q3KMy3X/hvTn2u5f8W/2KuDg1w==",
159
-
"license": "MIT",
160
-
"dependencies": {
161
-
"zod": "^3.23.8"
162
-
}
163
-
},
164
-
"node_modules/@atproto/jwk": {
165
-
"version": "0.1.1",
166
-
"resolved": "https://registry.npmjs.org/@atproto/jwk/-/jwk-0.1.1.tgz",
167
-
"integrity": "sha512-6h/bj1APUk7QcV9t/oA6+9DB5NZx9SZru9x+/pV5oHFI9Xz4ZuM5+dq1PfsJV54pZyqdnZ6W6M717cxoC7q7og==",
168
-
"license": "MIT",
169
-
"dependencies": {
170
-
"multiformats": "^9.9.0",
171
-
"zod": "^3.23.8"
172
-
}
173
-
},
174
-
"node_modules/@atproto/jwk-jose": {
175
-
"version": "0.1.2",
176
-
"resolved": "https://registry.npmjs.org/@atproto/jwk-jose/-/jwk-jose-0.1.2.tgz",
177
-
"integrity": "sha512-lDwc/6lLn2aZ/JpyyggyjLFsJPMntrVzryyGUx5aNpuTS8SIuc4Ky0REhxqfLopQXJJZCuRRjagHG3uP05/moQ==",
178
-
"license": "MIT",
179
-
"dependencies": {
180
-
"@atproto/jwk": "0.1.1",
181
-
"jose": "^5.2.0"
182
-
}
183
-
},
184
-
"node_modules/@atproto/jwk-webcrypto": {
185
-
"version": "0.1.2",
186
-
"resolved": "https://registry.npmjs.org/@atproto/jwk-webcrypto/-/jwk-webcrypto-0.1.2.tgz",
187
-
"integrity": "sha512-vTBUbUZXh0GI+6KJiPGukmI4BQEHFAij8fJJ4WnReF/hefAs3ISZtrWZHGBebz+q2EcExYlnhhlmxvDzV7veGw==",
188
-
"license": "MIT",
189
-
"dependencies": {
190
-
"@atproto/jwk": "0.1.1",
191
-
"@atproto/jwk-jose": "0.1.2"
192
-
}
193
-
},
194
-
"node_modules/@atproto/lexicon": {
195
-
"version": "0.4.2",
196
-
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.2.tgz",
197
-
"integrity": "sha512-CXoOkhcdF3XVUnR2oNgCs2ljWfo/8zUjxL5RIhJW/UNLp/FSl+KpF8Jm5fbk8Y/XXVPGRAsv9OYfxyU/14N/pw==",
198
-
"license": "MIT",
199
-
"dependencies": {
200
-
"@atproto/common-web": "^0.3.1",
201
-
"@atproto/syntax": "^0.3.0",
202
-
"iso-datestring-validator": "^2.2.2",
203
-
"multiformats": "^9.9.0",
204
-
"zod": "^3.23.8"
205
-
}
206
-
},
207
-
"node_modules/@atproto/oauth-client": {
208
-
"version": "0.2.2",
209
-
"resolved": "https://registry.npmjs.org/@atproto/oauth-client/-/oauth-client-0.2.2.tgz",
210
-
"integrity": "sha512-hYL7Hx2h52zeC1WZeFjV9FFfqt8PZnURKofz0VJVeiPqB9wySJ46MgFVxsZ3t08c03WSDugujEz2JlhtQpS7Zg==",
211
-
"license": "MIT",
212
-
"dependencies": {
213
-
"@atproto-labs/did-resolver": "0.1.4",
214
-
"@atproto-labs/fetch": "0.1.1",
215
-
"@atproto-labs/handle-resolver": "0.1.3",
216
-
"@atproto-labs/identity-resolver": "0.1.4",
217
-
"@atproto-labs/simple-store": "0.1.1",
218
-
"@atproto-labs/simple-store-memory": "0.1.1",
219
-
"@atproto/did": "0.1.2",
220
-
"@atproto/jwk": "0.1.1",
221
-
"@atproto/oauth-types": "0.1.5",
222
-
"@atproto/xrpc": "0.6.3",
223
-
"multiformats": "^9.9.0",
224
-
"zod": "^3.23.8"
225
-
}
226
-
},
227
-
"node_modules/@atproto/oauth-client-browser": {
228
-
"version": "0.2.2",
229
-
"resolved": "https://registry.npmjs.org/@atproto/oauth-client-browser/-/oauth-client-browser-0.2.2.tgz",
230
-
"integrity": "sha512-Y36LTqNMq2iqWrdGJljD5yqWDy9CbhHElxI5syiPCcgLCm9/UU8Hu5QTgCrESDzAyV5viYWDweeqAmLrpVrpQg==",
231
-
"license": "MIT",
232
-
"dependencies": {
233
-
"@atproto-labs/did-resolver": "0.1.4",
234
-
"@atproto-labs/handle-resolver": "0.1.3",
235
-
"@atproto-labs/simple-store": "0.1.1",
236
-
"@atproto/did": "0.1.2",
237
-
"@atproto/jwk": "0.1.1",
238
-
"@atproto/jwk-webcrypto": "0.1.2",
239
-
"@atproto/oauth-client": "0.2.2",
240
-
"@atproto/oauth-types": "0.1.5"
241
-
}
242
-
},
243
-
"node_modules/@atproto/oauth-types": {
244
-
"version": "0.1.5",
245
-
"resolved": "https://registry.npmjs.org/@atproto/oauth-types/-/oauth-types-0.1.5.tgz",
246
-
"integrity": "sha512-vNab/6BYUQCfmfhGc3G61EcatQxvh2d41FDWqR8CAYsblNXO6nOEVXn7cXdQUkb3K49LU0vy5Jf1+wFNcpY3IQ==",
247
-
"license": "MIT",
248
-
"dependencies": {
249
-
"@atproto/jwk": "0.1.1",
250
-
"zod": "^3.23.8"
251
-
}
252
-
},
253
-
"node_modules/@atproto/syntax": {
254
-
"version": "0.3.0",
255
-
"resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.3.0.tgz",
256
-
"integrity": "sha512-Weq0ZBxffGHDXHl9U7BQc2BFJi/e23AL+k+i5+D9hUq/bzT4yjGsrCejkjq0xt82xXDjmhhvQSZ0LqxyZ5woxA==",
257
-
"license": "MIT"
258
-
},
259
-
"node_modules/@atproto/xrpc": {
260
-
"version": "0.6.3",
261
-
"resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.6.3.tgz",
262
-
"integrity": "sha512-S3tRvOdA9amPkKLll3rc4vphlDitLrkN5TwWh5Tu/jzk7mnobVVE3akYgICV9XCNHKjWM+IAPxFFI2qi+VW6nQ==",
263
-
"license": "MIT",
264
-
"dependencies": {
265
-
"@atproto/lexicon": "^0.4.2",
266
-
"zod": "^3.23.8"
97
+
"engines": {
98
+
"node": "^18 || >=20"
267
99
}
268
100
},
269
101
"node_modules/@babel/code-frame": {
···
1661
1493
"dev": true,
1662
1494
"license": "MIT"
1663
1495
},
1496
+
"node_modules/@types/node": {
1497
+
"version": "22.7.5",
1498
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
1499
+
"integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
1500
+
"dev": true,
1501
+
"license": "MIT",
1502
+
"dependencies": {
1503
+
"undici-types": "~6.19.2"
1504
+
}
1505
+
},
1664
1506
"node_modules/agent-base": {
1665
1507
"version": "7.1.1",
1666
1508
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
···
2416
2258
"node": ">=4"
2417
2259
}
2418
2260
},
2419
-
"node_modules/graphemer": {
2420
-
"version": "1.4.0",
2421
-
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
2422
-
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
2423
-
"license": "MIT"
2424
-
},
2425
2261
"node_modules/has-flag": {
2426
2262
"version": "3.0.0",
2427
2263
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
···
2605
2441
"dev": true,
2606
2442
"license": "ISC"
2607
2443
},
2608
-
"node_modules/iso-datestring-validator": {
2609
-
"version": "2.2.2",
2610
-
"resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz",
2611
-
"integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==",
2612
-
"license": "MIT"
2613
-
},
2614
2444
"node_modules/jackspeak": {
2615
2445
"version": "3.4.3",
2616
2446
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
···
2739
2569
"jiti": "bin/jiti.js"
2740
2570
}
2741
2571
},
2742
-
"node_modules/jose": {
2743
-
"version": "5.9.3",
2744
-
"resolved": "https://registry.npmjs.org/jose/-/jose-5.9.3.tgz",
2745
-
"integrity": "sha512-egLIoYSpcd+QUF+UHgobt5YzI2Pkw/H39ou9suW687MY6PmCwPmkNV/4TNjn1p2tX5xO3j0d0sq5hiYE24bSlg==",
2746
-
"license": "MIT",
2747
-
"funding": {
2748
-
"url": "https://github.com/sponsors/panva"
2749
-
}
2750
-
},
2751
2572
"node_modules/js-tokens": {
2752
2573
"version": "4.0.0",
2753
2574
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
···
2843
2664
"version": "10.4.3",
2844
2665
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
2845
2666
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
2667
+
"dev": true,
2846
2668
"license": "ISC"
2847
2669
},
2848
2670
"node_modules/merge-anything": {
···
2950
2772
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
2951
2773
"dev": true,
2952
2774
"license": "MIT"
2953
-
},
2954
-
"node_modules/multiformats": {
2955
-
"version": "9.9.0",
2956
-
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
2957
-
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
2958
-
"license": "(Apache-2.0 AND MIT)"
2959
2775
},
2960
2776
"node_modules/mz": {
2961
2777
"version": "2.7.0",
···
4040
3856
"node": ">=14.17"
4041
3857
}
4042
3858
},
4043
-
"node_modules/uint8arrays": {
4044
-
"version": "3.0.0",
4045
-
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz",
4046
-
"integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==",
4047
-
"license": "MIT",
4048
-
"dependencies": {
4049
-
"multiformats": "^9.4.2"
4050
-
}
3859
+
"node_modules/undici-types": {
3860
+
"version": "6.19.8",
3861
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
3862
+
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
3863
+
"dev": true,
3864
+
"license": "MIT"
4051
3865
},
4052
3866
"node_modules/update-browserslist-db": {
4053
3867
"version": "1.1.1",
···
4458
4272
},
4459
4273
"engines": {
4460
4274
"node": ">= 14"
4461
-
}
4462
-
},
4463
-
"node_modules/zod": {
4464
-
"version": "3.23.8",
4465
-
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
4466
-
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
4467
-
"license": "MIT",
4468
-
"funding": {
4469
-
"url": "https://github.com/sponsors/colinhacks"
4470
4275
}
4471
4276
}
4472
4277
}
+2
-1
package.json
+2
-1
package.json
···
12
12
"license": "0BSD",
13
13
"devDependencies": {
14
14
"@tailwindcss/forms": "^0.5.7",
15
+
"@types/node": "^22.7.5",
15
16
"autoprefixer": "^10.4.19",
16
17
"postcss": "^8.4.39",
17
18
"prettier": "^3.3.3",
···
25
26
"dependencies": {
26
27
"@atcute/bluesky": "^1.0.7",
27
28
"@atcute/client": "^2.0.2",
28
-
"@atproto/oauth-client-browser": "^0.2.0",
29
+
"@atcute/oauth-browser-client": "^1.0.1",
29
30
"solid-js": "^1.8.11"
30
31
}
31
32
}
+72
-34
src/App.tsx
+72
-34
src/App.tsx
···
1
1
import {
2
+
createEffect,
2
3
createSignal,
3
-
onMount,
4
4
For,
5
+
onMount,
5
6
Show,
6
7
type Component,
7
-
createEffect,
8
8
} from "solid-js";
9
9
import { createStore } from "solid-js/store";
10
10
11
-
import {
12
-
BrowserOAuthClient,
13
-
OAuthSession,
14
-
} from "@atproto/oauth-client-browser";
15
-
import "@atcute/bluesky/lexicons";
16
11
import { XRPC } from "@atcute/client";
17
12
import {
18
13
AppBskyGraphFollow,
19
-
ComAtprotoRepoListRecords,
14
+
At,
15
+
Brand,
20
16
ComAtprotoRepoApplyWrites,
21
-
Brand,
17
+
ComAtprotoRepoListRecords,
22
18
} from "@atcute/client/lexicons";
19
+
import {
20
+
configureOAuth,
21
+
createAuthorizationUrl,
22
+
finalizeAuthorization,
23
+
getSession,
24
+
OAuthUserAgent,
25
+
resolveFromIdentity,
26
+
type Session,
27
+
} from "@atcute/oauth-browser-client";
28
+
29
+
configureOAuth({
30
+
metadata: {
31
+
client_id: import.meta.env.VITE_OAUTH_CLIENT_ID,
32
+
redirect_uri: import.meta.env.VITE_OAUTH_REDIRECT_URL,
33
+
},
34
+
});
23
35
24
36
enum RepoStatus {
25
37
BLOCKEDBY = 1 << 0,
···
44
56
const [followRecords, setFollowRecords] = createStore<FollowRecord[]>([]);
45
57
const [loginState, setLoginState] = createSignal(false);
46
58
let rpc: XRPC;
47
-
let session: OAuthSession;
59
+
let agent: OAuthUserAgent;
48
60
49
61
const resolveDid = async (did: string) => {
50
62
const res = await fetch(
···
66
78
const [loginInput, setLoginInput] = createSignal("");
67
79
const [handle, setHandle] = createSignal("");
68
80
const [notice, setNotice] = createSignal("");
69
-
let client: BrowserOAuthClient;
70
81
71
82
onMount(async () => {
72
83
setNotice("Loading...");
73
-
client = await BrowserOAuthClient.load({
74
-
clientId: "https://cleanfollow-bsky.pages.dev/client-metadata.json",
75
-
handleResolver: "https://boletus.us-west.host.bsky.network",
76
-
});
77
84
78
-
client.addEventListener("deleted", () => {
79
-
setLoginState(false);
80
-
});
81
-
const result = await client.init().catch(() => {});
85
+
const init = async (): Promise<Session | undefined> => {
86
+
const params = new URLSearchParams(location.hash.slice(1));
87
+
88
+
if (params.has("state") && (params.has("code") || params.has("error"))) {
89
+
history.replaceState(null, "", location.pathname + location.search);
82
90
83
-
if (result) {
84
-
session = result.session;
85
-
rpc = new XRPC({
86
-
handler: { handle: session.fetchHandler.bind(session) },
87
-
});
91
+
const session = await finalizeAuthorization(params);
92
+
const did = session.info.sub;
93
+
94
+
localStorage.setItem("lastSignedIn", did);
95
+
return session;
96
+
} else {
97
+
const lastSignedIn = localStorage.getItem("lastSignedIn");
98
+
99
+
if (lastSignedIn) {
100
+
try {
101
+
const session = await getSession(lastSignedIn as At.DID);
102
+
return session;
103
+
} catch (err) {
104
+
localStorage.removeItem("lastSignedIn");
105
+
throw err;
106
+
}
107
+
}
108
+
}
109
+
};
110
+
111
+
const session = await init().catch(() => {});
112
+
113
+
if (session) {
114
+
agent = new OAuthUserAgent(session);
115
+
rpc = new XRPC({ handler: agent });
116
+
88
117
setLoginState(true);
89
-
setHandle(await resolveDid(session.did));
118
+
setHandle(await resolveDid(agent.sub));
90
119
}
120
+
91
121
setNotice("");
92
122
});
93
123
94
124
const loginBsky = async (handle: string) => {
95
-
setNotice("Redirecting...");
96
125
try {
97
-
await client.signIn(handle, {
98
-
scope: "atproto transition:generic",
99
-
signal: new AbortController().signal,
126
+
setNotice(`Resolving your identity...`);
127
+
const resolved = await resolveFromIdentity(handle);
128
+
129
+
setNotice(`Contacting your data server...`);
130
+
const authUrl = await createAuthorizationUrl({
131
+
scope: import.meta.env.VITE_OAUTH_SCOPE,
132
+
...resolved,
100
133
});
134
+
135
+
setNotice(`Redirecting...`);
136
+
await new Promise((resolve) => setTimeout(resolve, 250));
137
+
138
+
location.assign(authUrl);
101
139
} catch (err) {
102
-
setNotice("Error during OAuth redirection");
140
+
setNotice("Error during OAuth login");
103
141
}
104
142
};
105
143
106
144
const logoutBsky = async () => {
107
-
if (session.sub) await client.revoke(session.sub);
145
+
await agent.signOut();
108
146
};
109
147
110
148
return (
···
157
195
const fetchPage = async (cursor?: string) => {
158
196
return await rpc.get("com.atproto.repo.listRecords", {
159
197
params: {
160
-
repo: session.did,
198
+
repo: agent.sub,
161
199
collection: "app.bsky.graph.follow",
162
200
limit: PAGE_LIMIT,
163
201
cursor: cursor,
···
203
241
viewer.blocking || viewer.blockingByList ?
204
242
RepoStatus.BLOCKEDBY | RepoStatus.BLOCKING
205
243
: RepoStatus.BLOCKEDBY;
206
-
} else if (res.data.did.includes(session.did)) {
244
+
} else if (res.data.did.includes(agent.sub)) {
207
245
status = RepoStatus.YOURSELF;
208
246
} else if (viewer.blocking || viewer.blockingByList) {
209
247
status = RepoStatus.BLOCKING;
···
260
298
for (let i = 0; i < writes.length; i += BATCHSIZE) {
261
299
await rpc.call("com.atproto.repo.applyWrites", {
262
300
data: {
263
-
repo: session.did,
301
+
repo: agent.sub,
264
302
writes: writes.slice(i, i + BATCHSIZE),
265
303
},
266
304
});
+14
src/vite-env.d.ts
+14
src/vite-env.d.ts
···
1
+
/// <reference types="vite/client" />
2
+
/// <reference types="@atcute/bluesky/lexicons" />
3
+
4
+
interface ImportMetaEnv {
5
+
readonly VITE_DEV_SERVER_PORT?: string;
6
+
readonly VITE_CLIENT_URI: string;
7
+
readonly VITE_OAUTH_CLIENT_ID: string;
8
+
readonly VITE_OAUTH_REDIRECT_URL: string;
9
+
readonly VITE_OAUTH_SCOPE: string;
10
+
}
11
+
12
+
interface ImportMeta {
13
+
readonly env: ImportMetaEnv;
14
+
}
+26
tsconfig.app.json
+26
tsconfig.app.json
···
1
+
{
2
+
"compilerOptions": {
3
+
"target": "ESNext",
4
+
"useDefineForClassFields": true,
5
+
"module": "ESNext",
6
+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
7
+
"types": [],
8
+
"skipLibCheck": true,
9
+
10
+
/* Bundler mode */
11
+
"moduleResolution": "bundler",
12
+
"allowImportingTsExtensions": true,
13
+
"isolatedModules": true,
14
+
"moduleDetection": "force",
15
+
"noEmit": true,
16
+
"jsx": "preserve",
17
+
"jsxImportSource": "solid-js",
18
+
19
+
/* Linting */
20
+
"strict": true,
21
+
"noUnusedLocals": true,
22
+
"noUnusedParameters": true,
23
+
"noFallthroughCasesInSwitch": true
24
+
},
25
+
"include": ["src"]
26
+
}
+6
-16
tsconfig.json
+6
-16
tsconfig.json
···
1
1
{
2
-
"compilerOptions": {
3
-
"strict": true,
4
-
"target": "ESNext",
5
-
"module": "nodenext",
6
-
"moduleResolution": "nodenext",
7
-
"allowSyntheticDefaultImports": true,
8
-
"esModuleInterop": true,
9
-
"jsx": "preserve",
10
-
"jsxImportSource": "solid-js",
11
-
"types": [
12
-
"vite/client"
13
-
],
14
-
"noEmit": true,
15
-
"isolatedModules": true
16
-
}
17
-
}
2
+
"files": [],
3
+
"references": [
4
+
{ "path": "./tsconfig.app.json" },
5
+
{ "path": "./tsconfig.node.json" }
6
+
]
7
+
}
+23
tsconfig.node.json
+23
tsconfig.node.json
···
1
+
{
2
+
"compilerOptions": {
3
+
"target": "ESNext",
4
+
"lib": ["ESNext"],
5
+
"types": ["node"],
6
+
"module": "ESNext",
7
+
"skipLibCheck": true,
8
+
9
+
/* Bundler mode */
10
+
"moduleResolution": "bundler",
11
+
"allowImportingTsExtensions": true,
12
+
"isolatedModules": true,
13
+
"moduleDetection": "force",
14
+
"noEmit": true,
15
+
16
+
/* Linting */
17
+
"strict": true,
18
+
"noUnusedLocals": true,
19
+
"noUnusedParameters": true,
20
+
"noFallthroughCasesInSwitch": true
21
+
},
22
+
"include": ["vite.config.ts"]
23
+
}
+35
-2
vite.config.ts
+35
-2
vite.config.ts
···
2
2
import solidPlugin from "vite-plugin-solid";
3
3
// import devtools from 'solid-devtools/vite';
4
4
5
+
import metadata from "./public/client-metadata.json";
6
+
7
+
const SERVER_HOST = "127.0.0.1";
8
+
const SERVER_PORT = 13213;
9
+
5
10
export default defineConfig({
6
11
plugins: [
7
12
/*
···
10
15
*/
11
16
// devtools(),
12
17
solidPlugin(),
18
+
19
+
// Injects OAuth-related variables
20
+
{
21
+
name: "oauth",
22
+
config(_conf, { command }) {
23
+
if (command === "build") {
24
+
process.env.VITE_OAUTH_CLIENT_ID = metadata.client_id;
25
+
process.env.VITE_OAUTH_REDIRECT_URL = metadata.redirect_uris[0];
26
+
} else {
27
+
const redirectUri = ((): string => {
28
+
const url = new URL(metadata.redirect_uris[0]);
29
+
return `http://${SERVER_HOST}:${SERVER_PORT}${url.pathname}`;
30
+
})();
31
+
32
+
const clientId =
33
+
`http://localhost` +
34
+
`?redirect_uri=${encodeURIComponent(redirectUri)}` +
35
+
`&scope=${encodeURIComponent(metadata.scope)}`;
36
+
37
+
process.env.VITE_DEV_SERVER_PORT = "" + SERVER_PORT;
38
+
process.env.VITE_OAUTH_CLIENT_ID = clientId;
39
+
process.env.VITE_OAUTH_REDIRECT_URL = redirectUri;
40
+
}
41
+
42
+
process.env.VITE_CLIENT_URI = metadata.client_uri;
43
+
process.env.VITE_OAUTH_SCOPE = metadata.scope;
44
+
},
45
+
},
13
46
],
14
47
server: {
15
-
host: "127.0.0.1",
16
-
port: 3000,
48
+
host: SERVER_HOST,
49
+
port: SERVER_PORT,
17
50
},
18
51
build: {
19
52
target: "esnext",