zidane 9.1.11 → 9.1.13
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/{acp-CxFKfjZ7.js → acp-Cz5mFUjB.js} +3 -3
- package/dist/{acp-CxFKfjZ7.js.map → acp-Cz5mFUjB.js.map} +1 -1
- package/dist/acp-cli.js +4 -4
- package/dist/acp.js +1 -1
- package/dist/{auth-store-port-8BMUBfqw.js → auth-store-port-CDJa8Q8U.js} +2 -2
- package/dist/{auth-store-port-8BMUBfqw.js.map → auth-store-port-CDJa8Q8U.js.map} +1 -1
- package/dist/{auto-update-restart-_S0w600V.js → auto-update-restart-B4pU7Qgf.js} +10 -10
- package/dist/{auto-update-restart-_S0w600V.js.map → auto-update-restart-B4pU7Qgf.js.map} +1 -1
- package/dist/chat.js +9 -9
- package/dist/{cli-shared-C6qeun-_.js → cli-shared-BVtiiICW.js} +3 -3
- package/dist/{cli-shared-C6qeun-_.js.map → cli-shared-BVtiiICW.js.map} +1 -1
- package/dist/{credentials-BPG17Xuo.js → credentials-axv5VvMR.js} +2 -2
- package/dist/{credentials-BPG17Xuo.js.map → credentials-axv5VvMR.js.map} +1 -1
- package/dist/daemon-cli.js +2 -2
- package/dist/{discovery-DWH6e_zd.js → discovery-D7qVZWzq.js} +4 -4
- package/dist/{discovery-DWH6e_zd.js.map → discovery-D7qVZWzq.js.map} +1 -1
- package/dist/{engine-C_Ndjp0u.js → engine-DjM5NPIf.js} +3 -3
- package/dist/{engine-C_Ndjp0u.js.map → engine-DjM5NPIf.js.map} +1 -1
- package/dist/{executor-BUWZhsfn.js → executor-DlW7qAeN.js} +2 -2
- package/dist/{executor-BUWZhsfn.js.map → executor-DlW7qAeN.js.map} +1 -1
- package/dist/extensions/testing.js +2 -2
- package/dist/{extensions-D4psC965.js → extensions-D7DeZNpn.js} +6 -6
- package/dist/{extensions-D4psC965.js.map → extensions-D7DeZNpn.js.map} +1 -1
- package/dist/extensions.js +5 -5
- package/dist/{google-CTQu7Zz-.js → google-D1zjAViO.js} +2 -2
- package/dist/{google-CTQu7Zz-.js.map → google-D1zjAViO.js.map} +1 -1
- package/dist/{host-D-sOuh0K.js → host-Ds3RDlG5.js} +9 -9
- package/dist/{host-D-sOuh0K.js.map → host-Ds3RDlG5.js.map} +1 -1
- package/dist/{host-signals-Dlxd0YYP.js → host-signals-C8x5Yso0.js} +5 -5
- package/dist/{host-signals-Dlxd0YYP.js.map → host-signals-C8x5Yso0.js.map} +1 -1
- package/dist/{host-version-smAFds1j.js → host-version-BGZumnpZ.js} +2 -2
- package/dist/{host-version-smAFds1j.js.map → host-version-BGZumnpZ.js.map} +1 -1
- package/dist/index.js +5 -5
- package/dist/ipc/remote.js +3 -3
- package/dist/{ipc-DnSKoy00.js → ipc-DGfuNEfR.js} +4 -4
- package/dist/{ipc-DnSKoy00.js.map → ipc-DGfuNEfR.js.map} +1 -1
- package/dist/ipc.js +4 -4
- package/dist/{links-BcfGBoRt.js → links-D_1RhPh5.js} +8 -8
- package/dist/{links-BcfGBoRt.js.map → links-D_1RhPh5.js.map} +1 -1
- package/dist/{loaded-entry-C0h8OMwN.js → loaded-entry-CLva6GQT.js} +2 -2
- package/dist/{loaded-entry-C0h8OMwN.js.map → loaded-entry-CLva6GQT.js.map} +1 -1
- package/dist/{memory-CZNbjYxJ.js → memory-CaFXUvQs.js} +15 -15
- package/dist/{memory-CZNbjYxJ.js.map → memory-CaFXUvQs.js.map} +1 -1
- package/dist/{path-display-DfFjoqUy.js → path-display-ZIWdFaTI.js} +3 -3
- package/dist/{path-display-DfFjoqUy.js.map → path-display-ZIWdFaTI.js.map} +1 -1
- package/dist/providers/google.js +1 -1
- package/dist/{providers-CCPHw25p.js → providers-CsYrxuX1.js} +2 -2
- package/dist/{providers-CCPHw25p.js.map → providers-CsYrxuX1.js.map} +1 -1
- package/dist/providers.js +1 -1
- package/dist/{registry-C-U_tMPi.js → registry-BY45AOA-.js} +2 -2
- package/dist/{registry-C-U_tMPi.js.map → registry-BY45AOA-.js.map} +1 -1
- package/dist/{registry-d-R3YZs1.js → registry-DTotchq6.js} +2 -2
- package/dist/{registry-d-R3YZs1.js.map → registry-DTotchq6.js.map} +1 -1
- package/dist/{registry-DHSQ4fdV.js → registry-Dl6261Xh.js} +2 -2
- package/dist/{registry-DHSQ4fdV.js.map → registry-Dl6261Xh.js.map} +1 -1
- package/dist/{remote-hosts-D77F5uTa.js → remote-hosts-usqMiMbs.js} +4 -4
- package/dist/{remote-hosts-D77F5uTa.js.map → remote-hosts-usqMiMbs.js.map} +1 -1
- package/dist/{setting-Cog4WQc1.js → setting-DzTMJIV3.js} +2 -2
- package/dist/{setting-Cog4WQc1.js.map → setting-DzTMJIV3.js.map} +1 -1
- package/dist/{settings-keys-B1q2NwvM.js → settings-keys-DDrfnBHi.js} +2 -2
- package/dist/{settings-keys-B1q2NwvM.js.map → settings-keys-DDrfnBHi.js.map} +1 -1
- package/dist/{system-freeze-CMY7QnoD.js → system-freeze-CY4Hc9WX.js} +2 -2
- package/dist/{system-freeze-CMY7QnoD.js.map → system-freeze-CY4Hc9WX.js.map} +1 -1
- package/dist/tui.js +15 -15
- package/dist/{version-DiGN0H-_.js → version-Bu3Nc8-U.js} +2 -2
- package/dist/{version-DiGN0H-_.js.map → version-Bu3Nc8-U.js.map} +1 -1
- package/dist/{wire-D4NlIUMg.js → wire-BKcREhuL.js} +2 -2
- package/dist/{wire-D4NlIUMg.js.map → wire-BKcREhuL.js.map} +1 -1
- package/dist/{ws-6EUa8pzM.js → ws-DriNRyP-.js} +4 -4
- package/dist/{ws-6EUa8pzM.js.map → ws-DriNRyP-.js.map} +1 -1
- package/dist/{ws-client-5i2lbQnC.js → ws-client-PZdbO0fj.js} +2 -2
- package/dist/{ws-client-5i2lbQnC.js.map → ws-client-PZdbO0fj.js.map} +1 -1
- package/docs/RELEASE.md +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-C-U_tMPi.js","names":[],"sources":["../src/extensions/integrations/oauth.ts","../src/extensions/integrations/connect.ts","../src/extensions/integrations/connections.ts","../src/extensions/integrations/refresh.ts","../src/extensions/integrations/registry.ts"],"sourcesContent":["/**\n * The OAuth flows of an integration's `oauth` method: authorization code\n * with PKCE (RFC 7636) and the device authorization grant (RFC 8628), plus\n * the refresh-token grant.\n *\n * PKCE runs on the `zidane/oauth` kit (`src/oauth-entry.ts`): the loopback\n * callback server and page, `generatePkce`, and the redirect-or-paste race\n * (`awaitAuthorizationCode`), so a remote sign-in (`callbackServer: false`)\n * works as it does for provider sign-ins. The kit is imported lazily:\n * `node:http` stays off the graph until a flow runs.\n *\n * Every network call goes through {@link OAuthIo.fetch} and every wait\n * through {@link OAuthIo.wait}, so tests drive a fake server and clock.\n */\n\nimport type { OAuthLoginCallbacks } from '@earendil-works/pi-ai/oauth'\nimport type { Credential, IntegrationMethod } from '../api/sessions'\n\n/** An `oauth` integration method. */\nexport type OAuthIntegrationMethod = Extract<IntegrationMethod, { type: 'oauth' }>\n\n/** An OAuth credential. */\nexport type OAuthCredential = Extract<Credential, { type: 'oauth' }>\n\n/** The I/O an OAuth flow uses. */\nexport interface OAuthIo {\n /** Sends an HTTP request (the global `fetch` by default). */\n fetch: (url: string, init: RequestInit) => Promise<Response>\n /** Resolves after `ms`, or rejects when `signal` aborts. Device polling waits through it. */\n wait: (ms: number, signal: AbortSignal) => Promise<void>\n /** The current time in ms; expiry times are computed from it. */\n now: () => number\n}\n\n/** What a flow or a refresh yields. */\nexport interface OAuthGrant {\n /** The credential to hand out. */\n credential: OAuthCredential\n /** The refresh token, when the server issued one. */\n refreshToken?: string\n}\n\n/** A token endpoint refused a request. */\nexport class OAuthTokenError extends Error {\n /**\n * @param code - The OAuth `error` code (`invalid_grant`, `authorization_pending`, …), or `http_<status>`.\n * @param description - The server's `error_description`, when given.\n * @param status - The HTTP status.\n */\n constructor(readonly code: string, readonly description: string | undefined, readonly status: number) {\n super(`OAuth token request failed (${status}): ${[code, description].filter(Boolean).join(': ')}`)\n this.name = 'OAuthTokenError'\n }\n}\n\n/** A hung token endpoint must not hold a resolve forever. */\nconst TOKEN_REQUEST_TIMEOUT_MS = 30_000\n/** RFC 8628 §3.2: default polling interval. */\nconst DEFAULT_POLL_INTERVAL_S = 5\n/** RFC 8628 §3.5: `slow_down` adds 5 seconds. */\nconst SLOW_DOWN_STEP_S = 5\n/** When the device endpoint omits `expires_in`. */\nconst DEFAULT_DEVICE_EXPIRY_S = 900\n\n/** Default {@link OAuthIo}: real fetch, timers and clock. */\nexport const defaultOAuthIo: OAuthIo = {\n fetch: (url, init) => fetch(url, init),\n wait: (ms, signal) => new Promise<void>((resolve, reject) => {\n if (signal.aborted)\n return reject(signal.reason)\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n function onAbort(): void {\n clearTimeout(timer)\n reject(signal.reason)\n }\n signal.addEventListener('abort', onAbort, { once: true })\n }),\n now: () => Date.now(),\n}\n\ninterface TokenResponse {\n access_token?: unknown\n refresh_token?: unknown\n expires_in?: unknown\n scope?: unknown\n error?: unknown\n error_description?: unknown\n}\n\n/** Reads a token or device response: JSON, or a form-encoded body (GitHub without `Accept`). */\nfunction parseBody(text: string): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(text)\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))\n return parsed as Record<string, unknown>\n }\n catch { /* not JSON */ }\n return Object.fromEntries(new URLSearchParams(text))\n}\n\nasync function postForm(io: OAuthIo, url: string, body: Record<string, string>, signal?: AbortSignal): Promise<Record<string, unknown>> {\n const timeout = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)\n const response = await io.fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' },\n body: new URLSearchParams(body).toString(),\n signal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n })\n const parsed = parseBody(await response.text())\n if (!response.ok || typeof parsed.error === 'string') {\n const code = typeof parsed.error === 'string' ? parsed.error : `http_${response.status}`\n throw new OAuthTokenError(code, typeof parsed.error_description === 'string' ? parsed.error_description : undefined, response.status)\n }\n return parsed\n}\n\nfunction clientFields(method: OAuthIntegrationMethod): Record<string, string> {\n return { client_id: method.clientId, ...(method.clientSecret ? { client_secret: method.clientSecret } : {}) }\n}\n\n/** The grant a token response carries. */\nfunction toGrant(tokens: TokenResponse, method: OAuthIntegrationMethod, io: OAuthIo, previousRefresh?: string): OAuthGrant {\n if (typeof tokens.access_token !== 'string' || !tokens.access_token)\n throw new Error('The token endpoint returned no access token.')\n const expiresIn = Number(tokens.expires_in)\n const scopes = typeof tokens.scope === 'string' && tokens.scope.trim()\n ? tokens.scope.trim().split(/[\\s,]+/)\n : method.scopes ? [...method.scopes] : undefined\n const refreshToken = typeof tokens.refresh_token === 'string' && tokens.refresh_token ? tokens.refresh_token : previousRefresh\n return {\n credential: {\n type: 'oauth',\n accessToken: tokens.access_token,\n ...(Number.isFinite(expiresIn) && expiresIn > 0 ? { expiresAt: io.now() + expiresIn * 1000 } : {}),\n ...(scopes ? { scopes } : {}),\n },\n ...(refreshToken ? { refreshToken } : {}),\n }\n}\n\nfunction randomHex(bytes: number): string {\n return [...crypto.getRandomValues(new Uint8Array(bytes))].map(b => b.toString(16).padStart(2, '0')).join('')\n}\n\nfunction abortable<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted)\n return Promise.reject(signal.reason)\n return new Promise<T>((resolve, reject) => {\n const onAbort = (): void => reject(signal.reason)\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort))\n })\n}\n\n/**\n * The loopback port and path of a PKCE method's `redirectUri`. Throws for a\n * URI the callback server can't serve.\n *\n * @param redirectUri - The method's `redirectUri`.\n */\nexport function parseLoopbackRedirect(redirectUri: string | undefined): { port: number, path: string } {\n let url: URL\n try {\n url = new URL(redirectUri ?? '')\n }\n catch {\n throw new TypeError(`redirectUri must be a loopback URL with a port, like http://localhost:51121/callback (got ${JSON.stringify(redirectUri)})`)\n }\n const port = Number(url.port)\n if (url.protocol !== 'http:' || !['localhost', '127.0.0.1'].includes(url.hostname) || !Number.isInteger(port) || port <= 0)\n throw new TypeError(`redirectUri must be http://localhost:<port>/<path> or http://127.0.0.1:<port>/<path> (got ${redirectUri})`)\n return { port, path: url.pathname || '/' }\n}\n\n/**\n * Runs the authorization code flow with PKCE: opens the authorize URL\n * (`callbacks.onAuth`), takes the code from the loopback redirect or a\n * pasted URL, and exchanges it at the token endpoint.\n *\n * @param method - The `oauth` method (`flow: 'pkce'`).\n * @param name - The integration's name, shown on the callback page.\n * @param callbacks - The host's login callbacks.\n * @param signal - Aborts the flow.\n * @param io - Network and clock.\n */\nexport async function loginWithPkce(method: OAuthIntegrationMethod, name: string, callbacks: OAuthLoginCallbacks, signal: AbortSignal, io: OAuthIo = defaultOAuthIo): Promise<OAuthGrant> {\n const { port, path } = parseLoopbackRedirect(method.redirectUri)\n const redirectUri = method.redirectUri as string\n const kit = await import('../../oauth-entry')\n const { verifier, challenge } = await kit.generatePkce()\n const state = randomHex(16)\n const server = await kit.startCallbackServer({\n port,\n path,\n expectedState: state,\n providerName: name,\n renderPage: kit.renderDefaultCallbackPage,\n successMessage: 'You can close this tab.',\n onListenError: 'reject',\n ...(kit.listensForCallback(callbacks) ? {} : { listen: false }),\n }).catch((err: unknown) => {\n if ((err as { code?: unknown } | null)?.code === 'EADDRINUSE')\n throw new Error(`Port ${port} is busy, likely another sign-in in progress. Finish or close it, then try again.`)\n throw err\n })\n try {\n const url = new URL(method.authorizeUrl)\n url.searchParams.set('client_id', method.clientId)\n url.searchParams.set('redirect_uri', redirectUri)\n url.searchParams.set('response_type', 'code')\n if (method.scopes?.length)\n url.searchParams.set('scope', method.scopes.join(' '))\n url.searchParams.set('code_challenge', challenge)\n url.searchParams.set('code_challenge_method', 'S256')\n url.searchParams.set('state', state)\n for (const [key, value] of Object.entries(method.params ?? {}))\n url.searchParams.set(key, value)\n callbacks.onAuth({\n url: url.toString(),\n instructions: `Sign in to ${name} in your browser. If the browser is on another machine, paste the final redirect URL here.`,\n })\n const pending = kit.awaitAuthorizationCode(server, state, callbacks)\n pending.catch(() => {})\n const code = await abortable(pending, signal)\n callbacks.onProgress?.('Exchanging authorization code for tokens...')\n const tokens = await postForm(io, method.tokenUrl, {\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n code_verifier: verifier,\n ...clientFields(method),\n }, signal)\n return toGrant(tokens, method, io)\n }\n finally {\n server.close()\n }\n}\n\n/**\n * Runs the device authorization grant: asks the device endpoint for a code,\n * shows it (`callbacks.onDeviceCode`), then polls the token endpoint until\n * the user approves, refuses, or the code expires.\n *\n * @param method - The `oauth` method (`flow: 'device'`).\n * @param callbacks - The host's login callbacks.\n * @param signal - Aborts the flow, polling included.\n * @param io - Network, waits and clock.\n */\nexport async function loginWithDeviceCode(method: OAuthIntegrationMethod, callbacks: OAuthLoginCallbacks, signal: AbortSignal, io: OAuthIo = defaultOAuthIo): Promise<OAuthGrant> {\n if (!method.deviceUrl)\n throw new TypeError('A device flow needs a deviceUrl')\n const start = await postForm(io, method.deviceUrl, {\n ...clientFields(method),\n ...(method.scopes?.length ? { scope: method.scopes.join(' ') } : {}),\n }, signal)\n const deviceCode = start.device_code\n const userCode = start.user_code\n const verificationUri = start.verification_uri ?? start.verification_url\n if (typeof deviceCode !== 'string' || typeof userCode !== 'string' || typeof verificationUri !== 'string')\n throw new Error('The device endpoint returned no device_code, user_code or verification_uri.')\n let intervalS = Number(start.interval) > 0 ? Number(start.interval) : DEFAULT_POLL_INTERVAL_S\n const expiresInS = Number(start.expires_in) > 0 ? Number(start.expires_in) : DEFAULT_DEVICE_EXPIRY_S\n callbacks.onDeviceCode({\n userCode,\n verificationUri: typeof start.verification_uri_complete === 'string' ? start.verification_uri_complete : verificationUri,\n intervalSeconds: intervalS,\n expiresInSeconds: expiresInS,\n })\n // Count waited time rather than reading the clock: the code expires after\n // `expires_in` of polling, and a driven clock in tests never advances.\n let waitedMs = 0\n while (waitedMs < expiresInS * 1000) {\n await io.wait(intervalS * 1000, signal)\n waitedMs += intervalS * 1000\n try {\n const tokens = await postForm(io, method.tokenUrl, {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n ...clientFields(method),\n }, signal)\n return toGrant(tokens, method, io)\n }\n catch (err) {\n if (!(err instanceof OAuthTokenError))\n throw err\n if (err.code === 'authorization_pending')\n continue\n if (err.code === 'slow_down') {\n intervalS += SLOW_DOWN_STEP_S\n continue\n }\n if (err.code === 'access_denied')\n throw new Error('The sign-in was refused.', { cause: err })\n if (err.code === 'expired_token')\n break\n throw err\n }\n }\n throw new Error('The device code expired before the sign-in finished. Try again.')\n}\n\n/**\n * Exchanges a refresh token for a new access token. Keeps the old refresh\n * token when the server does not rotate it.\n *\n * @param method - The `oauth` method the grant came from.\n * @param refreshToken - The stored refresh token.\n * @param io - Network and clock.\n * @param signal - Aborts the request.\n */\nexport async function refreshOAuthGrant(method: OAuthIntegrationMethod, refreshToken: string, io: OAuthIo = defaultOAuthIo, signal?: AbortSignal): Promise<OAuthGrant> {\n const tokens = await postForm(io, method.tokenUrl, {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n ...clientFields(method),\n }, signal)\n return toGrant(tokens, method, io, refreshToken)\n}\n","/**\n * The checks around connecting: spec validation, and the extension\n * callbacks (`beforeConnect`, `verify`, `account`, `parseCommandOutput`)\n * run through the registering extension's guard. A callback's throw or\n * returned message becomes the connect's error; a timeout refuses too.\n * A `custom` method's `connect` runs here too, on the host's flow UI\n * ({@link customFlowIo}).\n */\n\nimport type { OAuthLoginCallbacks } from '@earendil-works/pi-ai/oauth'\nimport type { Credential, IntegrationCustomMethod, IntegrationCustomResult, IntegrationFlowIO, IntegrationMethod, IntegrationSpec } from '../api/sessions'\nimport type { Guard } from '../runtime/deps'\nimport { errorMessage } from '../../errors'\nimport { parseLoopbackRedirect } from './oauth'\n\n/** What a host shows while a connect flow runs. */\nexport interface IntegrationFlowRequest {\n /** The integration being connected. */\n integrationId: string\n /** Its display name. */\n name: string\n /** The method the user picked. */\n method: IntegrationMethod\n /** Aborts when the flow is cancelled. */\n signal: AbortSignal\n}\n\n/** The outcome of a `command` method's process. */\nexport interface IntegrationCommandResult {\n /** Standard output; the credential is read from it. */\n stdout: string\n /** Standard error, quoted when the command fails. */\n stderr?: string\n /** Exit code; anything but 0 fails the connect. */\n exitCode: number\n}\n\n/**\n * What a host provides for connect flows. The TUI, desktop and daemon each\n * implement it once; Settings and `ctx.integrations.connect.start` both use it.\n */\nexport interface IntegrationFlowPort {\n /**\n * The login callbacks for an OAuth flow: open `onAuth`'s URL, show\n * `onDeviceCode`'s code, read a pasted redirect (`onManualCodeInput`),\n * show progress. The same callbacks hosts already build for provider\n * sign-in (`runOAuthLogin` in `src/chat/oauth.ts`); set\n * `callbackServer: false` for a client of a remote host.\n */\n oauthCallbacks: (request: IntegrationFlowRequest) => OAuthLoginCallbacks & { callbackServer?: false }\n /** Runs a `command` method's argv (no shell) and returns its output. */\n runCommand: (command: readonly string[], opts: { signal: AbortSignal }) => Promise<IntegrationCommandResult>\n}\n\n/** Integration ids become credential-file keys: no `#` (reserved for provider slots), no spaces. */\nconst ID_PATTERN = /^[\\w.:-]+$/\n\n/**\n * Throws a `TypeError` naming the first problem of a spec.\n *\n * @param spec - The spec an extension registers.\n */\nexport function validateSpec(spec: IntegrationSpec): void {\n if (!spec || typeof spec.id !== 'string' || !ID_PATTERN.test(spec.id))\n throw new TypeError(`integrations.register: id must match ${ID_PATTERN} (got ${JSON.stringify(spec?.id)})`)\n if (typeof spec.name !== 'string' || !spec.name)\n throw new TypeError(`integrations.register(${spec.id}): name is required`)\n if (!Array.isArray(spec.methods) || spec.methods.length === 0)\n throw new TypeError(`integrations.register(${spec.id}): at least one method is required`)\n const ids = new Set<string>()\n for (const method of spec.methods) {\n const where = `integrations.register(${spec.id}): method ${method.id}`\n if (!method.id || ids.has(method.id))\n throw new TypeError(`integrations.register(${spec.id}): method ids must be unique and non-empty (got ${JSON.stringify(method.id)})`)\n ids.add(method.id)\n if (method.type === 'oauth' && method.flow === 'pkce') {\n try {\n parseLoopbackRedirect(method.redirectUri)\n }\n catch (err) {\n throw new TypeError(`${where}: ${errorMessage(err)}`)\n }\n }\n if (method.type === 'oauth' && method.flow === 'device' && !method.deviceUrl)\n throw new TypeError(`${where}: a device flow needs a deviceUrl`)\n if (method.type === 'command' && (!Array.isArray(method.command) || method.command.length === 0))\n throw new TypeError(`${where}: command is empty`)\n if (method.type === 'custom' && typeof method.connect !== 'function')\n throw new TypeError(`${where}: a custom method needs a connect function`)\n if (method.type === 'custom' && method.refresh !== undefined && typeof method.refresh !== 'function')\n throw new TypeError(`${where}: refresh must be a function`)\n }\n if (spec.beforeConnect !== undefined && typeof spec.beforeConnect !== 'function')\n throw new TypeError(`integrations.register(${spec.id}): beforeConnect must be a function`)\n if (spec.legacyCredentialKey !== undefined && (typeof spec.legacyCredentialKey !== 'string' || !spec.legacyCredentialKey || spec.legacyCredentialKey.includes('#')))\n throw new TypeError(`integrations.register(${spec.id}): legacyCredentialKey must be a credentials-file key without \"#\"`)\n}\n\n/**\n * Runs the spec's `beforeConnect` for `method`. Throws its message when it\n * refuses (or throws); a timeout refuses too.\n *\n * @param spec - The integration.\n * @param guard - The registering extension's guard.\n * @param method - The method the user picked.\n */\nexport async function checkBeforeConnect(spec: IntegrationSpec, guard: Guard, method: IntegrationMethod): Promise<void> {\n const check = spec.beforeConnect\n if (!check)\n return\n const outcome = await guard.call(`integrations.beforeConnect(${spec.id})`, async () => {\n try {\n return { refusal: await check(method) }\n }\n catch (err) {\n return { refusal: errorMessage(err) || `${spec.name} refused to connect.` }\n }\n }, { fallback: { refusal: `${spec.name}: the connect check did not answer.` } })\n if (typeof outcome?.refusal === 'string' && outcome.refusal)\n throw new Error(outcome.refusal)\n}\n\n/**\n * The {@link IntegrationFlowIO} of a `custom` method, on the host's OAuth\n * login callbacks: links (`onAuth`), codes (`onDeviceCode`), questions\n * (`onPrompt`, `onSelect`) and progress lines (`onProgress`).\n *\n * @param callbacks - The host's login callbacks for this flow.\n * @param signal - Aborts the flow.\n */\nexport function customFlowIo(callbacks: OAuthLoginCallbacks, signal: AbortSignal): IntegrationFlowIO {\n return {\n openUrl: url => callbacks.onAuth({ url }),\n showCode: (code, url) => callbacks.onDeviceCode({ userCode: code, verificationUri: url ?? '' }),\n prompt: async (opts) => {\n try {\n if (opts.options)\n return await callbacks.onSelect({ message: opts.message, options: opts.options.map(o => ({ id: o.id, label: o.label })) })\n return await callbacks.onPrompt({ message: opts.message, ...(opts.placeholder ? { placeholder: opts.placeholder } : {}), ...(opts.allowEmpty ? { allowEmpty: true } : {}) })\n }\n catch (err) {\n // A host rejects a dismissed question; the flow reads that as a cancel unless the whole flow was aborted.\n if (signal.aborted)\n throw err\n return undefined\n }\n },\n signal,\n log: message => callbacks.onProgress?.(message),\n }\n}\n\n/**\n * Runs a `custom` method's `connect` and checks what it returns. Its\n * errors become the connect's (prefixed with the integration's name).\n *\n * @param spec - The integration.\n * @param method - The `custom` method.\n * @param io - The flow UI.\n */\nexport async function customCredential(spec: IntegrationSpec, method: IntegrationCustomMethod, io: IntegrationFlowIO): Promise<IntegrationCustomResult> {\n let result: IntegrationCustomResult\n try {\n result = await method.connect(io)\n }\n catch (err) {\n io.signal.throwIfAborted()\n throw new Error(`${spec.name}: ${errorMessage(err) || 'the sign-in failed'}`, { cause: err })\n }\n io.signal.throwIfAborted()\n const credential = validCredential(result?.credential)\n if (!credential)\n throw new Error(`${spec.name}: the sign-in returned no usable credential.`)\n const text = (v: unknown): string | undefined => (typeof v === 'string' && v.trim() ? v.trim() : undefined)\n const account = text(result.account)\n const label = text(result.label)\n return { credential, ...(account ? { account } : {}), ...(label ? { label } : {}) }\n}\n\n/**\n * The credential an extension built, checked; `undefined` when it is not one.\n *\n * @param value - What `parseCommandOutput` returned.\n */\nexport function validCredential(value: unknown): Credential | undefined {\n const c = value as Partial<Record<string, unknown>> | null\n if (!c || typeof c !== 'object')\n return undefined\n if (c.type === 'apiKey' && typeof c.key === 'string' && c.key)\n return { type: 'apiKey', key: c.key }\n if (c.type === 'token' && typeof c.token === 'string' && c.token)\n return { type: 'token', token: c.token }\n if (c.type === 'oauth' && typeof c.accessToken === 'string' && c.accessToken) {\n return {\n type: 'oauth',\n accessToken: c.accessToken,\n ...(typeof c.expiresAt === 'number' ? { expiresAt: c.expiresAt } : {}),\n ...(Array.isArray(c.scopes) ? { scopes: c.scopes.filter((s): s is string => typeof s === 'string') } : {}),\n ...(typeof c.refreshToken === 'string' && c.refreshToken ? { refreshToken: c.refreshToken } : {}),\n ...(c.extra && typeof c.extra === 'object' && !Array.isArray(c.extra) ? { extra: structuredClone(c.extra as Record<string, unknown>) } : {}),\n }\n }\n return undefined\n}\n\n/**\n * Runs the spec's `verify`. Throws when it refuses, throws or times out.\n *\n * @param spec - The integration.\n * @param guard - The registering extension's guard.\n * @param credential - The credential to check.\n */\nexport async function verifyCredential(spec: IntegrationSpec, guard: Guard, credential: Credential): Promise<void> {\n const verify = spec.verify\n if (!verify)\n return\n const outcome = await guard.call(`integrations.verify(${spec.id})`, async () => {\n try {\n return { error: await verify(credential) }\n }\n catch (err) {\n return { error: errorMessage(err) || 'verification failed' }\n }\n }, { fallback: { error: 'verification did not answer' } })\n if (outcome?.error)\n throw new Error(`${spec.name}: ${outcome.error}`)\n}\n\n/**\n * The spec's `account` label for a credential. `undefined` when it has none, throws or times out.\n *\n * @param spec - The integration.\n * @param guard - The registering extension's guard.\n * @param credential - The new credential.\n */\nexport async function accountLabel(spec: IntegrationSpec, guard: Guard, credential: Credential): Promise<string | undefined> {\n const account = spec.account\n if (!account)\n return undefined\n const label = await guard.call(`integrations.account(${spec.id})`, () => account(credential))\n return typeof label === 'string' && label ? label : undefined\n}\n\n/**\n * Runs a `command` method through the host and reads its credential: the\n * spec's `parseCommandOutput`, or by default the trimmed stdout as a token.\n *\n * @param spec - The integration.\n * @param guard - The registering extension's guard.\n * @param method - The `command` method.\n * @param port - The host's command runner.\n * @param signal - Aborts the command.\n */\nexport async function commandCredential(spec: IntegrationSpec, guard: Guard, method: Extract<IntegrationMethod, { type: 'command' }>, port: IntegrationFlowPort, signal: AbortSignal): Promise<Credential> {\n const shown = method.command.join(' ')\n const result = await port.runCommand(method.command, { signal })\n if (result.exitCode !== 0) {\n const detail = (result.stderr ?? '').trim().split('\\n')[0]\n throw new Error(`${shown} failed (exit ${result.exitCode})${detail ? `: ${detail}` : ''}`)\n }\n const parse = spec.parseCommandOutput\n if (!parse) {\n const token = result.stdout.trim()\n if (!token)\n throw new Error(`${shown} printed nothing.`)\n return { type: 'token', token }\n }\n const parsed = guard.callSync(`integrations.parseCommandOutput(${spec.id})`, () => {\n try {\n return { credential: parse(result.stdout) as unknown }\n }\n catch (err) {\n return { error: errorMessage(err) }\n }\n })\n if (parsed && 'error' in parsed)\n throw new Error(`${spec.name}: could not read the command output: ${parsed.error}`)\n const credential = validCredential(parsed?.credential)\n if (!credential)\n throw new Error(`${spec.name}: parseCommandOutput returned no usable credential.`)\n return credential\n}\n","/**\n * The registry's view of stored connections: a cache over the\n * {@link AuthStorePort} (one list per integration, the default first),\n * change detection and notification (`onChange` listeners per integration,\n * Settings subscribers), and the adoption of a legacy provider sign-in\n * (`IntegrationSpec.legacyCredentialKey`).\n */\n\nimport type { Logger } from '../../logger'\nimport type { Connection, IntegrationSpec } from '../api/sessions'\nimport type { AuthStorePort, StoredIntegration } from './store'\nimport { errorMessage } from '../../errors'\nimport { DEFAULT_ACCOUNT } from './auth-store-port'\n\n/** An integration's stored connections, the default first. */\nexport type Stored = StoredIntegration[]\n\n/** What the cache reads through. */\nexport interface ConnectionCacheDeps {\n store: AuthStorePort\n logger?: Logger\n /** The clock adopted connections are stamped with. */\n now: () => number\n /** The registered spec of an integration (for its `legacyCredentialKey`). */\n spec: (integrationId: string) => IntegrationSpec | undefined\n}\n\n/** The connections a store record holds, as `connections()` lists them (`isDefault` on the first). */\nexport function view(list: Stored | undefined | null): Connection[] {\n return (list ?? []).map((s, i) => ({ ...s.connection, ...(i === 0 ? { isDefault: true } : {}) }))\n}\n\nfunction connectionsKey(list: Stored | undefined | null): string {\n return JSON.stringify((list ?? []).map(s => s.connection))\n}\n\n/**\n * Makes the cache.\n *\n * @param deps - Store, logger, clock and spec lookup.\n */\nexport function createConnectionCache(deps: ConnectionCacheDeps) {\n const { store, logger } = deps\n /** Stored records read so far; `null` is \"read, none stored\". */\n const cache = new Map<string, Stored | null>()\n const listeners = new Map<string, Set<(connection: Connection | undefined) => void>>()\n const subscribers = new Set<() => void>()\n\n const safely = (what: string, fn: () => void, attrs?: Record<string, unknown>): void => {\n try {\n fn()\n }\n catch (err) {\n logger?.warn(`integrations: ${what} threw`, { ...attrs, error: errorMessage(err) })\n }\n }\n\n /** Adopts the legacy sign-in a spec names, when the integration has no connection. */\n function adoptLegacy(id: string): Stored | undefined {\n const spec = deps.spec(id)\n const key = spec?.legacyCredentialKey\n if (!spec || !key || !store.readLegacy)\n return undefined\n const grant = store.readLegacy(key)\n if (!grant)\n return undefined\n const methods = spec.methods\n const method = grant.credential.type === 'oauth'\n ? methods.find(m => m.type === 'oauth' || m.type === 'custom')\n : methods.find(m => m.type === 'apiKey') ?? methods.find(m => m.type === 'command')\n const account = grant.account ?? DEFAULT_ACCOUNT\n const record: StoredIntegration = {\n connection: {\n integrationId: id,\n methodId: (method ?? methods[0]!).id,\n account,\n ...(grant.label && grant.label !== account ? { label: grant.label } : {}),\n connectedAt: deps.now(),\n },\n credential: grant.credential,\n ...(grant.refreshToken ? { refreshToken: grant.refreshToken } : {}),\n }\n store.write(id, [record])\n store.markLegacy?.(key, id)\n logger?.info(`integrations: adopted the legacy sign-in under \"${key}\" as a connection of ${id}`)\n return [record]\n }\n\n /** Reads one record fresh from the store (adopting a legacy sign-in when it is empty). */\n function read(id: string): Stored | undefined {\n let value: Stored | undefined\n try {\n // A port written before several connections returns one record: read it as the only one.\n const raw = store.read(id) as Stored | StoredIntegration | undefined\n value = raw === undefined || Array.isArray(raw) ? raw : [raw]\n if (!value?.length)\n value = adoptLegacy(id)\n }\n catch (err) {\n logger?.warn('integrations: could not read the stored connections', { integration: id, error: errorMessage(err) })\n }\n const list = value?.length ? value : undefined\n cache.set(id, list ?? null)\n return list\n }\n\n function cached(id: string): Stored | undefined {\n const value = cache.get(id)\n return value === undefined ? read(id) : value ?? undefined\n }\n\n function notify(): void {\n for (const listener of [...subscribers])\n safely('a subscriber', listener)\n }\n\n function emit(id: string, list: Stored | undefined): void {\n const first = view(list)[0]\n for (const listener of [...listeners.get(id) ?? []])\n safely('an onChange listener', () => listener(first ? { ...first } : undefined), { integration: id })\n notify()\n }\n\n /** Re-reads one record and emits when its connections differ from what was cached. */\n function refresh(id: string): Stored | undefined {\n const before = cache.get(id)\n const after = read(id)\n if (before !== undefined && connectionsKey(before) !== connectionsKey(after))\n emit(id, after)\n return after\n }\n\n /** Writes a record (or deletes it) and emits when the connections changed. */\n function persist(id: string, value: Stored | undefined): void {\n const before = cached(id)\n const list = value?.length ? value : undefined\n store.write(id, list)\n cache.set(id, list ? structuredClone(list) : null)\n if (connectionsKey(before) !== connectionsKey(list))\n emit(id, list)\n }\n\n /** Replaces the connection of the same account, or adds it last. */\n function put(id: string, record: StoredIntegration): void {\n // Fresh from the store: another process may have added an account since the last read.\n const list = [...(refresh(id) ?? [])]\n const at = list.findIndex(s => s.connection.account === record.connection.account)\n if (at >= 0)\n list[at] = record\n else\n list.push(record)\n persist(id, list)\n }\n\n return {\n read,\n cached,\n refresh,\n persist,\n put,\n notify,\n /** Forgets a \"none stored\" read, so the next read may adopt a legacy sign-in. */\n forgetEmpty: (id: string): void => {\n if (cache.get(id) === null)\n cache.delete(id)\n },\n /** Integrations read so far. */\n known: (): string[] => [...cache.keys()],\n onChange(id: string, listener: (connection: Connection | undefined) => void): () => void {\n let set = listeners.get(id)\n if (!set)\n listeners.set(id, set = new Set())\n set.add(listener)\n return () => {\n set.delete(listener)\n if (set.size === 0 && listeners.get(id) === set)\n listeners.delete(id)\n }\n },\n subscribe(listener: () => void): () => void {\n subscribers.add(listener)\n return () => {\n subscribers.delete(listener)\n }\n },\n }\n}\n","/**\n * Refresh of expiring OAuth connections, on `resolveOAuthApiKey`\n * (`src/providers/oauth.ts`), the code provider sign-ins refresh through:\n * concurrent resolves of one connection share one refresh (keyed by the\n * stored grant and these functions' identities, hence one stable binding\n * per connection), and the refreshed grant is written only when the stored\n * one did not change meanwhile.\n *\n * An `oauth` method refreshes with the refresh-token grant; a `custom`\n * method with its own `refresh`. Each refresh is reported to `onRefresh`\n * (the `oauth:refresh` observation).\n */\n\nimport type { OAuthCredentials } from '@earendil-works/pi-ai/oauth'\nimport type { OAuthRefreshHookContext } from '../../types'\nimport type { Credential, IntegrationMethod } from '../api/sessions'\nimport type { OAuthIo } from './oauth'\nimport type { StoredIntegration } from './store'\nimport { AgentAuthError, errorMessage } from '../../errors'\nimport { resolveOAuthApiKey } from '../../providers/oauth'\nimport { validCredential } from './connect'\nimport { refreshOAuthGrant } from './oauth'\n\n/** Stands for \"no expiry\" in the `expires` field `resolveOAuthApiKey` requires; never stored. */\nconst NO_EXPIRY = Number.MAX_SAFE_INTEGER\n\n/** What the refresher reads and writes through (the registry's cached store). */\nexport interface RefresherDeps {\n /** OAuth network and clock. */\n io: OAuthIo\n /** Refresh this long before expiry. */\n skewMs: number\n /** Reads one connection fresh from the store. */\n read: (integrationId: string, account: string) => StoredIntegration | undefined\n /** Replaces one connection (the registry emits changes). */\n write: (integrationId: string, account: string, value: StoredIntegration) => void\n /** The method of a registered integration, `undefined` when unregistered. */\n method: (integrationId: string, methodId: string) => IntegrationMethod | undefined\n /** Told of each refresh that rotated a grant. */\n onRefresh?: (event: OAuthRefreshHookContext) => void | Promise<void>\n}\n\n/** Refreshes stored OAuth connections. */\nexport interface Refresher {\n /** Whether a stored credential expires within the skew. */\n due: (stored: StoredIntegration) => boolean\n /** The record after refreshing it (or as stored, when it can't refresh and has not expired). */\n refresh: (integrationId: string, name: string, stored: StoredIntegration) => Promise<StoredIntegration>\n}\n\ninterface Binding {\n read: () => Record<string, OAuthCredentials | undefined>\n write: (patch: Record<string, OAuthCredentials | undefined>) => void\n exchange: (providerId: string, credentials: Record<string, OAuthCredentials>, options?: { force?: boolean }) => Promise<{ newCredentials: OAuthCredentials, apiKey: string } | null>\n}\n\n/** The key a binding reads and writes its one connection under (never stored). */\nfunction slotOf(id: string, account: string): string {\n return `${id}#${account}`\n}\n\nfunction toOAuthCredentials(stored: StoredIntegration): OAuthCredentials | undefined {\n const credential = stored.credential\n if (credential.type !== 'oauth' || credential.expiresAt === undefined)\n return undefined\n return {\n access: credential.accessToken,\n refresh: stored.refreshToken ?? '',\n expires: credential.expiresAt,\n ...(credential.scopes ? { scopes: [...credential.scopes] } : {}),\n ...(credential.extra ? { extra: structuredClone(credential.extra) } : {}),\n }\n}\n\nfunction fromOAuthCredentials(next: OAuthCredentials): { credential: Credential, refreshToken?: string } {\n const scopes = Array.isArray(next.scopes) ? next.scopes as string[] : undefined\n const extra = next.extra && typeof next.extra === 'object' ? next.extra as Record<string, unknown> : undefined\n return {\n credential: {\n type: 'oauth',\n accessToken: next.access,\n ...(next.expires < NO_EXPIRY ? { expiresAt: next.expires } : {}),\n ...(scopes ? { scopes } : {}),\n ...(extra ? { extra } : {}),\n },\n ...(next.refresh ? { refreshToken: next.refresh } : {}),\n }\n}\n\n/**\n * Makes a refresher.\n *\n * @param deps - Store access, method lookup, I/O, skew and the refresh observer.\n */\nexport function createRefresher(deps: RefresherDeps): Refresher {\n const { io, skewMs } = deps\n const bindings = new Map<string, Binding>()\n\n async function renew(id: string, account: string, creds: OAuthCredentials): Promise<OAuthCredentials> {\n const stored = deps.read(id, account)\n const method = stored ? deps.method(id, stored.connection.methodId) : undefined\n if (method?.type === 'custom') {\n if (!method.refresh)\n throw new Error('the sign-in can\\'t be renewed')\n const current = fromOAuthCredentials(creds)\n const credential = { ...current.credential, ...(current.refreshToken ? { refreshToken: current.refreshToken } : {}) } as Credential\n const result = validCredential(await method.refresh(structuredClone(credential)))\n if (result?.type !== 'oauth')\n throw new Error('the refresh returned no OAuth credential')\n return {\n access: result.accessToken,\n refresh: result.refreshToken ?? creds.refresh,\n expires: result.expiresAt ?? NO_EXPIRY,\n ...(result.scopes ? { scopes: [...result.scopes] } : {}),\n ...(result.extra ? { extra: result.extra } : creds.extra ? { extra: creds.extra } : {}),\n }\n }\n if (method?.type !== 'oauth')\n throw new Error('the integration that issued it is not registered')\n const grant = await refreshOAuthGrant(method, creds.refresh, io)\n return {\n ...creds,\n access: grant.credential.accessToken,\n refresh: grant.refreshToken ?? creds.refresh,\n // A refreshed token without an expiry never needs another refresh by time.\n expires: grant.credential.expiresAt ?? NO_EXPIRY,\n ...(grant.credential.scopes ? { scopes: [...grant.credential.scopes] } : {}),\n }\n }\n\n /** Display names, for the refresh event (a spec's name can change). */\n const names = new Map<string, string>()\n\n function bindingFor(id: string, account: string): Binding {\n const slot = slotOf(id, account)\n const existing = bindings.get(slot)\n if (existing)\n return existing\n const binding: Binding = {\n read: () => {\n const stored = deps.read(id, account)\n return { [slot]: stored ? toOAuthCredentials(stored) : undefined }\n },\n write: (patch) => {\n const next = patch[slot]\n const current = deps.read(id, account)\n if (!next || !current)\n return\n deps.write(id, account, { connection: current.connection, ...fromOAuthCredentials(next) })\n // Once per rotation, here rather than per resolve: concurrent resolves share one refresh.\n const previous = toOAuthCredentials(current)\n if (deps.onRefresh && previous) {\n // Observers are any extension's: the refresh token stays in the store.\n const event: OAuthRefreshHookContext = { provider: names.get(id) ?? id, providerId: id, source: 'file', previousCredentials: { ...previous, refresh: '' }, credentials: { ...structuredClone(next), refresh: '' } }\n void Promise.resolve().then(() => deps.onRefresh?.(event)).catch(() => {})\n }\n },\n exchange: async (providerId, credentials, opts) => {\n const creds = credentials[providerId]\n if (!creds)\n return null\n if (!opts?.force && creds.expires - skewMs > io.now())\n return { newCredentials: creds, apiKey: creds.access }\n const next = await renew(id, account, creds)\n return { newCredentials: next, apiKey: next.access }\n },\n }\n bindings.set(slot, binding)\n return binding\n }\n\n function canRenew(id: string, stored: StoredIntegration): boolean {\n if (stored.refreshToken)\n return true\n const method = deps.method(id, stored.connection.methodId)\n return method?.type === 'custom' && typeof method.refresh === 'function'\n }\n\n return {\n due: (stored) => {\n const credential = stored.credential\n return credential.type === 'oauth' && credential.expiresAt !== undefined && credential.expiresAt - skewMs <= io.now()\n },\n\n async refresh(id, name, stored) {\n const { account } = stored.connection\n if (!canRenew(id, stored)) {\n if (stored.credential.type === 'oauth' && (stored.credential.expiresAt ?? Infinity) <= io.now())\n throw new AgentAuthError(`${name}: the sign-in expired. Connect again.`, { kind: 'expired', source: 'integration', provider: name, providerId: id, ...(account ? { accountId: account } : {}) })\n return stored\n }\n names.set(id, name)\n const binding = bindingFor(id, account)\n // Another writer (a second window) may rotate the grant between our\n // read and our write: `resolveOAuthApiKey` refuses that write, and one\n // more pass reads the grant it stored.\n for (let attempt = 0; ; attempt++) {\n try {\n await resolveOAuthApiKey({\n provider: name,\n providerId: id,\n credentialKey: slotOf(id, account),\n readCredentials: binding.read,\n writeCredentials: binding.write,\n getOAuthApiKey: binding.exchange,\n authSource: 'integration',\n missingError: `${name} is not connected.`,\n refreshError: reason => `${name}: could not refresh the sign-in (${reason}). Connect again if it keeps failing.`,\n })\n break\n }\n catch (err) {\n if (attempt > 0 || !/changed during refresh/.test(errorMessage(err)))\n throw err\n }\n }\n const after = deps.read(id, account)\n if (!after)\n throw new Error(`${name} is not connected.`)\n return after\n },\n }\n}\n","/**\n * The process-wide integration registry: the specs extensions register\n * (first id wins), their connections (through an {@link AuthStorePort}),\n * the connect flows, and credential resolution with OAuth refresh\n * (`./refresh`).\n *\n * An integration holds several connections, one per account; the first is\n * the default. Connecting an account already connected replaces it; the\n * first connection becomes the default. A spec's `legacyCredentialKey`\n * adopts a legacy provider sign-in the first time the integration is read with\n * no connection.\n *\n * Each extension's `ctx.integrations` (`./domain`) is a view on one\n * registry; Settings reads the same registry to draw Connect / Disconnect.\n * Extension callbacks run through the registering extension's guard\n * (`./connect`).\n */\n\nimport type { OAuthLoginCallbacks } from '@earendil-works/pi-ai/oauth'\nimport type { Logger } from '../../logger'\nimport type { OAuthRefreshHookContext } from '../../types'\nimport type { Disposable } from '../api/core'\nimport type { Connection, Credential, IntegrationMethod, IntegrationSpec, IntegrationSpecPatch } from '../api/sessions'\nimport type { Guard } from '../runtime/deps'\nimport type { IntegrationFlowPort } from './connect'\nimport type { OAuthGrant, OAuthIo } from './oauth'\nimport type { AuthStorePort } from './store'\nimport { DEFAULT_ACCOUNT } from './auth-store-port'\nimport { accountLabel, checkBeforeConnect, commandCredential, customCredential, customFlowIo, validateSpec, verifyCredential } from './connect'\nimport { createConnectionCache, view } from './connections'\nimport { defaultOAuthIo, loginWithDeviceCode, loginWithPkce } from './oauth'\nimport { createRefresher } from './refresh'\n\n/** Who registers a spec: its callbacks run through this guard. */\nexport interface IntegrationRegistrant {\n /** The registering extension. */\n extensionId: string\n /** That extension's guard. */\n guard: Guard\n}\n\n/** A registered integration, as Settings lists it. */\nexport interface IntegrationEntry {\n /** The spec. */\n spec: IntegrationSpec\n /** The extension that registered it. */\n extensionId: string\n /** Its default connection, if connected. */\n connection: Connection | undefined\n /** Every connection, the default first. */\n connections: Connection[]\n}\n\n/** A registration in the registry. */\nexport interface IntegrationRegistration extends Disposable {\n /** Replaces fields of the spec (validated; throws a `TypeError` and keeps the spec when invalid). No-op once disposed. */\n update: (patch: IntegrationSpecPatch) => void\n}\n\n/** What a registry is built on. */\nexport interface IntegrationRegistryOptions {\n /** Where connections persist. */\n store: AuthStorePort\n /** Network, waits and clock of the OAuth flows. Defaults to the real ones. */\n io?: Partial<OAuthIo>\n /** Refresh OAuth tokens this long before they expire. Default 60 s. */\n refreshSkewMs?: number\n /** Logs store failures, throwing listeners and refused registrations. */\n logger?: Logger\n /** Told of each refresh that rotated a grant (hosts fire the `oauth:refresh` observation with it). */\n onRefresh?: (event: OAuthRefreshHookContext) => void | Promise<void>\n}\n\n/** The process-wide integration registry. */\nexport interface IntegrationRegistry {\n /**\n * Registers a spec. Returns `undefined` when the id is taken: the first\n * registration wins. Throws a `TypeError` for an invalid spec.\n */\n register: (spec: IntegrationSpec, by: IntegrationRegistrant) => IntegrationRegistration | undefined\n /** A registered integration. */\n get: (integrationId: string) => IntegrationEntry | undefined\n /** Every registered integration, in registration order. */\n list: () => IntegrationEntry[]\n /** Every stored connection of an integration, registered or not, the default first. */\n connections: (integrationId: string) => Connection[]\n /** The default stored connection of an integration, or the one of `account`. */\n connection: (integrationId: string, account?: string) => Connection | undefined\n /** The credential of a connection (an id means its default), refreshed when it expires soon. Rejects when not connected. */\n resolve: (connection: Connection | string) => Promise<Credential>\n /** Connects with an API key: check, verify, then persist. Uses the first `apiKey` method unless `methodId` names one. */\n connectKey: (integrationId: string, key: string, methodId?: string) => Promise<Connection>\n /** Runs an `oauth`, `command` or `custom` method, then verifies and persists. */\n start: (integrationId: string, methodId: string, port: IntegrationFlowPort, opts?: { signal?: AbortSignal }) => Promise<Connection>\n /** Makes the connection of `account` the default. Rejects when there is none. */\n setDefault: (integrationId: string, account: string) => Promise<void>\n /** Deletes the connection of `account`, or all of them. */\n disconnect: (integrationId: string, account?: string) => Promise<void>\n /** Calls `listener` with the default connection when any connection of an integration changes. Returns the unsubscribe. */\n onChange: (integrationId: string, listener: (connection: Connection | undefined) => void) => () => void\n /** Calls `listener` after any spec or connection change (for Settings). Returns the unsubscribe. */\n subscribe: (listener: () => void) => () => void\n /** Re-reads stored connections (all read so far, or one) after the store changed outside the registry; emits what changed. */\n reload: (integrationId?: string) => void\n}\n\ninterface Entry {\n spec: IntegrationSpec\n by: IntegrationRegistrant\n}\n\n/**\n * Makes a registry. Hosts make one per process and install it with\n * {@link installIntegrationRegistry}; tests make their own.\n *\n * @param options - The store, OAuth I/O, refresh skew, logger and refresh observer.\n */\nexport function createIntegrationRegistry(options: IntegrationRegistryOptions): IntegrationRegistry {\n const { logger } = options\n const io: OAuthIo = { ...defaultOAuthIo, ...options.io }\n const entries = new Map<string, Entry>()\n // Assigned below; registrations join the process-wide live set under it.\n\n let registry: IntegrationRegistry\n const store = createConnectionCache({ store: options.store, ...(logger ? { logger } : {}), now: io.now, spec: id => entries.get(id)?.spec })\n\n const refresher = createRefresher({\n io,\n skewMs: options.refreshSkewMs ?? 60_000,\n read: (id, account) => store.read(id)?.find(s => s.connection.account === account),\n write: (id, _account, value) => store.put(id, value),\n method: (id, methodId) => entries.get(id)?.spec.methods.find(m => m.id === methodId),\n ...(options.onRefresh ? { onRefresh: options.onRefresh } : {}),\n })\n\n function entryOf(id: string): Entry {\n const entry = entries.get(id)\n if (!entry)\n throw new Error(`No integration \"${id}\" is registered.`)\n return entry\n }\n\n function methodOf(entry: Entry, methodId: string): IntegrationMethod {\n const method = entry.spec.methods.find(m => m.id === methodId)\n if (!method)\n throw new Error(`${entry.spec.name} has no connect method \"${methodId}\".`)\n return method\n }\n\n async function finish(entry: Entry, method: IntegrationMethod, issued: Credential, refreshToken?: string, named: { account?: string, label?: string } = {}): Promise<Connection> {\n // A custom method hands its refresh token in the credential: the store keeps it beside.\n const { refreshToken: carried, ...credential } = issued as Credential & { refreshToken?: string }\n const refresh = refreshToken ?? carried\n await verifyCredential(entry.spec, entry.by.guard, credential as Credential)\n const account = named.account ?? await accountLabel(entry.spec, entry.by.guard, credential as Credential) ?? DEFAULT_ACCOUNT\n const label = named.label\n const connection: Connection = {\n integrationId: entry.spec.id,\n methodId: method.id,\n account,\n ...(label && label !== account ? { label } : {}),\n connectedAt: io.now(),\n }\n store.put(entry.spec.id, { connection, credential: credential as Credential, ...(refresh ? { refreshToken: refresh } : {}) })\n return view(store.cached(entry.spec.id)).find(c => c.account === account) ?? { ...connection }\n }\n\n async function runFlow(entry: Entry, method: Exclude<IntegrationMethod, { type: 'apiKey' }>, port: IntegrationFlowPort, signal: AbortSignal): Promise<Connection> {\n if (method.type === 'command')\n return finish(entry, method, await commandCredential(entry.spec, entry.by.guard, method, port, signal))\n const callbacks = port.oauthCallbacks({ integrationId: entry.spec.id, name: entry.spec.name, method, signal })\n if (method.type === 'custom') {\n const result = await customCredential(entry.spec, method, customFlowIo(callbacks, signal))\n return finish(entry, method, result.credential, undefined, result)\n }\n const grant: OAuthGrant = method.flow === 'device'\n ? await loginWithDeviceCode(method, callbacks, signal, io)\n : await loginWithPkce(method, entry.spec.name, callbacks, signal, io)\n signal.throwIfAborted()\n return finish(entry, method, grant.credential, grant.refreshToken)\n }\n\n function register(spec: IntegrationSpec, by: IntegrationRegistrant): IntegrationRegistration | undefined {\n validateSpec(spec)\n const holder = entries.get(spec.id)\n if (holder) {\n logger?.warn(`integrations.register: \"${spec.id}\" is already registered by ${holder.by.extensionId}; the first registration wins`, { extension: by.extensionId })\n return undefined\n }\n const entry: Entry = { spec, by }\n entries.set(spec.id, entry)\n live().add(registry)\n // Adopt a legacy sign-in now (read before as \"none stored\" included), so\n // pickers reading the credentials file see it signed in at once.\n if (spec.legacyCredentialKey) {\n store.forgetEmpty(spec.id)\n store.cached(spec.id)\n }\n store.notify()\n const current = (): boolean => entries.get(spec.id) === entry\n return {\n update: (patch) => {\n if (!current())\n return\n const next: IntegrationSpec = { ...entry.spec, ...patch, id: entry.spec.id }\n validateSpec(next)\n entry.spec = next\n store.notify()\n },\n dispose: () => {\n if (!current())\n return\n entries.delete(spec.id)\n if (entries.size === 0)\n live().delete(registry)\n store.notify()\n },\n }\n }\n\n registry = {\n register,\n\n get(id) {\n const entry = entries.get(id)\n if (!entry)\n return undefined\n const connections = view(store.cached(id))\n return { spec: entry.spec, extensionId: entry.by.extensionId, connection: connections[0], connections }\n },\n\n list: () => [...entries.keys()].map(id => registry.get(id) as IntegrationEntry),\n\n connections: id => view(store.cached(id)),\n\n connection(id, account) {\n const all = view(store.cached(id))\n return account === undefined ? all[0] : all.find(c => c.account === account)\n },\n\n async resolve(connection) {\n const id = typeof connection === 'string' ? connection : connection.integrationId\n const account = typeof connection === 'string' ? undefined : connection.account\n const name = entries.get(id)?.spec.name ?? id\n // Fresh from the store: another process may have connected, rotated or disconnected.\n const list = store.refresh(id)\n let stored = account === undefined ? list?.[0] : list?.find(s => s.connection.account === account)\n if (!stored)\n throw new Error(account === undefined || !list?.length ? `${name} is not connected.` : `${name}: the account \"${account}\" is not connected.`)\n if (refresher.due(stored))\n stored = await refresher.refresh(id, name, stored)\n return structuredClone(stored.credential)\n },\n\n async connectKey(id, key, methodId) {\n const entry = entryOf(id)\n const method = methodId ? methodOf(entry, methodId) : entry.spec.methods.find(m => m.type === 'apiKey')\n if (method?.type !== 'apiKey')\n throw new Error(`${entry.spec.name} does not connect with an API key.`)\n const trimmed = typeof key === 'string' ? key.trim() : ''\n if (!trimmed)\n throw new Error(`${entry.spec.name}: the key is empty.`)\n await checkBeforeConnect(entry.spec, entry.by.guard, method)\n return finish(entry, method, { type: 'apiKey', key: trimmed })\n },\n\n async start(id, methodId, port, opts = {}) {\n const entry = entryOf(id)\n const method = methodOf(entry, methodId)\n const signal = opts.signal ?? new AbortController().signal\n signal.throwIfAborted()\n if (method.type === 'apiKey')\n throw new Error(`${entry.spec.name}: \"${method.id}\" takes an API key; use connect.key.`)\n await checkBeforeConnect(entry.spec, entry.by.guard, method)\n signal.throwIfAborted()\n return runFlow(entry, method, port, signal)\n },\n\n async setDefault(id, account) {\n const list = [...(store.refresh(id) ?? [])]\n const at = list.findIndex(s => s.connection.account === account)\n if (at < 0)\n throw new Error(`${entries.get(id)?.spec.name ?? id}: the account \"${account}\" is not connected.`)\n if (at === 0)\n return\n const [record] = list.splice(at, 1)\n store.persist(id, [record!, ...list])\n },\n\n async disconnect(id, account) {\n const list = store.refresh(id)\n if (!list)\n return\n if (account === undefined)\n return store.persist(id, undefined)\n const rest = list.filter(s => s.connection.account !== account)\n if (rest.length !== list.length)\n store.persist(id, rest)\n },\n\n onChange: (id, listener) => store.onChange(id, listener),\n\n subscribe: listener => store.subscribe(listener),\n\n reload(id) {\n for (const each of id === undefined ? store.known() : [id])\n store.refresh(each)\n },\n }\n return registry\n}\n\n/** Process-wide set of the registries holding at least one registration (every runtime has its own). */\nconst LIVE_SLOT = Symbol.for('zidane.integration-registries')\n\nfunction live(): Set<IntegrationRegistry> {\n const slots = globalThis as { [LIVE_SLOT]?: Set<IntegrationRegistry> }\n slots[LIVE_SLOT] ??= new Set()\n return slots[LIVE_SLOT]\n}\n\n/**\n * The registry where `integrationId` is registered: the installed one first,\n * else any runtime's (they share the credentials file, so any will do).\n * `undefined` when no extension registers it in this process.\n *\n * @param integrationId - The integration id.\n */\nexport function findIntegrationRegistry(integrationId: string): IntegrationRegistry | undefined {\n const installed = integrationRegistry()\n if (installed?.get(integrationId))\n return installed\n for (const registry of live()) {\n if (registry.get(integrationId))\n return registry\n }\n return undefined\n}\n\n/**\n * Connects an integration from a provider's \"Sign in\" (`ProviderDescriptor.integration`):\n * runs one of its flow methods (`oauth` or `custom`) on the host's provider\n * sign-in callbacks, asking which through `onSelect` when there are several.\n * The connection is stored by the registry; nothing is returned to persist.\n *\n * @param integrationId - The integration the provider signs in with.\n * @param callbacks - The sign-in UI's login callbacks (`callbackServer: false` for a remote client).\n * @param opts - Aborts the flow.\n * @param opts.signal - Aborts the flow.\n */\nexport async function signInWithIntegration(integrationId: string, callbacks: OAuthLoginCallbacks & { callbackServer?: false }, opts: { signal?: AbortSignal } = {}): Promise<Connection> {\n const registry = findIntegrationRegistry(integrationId)\n const entry = registry?.get(integrationId)\n if (!registry || !entry)\n throw new Error(`No extension offers the \"${integrationId}\" integration here. Enable the extension that provides it, then sign in again.`)\n const flows = entry.spec.methods.filter(m => m.type === 'oauth' || m.type === 'custom')\n if (flows.length === 0)\n throw new Error(`${entry.spec.name} has no browser sign-in. Connect it from Settings › Integrations.`)\n const methodId = flows.length === 1\n ? flows[0]!.id\n : await callbacks.onSelect({ message: `Sign in to ${entry.spec.name} with`, options: flows.map(m => ({ id: m.id, label: m.label })) })\n if (!methodId)\n throw new Error('Sign-in cancelled.')\n return registry.start(integrationId, methodId, {\n oauthCallbacks: () => callbacks,\n runCommand: async () => { throw new Error('A provider sign-in runs no command.') },\n }, opts.signal ? { signal: opts.signal } : {})\n}\n\n/** Process-wide slot, so every zidane copy in the process (src and dist) shares one registry. */\nconst REGISTRY_SLOT = Symbol.for('zidane.integration-registry')\n\nfunction slot(): { [REGISTRY_SLOT]?: IntegrationRegistry } {\n return globalThis as { [REGISTRY_SLOT]?: IntegrationRegistry }\n}\n\n/**\n * Makes `registry` the process's registry, the one `ctx.integrations` uses\n * by default. Disposing restores the previous one, if `registry` is still\n * the installed one.\n *\n * @param registry - The registry to install.\n */\nexport function installIntegrationRegistry(registry: IntegrationRegistry): Disposable {\n const previous = slot()[REGISTRY_SLOT]\n slot()[REGISTRY_SLOT] = registry\n return {\n dispose: () => {\n if (slot()[REGISTRY_SLOT] !== registry)\n return\n if (previous)\n slot()[REGISTRY_SLOT] = previous\n else\n delete slot()[REGISTRY_SLOT]\n },\n }\n}\n\n/** The process's registry, when a host installed one. */\nexport function integrationRegistry(): IntegrationRegistry | undefined {\n return slot()[REGISTRY_SLOT]\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"registry-BY45AOA-.js","names":[],"sources":["../src/extensions/integrations/oauth.ts","../src/extensions/integrations/connect.ts","../src/extensions/integrations/connections.ts","../src/extensions/integrations/refresh.ts","../src/extensions/integrations/registry.ts"],"sourcesContent":["/**\n * The OAuth flows of an integration's `oauth` method: authorization code\n * with PKCE (RFC 7636) and the device authorization grant (RFC 8628), plus\n * the refresh-token grant.\n *\n * PKCE runs on the `zidane/oauth` kit (`src/oauth-entry.ts`): the loopback\n * callback server and page, `generatePkce`, and the redirect-or-paste race\n * (`awaitAuthorizationCode`), so a remote sign-in (`callbackServer: false`)\n * works as it does for provider sign-ins. The kit is imported lazily:\n * `node:http` stays off the graph until a flow runs.\n *\n * Every network call goes through {@link OAuthIo.fetch} and every wait\n * through {@link OAuthIo.wait}, so tests drive a fake server and clock.\n */\n\nimport type { OAuthLoginCallbacks } from '@earendil-works/pi-ai/oauth'\nimport type { Credential, IntegrationMethod } from '../api/sessions'\n\n/** An `oauth` integration method. */\nexport type OAuthIntegrationMethod = Extract<IntegrationMethod, { type: 'oauth' }>\n\n/** An OAuth credential. */\nexport type OAuthCredential = Extract<Credential, { type: 'oauth' }>\n\n/** The I/O an OAuth flow uses. */\nexport interface OAuthIo {\n /** Sends an HTTP request (the global `fetch` by default). */\n fetch: (url: string, init: RequestInit) => Promise<Response>\n /** Resolves after `ms`, or rejects when `signal` aborts. Device polling waits through it. */\n wait: (ms: number, signal: AbortSignal) => Promise<void>\n /** The current time in ms; expiry times are computed from it. */\n now: () => number\n}\n\n/** What a flow or a refresh yields. */\nexport interface OAuthGrant {\n /** The credential to hand out. */\n credential: OAuthCredential\n /** The refresh token, when the server issued one. */\n refreshToken?: string\n}\n\n/** A token endpoint refused a request. */\nexport class OAuthTokenError extends Error {\n /**\n * @param code - The OAuth `error` code (`invalid_grant`, `authorization_pending`, …), or `http_<status>`.\n * @param description - The server's `error_description`, when given.\n * @param status - The HTTP status.\n */\n constructor(readonly code: string, readonly description: string | undefined, readonly status: number) {\n super(`OAuth token request failed (${status}): ${[code, description].filter(Boolean).join(': ')}`)\n this.name = 'OAuthTokenError'\n }\n}\n\n/** A hung token endpoint must not hold a resolve forever. */\nconst TOKEN_REQUEST_TIMEOUT_MS = 30_000\n/** RFC 8628 §3.2: default polling interval. */\nconst DEFAULT_POLL_INTERVAL_S = 5\n/** RFC 8628 §3.5: `slow_down` adds 5 seconds. */\nconst SLOW_DOWN_STEP_S = 5\n/** When the device endpoint omits `expires_in`. */\nconst DEFAULT_DEVICE_EXPIRY_S = 900\n\n/** Default {@link OAuthIo}: real fetch, timers and clock. */\nexport const defaultOAuthIo: OAuthIo = {\n fetch: (url, init) => fetch(url, init),\n wait: (ms, signal) => new Promise<void>((resolve, reject) => {\n if (signal.aborted)\n return reject(signal.reason)\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n function onAbort(): void {\n clearTimeout(timer)\n reject(signal.reason)\n }\n signal.addEventListener('abort', onAbort, { once: true })\n }),\n now: () => Date.now(),\n}\n\ninterface TokenResponse {\n access_token?: unknown\n refresh_token?: unknown\n expires_in?: unknown\n scope?: unknown\n error?: unknown\n error_description?: unknown\n}\n\n/** Reads a token or device response: JSON, or a form-encoded body (GitHub without `Accept`). */\nfunction parseBody(text: string): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(text)\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))\n return parsed as Record<string, unknown>\n }\n catch { /* not JSON */ }\n return Object.fromEntries(new URLSearchParams(text))\n}\n\nasync function postForm(io: OAuthIo, url: string, body: Record<string, string>, signal?: AbortSignal): Promise<Record<string, unknown>> {\n const timeout = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)\n const response = await io.fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' },\n body: new URLSearchParams(body).toString(),\n signal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n })\n const parsed = parseBody(await response.text())\n if (!response.ok || typeof parsed.error === 'string') {\n const code = typeof parsed.error === 'string' ? parsed.error : `http_${response.status}`\n throw new OAuthTokenError(code, typeof parsed.error_description === 'string' ? parsed.error_description : undefined, response.status)\n }\n return parsed\n}\n\nfunction clientFields(method: OAuthIntegrationMethod): Record<string, string> {\n return { client_id: method.clientId, ...(method.clientSecret ? { client_secret: method.clientSecret } : {}) }\n}\n\n/** The grant a token response carries. */\nfunction toGrant(tokens: TokenResponse, method: OAuthIntegrationMethod, io: OAuthIo, previousRefresh?: string): OAuthGrant {\n if (typeof tokens.access_token !== 'string' || !tokens.access_token)\n throw new Error('The token endpoint returned no access token.')\n const expiresIn = Number(tokens.expires_in)\n const scopes = typeof tokens.scope === 'string' && tokens.scope.trim()\n ? tokens.scope.trim().split(/[\\s,]+/)\n : method.scopes ? [...method.scopes] : undefined\n const refreshToken = typeof tokens.refresh_token === 'string' && tokens.refresh_token ? tokens.refresh_token : previousRefresh\n return {\n credential: {\n type: 'oauth',\n accessToken: tokens.access_token,\n ...(Number.isFinite(expiresIn) && expiresIn > 0 ? { expiresAt: io.now() + expiresIn * 1000 } : {}),\n ...(scopes ? { scopes } : {}),\n },\n ...(refreshToken ? { refreshToken } : {}),\n }\n}\n\nfunction randomHex(bytes: number): string {\n return [...crypto.getRandomValues(new Uint8Array(bytes))].map(b => b.toString(16).padStart(2, '0')).join('')\n}\n\nfunction abortable<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted)\n return Promise.reject(signal.reason)\n return new Promise<T>((resolve, reject) => {\n const onAbort = (): void => reject(signal.reason)\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort))\n })\n}\n\n/**\n * The loopback port and path of a PKCE method's `redirectUri`. Throws for a\n * URI the callback server can't serve.\n *\n * @param redirectUri - The method's `redirectUri`.\n */\nexport function parseLoopbackRedirect(redirectUri: string | undefined): { port: number, path: string } {\n let url: URL\n try {\n url = new URL(redirectUri ?? '')\n }\n catch {\n throw new TypeError(`redirectUri must be a loopback URL with a port, like http://localhost:51121/callback (got ${JSON.stringify(redirectUri)})`)\n }\n const port = Number(url.port)\n if (url.protocol !== 'http:' || !['localhost', '127.0.0.1'].includes(url.hostname) || !Number.isInteger(port) || port <= 0)\n throw new TypeError(`redirectUri must be http://localhost:<port>/<path> or http://127.0.0.1:<port>/<path> (got ${redirectUri})`)\n return { port, path: url.pathname || '/' }\n}\n\n/**\n * Runs the authorization code flow with PKCE: opens the authorize URL\n * (`callbacks.onAuth`), takes the code from the loopback redirect or a\n * pasted URL, and exchanges it at the token endpoint.\n *\n * @param method - The `oauth` method (`flow: 'pkce'`).\n * @param name - The integration's name, shown on the callback page.\n * @param callbacks - The host's login callbacks.\n * @param signal - Aborts the flow.\n * @param io - Network and clock.\n */\nexport async function loginWithPkce(method: OAuthIntegrationMethod, name: string, callbacks: OAuthLoginCallbacks, signal: AbortSignal, io: OAuthIo = defaultOAuthIo): Promise<OAuthGrant> {\n const { port, path } = parseLoopbackRedirect(method.redirectUri)\n const redirectUri = method.redirectUri as string\n const kit = await import('../../oauth-entry')\n const { verifier, challenge } = await kit.generatePkce()\n const state = randomHex(16)\n const server = await kit.startCallbackServer({\n port,\n path,\n expectedState: state,\n providerName: name,\n renderPage: kit.renderDefaultCallbackPage,\n successMessage: 'You can close this tab.',\n onListenError: 'reject',\n ...(kit.listensForCallback(callbacks) ? {} : { listen: false }),\n }).catch((err: unknown) => {\n if ((err as { code?: unknown } | null)?.code === 'EADDRINUSE')\n throw new Error(`Port ${port} is busy, likely another sign-in in progress. Finish or close it, then try again.`)\n throw err\n })\n try {\n const url = new URL(method.authorizeUrl)\n url.searchParams.set('client_id', method.clientId)\n url.searchParams.set('redirect_uri', redirectUri)\n url.searchParams.set('response_type', 'code')\n if (method.scopes?.length)\n url.searchParams.set('scope', method.scopes.join(' '))\n url.searchParams.set('code_challenge', challenge)\n url.searchParams.set('code_challenge_method', 'S256')\n url.searchParams.set('state', state)\n for (const [key, value] of Object.entries(method.params ?? {}))\n url.searchParams.set(key, value)\n callbacks.onAuth({\n url: url.toString(),\n instructions: `Sign in to ${name} in your browser. If the browser is on another machine, paste the final redirect URL here.`,\n })\n const pending = kit.awaitAuthorizationCode(server, state, callbacks)\n pending.catch(() => {})\n const code = await abortable(pending, signal)\n callbacks.onProgress?.('Exchanging authorization code for tokens...')\n const tokens = await postForm(io, method.tokenUrl, {\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n code_verifier: verifier,\n ...clientFields(method),\n }, signal)\n return toGrant(tokens, method, io)\n }\n finally {\n server.close()\n }\n}\n\n/**\n * Runs the device authorization grant: asks the device endpoint for a code,\n * shows it (`callbacks.onDeviceCode`), then polls the token endpoint until\n * the user approves, refuses, or the code expires.\n *\n * @param method - The `oauth` method (`flow: 'device'`).\n * @param callbacks - The host's login callbacks.\n * @param signal - Aborts the flow, polling included.\n * @param io - Network, waits and clock.\n */\nexport async function loginWithDeviceCode(method: OAuthIntegrationMethod, callbacks: OAuthLoginCallbacks, signal: AbortSignal, io: OAuthIo = defaultOAuthIo): Promise<OAuthGrant> {\n if (!method.deviceUrl)\n throw new TypeError('A device flow needs a deviceUrl')\n const start = await postForm(io, method.deviceUrl, {\n ...clientFields(method),\n ...(method.scopes?.length ? { scope: method.scopes.join(' ') } : {}),\n }, signal)\n const deviceCode = start.device_code\n const userCode = start.user_code\n const verificationUri = start.verification_uri ?? start.verification_url\n if (typeof deviceCode !== 'string' || typeof userCode !== 'string' || typeof verificationUri !== 'string')\n throw new Error('The device endpoint returned no device_code, user_code or verification_uri.')\n let intervalS = Number(start.interval) > 0 ? Number(start.interval) : DEFAULT_POLL_INTERVAL_S\n const expiresInS = Number(start.expires_in) > 0 ? Number(start.expires_in) : DEFAULT_DEVICE_EXPIRY_S\n callbacks.onDeviceCode({\n userCode,\n verificationUri: typeof start.verification_uri_complete === 'string' ? start.verification_uri_complete : verificationUri,\n intervalSeconds: intervalS,\n expiresInSeconds: expiresInS,\n })\n // Count waited time rather than reading the clock: the code expires after\n // `expires_in` of polling, and a driven clock in tests never advances.\n let waitedMs = 0\n while (waitedMs < expiresInS * 1000) {\n await io.wait(intervalS * 1000, signal)\n waitedMs += intervalS * 1000\n try {\n const tokens = await postForm(io, method.tokenUrl, {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n ...clientFields(method),\n }, signal)\n return toGrant(tokens, method, io)\n }\n catch (err) {\n if (!(err instanceof OAuthTokenError))\n throw err\n if (err.code === 'authorization_pending')\n continue\n if (err.code === 'slow_down') {\n intervalS += SLOW_DOWN_STEP_S\n continue\n }\n if (err.code === 'access_denied')\n throw new Error('The sign-in was refused.', { cause: err })\n if (err.code === 'expired_token')\n break\n throw err\n }\n }\n throw new Error('The device code expired before the sign-in finished. Try again.')\n}\n\n/**\n * Exchanges a refresh token for a new access token. Keeps the old refresh\n * token when the server does not rotate it.\n *\n * @param method - The `oauth` method the grant came from.\n * @param refreshToken - The stored refresh token.\n * @param io - Network and clock.\n * @param signal - Aborts the request.\n */\nexport async function refreshOAuthGrant(method: OAuthIntegrationMethod, refreshToken: string, io: OAuthIo = defaultOAuthIo, signal?: AbortSignal): Promise<OAuthGrant> {\n const tokens = await postForm(io, method.tokenUrl, {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n ...clientFields(method),\n }, signal)\n return toGrant(tokens, method, io, refreshToken)\n}\n","/**\n * The checks around connecting: spec validation, and the extension\n * callbacks (`beforeConnect`, `verify`, `account`, `parseCommandOutput`)\n * run through the registering extension's guard. A callback's throw or\n * returned message becomes the connect's error; a timeout refuses too.\n * A `custom` method's `connect` runs here too, on the host's flow UI\n * ({@link customFlowIo}).\n */\n\nimport type { OAuthLoginCallbacks } from '@earendil-works/pi-ai/oauth'\nimport type { Credential, IntegrationCustomMethod, IntegrationCustomResult, IntegrationFlowIO, IntegrationMethod, IntegrationSpec } from '../api/sessions'\nimport type { Guard } from '../runtime/deps'\nimport { errorMessage } from '../../errors'\nimport { parseLoopbackRedirect } from './oauth'\n\n/** What a host shows while a connect flow runs. */\nexport interface IntegrationFlowRequest {\n /** The integration being connected. */\n integrationId: string\n /** Its display name. */\n name: string\n /** The method the user picked. */\n method: IntegrationMethod\n /** Aborts when the flow is cancelled. */\n signal: AbortSignal\n}\n\n/** The outcome of a `command` method's process. */\nexport interface IntegrationCommandResult {\n /** Standard output; the credential is read from it. */\n stdout: string\n /** Standard error, quoted when the command fails. */\n stderr?: string\n /** Exit code; anything but 0 fails the connect. */\n exitCode: number\n}\n\n/**\n * What a host provides for connect flows. The TUI, desktop and daemon each\n * implement it once; Settings and `ctx.integrations.connect.start` both use it.\n */\nexport interface IntegrationFlowPort {\n /**\n * The login callbacks for an OAuth flow: open `onAuth`'s URL, show\n * `onDeviceCode`'s code, read a pasted redirect (`onManualCodeInput`),\n * show progress. The same callbacks hosts already build for provider\n * sign-in (`runOAuthLogin` in `src/chat/oauth.ts`); set\n * `callbackServer: false` for a client of a remote host.\n */\n oauthCallbacks: (request: IntegrationFlowRequest) => OAuthLoginCallbacks & { callbackServer?: false }\n /** Runs a `command` method's argv (no shell) and returns its output. */\n runCommand: (command: readonly string[], opts: { signal: AbortSignal }) => Promise<IntegrationCommandResult>\n}\n\n/** Integration ids become credential-file keys: no `#` (reserved for provider slots), no spaces. */\nconst ID_PATTERN = /^[\\w.:-]+$/\n\n/**\n * Throws a `TypeError` naming the first problem of a spec.\n *\n * @param spec - The spec an extension registers.\n */\nexport function validateSpec(spec: IntegrationSpec): void {\n if (!spec || typeof spec.id !== 'string' || !ID_PATTERN.test(spec.id))\n throw new TypeError(`integrations.register: id must match ${ID_PATTERN} (got ${JSON.stringify(spec?.id)})`)\n if (typeof spec.name !== 'string' || !spec.name)\n throw new TypeError(`integrations.register(${spec.id}): name is required`)\n if (!Array.isArray(spec.methods) || spec.methods.length === 0)\n throw new TypeError(`integrations.register(${spec.id}): at least one method is required`)\n const ids = new Set<string>()\n for (const method of spec.methods) {\n const where = `integrations.register(${spec.id}): method ${method.id}`\n if (!method.id || ids.has(method.id))\n throw new TypeError(`integrations.register(${spec.id}): method ids must be unique and non-empty (got ${JSON.stringify(method.id)})`)\n ids.add(method.id)\n if (method.type === 'oauth' && method.flow === 'pkce') {\n try {\n parseLoopbackRedirect(method.redirectUri)\n }\n catch (err) {\n throw new TypeError(`${where}: ${errorMessage(err)}`)\n }\n }\n if (method.type === 'oauth' && method.flow === 'device' && !method.deviceUrl)\n throw new TypeError(`${where}: a device flow needs a deviceUrl`)\n if (method.type === 'command' && (!Array.isArray(method.command) || method.command.length === 0))\n throw new TypeError(`${where}: command is empty`)\n if (method.type === 'custom' && typeof method.connect !== 'function')\n throw new TypeError(`${where}: a custom method needs a connect function`)\n if (method.type === 'custom' && method.refresh !== undefined && typeof method.refresh !== 'function')\n throw new TypeError(`${where}: refresh must be a function`)\n }\n if (spec.beforeConnect !== undefined && typeof spec.beforeConnect !== 'function')\n throw new TypeError(`integrations.register(${spec.id}): beforeConnect must be a function`)\n if (spec.legacyCredentialKey !== undefined && (typeof spec.legacyCredentialKey !== 'string' || !spec.legacyCredentialKey || spec.legacyCredentialKey.includes('#')))\n throw new TypeError(`integrations.register(${spec.id}): legacyCredentialKey must be a credentials-file key without \"#\"`)\n}\n\n/**\n * Runs the spec's `beforeConnect` for `method`. Throws its message when it\n * refuses (or throws); a timeout refuses too.\n *\n * @param spec - The integration.\n * @param guard - The registering extension's guard.\n * @param method - The method the user picked.\n */\nexport async function checkBeforeConnect(spec: IntegrationSpec, guard: Guard, method: IntegrationMethod): Promise<void> {\n const check = spec.beforeConnect\n if (!check)\n return\n const outcome = await guard.call(`integrations.beforeConnect(${spec.id})`, async () => {\n try {\n return { refusal: await check(method) }\n }\n catch (err) {\n return { refusal: errorMessage(err) || `${spec.name} refused to connect.` }\n }\n }, { fallback: { refusal: `${spec.name}: the connect check did not answer.` } })\n if (typeof outcome?.refusal === 'string' && outcome.refusal)\n throw new Error(outcome.refusal)\n}\n\n/**\n * The {@link IntegrationFlowIO} of a `custom` method, on the host's OAuth\n * login callbacks: links (`onAuth`), codes (`onDeviceCode`), questions\n * (`onPrompt`, `onSelect`) and progress lines (`onProgress`).\n *\n * @param callbacks - The host's login callbacks for this flow.\n * @param signal - Aborts the flow.\n */\nexport function customFlowIo(callbacks: OAuthLoginCallbacks, signal: AbortSignal): IntegrationFlowIO {\n return {\n openUrl: url => callbacks.onAuth({ url }),\n showCode: (code, url) => callbacks.onDeviceCode({ userCode: code, verificationUri: url ?? '' }),\n prompt: async (opts) => {\n try {\n if (opts.options)\n return await callbacks.onSelect({ message: opts.message, options: opts.options.map(o => ({ id: o.id, label: o.label })) })\n return await callbacks.onPrompt({ message: opts.message, ...(opts.placeholder ? { placeholder: opts.placeholder } : {}), ...(opts.allowEmpty ? { allowEmpty: true } : {}) })\n }\n catch (err) {\n // A host rejects a dismissed question; the flow reads that as a cancel unless the whole flow was aborted.\n if (signal.aborted)\n throw err\n return undefined\n }\n },\n signal,\n log: message => callbacks.onProgress?.(message),\n }\n}\n\n/**\n * Runs a `custom` method's `connect` and checks what it returns. Its\n * errors become the connect's (prefixed with the integration's name).\n *\n * @param spec - The integration.\n * @param method - The `custom` method.\n * @param io - The flow UI.\n */\nexport async function customCredential(spec: IntegrationSpec, method: IntegrationCustomMethod, io: IntegrationFlowIO): Promise<IntegrationCustomResult> {\n let result: IntegrationCustomResult\n try {\n result = await method.connect(io)\n }\n catch (err) {\n io.signal.throwIfAborted()\n throw new Error(`${spec.name}: ${errorMessage(err) || 'the sign-in failed'}`, { cause: err })\n }\n io.signal.throwIfAborted()\n const credential = validCredential(result?.credential)\n if (!credential)\n throw new Error(`${spec.name}: the sign-in returned no usable credential.`)\n const text = (v: unknown): string | undefined => (typeof v === 'string' && v.trim() ? v.trim() : undefined)\n const account = text(result.account)\n const label = text(result.label)\n return { credential, ...(account ? { account } : {}), ...(label ? { label } : {}) }\n}\n\n/**\n * The credential an extension built, checked; `undefined` when it is not one.\n *\n * @param value - What `parseCommandOutput` returned.\n */\nexport function validCredential(value: unknown): Credential | undefined {\n const c = value as Partial<Record<string, unknown>> | null\n if (!c || typeof c !== 'object')\n return undefined\n if (c.type === 'apiKey' && typeof c.key === 'string' && c.key)\n return { type: 'apiKey', key: c.key }\n if (c.type === 'token' && typeof c.token === 'string' && c.token)\n return { type: 'token', token: c.token }\n if (c.type === 'oauth' && typeof c.accessToken === 'string' && c.accessToken) {\n return {\n type: 'oauth',\n accessToken: c.accessToken,\n ...(typeof c.expiresAt === 'number' ? { expiresAt: c.expiresAt } : {}),\n ...(Array.isArray(c.scopes) ? { scopes: c.scopes.filter((s): s is string => typeof s === 'string') } : {}),\n ...(typeof c.refreshToken === 'string' && c.refreshToken ? { refreshToken: c.refreshToken } : {}),\n ...(c.extra && typeof c.extra === 'object' && !Array.isArray(c.extra) ? { extra: structuredClone(c.extra as Record<string, unknown>) } : {}),\n }\n }\n return undefined\n}\n\n/**\n * Runs the spec's `verify`. Throws when it refuses, throws or times out.\n *\n * @param spec - The integration.\n * @param guard - The registering extension's guard.\n * @param credential - The credential to check.\n */\nexport async function verifyCredential(spec: IntegrationSpec, guard: Guard, credential: Credential): Promise<void> {\n const verify = spec.verify\n if (!verify)\n return\n const outcome = await guard.call(`integrations.verify(${spec.id})`, async () => {\n try {\n return { error: await verify(credential) }\n }\n catch (err) {\n return { error: errorMessage(err) || 'verification failed' }\n }\n }, { fallback: { error: 'verification did not answer' } })\n if (outcome?.error)\n throw new Error(`${spec.name}: ${outcome.error}`)\n}\n\n/**\n * The spec's `account` label for a credential. `undefined` when it has none, throws or times out.\n *\n * @param spec - The integration.\n * @param guard - The registering extension's guard.\n * @param credential - The new credential.\n */\nexport async function accountLabel(spec: IntegrationSpec, guard: Guard, credential: Credential): Promise<string | undefined> {\n const account = spec.account\n if (!account)\n return undefined\n const label = await guard.call(`integrations.account(${spec.id})`, () => account(credential))\n return typeof label === 'string' && label ? label : undefined\n}\n\n/**\n * Runs a `command` method through the host and reads its credential: the\n * spec's `parseCommandOutput`, or by default the trimmed stdout as a token.\n *\n * @param spec - The integration.\n * @param guard - The registering extension's guard.\n * @param method - The `command` method.\n * @param port - The host's command runner.\n * @param signal - Aborts the command.\n */\nexport async function commandCredential(spec: IntegrationSpec, guard: Guard, method: Extract<IntegrationMethod, { type: 'command' }>, port: IntegrationFlowPort, signal: AbortSignal): Promise<Credential> {\n const shown = method.command.join(' ')\n const result = await port.runCommand(method.command, { signal })\n if (result.exitCode !== 0) {\n const detail = (result.stderr ?? '').trim().split('\\n')[0]\n throw new Error(`${shown} failed (exit ${result.exitCode})${detail ? `: ${detail}` : ''}`)\n }\n const parse = spec.parseCommandOutput\n if (!parse) {\n const token = result.stdout.trim()\n if (!token)\n throw new Error(`${shown} printed nothing.`)\n return { type: 'token', token }\n }\n const parsed = guard.callSync(`integrations.parseCommandOutput(${spec.id})`, () => {\n try {\n return { credential: parse(result.stdout) as unknown }\n }\n catch (err) {\n return { error: errorMessage(err) }\n }\n })\n if (parsed && 'error' in parsed)\n throw new Error(`${spec.name}: could not read the command output: ${parsed.error}`)\n const credential = validCredential(parsed?.credential)\n if (!credential)\n throw new Error(`${spec.name}: parseCommandOutput returned no usable credential.`)\n return credential\n}\n","/**\n * The registry's view of stored connections: a cache over the\n * {@link AuthStorePort} (one list per integration, the default first),\n * change detection and notification (`onChange` listeners per integration,\n * Settings subscribers), and the adoption of a legacy provider sign-in\n * (`IntegrationSpec.legacyCredentialKey`).\n */\n\nimport type { Logger } from '../../logger'\nimport type { Connection, IntegrationSpec } from '../api/sessions'\nimport type { AuthStorePort, StoredIntegration } from './store'\nimport { errorMessage } from '../../errors'\nimport { DEFAULT_ACCOUNT } from './auth-store-port'\n\n/** An integration's stored connections, the default first. */\nexport type Stored = StoredIntegration[]\n\n/** What the cache reads through. */\nexport interface ConnectionCacheDeps {\n store: AuthStorePort\n logger?: Logger\n /** The clock adopted connections are stamped with. */\n now: () => number\n /** The registered spec of an integration (for its `legacyCredentialKey`). */\n spec: (integrationId: string) => IntegrationSpec | undefined\n}\n\n/** The connections a store record holds, as `connections()` lists them (`isDefault` on the first). */\nexport function view(list: Stored | undefined | null): Connection[] {\n return (list ?? []).map((s, i) => ({ ...s.connection, ...(i === 0 ? { isDefault: true } : {}) }))\n}\n\nfunction connectionsKey(list: Stored | undefined | null): string {\n return JSON.stringify((list ?? []).map(s => s.connection))\n}\n\n/**\n * Makes the cache.\n *\n * @param deps - Store, logger, clock and spec lookup.\n */\nexport function createConnectionCache(deps: ConnectionCacheDeps) {\n const { store, logger } = deps\n /** Stored records read so far; `null` is \"read, none stored\". */\n const cache = new Map<string, Stored | null>()\n const listeners = new Map<string, Set<(connection: Connection | undefined) => void>>()\n const subscribers = new Set<() => void>()\n\n const safely = (what: string, fn: () => void, attrs?: Record<string, unknown>): void => {\n try {\n fn()\n }\n catch (err) {\n logger?.warn(`integrations: ${what} threw`, { ...attrs, error: errorMessage(err) })\n }\n }\n\n /** Adopts the legacy sign-in a spec names, when the integration has no connection. */\n function adoptLegacy(id: string): Stored | undefined {\n const spec = deps.spec(id)\n const key = spec?.legacyCredentialKey\n if (!spec || !key || !store.readLegacy)\n return undefined\n const grant = store.readLegacy(key)\n if (!grant)\n return undefined\n const methods = spec.methods\n const method = grant.credential.type === 'oauth'\n ? methods.find(m => m.type === 'oauth' || m.type === 'custom')\n : methods.find(m => m.type === 'apiKey') ?? methods.find(m => m.type === 'command')\n const account = grant.account ?? DEFAULT_ACCOUNT\n const record: StoredIntegration = {\n connection: {\n integrationId: id,\n methodId: (method ?? methods[0]!).id,\n account,\n ...(grant.label && grant.label !== account ? { label: grant.label } : {}),\n connectedAt: deps.now(),\n },\n credential: grant.credential,\n ...(grant.refreshToken ? { refreshToken: grant.refreshToken } : {}),\n }\n store.write(id, [record])\n store.markLegacy?.(key, id)\n logger?.info(`integrations: adopted the legacy sign-in under \"${key}\" as a connection of ${id}`)\n return [record]\n }\n\n /** Reads one record fresh from the store (adopting a legacy sign-in when it is empty). */\n function read(id: string): Stored | undefined {\n let value: Stored | undefined\n try {\n // A port written before several connections returns one record: read it as the only one.\n const raw = store.read(id) as Stored | StoredIntegration | undefined\n value = raw === undefined || Array.isArray(raw) ? raw : [raw]\n if (!value?.length)\n value = adoptLegacy(id)\n }\n catch (err) {\n logger?.warn('integrations: could not read the stored connections', { integration: id, error: errorMessage(err) })\n }\n const list = value?.length ? value : undefined\n cache.set(id, list ?? null)\n return list\n }\n\n function cached(id: string): Stored | undefined {\n const value = cache.get(id)\n return value === undefined ? read(id) : value ?? undefined\n }\n\n function notify(): void {\n for (const listener of [...subscribers])\n safely('a subscriber', listener)\n }\n\n function emit(id: string, list: Stored | undefined): void {\n const first = view(list)[0]\n for (const listener of [...listeners.get(id) ?? []])\n safely('an onChange listener', () => listener(first ? { ...first } : undefined), { integration: id })\n notify()\n }\n\n /** Re-reads one record and emits when its connections differ from what was cached. */\n function refresh(id: string): Stored | undefined {\n const before = cache.get(id)\n const after = read(id)\n if (before !== undefined && connectionsKey(before) !== connectionsKey(after))\n emit(id, after)\n return after\n }\n\n /** Writes a record (or deletes it) and emits when the connections changed. */\n function persist(id: string, value: Stored | undefined): void {\n const before = cached(id)\n const list = value?.length ? value : undefined\n store.write(id, list)\n cache.set(id, list ? structuredClone(list) : null)\n if (connectionsKey(before) !== connectionsKey(list))\n emit(id, list)\n }\n\n /** Replaces the connection of the same account, or adds it last. */\n function put(id: string, record: StoredIntegration): void {\n // Fresh from the store: another process may have added an account since the last read.\n const list = [...(refresh(id) ?? [])]\n const at = list.findIndex(s => s.connection.account === record.connection.account)\n if (at >= 0)\n list[at] = record\n else\n list.push(record)\n persist(id, list)\n }\n\n return {\n read,\n cached,\n refresh,\n persist,\n put,\n notify,\n /** Forgets a \"none stored\" read, so the next read may adopt a legacy sign-in. */\n forgetEmpty: (id: string): void => {\n if (cache.get(id) === null)\n cache.delete(id)\n },\n /** Integrations read so far. */\n known: (): string[] => [...cache.keys()],\n onChange(id: string, listener: (connection: Connection | undefined) => void): () => void {\n let set = listeners.get(id)\n if (!set)\n listeners.set(id, set = new Set())\n set.add(listener)\n return () => {\n set.delete(listener)\n if (set.size === 0 && listeners.get(id) === set)\n listeners.delete(id)\n }\n },\n subscribe(listener: () => void): () => void {\n subscribers.add(listener)\n return () => {\n subscribers.delete(listener)\n }\n },\n }\n}\n","/**\n * Refresh of expiring OAuth connections, on `resolveOAuthApiKey`\n * (`src/providers/oauth.ts`), the code provider sign-ins refresh through:\n * concurrent resolves of one connection share one refresh (keyed by the\n * stored grant and these functions' identities, hence one stable binding\n * per connection), and the refreshed grant is written only when the stored\n * one did not change meanwhile.\n *\n * An `oauth` method refreshes with the refresh-token grant; a `custom`\n * method with its own `refresh`. Each refresh is reported to `onRefresh`\n * (the `oauth:refresh` observation).\n */\n\nimport type { OAuthCredentials } from '@earendil-works/pi-ai/oauth'\nimport type { OAuthRefreshHookContext } from '../../types'\nimport type { Credential, IntegrationMethod } from '../api/sessions'\nimport type { OAuthIo } from './oauth'\nimport type { StoredIntegration } from './store'\nimport { AgentAuthError, errorMessage } from '../../errors'\nimport { resolveOAuthApiKey } from '../../providers/oauth'\nimport { validCredential } from './connect'\nimport { refreshOAuthGrant } from './oauth'\n\n/** Stands for \"no expiry\" in the `expires` field `resolveOAuthApiKey` requires; never stored. */\nconst NO_EXPIRY = Number.MAX_SAFE_INTEGER\n\n/** What the refresher reads and writes through (the registry's cached store). */\nexport interface RefresherDeps {\n /** OAuth network and clock. */\n io: OAuthIo\n /** Refresh this long before expiry. */\n skewMs: number\n /** Reads one connection fresh from the store. */\n read: (integrationId: string, account: string) => StoredIntegration | undefined\n /** Replaces one connection (the registry emits changes). */\n write: (integrationId: string, account: string, value: StoredIntegration) => void\n /** The method of a registered integration, `undefined` when unregistered. */\n method: (integrationId: string, methodId: string) => IntegrationMethod | undefined\n /** Told of each refresh that rotated a grant. */\n onRefresh?: (event: OAuthRefreshHookContext) => void | Promise<void>\n}\n\n/** Refreshes stored OAuth connections. */\nexport interface Refresher {\n /** Whether a stored credential expires within the skew. */\n due: (stored: StoredIntegration) => boolean\n /** The record after refreshing it (or as stored, when it can't refresh and has not expired). */\n refresh: (integrationId: string, name: string, stored: StoredIntegration) => Promise<StoredIntegration>\n}\n\ninterface Binding {\n read: () => Record<string, OAuthCredentials | undefined>\n write: (patch: Record<string, OAuthCredentials | undefined>) => void\n exchange: (providerId: string, credentials: Record<string, OAuthCredentials>, options?: { force?: boolean }) => Promise<{ newCredentials: OAuthCredentials, apiKey: string } | null>\n}\n\n/** The key a binding reads and writes its one connection under (never stored). */\nfunction slotOf(id: string, account: string): string {\n return `${id}#${account}`\n}\n\nfunction toOAuthCredentials(stored: StoredIntegration): OAuthCredentials | undefined {\n const credential = stored.credential\n if (credential.type !== 'oauth' || credential.expiresAt === undefined)\n return undefined\n return {\n access: credential.accessToken,\n refresh: stored.refreshToken ?? '',\n expires: credential.expiresAt,\n ...(credential.scopes ? { scopes: [...credential.scopes] } : {}),\n ...(credential.extra ? { extra: structuredClone(credential.extra) } : {}),\n }\n}\n\nfunction fromOAuthCredentials(next: OAuthCredentials): { credential: Credential, refreshToken?: string } {\n const scopes = Array.isArray(next.scopes) ? next.scopes as string[] : undefined\n const extra = next.extra && typeof next.extra === 'object' ? next.extra as Record<string, unknown> : undefined\n return {\n credential: {\n type: 'oauth',\n accessToken: next.access,\n ...(next.expires < NO_EXPIRY ? { expiresAt: next.expires } : {}),\n ...(scopes ? { scopes } : {}),\n ...(extra ? { extra } : {}),\n },\n ...(next.refresh ? { refreshToken: next.refresh } : {}),\n }\n}\n\n/**\n * Makes a refresher.\n *\n * @param deps - Store access, method lookup, I/O, skew and the refresh observer.\n */\nexport function createRefresher(deps: RefresherDeps): Refresher {\n const { io, skewMs } = deps\n const bindings = new Map<string, Binding>()\n\n async function renew(id: string, account: string, creds: OAuthCredentials): Promise<OAuthCredentials> {\n const stored = deps.read(id, account)\n const method = stored ? deps.method(id, stored.connection.methodId) : undefined\n if (method?.type === 'custom') {\n if (!method.refresh)\n throw new Error('the sign-in can\\'t be renewed')\n const current = fromOAuthCredentials(creds)\n const credential = { ...current.credential, ...(current.refreshToken ? { refreshToken: current.refreshToken } : {}) } as Credential\n const result = validCredential(await method.refresh(structuredClone(credential)))\n if (result?.type !== 'oauth')\n throw new Error('the refresh returned no OAuth credential')\n return {\n access: result.accessToken,\n refresh: result.refreshToken ?? creds.refresh,\n expires: result.expiresAt ?? NO_EXPIRY,\n ...(result.scopes ? { scopes: [...result.scopes] } : {}),\n ...(result.extra ? { extra: result.extra } : creds.extra ? { extra: creds.extra } : {}),\n }\n }\n if (method?.type !== 'oauth')\n throw new Error('the integration that issued it is not registered')\n const grant = await refreshOAuthGrant(method, creds.refresh, io)\n return {\n ...creds,\n access: grant.credential.accessToken,\n refresh: grant.refreshToken ?? creds.refresh,\n // A refreshed token without an expiry never needs another refresh by time.\n expires: grant.credential.expiresAt ?? NO_EXPIRY,\n ...(grant.credential.scopes ? { scopes: [...grant.credential.scopes] } : {}),\n }\n }\n\n /** Display names, for the refresh event (a spec's name can change). */\n const names = new Map<string, string>()\n\n function bindingFor(id: string, account: string): Binding {\n const slot = slotOf(id, account)\n const existing = bindings.get(slot)\n if (existing)\n return existing\n const binding: Binding = {\n read: () => {\n const stored = deps.read(id, account)\n return { [slot]: stored ? toOAuthCredentials(stored) : undefined }\n },\n write: (patch) => {\n const next = patch[slot]\n const current = deps.read(id, account)\n if (!next || !current)\n return\n deps.write(id, account, { connection: current.connection, ...fromOAuthCredentials(next) })\n // Once per rotation, here rather than per resolve: concurrent resolves share one refresh.\n const previous = toOAuthCredentials(current)\n if (deps.onRefresh && previous) {\n // Observers are any extension's: the refresh token stays in the store.\n const event: OAuthRefreshHookContext = { provider: names.get(id) ?? id, providerId: id, source: 'file', previousCredentials: { ...previous, refresh: '' }, credentials: { ...structuredClone(next), refresh: '' } }\n void Promise.resolve().then(() => deps.onRefresh?.(event)).catch(() => {})\n }\n },\n exchange: async (providerId, credentials, opts) => {\n const creds = credentials[providerId]\n if (!creds)\n return null\n if (!opts?.force && creds.expires - skewMs > io.now())\n return { newCredentials: creds, apiKey: creds.access }\n const next = await renew(id, account, creds)\n return { newCredentials: next, apiKey: next.access }\n },\n }\n bindings.set(slot, binding)\n return binding\n }\n\n function canRenew(id: string, stored: StoredIntegration): boolean {\n if (stored.refreshToken)\n return true\n const method = deps.method(id, stored.connection.methodId)\n return method?.type === 'custom' && typeof method.refresh === 'function'\n }\n\n return {\n due: (stored) => {\n const credential = stored.credential\n return credential.type === 'oauth' && credential.expiresAt !== undefined && credential.expiresAt - skewMs <= io.now()\n },\n\n async refresh(id, name, stored) {\n const { account } = stored.connection\n if (!canRenew(id, stored)) {\n if (stored.credential.type === 'oauth' && (stored.credential.expiresAt ?? Infinity) <= io.now())\n throw new AgentAuthError(`${name}: the sign-in expired. Connect again.`, { kind: 'expired', source: 'integration', provider: name, providerId: id, ...(account ? { accountId: account } : {}) })\n return stored\n }\n names.set(id, name)\n const binding = bindingFor(id, account)\n // Another writer (a second window) may rotate the grant between our\n // read and our write: `resolveOAuthApiKey` refuses that write, and one\n // more pass reads the grant it stored.\n for (let attempt = 0; ; attempt++) {\n try {\n await resolveOAuthApiKey({\n provider: name,\n providerId: id,\n credentialKey: slotOf(id, account),\n readCredentials: binding.read,\n writeCredentials: binding.write,\n getOAuthApiKey: binding.exchange,\n authSource: 'integration',\n missingError: `${name} is not connected.`,\n refreshError: reason => `${name}: could not refresh the sign-in (${reason}). Connect again if it keeps failing.`,\n })\n break\n }\n catch (err) {\n if (attempt > 0 || !/changed during refresh/.test(errorMessage(err)))\n throw err\n }\n }\n const after = deps.read(id, account)\n if (!after)\n throw new Error(`${name} is not connected.`)\n return after\n },\n }\n}\n","/**\n * The process-wide integration registry: the specs extensions register\n * (first id wins), their connections (through an {@link AuthStorePort}),\n * the connect flows, and credential resolution with OAuth refresh\n * (`./refresh`).\n *\n * An integration holds several connections, one per account; the first is\n * the default. Connecting an account already connected replaces it; the\n * first connection becomes the default. A spec's `legacyCredentialKey`\n * adopts a legacy provider sign-in the first time the integration is read with\n * no connection.\n *\n * Each extension's `ctx.integrations` (`./domain`) is a view on one\n * registry; Settings reads the same registry to draw Connect / Disconnect.\n * Extension callbacks run through the registering extension's guard\n * (`./connect`).\n */\n\nimport type { OAuthLoginCallbacks } from '@earendil-works/pi-ai/oauth'\nimport type { Logger } from '../../logger'\nimport type { OAuthRefreshHookContext } from '../../types'\nimport type { Disposable } from '../api/core'\nimport type { Connection, Credential, IntegrationMethod, IntegrationSpec, IntegrationSpecPatch } from '../api/sessions'\nimport type { Guard } from '../runtime/deps'\nimport type { IntegrationFlowPort } from './connect'\nimport type { OAuthGrant, OAuthIo } from './oauth'\nimport type { AuthStorePort } from './store'\nimport { DEFAULT_ACCOUNT } from './auth-store-port'\nimport { accountLabel, checkBeforeConnect, commandCredential, customCredential, customFlowIo, validateSpec, verifyCredential } from './connect'\nimport { createConnectionCache, view } from './connections'\nimport { defaultOAuthIo, loginWithDeviceCode, loginWithPkce } from './oauth'\nimport { createRefresher } from './refresh'\n\n/** Who registers a spec: its callbacks run through this guard. */\nexport interface IntegrationRegistrant {\n /** The registering extension. */\n extensionId: string\n /** That extension's guard. */\n guard: Guard\n}\n\n/** A registered integration, as Settings lists it. */\nexport interface IntegrationEntry {\n /** The spec. */\n spec: IntegrationSpec\n /** The extension that registered it. */\n extensionId: string\n /** Its default connection, if connected. */\n connection: Connection | undefined\n /** Every connection, the default first. */\n connections: Connection[]\n}\n\n/** A registration in the registry. */\nexport interface IntegrationRegistration extends Disposable {\n /** Replaces fields of the spec (validated; throws a `TypeError` and keeps the spec when invalid). No-op once disposed. */\n update: (patch: IntegrationSpecPatch) => void\n}\n\n/** What a registry is built on. */\nexport interface IntegrationRegistryOptions {\n /** Where connections persist. */\n store: AuthStorePort\n /** Network, waits and clock of the OAuth flows. Defaults to the real ones. */\n io?: Partial<OAuthIo>\n /** Refresh OAuth tokens this long before they expire. Default 60 s. */\n refreshSkewMs?: number\n /** Logs store failures, throwing listeners and refused registrations. */\n logger?: Logger\n /** Told of each refresh that rotated a grant (hosts fire the `oauth:refresh` observation with it). */\n onRefresh?: (event: OAuthRefreshHookContext) => void | Promise<void>\n}\n\n/** The process-wide integration registry. */\nexport interface IntegrationRegistry {\n /**\n * Registers a spec. Returns `undefined` when the id is taken: the first\n * registration wins. Throws a `TypeError` for an invalid spec.\n */\n register: (spec: IntegrationSpec, by: IntegrationRegistrant) => IntegrationRegistration | undefined\n /** A registered integration. */\n get: (integrationId: string) => IntegrationEntry | undefined\n /** Every registered integration, in registration order. */\n list: () => IntegrationEntry[]\n /** Every stored connection of an integration, registered or not, the default first. */\n connections: (integrationId: string) => Connection[]\n /** The default stored connection of an integration, or the one of `account`. */\n connection: (integrationId: string, account?: string) => Connection | undefined\n /** The credential of a connection (an id means its default), refreshed when it expires soon. Rejects when not connected. */\n resolve: (connection: Connection | string) => Promise<Credential>\n /** Connects with an API key: check, verify, then persist. Uses the first `apiKey` method unless `methodId` names one. */\n connectKey: (integrationId: string, key: string, methodId?: string) => Promise<Connection>\n /** Runs an `oauth`, `command` or `custom` method, then verifies and persists. */\n start: (integrationId: string, methodId: string, port: IntegrationFlowPort, opts?: { signal?: AbortSignal }) => Promise<Connection>\n /** Makes the connection of `account` the default. Rejects when there is none. */\n setDefault: (integrationId: string, account: string) => Promise<void>\n /** Deletes the connection of `account`, or all of them. */\n disconnect: (integrationId: string, account?: string) => Promise<void>\n /** Calls `listener` with the default connection when any connection of an integration changes. Returns the unsubscribe. */\n onChange: (integrationId: string, listener: (connection: Connection | undefined) => void) => () => void\n /** Calls `listener` after any spec or connection change (for Settings). Returns the unsubscribe. */\n subscribe: (listener: () => void) => () => void\n /** Re-reads stored connections (all read so far, or one) after the store changed outside the registry; emits what changed. */\n reload: (integrationId?: string) => void\n}\n\ninterface Entry {\n spec: IntegrationSpec\n by: IntegrationRegistrant\n}\n\n/**\n * Makes a registry. Hosts make one per process and install it with\n * {@link installIntegrationRegistry}; tests make their own.\n *\n * @param options - The store, OAuth I/O, refresh skew, logger and refresh observer.\n */\nexport function createIntegrationRegistry(options: IntegrationRegistryOptions): IntegrationRegistry {\n const { logger } = options\n const io: OAuthIo = { ...defaultOAuthIo, ...options.io }\n const entries = new Map<string, Entry>()\n // Assigned below; registrations join the process-wide live set under it.\n\n let registry: IntegrationRegistry\n const store = createConnectionCache({ store: options.store, ...(logger ? { logger } : {}), now: io.now, spec: id => entries.get(id)?.spec })\n\n const refresher = createRefresher({\n io,\n skewMs: options.refreshSkewMs ?? 60_000,\n read: (id, account) => store.read(id)?.find(s => s.connection.account === account),\n write: (id, _account, value) => store.put(id, value),\n method: (id, methodId) => entries.get(id)?.spec.methods.find(m => m.id === methodId),\n ...(options.onRefresh ? { onRefresh: options.onRefresh } : {}),\n })\n\n function entryOf(id: string): Entry {\n const entry = entries.get(id)\n if (!entry)\n throw new Error(`No integration \"${id}\" is registered.`)\n return entry\n }\n\n function methodOf(entry: Entry, methodId: string): IntegrationMethod {\n const method = entry.spec.methods.find(m => m.id === methodId)\n if (!method)\n throw new Error(`${entry.spec.name} has no connect method \"${methodId}\".`)\n return method\n }\n\n async function finish(entry: Entry, method: IntegrationMethod, issued: Credential, refreshToken?: string, named: { account?: string, label?: string } = {}): Promise<Connection> {\n // A custom method hands its refresh token in the credential: the store keeps it beside.\n const { refreshToken: carried, ...credential } = issued as Credential & { refreshToken?: string }\n const refresh = refreshToken ?? carried\n await verifyCredential(entry.spec, entry.by.guard, credential as Credential)\n const account = named.account ?? await accountLabel(entry.spec, entry.by.guard, credential as Credential) ?? DEFAULT_ACCOUNT\n const label = named.label\n const connection: Connection = {\n integrationId: entry.spec.id,\n methodId: method.id,\n account,\n ...(label && label !== account ? { label } : {}),\n connectedAt: io.now(),\n }\n store.put(entry.spec.id, { connection, credential: credential as Credential, ...(refresh ? { refreshToken: refresh } : {}) })\n return view(store.cached(entry.spec.id)).find(c => c.account === account) ?? { ...connection }\n }\n\n async function runFlow(entry: Entry, method: Exclude<IntegrationMethod, { type: 'apiKey' }>, port: IntegrationFlowPort, signal: AbortSignal): Promise<Connection> {\n if (method.type === 'command')\n return finish(entry, method, await commandCredential(entry.spec, entry.by.guard, method, port, signal))\n const callbacks = port.oauthCallbacks({ integrationId: entry.spec.id, name: entry.spec.name, method, signal })\n if (method.type === 'custom') {\n const result = await customCredential(entry.spec, method, customFlowIo(callbacks, signal))\n return finish(entry, method, result.credential, undefined, result)\n }\n const grant: OAuthGrant = method.flow === 'device'\n ? await loginWithDeviceCode(method, callbacks, signal, io)\n : await loginWithPkce(method, entry.spec.name, callbacks, signal, io)\n signal.throwIfAborted()\n return finish(entry, method, grant.credential, grant.refreshToken)\n }\n\n function register(spec: IntegrationSpec, by: IntegrationRegistrant): IntegrationRegistration | undefined {\n validateSpec(spec)\n const holder = entries.get(spec.id)\n if (holder) {\n logger?.warn(`integrations.register: \"${spec.id}\" is already registered by ${holder.by.extensionId}; the first registration wins`, { extension: by.extensionId })\n return undefined\n }\n const entry: Entry = { spec, by }\n entries.set(spec.id, entry)\n live().add(registry)\n // Adopt a legacy sign-in now (read before as \"none stored\" included), so\n // pickers reading the credentials file see it signed in at once.\n if (spec.legacyCredentialKey) {\n store.forgetEmpty(spec.id)\n store.cached(spec.id)\n }\n store.notify()\n const current = (): boolean => entries.get(spec.id) === entry\n return {\n update: (patch) => {\n if (!current())\n return\n const next: IntegrationSpec = { ...entry.spec, ...patch, id: entry.spec.id }\n validateSpec(next)\n entry.spec = next\n store.notify()\n },\n dispose: () => {\n if (!current())\n return\n entries.delete(spec.id)\n if (entries.size === 0)\n live().delete(registry)\n store.notify()\n },\n }\n }\n\n registry = {\n register,\n\n get(id) {\n const entry = entries.get(id)\n if (!entry)\n return undefined\n const connections = view(store.cached(id))\n return { spec: entry.spec, extensionId: entry.by.extensionId, connection: connections[0], connections }\n },\n\n list: () => [...entries.keys()].map(id => registry.get(id) as IntegrationEntry),\n\n connections: id => view(store.cached(id)),\n\n connection(id, account) {\n const all = view(store.cached(id))\n return account === undefined ? all[0] : all.find(c => c.account === account)\n },\n\n async resolve(connection) {\n const id = typeof connection === 'string' ? connection : connection.integrationId\n const account = typeof connection === 'string' ? undefined : connection.account\n const name = entries.get(id)?.spec.name ?? id\n // Fresh from the store: another process may have connected, rotated or disconnected.\n const list = store.refresh(id)\n let stored = account === undefined ? list?.[0] : list?.find(s => s.connection.account === account)\n if (!stored)\n throw new Error(account === undefined || !list?.length ? `${name} is not connected.` : `${name}: the account \"${account}\" is not connected.`)\n if (refresher.due(stored))\n stored = await refresher.refresh(id, name, stored)\n return structuredClone(stored.credential)\n },\n\n async connectKey(id, key, methodId) {\n const entry = entryOf(id)\n const method = methodId ? methodOf(entry, methodId) : entry.spec.methods.find(m => m.type === 'apiKey')\n if (method?.type !== 'apiKey')\n throw new Error(`${entry.spec.name} does not connect with an API key.`)\n const trimmed = typeof key === 'string' ? key.trim() : ''\n if (!trimmed)\n throw new Error(`${entry.spec.name}: the key is empty.`)\n await checkBeforeConnect(entry.spec, entry.by.guard, method)\n return finish(entry, method, { type: 'apiKey', key: trimmed })\n },\n\n async start(id, methodId, port, opts = {}) {\n const entry = entryOf(id)\n const method = methodOf(entry, methodId)\n const signal = opts.signal ?? new AbortController().signal\n signal.throwIfAborted()\n if (method.type === 'apiKey')\n throw new Error(`${entry.spec.name}: \"${method.id}\" takes an API key; use connect.key.`)\n await checkBeforeConnect(entry.spec, entry.by.guard, method)\n signal.throwIfAborted()\n return runFlow(entry, method, port, signal)\n },\n\n async setDefault(id, account) {\n const list = [...(store.refresh(id) ?? [])]\n const at = list.findIndex(s => s.connection.account === account)\n if (at < 0)\n throw new Error(`${entries.get(id)?.spec.name ?? id}: the account \"${account}\" is not connected.`)\n if (at === 0)\n return\n const [record] = list.splice(at, 1)\n store.persist(id, [record!, ...list])\n },\n\n async disconnect(id, account) {\n const list = store.refresh(id)\n if (!list)\n return\n if (account === undefined)\n return store.persist(id, undefined)\n const rest = list.filter(s => s.connection.account !== account)\n if (rest.length !== list.length)\n store.persist(id, rest)\n },\n\n onChange: (id, listener) => store.onChange(id, listener),\n\n subscribe: listener => store.subscribe(listener),\n\n reload(id) {\n for (const each of id === undefined ? store.known() : [id])\n store.refresh(each)\n },\n }\n return registry\n}\n\n/** Process-wide set of the registries holding at least one registration (every runtime has its own). */\nconst LIVE_SLOT = Symbol.for('zidane.integration-registries')\n\nfunction live(): Set<IntegrationRegistry> {\n const slots = globalThis as { [LIVE_SLOT]?: Set<IntegrationRegistry> }\n slots[LIVE_SLOT] ??= new Set()\n return slots[LIVE_SLOT]\n}\n\n/**\n * The registry where `integrationId` is registered: the installed one first,\n * else any runtime's (they share the credentials file, so any will do).\n * `undefined` when no extension registers it in this process.\n *\n * @param integrationId - The integration id.\n */\nexport function findIntegrationRegistry(integrationId: string): IntegrationRegistry | undefined {\n const installed = integrationRegistry()\n if (installed?.get(integrationId))\n return installed\n for (const registry of live()) {\n if (registry.get(integrationId))\n return registry\n }\n return undefined\n}\n\n/**\n * Connects an integration from a provider's \"Sign in\" (`ProviderDescriptor.integration`):\n * runs one of its flow methods (`oauth` or `custom`) on the host's provider\n * sign-in callbacks, asking which through `onSelect` when there are several.\n * The connection is stored by the registry; nothing is returned to persist.\n *\n * @param integrationId - The integration the provider signs in with.\n * @param callbacks - The sign-in UI's login callbacks (`callbackServer: false` for a remote client).\n * @param opts - Aborts the flow.\n * @param opts.signal - Aborts the flow.\n */\nexport async function signInWithIntegration(integrationId: string, callbacks: OAuthLoginCallbacks & { callbackServer?: false }, opts: { signal?: AbortSignal } = {}): Promise<Connection> {\n const registry = findIntegrationRegistry(integrationId)\n const entry = registry?.get(integrationId)\n if (!registry || !entry)\n throw new Error(`No extension offers the \"${integrationId}\" integration here. Enable the extension that provides it, then sign in again.`)\n const flows = entry.spec.methods.filter(m => m.type === 'oauth' || m.type === 'custom')\n if (flows.length === 0)\n throw new Error(`${entry.spec.name} has no browser sign-in. Connect it from Settings › Integrations.`)\n const methodId = flows.length === 1\n ? flows[0]!.id\n : await callbacks.onSelect({ message: `Sign in to ${entry.spec.name} with`, options: flows.map(m => ({ id: m.id, label: m.label })) })\n if (!methodId)\n throw new Error('Sign-in cancelled.')\n return registry.start(integrationId, methodId, {\n oauthCallbacks: () => callbacks,\n runCommand: async () => { throw new Error('A provider sign-in runs no command.') },\n }, opts.signal ? { signal: opts.signal } : {})\n}\n\n/** Process-wide slot, so every zidane copy in the process (src and dist) shares one registry. */\nconst REGISTRY_SLOT = Symbol.for('zidane.integration-registry')\n\nfunction slot(): { [REGISTRY_SLOT]?: IntegrationRegistry } {\n return globalThis as { [REGISTRY_SLOT]?: IntegrationRegistry }\n}\n\n/**\n * Makes `registry` the process's registry, the one `ctx.integrations` uses\n * by default. Disposing restores the previous one, if `registry` is still\n * the installed one.\n *\n * @param registry - The registry to install.\n */\nexport function installIntegrationRegistry(registry: IntegrationRegistry): Disposable {\n const previous = slot()[REGISTRY_SLOT]\n slot()[REGISTRY_SLOT] = registry\n return {\n dispose: () => {\n if (slot()[REGISTRY_SLOT] !== registry)\n return\n if (previous)\n slot()[REGISTRY_SLOT] = previous\n else\n delete slot()[REGISTRY_SLOT]\n },\n }\n}\n\n/** The process's registry, when a host installed one. */\nexport function integrationRegistry(): IntegrationRegistry | undefined {\n return slot()[REGISTRY_SLOT]\n}\n"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import { i as writeJsonFileAtomic, n as writeFileAtomic, t as OWNER_ONLY } from
|
|
|
7
7
|
import { n as validateToolArgs } from "./validation-Rrpbb2zy.js";
|
|
8
8
|
import { t as isStandardSchema } from "./zod-Bcn20m2L.js";
|
|
9
9
|
import { i as isBadgeColor } from "./row-fields-CAYcZogp.js";
|
|
10
|
-
import { n as satisfiesVersionRange } from "./host-version-
|
|
10
|
+
import { n as satisfiesVersionRange } from "./host-version-BGZumnpZ.js";
|
|
11
11
|
import { B as badgeMenu, C as isExtensionPanelScope, D as normalizePanelLoadContext, E as normalizePanelHomeLayout, F as bindingAlternatives, J as runBadgeAction, L as parseBindingSpec, P as resolvePanelLoadContext, R as parseBindingSpecs, T as normalizePanelContent, i as referenceProviderWires, n as createReferenceResolver, u as validateTemplate, w as isPanelSurface, x as SessionQueryError } from "./references-BEKthBnn.js";
|
|
12
12
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
13
13
|
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, watch } from "node:fs";
|
|
@@ -5459,4 +5459,4 @@ function createUiRegistry(options = {}) {
|
|
|
5459
5459
|
//#endregion
|
|
5460
5460
|
export { SidebarDecoration as $, DisposedError as $t, projectStorageFolder as A, KEYBINDING_KEY_COL_WIDTH as At, settingsWire as B, resolveExtensionKeybindings as Bt, createFileStoragePort as C, chordKey as Ct, errorMessage as D, DEFAULT_KEYBINDINGS as Dt, checkSchema as E, resolveMod as Et, createFacetRegistry as F, matchesBinding as Ft, LinkHandler as G, checkSettingValue as Gt, BadgeAction as H, looksLikeDefinition as Ht, MAX_SLOT_BADGES as I, mergeKeybindings as It, Panel as J, isValueSetting as Jt, Menu as K, isSettingKey as Kt, UI_TOKEN_NAMES as L, normalizeBindingValue as Lt, MAX_FACETS_PER_EXTENSION as M, formatBindingForDisplay as Mt, MAX_FACET_BYTES as N, groupBindings as Nt, isPlainRecord as O, KEYBINDING_DEFS as Ot, SESSION_FACET_TRIGGERS as P, keybindingsPath as Pt, SettingsPage as Q, settingsForDefinition as Qt, checkSettingsValues as R, readKeybindings as Rt, createMemoryRegistry as S, builtinKeymapEntries as St, validateStoreValue as T, normalizeChords as Tt, ContextSection as U, validateDefinition as Ut, wireWithSettingsPages as V, stripJsonComments as Vt, DialogTimeoutError as W, actionScope as Wt, Renderer as X, settingDefault as Xt, Reference as Y, normalizeSettingValue as Yt, Screen as Z, settingScopes as Zt, createMemorySettingsPort as _, mergeWireSettings as _t, systemClock as a, Space as at, createScriptedDialogPort as b, toWireValue as bt, extensionSettingsWire as c, assertAlive as ct, touchesSettingsPages as d, isTornDown as dt, SidebarFilter as et, EMPTY_MCP_PORT as f, track as ft, NO_UI_CLIENT_PORT as g, createWorkspaceSurface as gt, NO_INTEGRATION_FLOWS as h, createScheduleHandlers as ht, onPanelChanged as i, Slot as it, FACET_COMPUTE_TIMEOUT_MS as j, ensureKeybindingsFile as jt, resolveStoragePath as k, KEYBINDING_DEF_BY_ACTION as kt, onSettingsPagesChanged as l, assertUsable as lt, NO_CLIENT_DIALOG_PORT as m, createExtensionHostRuntimeBridge as mt, MAX_SIDEBAR_ROWS as n, SidebarRow as nt, LINK_SOURCES as o, ThemeToken as ot, MEMORY_CLIENT_ID as p, createArtifactsSurface as pt, NoUiError as q, isSettingsIcon as qt, createUiRegistry as r, SidebarSort as rt, MAX_LINK_URL_LENGTH as s, Webview as st, MAX_COMPOSER_BADGES as t, SidebarGroup as tt, runtimeSettingsWire as u, createOwner as ut, createMemoryStoragePort as v, toWireActionStatus as vt, createStorageDomain as w, createKeymap as wt, storage_exports as x, withSettingsPages as xt, createRecordingUiClientPort as y, toWireSettings as yt, cleanSettingsSchema as z, readKeybindingsRaw as zt };
|
|
5461
5461
|
|
|
5462
|
-
//# sourceMappingURL=registry-
|
|
5462
|
+
//# sourceMappingURL=registry-DTotchq6.js.map
|