@oh-my-pi/pi-ai 15.1.2 → 15.1.3

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.
Files changed (120) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/README.md +3 -6
  3. package/dist/types/auth-broker/client.d.ts +46 -0
  4. package/dist/types/auth-broker/index.d.ts +5 -0
  5. package/dist/types/auth-broker/refresher.d.ts +25 -0
  6. package/dist/types/auth-broker/remote-store.d.ts +71 -0
  7. package/dist/types/auth-broker/server.d.ts +26 -0
  8. package/dist/types/auth-broker/types.d.ts +69 -0
  9. package/dist/types/auth-broker/wire-schemas.d.ts +264 -0
  10. package/dist/types/auth-gateway/http.d.ts +39 -0
  11. package/dist/types/auth-gateway/index.d.ts +3 -0
  12. package/dist/types/auth-gateway/server.d.ts +17 -0
  13. package/dist/types/auth-gateway/types.d.ts +115 -0
  14. package/dist/types/auth-storage.d.ts +245 -12
  15. package/dist/types/index.d.ts +5 -0
  16. package/dist/types/model-cache.d.ts +8 -1
  17. package/dist/types/provider-details.d.ts +6 -0
  18. package/dist/types/provider-models/special.d.ts +0 -9
  19. package/dist/types/providers/amazon-bedrock.d.ts +8 -0
  20. package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
  21. package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
  22. package/dist/types/providers/anthropic.d.ts +21 -0
  23. package/dist/types/providers/aws-credentials.d.ts +32 -0
  24. package/dist/types/providers/aws-eventstream.d.ts +38 -0
  25. package/dist/types/providers/aws-sigv4.d.ts +55 -0
  26. package/dist/types/providers/google-auth.d.ts +24 -0
  27. package/dist/types/providers/google-gemini-cli.d.ts +1 -1
  28. package/dist/types/providers/google-shared.d.ts +12 -9
  29. package/dist/types/providers/google-types.d.ts +138 -0
  30. package/dist/types/providers/mock.d.ts +31 -9
  31. package/dist/types/providers/openai-chat-server-schema.d.ts +814 -0
  32. package/dist/types/providers/openai-chat-server.d.ts +16 -0
  33. package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
  34. package/dist/types/providers/openai-responses-server.d.ts +17 -0
  35. package/dist/types/providers/pi-native-client.d.ts +13 -0
  36. package/dist/types/providers/pi-native-server.d.ts +68 -0
  37. package/dist/types/stream.d.ts +8 -1
  38. package/dist/types/types.d.ts +36 -0
  39. package/dist/types/usage.d.ts +141 -0
  40. package/dist/types/utils/anthropic-auth.d.ts +1 -1
  41. package/dist/types/utils/discovery/index.d.ts +0 -1
  42. package/dist/types/utils/oauth/github-copilot.d.ts +2 -0
  43. package/dist/types/utils/parse-bind.d.ts +23 -0
  44. package/dist/types/utils/retry.d.ts +1 -0
  45. package/dist/types/utils/schema/adapt.d.ts +10 -7
  46. package/dist/types/utils/schema/compatibility.d.ts +2 -2
  47. package/dist/types/utils/schema/fields.d.ts +8 -2
  48. package/dist/types/utils/schema/index.d.ts +2 -3
  49. package/dist/types/utils/schema/normalize.d.ts +92 -0
  50. package/dist/types/utils/schema/spill.d.ts +8 -0
  51. package/dist/types/utils/sse-debug.d.ts +1 -1
  52. package/package.json +18 -8
  53. package/src/auth-broker/client.ts +261 -0
  54. package/src/auth-broker/index.ts +5 -0
  55. package/src/auth-broker/refresher.ts +127 -0
  56. package/src/auth-broker/remote-store.ts +409 -0
  57. package/src/auth-broker/server.ts +454 -0
  58. package/src/auth-broker/types.ts +84 -0
  59. package/src/auth-broker/wire-schemas.ts +162 -0
  60. package/src/auth-gateway/http.ts +194 -0
  61. package/src/auth-gateway/index.ts +3 -0
  62. package/src/auth-gateway/server.ts +651 -0
  63. package/src/auth-gateway/types.ts +134 -0
  64. package/src/auth-storage.ts +819 -57
  65. package/src/cli.ts +4 -4
  66. package/src/index.ts +10 -0
  67. package/src/model-cache.ts +22 -4
  68. package/src/model-manager.ts +128 -27
  69. package/src/model-thinking.ts +27 -10
  70. package/src/provider-details.ts +9 -0
  71. package/src/provider-models/special.ts +6 -45
  72. package/src/providers/amazon-bedrock.ts +278 -254
  73. package/src/providers/anthropic-messages-server-schema.ts +229 -0
  74. package/src/providers/anthropic-messages-server.ts +677 -0
  75. package/src/providers/anthropic.ts +190 -53
  76. package/src/providers/aws-credentials.ts +334 -0
  77. package/src/providers/aws-eventstream.ts +185 -0
  78. package/src/providers/aws-sigv4.ts +218 -0
  79. package/src/providers/azure-openai-responses.ts +2 -3
  80. package/src/providers/cursor.ts +1 -2
  81. package/src/providers/google-auth.ts +252 -0
  82. package/src/providers/google-gemini-cli.ts +3 -3
  83. package/src/providers/google-shared.ts +138 -42
  84. package/src/providers/google-types.ts +167 -0
  85. package/src/providers/google-vertex.ts +33 -54
  86. package/src/providers/google.ts +23 -31
  87. package/src/providers/mock.ts +80 -79
  88. package/src/providers/openai-chat-server-schema.ts +243 -0
  89. package/src/providers/openai-chat-server.ts +628 -0
  90. package/src/providers/openai-completions.ts +7 -0
  91. package/src/providers/openai-responses-server-schema.ts +290 -0
  92. package/src/providers/openai-responses-server.ts +1183 -0
  93. package/src/providers/openai-responses.ts +6 -0
  94. package/src/providers/pi-native-client.ts +228 -0
  95. package/src/providers/pi-native-server.ts +210 -0
  96. package/src/stream.ts +67 -3
  97. package/src/types.ts +36 -0
  98. package/src/usage/claude.ts +130 -36
  99. package/src/usage/openai-codex.ts +132 -6
  100. package/src/usage.ts +54 -1
  101. package/src/utils/anthropic-auth.ts +9 -7
  102. package/src/utils/discovery/index.ts +0 -1
  103. package/src/utils/oauth/github-copilot.ts +10 -2
  104. package/src/utils/parse-bind.ts +54 -0
  105. package/src/utils/retry.ts +3 -2
  106. package/src/utils/schema/CONSTRAINTS.md +20 -18
  107. package/src/utils/schema/adapt.ts +14 -62
  108. package/src/utils/schema/compatibility.ts +2 -2
  109. package/src/utils/schema/fields.ts +26 -2
  110. package/src/utils/schema/index.ts +2 -3
  111. package/src/utils/schema/normalize.ts +1494 -0
  112. package/src/utils/schema/spill.ts +43 -0
  113. package/src/utils/sse-debug.ts +239 -20
  114. package/src/utils/validation.ts +9 -10
  115. package/dist/types/utils/schema/normalize-cca.d.ts +0 -17
  116. package/dist/types/utils/schema/sanitize-google.d.ts +0 -29
  117. package/dist/types/utils/schema/strict-mode.d.ts +0 -56
  118. package/src/utils/schema/normalize-cca.ts +0 -490
  119. package/src/utils/schema/sanitize-google.ts +0 -255
  120. package/src/utils/schema/strict-mode.ts +0 -490
