feat: create atproto oauth login
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
"generate-pwa-assets": "pwa-assets-generator"
|
"generate-pwa-assets": "pwa-assets-generator"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@atproto/oauth-client-browser": "^0.3.41",
|
||||||
"@better-fetch/fetch": "^1.1.21",
|
"@better-fetch/fetch": "^1.1.21",
|
||||||
"@better-fetch/logger": "^1.1.21",
|
"@better-fetch/logger": "^1.1.21",
|
||||||
"@intlify/unplugin-vue-i18n": "^6.0.8",
|
"@intlify/unplugin-vue-i18n": "^6.0.8",
|
||||||
|
|||||||
234
pnpm-lock.yaml
generated
234
pnpm-lock.yaml
generated
@@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@atproto/oauth-client-browser':
|
||||||
|
specifier: ^0.3.41
|
||||||
|
version: 0.3.41
|
||||||
'@better-fetch/fetch':
|
'@better-fetch/fetch':
|
||||||
specifier: ^1.1.21
|
specifier: ^1.1.21
|
||||||
version: 1.1.21
|
version: 1.1.21
|
||||||
@@ -254,6 +257,66 @@ packages:
|
|||||||
'@ark/util@0.56.0':
|
'@ark/util@0.56.0':
|
||||||
resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==}
|
resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==}
|
||||||
|
|
||||||
|
'@atproto-labs/did-resolver@0.2.6':
|
||||||
|
resolution: {integrity: sha512-2K1bC04nI2fmgNcvof+yA28IhGlpWn2JKYlPa7To9JTKI45FINCGkQSGiL2nyXlyzDJJ34fZ1aq6/IRFIOIiqg==}
|
||||||
|
|
||||||
|
'@atproto-labs/fetch@0.2.3':
|
||||||
|
resolution: {integrity: sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw==}
|
||||||
|
|
||||||
|
'@atproto-labs/handle-resolver@0.3.6':
|
||||||
|
resolution: {integrity: sha512-qnSTXvOBNj1EHhp2qTWSX8MS5q3AwYU5LKlt5fBvSbCjgmTr2j0URHCv+ydrwO55KvsojIkTMgeMOh4YuY4fCA==}
|
||||||
|
|
||||||
|
'@atproto-labs/identity-resolver@0.3.6':
|
||||||
|
resolution: {integrity: sha512-qoWqBDRobln0NR8L8dQjSp79E0chGkBhibEgxQa2f9WD+JbJdjQ0YvwwO5yeQn05pJoJmAwmI2wyJ45zjU7aWg==}
|
||||||
|
|
||||||
|
'@atproto-labs/pipe@0.1.1':
|
||||||
|
resolution: {integrity: sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg==}
|
||||||
|
|
||||||
|
'@atproto-labs/simple-store-memory@0.1.4':
|
||||||
|
resolution: {integrity: sha512-3mKY4dP8I7yKPFj9VKpYyCRzGJOi5CEpOLPlRhoJyLmgs3J4RzDrjn323Oakjz2Aj2JzRU/AIvWRAZVhpYNJHw==}
|
||||||
|
|
||||||
|
'@atproto-labs/simple-store@0.3.0':
|
||||||
|
resolution: {integrity: sha512-nOb6ONKBRJHRlukW1sVawUkBqReLlLx6hT35VS3imaNPwiXDxLnTK7lxw3Lrl9k5yugSBDQAkZAq3MPTEFSUBQ==}
|
||||||
|
|
||||||
|
'@atproto/common-web@0.4.18':
|
||||||
|
resolution: {integrity: sha512-ilImzP+9N/mtse440kN60pGrEzG7wi4xsV13nGeLrS+Zocybc/ISOpKlbZM13o+twPJ+Q7veGLw9CtGg0GAFoQ==}
|
||||||
|
|
||||||
|
'@atproto/did@0.3.0':
|
||||||
|
resolution: {integrity: sha512-raUPzUGegtW/6OxwCmM8bhZvuIMzxG5t9oWsth6Tp91Kb5fTnHV2h/KKNF1C82doeA4BdXCErTyg7ISwLbQkzA==}
|
||||||
|
|
||||||
|
'@atproto/jwk-jose@0.1.11':
|
||||||
|
resolution: {integrity: sha512-i4Fnr2sTBYmMmHXl7NJh8GrCH+tDQEVWrcDMDnV5DjJfkgT17wIqvojIw9SNbSL4Uf0OtfEv6AgG0A+mgh8b5Q==}
|
||||||
|
|
||||||
|
'@atproto/jwk-webcrypto@0.2.0':
|
||||||
|
resolution: {integrity: sha512-UmgRrrEAkWvxwhlwe30UmDOdTEFidlIzBC7C3cCbeJMcBN1x8B3KH+crXrsTqfWQBG58mXgt8wgSK3Kxs2LhFg==}
|
||||||
|
|
||||||
|
'@atproto/jwk@0.6.0':
|
||||||
|
resolution: {integrity: sha512-bDoJPvt7TrQVi/rBfBrSSpGykhtIriKxeYCYQTiPRKFfyRhbgpElF0wPXADjIswnbzZdOwbY63az4E/CFVT3Tw==}
|
||||||
|
|
||||||
|
'@atproto/lex-data@0.0.13':
|
||||||
|
resolution: {integrity: sha512-7Z7RwZ1Y/JzBF/Tcn/I4UJ/vIGfh5zn1zjv0KX+flke2JtgFkSE8uh2hOtqgBQMNqE3zdJFM+dcSWln86hR3MQ==}
|
||||||
|
|
||||||
|
'@atproto/lex-json@0.0.13':
|
||||||
|
resolution: {integrity: sha512-hwLhkKaIHulGJpt0EfXAEWdrxqM2L1tV/tvilzhMp3QxPqYgXchFnrfVmLsyFDx6P6qkH1GsX/XC2V36U0UlPQ==}
|
||||||
|
|
||||||
|
'@atproto/lexicon@0.6.2':
|
||||||
|
resolution: {integrity: sha512-p3Ly6hinVZW0ETuAXZMeUGwuMm3g8HvQMQ41yyEE6AL0hAkfeKFaZKos6BdBrr6CjkpbrDZqE8M+5+QOceysMw==}
|
||||||
|
|
||||||
|
'@atproto/oauth-client-browser@0.3.41':
|
||||||
|
resolution: {integrity: sha512-4QTm8zPgm08vl53flrVmL+MS5IOhvWWctNZmEnPbvQ2t1ISw9Q5m815m2Sszi5ULMFjOqvT7lhKB7zQUn5gq5g==}
|
||||||
|
|
||||||
|
'@atproto/oauth-client@0.6.0':
|
||||||
|
resolution: {integrity: sha512-F7ZTKzFptXgyihMkd7QTdRSkrh4XqrS+qTw+V81k5Q6Bh3MB1L3ypvfSJ6v7SSUJa6XxoZYJTCahHC1e+ndE6Q==}
|
||||||
|
|
||||||
|
'@atproto/oauth-types@0.6.3':
|
||||||
|
resolution: {integrity: sha512-jdKuoPknJuh/WjI+mYk7agSbx9mNVMbS6Dr3k1z2YMY2oRiCQjxYBuo4MLKATbxj05nMQaZRWlHRUazoAu5Cng==}
|
||||||
|
|
||||||
|
'@atproto/syntax@0.5.0':
|
||||||
|
resolution: {integrity: sha512-UA2DSpGdOQzUQ4gi5SH+NEJz/YR3a3Fg3y2oh+xETDSiTRmA4VhHRCojhXAVsBxUT6EnItw190C/KN+DWW90kw==}
|
||||||
|
|
||||||
|
'@atproto/xrpc@0.7.7':
|
||||||
|
resolution: {integrity: sha512-K1ZyO/BU8JNtXX5dmPp7b5UrkLMMqpsIa/Lrj5D3Su+j1Xwq1m6QJ2XJ1AgjEjkI1v4Muzm7klianLE6XGxtmA==}
|
||||||
|
|
||||||
'@babel/code-frame@7.27.1':
|
'@babel/code-frame@7.27.1':
|
||||||
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
|
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -2653,6 +2716,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==}
|
resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==}
|
||||||
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||||
|
|
||||||
|
core-js@3.48.0:
|
||||||
|
resolution: {integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==}
|
||||||
|
|
||||||
core-util-is@1.0.2:
|
core-util-is@1.0.2:
|
||||||
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
|
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
|
||||||
|
|
||||||
@@ -4000,6 +4066,9 @@ packages:
|
|||||||
isexe@2.0.0:
|
isexe@2.0.0:
|
||||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||||
|
|
||||||
|
iso-datestring-validator@2.2.2:
|
||||||
|
resolution: {integrity: sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==}
|
||||||
|
|
||||||
isobject@2.1.0:
|
isobject@2.1.0:
|
||||||
resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
|
resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -4119,6 +4188,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
|
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
jose@5.10.0:
|
||||||
|
resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==}
|
||||||
|
|
||||||
js-tokens@3.0.2:
|
js-tokens@3.0.2:
|
||||||
resolution: {integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==}
|
resolution: {integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==}
|
||||||
|
|
||||||
@@ -4380,6 +4452,9 @@ packages:
|
|||||||
loupe@3.2.0:
|
loupe@3.2.0:
|
||||||
resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==}
|
resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==}
|
||||||
|
|
||||||
|
lru-cache@10.4.3:
|
||||||
|
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||||
|
|
||||||
lru-cache@4.1.5:
|
lru-cache@4.1.5:
|
||||||
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
|
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
|
||||||
|
|
||||||
@@ -4530,6 +4605,9 @@ packages:
|
|||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
|
multiformats@9.9.0:
|
||||||
|
resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==}
|
||||||
|
|
||||||
nan@2.25.0:
|
nan@2.25.0:
|
||||||
resolution: {integrity: sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==}
|
resolution: {integrity: sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==}
|
||||||
|
|
||||||
@@ -5612,6 +5690,9 @@ packages:
|
|||||||
tslib@2.6.1:
|
tslib@2.6.1:
|
||||||
resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==}
|
resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==}
|
||||||
|
|
||||||
|
tslib@2.8.1:
|
||||||
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
tsx@4.20.3:
|
tsx@4.20.3:
|
||||||
resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==}
|
resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
@@ -5678,6 +5759,9 @@ packages:
|
|||||||
engines: {node: '>=0.8.0'}
|
engines: {node: '>=0.8.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
uint8arrays@3.0.0:
|
||||||
|
resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==}
|
||||||
|
|
||||||
unbox-primitive@1.1.0:
|
unbox-primitive@1.1.0:
|
||||||
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -5710,6 +5794,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==}
|
resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
unicode-segmenter@0.14.5:
|
||||||
|
resolution: {integrity: sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==}
|
||||||
|
|
||||||
union-value@1.0.1:
|
union-value@1.0.1:
|
||||||
resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
|
resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -6104,6 +6191,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
zod@3.25.76:
|
||||||
|
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@aashutoshrathi/word-wrap@1.2.6': {}
|
'@aashutoshrathi/word-wrap@1.2.6': {}
|
||||||
@@ -6130,6 +6220,130 @@ snapshots:
|
|||||||
|
|
||||||
'@ark/util@0.56.0': {}
|
'@ark/util@0.56.0': {}
|
||||||
|
|
||||||
|
'@atproto-labs/did-resolver@0.2.6':
|
||||||
|
dependencies:
|
||||||
|
'@atproto-labs/fetch': 0.2.3
|
||||||
|
'@atproto-labs/pipe': 0.1.1
|
||||||
|
'@atproto-labs/simple-store': 0.3.0
|
||||||
|
'@atproto-labs/simple-store-memory': 0.1.4
|
||||||
|
'@atproto/did': 0.3.0
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
|
'@atproto-labs/fetch@0.2.3':
|
||||||
|
dependencies:
|
||||||
|
'@atproto-labs/pipe': 0.1.1
|
||||||
|
|
||||||
|
'@atproto-labs/handle-resolver@0.3.6':
|
||||||
|
dependencies:
|
||||||
|
'@atproto-labs/simple-store': 0.3.0
|
||||||
|
'@atproto-labs/simple-store-memory': 0.1.4
|
||||||
|
'@atproto/did': 0.3.0
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
|
'@atproto-labs/identity-resolver@0.3.6':
|
||||||
|
dependencies:
|
||||||
|
'@atproto-labs/did-resolver': 0.2.6
|
||||||
|
'@atproto-labs/handle-resolver': 0.3.6
|
||||||
|
|
||||||
|
'@atproto-labs/pipe@0.1.1': {}
|
||||||
|
|
||||||
|
'@atproto-labs/simple-store-memory@0.1.4':
|
||||||
|
dependencies:
|
||||||
|
'@atproto-labs/simple-store': 0.3.0
|
||||||
|
lru-cache: 10.4.3
|
||||||
|
|
||||||
|
'@atproto-labs/simple-store@0.3.0': {}
|
||||||
|
|
||||||
|
'@atproto/common-web@0.4.18':
|
||||||
|
dependencies:
|
||||||
|
'@atproto/lex-data': 0.0.13
|
||||||
|
'@atproto/lex-json': 0.0.13
|
||||||
|
'@atproto/syntax': 0.5.0
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
|
'@atproto/did@0.3.0':
|
||||||
|
dependencies:
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
|
'@atproto/jwk-jose@0.1.11':
|
||||||
|
dependencies:
|
||||||
|
'@atproto/jwk': 0.6.0
|
||||||
|
jose: 5.10.0
|
||||||
|
|
||||||
|
'@atproto/jwk-webcrypto@0.2.0':
|
||||||
|
dependencies:
|
||||||
|
'@atproto/jwk': 0.6.0
|
||||||
|
'@atproto/jwk-jose': 0.1.11
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
|
'@atproto/jwk@0.6.0':
|
||||||
|
dependencies:
|
||||||
|
multiformats: 9.9.0
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
|
'@atproto/lex-data@0.0.13':
|
||||||
|
dependencies:
|
||||||
|
multiformats: 9.9.0
|
||||||
|
tslib: 2.8.1
|
||||||
|
uint8arrays: 3.0.0
|
||||||
|
unicode-segmenter: 0.14.5
|
||||||
|
|
||||||
|
'@atproto/lex-json@0.0.13':
|
||||||
|
dependencies:
|
||||||
|
'@atproto/lex-data': 0.0.13
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@atproto/lexicon@0.6.2':
|
||||||
|
dependencies:
|
||||||
|
'@atproto/common-web': 0.4.18
|
||||||
|
'@atproto/syntax': 0.5.0
|
||||||
|
iso-datestring-validator: 2.2.2
|
||||||
|
multiformats: 9.9.0
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
|
'@atproto/oauth-client-browser@0.3.41':
|
||||||
|
dependencies:
|
||||||
|
'@atproto-labs/did-resolver': 0.2.6
|
||||||
|
'@atproto-labs/handle-resolver': 0.3.6
|
||||||
|
'@atproto-labs/simple-store': 0.3.0
|
||||||
|
'@atproto/did': 0.3.0
|
||||||
|
'@atproto/jwk': 0.6.0
|
||||||
|
'@atproto/jwk-webcrypto': 0.2.0
|
||||||
|
'@atproto/oauth-client': 0.6.0
|
||||||
|
'@atproto/oauth-types': 0.6.3
|
||||||
|
core-js: 3.48.0
|
||||||
|
|
||||||
|
'@atproto/oauth-client@0.6.0':
|
||||||
|
dependencies:
|
||||||
|
'@atproto-labs/did-resolver': 0.2.6
|
||||||
|
'@atproto-labs/fetch': 0.2.3
|
||||||
|
'@atproto-labs/handle-resolver': 0.3.6
|
||||||
|
'@atproto-labs/identity-resolver': 0.3.6
|
||||||
|
'@atproto-labs/simple-store': 0.3.0
|
||||||
|
'@atproto-labs/simple-store-memory': 0.1.4
|
||||||
|
'@atproto/did': 0.3.0
|
||||||
|
'@atproto/jwk': 0.6.0
|
||||||
|
'@atproto/oauth-types': 0.6.3
|
||||||
|
'@atproto/xrpc': 0.7.7
|
||||||
|
core-js: 3.48.0
|
||||||
|
multiformats: 9.9.0
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
|
'@atproto/oauth-types@0.6.3':
|
||||||
|
dependencies:
|
||||||
|
'@atproto/did': 0.3.0
|
||||||
|
'@atproto/jwk': 0.6.0
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
|
'@atproto/syntax@0.5.0':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@atproto/xrpc@0.7.7':
|
||||||
|
dependencies:
|
||||||
|
'@atproto/lexicon': 0.6.2
|
||||||
|
zod: 3.25.76
|
||||||
|
|
||||||
'@babel/code-frame@7.27.1':
|
'@babel/code-frame@7.27.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/helper-validator-identifier': 7.27.1
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
@@ -8809,6 +9023,8 @@ snapshots:
|
|||||||
|
|
||||||
core-js@2.6.12: {}
|
core-js@2.6.12: {}
|
||||||
|
|
||||||
|
core-js@3.48.0: {}
|
||||||
|
|
||||||
core-util-is@1.0.2: {}
|
core-util-is@1.0.2: {}
|
||||||
|
|
||||||
cose-base@1.0.3:
|
cose-base@1.0.3:
|
||||||
@@ -10243,6 +10459,8 @@ snapshots:
|
|||||||
|
|
||||||
isexe@2.0.0: {}
|
isexe@2.0.0: {}
|
||||||
|
|
||||||
|
iso-datestring-validator@2.2.2: {}
|
||||||
|
|
||||||
isobject@2.1.0:
|
isobject@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
isarray: 1.0.0
|
isarray: 1.0.0
|
||||||
@@ -10518,6 +10736,8 @@ snapshots:
|
|||||||
|
|
||||||
jiti@2.6.1: {}
|
jiti@2.6.1: {}
|
||||||
|
|
||||||
|
jose@5.10.0: {}
|
||||||
|
|
||||||
js-tokens@3.0.2: {}
|
js-tokens@3.0.2: {}
|
||||||
|
|
||||||
js-tokens@4.0.0: {}
|
js-tokens@4.0.0: {}
|
||||||
@@ -10762,6 +10982,8 @@ snapshots:
|
|||||||
|
|
||||||
loupe@3.2.0: {}
|
loupe@3.2.0: {}
|
||||||
|
|
||||||
|
lru-cache@10.4.3: {}
|
||||||
|
|
||||||
lru-cache@4.1.5:
|
lru-cache@4.1.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
pseudomap: 1.0.2
|
pseudomap: 1.0.2
|
||||||
@@ -10955,6 +11177,8 @@ snapshots:
|
|||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
|
multiformats@9.9.0: {}
|
||||||
|
|
||||||
nan@2.25.0:
|
nan@2.25.0:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -12126,6 +12350,8 @@ snapshots:
|
|||||||
|
|
||||||
tslib@2.6.1: {}
|
tslib@2.6.1: {}
|
||||||
|
|
||||||
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
tsx@4.20.3:
|
tsx@4.20.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.5
|
esbuild: 0.25.5
|
||||||
@@ -12204,6 +12430,10 @@ snapshots:
|
|||||||
uglify-js@3.19.3:
|
uglify-js@3.19.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
uint8arrays@3.0.0:
|
||||||
|
dependencies:
|
||||||
|
multiformats: 9.9.0
|
||||||
|
|
||||||
unbox-primitive@1.1.0:
|
unbox-primitive@1.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bound: 1.0.4
|
call-bound: 1.0.4
|
||||||
@@ -12239,6 +12469,8 @@ snapshots:
|
|||||||
|
|
||||||
unicode-property-aliases-ecmascript@2.2.0: {}
|
unicode-property-aliases-ecmascript@2.2.0: {}
|
||||||
|
|
||||||
|
unicode-segmenter@0.14.5: {}
|
||||||
|
|
||||||
union-value@1.0.1:
|
union-value@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
arr-union: 3.1.0
|
arr-union: 3.1.0
|
||||||
@@ -12727,3 +12959,5 @@ snapshots:
|
|||||||
yargs-parser: 7.0.0
|
yargs-parser: 7.0.0
|
||||||
|
|
||||||
yocto-queue@0.1.0: {}
|
yocto-queue@0.1.0: {}
|
||||||
|
|
||||||
|
zod@3.25.76: {}
|
||||||
|
|||||||
15
public/client-metadata.json
Normal file
15
public/client-metadata.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"client_id": "https://remanso.space/client-metadata.json",
|
||||||
|
"client_name": "Remanso",
|
||||||
|
"client_uri": "https://remanso.space",
|
||||||
|
"redirect_uris": [
|
||||||
|
"https://remanso.space/",
|
||||||
|
"http://localhost:5173/"
|
||||||
|
],
|
||||||
|
"scope": "atproto transition:generic",
|
||||||
|
"grant_types": ["authorization_code", "refresh_token"],
|
||||||
|
"response_types": ["code"],
|
||||||
|
"application_type": "web",
|
||||||
|
"dpop_bound_access_tokens": true,
|
||||||
|
"token_endpoint_auth_method": "none"
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import NewVersion from '@/components/NewVersion.vue'
|
import NewVersion from '@/components/NewVersion.vue'
|
||||||
|
import { useATProtoLogin } from '@/hooks/useATProtoLogin.hook'
|
||||||
import { useGitHubLogin } from '@/hooks/useGitHubLogin.hook'
|
import { useGitHubLogin } from '@/hooks/useGitHubLogin.hook'
|
||||||
|
|
||||||
const { isReady } = useGitHubLogin()
|
const { isReady } = useGitHubLogin()
|
||||||
|
const { isATProtoReady } = useATProtoLogin()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="main-app" class="prose">
|
<div id="main-app" class="prose">
|
||||||
<router-view v-if="isReady" />
|
<router-view v-if="isReady && isATProtoReady" />
|
||||||
|
|
||||||
<new-version />
|
<new-version />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
32
src/components/SignInAtproto.vue
Normal file
32
src/components/SignInAtproto.vue
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
import { useATProtoLogin } from '@/hooks/useATProtoLogin.hook'
|
||||||
|
|
||||||
|
const { handle, isLoggedIn, signIn, signOut } = useATProtoLogin()
|
||||||
|
|
||||||
|
const inputHandle = ref('')
|
||||||
|
|
||||||
|
const onSignIn = () => {
|
||||||
|
if (inputHandle.value) {
|
||||||
|
signIn(inputHandle.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="isLoggedIn" class="sign-in-atproto">
|
||||||
|
<span>{{ handle }}</span>
|
||||||
|
<button class="btn btn-sm" @click="signOut">Sign out</button>
|
||||||
|
</div>
|
||||||
|
<div v-else class="sign-in-atproto">
|
||||||
|
<input
|
||||||
|
v-model="inputHandle"
|
||||||
|
class="input input-sm"
|
||||||
|
type="text"
|
||||||
|
placeholder="yourhandle.bsky.social"
|
||||||
|
@keyup.enter="onSignIn"
|
||||||
|
/>
|
||||||
|
<button class="btn btn-sm" @click="onSignIn">Sign in with Bluesky</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import RepoList from "@/components/RepoList.vue"
|
import RepoList from "@/components/RepoList.vue"
|
||||||
|
import SignInAtproto from "@/components/SignInAtproto.vue"
|
||||||
import SignInGithub from "@/components/SignInGithub.vue"
|
import SignInGithub from "@/components/SignInGithub.vue"
|
||||||
import ThemeSwap from "@/components/ThemeSwap.vue"
|
import ThemeSwap from "@/components/ThemeSwap.vue"
|
||||||
import { useForm } from "@/hooks/useForm.hook"
|
import { useForm } from "@/hooks/useForm.hook"
|
||||||
@@ -23,6 +24,7 @@ const { userInput, repoInput, submit } = useForm()
|
|||||||
|
|
||||||
<div class="get-started">
|
<div class="get-started">
|
||||||
<sign-in-github />
|
<sign-in-github />
|
||||||
|
<sign-in-atproto />
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
name: 'FluxNoteView',
|
name: 'FluxNoteView',
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ export enum DataType {
|
|||||||
BacklinkNote = 'BacklinkNote',
|
BacklinkNote = 'BacklinkNote',
|
||||||
RepetitionCard = 'RepetitionCard',
|
RepetitionCard = 'RepetitionCard',
|
||||||
History = 'History',
|
History = 'History',
|
||||||
UserSettings = 'UserSettings'
|
UserSettings = 'UserSettings',
|
||||||
|
AtprotoSession = 'AtprotoSession'
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/data/models/AtprotoSession.ts
Normal file
7
src/data/models/AtprotoSession.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { DataType } from '@/data/DataType.enum'
|
||||||
|
import { Model } from '@/data/models/Model'
|
||||||
|
|
||||||
|
export interface AtprotoSession extends Model<DataType.AtprotoSession> {
|
||||||
|
did: string
|
||||||
|
handle: string
|
||||||
|
}
|
||||||
59
src/hooks/useATProtoLogin.hook.ts
Normal file
59
src/hooks/useATProtoLogin.hook.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
import { getAuthor } from '@/modules/atproto/getAuthor'
|
||||||
|
import { restoreSession, sdkSignOut, signInWithHandle } from '@/modules/atproto/service/atprotoOAuth'
|
||||||
|
import { clearSession, loadSession, saveSession } from '@/modules/atproto/service/atprotoSession'
|
||||||
|
|
||||||
|
const did = ref<string | null>(null)
|
||||||
|
const handle = ref<string | null>(null)
|
||||||
|
|
||||||
|
let init = true
|
||||||
|
|
||||||
|
const initializeAuth = async () => {
|
||||||
|
const session = await restoreSession()
|
||||||
|
|
||||||
|
if (session) {
|
||||||
|
const author = await getAuthor(session.did)
|
||||||
|
const resolvedHandle = author?.handle ?? ''
|
||||||
|
|
||||||
|
did.value = session.did
|
||||||
|
handle.value = resolvedHandle
|
||||||
|
await saveSession(session.did, resolvedHandle)
|
||||||
|
} else {
|
||||||
|
const stored = await loadSession()
|
||||||
|
did.value = stored?.did ?? ''
|
||||||
|
handle.value = stored?.handle ?? ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useATProtoLogin = () => {
|
||||||
|
if (init) {
|
||||||
|
init = false
|
||||||
|
initializeAuth()
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLoggedIn = computed(() => !!did.value)
|
||||||
|
const isATProtoReady = computed(() => did.value !== null)
|
||||||
|
|
||||||
|
const signIn = async (inputHandle: string): Promise<void> => {
|
||||||
|
await signInWithHandle(inputHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
const signOut = async (): Promise<void> => {
|
||||||
|
if (did.value) {
|
||||||
|
await sdkSignOut(did.value)
|
||||||
|
}
|
||||||
|
await clearSession()
|
||||||
|
did.value = ''
|
||||||
|
handle.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
did,
|
||||||
|
handle,
|
||||||
|
isLoggedIn,
|
||||||
|
isATProtoReady,
|
||||||
|
signIn,
|
||||||
|
signOut,
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/hooks/useFollows.hook.ts
Normal file
21
src/hooks/useFollows.hook.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Ref, ref, watch } from 'vue'
|
||||||
|
|
||||||
|
import { getFollows } from '@/modules/atproto/service/getFollows'
|
||||||
|
|
||||||
|
export const useFollows = (did: Ref<string | null>) => {
|
||||||
|
const follows = ref<Set<string>>(new Set())
|
||||||
|
|
||||||
|
watch(
|
||||||
|
did,
|
||||||
|
async (value) => {
|
||||||
|
if (value) {
|
||||||
|
follows.value = await getFollows(value)
|
||||||
|
} else {
|
||||||
|
follows.value = new Set()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
return { follows }
|
||||||
|
}
|
||||||
@@ -3,7 +3,12 @@ import { PublicNoteListItem } from "@/modules/note/models/Note"
|
|||||||
import { computedAsync } from "@vueuse/core"
|
import { computedAsync } from "@vueuse/core"
|
||||||
import { computed, ref, Ref } from "vue"
|
import { computed, ref, Ref } from "vue"
|
||||||
|
|
||||||
export function usePublicNoteList(did?: Ref<string | undefined>) {
|
interface UsePublicNoteListOptions {
|
||||||
|
did?: Ref<string | undefined>
|
||||||
|
followsFilter?: Ref<Set<string>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePublicNoteList(options?: UsePublicNoteListOptions) {
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const notes = ref<PublicNoteListItem[]>([])
|
const notes = ref<PublicNoteListItem[]>([])
|
||||||
const cursor = ref<string | null | undefined>(null)
|
const cursor = ref<string | null | undefined>(null)
|
||||||
@@ -12,7 +17,7 @@ export function usePublicNoteList(did?: Ref<string | undefined>) {
|
|||||||
const onLoadMore = async () => {
|
const onLoadMore = async () => {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
|
|
||||||
const path = did?.value ? `/${did.value}/notes` : "/notes"
|
const path = options?.did?.value ? `/${options.did.value}/notes` : "/notes"
|
||||||
const noteAPI = new URL(path, "https://api.litenote.li212.fr")
|
const noteAPI = new URL(path, "https://api.litenote.li212.fr")
|
||||||
|
|
||||||
if (cursor.value) {
|
if (cursor.value) {
|
||||||
@@ -39,8 +44,14 @@ export function usePublicNoteList(did?: Ref<string | undefined>) {
|
|||||||
const getAuthor = (did: string) =>
|
const getAuthor = (did: string) =>
|
||||||
authors.value.has(did) ? authors.value.get(did)?.handle : ""
|
authors.value.has(did) ? authors.value.get(did)?.handle : ""
|
||||||
|
|
||||||
|
const filteredNotes = computed(() => {
|
||||||
|
const filter = options?.followsFilter?.value
|
||||||
|
if (!filter || filter.size === 0) return notes.value
|
||||||
|
return notes.value.filter((n) => filter.has(n.did))
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
notes,
|
notes: filteredNotes,
|
||||||
isLoading,
|
isLoading,
|
||||||
canLoadMore,
|
canLoadMore,
|
||||||
onLoadMore,
|
onLoadMore,
|
||||||
|
|||||||
30
src/modules/atproto/service/atprotoOAuth.ts
Normal file
30
src/modules/atproto/service/atprotoOAuth.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { BrowserOAuthClient } from '@atproto/oauth-client-browser'
|
||||||
|
|
||||||
|
const CLIENT_ID = import.meta.env.DEV
|
||||||
|
? 'http://localhost'
|
||||||
|
: 'https://remanso.space/client-metadata.json'
|
||||||
|
|
||||||
|
let clientPromise: Promise<BrowserOAuthClient> | null = null
|
||||||
|
|
||||||
|
export const getOAuthClient = (): Promise<BrowserOAuthClient> => {
|
||||||
|
if (!clientPromise) {
|
||||||
|
clientPromise = BrowserOAuthClient.load({ clientId: CLIENT_ID })
|
||||||
|
}
|
||||||
|
return clientPromise
|
||||||
|
}
|
||||||
|
|
||||||
|
export const signInWithHandle = async (handle: string): Promise<void> => {
|
||||||
|
const client = await getOAuthClient()
|
||||||
|
await client.signInRedirect(handle, { scope: 'atproto transition:generic' })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const restoreSession = async () => {
|
||||||
|
const client = await getOAuthClient()
|
||||||
|
const result = await client.init()
|
||||||
|
return result?.session ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sdkSignOut = async (sub: string): Promise<void> => {
|
||||||
|
const client = await getOAuthClient()
|
||||||
|
await client.revoke(sub)
|
||||||
|
}
|
||||||
23
src/modules/atproto/service/atprotoSession.ts
Normal file
23
src/modules/atproto/service/atprotoSession.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { data } from '@/data/data'
|
||||||
|
import { DataType } from '@/data/DataType.enum'
|
||||||
|
import { AtprotoSession } from '@/data/models/AtprotoSession'
|
||||||
|
|
||||||
|
const SESSION_ID = `${DataType.AtprotoSession}-current`
|
||||||
|
|
||||||
|
export const loadSession = (): Promise<AtprotoSession | null> => {
|
||||||
|
return data.get<DataType.AtprotoSession, AtprotoSession>(SESSION_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const saveSession = async (did: string, handle: string): Promise<void> => {
|
||||||
|
const session: AtprotoSession = {
|
||||||
|
_id: SESSION_ID,
|
||||||
|
$type: DataType.AtprotoSession,
|
||||||
|
did,
|
||||||
|
handle,
|
||||||
|
}
|
||||||
|
await data.update<DataType.AtprotoSession, AtprotoSession>(session)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const clearSession = (): Promise<boolean> => {
|
||||||
|
return data.remove(SESSION_ID)
|
||||||
|
}
|
||||||
24
src/modules/atproto/service/getFollows.ts
Normal file
24
src/modules/atproto/service/getFollows.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
export const getFollows = async (did: string): Promise<Set<string>> => {
|
||||||
|
const follows = new Set<string>()
|
||||||
|
let cursor: string | undefined
|
||||||
|
|
||||||
|
do {
|
||||||
|
const url = new URL('https://public.api.bsky.app/xrpc/app.bsky.graph.getFollows')
|
||||||
|
url.searchParams.set('actor', did)
|
||||||
|
url.searchParams.set('limit', '100')
|
||||||
|
if (cursor) {
|
||||||
|
url.searchParams.set('cursor', cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(url)
|
||||||
|
const result: { follows: { did: string }[]; cursor?: string } = await response.json()
|
||||||
|
|
||||||
|
for (const follow of result.follows) {
|
||||||
|
follows.add(follow.did)
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = result.cursor
|
||||||
|
} while (cursor)
|
||||||
|
|
||||||
|
return follows
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ import { computed } from "vue"
|
|||||||
const props = defineProps<{ did: string }>()
|
const props = defineProps<{ did: string }>()
|
||||||
const did = computed(() => props.did)
|
const did = computed(() => props.did)
|
||||||
|
|
||||||
const { notes, isLoading, canLoadMore, onLoadMore } = usePublicNoteList(did)
|
const { notes, isLoading, canLoadMore, onLoadMore } = usePublicNoteList({ did })
|
||||||
|
|
||||||
const author = computedAsync(async () => getAuthor(did.value))
|
const author = computedAsync(async () => getAuthor(did.value))
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import BackButton from "@/components/BackButton.vue"
|
import BackButton from "@/components/BackButton.vue"
|
||||||
import PublicNoteList from "@/components/PublicNoteList.vue"
|
import PublicNoteList from "@/components/PublicNoteList.vue"
|
||||||
|
import SignInAtproto from "@/components/SignInAtproto.vue"
|
||||||
|
import { useATProtoLogin } from "@/hooks/useATProtoLogin.hook"
|
||||||
|
import { useFollows } from "@/hooks/useFollows.hook"
|
||||||
import { usePublicNoteList } from "@/hooks/usePublicNoteList.hook"
|
import { usePublicNoteList } from "@/hooks/usePublicNoteList.hook"
|
||||||
|
|
||||||
|
const { did, isLoggedIn } = useATProtoLogin()
|
||||||
|
const { follows } = useFollows(did)
|
||||||
const { notes, isLoading, canLoadMore, onLoadMore, getAuthor } =
|
const { notes, isLoading, canLoadMore, onLoadMore, getAuthor } =
|
||||||
usePublicNoteList()
|
usePublicNoteList({ followsFilter: follows })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -12,6 +17,10 @@ const { notes, isLoading, canLoadMore, onLoadMore, getAuthor } =
|
|||||||
<div class="header">
|
<div class="header">
|
||||||
<back-button class="back-button" :fallback="{ name: 'Home' }" />
|
<back-button class="back-button" :fallback="{ name: 'Home' }" />
|
||||||
<h1>Remanso notes</h1>
|
<h1>Remanso notes</h1>
|
||||||
|
<sign-in-atproto />
|
||||||
|
</div>
|
||||||
|
<div v-if="isLoggedIn && follows.size > 0" class="follows-badge">
|
||||||
|
Showing follows only
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isLoading"></div>
|
<div v-if="isLoading"></div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
@@ -74,4 +83,11 @@ const { notes, isLoading, canLoadMore, onLoadMore, getAuthor } =
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.follows-badge {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
opacity: 0.7;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user