@byok-sdk/keys 0.3.10 → 0.4.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.
@@ -72,6 +72,89 @@ function assertSecretNamespace(value) {
72
72
  return normalized;
73
73
  }
74
74
 
75
+ // src/provider-catalog.ts
76
+ function openAiCompatible(display_name, base_url, api_key_env) {
77
+ return {
78
+ display_name,
79
+ base_url,
80
+ adapter: "openai_compatible",
81
+ auth_mode: "bearer",
82
+ api_key_env
83
+ };
84
+ }
85
+ function anthropicMessages(display_name, base_url, api_key_env) {
86
+ return {
87
+ display_name,
88
+ base_url,
89
+ adapter: "anthropic",
90
+ auth_mode: "x_api_key",
91
+ api_key_env
92
+ };
93
+ }
94
+ var MODEL_PROVIDER_VENDORS = {
95
+ "ant-ling": openAiCompatible("Ant Ling", "https://api.ant-ling.com/v1", "ANT_LING_API_KEY"),
96
+ baseten: openAiCompatible("Baseten", "https://inference.baseten.co/v1", "BASETEN_API_KEY"),
97
+ cerebras: openAiCompatible("Cerebras", "https://api.cerebras.ai/v1", "CEREBRAS_API_KEY"),
98
+ deepseek: openAiCompatible("DeepSeek", "https://api.deepseek.com", "DEEPSEEK_API_KEY"),
99
+ groq: openAiCompatible("Groq", "https://api.groq.com/openai/v1", "GROQ_API_KEY"),
100
+ huggingface: openAiCompatible("Hugging Face", "https://router.huggingface.co/v1", "HF_TOKEN"),
101
+ moonshotai: openAiCompatible("Moonshot AI", "https://api.moonshot.ai/v1", "MOONSHOT_API_KEY"),
102
+ "moonshotai-cn": openAiCompatible("Moonshot AI CN", "https://api.moonshot.cn/v1", "MOONSHOT_API_KEY"),
103
+ nvidia: openAiCompatible("NVIDIA", "https://integrate.api.nvidia.com/v1", "NVIDIA_API_KEY"),
104
+ openai: openAiCompatible("OpenAI", "https://api.openai.com/v1", "OPENAI_API_KEY"),
105
+ openrouter: openAiCompatible("OpenRouter", "https://openrouter.ai/api/v1", "OPENROUTER_API_KEY"),
106
+ "qwen-token-plan": openAiCompatible(
107
+ "Qwen Token Plan",
108
+ "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
109
+ "QWEN_TOKEN_PLAN_API_KEY"
110
+ ),
111
+ "qwen-token-plan-cn": openAiCompatible(
112
+ "Qwen Token Plan CN",
113
+ "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
114
+ "QWEN_TOKEN_PLAN_CN_API_KEY"
115
+ ),
116
+ together: openAiCompatible("Together", "https://api.together.ai/v1", "TOGETHER_API_KEY"),
117
+ xai: openAiCompatible("xAI", "https://api.x.ai/v1", "XAI_API_KEY"),
118
+ xiaomi: openAiCompatible("Xiaomi", "https://api.xiaomimimo.com/v1", "XIAOMI_API_KEY"),
119
+ "xiaomi-token-plan-ams": openAiCompatible(
120
+ "Xiaomi Token Plan AMS",
121
+ "https://token-plan-ams.xiaomimimo.com/v1",
122
+ "XIAOMI_TOKEN_PLAN_AMS_API_KEY"
123
+ ),
124
+ "xiaomi-token-plan-cn": openAiCompatible(
125
+ "Xiaomi Token Plan CN",
126
+ "https://token-plan-cn.xiaomimimo.com/v1",
127
+ "XIAOMI_TOKEN_PLAN_CN_API_KEY"
128
+ ),
129
+ "xiaomi-token-plan-sgp": openAiCompatible(
130
+ "Xiaomi Token Plan SGP",
131
+ "https://token-plan-sgp.xiaomimimo.com/v1",
132
+ "XIAOMI_TOKEN_PLAN_SGP_API_KEY"
133
+ ),
134
+ zai: openAiCompatible("Z.AI", "https://api.z.ai/api/coding/paas/v4", "ZAI_API_KEY"),
135
+ "zai-coding-cn": openAiCompatible(
136
+ "Z.AI Coding CN",
137
+ "https://open.bigmodel.cn/api/coding/paas/v4",
138
+ "ZAI_CODING_CN_API_KEY"
139
+ ),
140
+ anthropic: anthropicMessages("Anthropic", "https://api.anthropic.com/v1", "ANTHROPIC_API_KEY"),
141
+ fireworks: anthropicMessages("Fireworks", "https://api.fireworks.ai/inference/v1", "FIREWORKS_API_KEY"),
142
+ "kimi-coding": anthropicMessages("Kimi For Coding", "https://api.kimi.com/coding/v1", "KIMI_API_KEY"),
143
+ minimax: anthropicMessages("MiniMax", "https://api.minimax.io/anthropic/v1", "MINIMAX_API_KEY"),
144
+ "minimax-cn": anthropicMessages("MiniMax CN", "https://api.minimaxi.com/anthropic/v1", "MINIMAX_CN_API_KEY"),
145
+ "vercel-ai-gateway": anthropicMessages(
146
+ "Vercel AI Gateway",
147
+ "https://ai-gateway.vercel.sh/v1",
148
+ "AI_GATEWAY_API_KEY"
149
+ )
150
+ };
151
+ var MODEL_PROVIDER_VENDOR_IDS = Object.keys(
152
+ MODEL_PROVIDER_VENDORS
153
+ );
154
+ function modelProviderVendor(kind) {
155
+ return Object.hasOwn(MODEL_PROVIDER_VENDORS, kind) ? MODEL_PROVIDER_VENDORS[kind] : void 0;
156
+ }
157
+
75
158
  // src/url.ts
