@byok-sdk/keys 0.1.0 → 0.2.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.
@@ -0,0 +1,34 @@
1
+ import { type ModelProviderId, type ModelProviderProfile } from './provider-profile';
2
+ import { type SecretStore } from './secret-store';
3
+ export interface PiProviderLauncherOptions {
4
+ piBin: string;
5
+ profileDbPath: string;
6
+ providerId: ModelProviderId;
7
+ modelId: string;
8
+ sessionDir: string;
9
+ secretServicePrefix?: string;
10
+ piArgs: string[];
11
+ }
12
+ export declare function parsePiProviderLauncherOptions(args: string[]): PiProviderLauncherOptions;
13
+ /**
14
+ * Resolve only the credential the validated profile requires. In particular,
15
+ * an auth-free local provider must remain usable on hosts without an OS
16
+ * credential backend; constructing a keychain there would invent a false
17
+ * dependency and turn an explicit `auth_mode: none` into a hidden fallback.
18
+ */
19
+ export declare function resolvePiProviderSecret(profile: ModelProviderProfile, createStore: () => SecretStore): Promise<string | undefined>;
20
+ /** Build Pi's child environment from a closed platform baseline plus one exact key. */
21
+ export declare function buildPiProviderChildEnvironment(options: {
22
+ ambient: NodeJS.ProcessEnv;
23
+ projectionDir: string;
24
+ sessionDir: string;
25
+ secret: string | undefined;
26
+ platform?: NodeJS.Platform;
27
+ }): Record<string, string>;
28
+ /**
29
+ * Create the configured session directory owner-only without mutating the
30
+ * mode of an existing host-owned directory. The path is operator config, so
31
+ * an accidental `/`, home, or shared-directory value must never become a
32
+ * recursive chmod sink.
33
+ */
34
+ export declare function ensurePiSessionDirectory(sessionDir: string): Promise<void>;
@@ -0,0 +1,11 @@
1
+ import type { ModelProviderProfile } from './provider-profile';
2
+ export declare const PI_PROJECTED_KEY_ENV = "PI_PROVIDER_API_KEY";
3
+ /** Keep projected providers disjoint from Pi built-ins so composition can never fall back to one. */
4
+ export declare function piProjectionProviderId(profileProviderId: string): string;
5
+ /** Credential-blind Pi configuration derived from one validated local profile. */
6
+ export declare function buildPiProviderProjection(profile: ModelProviderProfile): object;
7
+ /**
8
+ * Validate the credential-blind RPC argv the client may delegate, then bind
9
+ * the Pi child to the namespaced projection and exact configured model.
10
+ */
11
+ export declare function buildPiProviderArgs(profile: ModelProviderProfile, delegatedArgs: readonly string[]): string[];
@@ -4,7 +4,7 @@ import { type ModelProviderId, type ModelProviderProfile } from './provider-prof
4
4
  * Storage contract for provider profiles — everything needed to address a
5
5
  * provider except the API key, which lives in a {@link SecretStore}.
6
6
  *
7
- * Shaped after `@byok/server`'s `TaskStore` (`packages/server/src/task-store.ts`)
7
+ * Shaped after `@byok-sdk/server`'s `TaskStore` (`packages/server/src/task-store.ts`)
8
8
  * as a *pattern*, not a dependency: `keys` must not import `server`, and
9
9
  * `server` must not import `keys` (the plan's Security Boundary keeps the
10
10
  * agent-dispatch packages free of any credential-adjacent code).
@@ -22,22 +22,22 @@ import { type ModelProviderId, type ModelProviderProfile } from './provider-prof
22
22
  */
