Something went wrong. Try again.
A CLI for publishing standard.site documents to ATProto
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495import { NodeOAuthClient, type NodeOAuthClientOptions,} from "@atproto/oauth-client-node";import { sessionStore, stateStore } from "./oauth-store";
const CALLBACK_PORT = 4000;const CALLBACK_HOST = "127.0.0.1";const CALLBACK_URL = `http://${CALLBACK_HOST}:${CALLBACK_PORT}/oauth/callback`;
// OAuth scope for Sequoia CLI - includes atproto base scope plus our collectionsconst OAUTH_SCOPE = "atproto repo:site.standard.document repo:site.standard.publication repo:app.bsky.feed.post blob:*/*";
let oauthClient: NodeOAuthClient | null = null;
// Simple lock implementation for CLI (single process, no contention)// This prevents the "No lock mechanism provided" warningconst locks = new Map<string, Promise<void>>();
async function requestLock<T>( key: string, fn: () => T | PromiseLike<T>,): Promise<T> { // Wait for any existing lock on this key while (locks.has(key)) { await locks.get(key); }
// Create our lock let resolve: () => void; const lockPromise = new Promise<void>((r) => { resolve = r; }); locks.set(key, lockPromise);
try { return await fn(); } finally { locks.delete(key); resolve!(); }}
/** * Get or create the OAuth client singleton */export async function getOAuthClient(): Promise<NodeOAuthClient> { if (oauthClient) { return oauthClient; }
// Build client_id with required parameters const clientIdParams = new URLSearchParams(); clientIdParams.append("redirect_uri", CALLBACK_URL); clientIdParams.append("scope", OAUTH_SCOPE);
const clientOptions: NodeOAuthClientOptions = { clientMetadata: { client_id: `http://localhost?${clientIdParams.toString()}`, client_name: "Sequoia CLI", client_uri: "https://sequoia.pub", redirect_uris: [CALLBACK_URL], grant_types: ["authorization_code", "refresh_token"], response_types: ["code"], token_endpoint_auth_method: "none", application_type: "web", scope: OAUTH_SCOPE, dpop_bound_access_tokens: false, }, stateStore, sessionStore, // Configure identity resolution plcDirectoryUrl: "https://plc.directory", // Provide lock mechanism to prevent warning requestLock, };
oauthClient = new NodeOAuthClient(clientOptions);
return oauthClient;}
export function getOAuthScope(): string { return OAUTH_SCOPE;}
export function getCallbackUrl(): string { return CALLBACK_URL;}
export function getCallbackPort(): number { return CALLBACK_PORT;}