76
159
  function normalizeProviderUrl(value) {
77
160
  let url;
@@ -118,9 +201,7 @@ var ProviderProfileRefSchema = z.string().min(1).max(64).regex(
118
201
  "provider profile refs must be lowercase portable identifiers"
119
202
  );
120
203
  var MODEL_PROVIDER_KINDS = [
121
- "openai",
122
- "deepseek",
123
- "anthropic",
204
+ ...MODEL_PROVIDER_VENDOR_IDS,
124
205
  "custom"
125
206
  ];
126
207
  var PROVIDER_MODEL_CAPABILITIES = ["image-input"];
@@ -195,6 +276,14 @@ var ModelProviderProfileSchema = z.object({
195
276
  path: ["auth_mode"]
196
277
  });
197
278
  }
279
+ const vendor = modelProviderVendor(profile.provider_kind);
280
+ if (vendor !== void 0 && vendor.adapter !== profile.adapter) {
281
+ ctx.addIssue({
282
+ code: "custom",
283
+ message: `Provider kind ${profile.provider_kind} speaks the ${vendor.adapter} adapter`,
284
+ path: ["adapter"]
285
+ });
286
+ }
198
287
  if (Date.parse(profile.updated_at) < Date.parse(profile.created_at)) {
199
288
  ctx.addIssue({
200
289
  code: "custom",
@@ -776,15 +865,18 @@ function secureSqliteFilePermissions(databasePath) {
776
865
  }
777
866
 
778
867
  // src/sqlite-profile-store.ts
868
+ function sqlList(values) {
869
+ return values.map((value) => `'${value}'`).join(", ");
870
+ }
779
871
  var SCHEMA = `
780
872
  CREATE TABLE IF NOT EXISTS provider_profile (
781
873
  profile_ref TEXT PRIMARY KEY,
782
- provider_kind TEXT NOT NULL CHECK (provider_kind IN ('openai', 'deepseek', 'anthropic', 'custom')),
874
+ provider_kind TEXT NOT NULL CHECK (provider_kind IN (${sqlList(MODEL_PROVIDER_KINDS)})),
783
875
  kind TEXT NOT NULL CHECK (kind = 'model'),
784
- adapter TEXT NOT NULL CHECK (adapter IN ('openai_compatible', 'anthropic')),
876
+ adapter TEXT NOT NULL CHECK (adapter IN (${sqlList(MODEL_PROVIDER_ADAPTERS)})),
785
877
  display_name TEXT NOT NULL,
786
878
  base_url TEXT NOT NULL,
787
- auth_mode TEXT NOT NULL CHECK (auth_mode IN ('bearer', 'x_api_key', 'none')),
879
+ auth_mode TEXT NOT NULL CHECK (auth_mode IN (${sqlList(PROVIDER_AUTH_MODES)})),
788
880
  model TEXT NOT NULL,
789
881
  capabilities TEXT NOT NULL,
790
882
  enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)),
@@ -792,6 +884,21 @@ CREATE TABLE IF NOT EXISTS provider_profile (
792
884
  updated_at TEXT NOT NULL
793
885
  );
794
886
  `;
887
+ function normalizeTableDdl(sql) {
888
+ return sql.replace(/\bIF\s+NOT\s+EXISTS\b/giu, "").replace(/\s+/gu, " ").trim().replace(/;$/u, "").trim();
889
+ }
890
+ function assertProviderProfileSchemaIsCurrent(database, path4) {
891
+ const row = database.prepare(
892
+ "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'provider_profile'"
893
+ ).get();
894
+ const stored = row?.sql;
895
+ if (typeof stored !== "string") return;
896
+ if (normalizeTableDdl(stored) === normalizeTableDdl(SCHEMA)) return;
897
+ throw new ByokKeysError(
898
+ "PROVIDER_STORE_SCHEMA_STALE",
899
+ `Provider profile store at ${path4} was created by a different @byok-sdk/keys schema; recreate the store file to continue`
900
+ );
901
+ }
795
902
  var ENABLED_INDEX = `
796
903
  CREATE UNIQUE INDEX IF NOT EXISTS provider_profile_one_enabled
797
904
  ON provider_profile(kind)
@@ -808,6 +915,7 @@ var SqliteProviderProfileStore = class {
808
915
  try {
809
916
  this.#database.exec(SCHEMA);
810
917
  this.#database.exec(ENABLED_INDEX);
918
+ assertProviderProfileSchemaIsCurrent(this.#database, options.path);
811
919
  secureSqliteFilePermissions(options.path);
812
920
  } catch (error) {
813
921
  closeSqliteDatabaseAfterInitializationFailure(
@@ -816,6 +924,16 @@ var SqliteProviderProfileStore = class {
816
924
  "SqliteProviderProfileStore initialization failed and its native handle could not be closed"
817
925
  );
818
926
  }
927
+ } else {
928
+ try {
929
+ assertProviderProfileSchemaIsCurrent(this.#database, options.path);
930
+ } catch (error) {
931
+ closeSqliteDatabaseAfterInitializationFailure(
932
+ this.#database,
933
+ error,
934
+ "SqliteProviderProfileStore read-only schema check failed and its native handle could not be closed"
935
+ );
936
+ }
819
937
  }
820
938
  }
821
939
  /**