@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.
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { createHash } from 'crypto';
4
4
  import { mkdirSync, existsSync, chmodSync } from 'fs';
5
5
  import { createRequire } from 'module';
6
6
  import { dirname } from 'path';
7
+ import { isCoreConflictError, contentHash } from '@byok-sdk/core';
7
8
 
8
9
  // src/errors.ts
9
10
  var ByokKeysError = class extends Error {
@@ -38,13 +39,16 @@ var BYOK_KEYS_ERROR_CODES = {
38
39
  MODEL_RESPONSE_INVALID: "MODEL_RESPONSE_INVALID",
39
40
  PROVIDER_NOT_CONFIGURED: "PROVIDER_NOT_CONFIGURED",
40
41
  PROVIDER_PROFILE_INVALID: "PROVIDER_PROFILE_INVALID",
42
+ PROVIDER_PROFILE_CONFLICT: "PROVIDER_PROFILE_CONFLICT",
41
43
  PROVIDER_REQUEST_TIMEOUT: "PROVIDER_REQUEST_TIMEOUT",
42
44
  PROVIDER_RESPONSE_INVALID: "PROVIDER_RESPONSE_INVALID",
43
45
  PROVIDER_RESPONSE_TOO_LARGE: "PROVIDER_RESPONSE_TOO_LARGE",
44
46
  PROVIDER_SECRET_EMPTY: "PROVIDER_SECRET_EMPTY",
45
47
  PROVIDER_SECRET_MISSING: "PROVIDER_SECRET_MISSING",
46
48
  PROVIDER_SECRET_NOT_ALLOWED: "PROVIDER_SECRET_NOT_ALLOWED",
49
+ PROVIDER_SECRET_ROLLBACK_FAILED: "PROVIDER_SECRET_ROLLBACK_FAILED",
47
50
  PROVIDER_STORE_UNAVAILABLE: "PROVIDER_STORE_UNAVAILABLE",
51
+ PROVIDER_TRUTH_INVALID: "PROVIDER_TRUTH_INVALID",
48
52
  PROVIDER_URL_INVALID: "PROVIDER_URL_INVALID",
49
53
  SECRET_ENVELOPE_INVALID: "SECRET_ENVELOPE_INVALID",
50
54
  SECRET_NAME_INVALID: "SECRET_NAME_INVALID",
@@ -1135,24 +1139,24 @@ function providerNotConfigured(providerId) {
1135
1139
  }
1136
1140
  var InMemoryProviderProfileStore = class {
1137
1141
  #profiles = /* @__PURE__ */ new Map();
1138
- close() {
1142
+ async close() {
1139
1143
  this.#profiles.clear();
1140
1144
  }
1141
- delete(providerId) {
1145
+ async delete(providerId) {
1142
1146
  return this.#profiles.delete(providerId);
1143
1147
  }
1144
- get(providerId) {
1148
+ async get(providerId) {
1145
1149
  return this.#profiles.get(providerId);
1146
1150
  }
1147
- getEnabled() {
1148
- return this.list().find((profile) => profile.enabled);
1151
+ async getEnabled() {
1152
+ return [...this.#profiles.values()].find((profile) => profile.enabled);
1149
1153
  }
1150
- list() {
1154
+ async list() {
1151
1155
  return [...this.#profiles.values()].sort(
1152
1156
  (left, right) => left.provider_id.localeCompare(right.provider_id)
1153
1157
  );
1154
1158
  }
1155
- save(profile) {
1159
+ async save(profile) {
1156
1160
  const validated = parseModelProviderProfile({
1157
1161
  ...profile,
1158
1162
  created_at: this.#profiles.get(profile.provider_id)?.created_at ?? profile.created_at
@@ -1167,12 +1171,20 @@ var InMemoryProviderProfileStore = class {
1167
1171
  this.#profiles.set(validated.provider_id, validated);
1168
1172
  return validated;
1169
1173
  }
1170
- setEnabled(providerId) {
1174
+ async setEnabled(providerId) {
1171
1175
  const existing = this.#profiles.get(providerId);
1172
1176
  if (existing === void 0) throw providerNotConfigured(providerId);
1173
1177
  return this.save({ ...existing, enabled: true });
1174
1178
  }
1175
1179
  };
1180
+ function closeSqliteDatabaseAfterInitializationFailure(database, initializationError, message, close = (handle) => handle.close()) {
1181
+ try {
1182
+ close(database);
1183
+ } catch (closeError) {
1184
+ throw new AggregateError([initializationError, closeError], message);
1185
+ }
1186
+ throw initializationError;
1187
+ }
1176
1188
  var SECURE_DIR_MODE = 448;
1177
1189
  var SECURE_FILE_MODE = 384;
1178
1190
  var DEFAULT_BUSY_TIMEOUT_MS = 5e3;
@@ -1195,20 +1207,33 @@ function isSqliteAvailable() {
1195
1207
  return false;
1196
1208
  }
1197
1209
  }
1198
- function openSqliteDatabase(path, options) {
1210
+ function openSqliteDatabase(path, options, faults) {
1199
1211
  const { DatabaseSync } = loadSqliteModule();
1200
- if (path !== ":memory:") {
1212
+ const readOnly = options?.readOnly === true;
1213
+ if (path !== ":memory:" && !readOnly) {
1201
1214
  mkdirSync(dirname(path), { mode: SECURE_DIR_MODE, recursive: true });
1202
1215
  }
1203
1216
  const database = new DatabaseSync(path, {
1204
1217
  timeout: DEFAULT_BUSY_TIMEOUT_MS,
1205
1218
  ...options
1206
1219
  });
1207
- if (path !== ":memory:") {
1208
- database.exec("PRAGMA journal_mode = WAL");
1209
- database.exec("PRAGMA synchronous = FULL");
1220
+ try {
1221
+ faults?.onStep?.("after-open");
1222
+ if (path !== ":memory:" && !readOnly) {
1223
+ database.exec("PRAGMA journal_mode = WAL");
1224
+ faults?.onStep?.("after-wal");
1225
+ database.exec("PRAGMA synchronous = FULL");
1226
+ faults?.onStep?.("after-synchronous");
1227
+ }
1228
+ return database;
1229
+ } catch (error) {
1230
+ closeSqliteDatabaseAfterInitializationFailure(
1231
+ database,
1232
+ error,
1233
+ "provider profile SQLite open initialization failed and its native handle could not be closed",
1234
+ faults?.close
1235
+ );
1210
1236
  }
1211
- return database;
1212
1237
  }
1213
1238
  function secureSqliteFilePermissions(databasePath) {
1214
1239
  if (databasePath === ":memory:") return;
@@ -1247,10 +1272,22 @@ var SqliteProviderProfileStore = class {
1247
1272
  #database;
1248
1273
  #closed = false;
1249
1274
  constructor(options) {
1250
- this.#database = openSqliteDatabase(options.path);
1251
- this.#database.exec(SCHEMA);
1252
- this.#database.exec(ENABLED_INDEX);
1253
- secureSqliteFilePermissions(options.path);
1275
+ this.#database = openSqliteDatabase(options.path, {
1276
+ readOnly: options.readOnly ?? false
1277
+ });
1278
+ if (!options.readOnly) {
1279
+ try {
1280
+ this.#database.exec(SCHEMA);
1281
+ this.#database.exec(ENABLED_INDEX);
1282
+ secureSqliteFilePermissions(options.path);
1283
+ } catch (error) {
1284
+ closeSqliteDatabaseAfterInitializationFailure(
1285
+ this.#database,
1286
+ error,
1287
+ "SqliteProviderProfileStore initialization failed and its native handle could not be closed"
1288
+ );
1289
+ }
1290
+ }
1254
1291
  }
1255
1292
  /**
1256
1293
  * Idempotent, as {@link ProviderProfileStore.close} requires: `node:sqlite`
@@ -1258,31 +1295,32 @@ var SqliteProviderProfileStore = class {
1258
1295
  * routinely closed both by the code that finished with it and by a test's
1259
1296
  * teardown.
1260
1297
  */
1261
- close() {
1298
+ async close() {
1262
1299
  if (this.#closed) return;
1263
1300
  this.#closed = true;
1264
1301
  this.#database.close();
1265
1302
  }
1266
- delete(providerId) {
1303
+ async delete(providerId) {
1267
1304
  const result = this.#database.prepare("DELETE FROM provider_profile WHERE provider_id = ?").run(providerId);
1268
1305
  return Number(result.changes) === 1;
1269
1306
  }
1270
- get(providerId) {
1307
+ async get(providerId) {
1271
1308
  const row = this.#database.prepare("SELECT * FROM provider_profile WHERE provider_id = ?").get(providerId);
1272
1309
  return row === void 0 ? void 0 : parseRow(row);
1273
1310
  }
1274
- getEnabled() {
1311
+ async getEnabled() {
1275
1312
  const row = this.#database.prepare("SELECT * FROM provider_profile WHERE enabled = 1").get();
1276
1313
  return row === void 0 ? void 0 : parseRow(row);
1277
1314
  }
1278
- list() {
1315
+ async list() {
1279
1316
  const rows = this.#database.prepare("SELECT * FROM provider_profile ORDER BY provider_id ASC").all();
1280
1317
  return rows.map(parseRow);
1281
1318
  }
1282
- save(profile) {
1319
+ async save(profile) {
1320
+ const existing = await this.get(profile.provider_id);
1283
1321
  const validated = parseModelProviderProfile({
1284
1322
  ...profile,
1285
- created_at: this.get(profile.provider_id)?.created_at ?? profile.created_at
1323
+ created_at: existing?.created_at ?? profile.created_at
1286
1324
  });
1287
1325
  this.#transaction(() => {
1288
1326
  if (validated.enabled) {
@@ -1316,10 +1354,10 @@ var SqliteProviderProfileStore = class {
1316
1354
  validated.updated_at
1317
1355
  );
1318
1356
  });
1319
- return this.get(validated.provider_id);
1357
+ return await this.get(validated.provider_id);
1320
1358
  }
1321
- setEnabled(providerId) {
1322
- const existing = this.get(providerId);
1359
+ async setEnabled(providerId) {
1360
+ const existing = await this.get(providerId);
1323
1361
  if (existing === void 0) throw providerNotConfigured(providerId);
1324
1362
  return this.save({ ...existing, enabled: true });
1325
1363
  }
@@ -1341,6 +1379,219 @@ function parseRow(row) {
1341
1379
  enabled: row.enabled === 1
1342
1380
  });
1343
1381
  }
1382
+ var PROVIDER_PROFILE_TRUTH_RECORD_KEY = "byok-sdk.keys/model-provider-registry-v1";
1383
+ var PROFILE_KEYS = [
1384
+ "adapter",
1385
+ "auth_mode",
1386
+ "base_url",
1387
+ "created_at",
1388
+ "display_name",
1389
+ "enabled",
1390
+ "kind",
1391
+ "model",
1392
+ "provider_id",
1393
+ "updated_at"
1394
+ ];
1395
+ var TruthStoreProviderProfileStore = class {
1396
+ #tenant;
1397
+ #truth;
1398
+ constructor(options) {
1399
+ this.#tenant = options.tenant;
1400
+ this.#truth = options.truthStore;
1401
+ }
1402
+ async close() {
1403
+ }
1404
+ async delete(providerId) {
1405
+ const current = await this.#load();
1406
+ if (!current.profiles.some((profile) => profile.provider_id === providerId)) {
1407
+ return false;
1408
+ }
1409
+ await this.#write(
1410
+ current.profiles.filter((profile) => profile.provider_id !== providerId),
1411
+ current.rev
1412
+ );
1413
+ return true;
1414
+ }
1415
+ async get(providerId) {
1416
+ return (await this.#load()).profiles.find(
1417
+ (profile) => profile.provider_id === providerId
1418
+ );
1419
+ }
1420
+ async getEnabled() {
1421
+ return (await this.#load()).profiles.find((profile) => profile.enabled);
1422
+ }
1423
+ async list() {
1424
+ return [...(await this.#load()).profiles];
1425
+ }
1426
+ async save(profile) {
1427
+ const current = await this.#load();
1428
+ const existing = current.profiles.find(
1429
+ (candidate) => candidate.provider_id === profile.provider_id
1430
+ );
1431
+ const validated = parseModelProviderProfile({
1432
+ ...profile,
1433
+ created_at: existing?.created_at ?? profile.created_at
1434
+ });
1435
+ const next = current.profiles.filter((candidate) => candidate.provider_id !== validated.provider_id).map(
1436
+ (candidate) => validated.enabled && candidate.enabled ? { ...candidate, enabled: false } : candidate
1437
+ );
1438
+ next.push(validated);
1439
+ await this.#write(next, current.rev);
1440
+ return validated;
1441
+ }
1442
+ async setEnabled(providerId) {
1443
+ const current = await this.#load();
1444
+ const selected = current.profiles.find(
1445
+ (profile) => profile.provider_id === providerId
1446
+ );
1447
+ if (selected === void 0) throw providerNotConfigured(providerId);
1448
+ const next = current.profiles.map((profile) => ({
1449
+ ...profile,
1450
+ enabled: profile.provider_id === providerId
1451
+ }));
1452
+ await this.#write(next, current.rev);
1453
+ return { ...selected, enabled: true };
1454
+ }
1455
+ async #load() {
1456
+ const record = await this.#truth.getRecord(this.#tenant, {
1457
+ kind: "profile",
1458
+ recordKey: PROVIDER_PROFILE_TRUTH_RECORD_KEY
1459
+ });
1460
+ if (record === void 0) return { profiles: [], rev: 0 };
1461
+ return decodeRegistryRecord(record, this.#tenant);
1462
+ }
1463
+ async #write(profiles, expectedRev) {
1464
+ const encoded = encodeRegistry(profiles);
1465
+ let written;
1466
+ try {
1467
+ written = await this.#truth.writeSnapshot(this.#tenant, {
1468
+ kind: "profile",
1469
+ recordKey: PROVIDER_PROFILE_TRUTH_RECORD_KEY,
1470
+ expectedRev,
1471
+ contentHash: hashBody(encoded),
1472
+ byteSize: BigInt(new TextEncoder().encode(encoded).byteLength),
1473
+ body: { kind: "inline", body: encoded },
1474
+ label: "BYOK model provider registry"
1475
+ });
1476
+ } catch (cause) {
1477
+ if (isCoreConflictError(cause, "truth_revision_conflict")) {
1478
+ throw new ByokKeysError(
1479
+ "PROVIDER_PROFILE_CONFLICT",
1480
+ "Provider profiles changed since this operation read them",
1481
+ { cause }
1482
+ );
1483
+ }
1484
+ throw cause;
1485
+ }
1486
+ if (written.body.kind !== "inline" || written.body.body !== encoded) {
1487
+ throw invalidTruth("TruthStore did not confirm the requested provider profile snapshot");
1488
+ }
1489
+ const confirmed = decodeRegistryRecord(written, this.#tenant);
1490
+ if (confirmed.rev !== expectedRev + 1) {
1491
+ throw invalidTruth("TruthStore confirmed an unexpected provider profile revision");
1492
+ }
1493
+ }
1494
+ };
1495
+ function encodeRegistry(profiles) {
1496
+ const normalized = profiles.map((profile) => parseModelProviderProfile(profile)).sort((left, right) => left.provider_id.localeCompare(right.provider_id));
1497
+ assertRegistryInvariants(normalized);
1498
+ const snapshot = {
1499
+ schema_version: 1,
1500
+ profiles: normalized.map((profile) => ({
1501
+ adapter: profile.adapter,
1502
+ auth_mode: profile.auth_mode,
1503
+ base_url: profile.base_url,
1504
+ created_at: profile.created_at,
1505
+ display_name: profile.display_name,
1506
+ enabled: profile.enabled,
1507
+ kind: profile.kind,
1508
+ model: profile.model,
1509
+ provider_id: profile.provider_id,
1510
+ updated_at: profile.updated_at
1511
+ }))
1512
+ };
1513
+ return JSON.stringify(snapshot);
1514
+ }
1515
+ function decodeRegistryRecord(record, tenant) {
1516
+ if (record.tenantId !== tenant || record.kind !== "profile" || record.recordKey !== PROVIDER_PROFILE_TRUTH_RECORD_KEY || !Number.isSafeInteger(record.rev) || record.rev < 1) {
1517
+ throw invalidTruth("TruthStore returned mismatched provider profile authority");
1518
+ }
1519
+ if (record.body.kind !== "inline") {
1520
+ throw invalidTruth("Provider profiles must use an inline TruthStore body");
1521
+ }
1522
+ const bytes = new TextEncoder().encode(record.body.body);
1523
+ if (record.byteSize !== BigInt(bytes.byteLength)) {
1524
+ throw invalidTruth("Provider profile TruthStore byte size does not match its body");
1525
+ }
1526
+ if (record.contentHash !== hashBody(record.body.body)) {
1527
+ throw invalidTruth("Provider profile TruthStore hash does not match its body");
1528
+ }
1529
+ let raw;
1530
+ try {
1531
+ raw = JSON.parse(record.body.body);
1532
+ } catch (cause) {
1533
+ throw invalidTruth("Provider profile TruthStore body is not valid JSON", cause);
1534
+ }
1535
+ if (!isPlainRecord(raw) || !hasExactKeys(raw, ["profiles", "schema_version"])) {
1536
+ throw invalidTruth("Provider profile TruthStore body has an unknown top-level field");
1537
+ }
1538
+ if (raw.schema_version !== 1 || !Array.isArray(raw.profiles)) {
1539
+ throw invalidTruth("Provider profile TruthStore body has an unsupported schema");
1540
+ }
1541
+ if (raw.profiles.length > MODEL_PROVIDER_IDS.length) {
1542
+ throw invalidTruth("Provider profile TruthStore body exceeds the provider registry bound");
1543
+ }
1544
+ let profiles;
1545
+ try {
1546
+ profiles = raw.profiles.map((candidate) => {
1547
+ if (!isPlainRecord(candidate) || !hasExactKeys(candidate, PROFILE_KEYS)) {
1548
+ throw invalidTruth("Provider profile TruthStore body contains an unknown profile field");
1549
+ }
1550
+ return parseModelProviderProfile(candidate);
1551
+ });
1552
+ } catch (cause) {
1553
+ if (cause instanceof ByokKeysError && cause.code === "PROVIDER_TRUTH_INVALID") {
1554
+ throw cause;
1555
+ }
1556
+ throw invalidTruth("Provider profile TruthStore body contains an invalid profile", cause);
1557
+ }
1558
+ assertRegistryInvariants(profiles);
1559
+ if (record.body.body !== encodeRegistry(profiles)) {
1560
+ throw invalidTruth("Provider profile TruthStore body is not in canonical form");
1561
+ }
1562
+ return { profiles, rev: record.rev };
1563
+ }
1564
+ function assertRegistryInvariants(profiles) {
1565
+ const seen = /* @__PURE__ */ new Set();
1566
+ let enabled = 0;
1567
+ for (const profile of profiles) {
1568
+ if (seen.has(profile.provider_id)) {
1569
+ throw invalidTruth(`Provider profile ${profile.provider_id} appears more than once`);
1570
+ }
1571
+ seen.add(profile.provider_id);
1572
+ if (profile.enabled) enabled += 1;
1573
+ }
1574
+ if (enabled > 1) {
1575
+ throw invalidTruth("Provider profile TruthStore body enables more than one provider");
1576
+ }
1577
+ }
1578
+ function hashBody(body) {
1579
+ const digest = createHash("sha256").update(body, "utf8").digest("hex");
1580
+ return contentHash(`sha256:${digest}`);
1581
+ }
1582
+ function isPlainRecord(value) {
1583
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1584
+ }
1585
+ function hasExactKeys(value, expected) {
1586
+ const keys = Object.keys(value).sort();
1587
+ const wanted = [...expected].sort();
1588
+ return keys.length === wanted.length && keys.every((key, index) => key === wanted[index]);
1589
+ }
1590
+ function invalidTruth(message, cause) {
1591
+ return new ByokKeysError("PROVIDER_TRUTH_INVALID", message, {
1592
+ ...cause === void 0 ? {} : { cause }
1593
+ });
1594
+ }
1344
1595
 
1345
1596
  // src/registry.ts
1346
1597
  var ProviderRegistry = class {
@@ -1354,8 +1605,8 @@ var ProviderRegistry = class {
1354
1605
  this.#profiles = options.profileStore;
1355
1606
  this.#secrets = options.secretStore;
1356
1607
  }
1357
- close() {
1358
- this.#profiles.close();
1608
+ async close() {
1609
+ await this.#profiles.close();
1359
1610
  }
1360
1611
  /**
1361
1612
  * Persist a provider's profile and, when supplied, its secret
@@ -1368,15 +1619,17 @@ var ProviderRegistry = class {
1368
1619
  */
1369
1620
  async configure(configuration, secret) {
1370
1621
  const timestamp = this.#now().toISOString();
1371
- const previous = this.#profiles.get(configuration.provider_id);
1372
- const profile = {
1622
+ const previous = await this.#profiles.get(configuration.provider_id);
1623
+ const profile = parseModelProviderProfile({
1373
1624
  ...configuration,
1374
1625
  created_at: previous?.created_at ?? timestamp,
1375
1626
  enabled: configuration.enabled ?? true,
1376
1627
  kind: "model",
1377
1628
  updated_at: timestamp
1378
- };
1629
+ });
1379
1630
  const secretName = modelProviderSecretName(configuration.provider_id);
1631
+ let previousSecret;
1632
+ let secretWritten = false;
1380
1633
  if (configuration.auth_mode === "none" && secret !== void 0) {
1381
1634
  throw new ByokKeysError(
1382
1635
  "PROVIDER_SECRET_NOT_ALLOWED",
@@ -1390,7 +1643,9 @@ var ProviderRegistry = class {
1390
1643
  "Provider secret cannot be empty"
1391
1644
  );
1392
1645
  }
1646
+ previousSecret = await this.#secrets.get(secretName);
1393
1647
  await this.#secrets.set(secretName, secret);
1648
+ secretWritten = true;
1394
1649
  }
1395
1650
  if (configuration.auth_mode !== "none" && !await this.#secrets.has(secretName)) {
1396
1651
  throw new ByokKeysError(
@@ -1398,7 +1653,27 @@ var ProviderRegistry = class {
1398
1653
  "Provider authentication requires a secret in the operating-system credential store"
1399
1654
  );
1400
1655
  }
1401
- const saved = this.#profiles.save(profile);
1656
+ let saved;
1657
+ try {
1658
+ saved = await this.#profiles.save(profile);
1659
+ } catch (cause) {
1660
+ if (secretWritten) {
1661
+ try {
1662
+ if (previousSecret === void 0) {
1663
+ await this.#secrets.delete(secretName);
1664
+ } else {
1665
+ await this.#secrets.set(secretName, previousSecret);
1666
+ }
1667
+ } catch (rollbackCause) {
1668
+ throw new ByokKeysError(
1669
+ "PROVIDER_SECRET_ROLLBACK_FAILED",
1670
+ "Provider profile write failed and the previous secret could not be restored",
1671
+ { cause: new AggregateError([cause, rollbackCause]) }
1672
+ );
1673
+ }
1674
+ }
1675
+ throw cause;
1676
+ }
1402
1677
  if (saved.auth_mode === "none") {
1403
1678
  await this.#secrets.delete(secretName);
1404
1679
  }
@@ -1406,17 +1681,17 @@ var ProviderRegistry = class {
1406
1681
  }
1407
1682
  /** Remove a provider's profile and its secret together. */
1408
1683
  async delete(providerId) {
1409
- const removed = this.#profiles.delete(providerId);
1684
+ const removed = await this.#profiles.delete(providerId);
1410
1685
  await this.#secrets.delete(modelProviderSecretName(providerId));
1411
1686
  return removed;
1412
1687
  }
1413
1688
  async get(providerId) {
1414
- const profile = this.#profiles.get(providerId);
1689
+ const profile = await this.#profiles.get(providerId);
1415
1690
  return profile === void 0 ? void 0 : this.#status(profile);
1416
1691
  }
1417
1692
  async list() {
1418
1693
  return Promise.all(
1419
- this.#profiles.list().map((profile) => this.#status(profile))
1694
+ (await this.#profiles.list()).map((profile) => this.#status(profile))
1420
1695
  );
1421
1696
  }
1422
1697
  /**
@@ -1427,7 +1702,7 @@ var ProviderRegistry = class {
1427
1702
  * missing secret or an unusable profile is a fault, not an absence.
1428
1703
  */
1429
1704
  async resolveDefaultModelProvider() {
1430
- const profile = this.#profiles.getEnabled();
1705
+ const profile = await this.#profiles.getEnabled();
1431
1706
  if (profile === void 0) return void 0;
1432
1707
  const secret = await this.#secrets.get(
1433
1708
  modelProviderSecretName(profile.provider_id)
@@ -1437,7 +1712,7 @@ var ProviderRegistry = class {
1437
1712
  }
1438
1713
  /** Switch which configured provider is the default. */
1439
1714
  async setDefaultModelProvider(providerId) {
1440
- return this.#status(this.#profiles.setEnabled(providerId));
1715
+ return this.#status(await this.#profiles.setEnabled(providerId));
1441
1716
  }
1442
1717
  async #status(profile) {
1443
1718
  return {
@@ -1457,6 +1732,31 @@ var ProviderRegistry = class {
1457
1732
  }
1458
1733
  };
1459
1734
 
1460
- export { AnthropicMessagesClient, BYOK_KEYS_ERROR_CODES, ByokKeysError, DEFAULT_KEYCHAIN_SECRET_STORAGE_PREFIX, DEFAULT_SECRET_ENVELOPE_PREFIX, DEFAULT_SECRET_SERVICE_PREFIX, EnvelopeScopedSecretStore, InMemoryProviderProfileStore, InMemorySecretStore, MODEL_PROVIDER_ADAPTERS, MODEL_PROVIDER_IDS, MODEL_PROVIDER_SECRET_NAMES, MacOsKeychainSecretStore, ModelProviderProfileSchema, OpenAiCompatibleChatClient, PROVIDER_AUTH_MODES, PROVIDER_RESPONSE_MAX_BYTES, PROVIDER_TIMEOUT_MS, ProviderRegistry, SECRET_NAMESPACE_PATTERN, SECRET_NAME_PATTERN, SqliteProviderProfileStore, WindowsCredentialManagerSecretStore, anthropicMessageText, assertLiveModelResponse, assertSecretName, assertSecretNamespace, assertSharedSecretValue, chatCompletionText, classifyModelProviderHttpError, decodeStrictBase64Utf8, fetchWithProviderGuards, isLoopbackHost, isLoopbackProviderUrl, isPrivateNetworkLiteral, isSqliteAvailable, loadSqliteModule, modelApiUrl, modelMessageText, modelProviderSecretName, normalizeProviderUrl, objectValue, openSqliteDatabase, parseBoundedJsonResponse, parseModelProviderProfile, providerHeaders, readModelProviderResponse, requiredProviderSecret, runCommand, scopeSecretStore, secretScopeId, secureSqliteFilePermissions };
1735
+ // src/pi-provider-projection.ts
1736
+ var PI_PROJECTED_KEY_ENV = "PI_PROVIDER_API_KEY";
1737
+ function piProjectionProviderId(profileProviderId) {
1738
+ return `byok-sdk-${profileProviderId}`;
1739
+ }
1740
+ function buildPiProviderProjection(profile) {
1741
+ const projectedProviderId = piProjectionProviderId(profile.provider_id);
1742
+ return {
1743
+ providers: {
1744
+ [projectedProviderId]: {
1745
+ baseUrl: profile.base_url,
1746
+ api: profile.adapter === "anthropic" ? "anthropic-messages" : "openai-completions",
1747
+ ...profile.auth_mode === "none" ? {} : { apiKey: `$${PI_PROJECTED_KEY_ENV}` },
1748
+ ...profile.auth_mode === "bearer" ? { authHeader: true } : {},
1749
+ models: [
1750
+ {
1751
+ id: profile.model,
1752
+ name: profile.display_name
1753
+ }
1754
+ ]
1755
+ }
1756
+ }
1757
+ };
1758
+ }
1759
+
1760
+ export { AnthropicMessagesClient, BYOK_KEYS_ERROR_CODES, ByokKeysError, DEFAULT_KEYCHAIN_SECRET_STORAGE_PREFIX, DEFAULT_SECRET_ENVELOPE_PREFIX, DEFAULT_SECRET_SERVICE_PREFIX, EnvelopeScopedSecretStore, InMemoryProviderProfileStore, InMemorySecretStore, MODEL_PROVIDER_ADAPTERS, MODEL_PROVIDER_IDS, MODEL_PROVIDER_SECRET_NAMES, MacOsKeychainSecretStore, ModelProviderProfileSchema, OpenAiCompatibleChatClient, PI_PROJECTED_KEY_ENV, PROVIDER_AUTH_MODES, PROVIDER_PROFILE_TRUTH_RECORD_KEY, PROVIDER_RESPONSE_MAX_BYTES, PROVIDER_TIMEOUT_MS, ProviderRegistry, SECRET_NAMESPACE_PATTERN, SECRET_NAME_PATTERN, SqliteProviderProfileStore, TruthStoreProviderProfileStore, WindowsCredentialManagerSecretStore, anthropicMessageText, assertLiveModelResponse, assertSecretName, assertSecretNamespace, assertSharedSecretValue, buildPiProviderProjection, chatCompletionText, classifyModelProviderHttpError, decodeStrictBase64Utf8, fetchWithProviderGuards, isLoopbackHost, isLoopbackProviderUrl, isPrivateNetworkLiteral, isSqliteAvailable, loadSqliteModule, modelApiUrl, modelMessageText, modelProviderSecretName, normalizeProviderUrl, objectValue, openSqliteDatabase, parseBoundedJsonResponse, parseModelProviderProfile, providerHeaders, readModelProviderResponse, requiredProviderSecret, runCommand, scopeSecretStore, secretScopeId, secureSqliteFilePermissions };
1461
1761
  //# sourceMappingURL=index.js.map
1462
1762
  //# sourceMappingURL=index.js.map