23
23
  export interface ProviderProfileStore {
24
24
  /** Release the underlying resource. Safe to call more than once. */
25
- close(): void;
25
+ close(): Promise<void>;
26
26
  /** Remove `providerId`; `false` when it was not configured. */
27
- delete(providerId: ModelProviderId): boolean;
27
+ delete(providerId: ModelProviderId): Promise<boolean>;
28
28
  /** Read one provider's profile, configured or not enabled alike. */
29
- get(providerId: ModelProviderId): ModelProviderProfile | undefined;
29
+ get(providerId: ModelProviderId): Promise<ModelProviderProfile | undefined>;
30
30
  /** The single enabled profile, or `undefined` when none is enabled. */
31
- getEnabled(): ModelProviderProfile | undefined;
31
+ getEnabled(): Promise<ModelProviderProfile | undefined>;
32
32
  /** Every configured profile, ordered by provider id. */
33
- list(): ModelProviderProfile[];
33
+ list(): Promise<ModelProviderProfile[]>;
34
34
  /** Insert or update `profile`, enforcing both invariants above. */
35
- save(profile: ModelProviderProfile): ModelProviderProfile;
35
+ save(profile: ModelProviderProfile): Promise<ModelProviderProfile>;
36
36
  /**
37
37
  * Make `providerId` the enabled profile. Throws `PROVIDER_NOT_CONFIGURED`
38
38
  * when it has no profile — a fail-closed port of `providers.ts:1243-1250`.
39
39
  */
40
- setEnabled(providerId: ModelProviderId): ModelProviderProfile;
40
+ setEnabled(providerId: ModelProviderId): Promise<ModelProviderProfile>;
41
41
  }
42
42
  /** Shared by both implementations so their error text cannot drift apart. */
43
43
  export declare function providerNotConfigured(providerId: ModelProviderId): ByokKeysError;
@@ -45,17 +45,17 @@ export declare function providerNotConfigured(providerId: ModelProviderId): Byok
45
45
  * Profile store held in process memory: the default, and the one every test
46
46
  * that does not specifically exercise SQLite should use.
47
47
  *
48
- * Mirrors `InMemoryTaskStore`'s role in `@byok/server` — a real implementation
48
+ * Mirrors `InMemoryTaskStore`'s role in `@byok-sdk/server` — a real implementation
49
49
  * of the contract, not a stub, so behaviour proven here is the behaviour the
50
50
  * SQLite store must match (`profile-store.test.ts` runs one suite against both).
51
51
  */
52
52
  export declare class InMemoryProviderProfileStore implements ProviderProfileStore {
53
53
  #private;
54
- close(): void;
55
- delete(providerId: ModelProviderId): boolean;
56
- get(providerId: ModelProviderId): ModelProviderProfile | undefined;
57
- getEnabled(): ModelProviderProfile | undefined;
58
- list(): ModelProviderProfile[];
59
- save(profile: ModelProviderProfile): ModelProviderProfile;
60
- setEnabled(providerId: ModelProviderId): ModelProviderProfile;
54
+ close(): Promise<void>;
55
+ delete(providerId: ModelProviderId): Promise<boolean>;
56
+ get(providerId: ModelProviderId): Promise<ModelProviderProfile | undefined>;
57
+ getEnabled(): Promise<ModelProviderProfile | undefined>;
58
+ list(): Promise<ModelProviderProfile[]>;
59
+ save(profile: ModelProviderProfile): Promise<ModelProviderProfile>;
60
+ setEnabled(providerId: ModelProviderId): Promise<ModelProviderProfile>;
61
61
  }
