@mastra/code-sdk 1.8.0-alpha.7 → 1.8.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/mastracode-gateway.d.ts +2 -0
- package/dist/agents/mastracode-gateway.d.ts.map +1 -1
- package/dist/agents/mastracode-gateway.js +29 -10
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.d.ts +1 -1
- package/dist/agents/memory.d.ts.map +1 -1
- package/dist/agents/memory.js +32 -25
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/model.d.ts +41 -1
- package/dist/agents/model.d.ts.map +1 -1
- package/dist/agents/model.js +141 -7
- package/dist/agents/model.js.map +1 -1
- package/dist/auth/account-rotation-processor.d.ts +207 -0
- package/dist/auth/account-rotation-processor.d.ts.map +1 -0
- package/dist/auth/account-rotation-processor.js +669 -0
- package/dist/auth/account-rotation-processor.js.map +1 -0
- package/dist/auth/account-routing-context.d.ts +13 -0
- package/dist/auth/account-routing-context.d.ts.map +1 -0
- package/dist/auth/account-routing-context.js +41 -0
- package/dist/auth/account-routing-context.js.map +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +2 -1
- package/dist/auth/providers/anthropic.d.ts.map +1 -1
- package/dist/auth/providers/anthropic.js +2 -8
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/github-copilot.d.ts.map +1 -1
- package/dist/auth/providers/github-copilot.js +34 -12
- package/dist/auth/providers/github-copilot.js.map +1 -1
- package/dist/auth/providers/kimi-coding.d.ts.map +1 -1
- package/dist/auth/providers/kimi-coding.js +2 -6
- package/dist/auth/providers/kimi-coding.js.map +1 -1
- package/dist/auth/providers/openai-codex.d.ts +3 -1
- package/dist/auth/providers/openai-codex.d.ts.map +1 -1
- package/dist/auth/providers/openai-codex.js +50 -24
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/providers/xai.d.ts +1 -1
- package/dist/auth/providers/xai.d.ts.map +1 -1
- package/dist/auth/providers/xai.js +36 -16
- package/dist/auth/providers/xai.js.map +1 -1
- package/dist/auth/storage.d.ts +130 -8
- package/dist/auth/storage.d.ts.map +1 -1
- package/dist/auth/storage.js +602 -39
- package/dist/auth/storage.js.map +1 -1
- package/dist/auth/types.d.ts +69 -2
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +88 -23
- package/dist/index.js.map +1 -1
- package/dist/onboarding/custom-packs.d.ts.map +1 -1
- package/dist/onboarding/custom-packs.js +3 -0
- package/dist/onboarding/custom-packs.js.map +1 -1
- package/dist/onboarding/index.js +1 -1
- package/dist/onboarding/packs.d.ts +44 -0
- package/dist/onboarding/packs.d.ts.map +1 -1
- package/dist/onboarding/packs.js +80 -2
- package/dist/onboarding/packs.js.map +1 -1
- package/dist/onboarding/settings.d.ts +28 -0
- package/dist/onboarding/settings.d.ts.map +1 -1
- package/dist/onboarding/settings.js +81 -8
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/providers/claude-max.d.ts.map +1 -1
- package/dist/providers/claude-max.js +4 -5
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/providers/github-copilot.d.ts +1 -1
- package/dist/providers/github-copilot.d.ts.map +1 -1
- package/dist/providers/github-copilot.js +89 -37
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/kimi-coding.d.ts.map +1 -1
- package/dist/providers/kimi-coding.js +16 -2
- package/dist/providers/kimi-coding.js.map +1 -1
- package/dist/providers/openai-codex.d.ts.map +1 -1
- package/dist/providers/openai-codex.js +42 -27
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/schema.d.ts +27 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +9 -0
- package/dist/schema.js.map +1 -1
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xai.js","names":[],"sources":["../../../src/auth/providers/xai.ts"],"sourcesContent":["/**\n * xAI OAuth flow (Grok)\n *\n * Ported from pi-mono's xAI OAuth implementation:\n * https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/utils/oauth/xai.ts\n *\n * xAI uses a standard RFC 8628 device authorization grant, so the flow needs\n * no inbound connection to the server. The primitives are split into\n * `startXAIDeviceLogin()` / `pollXAIDeviceLogin()` so web routes can persist\n * the JSON-serializable pending state between HTTP requests; the blocking\n * `loginXAI()` wraps them for TUI use.\n */\n\nimport { createDeviceCodePollState, pollDeviceCodeUntilComplete, stepDeviceCodePoll } from '../device-code.js';\nimport type { DeviceCodePollOutcome, DeviceCodePollState } from '../device-code.js';\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from '../types.js';\n\nconst CLIENT_ID = 'b1a00492-073a-47ea-816f-4c329264a828';\nconst DEVICE_CODE_URL = 'https://auth.x.ai/oauth2/device/code';\nconst TOKEN_URL = 'https://auth.x.ai/oauth2/token';\nconst SCOPE = 'openid profile email offline_access grok-cli:access api:access';\nconst DEVICE_CODE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';\nconst DEFAULT_TOKEN_EXPIRES_IN_SECONDS = 3600;\n// Refresh 5 minutes before actual expiry (same skew as Anthropic).\nconst REFRESH_SKEW_MS = 5 * 60 * 1000;\n\nasync function postForm(url: string, params: Record<string, string>, signal?: AbortSignal): Promise<Response> {\n return fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams(params).toString(),\n signal,\n });\n}\n\n/** The verification URI is opened by the user; only accept https URLs. */\nfunction validateVerificationUri(raw: string): string {\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n throw new Error(`xAI device authorization returned an invalid verification_uri: ${raw}`);\n }\n if (parsed.protocol !== 'https:') {\n throw new Error(`xAI device authorization returned a non-https verification_uri: ${raw}`);\n }\n return parsed.toString();\n}\n\nfunction credentialsFromTokenResponse(data: unknown, previousRefreshToken?: string): OAuthCredentials {\n const record = (data ?? {}) as Record<string, unknown>;\n const access = record.access_token;\n if (typeof access !== 'string' || access.length === 0) {\n throw new Error('xAI token response missing access_token');\n }\n\n // xAI may not rotate the refresh token on refresh; keep the previous one.\n const refresh =\n typeof record.refresh_token === 'string' && record.refresh_token.length > 0\n ? record.refresh_token\n : previousRefreshToken;\n if (!refresh) {\n throw new Error('xAI token response missing refresh_token');\n }\n\n const expiresIn =\n typeof record.expires_in === 'number' && record.expires_in > 0\n ? record.expires_in\n : DEFAULT_TOKEN_EXPIRES_IN_SECONDS;\n\n return {\n access,\n refresh,\n expires: Date.now() + expiresIn * 1000 - REFRESH_SKEW_MS,\n };\n}\n\n/**\n * Serializable pending state for an xAI device-code login. Safe to persist\n * (e.g. a `pending jsonb` column) so polling can span HTTP requests.\n */\nexport interface XAIDeviceLoginPending {\n deviceCode: string;\n userCode: string;\n /** Verification URL for the user to open (https-only, validated). */\n url: string;\n instructions: string;\n /** RFC 8628 poll-loop state (interval growth, deadline, slow_down count). */\n state: DeviceCodePollState;\n}\n\nexport type XAIDevicePollResult =\n | { status: 'complete'; credentials: OAuthCredentials }\n | { status: 'pending'; nextPollMs: number; pending: XAIDeviceLoginPending }\n | { status: 'failed'; error: string };\n\n/**\n * Start an xAI device-code login: request a user code and return the\n * serializable pending state for subsequent polls.\n */\nexport async function startXAIDeviceLogin(options?: { signal?: AbortSignal }): Promise<XAIDeviceLoginPending> {\n const response = await postForm(DEVICE_CODE_URL, { client_id: CLIENT_ID, scope: SCOPE }, options?.signal);\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(`Failed to initiate xAI device authorization: ${response.status}${text ? ` ${text}` : ''}`);\n }\n\n const data = (await response.json()) as {\n device_code?: string;\n user_code?: string;\n verification_uri?: string;\n verification_uri_complete?: string;\n interval?: number;\n expires_in?: number;\n };\n\n if (!data.device_code || !data.user_code || !data.verification_uri) {\n throw new Error('xAI device authorization response missing required fields');\n }\n\n const url = validateVerificationUri(data.verification_uri_complete ?? data.verification_uri);\n\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n url,\n instructions: `Enter code: ${data.user_code}`,\n state: createDeviceCodePollState({\n intervalSeconds: data.interval,\n expiresInSeconds: typeof data.expires_in === 'number' && data.expires_in > 0 ? data.expires_in : 600,\n }),\n };\n}\n\nasync function pollXAITokenOnce(\n pending: XAIDeviceLoginPending,\n signal?: AbortSignal,\n): Promise<DeviceCodePollOutcome<OAuthCredentials>> {\n const response = await postForm(\n TOKEN_URL,\n {\n grant_type: DEVICE_CODE_GRANT_TYPE,\n device_code: pending.deviceCode,\n client_id: CLIENT_ID,\n },\n signal,\n );\n\n if (response.ok) {\n const data = (await response.json()) as unknown;\n try {\n return { status: 'complete', result: credentialsFromTokenResponse(data) };\n } catch (error) {\n return { status: 'failed', error: error instanceof Error ? error.message : String(error) };\n }\n }\n\n const text = await response.text().catch(() => '');\n let body: { error?: string; interval?: number } = {};\n try {\n body = JSON.parse(text) as { error?: string; interval?: number };\n } catch {\n // Non-JSON error body — fail loudly below with the raw text.\n }\n\n switch (body.error) {\n case 'authorization_pending':\n return { status: 'pending', intervalSeconds: body.interval };\n case 'slow_down':\n return { status: 'slow_down', intervalSeconds: body.interval };\n case 'access_denied':\n case 'authorization_denied':\n return { status: 'failed', error: 'xAI authorization was denied' };\n case 'expired_token':\n return { status: 'failed', error: 'xAI device code expired before authorization completed' };\n default:\n return {\n status: 'failed',\n error: `xAI device authorization failed: ${response.status}${text ? ` ${text}` : ''}`,\n };\n }\n}\n\n/**\n * Perform exactly one upstream poll for a pending xAI device login.\n * Returns the updated pending state so callers (e.g. web routes) can persist\n * slow_down interval growth between polls. Never throws for flow-level\n * conditions.\n */\nexport async function pollXAIDeviceLogin(\n pending: XAIDeviceLoginPending,\n options?: { signal?: AbortSignal },\n): Promise<XAIDevicePollResult> {\n const step = await stepDeviceCodePoll(pending.state, () => pollXAITokenOnce(pending, options?.signal));\n\n switch (step.status) {\n case 'complete':\n return { status: 'complete', credentials: step.result };\n case 'failed':\n return { status: 'failed', error: step.error };\n case 'pending':\n case 'slow_down':\n return {\n status: 'pending',\n nextPollMs: step.nextPollMs,\n pending: { ...pending, state: step.state },\n };\n }\n}\n\n/**\n * Login with xAI OAuth (device-code flow), blocking until authorized.\n */\nexport async function loginXAI(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const pending = await startXAIDeviceLogin({ signal: callbacks.signal });\n\n callbacks.onAuth({ url: pending.url, instructions: pending.instructions });\n callbacks.onProgress?.('Waiting for xAI device authorization...');\n\n return pollDeviceCodeUntilComplete({\n state: pending.state,\n pollOnce: () => pollXAITokenOnce(pending, callbacks.signal),\n signal: callbacks.signal,\n });\n}\n\n/**\n * Refresh xAI OAuth token\n */\nexport async function refreshXAIToken(refreshToken: string, signal?: AbortSignal): Promise<OAuthCredentials> {\n const response = await postForm(\n TOKEN_URL,\n {\n grant_type: 'refresh_token',\n client_id: CLIENT_ID,\n refresh_token: refreshToken,\n },\n signal,\n );\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(`xAI token refresh failed: ${response.status}${text ? ` ${text}` : ''}`);\n }\n\n return credentialsFromTokenResponse((await response.json()) as unknown, refreshToken);\n}\n\nexport const xaiOAuthProvider: OAuthProviderInterface = {\n id: 'xai',\n name: 'xAI (Grok)',\n\n async login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n return loginXAI(callbacks);\n },\n\n async refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n return refreshXAIToken(credentials.refresh);\n },\n\n getApiKey(credentials: OAuthCredentials): string {\n return credentials.access;\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"xai.js","names":[],"sources":["../../../src/auth/providers/xai.ts"],"sourcesContent":["/**\n * xAI OAuth flow (Grok)\n *\n * Ported from pi-mono's xAI OAuth implementation:\n * https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/utils/oauth/xai.ts\n *\n * xAI uses a standard RFC 8628 device authorization grant, so the flow needs\n * no inbound connection to the server. The primitives are split into\n * `startXAIDeviceLogin()` / `pollXAIDeviceLogin()` so web routes can persist\n * the JSON-serializable pending state between HTTP requests; the blocking\n * `loginXAI()` wraps them for TUI use.\n */\n\nimport { createDeviceCodePollState, pollDeviceCodeUntilComplete, stepDeviceCodePoll } from '../device-code.js';\nimport type { DeviceCodePollOutcome, DeviceCodePollState } from '../device-code.js';\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from '../types.js';\n\nconst CLIENT_ID = 'b1a00492-073a-47ea-816f-4c329264a828';\nconst DEVICE_CODE_URL = 'https://auth.x.ai/oauth2/device/code';\nconst TOKEN_URL = 'https://auth.x.ai/oauth2/token';\nconst SCOPE = 'openid profile email offline_access grok-cli:access api:access';\nconst DEVICE_CODE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';\nconst DEFAULT_TOKEN_EXPIRES_IN_SECONDS = 3600;\nconst REQUEST_TIMEOUT_MS = 30_000;\n// Refresh 5 minutes before actual expiry (same skew as Anthropic).\nconst REFRESH_SKEW_MS = 5 * 60 * 1000;\n\nasync function postForm(url: string, params: Record<string, string>, signal?: AbortSignal): Promise<Response> {\n const timeoutSignal = AbortSignal.timeout(REQUEST_TIMEOUT_MS);\n return fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams(params).toString(),\n signal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n });\n}\n\n/** The verification URI is opened by the user; only accept https URLs. */\nfunction validateVerificationUri(raw: string): string {\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n throw new Error('xAI device authorization returned an invalid verification_uri');\n }\n if (parsed.protocol !== 'https:') {\n throw new Error('xAI device authorization returned a non-https verification_uri');\n }\n return parsed.toString();\n}\n\nfunction credentialsFromTokenResponse(\n data: unknown,\n previousRefreshToken?: string,\n previousIdToken?: string,\n): OAuthCredentials {\n const record = (data ?? {}) as Record<string, unknown>;\n const access = record.access_token;\n if (typeof access !== 'string' || access.length === 0) {\n throw new Error('xAI token response missing access_token');\n }\n\n // xAI may not rotate the refresh token on refresh; keep the previous one.\n const refresh =\n typeof record.refresh_token === 'string' && record.refresh_token.length > 0\n ? record.refresh_token\n : previousRefreshToken;\n if (!refresh) {\n throw new Error('xAI token response missing refresh_token');\n }\n\n const expiresIn =\n typeof record.expires_in === 'number' && record.expires_in > 0\n ? record.expires_in\n : DEFAULT_TOKEN_EXPIRES_IN_SECONDS;\n\n return {\n access,\n refresh,\n expires: Date.now() + expiresIn * 1000 - REFRESH_SKEW_MS,\n // Kept so the account label can resolve the email claim later; xAI's\n // refresh responses re-issue it, and the previous one is carried forward\n // when they don't.\n idToken: typeof record.id_token === 'string' && record.id_token.length > 0 ? record.id_token : previousIdToken,\n };\n}\n\n/**\n * Serializable pending state for an xAI device-code login. Safe to persist\n * (e.g. a `pending jsonb` column) so polling can span HTTP requests.\n */\nexport interface XAIDeviceLoginPending {\n deviceCode: string;\n userCode: string;\n /** Verification URL for the user to open (https-only, validated). */\n url: string;\n instructions: string;\n /** RFC 8628 poll-loop state (interval growth, deadline, slow_down count). */\n state: DeviceCodePollState;\n}\n\nexport type XAIDevicePollResult =\n | { status: 'complete'; credentials: OAuthCredentials }\n | { status: 'pending'; nextPollMs: number; pending: XAIDeviceLoginPending }\n | { status: 'failed'; error: string };\n\n/**\n * Start an xAI device-code login: request a user code and return the\n * serializable pending state for subsequent polls.\n */\nexport async function startXAIDeviceLogin(options?: { signal?: AbortSignal }): Promise<XAIDeviceLoginPending> {\n const response = await postForm(DEVICE_CODE_URL, { client_id: CLIENT_ID, scope: SCOPE }, options?.signal);\n\n if (!response.ok) {\n throw new Error(`Failed to initiate xAI device authorization: ${response.status}`);\n }\n\n const data = (await response.json()) as {\n device_code?: string;\n user_code?: string;\n verification_uri?: string;\n verification_uri_complete?: string;\n interval?: number;\n expires_in?: number;\n };\n\n if (!data.device_code || !data.user_code || !data.verification_uri) {\n throw new Error('xAI device authorization response missing required fields');\n }\n\n const url = validateVerificationUri(data.verification_uri_complete ?? data.verification_uri);\n\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n url,\n instructions: `Enter code: ${data.user_code}`,\n state: createDeviceCodePollState({\n intervalSeconds: data.interval,\n expiresInSeconds: typeof data.expires_in === 'number' && data.expires_in > 0 ? data.expires_in : 600,\n }),\n };\n}\n\nasync function pollXAITokenOnce(\n pending: XAIDeviceLoginPending,\n signal?: AbortSignal,\n): Promise<DeviceCodePollOutcome<OAuthCredentials>> {\n const response = await postForm(\n TOKEN_URL,\n {\n grant_type: DEVICE_CODE_GRANT_TYPE,\n device_code: pending.deviceCode,\n client_id: CLIENT_ID,\n },\n signal,\n );\n\n if (response.ok) {\n const data = (await response.json()) as unknown;\n try {\n return { status: 'complete', result: credentialsFromTokenResponse(data) };\n } catch (error) {\n return { status: 'failed', error: error instanceof Error ? error.message : String(error) };\n }\n }\n\n const text = await response.text().catch(() => '');\n let body: { error?: string; interval?: number } = {};\n try {\n body = JSON.parse(text) as { error?: string; interval?: number };\n } catch {\n // Non-JSON upstream bodies are intentionally omitted from user-visible errors.\n }\n\n switch (body.error) {\n case 'authorization_pending':\n return { status: 'pending', intervalSeconds: body.interval };\n case 'slow_down':\n return { status: 'slow_down', intervalSeconds: body.interval };\n case 'access_denied':\n case 'authorization_denied':\n return { status: 'failed', error: 'xAI authorization was denied' };\n case 'expired_token':\n return { status: 'failed', error: 'xAI device code expired before authorization completed' };\n default:\n // Status only: `body.error` is untrusted upstream text (RFC 6749 does not\n // constrain it), so echoing it would render provider-controlled content\n // in the TUI. The known flow codes above are handled explicitly.\n return {\n status: 'failed',\n error: `xAI device authorization failed: ${response.status}`,\n };\n }\n}\n\n/**\n * Perform exactly one upstream poll for a pending xAI device login.\n * Returns the updated pending state so callers (e.g. web routes) can persist\n * slow_down interval growth between polls. Never throws for flow-level\n * conditions.\n */\nexport async function pollXAIDeviceLogin(\n pending: XAIDeviceLoginPending,\n options?: { signal?: AbortSignal },\n): Promise<XAIDevicePollResult> {\n const step = await stepDeviceCodePoll(pending.state, () => pollXAITokenOnce(pending, options?.signal));\n\n switch (step.status) {\n case 'complete':\n return { status: 'complete', credentials: step.result };\n case 'failed':\n return { status: 'failed', error: step.error };\n case 'pending':\n case 'slow_down':\n return {\n status: 'pending',\n nextPollMs: step.nextPollMs,\n pending: { ...pending, state: step.state },\n };\n }\n}\n\n/**\n * Login with xAI OAuth (device-code flow), blocking until authorized.\n */\nexport async function loginXAI(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const pending = await startXAIDeviceLogin({ signal: callbacks.signal });\n\n callbacks.onAuth({ url: pending.url, instructions: pending.instructions });\n callbacks.onProgress?.('Waiting for xAI device authorization...');\n\n return pollDeviceCodeUntilComplete({\n state: pending.state,\n pollOnce: () => pollXAITokenOnce(pending, callbacks.signal),\n signal: callbacks.signal,\n });\n}\n\n/**\n * Refresh xAI OAuth token\n */\nexport async function refreshXAIToken(\n refreshToken: string,\n signal?: AbortSignal,\n previousIdToken?: string,\n): Promise<OAuthCredentials> {\n const response = await postForm(\n TOKEN_URL,\n {\n grant_type: 'refresh_token',\n client_id: CLIENT_ID,\n refresh_token: refreshToken,\n },\n signal,\n );\n\n if (!response.ok) {\n throw new Error(`xAI token refresh failed: ${response.status}`);\n }\n\n return credentialsFromTokenResponse((await response.json()) as unknown, refreshToken, previousIdToken);\n}\n\n/** Decode the email claim out of an id_token JWT payload (no verification). */\nfunction emailFromIdToken(idToken: string | undefined): string | undefined {\n if (typeof idToken !== 'string') return undefined;\n const parts = idToken.split('.');\n if (parts.length !== 3) return undefined;\n try {\n const padded = (parts[1] ?? '').replace(/-/g, '+').replace(/_/g, '/');\n const json = JSON.parse(Buffer.from(padded, 'base64').toString('utf8')) as { email?: unknown };\n return typeof json.email === 'string' && json.email.length > 0 ? json.email : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport const xaiOAuthProvider: OAuthProviderInterface = {\n id: 'xai',\n name: 'xAI (Grok)',\n\n async login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n return loginXAI(callbacks);\n },\n\n async refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n return refreshXAIToken(credentials.refresh, undefined, credentials.idToken as string | undefined);\n },\n\n getApiKey(credentials: OAuthCredentials): string {\n return credentials.access;\n },\n\n getAccountLabel(credentials: OAuthCredentials): Promise<string | undefined> {\n return Promise.resolve(emailFromIdToken(credentials.idToken as string | undefined));\n },\n\n /**\n * The account's email, read from the id token — one subscription per email,\n * so this distinguishes two xAI accounts from a re-authorization of one.\n */\n getAccountIdentity(credentials: OAuthCredentials): string | undefined {\n return emailFromIdToken(credentials.idToken as string | undefined);\n },\n};\n"],"mappings":"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"}
|
package/dist/auth/storage.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Credential storage for API keys and OAuth tokens.
|
|
3
3
|
* Handles loading, saving, and refreshing credentials from auth.json.
|
|
4
4
|
*/
|
|
5
|
-
import type { AuthCredential, OAuthLoginCallbacks, OAuthProviderId, OAuthProviderInterface } from './types.js';
|
|
5
|
+
import type { AuthCredential, OAuthAccountRecord, OAuthCredentialSnapshot, OAuthCredentials, OAuthLoginCallbacks, OAuthProviderId, OAuthProviderInterface } from './types.js';
|
|
6
6
|
/**
|
|
7
7
|
* Best/default models for each OAuth provider.
|
|
8
8
|
* Used when auto-selecting a model after login.
|
|
@@ -28,12 +28,31 @@ export declare class AuthStorage {
|
|
|
28
28
|
* Reload credentials from disk.
|
|
29
29
|
*/
|
|
30
30
|
reload(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Bring auth.json up to the multi-account registry format. Runs on every
|
|
33
|
+
* load; saves only when something actually changed.
|
|
34
|
+
*
|
|
35
|
+
* 1. A legacy OAuth slot with no registry gets one adopted active entry
|
|
36
|
+
* (the slot's tokens stay put — the entry mirrors them).
|
|
37
|
+
* 2. When the slot's refresh token differs from the active entry's, an
|
|
38
|
+
* external writer (older build, another worktree) owns the slot — the
|
|
39
|
+
* slot wins and its tokens are adopted onto the active entry.
|
|
40
|
+
* 3. A registry with no active entry (hand-edited) self-heals to its first
|
|
41
|
+
* entry; malformed `accounts:` values are skipped, never fatal.
|
|
42
|
+
* 4. A registry whose legacy slot disappeared (partial write, an external
|
|
43
|
+
* hand-edit) self-heals by mirroring the active entry's tokens back into
|
|
44
|
+
* the slot, so `isLoggedIn()`/`getOAuthCredential()` keep agreeing with
|
|
45
|
+
* `listAccounts()`. `remove()`/`logout()` clear the registry with the
|
|
46
|
+
* slot, so they never leave the shape this heals.
|
|
47
|
+
*/
|
|
48
|
+
private migrate;
|
|
31
49
|
/**
|
|
32
50
|
* Save credentials to disk.
|
|
33
51
|
*/
|
|
34
52
|
private save;
|
|
35
53
|
/**
|
|
36
|
-
* Get credential for a provider.
|
|
54
|
+
* Get credential for a provider. Registry entries (type 'oauth-account')
|
|
55
|
+
* live under `accounts:` keys and never surface here.
|
|
37
56
|
*/
|
|
38
57
|
get(provider: string): AuthCredential | undefined;
|
|
39
58
|
/**
|
|
@@ -41,7 +60,10 @@ export declare class AuthStorage {
|
|
|
41
60
|
*/
|
|
42
61
|
set(provider: string, credential: AuthCredential): void;
|
|
43
62
|
/**
|
|
44
|
-
* Remove credential for a provider.
|
|
63
|
+
* Remove credential for a provider, including its account registry.
|
|
64
|
+
* Clearing only the slot would leave the registry behind, and the next
|
|
65
|
+
* load's migration would heal the slot back from it — resurrecting the
|
|
66
|
+
* provider the caller just signed out.
|
|
45
67
|
*/
|
|
46
68
|
remove(provider: string): void;
|
|
47
69
|
/**
|
|
@@ -77,16 +99,116 @@ export declare class AuthStorage {
|
|
|
77
99
|
*/
|
|
78
100
|
loadStoredApiKeysIntoEnv(providerEnvVars: Record<string, string | undefined>): void;
|
|
79
101
|
/**
|
|
80
|
-
* Login to an OAuth provider.
|
|
102
|
+
* Login to an OAuth provider. Resolves to the registered account record.
|
|
103
|
+
* Pass `activate: false` to add the account without making it active (the
|
|
104
|
+
* first account for a provider is always activated — a provider with
|
|
105
|
+
* accounts must have an active one).
|
|
81
106
|
*/
|
|
82
|
-
login(providerId: OAuthProviderId, callbacks: OAuthLoginCallbacks
|
|
107
|
+
login(providerId: OAuthProviderId, callbacks: OAuthLoginCallbacks, opts?: {
|
|
108
|
+
replaceAccountId?: string;
|
|
109
|
+
activate?: boolean;
|
|
110
|
+
}): Promise<OAuthAccountRecord>;
|
|
83
111
|
/**
|
|
84
|
-
* Logout from a provider.
|
|
112
|
+
* Logout from a provider: remove the legacy slot and every registered account.
|
|
85
113
|
*/
|
|
86
114
|
logout(provider: string): void;
|
|
115
|
+
private accountPrefixFor;
|
|
116
|
+
private accountKeyFor;
|
|
117
|
+
/** Registry entries for a provider in JSON insertion order (malformed values skipped). */
|
|
118
|
+
private accountEntries;
|
|
119
|
+
/** Adopt a legacy slot credential as the registry's first active entry. */
|
|
120
|
+
private adoptSlot;
|
|
121
|
+
/**
|
|
122
|
+
* Registered OAuth accounts for a provider, in insertion order. Copies —
|
|
123
|
+
* callers cannot corrupt unsaved storage state by mutating a record.
|
|
124
|
+
*/
|
|
125
|
+
listAccounts(providerId: string): OAuthAccountRecord[];
|
|
126
|
+
/**
|
|
127
|
+
* The provider's active registry entry, if a registry exists. A copy.
|
|
128
|
+
*/
|
|
129
|
+
getActiveAccount(providerId: string): OAuthAccountRecord | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* Register OAuth credentials as an account for a provider, making it active
|
|
132
|
+
* unless `activate: false` is passed.
|
|
133
|
+
*
|
|
134
|
+
* With `replaceAccountId` (re-authentication of a picked account), the
|
|
135
|
+
* target entry's tokens are replaced in place — id re-keyed to the new
|
|
136
|
+
* refresh-token hash, label/position/addedAt preserved — because providers
|
|
137
|
+
* rotate refresh tokens per authorization, so the picked account's old id
|
|
138
|
+
* never matches the new token hash. Re-authentication keeps the target's
|
|
139
|
+
* active state: an inactive account stays inactive and the currently active
|
|
140
|
+
* account keeps the legacy slot. Otherwise, when the new credentials
|
|
141
|
+
* hash to an existing entry's id (same refresh token), that entry is
|
|
142
|
+
* updated in place; a genuinely new account is appended and activated.
|
|
143
|
+
*
|
|
144
|
+
* `activate: false` only applies to the plain add path: the new/updated entry
|
|
145
|
+
* keeps the active state it had, and the previously active account stays
|
|
146
|
+
* active. The first account of a provider is activated regardless.
|
|
147
|
+
*/
|
|
148
|
+
addAccount(providerId: string, creds: OAuthCredentials, opts?: {
|
|
149
|
+
label?: string;
|
|
150
|
+
replaceAccountId?: string;
|
|
151
|
+
activate?: boolean;
|
|
152
|
+
}): Promise<OAuthAccountRecord>;
|
|
153
|
+
/**
|
|
154
|
+
* Activate an account: move the active tokens out of the legacy slot back
|
|
155
|
+
* into the previously active entry, and the target's tokens into the slot
|
|
156
|
+
* (never copy — one home per token set). With no `instanceId`, rotate to
|
|
157
|
+
* the next entry in insertion order, wrapping once to the front; returns
|
|
158
|
+
* undefined when there is no other entry to rotate to.
|
|
159
|
+
*/
|
|
160
|
+
activateAccount(providerId: string, instanceId?: string): OAuthAccountRecord | undefined;
|
|
161
|
+
/**
|
|
162
|
+
* Activate an account in memory only — the caller owns reload/save. Move the
|
|
163
|
+
* active tokens out of the legacy slot back into the previously active
|
|
164
|
+
* entry, and the target's tokens into the slot (never copy — one home per
|
|
165
|
+
* token set). With no `instanceId`, rotate to the next entry in insertion
|
|
166
|
+
* order, wrapping once to the front; returns undefined when there is no
|
|
167
|
+
* other entry to rotate to.
|
|
168
|
+
*/
|
|
169
|
+
private activateInMemory;
|
|
170
|
+
/**
|
|
171
|
+
* Remove an account from the registry. If it was active, the next entry in
|
|
172
|
+
* insertion order is activated; when it was the last one, the legacy slot
|
|
173
|
+
* is removed too (full sign-out for that provider).
|
|
174
|
+
*/
|
|
175
|
+
removeAccount(providerId: string, instanceId: string): void;
|
|
176
|
+
/**
|
|
177
|
+
* Rename an account's label.
|
|
178
|
+
*/
|
|
179
|
+
renameAccount(providerId: string, instanceId: string, label: string): void;
|
|
180
|
+
/**
|
|
181
|
+
* Persist refreshed credentials for the account that initiated the refresh.
|
|
182
|
+
* The legacy slot is updated only if that account is still active when the
|
|
183
|
+
* refresh completes; otherwise a delayed refresh could overwrite a newer
|
|
184
|
+
* activation.
|
|
185
|
+
*/
|
|
186
|
+
private persistRefreshedCredential;
|
|
187
|
+
/**
|
|
188
|
+
* Refresh one account instance through the per-instance dedupe map. Used
|
|
189
|
+
* for sibling refreshes during the rotation walk, so a concurrent
|
|
190
|
+
* `getApiKey` that reloads storage mid-walk (after the candidate was
|
|
191
|
+
* activated but before its refresh resolves) joins the same refresh
|
|
192
|
+
* instead of double-spending a single-use refresh token.
|
|
193
|
+
*/
|
|
194
|
+
private refreshInstance;
|
|
195
|
+
/**
|
|
196
|
+
* Get a ready-to-use OAuth credential snapshot, auto-refreshing if needed.
|
|
197
|
+
* A failed refresh leaves the active account unchanged and returns undefined;
|
|
198
|
+
* the account-rotation processor owns switching so it can persist a visible
|
|
199
|
+
* account-switch notice with the request that triggered the change.
|
|
200
|
+
*/
|
|
201
|
+
getOAuthCredential(providerId: string, accountInstanceId?: string): Promise<OAuthCredentialSnapshot | undefined>;
|
|
202
|
+
/** Get API key for a provider, refreshing OAuth tokens if needed. */
|
|
203
|
+
getApiKey(providerId: string, accountInstanceId?: string): Promise<string | undefined>;
|
|
87
204
|
/**
|
|
88
|
-
*
|
|
205
|
+
* Force one refresh of the active OAuth account's tokens, regardless of
|
|
206
|
+
* expiry. The account-rotation error processor calls this when a provider
|
|
207
|
+
* rejects a not-yet-expired token (401/403) — server-side clock skew and
|
|
208
|
+
* refresh-token races surface that way. Returns the fresh access token, or
|
|
209
|
+
* undefined when the refresh fails or there is no OAuth credential.
|
|
210
|
+
* Shares the per-instance refresh dedupe with `getApiKey`.
|
|
89
211
|
*/
|
|
90
|
-
|
|
212
|
+
forceRefreshActiveAccount(providerId: string, accountInstanceId?: string): Promise<string | undefined>;
|
|
91
213
|
}
|
|
92
214
|
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,KAAK,EACV,cAAc,EAEd,kBAAkB,EAElB,uBAAuB,EACvB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CASnE,CAAC;AAWF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,eAAe,GAAG,sBAAsB,GAAG,SAAS,CAExF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,sBAAsB,EAAE,CAE5D;AAyED;;GAEG;AACH,qBAAa,WAAW;IAIV,OAAO,CAAC,QAAQ;IAH5B,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,eAAe,CAA4D;gBAE/D,QAAQ,GAAE,MAA2C;IAIzE;;OAEG;IACH,MAAM,IAAI,IAAI;IAad;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,OAAO;IAsFf;;OAEG;IACH,OAAO,CAAC,IAAI;IAmBZ;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAKjD;;OAEG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,GAAG,IAAI;IAMvD;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAU9B;;OAEG;IACH,IAAI,IAAI,MAAM,EAAE;IAIhB;;OAEG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI9B;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKrC;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAK1C;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKrD;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAOrE;;;;OAIG;IACH,wBAAwB,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI;IAWnF;;;;;OAKG;IACG,KAAK,CACT,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,mBAAmB,EAC9B,IAAI,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GACvD,OAAO,CAAC,kBAAkB,CAAC;IAa9B;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQ9B,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,aAAa;IAIrB,0FAA0F;IAC1F,OAAO,CAAC,cAAc;IAStB,2EAA2E;IAC3E,OAAO,CAAC,SAAS;IAiBjB;;;OAGG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAItD;;OAEG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAKpE;;;;;;;;;;;;;;;;;OAiBG;IACG,UAAU,CACd,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,gBAAgB,EACvB,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GACvE,OAAO,CAAC,kBAAkB,CAAC;IAyJ9B;;;;;;OAMG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAOxF;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IA+CxB;;;;OAIG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IA8B3D;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAS1E;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;IAwBlC;;;;;;OAMG;YACW,eAAe;IA2B7B;;;;;OAKG;IACG,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC;IAsE/C,qEAAqE;IAC/D,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAc5F;;;;;;;OAOG;IACG,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CA8C7G"}
|