Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 12 additions & 27 deletions src/auth/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ import type { Command } from 'commander'
import { CliError } from '../errors.js'
import { formatJson, formatNdjson } from '../json.js'
import { type ViewOptions, emitView } from '../options.js'
import type { AccountRef, AuthAccount, TokenStore } from './types.js'
import type {
AccountRef,
AttachContextBase,
AuthAccount,
TokenStore,
WithAccount,
} from './types.js'
import { accountNotFoundError } from './user-flag.js'

export type AttachAccountListContext<TAccount extends AuthAccount> = {
export type AttachAccountListContext<TAccount extends AuthAccount> = AttachContextBase & {
/** Every stored account with its default marker, in store order. */
accounts: ReadonlyArray<{ account: TAccount; isDefault: boolean }>
/** The default account's ref (its `id`), or `null` when nothing is stored. */
default: AccountRef | null
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
view: Required<ViewOptions>
/** Consumer-attached options. The registrar flags (`--json`, `--ndjson`) are stripped. */
flags: Record<string, unknown>
}

export type AttachAccountListCommandOptions<TAccount extends AuthAccount = AuthAccount> = {
Expand Down Expand Up @@ -49,11 +51,7 @@ export type AttachAccountUseCommandOptions<TAccount extends AuthAccount = AuthAc
* positional argument. Use for CLI-specific follow-ups (e.g. dropping a
* cached client bound to the previous default). Awaited.
*/
onDefaultSet?(ctx: {
ref: AccountRef
view: Required<ViewOptions>
flags: Record<string, unknown>
}): void | Promise<void>
onDefaultSet?(ctx: AttachContextBase & { ref: AccountRef }): void | Promise<void>
}

/** Split the parsed Commander options into the canonical machine-output view + the remaining consumer flags. */
Expand Down Expand Up @@ -234,15 +232,9 @@ export function attachAccountUseCommand<TAccount extends AuthAccount = AuthAccou
})
}

export type AttachAccountCurrentContext<TAccount extends AuthAccount> = {
/** The resolved active account. */
account: TAccount
export type AttachAccountCurrentContext<TAccount extends AuthAccount> = WithAccount<TAccount> & {
/** Whether the active account is the store's effective default. */
isDefault: boolean
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
view: Required<ViewOptions>
/** Consumer-attached options. The registrar flags (`--json`, `--ndjson`) are stripped. */
flags: Record<string, unknown>
}

export type AttachAccountCurrentCommandOptions<TAccount extends AuthAccount = AuthAccount> = {
Expand Down Expand Up @@ -271,10 +263,7 @@ export type AttachAccountCurrentCommandOptions<TAccount extends AuthAccount = Au
* credential sources (env var, legacy single-user creds) use this hook to
* render those cases — mirroring `attachStatusCommand`.
*/
onNotAuthenticated?(ctx: {
view: Required<ViewOptions>
flags: Record<string, unknown>
}): void | Promise<void>
onNotAuthenticated?(ctx: AttachContextBase): void | Promise<void>
}

/**
Expand Down Expand Up @@ -329,17 +318,13 @@ export function attachAccountCurrentCommand<TAccount extends AuthAccount = AuthA
})
}

export type AttachAccountRemoveContext<TAccount extends AuthAccount> = {
export type AttachAccountRemoveContext<TAccount extends AuthAccount> = AttachContextBase & {
/** The account that was removed, as reported by `store.clear()`. */
account: TAccount
/** The raw `<ref>` positional the user typed. */
ref: AccountRef
/** Whether the removed account was the default before clearing. */
wasDefault: boolean
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
view: Required<ViewOptions>
/** Consumer-attached options. The registrar flags (`--json`, `--ndjson`) are stripped. */
flags: Record<string, unknown>
}