package/CHANGELOG.md CHANGED
@@ -2,6 +2,91 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [15.1.3] - 2026-05-17
6
+ ### Breaking Changes
7
+
8
+ - Changed `AuthBrokerClient.fetchSnapshot()` to return status-based results (`200` or `304`) instead of always returning a raw snapshot body, so callers now need to branch on `status`
9
+ - Renamed public schema utilities in `@oh-my-pi/pi-ai/utils/schema` by replacing `sanitizeSchemaForGoogle`, `sanitizeSchemaForCCA`, `prepareSchemaForCCA`, and `sanitizeSchemaForMCP` with `normalizeSchemaForGoogle`, `normalizeSchemaForCCA`, and `normalizeSchemaForMCP`
10
+ - Added MCP schema normalization via `normalizeSchemaForMCP` for compatibility checks
11
+ - Removed the `StringEnum` helper from `@oh-my-pi/pi-ai/utils/schema`. Use `z.enum([...])` directly; Zod's emitted JSON Schema is already wire-compatible with Google and other providers.
12
+ - Renamed the concrete SQLite credential store class from `AuthCredentialStore` to `SqliteAuthCredentialStore`. `AuthCredentialStore` is now the persistence interface implemented by both the SQLite store and the new `RemoteAuthCredentialStore`. Update `new AuthCredentialStore(db)` / `AuthCredentialStore.open(...)` call-sites to `SqliteAuthCredentialStore`; type-position uses (`store: AuthCredentialStore`) continue to work unchanged.
13
+
14
+ ### Added
15
+
16
+ - Added `onAuthError` to `StreamOptions` and wired `streamSimple()` to retry once with a replacement API key when the first provider response is a 401 before any assistant events are emitted
17
+ - Added generation-aware snapshot metadata (`generation`, `serverNowMs`, `refresher`, and `rotatesInMs`) to auth-broker snapshot responses to support client-side credential-rotation planning
18
+ - Added `transport: "pi-native"` on `Model` and the matching `streamPiNative` client. When `model.transport === "pi-native"`, `streamSimple` short-circuits the per-provider dispatch and POSTs the canonical `Context` to the auth-gateway's `POST /v1/pi/stream` endpoint. The response is SSE-framed `AssistantMessageEvent`s parsed by `readSseJson` and pushed verbatim into the local `AssistantMessageEventStream` — no wire-format translation, no partial-stripping reconstruction. Used by containerized omp installs (robomp slots, swarm extension, etc.) to route every LLM call through a credential-holding sidecar; the slot itself never sees the real provider tokens. Server-controlled fields (`apiKey`, `signal`, `fetch`, lifecycle callbacks, the provider-session map) are stripped from the wire body — `apiKey` rides in the `Authorization` header as the gateway bearer.
19
+ - Added `POST /v1/pi/stream` to the auth-gateway. Same auth + abort + model-resolution + codex-compat + prefix-cache plumbing as the foreign-wire routes; only the wire-format translation is skipped. Request body is `{ modelId, context, options?, stream? }` where `context` is the canonical pi-ai `Context` and `options` is `SimpleStreamOptions` with non-serializable fields stripped. Response is SSE-framed `AssistantMessageEvent` (terminated by `data: [DONE]`) when streaming, or `{ message: AssistantMessage }` JSON when `stream: false`.
20
+ - Added Vertex AI authentication via Google Application Default Credentials from `GOOGLE_APPLICATION_CREDENTIALS`, `~/.config/gcloud/application_default_credentials.json`, or metadata server tokens, with token caching and refresh skew control via `GOOGLE_VERTEX_REFRESH_SKEW_MS`
21
+ - Added support for Anthropic image message parts with `type: "url"` and `type: "file"` sources
22
+ - Added `stopSequences` and `frequencyPenalty` to shared stream options and wired them through to OpenAI request translation
23
+ - Added optional request cancellation support to auth-broker interactions by propagating `AbortSignal` into health, snapshot, usage, and refresh calls
24
+ - Added `AuthStorage.setConfigApiKey` / `removeConfigApiKey` / `clearConfigApiKeys` for config-sourced per-provider bearers (e.g. `models.yml` `providers.<name>.apiKey`). The new tier sits between runtime `--api-key` and stored credentials in `getApiKey`/`peekApiKey` resolution, so a bearer pinned in config now beats the broker's OAuth access token. Also suppresses OAuth `account_uuid` attribution when active, since outbound auth is the explicit config bearer, not OAuth. `describeCredentialSource` reports `"config override (models.yml)"` for visibility.
25
+ - Added per-model `additional_rate_limits` parsing to `openaiCodexUsageProvider`. The Codex `wham/usage` endpoint surfaces a separate `GPT-5.3-Codex-Spark` rate limit (`metered_feature: codex_bengalfox`) on Pro accounts; these now emit dedicated `openai-codex:spark:{primary,secondary}` `UsageLimit` entries with `scope.tier = "spark"`, mirroring how Anthropic exposes `anthropic:7d:sonnet` separately from the umbrella `anthropic:7d` bucket. The osx-widgets client already keyed spark detection off `limit.id.includes("spark")`; this populates that contract end-to-end.
26
+ - Added `GET /v1/usage` to the auth-broker API to expose aggregated usage reports from `AuthStorage.fetchUsageReports`
27
+ - Added auth-broker usage polling response handling that returns normalized usage reports plus generation timestamp for clients (5-min per-credential cache via `AuthStorage`)
28
+ - Added the auth-broker subsystem (`@oh-my-pi/pi-ai/auth-broker`) for sharing OAuth credentials across machines without leaking refresh tokens.
29
+ - `startAuthBroker(...)` boots a `Bun.serve` HTTP server exposing `GET /v1/healthz`, `GET /v1/snapshot`, `POST /v1/credential` (upsert), `POST /v1/credential/:id/refresh`, and `POST /v1/credential/:id/disable`.
30
+ - `AuthBrokerClient` is the matching HTTP client used by remote clients.
31
+ - `RemoteAuthCredentialStore` is a client-side `AuthCredentialStore` that mirrors a broker snapshot in memory; mutating methods (`replace*`, `upsert*`, `delete*ForProvider`) throw because writes are server-side only.
32
+ - `AuthBrokerRefresher` is the background refresh loop that pre-refreshes credentials within `refreshSkewMs` and disables on definitive failure (`invalid_grant` / non-network 401-403).
33
+ - Added `AuthStorage.exportSnapshot()`, `AuthStorage.upsertCredential(provider, credential)`, `AuthStorage.forceRefreshCredentialById(id)`, and `AuthStorage.disableCredentialById(id, cause)` public methods consumed by the auth-broker server.
34
+ - Added `AuthStorageOptions.refreshOAuthCredential` override so a remote-store client can route every OAuth refresh through the broker instead of the local OAuth endpoint.
35
+ - Added `REMOTE_REFRESH_SENTINEL` (`"__remote__"`) — the wire placeholder substituted for OAuth refresh tokens in broker snapshots; clients never see the real refresh token.
36
+ - Exposed the OAuth provider catalog (`getOAuthProviders`, `OAuthProvider`, `OAuthProviderInfo`) and `refreshOAuthToken` through the package barrel so the coding-agent CLI can target them without reaching into `utils/oauth`.
37
+ - Added the auth-gateway subsystem (`@oh-my-pi/pi-ai/auth-gateway`) — a forward-proxy that sits between unauthenticated clients (the macOS usage widget, llm-git, robomp containers, …) and the broker. Clients send standard provider-format requests; the gateway parses them into omp's canonical `Context`, dispatches through pi-ai's `streamSimple()`, and translates the canonical event stream back to the matching wire format. `Authorization` is injected server-side so access tokens never leave the gateway host. Wire surface:
38
+ - `GET /healthz` — unauth liveness.
39
+ - `GET /v1/usage` — aggregated provider usage; 5-min per-credential cache via `AuthStorage.fetchUsageReports`.
40
+ - `GET /v1/models` — model catalog (scoped to providers with credentials).
41
+ - `POST /v1/chat/completions` — OpenAI chat-completions in/out.
42
+ - `POST /v1/messages` — Anthropic messages in/out (text + thinking + tool_use blocks, SSE event taxonomy preserved).
43
+ - `POST /v1/responses` — OpenAI Responses in/out (reasoning items + function_call output items, SSE pass-through).
44
+ - Added exports from `@oh-my-pi/pi-ai/auth-gateway`: `startAuthGateway`, `AuthGatewayServerOptions`, `AuthGatewayBootOptions`, `AuthGatewayServerHandle`, `ModelResolver`, `DEFAULT_AUTH_GATEWAY_BIND`. Per-format `parseRequest` / `encodeResponse` / `encodeStream` triples are reachable via the `./providers/*` subpath as `openai-chat-server`, `anthropic-messages-server`, and `openai-responses-server`.
45
+ - Added `listProvidersWithEnvKey()` to enumerate every provider with an env-var fallback (used by the new migrate command in coding-agent).
46
+
47
+ ### Changed
48
+
49
+ - Changed `GET /v1/snapshot` to support generation-based polling with `If-None-Match` and `wait` for long-poll updates and to return `304` when no snapshot changes are available
50
+ - Changed Bedrock credential resolution for streaming calls to prefer environment keys, AWS profile/SSO credentials, and IMDSv2 fallback when available
51
+ - Changed auth-gateway parsing for OpenAI chat-completions and Responses to ignore unsupported SDK-only fields instead of rejecting requests
52
+ - Changed auth-gateway protocol handling to include CORS headers on responses and support browser-origin requests
53
+ - Changed prompt-cache handling to resolve cache keys from request metadata and headers and preserve them through protocol translation
54
+ - Changed Anthropic messages parsing to forward request `metadata` through to downstream execution
55
+ - Changed usage report caching to use a 5-minute per-credential TTL with jittered refresh timing to reduce usage endpoint rate-limit collisions
56
+ - Changed usage polling failure handling so transient errors continue serving the last known report instead of returning null and dropping the credential from usage aggregates after cache expiry
57
+ - Changed `sanitizeSchemaForGoogle` to normalize snake_case schema keys (such as `any_of` and `additional_properties`) to camelCase and auto-generate `propertyOrdering` for multi-property objects
58
+ - Changed strict-mode sanitization to resolve `$ref` nodes with sibling keys by inlining and merging referenced local definitions
59
+ - Changed strict-mode sanitization to flatten single-entry `allOf` nodes and remove the `allOf` wrapper
60
+ - Changed Anthropic tool schema normalization to preserve supported metadata keywords such as `$ref`, `$defs`, `$schema`, `enum`, `const`, `default`, `title`, and `nullable` instead of stripping them
61
+ - Changed string schema processing to retain only supported `format` values (`date-time`, `time`, `date`, `duration`, `email`, `hostname`, `uri`, `ipv4`, `ipv6`, `uuid`) and demote unsupported `format` values to `description` hints
62
+
63
+ ### Fixed
64
+
65
+ - Fixed OAuth credential refresh flow so concurrent manual and background refreshes now share one in-flight attempt per credential, and `RemoteAuthCredentialStore` now re-synchronizes before using near-expiring OAuth credentials
66
+ - Fixed stale-credential handling after auth failures by waiting for updated broker snapshots and refreshing suspect credentials through broker endpoints before continuing
67
+ - Fixed Google Generative AI startup behavior to throw a clear API-key-required error when no key is configured
68
+ - Fixed AWS Bedrock image message serialization to preserve base64 `source.bytes` payloads instead of decoding and rebuilding them
69
+ - Fixed Google provider error handling to extract the API-reported `error.message` from JSON response bodies when available
70
+ - Fixed `RemoteAuthCredentialStore.getUsageReport` to return the matching credential-specific usage report and coalesce parallel callers into one broker `/v1/usage` fetch
71
+ - Fixed auth-broker credential upload validation to reject the remote refresh-token sentinel and prevent storing a non-refresh value
72
+ - Fixed OpenAI Responses streaming output to emit `reasoning_summary_text` events and parse/send `summary_text` reasoning payloads
73
+ - Fixed Anthropic stop-sequence handling by trimming requests to the API limit of four entries before forwarding
74
+ - Fixed prompt caching behavior across protocol translations so cached-token usage is preserved when Anthropic and OpenAI requests are routed through each other
75
+ - Fixed Claude usage fetching to retry transient `429` and `5xx` responses with exponential backoff, respecting `Retry-After` before returning failure
76
+ - Fixed auth-gateway request translation to preserve OpenAI Responses string/system message content, reasoning replay payloads, completed item text in stream item-done events, Anthropic tool-result ordering, and OpenAI Chat/Responses cached-token usage totals
77
+ - Fixed auth-gateway failure handling so unsupported request controls, upstream terminal errors, non-streaming aborts, and already-aborted client requests fail explicitly instead of being accepted, ignored, or encoded as successful HTTP 200 responses
78
+ - Fixed Gemini CLI / Antigravity tool schema normalization to run the full Cloud Code Assist pipeline, matching shared Google schema handling for union/object merging and nullable extraction
79
+ - Fixed stripped validation hints to be preserved as description spill text (`{key: value}` blocks) when `normalizeSchemaForGoogle` and `normalizeSchemaForCCA` drop unsupported schema keywords
80
+ - Fixed `sanitizeSchemaForGoogle` to collapse nullability forms (`type:'null'` and null-bearing `anyOf` variants) into `nullable` while preserving remaining variants
81
+ - Fixed `sanitizeSchemaForGoogle` to inline local `$defs` references instead of dropping `$ref`/`$defs` structure during Google schema sanitization
82
+ - Fixed `normalizeAnthropicToolSchema` to handle self-referential schemas without infinite recursion
83
+ - Fixed object schema normalization so explicit open-map declarations (`additionalProperties: true` and schema-valued `additionalProperties`) are preserved instead of being converted to closed objects
84
+ - Fixed unsupported schema constraints on arrays and strings (`maxItems`, `uniqueItems`, `pattern`, `minLength`, `maxLength`, and `minItems` when greater than 1) by demoting them into `description` rather than dropping them
85
+
86
+ ### Security
87
+
88
+ - Hardened auth-gateway bearer-token checks with constant-time comparison to avoid timing-side-channel leaks
89
+
5
90
  ## [15.1.2] - 2026-05-15
