@byok-sdk/keys 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ancienttwo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # @byok-sdk/keys
2
+
3
+ Key-based BYOK: a validated provider profile, credential-backed auth headers, and
4
+ direct transports to OpenAI-compatible and Anthropic providers.
5
+
6
+ Status: **K3 done** — the pure-function layer (K0), the `SecretStore` layer
7
+ backed by the macOS Keychain and the Windows Credential Manager (K1), and the
8
+ configure/resolve registry with pluggable profile persistence (K2) have all
9
+ landed. K3 settled the settings-page question, recorded under
10
+ [Not in this package](#not-in-this-package). Next is K4, the aip-main-open swap.
11
+
12
+ ## Security boundary
13
+
14
+ `@byok-sdk/keys` is a separate package with a separate security model from
15
+ `@byok/client` / `@byok/server` / `@byok/protocol`. Those three dispatch tasks to
16
+ agent runtimes the user already authenticated, and their credential-isolation
17
+ rule (`packages/client/src/types.ts:120-124`, audited in
18
+ `docs/security-review-m5-pilot-entry.md`) promises the dispatch path never
19
+ touches credentials. This package's job *is* to hold a provider API key, so it
20
+ lives on the other side of that line: `client`, `server`, and `protocol` must not
21
+ depend on `keys`.
22
+
23
+ Two consequences hold today and are the package's standing constraints:
24
+
25
+ 1. `client`, `server`, and `protocol` must not gain a dependency on `keys`.
26
+ 2. `@byok-sdk/keys` is outside the scope of the M5 credential-isolation claim.
27
+ Installing it is opting into a package that holds a provider API key, and
28
+ that choice is yours, not something the dispatch SDK does on your behalf.
29
+
30
+ The full declaration of the boundary between the two security models is
31
+ [`docs/security.md`](../../docs/security.md), section *Key management
32
+ (`@byok-sdk/keys`) is a separate package with a separate security model*.
33
+
34
+ ## Not in this package
35
+
36
+ **There is no settings-page HTTP server here, and there will not be one.** The
37
+ source this package was ported from ships one — a localhost listener on a random
38
+ port, guarded by a token plus `Host`/`Origin`/CSP checks, serving
39
+ `/api/model/configure` and `/api/model/test`. It was evaluated for this package
40
+ at milestone K3 and deliberately excluded. Three reasons:
41
+
42
+ - **The host owns its own UI.** A settings page is product surface: its
43
+ branding, its routing, its invoke protocol, and its idea of what "configured"
44
+ should look like to a user. Shipping one from a library means every consumer
45
+ either accepts our product decisions or works around them.
46
+ - **This is a library, not a local web server.** A package you `npm install` to
47
+ hold a key should not decide to bind a socket. Anything that listens has a
48
+ lifecycle, a port, and an availability story that belongs to the application,
49
+ not to a dependency of it.
50
+ - **A key custodian does not open a listening port.** Every listener is an
51
+ entry point into the process that holds the API key. The narrowest defensible
52
+ posture for a component whose whole job is key custody is to expose no
53
+ network surface at all, so there is nothing to authenticate, rate-limit, or
54
+ CSRF-guard in the first place.
55
+
56
+ **The alternative: call `ProviderRegistry` directly.** Everything the settings
57
+ page did is available as a normal API. A host renders its own page and, in its
58
+ own request handler, calls `configure()`, `list()`, `get()`,
59
+ `setDefaultModelProvider()`, or `delete()`; to verify a key before committing to
60
+ it, resolve a client and call `testConnection()` on it. The registry never
61
+ returns the secret — `ProviderStatus` reports `secret_configured: boolean` and
62
+ nothing more — so a host can serve that object to its own UI without a
63
+ redaction step.
64
+
65
+ ### What this transfers to you
66
+
67
+ This exclusion moves a security property, and the move is the point of this
68
+ section. In the source, the settings page was part of the same local process
69
+ and never sent the API key anywhere; **the package itself underwrote the
70
+ guarantee that the key does not leave the machine.**
71
+
72
+ With the page gone, `@byok-sdk/keys` guarantees only its own half: the key goes
73
+ into the OS credential store, it is never written to the profile store, it is
74
+ never present in any `ProviderStatus`, and it leaves the process only in the
75
+ `authorization` / `x-api-key` header of a request to the provider base URL the
76
+ profile declares. **Everything between the user's keystroke and
77
+ `configure(configuration, secret)` is now yours.** If your settings page posts
78
+ the key to your own backend before handing it to this package, or renders it
79
+ back into a response, or logs the request body, the key has left the machine —
80
+ and no property of this package prevents that. You are the custodian of that
81
+ path now.
82
+
83
+ ## Node version and storage backends
84
+
85
+ `engines.node` is `>=20`, and that floor is deliberate: the package is fully
86
+ usable on Node 20.
87
+
88
+ | Backend | Requirement | Behaviour below it |
89
+ | --- | --- | --- |
90
+ | `InMemoryProviderProfileStore` | Node 20+ | — the whole configure/resolve lifecycle works |
91
+ | `SqliteProviderProfileStore` | Node 22.5+ (`node:sqlite`) | fails closed with `PROVIDER_STORE_UNAVAILABLE` |
92
+
93
+ Only on-disk profile persistence needs the newer runtime. `node:sqlite` shipped
94
+ in Node 22.5 and spent part of the 22.x line behind `--experimental-sqlite`, so
95
+ a version-number comparison would be wrong in both directions; call
96
+ `isSqliteAvailable()` to branch, and constructing a `SqliteProviderProfileStore`
97
+ without it throws `ByokKeysError` with code `PROVIDER_STORE_UNAVAILABLE` rather
98
+ than degrading to a plaintext file.
99
+
100
+ The floor rises only when a consumer needs on-disk persistence as an
101
+ install-time guarantee rather than a runtime capability — that is, when
102
+ "`@byok-sdk/keys` installed successfully" must by itself imply
103
+ `SqliteProviderProfileStore` will construct. Until then, raising it would drop
104
+ Node 20 hosts that are served perfectly well by the in-memory store.
105
+
106
+ ## Module inventory
107
+
108
+ Every module under `src/`, one line of responsibility each. The public surface is
109
+ whatever `index.ts` re-exports; nothing here is reachable by deep import.
110
+
111
+ | Module | Contents |
112
+ | --- | --- |
113
+ | `index.ts` | The package barrel — the single public entry point, and the only supported import path |
114
+ | `errors.ts` | `ByokKeysError` (`code` + message) and `BYOK_KEYS_ERROR_CODES`, the code strings consumers branch on |
115
+ | `provider-profile.ts` | zod schema for the model provider profile, including the adapter/auth-mode legality rules |
116
+ | `headers.ts` | `providerHeaders()` and fail-closed `requiredProviderSecret()` |
117
+ | `url.ts` | `normalizeProviderUrl()` with the HTTPS / loopback / private-network guard |
118
+ | `http.ts` | Shared transport guards: injectable `fetch`, timeout, bounded JSON, HTTP error classification |
119
+ | `openai-client.ts` | `OpenAiCompatibleChatClient` — chat/completions, injected `fetchImpl` |
120
+ | `anthropic-client.ts` | `AnthropicMessagesClient` — Messages API, injected `fetchImpl` |
121
+ | `secret-store.ts` | The `SecretStore` contract one credential entry is read and written through, plus the shared value/encoding guards |
122
+ | `secret-name.ts` | Runtime validation of secret entry names and namespaces, including the dot exclusion that stops one scope from spelling out another's storage key |
123
+ | `secret-scope.ts` | `SecretScope` and the envelope-scoped store that partitions a credential store by account and workspace |
124
+ | `macos-keychain.ts` | `SecretStore` backed by the macOS Keychain via the `security` CLI |
125
+ | `windows-credential-manager.ts` | `SecretStore` backed by the Win32 credential API via a PowerShell bridge |
126
+ | `command-runner.ts` | The `CommandRunner` injection seam both OS backends are written against, so no unit test touches a real credential store |
127
+ | `profile-store.ts` | The `ProviderProfileStore` persistence contract, plus the in-memory implementation |
128
+ | `sqlite-profile-store.ts` | `SqliteProviderProfileStore` — on-disk profile persistence on `node:sqlite` |
129
+ | `sqlite-support.ts` | Runtime `node:sqlite` capability detection and owner-only database file/directory creation |
130
+ | `registry.ts` | `ProviderRegistry` — the configure / list / resolve / delete lifecycle that binds a profile store to a secret store and hands back a ready client |
131
+
132
+ Auth modes map to headers as follows, and this mapping is the package's wire
133
+ contract:
134
+
135
+ | `auth_mode` | Headers added on top of `accept` / `content-type` |
136
+ | --- | --- |
137
+ | `bearer` | `authorization: Bearer <secret>` |
138
+ | `x_api_key` | `x-api-key: <secret>`, `anthropic-version: 2023-06-01` |
139
+ | `none` | none |
140
+
141
+ A profile declaring `bearer` or `x_api_key` without a secret fails closed with
142
+ `PROVIDER_SECRET_MISSING` instead of sending an unauthenticated request.
143
+
144
+ ## Provenance
145
+
146
+ Ported symbol by symbol from `aip-main-open@c6a5385`
147
+ `apps/local-agent/src/providers.ts`. The AiphaBee narrative and finance domain
148
+ symbols listed in `docs/researches/HANDOFF-byok-keys.md` §4.5 deliberately stayed
149
+ behind; the clients here take generic `messages` / `max_tokens` / `system`
150
+ parameters instead of building domain prompts.
@@ -0,0 +1,37 @@
1
+ import type { ModelProviderClientOptions } from './openai-client';
2
+ /** One Anthropic message. `content` is `unknown` so block arrays pass through. */
3
+ export interface AnthropicMessage {
4
+ role: 'user' | 'assistant';
5
+ content: unknown;
6
+ }
7
+ /**
8
+ * A Messages API request minus `model`, which the client fills from the
9
+ * profile. `max_tokens` is required because the API requires it.
10
+ */
11
+ export interface AnthropicMessageRequest {
12
+ messages: readonly AnthropicMessage[];
13
+ max_tokens: number;
14
+ system?: string;
15
+ temperature?: number;
16
+ }
17
+ /**
18
+ * Transport for the Anthropic Messages API, ported from
19
+ * `aip-main-open@c6a5385` `providers.ts:831-1067`.
20
+ *
21
+ * As with the OpenAI-compatible client, only `#createMessage`'s generic
22
+ * request/parse/error path travels; the narrative methods that wrapped it stay
23
+ * in aip-main-open per `docs/researches/HANDOFF-byok-keys.md` §4.5.
24
+ */
25
+ export declare class AnthropicMessagesClient {
26
+ #private;
27
+ readonly model: string;
28
+ /** False only when the provider is loopback, i.e. no data leaves the machine. */
29
+ readonly remoteDataTransfer: boolean;
30
+ constructor(options: ModelProviderClientOptions);
31
+ /** POST `<base_url>/messages`; returns the parsed response object. */
32
+ createMessage(request: AnthropicMessageRequest, signal?: AbortSignal): Promise<Record<string, unknown>>;
33
+ /** Round-trip the configured key against the provider (`providers.ts:1037-1054`). */
34
+ testConnection(signal?: AbortSignal): Promise<void>;
35
+ }
36
+ /** Pull the assistant text out of a Messages API payload (`providers.ts:1084`). */
37
+ export declare function anthropicMessageText(payload: Record<string, unknown>): string;
@@ -0,0 +1,22 @@
1
+ /** A finished child process, ported from `aip-main-open@c6a5385` `index.ts:284-288`. */
2
+ export interface CommandResult {
3
+ exitCode: number;
4
+ stderr: string;
5
+ stdout: string;
6
+ }
7
+ /**
8
+ * The injection seam both OS backends are written against. Unit tests supply a
9
+ * fake so no test ever reads or writes a real credential store; production code
10
+ * gets {@link runCommand}.
11
+ */
12
+ export type CommandRunner = (executable: string, args: string[], stdin?: string) => Promise<CommandResult>;
13
+ /**
14
+ * Spawn `executable`, feed it `stdin`, and collect its output
15
+ * (`index.ts:2498-2527`).
16
+ *
17
+ * It never rejects: a missing executable resolves as exit code 127 so the
18
+ * backends' `available()` probes can treat "no such binary" the same way they
19
+ * treat "binary said no". Stdin is always closed, otherwise a child that reads
20
+ * to EOF would hang forever.
21
+ */
22
+ export declare function runCommand(executable: string, args: string[], stdin?: string): Promise<CommandResult>;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Single error class for `@byok/keys`.
3
+ *
4
+ * The ported source (`aip-main-open@c6a5385`, `apps/local-agent/src/providers.ts`)
5
+ * raised two different classes — `LocalExecutionError` and
6
+ * `ResearchExecutionError` — that differed only in which subsystem owned the
7
+ * throw site; both carried a `code` string and consumers branched on that code.
8
+ * The narrative/research subsystem stays behind in aip-main-open, so this
9
+ * package keeps one class and preserves the `code` strings verbatim. K4's swap
10
+ * converts aip's two `instanceof` sites to structured code detection, so the
11
+ * strings — not the class identity — are the compatibility surface.
12
+ */
13
+ export declare class ByokKeysError extends Error {
14
+ readonly code: string;
15
+ readonly httpStatus?: number;
16
+ constructor(code: string, message: string, options?: ErrorOptions & {
17
+ httpStatus?: number;
18
+ });
19
+ }
20
+ /**
21
+ * Error codes this package can throw, ported verbatim from the source. Kept as
22
+ * a named record so consumers (and K4's aip-main-open swap) can branch on
23
+ * `error.code` without retyping string literals.
24
+ *
25
+ * Four codes have no source counterpart, and each guards a check the source did
26
+ * not make: `KEYCHAIN_SECRET_DECODE_FAILED` (the source returned an undecodable
27
+ * stored value as-is), `SECRET_ENVELOPE_INVALID` (it reported a malformed
28
+ * envelope as an absent secret), and `SECRET_NAME_INVALID` /
29
+ * `SECRET_VALUE_INVALID` (the runtime replacements for the closed
30
+ * `KeychainSecretName` union). Everything else matches the source string for
31
+ * string.
32
+ *
33
+ * `SECRET_NAMESPACE_INVALID` is a separate case. The source does record it:
34
+ * `normalizeSecretNamespace` (`index.ts:748-757`) throws the verbatim string
35
+ * `'SECRET_NAMESPACE_INVALID'` at `index.ts:752`, and this package ports both
36
+ * that string and its pattern unchanged. It is still not a compatibility
37
+ * surface K4 must match, but for a different reason than the string: neither
38
+ * side has a branch consumer. In the source the only callers are the two OS
39
+ * stores' `scope()` methods, which just compose a service prefix; here the code
40
+ * is only ever asserted in tests. Matching it costs nothing and constrains
41
+ * nothing.
42
+ */
43
+ export declare const BYOK_KEYS_ERROR_CODES: {
44
+ readonly CREDENTIAL_MANAGER_DELETE_FAILED: 'CREDENTIAL_MANAGER_DELETE_FAILED';
45
+ readonly CREDENTIAL_MANAGER_READ_FAILED: 'CREDENTIAL_MANAGER_READ_FAILED';
46
+ readonly CREDENTIAL_MANAGER_SECRET_INVALID: 'CREDENTIAL_MANAGER_SECRET_INVALID';
47
+ readonly CREDENTIAL_MANAGER_UNAVAILABLE: 'CREDENTIAL_MANAGER_UNAVAILABLE';
48
+ readonly CREDENTIAL_MANAGER_WRITE_FAILED: 'CREDENTIAL_MANAGER_WRITE_FAILED';
49
+ readonly KEYCHAIN_ARGUMENT_INVALID: 'KEYCHAIN_ARGUMENT_INVALID';
50
+ readonly KEYCHAIN_DELETE_FAILED: 'KEYCHAIN_DELETE_FAILED';
51
+ readonly KEYCHAIN_READ_FAILED: 'KEYCHAIN_READ_FAILED';
52
+ readonly KEYCHAIN_SECRET_DECODE_FAILED: 'KEYCHAIN_SECRET_DECODE_FAILED';
53
+ readonly KEYCHAIN_SECRET_INVALID: 'KEYCHAIN_SECRET_INVALID';
54
+ readonly KEYCHAIN_UNAVAILABLE: 'KEYCHAIN_UNAVAILABLE';
55
+ readonly KEYCHAIN_WRITE_FAILED: 'KEYCHAIN_WRITE_FAILED';
56
+ readonly LOCAL_ACCOUNT_SCOPE_INVALID: 'LOCAL_ACCOUNT_SCOPE_INVALID';
57
+ readonly MODEL_PROVIDER_AUTH_FAILED: 'MODEL_PROVIDER_AUTH_FAILED';
58
+ readonly MODEL_PROVIDER_BALANCE_INSUFFICIENT: 'MODEL_PROVIDER_BALANCE_INSUFFICIENT';
59
+ readonly MODEL_PROVIDER_HTTP_ERROR: 'MODEL_PROVIDER_HTTP_ERROR';
60
+ readonly MODEL_PROVIDER_MODEL_NOT_FOUND: 'MODEL_PROVIDER_MODEL_NOT_FOUND';
61
+ readonly MODEL_PROVIDER_RATE_LIMITED: 'MODEL_PROVIDER_RATE_LIMITED';
62
+ readonly MODEL_RESPONSE_INVALID: 'MODEL_RESPONSE_INVALID';
63
+ readonly PROVIDER_NOT_CONFIGURED: 'PROVIDER_NOT_CONFIGURED';
64
+ readonly PROVIDER_PROFILE_INVALID: 'PROVIDER_PROFILE_INVALID';
65
+ readonly PROVIDER_REQUEST_TIMEOUT: 'PROVIDER_REQUEST_TIMEOUT';
66
+ readonly PROVIDER_RESPONSE_INVALID: 'PROVIDER_RESPONSE_INVALID';
67
+ readonly PROVIDER_RESPONSE_TOO_LARGE: 'PROVIDER_RESPONSE_TOO_LARGE';
68
+ readonly PROVIDER_SECRET_EMPTY: 'PROVIDER_SECRET_EMPTY';
69
+ readonly PROVIDER_SECRET_MISSING: 'PROVIDER_SECRET_MISSING';
70
+ readonly PROVIDER_SECRET_NOT_ALLOWED: 'PROVIDER_SECRET_NOT_ALLOWED';
71
+ readonly PROVIDER_STORE_UNAVAILABLE: 'PROVIDER_STORE_UNAVAILABLE';
72
+ readonly PROVIDER_URL_INVALID: 'PROVIDER_URL_INVALID';
73
+ readonly SECRET_ENVELOPE_INVALID: 'SECRET_ENVELOPE_INVALID';
74
+ readonly SECRET_NAME_INVALID: 'SECRET_NAME_INVALID';
75
+ readonly SECRET_NAMESPACE_INVALID: 'SECRET_NAMESPACE_INVALID';
76
+ readonly SECRET_VALUE_INVALID: 'SECRET_VALUE_INVALID';
77
+ };
78
+ export type ByokKeysErrorCode = (typeof BYOK_KEYS_ERROR_CODES)[keyof typeof BYOK_KEYS_ERROR_CODES];
@@ -0,0 +1,21 @@
1
+ import type { ProviderAuthMode } from './provider-profile';
2
+ /** The subset of a profile the header builder reads. */
3
+ export interface ProviderAuthProfile {
4
+ auth_mode: ProviderAuthMode;
5
+ kind: string;
6
+ }
7
+ /**
8
+ * Fail-closed secret check. Ported from `aip-main-open@c6a5385`
9
+ * `providers.ts:1657-1671`: a profile that declares `bearer` or `x_api_key`
10
+ * must have a secret, or the request is refused rather than sent unauthenticated.
11
+ */
12
+ export declare function requiredProviderSecret(profile: ProviderAuthProfile, secret: string | undefined): string | undefined;
13
+ /**
14
+ * Build the outbound request headers for a provider call. Key-for-key
15
+ * equivalent to `providers.ts:1680-1697`:
16
+ * - always `accept` and `content-type`;
17
+ * - `bearer` adds `authorization: Bearer <secret>`;
18
+ * - `x_api_key` adds `x-api-key: <secret>` and `anthropic-version: 2023-06-01`;
19
+ * - `none` adds nothing.
20
+ */
21
+ export declare function providerHeaders(profile: ProviderAuthProfile, secret: string | undefined): Record<string, string>;
package/dist/http.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ /** Injectable `fetch`. Defaults to `globalThis.fetch` at every call site. */
2
+ export type ProviderFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
3
+ /** Response body ceiling, ported from `providers.ts:106`. */
4
+ export declare const PROVIDER_RESPONSE_MAX_BYTES: number;
5
+ /** Per-request timeout, ported from `providers.ts:107`. */
6
+ export declare const PROVIDER_TIMEOUT_MS = 15000;
7
+ /**
8
+ * Issue a provider request under the source's guards
9
+ * (`providers.ts:1711-1743`): the URL is re-validated immediately before the
10
+ * call, the caller's abort signal is chained, and an internal timeout aborts
11
+ * with a distinguishable reason so a timeout maps to
12
+ * `PROVIDER_REQUEST_TIMEOUT` rather than a bare `AbortError`.
13
+ */
14
+ export declare function fetchWithProviderGuards(fetchImpl: ProviderFetch, url: string, init: RequestInit, signal: AbortSignal): Promise<Response>;
15
+ /**
16
+ * Read a JSON body with a size ceiling (`providers.ts:1825-1851`). The
17
+ * `content-length` check is an early exit; the decoded-byte check is the one
18
+ * that actually holds, since `content-length` is attacker-controlled.
19
+ */
20
+ export declare function parseBoundedJsonResponse(response: Response): Promise<unknown>;
21
+ /**
22
+ * Parse a model-provider response, mapping non-2xx to a classified error
23
+ * (`providers.ts:1748-1769`). The source's `context` parameter only chose
24
+ * between two error classes; this package has one, so the parameter is gone.
25
+ */
26
+ export declare function readModelProviderResponse(response: Response): Promise<unknown>;
27
+ /**
28
+ * Map an HTTP status plus error body onto a stable code
29
+ * (`providers.ts:1783-1815`). Providers disagree on status codes for billing
30
+ * and key problems, so the body text is inspected as well — the pattern lists
31
+ * are verbatim from the source, including the Chinese-language variants the
32
+ * source's providers actually return.
33
+ */
34
+ export declare function classifyModelProviderHttpError(status: number, payload: unknown): string;
35
+ /** Join a normalized base URL with an API path, idempotently (`providers.ts:1949-1953`). */
36
+ export declare function modelApiUrl(baseUrl: string, suffix: string): string;
37
+ /**
38
+ * Flatten a message content field to text (`providers.ts:1955-1971`). Both
39
+ * dialects return either a string or an array of typed blocks.
40
+ */
41
+ export declare function modelMessageText(value: unknown): string;
42
+ export declare function objectValue(value: unknown): Record<string, unknown> | undefined;
43
+ /** `providers.ts:2301-2308` — an empty completion does not prove a live key. */
44
+ export declare function assertLiveModelResponse(value: string): void;
@@ -0,0 +1,31 @@
1
+ export { ByokKeysError, BYOK_KEYS_ERROR_CODES } from './errors';
2
+ export type { ByokKeysErrorCode } from './errors';
3
+ export { MODEL_PROVIDER_IDS, MODEL_PROVIDER_ADAPTERS, PROVIDER_AUTH_MODES, ModelProviderProfileSchema, parseModelProviderProfile, } from './provider-profile';
4
+ export type { ModelProviderAdapter, ModelProviderId, ModelProviderProfile, ModelProviderProfileInput, ProviderAuthMode, } from './provider-profile';
5
+ export { providerHeaders, requiredProviderSecret } from './headers';
6
+ export type { ProviderAuthProfile } from './headers';
7
+ export { normalizeProviderUrl, isLoopbackHost, isLoopbackProviderUrl, isPrivateNetworkLiteral, } from './url';
8
+ export { assertLiveModelResponse, classifyModelProviderHttpError, fetchWithProviderGuards, modelApiUrl, modelMessageText, objectValue, parseBoundedJsonResponse, PROVIDER_RESPONSE_MAX_BYTES, PROVIDER_TIMEOUT_MS, readModelProviderResponse, } from './http';
9
+ export type { ProviderFetch } from './http';
10
+ export { OpenAiCompatibleChatClient, chatCompletionText } from './openai-client';
11
+ export type { ChatCompletionRequest, ChatMessage, ModelProviderClientOptions, } from './openai-client';
12
+ export { AnthropicMessagesClient, anthropicMessageText } from './anthropic-client';
13
+ export type { AnthropicMessage, AnthropicMessageRequest, } from './anthropic-client';
14
+ export { runCommand } from './command-runner';
15
+ export type { CommandResult, CommandRunner } from './command-runner';
16
+ export { SECRET_NAME_PATTERN, SECRET_NAMESPACE_PATTERN, assertSecretName, assertSecretNamespace, } from './secret-name';
17
+ export { DEFAULT_SECRET_SERVICE_PREFIX, InMemorySecretStore, MODEL_PROVIDER_SECRET_NAMES, assertSharedSecretValue, decodeStrictBase64Utf8, modelProviderSecretName, } from './secret-store';
18
+ export type { ModelProviderSecretName, SecretStore } from './secret-store';
19
+ export { DEFAULT_KEYCHAIN_SECRET_STORAGE_PREFIX, MacOsKeychainSecretStore, } from './macos-keychain';
20
+ export type { MacOsKeychainSecretStoreOptions } from './macos-keychain';
21
+ export { WindowsCredentialManagerSecretStore } from './windows-credential-manager';
22
+ export type { WindowsCredentialManagerSecretStoreOptions } from './windows-credential-manager';
23
+ export { DEFAULT_SECRET_ENVELOPE_PREFIX, EnvelopeScopedSecretStore, scopeSecretStore, secretScopeId, } from './secret-scope';
24
+ export type { SecretScope } from './secret-scope';
25
+ export { InMemoryProviderProfileStore } from './profile-store';
26
+ export type { ProviderProfileStore } from './profile-store';
27
+ export { isSqliteAvailable, loadSqliteModule, openSqliteDatabase, secureSqliteFilePermissions, } from './sqlite-support';
28
+ export { SqliteProviderProfileStore } from './sqlite-profile-store';
29
+ export type { SqliteProviderProfileStoreOptions } from './sqlite-profile-store';
30
+ export { ProviderRegistry } from './registry';
31
+ export type { ModelProviderClient, ProviderConfiguration, ProviderRegistryOptions, ProviderStatus, } from './registry';