export type AttachAccountRemoveCommandOptions<TAccount extends AuthAccount = AuthAccount> = {
Expand Down
19 changes: 7 additions & 12 deletions src/auth/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,14 @@ import type { Command } from 'commander'
import { CliError } from '../errors.js'
import type { ViewOptions } from '../options.js'
import { runOAuthFlow } from './flow.js'
import type { AuthAccount, AuthProvider, TokenStore } from './types.js'
import type { AuthAccount, AuthProvider, TokenStore, WithAccount } from './types.js'

export type AttachLoginContext<TAccount extends AuthAccount> = {
account: TAccount
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
view: Required<ViewOptions>
/**
* Stripped per-CLI flags — the parsed options object with the standard
* registrar flags (`--read-only`, `--callback-port`, `--json`, `--ndjson`)
* removed. Same view `resolveScopes` saw at flow start.
*/
flags: Record<string, unknown>
}
/**
* `flags` is the parsed options with the login registrar flags (`--read-only`,
* `--callback-port`, `--json`, `--ndjson`) stripped — the same view
* `resolveScopes` saw at flow start.
*/
export type AttachLoginContext<TAccount extends AuthAccount> = WithAccount<TAccount>
Comment thread
scottlovegrove marked this conversation as resolved.

export type AttachLoginCommandOptions<TAccount extends AuthAccount = AuthAccount> = {
provider: AuthProvider<TAccount>
Expand Down
8 changes: 2 additions & 6 deletions src/auth/logout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import type { Command } from 'commander'
import { CliError } from '../errors.js'
import { formatJson } from '../json.js'
import type { ViewOptions } from '../options.js'
import type { AccountRef, AuthAccount, TokenStore } from './types.js'
import type { AccountRef, AttachContextBase, AuthAccount, TokenStore } from './types.js'
import { attachUserFlag, extractUserRef, requireSnapshotForRef } from './user-flag.js'

export type AttachLogoutContext<TAccount extends AuthAccount> = {
export type AttachLogoutContext<TAccount extends AuthAccount> = AttachContextBase & {
/**
* The account that was active immediately before `clear()` ran, or
* `null` if nothing was stored. Also `null` on the `AUTH_STORE_READ_FAILED`
Expand All @@ -15,10 +15,6 @@ export type AttachLogoutContext<TAccount extends AuthAccount> = {
account: TAccount | null
/** The `--user <ref>` value, or `undefined` when not supplied. Always present so consumers can tell "no stored account" from "cleared an unreadable account by ref". */
ref: AccountRef | undefined
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
view: Required<ViewOptions>
/** Consumer-attached options. The registrar flags (`--json`, `--ndjson`, `--user`) are stripped. */
flags: Record<string, unknown>
}

export type AttachLogoutRevokeContext<TAccount extends AuthAccount> = Omit<
Expand Down
47 changes: 21 additions & 26 deletions src/auth/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import type { Command } from 'commander'
import { CliError } from '../errors.js'
import { formatJson, formatNdjson } from '../json.js'
import type { ViewOptions } from '../options.js'
import type { AccountRef, AuthAccount, TokenBundle, TokenStore } from './types.js'
import type {
AccountRef,
AttachContextBase,
AuthAccount,
TokenBundle,
TokenStore,
WithAccount,
} from './types.js'
import {
accountNotFoundError,
attachUserFlag,
Expand Down Expand Up @@ -55,13 +62,7 @@ async function resolveStatusSnapshot<TAccount extends AuthAccount>(
return snapshot ? { token: snapshot.token, account: snapshot.account } : null
}

export type AttachStatusContext<TAccount extends AuthAccount> = {
account: TAccount
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
view: Required<ViewOptions>
/** Consumer-attached options (e.g. `--full`). The registrar flags (`--json`, `--ndjson`, `--user`) are stripped. */
flags: Record<string, unknown>
}
export type AttachStatusContext<TAccount extends AuthAccount> = WithAccount<TAccount>

export type AttachStatusCommandOptions<TAccount extends AuthAccount = AuthAccount> = {
store: TokenStore<TAccount>
Expand All @@ -72,19 +73,17 @@ export type AttachStatusCommandOptions<TAccount extends AuthAccount = AuthAccoun
* the token still works. Throws (e.g. a `CliError('NO_TOKEN', …)` translation
* of a 401) propagate to the top-level handler.
*/
fetchLive?(ctx: {
account: TAccount
token: string
/**
* Full bundle when the store implements `activeBundle` — lets a
* consumer render expiry without a second read. Absent when the
* store only exposes `active()` (no refresh-side metadata available).
*/
bundle?: TokenBundle
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
view: Required<ViewOptions>
flags: Record<string, unknown>
}): Promise<TAccount>
fetchLive?(
ctx: WithAccount<TAccount> & {
token: string
/**
* Full bundle when the store implements `activeBundle` — lets a
* consumer render expiry without a second read. Absent when the
* store only exposes `active()` (no refresh-side metadata available).
*/
bundle?: TokenBundle
},
): Promise<TAccount>
/**
* Human-mode renderer. May return a single string or an array of lines;
* lines are joined with `\n` on output.
Expand All @@ -100,11 +99,7 @@ export type AttachStatusCommandOptions<TAccount extends AuthAccount = AuthAccoun
* Called when `store.active()` returns null. Default behaviour throws
* `CliError('NOT_AUTHENTICATED', …)`.
*/
onNotAuthenticated?(ctx: {
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
view: Required<ViewOptions>
flags: Record<string, unknown>
}): void | Promise<void>
onNotAuthenticated?(ctx: AttachContextBase): void | Promise<void>
}

/**
Expand Down
14 changes: 14 additions & 0 deletions src/auth/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import type { ViewOptions } from '../options.js'

/** A single authenticated identity. `id` is the stable key the store indexes on. */
export type AuthAccount = {
id: string
label?: string
[key: string]: unknown
}

/** The view + flags pair every auth attacher callback receives. */
export type AttachContextBase = {
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
view: Required<ViewOptions>
/** Consumer-attached options. The standard registrar flags (`--json` / `--ndjson`, and `--user` where attached) are stripped. */
flags: Record<string, unknown>
}

export type WithAccount<TAccount extends AuthAccount> = AttachContextBase & {
account: TAccount
}

export type PrepareInput = {
redirectUri: string
flags: Record<string, unknown>
Expand Down
Loading