open source is social v-it.org
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add Bluesky OAuth CLI tool (bsky_oauth.js)

New Bun CLI utility that performs the ATProto OAuth authorization code
flow against a user's PDS. Hosts a temporary localhost callback server,
completes PAR + PKCE + DPoP token exchange via @atproto/oauth-client-node,
and prints the resulting DPoP-bound access token.

Also adds hosted client metadata (docs/client-metadata.json) for
https://v-it.org and updates README with usage instructions.

+345 -2
+38 -1
README.md
··· 1 - # vit 1 + # vit 2 + 3 + Minimal DID:PLC genesis op generator + registrar, and Bluesky OAuth CLI tool. 4 + 5 + ## PLC Register 6 + 7 + Generate and register a DID:PLC genesis operation: 8 + 9 + ``` 10 + bun install 11 + bun plc_register.js --help 12 + ``` 13 + 14 + ## Bluesky OAuth 15 + 16 + Obtain an ATProto OAuth access token via browser-based authorization. 17 + 18 + ### Usage 19 + 20 + ``` 21 + bun install 22 + bun bsky_oauth.js --handle alice.bsky.social 23 + ``` 24 + 25 + This will: 26 + 1. Start a temporary localhost callback server 27 + 2. Open your browser to the Bluesky authorization page 28 + 3. After you approve, print the DPoP-bound access token and DID 29 + 30 + ### Options 31 + 32 + - `--handle <handle>` — Bluesky handle (required) 33 + - `-v, --verbose` — Show discovery and protocol details 34 + - `--output <file>` — Save token JSON to a file 35 + 36 + ### Notes 37 + 38 + The access token is DPoP-bound, meaning it requires a DPoP proof JWT for each API request. The token cannot be used as a simple Bearer token. Token refresh is not implemented in this version.
+186
bsky_oauth.js
··· 1 + #!/usr/bin/env bun 2 + 3 + import { NodeOAuthClient } from '@atproto/oauth-client-node'; 4 + import { Command } from 'commander'; 5 + import { writeFileSync } from 'node:fs'; 6 + 7 + function createStore() { 8 + const map = new Map(); 9 + 10 + return { 11 + set: async (key, value) => { 12 + map.set(key, value); 13 + }, 14 + get: async (key) => map.get(key), 15 + del: async (key) => { 16 + map.delete(key); 17 + }, 18 + }; 19 + } 20 + 21 + async function main() { 22 + const program = new Command(); 23 + 24 + program 25 + .name('bsky_oauth') 26 + .description('Obtain an ATProto OAuth access token via browser authorization') 27 + .option('--handle <handle>', 'Bluesky handle (e.g. alice.bsky.social)') 28 + .option('-v, --verbose', 'Show discovery details') 29 + .option('--output <file>', 'Save token JSON to file') 30 + .parse(); 31 + 32 + const { handle, verbose, output } = program.opts(); 33 + 34 + let server; 35 + let timeout; 36 + 37 + try { 38 + if (!handle) { 39 + throw new Error('Missing required --handle argument.'); 40 + } 41 + 42 + let resolveCallback; 43 + let callbackResolved = false; 44 + const callbackPromise = new Promise((resolve) => { 45 + resolveCallback = resolve; 46 + }); 47 + 48 + server = Bun.serve({ 49 + hostname: '127.0.0.1', 50 + port: 0, 51 + fetch(req) { 52 + const url = new URL(req.url); 53 + 54 + if (req.method === 'GET' && url.pathname === '/callback') { 55 + const params = new URLSearchParams(url.searchParams); 56 + 57 + if (!callbackResolved) { 58 + callbackResolved = true; 59 + resolveCallback(params); 60 + } 61 + 62 + return new Response( 63 + '<!doctype html><html><body><h2>Authorization complete, you can close this tab.</h2></body></html>', 64 + { 65 + headers: { 'content-type': 'text/html; charset=utf-8' }, 66 + }, 67 + ); 68 + } 69 + 70 + return new Response('Not found', { status: 404 }); 71 + }, 72 + }); 73 + 74 + if (verbose) { 75 + console.log(`[verbose] Server started on port ${server.port}`); 76 + } 77 + 78 + const redirectUri = `http://127.0.0.1:${server.port}/callback`; 79 + 80 + if (verbose) { 81 + console.log(`[verbose] Redirect URI: ${redirectUri}`); 82 + } 83 + 84 + const stateStore = createStore(); 85 + const sessionStore = createStore(); 86 + 87 + const client = new NodeOAuthClient({ 88 + clientMetadata: { 89 + client_id: 'https://v-it.org/client-metadata.json', 90 + client_name: 'vit CLI', 91 + application_type: 'native', 92 + grant_types: ['authorization_code'], 93 + response_types: ['code'], 94 + redirect_uris: [redirectUri], 95 + scope: 'atproto transition:generic', 96 + token_endpoint_auth_method: 'none', 97 + dpop_bound_access_tokens: true, 98 + client_uri: 'https://v-it.org', 99 + }, 100 + stateStore, 101 + sessionStore, 102 + }); 103 + 104 + const authUrl = await client.authorize(handle, { 105 + scope: 'atproto transition:generic', 106 + }); 107 + 108 + if (verbose) { 109 + console.log(`[verbose] Authorization URL: ${authUrl.toString()}`); 110 + } 111 + 112 + const platform = process.platform; 113 + const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'cmd' : 'xdg-open'; 114 + const args = platform === 'win32' ? ['/c', 'start', authUrl.toString()] : [authUrl.toString()]; 115 + 116 + try { 117 + Bun.spawn([cmd, ...args], { 118 + stdio: ['ignore', 'ignore', 'ignore'], 119 + }); 120 + } catch { 121 + // Ignore browser-open failures and rely on printed URL. 122 + } 123 + 124 + console.log(`Open this URL in your browser:\n ${authUrl.toString()}\n`); 125 + 126 + const timeoutMs = 5 * 60 * 1000; 127 + const timeoutPromise = new Promise((_, reject) => { 128 + timeout = setTimeout(() => { 129 + reject(new Error('Timed out waiting for callback.')); 130 + }, timeoutMs); 131 + }); 132 + 133 + const params = await Promise.race([callbackPromise, timeoutPromise]); 134 + 135 + clearTimeout(timeout); 136 + timeout = undefined; 137 + 138 + if (verbose) { 139 + console.log(`[verbose] Callback received with params: ${params.toString()}`); 140 + } 141 + 142 + const oauthError = params.get('error'); 143 + if (oauthError) { 144 + const description = params.get('error_description'); 145 + if (description) { 146 + throw new Error(`OAuth error: ${oauthError} (${description})`); 147 + } 148 + throw new Error(`OAuth error: ${oauthError}`); 149 + } 150 + 151 + const { session } = await client.callback(params); 152 + 153 + if (verbose) { 154 + console.log(`[verbose] Token exchange result for DID: ${session.did}`); 155 + } 156 + 157 + console.log(`DID: ${session.did}`); 158 + 159 + const sessionData = await sessionStore.get(session.did); 160 + const outputData = { 161 + did: session.did, 162 + accessToken: sessionData?.tokenSet?.access_token ?? null, 163 + refreshToken: sessionData?.tokenSet?.refresh_token ?? null, 164 + expiresAt: sessionData?.tokenSet?.expires_at ?? null, 165 + }; 166 + 167 + console.log(JSON.stringify(outputData, null, 2)); 168 + 169 + if (output) { 170 + writeFileSync(output, `${JSON.stringify(outputData, null, 2)}\n`); 171 + } 172 + } catch (err) { 173 + console.error(err instanceof Error ? err.message : String(err)); 174 + process.exitCode = 1; 175 + } finally { 176 + if (timeout) { 177 + clearTimeout(timeout); 178 + } 179 + 180 + if (server) { 181 + server.stop(); 182 + } 183 + } 184 + } 185 + 186 + await main();
+107
bun.lock
··· 1 + { 2 + "lockfileVersion": 1, 3 + "workspaces": { 4 + "": { 5 + "name": "vit", 6 + "dependencies": { 7 + "@atproto/oauth-client-node": "0.3.16", 8 + "@ipld/dag-cbor": "^9.2.0", 9 + "@noble/curves": "^1.8.0", 10 + "@noble/hashes": "^1.7.0", 11 + "bs58": "^6.0.0", 12 + "commander": "^13.0.0", 13 + }, 14 + }, 15 + }, 16 + "packages": { 17 + "@atproto-labs/did-resolver": ["@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.23.8" } }, "sha512-2K1bC04nI2fmgNcvof+yA28IhGlpWn2JKYlPa7To9JTKI45FINCGkQSGiL2nyXlyzDJJ34fZ1aq6/IRFIOIiqg=="], 18 + 19 + "@atproto-labs/fetch": ["@atproto-labs/fetch@0.2.3", "", { "dependencies": { "@atproto-labs/pipe": "0.1.1" } }, "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw=="], 20 + 21 + "@atproto-labs/fetch-node": ["@atproto-labs/fetch-node@0.2.0", "", { "dependencies": { "@atproto-labs/fetch": "0.2.3", "@atproto-labs/pipe": "0.1.1", "ipaddr.js": "^2.1.0", "undici": "^6.14.1" } }, "sha512-Krq09nH/aeoiU2s9xdHA0FjTEFWG9B5FFenipv1iRixCcPc7V3DhTNDawxG9gI8Ny0k4dBVS9WTRN/IDzBx86Q=="], 22 + 23 + "@atproto-labs/handle-resolver": ["@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.23.8" } }, "sha512-qnSTXvOBNj1EHhp2qTWSX8MS5q3AwYU5LKlt5fBvSbCjgmTr2j0URHCv+ydrwO55KvsojIkTMgeMOh4YuY4fCA=="], 24 + 25 + "@atproto-labs/handle-resolver-node": ["@atproto-labs/handle-resolver-node@0.1.25", "", { "dependencies": { "@atproto-labs/fetch-node": "0.2.0", "@atproto-labs/handle-resolver": "0.3.6", "@atproto/did": "0.3.0" } }, "sha512-NY9WYM2VLd3IuMGRkkmvGBg8xqVEaK/fitv1vD8SMXqFTekdpjOLCCyv7EFtqVHouzmDcL83VOvWRfHVa8V9Yw=="], 26 + 27 + "@atproto-labs/identity-resolver": ["@atproto-labs/identity-resolver@0.3.6", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.6", "@atproto-labs/handle-resolver": "0.3.6" } }, "sha512-qoWqBDRobln0NR8L8dQjSp79E0chGkBhibEgxQa2f9WD+JbJdjQ0YvwwO5yeQn05pJoJmAwmI2wyJ45zjU7aWg=="], 28 + 29 + "@atproto-labs/pipe": ["@atproto-labs/pipe@0.1.1", "", {}, "sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg=="], 30 + 31 + "@atproto-labs/simple-store": ["@atproto-labs/simple-store@0.3.0", "", {}, "sha512-nOb6ONKBRJHRlukW1sVawUkBqReLlLx6hT35VS3imaNPwiXDxLnTK7lxw3Lrl9k5yugSBDQAkZAq3MPTEFSUBQ=="], 32 + 33 + "@atproto-labs/simple-store-memory": ["@atproto-labs/simple-store-memory@0.1.4", "", { "dependencies": { "@atproto-labs/simple-store": "0.3.0", "lru-cache": "^10.2.0" } }, "sha512-3mKY4dP8I7yKPFj9VKpYyCRzGJOi5CEpOLPlRhoJyLmgs3J4RzDrjn323Oakjz2Aj2JzRU/AIvWRAZVhpYNJHw=="], 34 + 35 + "@atproto/common-web": ["@atproto/common-web@0.4.16", "", { "dependencies": { "@atproto/lex-data": "^0.0.11", "@atproto/lex-json": "^0.0.11", "@atproto/syntax": "^0.4.3", "zod": "^3.23.8" } }, "sha512-Ufvaff5JgxUyUyTAG0/3o7ltpy3lnZ1DvLjyAnvAf+hHfiK7OMQg+8byr+orN+KP9MtIQaRTsCgYPX+PxMKUoA=="], 36 + 37 + "@atproto/did": ["@atproto/did@0.3.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-raUPzUGegtW/6OxwCmM8bhZvuIMzxG5t9oWsth6Tp91Kb5fTnHV2h/KKNF1C82doeA4BdXCErTyg7ISwLbQkzA=="], 38 + 39 + "@atproto/jwk": ["@atproto/jwk@0.6.0", "", { "dependencies": { "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-bDoJPvt7TrQVi/rBfBrSSpGykhtIriKxeYCYQTiPRKFfyRhbgpElF0wPXADjIswnbzZdOwbY63az4E/CFVT3Tw=="], 40 + 41 + "@atproto/jwk-jose": ["@atproto/jwk-jose@0.1.11", "", { "dependencies": { "@atproto/jwk": "0.6.0", "jose": "^5.2.0" } }, "sha512-i4Fnr2sTBYmMmHXl7NJh8GrCH+tDQEVWrcDMDnV5DjJfkgT17wIqvojIw9SNbSL4Uf0OtfEv6AgG0A+mgh8b5Q=="], 42 + 43 + "@atproto/jwk-webcrypto": ["@atproto/jwk-webcrypto@0.2.0", "", { "dependencies": { "@atproto/jwk": "0.6.0", "@atproto/jwk-jose": "0.1.11", "zod": "^3.23.8" } }, "sha512-UmgRrrEAkWvxwhlwe30UmDOdTEFidlIzBC7C3cCbeJMcBN1x8B3KH+crXrsTqfWQBG58mXgt8wgSK3Kxs2LhFg=="], 44 + 45 + "@atproto/lex-data": ["@atproto/lex-data@0.0.11", "", { "dependencies": { "multiformats": "^9.9.0", "tslib": "^2.8.1", "uint8arrays": "3.0.0", "unicode-segmenter": "^0.14.0" } }, "sha512-4+KTtHdqwlhiTKA7D4SACea4jprsNpCQsNALW09wsZ6IHhCDGO5tr1cmV+QnLYe3G3mu1E1yXHXbPUHrUUDT/A=="], 46 + 47 + "@atproto/lex-json": ["@atproto/lex-json@0.0.11", "", { "dependencies": { "@atproto/lex-data": "^0.0.11", "tslib": "^2.8.1" } }, "sha512-2IExAoQ4KsR5fyPa1JjIvtR316PvdgRH/l3BVGLBd3cSxM3m5MftIv1B6qZ9HjNiK60SgkWp0mi9574bTNDhBQ=="], 48 + 49 + "@atproto/lexicon": ["@atproto/lexicon@0.6.1", "", { "dependencies": { "@atproto/common-web": "^0.4.13", "@atproto/syntax": "^0.4.3", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-/vI1kVlY50Si+5MXpvOucelnYwb0UJ6Qto5mCp+7Q5C+Jtp+SoSykAPVvjVtTnQUH2vrKOFOwpb3C375vSKzXw=="], 50 + 51 + "@atproto/oauth-client": ["@atproto/oauth-client@0.5.14", "", { "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.2", "@atproto/xrpc": "0.7.7", "core-js": "^3", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-sPH+vcdq9maTEAhJI0HzmFcFAMrkCS19np+RUssNkX6kS8Xr3OYr57tvYRCbkcnIyYTfYcxKQgpwHKx3RVEaYw=="], 52 + 53 + "@atproto/oauth-client-node": ["@atproto/oauth-client-node@0.3.16", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.6", "@atproto-labs/handle-resolver-node": "0.1.25", "@atproto-labs/simple-store": "0.3.0", "@atproto/did": "0.3.0", "@atproto/jwk": "0.6.0", "@atproto/jwk-jose": "0.1.11", "@atproto/jwk-webcrypto": "0.2.0", "@atproto/oauth-client": "0.5.14", "@atproto/oauth-types": "0.6.2" } }, "sha512-2dooMzxAkiQ4MkOAZlEQ3iwbB9SEovrbIKMNuBbVCLQYORVNxe20tMdjs3lvhrzdpzvaHLlQnJJhw5dA9VELFw=="], 54 + 55 + "@atproto/oauth-types": ["@atproto/oauth-types@0.6.2", "", { "dependencies": { "@atproto/did": "0.3.0", "@atproto/jwk": "0.6.0", "zod": "^3.23.8" } }, "sha512-2cuboM4RQBCYR8NQC5uGRkW6KgCgKyq/B5/+tnMmWZYtZGVUQvsUWQHK/ZiMCnVXbcDNtc/RIEJQJDZ8FXMoxg=="], 56 + 57 + "@atproto/syntax": ["@atproto/syntax@0.4.3", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-YoZUz40YAJr5nPwvCDWgodEOlt5IftZqPJvA0JDWjuZKD8yXddTwSzXSaKQAzGOpuM+/A3uXRtPzJJqlScc+iA=="], 58 + 59 + "@atproto/xrpc": ["@atproto/xrpc@0.7.7", "", { "dependencies": { "@atproto/lexicon": "^0.6.0", "zod": "^3.23.8" } }, "sha512-K1ZyO/BU8JNtXX5dmPp7b5UrkLMMqpsIa/Lrj5D3Su+j1Xwq1m6QJ2XJ1AgjEjkI1v4Muzm7klianLE6XGxtmA=="], 60 + 61 + "@ipld/dag-cbor": ["@ipld/dag-cbor@9.2.5", "", { "dependencies": { "cborg": "^4.0.0", "multiformats": "^13.1.0" } }, "sha512-84wSr4jv30biui7endhobYhXBQzQE4c/wdoWlFrKcfiwH+ofaPg8fwsM8okX9cOzkkrsAsNdDyH3ou+kiLquwQ=="], 62 + 63 + "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], 64 + 65 + "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], 66 + 67 + "base-x": ["base-x@5.0.1", "", {}, "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg=="], 68 + 69 + "bs58": ["bs58@6.0.0", "", { "dependencies": { "base-x": "^5.0.0" } }, "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw=="], 70 + 71 + "cborg": ["cborg@4.5.8", "", { "bin": { "cborg": "lib/bin.js" } }, "sha512-6/viltD51JklRhq4L7jC3zgy6gryuG5xfZ3kzpE+PravtyeQLeQmCYLREhQH7pWENg5pY4Yu/XCd6a7dKScVlw=="], 72 + 73 + "commander": ["commander@13.1.0", "", {}, "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw=="], 74 + 75 + "core-js": ["core-js@3.48.0", "", {}, "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ=="], 76 + 77 + "ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="], 78 + 79 + "iso-datestring-validator": ["iso-datestring-validator@2.2.2", "", {}, "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA=="], 80 + 81 + "jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], 82 + 83 + "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], 84 + 85 + "multiformats": ["multiformats@13.4.2", "", {}, "sha512-eh6eHCrRi1+POZ3dA+Dq1C6jhP1GNtr9CRINMb67OKzqW9I5DUuZM/3jLPlzhgpGeiNUlEGEbkCYChXMCc/8DQ=="], 86 + 87 + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 88 + 89 + "uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA=="], 90 + 91 + "undici": ["undici@6.23.0", "", {}, "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g=="], 92 + 93 + "unicode-segmenter": ["unicode-segmenter@0.14.5", "", {}, "sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g=="], 94 + 95 + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], 96 + 97 + "@atproto/jwk/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 98 + 99 + "@atproto/lex-data/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 100 + 101 + "@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 102 + 103 + "@atproto/oauth-client/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 104 + 105 + "uint8arrays/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 106 + } 107 + }
+12
docs/client-metadata.json
··· 1 + { 2 + "client_id": "https://v-it.org/client-metadata.json", 3 + "client_name": "vit CLI", 4 + "application_type": "native", 5 + "grant_types": ["authorization_code"], 6 + "response_types": ["code"], 7 + "redirect_uris": ["http://127.0.0.1/callback"], 8 + "scope": "atproto transition:generic", 9 + "token_endpoint_auth_method": "none", 10 + "dpop_bound_access_tokens": true, 11 + "client_uri": "https://v-it.org" 12 + }
+2 -1
package.json
··· 2 2 "name": "vit", 3 3 "type": "module", 4 4 "dependencies": { 5 + "@atproto/oauth-client-node": "^0.3.16", 6 + "@ipld/dag-cbor": "^9.2.0", 5 7 "@noble/curves": "^1.8.0", 6 8 "@noble/hashes": "^1.7.0", 7 - "@ipld/dag-cbor": "^9.2.0", 8 9 "bs58": "^6.0.0", 9 10 "commander": "^13.0.0" 10 11 }