6
91
  ### Breaking Changes
7
92
 
package/README.md CHANGED
@@ -89,7 +89,7 @@ npm install @oh-my-pi/pi-ai
89
89
  ## Quick Start
90
90
 
91
91
  ```typescript
92
- import { z, getModel, stream, complete, Context, Tool, StringEnum } from "@oh-my-pi/pi-ai";
92
+ import { z, getModel, stream, complete, Context, Tool } from "@oh-my-pi/pi-ai";
93
93
 
94
94
  // Fully typed with auto-complete support for both providers and models
95
95
  const model = getModel("openai", "gpt-4o-mini");
@@ -221,7 +221,7 @@ Tools enable LLMs to interact with external systems. This library uses **Zod** s
221
221
  ### Defining Tools
222
222
 
223
223
  ```typescript
224
- import { z, Tool, StringEnum } from "@oh-my-pi/pi-ai";
224
+ import { z, Tool } from "@oh-my-pi/pi-ai";
225
225
 
226
226
  // Define tool parameters with Zod
227
227
  const weatherTool: Tool = {
@@ -229,13 +229,10 @@ const weatherTool: Tool = {
229
229
  description: "Get current weather for a location",
230
230
  parameters: z.object({
231
231
  location: z.string().describe("City name or coordinates"),
232
- units: StringEnum(["celsius", "fahrenheit"], { default: "celsius" }),
232
+ units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
233
233
  }),
234
234
  };
235
235
 
236
- // Note: For Google API compatibility, use the StringEnum helper instead of z.enum alone
237
- // when you need wire-compatible { type: "string", enum: [...] } shapes.
238
-
239
236
  const bookMeetingTool: Tool = {
240
237
  name: "book_meeting",
241
238
  description: "Schedule a meeting",
@@ -0,0 +1,46 @@
1
+ import type { AuthCredential } from "../auth-storage";
2
+ import type { CredentialDisableResponse, CredentialRefreshResponse, CredentialUploadResponse, HealthzResponse, SnapshotResponse, UsageResponse } from "./types";
3
+ export interface AuthBrokerClientOptions {
4
+ /** Base URL (e.g. `https://broker.tailnet:8765`). Trailing slashes are trimmed. */
5
+ url: string;
6
+ /** Bearer token used for everything except `healthz`. */
7
+ token: string;
8
+ /** Per-request timeout in milliseconds. Default 10s. */
9
+ timeoutMs?: number;
10
+ /** Retry connection errors this many times. Default 1. */
11
+ maxRetries?: number;
12
+ /** Override fetch (used in tests). Default global `fetch`. */
13
+ fetchImpl?: typeof fetch;
14
+ }
15
+ export declare class AuthBrokerError extends Error {
16
+ readonly status: number | undefined;
17
+ readonly body: string | undefined;
18
+ constructor(message: string, opts?: {
19
+ status?: number;
20
+ body?: string;
21
+ cause?: unknown;
22
+ });
23
+ }
24
+ export interface FetchSnapshotOptions {
25
+ ifGenerationGt?: number;
26
+ waitMs?: number;
27
+ signal?: AbortSignal;
28
+ }
29
+ export type FetchSnapshotResult = {
30
+ status: 200;
31
+ snapshot: SnapshotResponse;
32
+ generation: number;
33
+ } | {
34
+ status: 304;
35
+ generation: number;
36
+ };
37
+ export declare class AuthBrokerClient {
38
+ #private;
39
+ constructor(opts: AuthBrokerClientOptions);
40
+ healthz(signal?: AbortSignal): Promise<HealthzResponse>;
41
+ fetchSnapshot(opts?: FetchSnapshotOptions): Promise<FetchSnapshotResult>;
42
+ fetchUsage(signal?: AbortSignal): Promise<UsageResponse>;
43
+ refreshCredential(id: number, signal?: AbortSignal): Promise<CredentialRefreshResponse>;
44
+ disableCredential(id: number, cause: string, signal?: AbortSignal): Promise<CredentialDisableResponse>;
45
+ uploadCredential(provider: string, credential: AuthCredential, signal?: AbortSignal): Promise<CredentialUploadResponse>;
46
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./client";
2
+ export * from "./refresher";
3
+ export * from "./remote-store";
4
+ export * from "./server";
5
+ export * from "./types";
@@ -0,0 +1,25 @@
1
+ import type { AuthStorage } from "../auth-storage";
2
+ export interface AuthBrokerRefresherOptions {
3
+ storage: AuthStorage;
4
+ /** Refresh credentials expiring within this window. Default 5 min. */
5
+ refreshSkewMs?: number;
6
+ /** Loop cadence. Default 60s. */
7
+ refreshIntervalMs?: number;
8
+ /** Override clock (tests). */
9
+ now?: () => number;
10
+ }
11
+ export interface AuthBrokerRefresherSchedule {
12
+ enabled: boolean;
13
+ intervalMs: number;
14
+ skewMs: number;
15
+ nextSweepAt: number;
16
+ }
17
+ export declare class AuthBrokerRefresher {
18
+ #private;
19
+ constructor(opts: AuthBrokerRefresherOptions);
20
+ start(): void;
21
+ stop(): void;
22
+ getSchedule(): AuthBrokerRefresherSchedule;
23
+ /** Run one sweep. Exposed for tests. */
24
+ tick(): Promise<void>;
25
+ }
@@ -0,0 +1,71 @@
1
+ import { type AuthCredential, type AuthCredentialStore, type OAuthCredential, type StoredAuthCredential } from "../auth-storage";
2
+ import type { Provider } from "../types";
3
+ import type { UsageReport } from "../usage";
4
+ import type { OAuthCredentials } from "../utils/oauth/types";
5
+ import type { AuthBrokerClient } from "./client";
6
+ import type { SnapshotResponse } from "./types";
7
+ export interface RemoteAuthCredentialStoreOptions {
8
+ client: AuthBrokerClient;
9
+ /**
10
+ * Initial snapshot. When omitted, callers must call
11
+ * {@link RemoteAuthCredentialStore.refreshSnapshot} before the first read.
12
+ */
13
+ initialSnapshot?: SnapshotResponse;
14
+ }
15
+ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
16
+ #private;
17
+ constructor(opts: RemoteAuthCredentialStoreOptions);
18
+ get client(): AuthBrokerClient;
19
+ get snapshot(): SnapshotResponse;
20
+ /** Re-hydrate the in-memory snapshot from the broker. */
21
+ refreshSnapshot(): Promise<SnapshotResponse>;
22
+ listAuthCredentials(provider?: string): StoredAuthCredential[];
23
+ /**
24
+ * In-memory update from a successful refresh through the broker. AuthStorage
25
+ * calls this after `#replaceCredentialAt`; the broker already persisted the
26
+ * authoritative row, so we just mirror it.
27
+ */
28
+ updateAuthCredential(id: number, credential: AuthCredential): void;
29
+ deleteAuthCredential(id: number, disabledCause: string): void;
30
+ tryDisableAuthCredentialIfMatches(id: number, _expectedData: string, disabledCause: string): boolean;
31
+ waitForFreshSnapshot(maxWaitMs: number, opts?: {
32
+ signal?: AbortSignal;
33
+ }): Promise<boolean>;
34
+ prepareForRequest(credentialId: number, opts?: {
35
+ signal?: AbortSignal;
36
+ }): Promise<boolean>;
37
+ markCredentialSuspect(credentialId: number, opts?: {
38
+ signal?: AbortSignal;
39
+ }): Promise<void>;
40
+ replaceAuthCredentialsForProvider(_provider: string, _credentials: AuthCredential[]): StoredAuthCredential[];
41
+ upsertAuthCredentialForProvider(_provider: string, _credential: AuthCredential): StoredAuthCredential[];
42
+ deleteAuthCredentialsForProvider(_provider: string, _disabledCause: string): void;
43
+ getCache(key: string): string | null;
44
+ setCache(key: string, value: string, expiresAtSec: number): void;
45
+ cleanExpiredCache(): void;
46
+ /**
47
+ * Store-level hook consumed by `AuthStorage` — routes refresh through the
48
+ * broker so the actual refresh token never leaves the broker host. Returns
49
+ * the broker-redacted credential with {@link REMOTE_REFRESH_SENTINEL} in
50
+ * the `refresh` slot.
51
+ */
52
+ refreshOAuthCredential(_provider: Provider, credentialId: number, _credential: OAuthCredential, signal?: AbortSignal): Promise<OAuthCredentials>;
53
+ /**
54
+ * Store-level hook consumed by `AuthStorage.fetchUsageReports()` — proxies
55
+ * to the broker's `/v1/usage` endpoint. The broker's egress IP isn't
56
+ * rate-limited by Anthropic's per-IP `/usage` cap the way a heavy
57
+ * residential laptop is, so all credentials surface every cycle.
58
+ */
59
+ fetchUsageReports(signal?: AbortSignal): Promise<UsageReport[] | null>;
60
+ /**
61
+ * Per-credential usage hook consumed by `AuthStorage.#getUsageReport`. Pulls
62
+ * the aggregate broker `/v1/usage` once and serves all callers from the
63
+ * same response (coalesced + cached), then matches the credential to a
64
+ * report by provider + identity (accountId / email / projectId).
65
+ *
66
+ * The broker already aggregates with its own 30s TTL on the server side; our
67
+ * 15s client TTL is below that so we usually re-use the broker's cache too.
68
+ */
69
+ getUsageReport(provider: Provider, credential: OAuthCredential, signal?: AbortSignal): Promise<UsageReport | null>;
70
+ close(): void;
71
+ }
@@ -0,0 +1,26 @@
1
+ import type { AuthStorage } from "../auth-storage";
2
+ export interface AuthBrokerServerOptions {
3
+ /** Underlying credential storage (wraps the local SQLite store on the broker). */
4
+ storage: AuthStorage;
5
+ /** Listen address; accepts `host:port` or just `port`. */
6
+ bind?: string;
7
+ /** Accept any of these bearer tokens. Empty disables auth (loopback only). */
8
+ bearerTokens: string[];
9
+ /** Broker version string surfaced on `/v1/healthz`. */
10
+ version?: string;
11
+ /** Refresh credentials expiring within this window. Default 5 min. */
12
+ refreshSkewMs?: number;
13
+ /** Background refresh cadence. Default 60s. */
14
+ refreshIntervalMs?: number;
15
+ /** Disable the background refresher (e.g. for tests). */
16
+ disableRefresher?: boolean;
17
+ }
18
+ export interface AuthBrokerServerHandle {
19
+ /** Bound URL (`http://host:port`). */
20
+ url: string;
21
+ port: number;
22
+ hostname: string;
23
+ close(): Promise<void>;
24
+ }
25
+ /** Boot the broker. Caller owns lifecycle; `handle.close()` to stop. */
26
+ export declare function startAuthBroker(opts: AuthBrokerServerOptions): AuthBrokerServerHandle;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Wire types shared between the auth-broker server and clients.
3
+ *
4
+ * The broker holds OAuth refresh tokens and exposes a redacted snapshot;
5
+ * clients use `access` tokens directly and call back to the broker when a
6
+ * credential expires or a 401 surfaces on a supposedly-fresh credential.
7
+ */
8
+ import type { AuthCredential, AuthCredentialSnapshot, AuthCredentialSnapshotEntry } from "../auth-storage";
9
+ import type { UsageReport } from "../usage";
10
+ /** GET /v1/healthz response body. */
11
+ export interface HealthzResponse {
12
+ ok: boolean;
13
+ version?: string;
14
+ }
15
+ export interface RefresherSchedule {
16
+ enabled: boolean;
17
+ intervalMs: number;
18
+ skewMs: number;
19
+ nextSweepInMs: number;
20
+ }
21
+ export type SnapshotEntry = AuthCredentialSnapshotEntry & {
22
+ rotatesInMs: number | null;
23
+ };
24
+ /** GET /v1/snapshot response body. */
25
+ export interface SnapshotResponse extends Omit<AuthCredentialSnapshot, "credentials"> {
26
+ serverNowMs: number;
27
+ refresher: RefresherSchedule;
28
+ credentials: SnapshotEntry[];
29
+ }
30
+ /** GET /v1/usage response body — matches the local `AuthStorage.fetchUsageReports` shape. */
31
+ export interface UsageResponse {
32
+ generatedAt: number;
33
+ reports: UsageReport[];
34
+ }
35
+ /** POST /v1/credential/:id/refresh response body. */
36
+ export interface CredentialRefreshResponse {
37
+ entry: AuthCredentialSnapshotEntry;
38
+ }
39
+ /** POST /v1/credential/:id/disable request body. */
40
+ export interface CredentialDisableRequest {
41
+ cause: string;
42
+ }
43
+ /** POST /v1/credential/:id/disable response body. */
44
+ export interface CredentialDisableResponse {
45
+ ok: boolean;
46
+ }
47
+ /**
48
+ * POST /v1/credential request body. The OAuth `refresh` must be the *real*
49
+ * refresh token (not the sentinel) — the broker is the canonical writer.
50
+ */
51
+ export interface CredentialUploadRequest {
52
+ provider: string;
53
+ credential: AuthCredential;
54
+ }
55
+ /** POST /v1/credential response body — redacted snapshot of the provider's rows after upsert. */
56
+ export interface CredentialUploadResponse {
57
+ entries: AuthCredentialSnapshotEntry[];
58
+ }
59
+ /**
60
+ * Default bearer-protected route prefix. The broker exposes `/v1/healthz`
61
+ * unauthenticated for liveness probes; everything else requires a bearer.
62
+ */
63
+ export declare const AUTH_BROKER_API_PREFIX = "/v1";
64
+ /** Default port when none is configured. Loopback-only, no external exposure. */
65
+ export declare const DEFAULT_AUTH_BROKER_BIND = "127.0.0.1:8765";
66
+ /** Default broker→provider refresh skew. Refresh credentials this close to expiry. */
67
+ export declare const DEFAULT_REFRESH_SKEW_MS: number;
68
+ /** Default broker refresh-loop cadence. */
69
+ export declare const DEFAULT_REFRESH_INTERVAL_MS = 60000;
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Zod schemas for the auth-broker wire protocol.
3
+ *
4
+ * Shared between the server (validates inbound request bodies) and the client
5
+ * (validates responses from the broker). Schemas mirror the TypeScript types
6
+ * in `./types.ts` 1:1; the types remain the source of truth for static typing,
7
+ * and `z.infer<typeof Schema>` is asserted-compatible with them where possible.
8
+ *
9
+ * Schemas use `.strict()` on objects with a closed set of fields so unknown
10
+ * keys are rejected — the previous implementation used a hand-rolled
11
+ * `hasOnlyFields` allowlist for the same effect.
12
+ */
13
+ import * as z from "zod/v4";
14
+ /** Real OAuth credential (broker-side) — refresh token is the actual upstream value. */
15
+ export declare const oauthCredentialSchema: z.ZodObject<{
16
+ type: z.ZodLiteral<"oauth">;
17
+ refresh: z.ZodString;
18
+ access: z.ZodString;
19
+ expires: z.ZodNumber;
20
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
21
+ projectId: z.ZodOptional<z.ZodString>;
22
+ email: z.ZodOptional<z.ZodString>;
23
+ accountId: z.ZodOptional<z.ZodString>;
24
+ }, z.core.$strict>;
25
+ /** OAuth credential as it appears in broker snapshots — refresh replaced with sentinel. */
26
+ export declare const remoteOauthCredentialSchema: z.ZodObject<{
27
+ type: z.ZodLiteral<"oauth">;
28
+ access: z.ZodString;
29
+ expires: z.ZodNumber;
30
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
31
+ projectId: z.ZodOptional<z.ZodString>;
32
+ email: z.ZodOptional<z.ZodString>;
33
+ accountId: z.ZodOptional<z.ZodString>;
34
+ refresh: z.ZodLiteral<"__remote__">;
35
+ }, z.core.$strict>;
36
+ export declare const apiKeyCredentialSchema: z.ZodObject<{
37
+ type: z.ZodLiteral<"api_key">;
38
+ key: z.ZodString;
39
+ }, z.core.$strict>;
40
+ /** Discriminated union accepted on POST /v1/credential (writes). */
41
+ export declare const writableAuthCredentialSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
42
+ type: z.ZodLiteral<"oauth">;
43
+ refresh: z.ZodString;
44
+ access: z.ZodString;
45
+ expires: z.ZodNumber;
46
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
47
+ projectId: z.ZodOptional<z.ZodString>;
48
+ email: z.ZodOptional<z.ZodString>;
49
+ accountId: z.ZodOptional<z.ZodString>;
50
+ }, z.core.$strict>, z.ZodObject<{
51
+ type: z.ZodLiteral<"api_key">;
52
+ key: z.ZodString;
53
+ }, z.core.$strict>], "type">;
54
+ /** Discriminated union returned in snapshots (refresh is sentinel for OAuth). */
55
+ export declare const snapshotCredentialSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
56
+ type: z.ZodLiteral<"oauth">;
57
+ access: z.ZodString;
58
+ expires: z.ZodNumber;
59
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
60
+ projectId: z.ZodOptional<z.ZodString>;
61
+ email: z.ZodOptional<z.ZodString>;
62
+ accountId: z.ZodOptional<z.ZodString>;
63
+ refresh: z.ZodLiteral<"__remote__">;
64
+ }, z.core.$strict>, z.ZodObject<{
65
+ type: z.ZodLiteral<"api_key">;
66
+ key: z.ZodString;
67
+ }, z.core.$strict>], "type">;
68
+ export declare const credentialSnapshotEntrySchema: z.ZodObject<{
69
+ id: z.ZodNumber;
70
+ provider: z.ZodString;
71
+ credential: z.ZodDiscriminatedUnion<[z.ZodObject<{
72
+ type: z.ZodLiteral<"oauth">;
73
+ access: z.ZodString;
74
+ expires: z.ZodNumber;
75
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
76
+ projectId: z.ZodOptional<z.ZodString>;
77
+ email: z.ZodOptional<z.ZodString>;
78
+ accountId: z.ZodOptional<z.ZodString>;
79
+ refresh: z.ZodLiteral<"__remote__">;
80
+ }, z.core.$strict>, z.ZodObject<{
81
+ type: z.ZodLiteral<"api_key">;
82
+ key: z.ZodString;
83
+ }, z.core.$strict>], "type">;
84
+ identityKey: z.ZodNullable<z.ZodString>;
85
+ }, z.core.$strict>;
86
+ export declare const snapshotEntrySchema: z.ZodObject<{
87
+ id: z.ZodNumber;
88
+ provider: z.ZodString;
89
+ credential: z.ZodDiscriminatedUnion<[z.ZodObject<{
90
+ type: z.ZodLiteral<"oauth">;
91
+ access: z.ZodString;
92
+ expires: z.ZodNumber;
93
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
94
+ projectId: z.ZodOptional<z.ZodString>;
95
+ email: z.ZodOptional<z.ZodString>;
96
+ accountId: z.ZodOptional<z.ZodString>;
97
+ refresh: z.ZodLiteral<"__remote__">;
98
+ }, z.core.$strict>, z.ZodObject<{
99
+ type: z.ZodLiteral<"api_key">;
100
+ key: z.ZodString;
101
+ }, z.core.$strict>], "type">;
102
+ identityKey: z.ZodNullable<z.ZodString>;
103
+ rotatesInMs: z.ZodNullable<z.ZodNumber>;
104
+ }, z.core.$strict>;
105
+ export declare const refresherScheduleSchema: z.ZodObject<{
106
+ enabled: z.ZodBoolean;
107
+ intervalMs: z.ZodNumber;
108
+ skewMs: z.ZodNumber;
109
+ nextSweepInMs: z.ZodNumber;
110
+ }, z.core.$strict>;
111
+ export declare const snapshotResponseSchema: z.ZodObject<{
112
+ generation: z.ZodNumber;
113
+ generatedAt: z.ZodNumber;
114
+ serverNowMs: z.ZodNumber;
115
+ refresher: z.ZodObject<{
116
+ enabled: z.ZodBoolean;
117
+ intervalMs: z.ZodNumber;
118
+ skewMs: z.ZodNumber;
119
+ nextSweepInMs: z.ZodNumber;
120
+ }, z.core.$strict>;
121
+ credentials: z.ZodArray<z.ZodObject<{
122
+ id: z.ZodNumber;
123
+ provider: z.ZodString;
124
+ credential: z.ZodDiscriminatedUnion<[z.ZodObject<{
125
+ type: z.ZodLiteral<"oauth">;
126
+ access: z.ZodString;
127
+ expires: z.ZodNumber;
128
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
129
+ projectId: z.ZodOptional<z.ZodString>;
130
+ email: z.ZodOptional<z.ZodString>;
131
+ accountId: z.ZodOptional<z.ZodString>;
132
+ refresh: z.ZodLiteral<"__remote__">;
133
+ }, z.core.$strict>, z.ZodObject<{
134
+ type: z.ZodLiteral<"api_key">;
135
+ key: z.ZodString;
136
+ }, z.core.$strict>], "type">;
137
+ identityKey: z.ZodNullable<z.ZodString>;
138
+ rotatesInMs: z.ZodNullable<z.ZodNumber>;
139
+ }, z.core.$strict>>;
140
+ }, z.core.$strict>;
141
+ export declare const healthzResponseSchema: z.ZodObject<{
142
+ ok: z.ZodBoolean;
143
+ version: z.ZodOptional<z.ZodString>;
144
+ }, z.core.$strict>;
145
+ /**
146
+ * Broker `/v1/usage` response. Reports are full {@link UsageReport}s minus the
147
+ * heavy provider-specific `raw` field (the server strips it before send) — we
148
+ * keep `raw` optional in the underlying schema so a misconfigured broker that
149
+ * forgot to strip still validates.
150
+ */
151
+ export declare const usageResponseSchema: z.ZodObject<{
152
+ generatedAt: z.ZodNumber;
153
+ reports: z.ZodArray<z.ZodObject<{
154
+ provider: z.ZodString;
155
+ fetchedAt: z.ZodNumber;
156
+ limits: z.ZodArray<z.ZodObject<{
157
+ id: z.ZodString;
158
+ label: z.ZodString;
159
+ scope: z.ZodObject<{
160
+ provider: z.ZodString;
161
+ accountId: z.ZodOptional<z.ZodString>;
162
+ projectId: z.ZodOptional<z.ZodString>;
163
+ orgId: z.ZodOptional<z.ZodString>;
164
+ modelId: z.ZodOptional<z.ZodString>;
165
+ tier: z.ZodOptional<z.ZodString>;
166
+ windowId: z.ZodOptional<z.ZodString>;
167
+ shared: z.ZodOptional<z.ZodBoolean>;
168
+ }, z.core.$strip>;
169
+ window: z.ZodOptional<z.ZodObject<{
170
+ id: z.ZodString;
171
+ label: z.ZodString;
172
+ durationMs: z.ZodOptional<z.ZodNumber>;
173
+ resetsAt: z.ZodOptional<z.ZodNumber>;
174
+ }, z.core.$strip>>;
175
+ amount: z.ZodObject<{
176
+ used: z.ZodOptional<z.ZodNumber>;
177
+ limit: z.ZodOptional<z.ZodNumber>;
178
+ remaining: z.ZodOptional<z.ZodNumber>;
179
+ usedFraction: z.ZodOptional<z.ZodNumber>;
180
+ remainingFraction: z.ZodOptional<z.ZodNumber>;
181
+ unit: z.ZodEnum<{
182
+ bytes: "bytes";
183
+ minutes: "minutes";
184
+ percent: "percent";
185
+ requests: "requests";
186
+ tokens: "tokens";
187
+ unknown: "unknown";
188
+ usd: "usd";
189
+ }>;
190
+ }, z.core.$strip>;
191
+ status: z.ZodOptional<z.ZodEnum<{
192
+ exhausted: "exhausted";
193
+ ok: "ok";
194
+ unknown: "unknown";
195
+ warning: "warning";
196
+ }>>;
197
+ notes: z.ZodOptional<z.ZodArray<z.ZodString>>;
198
+ }, z.core.$strip>>;
199
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
200
+ raw: z.ZodOptional<z.ZodUnknown>;
201
+ }, z.core.$strip>>;
202
+ }, z.core.$strict>;
203
+ export declare const credentialRefreshResponseSchema: z.ZodObject<{
204
+ entry: z.ZodObject<{
205
+ id: z.ZodNumber;
206
+ provider: z.ZodString;
207
+ credential: z.ZodDiscriminatedUnion<[z.ZodObject<{
208
+ type: z.ZodLiteral<"oauth">;
209
+ access: z.ZodString;
210
+ expires: z.ZodNumber;
211
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
212
+ projectId: z.ZodOptional<z.ZodString>;
213
+ email: z.ZodOptional<z.ZodString>;
214
+ accountId: z.ZodOptional<z.ZodString>;
215
+ refresh: z.ZodLiteral<"__remote__">;
216
+ }, z.core.$strict>, z.ZodObject<{
217
+ type: z.ZodLiteral<"api_key">;
218
+ key: z.ZodString;
219
+ }, z.core.$strict>], "type">;
220
+ identityKey: z.ZodNullable<z.ZodString>;
221
+ }, z.core.$strict>;
222
+ }, z.core.$strict>;
223
+ export declare const credentialDisableRequestSchema: z.ZodObject<{
224
+ cause: z.ZodOptional<z.ZodString>;
225
+ }, z.core.$strict>;
226
+ export declare const credentialDisableResponseSchema: z.ZodObject<{
227
+ ok: z.ZodBoolean;
228
+ }, z.core.$strict>;
229
+ export declare const credentialUploadRequestSchema: z.ZodObject<{
230
+ provider: z.ZodString;
231
+ credential: z.ZodDiscriminatedUnion<[z.ZodObject<{
232
+ type: z.ZodLiteral<"oauth">;
233
+ refresh: z.ZodString;
234
+ access: z.ZodString;
235
+ expires: z.ZodNumber;
236
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
237
+ projectId: z.ZodOptional<z.ZodString>;
238
+ email: z.ZodOptional<z.ZodString>;
239
+ accountId: z.ZodOptional<z.ZodString>;
240
+ }, z.core.$strict>, z.ZodObject<{
241
+ type: z.ZodLiteral<"api_key">;
242
+ key: z.ZodString;
243
+ }, z.core.$strict>], "type">;
244
+ }, z.core.$strict>;
245
+ export declare const credentialUploadResponseSchema: z.ZodObject<{
246
+ entries: z.ZodArray<z.ZodObject<{
247
+ id: z.ZodNumber;
248
+ provider: z.ZodString;
249
+ credential: z.ZodDiscriminatedUnion<[z.ZodObject<{
250
+ type: z.ZodLiteral<"oauth">;
251
+ access: z.ZodString;
252
+ expires: z.ZodNumber;
253
+ enterpriseUrl: z.ZodOptional<z.ZodString>;
254
+ projectId: z.ZodOptional<z.ZodString>;
255
+ email: z.ZodOptional<z.ZodString>;
256
+ accountId: z.ZodOptional<z.ZodString>;
257
+ refresh: z.ZodLiteral<"__remote__">;
258
+ }, z.core.$strict>, z.ZodObject<{
259
+ type: z.ZodLiteral<"api_key">;
260
+ key: z.ZodString;
261
+ }, z.core.$strict>], "type">;
262
+ identityKey: z.ZodNullable<z.ZodString>;
263
+ }, z.core.$strict>>;
264
+ }, z.core.$strict>;