@@ -75,7 +75,7 @@ export interface ProviderRegistryOptions {
75
75
  export declare class ProviderRegistry {
76
76
  #private;
77
77
  constructor(options: ProviderRegistryOptions);
78
- close(): void;
78
+ close(): Promise<void>;
79
79
  /**
80
80
  * Persist a provider's profile and, when supplied, its secret
81
81
  * (`providers.ts:1180-1229`).
@@ -4,12 +4,14 @@ export interface SqliteProviderProfileStoreOptions {
4
4
  /**
5
5
  * Database file path. `:memory:` exercises the SQLite code path without a
6
6
  * temp file, but defeats the point of this store (restart-safety) exactly as
7
- * it does for `@byok/server`'s `SqliteTaskStore`.
7
+ * it does for `@byok-sdk/server`'s `SqliteTaskStore`.
8
8
  */
9
9
  path: string;
10
+ /** Open an existing profile database without creating or mutating it. */
11
+ readOnly?: boolean;
10
12
  }
11
13
  /**
12
- * SQLite-backed {@link ProviderProfileStore}, following `@byok/server`'s
14
+ * SQLite-backed {@link ProviderProfileStore}, following `@byok-sdk/server`'s
13
15
  * `SqliteTaskStore` shape. Holds no secret: the API key lives in the injected
14
16
  * `SecretStore`, and `registry.golden.test.ts` asserts the plaintext key never
15
17
  * appears in this file's bytes.
@@ -23,13 +25,13 @@ export declare class SqliteProviderProfileStore implements ProviderProfileStore
23
25
  * routinely closed both by the code that finished with it and by a test's
24
26
  * teardown.
25
27
  */
26
- close(): void;
27
- delete(providerId: ModelProviderId): boolean;
28
- get(providerId: ModelProviderId): ModelProviderProfile | undefined;
29
- getEnabled(): ModelProviderProfile | undefined;
30
- list(): ModelProviderProfile[];
31
- save(profile: ModelProviderProfile): ModelProviderProfile;
32
- setEnabled(providerId: ModelProviderId): ModelProviderProfile;
28
+ close(): Promise<void>;
29
+ delete(providerId: ModelProviderId): Promise<boolean>;
30
+ get(providerId: ModelProviderId): Promise<ModelProviderProfile | undefined>;
31
+ getEnabled(): Promise<ModelProviderProfile | undefined>;
32
+ list(): Promise<ModelProviderProfile[]>;
33
+ save(profile: ModelProviderProfile): Promise<ModelProviderProfile>;
34
+ setEnabled(providerId: ModelProviderId): Promise<ModelProviderProfile>;
33
35
  }
34
36
  /** Exported for the store's own tests to enumerate the CHECK-constrained ids. */
35
37
  export declare const SQLITE_PROFILE_PROVIDER_IDS: readonly ["openai", "deepseek", "anthropic", "custom"];
@@ -1,4 +1,12 @@
1
1
  import type { DatabaseSync, DatabaseSyncOptions } from 'node:sqlite';
2
+ export type SqliteOpenStep = 'after-open' | 'after-wal' | 'after-synchronous';
3
+ /** Test-only seam for proving that post-open initialization failures release the native handle. */
4
+ export interface SqliteOpenFaultSeam {
5
+ onStep?(step: SqliteOpenStep): void;
6
+ close?(database: DatabaseSync): void;
7
+ }
8
+ /** Release an opened handle before propagating an initialization failure. */
9
+ export declare function closeSqliteDatabaseAfterInitializationFailure(database: DatabaseSync, initializationError: unknown, message: string, close?: (database: DatabaseSync) => void): never;
2
10
  interface SqliteModule {
3
11
  DatabaseSync: new (path: string, options?: DatabaseSyncOptions) => DatabaseSync;
4
12
  }
