A CLI for publishing standard.site documents to ATProto sequoia.pub
standard site lexicon cli publishing

Clean up remaining auth implementations #17

merged opened by stevedylan.dev targeting main from chore/auth-cleanup

Small refactors and better handling of multiple identities in functions that require auth

Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/sh.tangled.repo.pull/3me3ie4j7m622
+70 -16
Diff #1
+3 -2
packages/cli/src/commands/init.ts
··· 325 325 }; 326 326 } 327 327 328 - // Get PDS URL from credentials (already loaded earlier) 329 - const pdsUrl = credentials?.pdsUrl; 328 + // Get PDS URL from credentials (only available for app-password auth) 329 + const pdsUrl = 330 + credentials?.type === "app-password" ? credentials.pdsUrl : undefined; 330 331 331 332 // Generate config file 332 333 const configContent = generateConfigTemplate({
+3 -2
packages/cli/src/commands/publish.ts
··· 107 107 type: "oauth", 108 108 did: selected, 109 109 handle: handle || selected, 110 - pdsUrl: "https://bsky.social", 111 110 }; 112 111 } 113 112 } else { ··· 246 245 } 247 246 248 247 // Create agent 249 - s.start(`Connecting to ${credentials.pdsUrl}...`); 248 + const connectingTo = 249 + credentials.type === "oauth" ? credentials.handle : credentials.pdsUrl; 250 + s.start(`Connecting as ${connectingTo}...`); 250 251 let agent: Awaited<ReturnType<typeof createAgent>> | undefined; 251 252 try { 252 253 agent = await createAgent(credentials);
+3 -2
packages/cli/src/commands/sync.ts
··· 93 93 type: "oauth", 94 94 did: selected, 95 95 handle: handle || selected, 96 - pdsUrl: "https://bsky.social", 97 96 }; 98 97 } 99 98 } else { ··· 108 107 109 108 // Create agent 110 109 const s = spinner(); 111 - s.start(`Connecting to ${credentials.pdsUrl}...`); 110 + const connectingTo = 111 + credentials.type === "oauth" ? credentials.handle : credentials.pdsUrl; 112 + s.start(`Connecting as ${connectingTo}...`); 112 113 let agent: Awaited<ReturnType<typeof createAgent>> | undefined; 113 114 try { 114 115 agent = await createAgent(credentials);
+60 -5
packages/cli/src/commands/update.ts
··· 11 11 log, 12 12 } from "@clack/prompts"; 13 13 import { findConfig, loadConfig, generateConfigTemplate } from "../lib/config"; 14 - import { loadCredentials } from "../lib/credentials"; 14 + import { 15 + loadCredentials, 16 + listAllCredentials, 17 + getCredentials, 18 + } from "../lib/credentials"; 19 + import { getOAuthHandle, getOAuthSession } from "../lib/oauth-store"; 15 20 import { createAgent, getPublication, updatePublication } from "../lib/atproto"; 16 21 import { exitOnCancel } from "../lib/prompts"; 17 22 import type { ··· 438 443 439 444 async function updatePublicationFlow(config: PublisherConfig): Promise<void> { 440 445 // Load credentials 441 - const credentials = await loadCredentials(config.identity); 446 + let credentials = await loadCredentials(config.identity); 447 + 442 448 if (!credentials) { 443 - log.error( 444 - "No credentials found. Run 'sequoia auth' or 'sequoia login' first.", 449 + const identities = await listAllCredentials(); 450 + if (identities.length === 0) { 451 + log.error( 452 + "No credentials found. Run 'sequoia login' or 'sequoia auth' first.", 453 + ); 454 + process.exit(1); 455 + } 456 + 457 + // Build labels with handles for OAuth sessions 458 + const options = await Promise.all( 459 + identities.map(async (cred) => { 460 + if (cred.type === "oauth") { 461 + const handle = await getOAuthHandle(cred.id); 462 + return { 463 + value: cred.id, 464 + label: `${handle || cred.id} (OAuth)`, 465 + }; 466 + } 467 + return { 468 + value: cred.id, 469 + label: `${cred.id} (App Password)`, 470 + }; 471 + }), 445 472 ); 446 - process.exit(1); 473 + 474 + log.info("Multiple identities found. Select one to use:"); 475 + const selected = exitOnCancel( 476 + await select({ 477 + message: "Identity:", 478 + options, 479 + }), 480 + ); 481 + 482 + // Load the selected credentials 483 + const selectedCred = identities.find((c) => c.id === selected); 484 + if (selectedCred?.type === "oauth") { 485 + const session = await getOAuthSession(selected); 486 + if (session) { 487 + const handle = await getOAuthHandle(selected); 488 + credentials = { 489 + type: "oauth", 490 + did: selected, 491 + handle: handle || selected, 492 + }; 493 + } 494 + } else { 495 + credentials = await getCredentials(selected); 496 + } 497 + 498 + if (!credentials) { 499 + log.error("Failed to load selected credentials."); 500 + process.exit(1); 501 + } 447 502 } 448 503 449 504 const s = spinner();
-1
packages/cli/src/lib/credential-select.ts
··· 41 41 type: "oauth", 42 42 did: selected.id, 43 43 handle: handle || selected.id, 44 - pdsUrl: "https://bsky.social", 45 44 }; 46 45 } 47 46 } else {
-3
packages/cli/src/lib/credentials.ts
··· 96 96 type: "oauth", 97 97 did: profile, 98 98 handle: handle || profile, 99 - pdsUrl: "https://bsky.social", // Will be resolved from DID doc 100 99 }; 101 100 } 102 101 } ··· 109 108 type: "oauth", 110 109 did: match.did, 111 110 handle: match.handle || match.did, 112 - pdsUrl: "https://bsky.social", 113 111 }; 114 112 } 115 113 ··· 186 184 type: "oauth", 187 185 did: oauthDids[0], 188 186 handle: handle || oauthDids[0], 189 - pdsUrl: "https://bsky.social", 190 187 }; 191 188 } 192 189 }
+1 -1
packages/cli/src/lib/types.ts
··· 54 54 } 55 55 56 56 // OAuth credentials (references stored OAuth session) 57 + // Note: pdsUrl is not needed for OAuth - the OAuth client resolves PDS from the DID 57 58 export interface OAuthCredentials { 58 59 type: "oauth"; 59 60 did: string; 60 61 handle: string; 61 - pdsUrl: string; 62 62 } 63 63 64 64 // Union type for all credential types

History

2 rounds 0 comments
sign up or login to add to the discussion
2 commits
expand
chore: cleaned up remaining auth implementations
chore: format
expand 0 comments
pull request successfully merged
1 commit
expand
chore: cleaned up remaining auth implementations
1/1 failed
expand
expand 0 comments