@@ -7,7 +15,7 @@ interface SqliteModule {
7
15
  *
8
16
  * `node:sqlite` shipped in Node.js 22.5.0 and stays marked experimental (an
9
17
  * `ExperimentalWarning` on stderr is expected and harmless). Following
10
- * `@byok/server`'s `sqlite-support.ts`, the SQLite-backed store here depends on
18
+ * `@byok-sdk/server`'s `sqlite-support.ts`, the SQLite-backed store here depends on
11
19
  * nothing else — no `better-sqlite3`, no native module — because zero native
12
20
  * dependencies is what keeps this package trivially packageable. The tradeoff
13
21
  * is that {@link SqliteProviderProfileStore} does not work below Node 22.5, and
@@ -18,7 +26,7 @@ export declare function loadSqliteModule(): SqliteModule;
18
26
  /**
19
27
  * Whether `node:sqlite` can ACTUALLY be loaded right now.
20
28
  *
21
- * Same predicate as `@byok/server`'s `sqlite-support.ts`, and it exists for the
29
+ * Same predicate as `@byok-sdk/server`'s `sqlite-support.ts`, and it exists for the
22
30
  * same reason: this package's `engines.node` is `>=20` and CI runs the matrix
23
31
  * on 20 and 22, but `node:sqlite` shipped in 22.5 and stayed behind
24
32
  * `--experimental-sqlite` for part of the 22.x line. A version-number
@@ -35,7 +43,7 @@ export declare function isSqliteAvailable(): boolean;
35
43
  * skips every filesystem step, which is how the shared contract suite exercises
36
44
  * the SQLite code path without leaving anything on disk.
37
45
  */
38
- export declare function openSqliteDatabase(path: string, options?: DatabaseSyncOptions): DatabaseSync;
46
+ export declare function openSqliteDatabase(path: string, options?: DatabaseSyncOptions, faults?: SqliteOpenFaultSeam): DatabaseSync;
39
47
  /**
40
48
  * Restrict `databasePath` and its WAL/SHM siblings to owner-only read/write.
41
49
  *
@@ -0,0 +1,27 @@
1
+ import { type TenantId, type TruthStore } from '@byok-sdk/core';
2
+ import { type ProviderProfileStore } from './profile-store';
3
+ import { type ModelProviderId, type ModelProviderProfile } from './provider-profile';
4
+ export declare const PROVIDER_PROFILE_TRUTH_RECORD_KEY = "byok-sdk.keys/model-provider-registry-v1";
5
+ export interface TruthStoreProviderProfileStoreOptions {
6
+ tenant: TenantId;
7
+ truthStore: TruthStore;
8
+ }
9
+ /**
10
+ * Tenant-bound profile persistence over the core TruthStore snapshot contract.
11
+ *
12
+ * The complete, closed provider registry is one CAS unit. That is what makes a
13
+ * delete and the "at most one enabled profile" transition atomic without
14
+ * adding a second transaction authority. The body is metadata only; provider
15
+ * credentials remain exclusively in the independently injected SecretStore.
16
+ */
17
+ export declare class TruthStoreProviderProfileStore implements ProviderProfileStore {
18
+ #private;
19
+ constructor(options: TruthStoreProviderProfileStoreOptions);
20
+ close(): Promise<void>;
21
+ delete(providerId: ModelProviderId): Promise<boolean>;
22
+ get(providerId: ModelProviderId): Promise<ModelProviderProfile | undefined>;
23
+ getEnabled(): Promise<ModelProviderProfile | undefined>;
24
+ list(): Promise<ModelProviderProfile[]>;
25
+ save(profile: ModelProviderProfile): Promise<ModelProviderProfile>;
26
+ setEnabled(providerId: ModelProviderId): Promise<ModelProviderProfile>;
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byok-sdk/keys",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "BYOK SDK key management: provider profiles, credential-backed auth headers, and direct provider transports",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,12 +14,15 @@
14
14
  },
15
15
  "homepage": "https://github.com/Ancienttwo/byok-sdk#readme",
16
16
  "engines": {
17
- "node": ">=20"
17
+ "node": ">=22.22.0"
18
18
  },
19
19
  "sideEffects": false,
20
20
  "main": "./dist/index.js",
21
21
  "module": "./dist/index.js",
22
22
  "types": "./dist/index.d.ts",
23
+ "bin": {
24
+ "byok-pi-provider-launcher": "./dist/bin/pi-provider-launcher.js"
25
+ },
23
26
  "exports": {
24
27
  ".": {
25
28
  "types": "./dist/index.d.ts",
@@ -28,20 +31,24 @@
28
31
  "./package.json": "./package.json"
29
32
  },
30
33
  "files": [
31
- "dist"
34
+ "dist",
35
+ "README.md",
36
+ "LICENSE"
32
37
  ],
33
38
  "publishConfig": {
34
39
  "access": "public"
35
40
  },
36
- "dependencies": {
37
- "zod": "^4.4.3"
38
- },
39
41
  "scripts": {
42
+ "prepublishOnly": "bun run build",
40
43
  "build": "tsup && tsc -p tsconfig.build.json",
41
44
  "dev": "tsup --watch",
42
45
  "test": "vitest run",
43
46
  "test:watch": "vitest",
44
47
  "typecheck": "tsc --noEmit",
45
48
  "clean": "rm -rf dist"
49
+ },
50
+ "dependencies": {
51
+ "@byok-sdk/core": "0.4.2",
52
+ "zod": "^4.4.3"
46
53
  }
47
- }
54
+ }