ai-sdk-provider-env 0.2.0 → 0.3.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/README.md CHANGED
@@ -162,6 +162,7 @@ const provider = envProvider(options)
162
162
  | `configs` | `Record<string, ConfigSetEntry>` | `undefined` | Explicit config sets (takes precedence over env vars) |
163
163
  | `defaults` | `EnvProviderDefaults` | `undefined` | Global defaults applied to all providers (can be overridden per config set) |
164
164
  | `presetAutoDetect` | `boolean` | `true` | Auto-apply a built-in preset when the config set name matches. Set to `false` to require explicit `_PRESET` configuration. |
165
+ | `factories` | `EnvProviderFactories` | `undefined` | User-provided factory functions for [bundler-safe usage](#bundler-usage). |
165
166
 
166
167
  **`EnvProviderDefaults`:**
167
168
 
@@ -298,3 +299,26 @@ const registry = createProviderRegistry({
298
299
  openai: createOpenAI({ apiKey: process.env.OPENAI_API_KEY }),
299
300
  })
300
301
  ```
302
+
303
+ ## Bundler Usage
304
+
305
+ Works out of the box without a bundler. If you bundle your app, two options:
306
+
307
+ **Option A** — mark packages as external (server-side with `node_modules`):
308
+
309
+ ```bash
310
+ bun build --packages=external
311
+ ```
312
+
313
+ **Option B** — provide explicit factories (single-file / `bun build --compile`):
314
+
315
+ ```ts
316
+ import { createOpenAI } from '@ai-sdk/openai'
317
+ import { envProvider } from 'ai-sdk-provider-env'
318
+
319
+ const provider = envProvider({
320
+ factories: { openai: createOpenAI },
321
+ })
322
+ ```
323
+
324
+ For the full guide (factory key mapping, lazy-strict behavior, combining with other options), see **[Bundler Usage Guide](./docs/bundler.md)**.
package/dist/index.cjs CHANGED
@@ -348,6 +348,24 @@ function createEnvProvider(factories, options = {}) {
348
348
  };
349
349
  }
350
350
  /**
351
+ * Build internal `ProviderFactories` from user-provided `EnvProviderFactories`.
352
+ *
353
+ * Uses lazy-strict semantics: each factory slot is only evaluated when actually called.
354
+ * If the user provided a factory for a given compatible mode, it is used;
355
+ * otherwise, a clear error is thrown (no silent fallback to dynamic `require()`).
356
+ */
357
+ function buildUserFactories(userFactories) {
358
+ function missingFactory(key, fnName, pkg) {
359
+ throw new Error(`[ai-sdk-provider-env] No factory provided for "${key}". When using the factories option, provide a factory for each compatibility mode you use. Add: import { ${fnName} } from '${pkg}' and set factories: { ${key}: ${fnName} }`);
360
+ }
361
+ return {
362
+ createOpenAI: (opts) => userFactories.openai ? userFactories.openai(opts) : missingFactory("openai", "createOpenAI", "@ai-sdk/openai"),
363
+ createAnthropic: (opts) => userFactories.anthropic ? userFactories.anthropic(opts) : missingFactory("anthropic", "createAnthropic", "@ai-sdk/anthropic"),
364
+ createGemini: (opts) => userFactories.gemini ? userFactories.gemini(opts) : missingFactory("gemini", "createGoogleGenerativeAI", "@ai-sdk/google"),
365
+ createOpenAICompatible: (opts) => userFactories.openaiCompatible ? userFactories.openaiCompatible(opts) : missingFactory("openaiCompatible", "createOpenAICompatible", "@ai-sdk/openai-compatible")
366
+ };
367
+ }
368
+ /**
351
369
  * Create a dynamic, environment-variable-driven AI SDK provider.
352
370
  *
353
371
  * Automatically resolves provider configurations from env var naming conventions,
@@ -379,9 +397,19 @@ function createEnvProvider(factories, options = {}) {
379
397
  * // MYAPI_API_KEY=xxx
380
398
  * const model2 = registry.languageModel('env:myapi/some-model')
381
399
  * ```
400
+ *
401
+ * @example Bundler-safe usage with explicit factories
402
+ * ```ts
403
+ * import { createOpenAI } from '@ai-sdk/openai'
404
+ * import { envProvider } from 'ai-sdk-provider-env'
405
+ *
406
+ * const provider = envProvider({
407
+ * factories: { openai: createOpenAI },
408
+ * })
409
+ * ```
382
410
  */
383
411
  function envProvider(options = {}) {
384
- return createEnvProvider(defaultFactories, options);
412
+ return createEnvProvider(options.factories ? buildUserFactories(options.factories) : defaultFactories, options);
385
413
  }
386
414
 
387
415
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["process","NoSuchModelError"],"sources":["../src/factories.ts","../src/presets.ts","../src/env-provider.ts"],"sourcesContent":["import type { ProviderV3 } from '@ai-sdk/provider'\n\nexport interface ProviderOpts {\n baseURL: string\n apiKey: string\n headers?: Record<string, string>\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create an OpenAI provider.\n *\n * Dynamically requires `@ai-sdk/openai`, so it only needs to be installed when actually used.\n */\nexport function createOpenAIProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAI } = require('@ai-sdk/openai')\n return createOpenAI(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] openai compatibility mode requires @ai-sdk/openai. '\n + 'Run: npm install @ai-sdk/openai',\n )\n }\n}\n\n/**\n * Create an Anthropic provider.\n *\n * Dynamically requires `@ai-sdk/anthropic`, so it only needs to be installed when actually used.\n */\nexport function createAnthropicProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createAnthropic } = require('@ai-sdk/anthropic')\n return createAnthropic(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] anthropic compatibility mode requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n}\n\n/**\n * Create a Google Generative AI (Gemini) provider.\n *\n * Dynamically requires `@ai-sdk/google`, so it only needs to be installed when actually used.\n */\nexport function createGeminiProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createGoogleGenerativeAI } = require('@ai-sdk/google')\n return createGoogleGenerativeAI(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] gemini compatibility mode requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n}\n\n/**\n * Create an OpenAI Compatible provider.\n *\n * Dynamically requires `@ai-sdk/openai-compatible`, so it only needs to be installed when actually used.\n */\nexport function createOpenAICompatibleProvider(opts: ProviderOpts & { name: string }): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAICompatible } = require('@ai-sdk/openai-compatible')\n return createOpenAICompatible(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] openai-compatible mode requires @ai-sdk/openai-compatible. '\n + 'Run: npm install @ai-sdk/openai-compatible',\n )\n }\n}\n","import type { PresetConfig } from './types'\n\n/**\n * Built-in preset configurations for common providers.\n *\n * When using a preset, only `{PREFIX}__PRESET` and `{PREFIX}__API_KEY`\n * are required; `BASE_URL` and `COMPATIBLE` are provided by the preset.\n */\nexport const builtinPresets: Record<string, PresetConfig> = {\n // OpenAI\n openai: {\n baseURL: 'https://api.openai.com/v1',\n compatible: 'openai',\n },\n\n // Anthropic\n anthropic: {\n baseURL: 'https://api.anthropic.com',\n compatible: 'anthropic',\n },\n\n // Google AI Studio (Gemini)\n google: {\n baseURL: 'https://generativelanguage.googleapis.com/v1beta',\n compatible: 'gemini',\n },\n\n // DeepSeek\n deepseek: {\n baseURL: 'https://api.deepseek.com',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI (GLM series)\n zhipu: {\n baseURL: 'https://open.bigmodel.cn/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // Groq\n groq: {\n baseURL: 'https://api.groq.com/openai/v1',\n compatible: 'openai-compatible',\n },\n\n // Together AI\n together: {\n baseURL: 'https://api.together.xyz/v1',\n compatible: 'openai-compatible',\n },\n\n // Fireworks AI\n fireworks: {\n baseURL: 'https://api.fireworks.ai/inference/v1',\n compatible: 'openai-compatible',\n },\n\n // Mistral AI\n mistral: {\n baseURL: 'https://api.mistral.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI\n moonshot: {\n baseURL: 'https://api.moonshot.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // Perplexity\n perplexity: {\n baseURL: 'https://api.perplexity.ai',\n compatible: 'openai-compatible',\n },\n\n // OpenRouter\n openrouter: {\n baseURL: 'https://openrouter.ai/api/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow\n siliconflow: {\n baseURL: 'https://api.siliconflow.cn/v1',\n compatible: 'openai-compatible',\n },\n}\n","import type { ProviderV3 } from '@ai-sdk/provider'\nimport type { ProviderOpts } from './factories'\nimport type { EnvProviderOptions } from './types'\nimport process from 'node:process'\nimport { NoSuchModelError } from '@ai-sdk/provider'\nimport { createAnthropicProvider, createGeminiProvider, createOpenAICompatibleProvider, createOpenAIProvider } from './factories'\nimport { builtinPresets } from './presets'\n\n/**\n * Interface for provider factory functions, used for dependency injection.\n *\n * In production, `defaultFactories` delegates to the real SDK implementations.\n * In tests, fake factories can be injected to avoid module mocking.\n */\nexport interface ProviderFactories {\n createOpenAI: (opts: ProviderOpts) => ProviderV3\n createAnthropic: (opts: ProviderOpts) => ProviderV3\n createGemini: (opts: ProviderOpts) => ProviderV3\n createOpenAICompatible: (opts: ProviderOpts & { name: string }) => ProviderV3\n}\n\n/**\n * Default factories that delegate to the real implementations in `factories.ts`.\n */\nconst defaultFactories: ProviderFactories = {\n createOpenAI: createOpenAIProvider,\n createAnthropic: createAnthropicProvider,\n createGemini: createGeminiProvider,\n createOpenAICompatible: createOpenAICompatibleProvider,\n}\n\n/**\n * Internally resolved configuration with all required fields determined.\n */\ninterface ResolvedConfig {\n baseURL: string\n apiKey: string\n compatible: string\n headers?: Record<string, string>\n}\n\n/**\n * Testable core implementation that accepts injected provider factories.\n *\n * In tests, call this function directly with fake factories\n * to avoid module mocking entirely.\n */\nexport function createEnvProvider(\n factories: ProviderFactories,\n options: EnvProviderOptions = {},\n): ProviderV3 {\n const separator = options.separator ?? '_'\n const defaultFetch = options.defaults?.fetch\n const defaultHeaders = options.defaults?.headers\n\n // Cache created providers to avoid redundant initialization\n const cache = new Map<string, ProviderV3>()\n\n /**\n * Resolve baseURL and compatible from a preset name.\n */\n function resolvePreset(presetName: string): { baseURL: string, compatible: string } {\n const preset = builtinPresets[presetName]\n if (!preset) {\n const available = Object.keys(builtinPresets).join(', ')\n throw new Error(\n `[ai-sdk-provider-env] Unknown preset \"${presetName}\". Available presets: ${available}`,\n )\n }\n return {\n baseURL: preset.baseURL,\n compatible: preset.compatible ?? 'openai-compatible',\n }\n }\n\n /**\n * Resolve config set configuration from explicit configs, presets, or environment variables.\n */\n function resolveConfig(configSet: string): ResolvedConfig {\n // Explicit configs take precedence over env vars\n if (options.configs?.[configSet]) {\n const config = options.configs[configSet]\n\n // Code-based configs also support presets\n if (config.preset) {\n const preset = resolvePreset(config.preset)\n return {\n baseURL: config.baseURL ?? preset.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? preset.compatible,\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n if (!config.baseURL) {\n throw new Error(\n `[ai-sdk-provider-env] Missing baseURL in config for \"${configSet}\"`\n + ` (or set preset to use a built-in preset)`,\n )\n }\n\n return {\n baseURL: config.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? 'openai-compatible',\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n const prefix = configSet.toUpperCase()\n const env = (key: string): string | undefined => process.env[`${prefix}${separator}${key}`]\n\n const apiKey = env('API_KEY')\n if (!apiKey) {\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}API_KEY`,\n )\n }\n\n // Parse headers from env var (JSON format)\n const headersRaw = env('HEADERS')\n let headers: Record<string, string> | undefined\n if (headersRaw) {\n try {\n headers = JSON.parse(headersRaw)\n }\n catch {\n throw new Error(\n `[ai-sdk-provider-env] Invalid JSON in ${prefix}${separator}HEADERS: ${headersRaw}`,\n )\n }\n }\n\n // Check for preset\n const presetName = env('PRESET')\n if (presetName) {\n const preset = resolvePreset(presetName)\n return {\n baseURL: env('BASE_URL') ?? preset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? preset.compatible,\n ...(headers && { headers }),\n }\n }\n\n // Without a preset, try BASE_URL first\n const baseURL = env('BASE_URL')\n if (baseURL) {\n return {\n baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? 'openai-compatible',\n ...(headers && { headers }),\n }\n }\n\n // Auto-detect: if configSet name matches a built-in preset, use it automatically\n if (options.presetAutoDetect !== false) {\n const autoPreset = builtinPresets[configSet.toLowerCase()]\n if (autoPreset) {\n return {\n baseURL: autoPreset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? autoPreset.compatible ?? 'openai-compatible',\n ...(headers && { headers }),\n }\n }\n }\n\n // Error: neither BASE_URL nor a matching preset found\n const available = Object.keys(builtinPresets).join(', ')\n const presetHint = builtinPresets[configSet.toLowerCase()]\n ? ` (Note: \"${configSet}\" matches a built-in preset, but presetAutoDetect is disabled.)`\n : ''\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}BASE_URL`\n + ` (or set ${prefix}${separator}PRESET to use a preset.`\n + ` Available presets: ${available})${presetHint}`,\n )\n }\n\n /**\n * Create the underlying provider based on the compatibility mode.\n */\n function createUnderlying(configSet: string, config: ResolvedConfig): ProviderV3 {\n const { baseURL, apiKey, compatible, headers } = config\n\n // Merge headers: defaults.headers as base, config-set headers override matching keys\n const mergedHeaders = (defaultHeaders || headers)\n ? { ...defaultHeaders, ...headers }\n : undefined\n\n const baseOpts = {\n baseURL,\n apiKey,\n ...(mergedHeaders && { headers: mergedHeaders }),\n ...(defaultFetch && { fetch: defaultFetch }),\n }\n\n switch (compatible) {\n case 'openai':\n return factories.createOpenAI(baseOpts)\n case 'anthropic':\n return factories.createAnthropic(baseOpts)\n case 'gemini':\n return factories.createGemini(baseOpts)\n case 'openai-compatible':\n return factories.createOpenAICompatible({ name: configSet, ...baseOpts })\n default:\n throw new Error(\n `[ai-sdk-provider-env] Unknown compatible mode \"${compatible}\".`\n + ` Supported values: \"openai\", \"anthropic\", \"gemini\", \"openai-compatible\".`\n + ` Set COMPATIBLE=openai-compatible (or omit it) to use the OpenAI-compatible provider.`,\n )\n }\n }\n\n /**\n * Get or create a cached provider for the given config set.\n */\n function getProvider(configSet: string): ProviderV3 {\n const key = configSet.toUpperCase()\n const cached = cache.get(key)\n if (cached)\n return cached\n\n const config = resolveConfig(configSet)\n const provider = createUnderlying(configSet, config)\n cache.set(key, provider)\n return provider\n }\n\n /**\n * Parse a model ID. The first `/` separates the config set name from the actual model ID.\n */\n function parseModelId(modelId: string): { configSet: string, model: string } {\n const slashIndex = modelId.indexOf('/')\n if (slashIndex === -1) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid model ID \"${modelId}\". `\n + `Expected format: \"{configSet}/{modelId}\", e.g. \"zhipu/glm-4\"`,\n )\n }\n return {\n configSet: modelId.slice(0, slashIndex),\n model: modelId.slice(slashIndex + 1),\n }\n }\n\n return {\n specificationVersion: 'v3' as const,\n\n languageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).languageModel(model)\n },\n\n embeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).embeddingModel(model)\n },\n\n imageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).imageModel(model)\n },\n\n textEmbeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.textEmbeddingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' })\n }\n return provider.textEmbeddingModel(model)\n },\n\n transcriptionModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.transcriptionModel) {\n throw new NoSuchModelError({ modelId, modelType: 'transcriptionModel' })\n }\n return provider.transcriptionModel(model)\n },\n\n speechModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.speechModel) {\n throw new NoSuchModelError({ modelId, modelType: 'speechModel' })\n }\n return provider.speechModel(model)\n },\n\n rerankingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.rerankingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' })\n }\n return provider.rerankingModel(model)\n },\n }\n}\n\n/**\n * Create a dynamic, environment-variable-driven AI SDK provider.\n *\n * Automatically resolves provider configurations from env var naming conventions,\n * with built-in preset support for quick setup.\n *\n * Env var convention (using config set `ZHIPU` with default separator `_` as example):\n * - `ZHIPU_PRESET` — use a built-in preset (BASE_URL and COMPATIBLE become optional)\n * - `ZHIPU_BASE_URL` — API base URL\n * - `ZHIPU_API_KEY` — API key (required)\n * - `ZHIPU_COMPATIBLE` — compatibility mode (defaults to `'openai-compatible'`)\n * - `ZHIPU_HEADERS` — custom HTTP headers (JSON format)\n *\n * @example\n * ```ts\n * import { createProviderRegistry } from 'ai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const registry = createProviderRegistry({\n * env: envProvider(),\n * })\n *\n * // Use a preset (only API_KEY is required)\n * // DEEPSEEK_PRESET=deepseek\n * // DEEPSEEK_API_KEY=sk-xxx\n * const model = registry.languageModel('env:deepseek/deepseek-chat')\n *\n * // Specify all parameters manually\n * // MYAPI_BASE_URL=https://api.example.com/v1\n * // MYAPI_API_KEY=xxx\n * const model2 = registry.languageModel('env:myapi/some-model')\n * ```\n */\nexport function envProvider(options: EnvProviderOptions = {}): ProviderV3 {\n return createEnvProvider(defaultFactories, options)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["process","NoSuchModelError"],"sources":["../src/factories.ts","../src/presets.ts","../src/env-provider.ts"],"sourcesContent":["import type { ProviderV3 } from '@ai-sdk/provider'\n\nexport interface ProviderOpts {\n baseURL: string\n apiKey: string\n headers?: Record<string, string>\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create an OpenAI provider.\n *\n * Dynamically requires `@ai-sdk/openai`, so it only needs to be installed when actually used.\n */\nexport function createOpenAIProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAI } = require('@ai-sdk/openai')\n return createOpenAI(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] openai compatibility mode requires @ai-sdk/openai. '\n + 'Run: npm install @ai-sdk/openai',\n )\n }\n}\n\n/**\n * Create an Anthropic provider.\n *\n * Dynamically requires `@ai-sdk/anthropic`, so it only needs to be installed when actually used.\n */\nexport function createAnthropicProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createAnthropic } = require('@ai-sdk/anthropic')\n return createAnthropic(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] anthropic compatibility mode requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n}\n\n/**\n * Create a Google Generative AI (Gemini) provider.\n *\n * Dynamically requires `@ai-sdk/google`, so it only needs to be installed when actually used.\n */\nexport function createGeminiProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createGoogleGenerativeAI } = require('@ai-sdk/google')\n return createGoogleGenerativeAI(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] gemini compatibility mode requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n}\n\n/**\n * Create an OpenAI Compatible provider.\n *\n * Dynamically requires `@ai-sdk/openai-compatible`, so it only needs to be installed when actually used.\n */\nexport function createOpenAICompatibleProvider(opts: ProviderOpts & { name: string }): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAICompatible } = require('@ai-sdk/openai-compatible')\n return createOpenAICompatible(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] openai-compatible mode requires @ai-sdk/openai-compatible. '\n + 'Run: npm install @ai-sdk/openai-compatible',\n )\n }\n}\n","import type { PresetConfig } from './types'\n\n/**\n * Built-in preset configurations for common providers.\n *\n * When using a preset, only `{PREFIX}__PRESET` and `{PREFIX}__API_KEY`\n * are required; `BASE_URL` and `COMPATIBLE` are provided by the preset.\n */\nexport const builtinPresets: Record<string, PresetConfig> = {\n // OpenAI\n openai: {\n baseURL: 'https://api.openai.com/v1',\n compatible: 'openai',\n },\n\n // Anthropic\n anthropic: {\n baseURL: 'https://api.anthropic.com',\n compatible: 'anthropic',\n },\n\n // Google AI Studio (Gemini)\n google: {\n baseURL: 'https://generativelanguage.googleapis.com/v1beta',\n compatible: 'gemini',\n },\n\n // DeepSeek\n deepseek: {\n baseURL: 'https://api.deepseek.com',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI (GLM series)\n zhipu: {\n baseURL: 'https://open.bigmodel.cn/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // Groq\n groq: {\n baseURL: 'https://api.groq.com/openai/v1',\n compatible: 'openai-compatible',\n },\n\n // Together AI\n together: {\n baseURL: 'https://api.together.xyz/v1',\n compatible: 'openai-compatible',\n },\n\n // Fireworks AI\n fireworks: {\n baseURL: 'https://api.fireworks.ai/inference/v1',\n compatible: 'openai-compatible',\n },\n\n // Mistral AI\n mistral: {\n baseURL: 'https://api.mistral.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI\n moonshot: {\n baseURL: 'https://api.moonshot.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // Perplexity\n perplexity: {\n baseURL: 'https://api.perplexity.ai',\n compatible: 'openai-compatible',\n },\n\n // OpenRouter\n openrouter: {\n baseURL: 'https://openrouter.ai/api/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow\n siliconflow: {\n baseURL: 'https://api.siliconflow.cn/v1',\n compatible: 'openai-compatible',\n },\n}\n","import type { ProviderV3 } from '@ai-sdk/provider'\nimport type { ProviderOpts } from './factories'\nimport type { EnvProviderFactories, EnvProviderOptions } from './types'\nimport process from 'node:process'\nimport { NoSuchModelError } from '@ai-sdk/provider'\nimport { createAnthropicProvider, createGeminiProvider, createOpenAICompatibleProvider, createOpenAIProvider } from './factories'\nimport { builtinPresets } from './presets'\n\n/**\n * Interface for provider factory functions, used for dependency injection.\n *\n * In production, `defaultFactories` delegates to the real SDK implementations.\n * In tests, fake factories can be injected to avoid module mocking.\n */\nexport interface ProviderFactories {\n createOpenAI: (opts: ProviderOpts) => ProviderV3\n createAnthropic: (opts: ProviderOpts) => ProviderV3\n createGemini: (opts: ProviderOpts) => ProviderV3\n createOpenAICompatible: (opts: ProviderOpts & { name: string }) => ProviderV3\n}\n\n/**\n * Default factories that delegate to the real implementations in `factories.ts`.\n */\nconst defaultFactories: ProviderFactories = {\n createOpenAI: createOpenAIProvider,\n createAnthropic: createAnthropicProvider,\n createGemini: createGeminiProvider,\n createOpenAICompatible: createOpenAICompatibleProvider,\n}\n\n/**\n * Internally resolved configuration with all required fields determined.\n */\ninterface ResolvedConfig {\n baseURL: string\n apiKey: string\n compatible: string\n headers?: Record<string, string>\n}\n\n/**\n * Testable core implementation that accepts injected provider factories.\n *\n * In tests, call this function directly with fake factories\n * to avoid module mocking entirely.\n */\nexport function createEnvProvider(\n factories: ProviderFactories,\n options: Omit<EnvProviderOptions, 'factories'> = {},\n): ProviderV3 {\n const separator = options.separator ?? '_'\n const defaultFetch = options.defaults?.fetch\n const defaultHeaders = options.defaults?.headers\n\n // Cache created providers to avoid redundant initialization\n const cache = new Map<string, ProviderV3>()\n\n /**\n * Resolve baseURL and compatible from a preset name.\n */\n function resolvePreset(presetName: string): { baseURL: string, compatible: string } {\n const preset = builtinPresets[presetName]\n if (!preset) {\n const available = Object.keys(builtinPresets).join(', ')\n throw new Error(\n `[ai-sdk-provider-env] Unknown preset \"${presetName}\". Available presets: ${available}`,\n )\n }\n return {\n baseURL: preset.baseURL,\n compatible: preset.compatible ?? 'openai-compatible',\n }\n }\n\n /**\n * Resolve config set configuration from explicit configs, presets, or environment variables.\n */\n function resolveConfig(configSet: string): ResolvedConfig {\n // Explicit configs take precedence over env vars\n if (options.configs?.[configSet]) {\n const config = options.configs[configSet]\n\n // Code-based configs also support presets\n if (config.preset) {\n const preset = resolvePreset(config.preset)\n return {\n baseURL: config.baseURL ?? preset.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? preset.compatible,\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n if (!config.baseURL) {\n throw new Error(\n `[ai-sdk-provider-env] Missing baseURL in config for \"${configSet}\"`\n + ` (or set preset to use a built-in preset)`,\n )\n }\n\n return {\n baseURL: config.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? 'openai-compatible',\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n const prefix = configSet.toUpperCase()\n const env = (key: string): string | undefined => process.env[`${prefix}${separator}${key}`]\n\n const apiKey = env('API_KEY')\n if (!apiKey) {\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}API_KEY`,\n )\n }\n\n // Parse headers from env var (JSON format)\n const headersRaw = env('HEADERS')\n let headers: Record<string, string> | undefined\n if (headersRaw) {\n try {\n headers = JSON.parse(headersRaw)\n }\n catch {\n throw new Error(\n `[ai-sdk-provider-env] Invalid JSON in ${prefix}${separator}HEADERS: ${headersRaw}`,\n )\n }\n }\n\n // Check for preset\n const presetName = env('PRESET')\n if (presetName) {\n const preset = resolvePreset(presetName)\n return {\n baseURL: env('BASE_URL') ?? preset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? preset.compatible,\n ...(headers && { headers }),\n }\n }\n\n // Without a preset, try BASE_URL first\n const baseURL = env('BASE_URL')\n if (baseURL) {\n return {\n baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? 'openai-compatible',\n ...(headers && { headers }),\n }\n }\n\n // Auto-detect: if configSet name matches a built-in preset, use it automatically\n if (options.presetAutoDetect !== false) {\n const autoPreset = builtinPresets[configSet.toLowerCase()]\n if (autoPreset) {\n return {\n baseURL: autoPreset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? autoPreset.compatible ?? 'openai-compatible',\n ...(headers && { headers }),\n }\n }\n }\n\n // Error: neither BASE_URL nor a matching preset found\n const available = Object.keys(builtinPresets).join(', ')\n const presetHint = builtinPresets[configSet.toLowerCase()]\n ? ` (Note: \"${configSet}\" matches a built-in preset, but presetAutoDetect is disabled.)`\n : ''\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}BASE_URL`\n + ` (or set ${prefix}${separator}PRESET to use a preset.`\n + ` Available presets: ${available})${presetHint}`,\n )\n }\n\n /**\n * Create the underlying provider based on the compatibility mode.\n */\n function createUnderlying(configSet: string, config: ResolvedConfig): ProviderV3 {\n const { baseURL, apiKey, compatible, headers } = config\n\n // Merge headers: defaults.headers as base, config-set headers override matching keys\n const mergedHeaders = (defaultHeaders || headers)\n ? { ...defaultHeaders, ...headers }\n : undefined\n\n const baseOpts = {\n baseURL,\n apiKey,\n ...(mergedHeaders && { headers: mergedHeaders }),\n ...(defaultFetch && { fetch: defaultFetch }),\n }\n\n switch (compatible) {\n case 'openai':\n return factories.createOpenAI(baseOpts)\n case 'anthropic':\n return factories.createAnthropic(baseOpts)\n case 'gemini':\n return factories.createGemini(baseOpts)\n case 'openai-compatible':\n return factories.createOpenAICompatible({ name: configSet, ...baseOpts })\n default:\n throw new Error(\n `[ai-sdk-provider-env] Unknown compatible mode \"${compatible}\".`\n + ` Supported values: \"openai\", \"anthropic\", \"gemini\", \"openai-compatible\".`\n + ` Set COMPATIBLE=openai-compatible (or omit it) to use the OpenAI-compatible provider.`,\n )\n }\n }\n\n /**\n * Get or create a cached provider for the given config set.\n */\n function getProvider(configSet: string): ProviderV3 {\n const key = configSet.toUpperCase()\n const cached = cache.get(key)\n if (cached)\n return cached\n\n const config = resolveConfig(configSet)\n const provider = createUnderlying(configSet, config)\n cache.set(key, provider)\n return provider\n }\n\n /**\n * Parse a model ID. The first `/` separates the config set name from the actual model ID.\n */\n function parseModelId(modelId: string): { configSet: string, model: string } {\n const slashIndex = modelId.indexOf('/')\n if (slashIndex === -1) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid model ID \"${modelId}\". `\n + `Expected format: \"{configSet}/{modelId}\", e.g. \"zhipu/glm-4\"`,\n )\n }\n return {\n configSet: modelId.slice(0, slashIndex),\n model: modelId.slice(slashIndex + 1),\n }\n }\n\n return {\n specificationVersion: 'v3' as const,\n\n languageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).languageModel(model)\n },\n\n embeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).embeddingModel(model)\n },\n\n imageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).imageModel(model)\n },\n\n textEmbeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.textEmbeddingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' })\n }\n return provider.textEmbeddingModel(model)\n },\n\n transcriptionModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.transcriptionModel) {\n throw new NoSuchModelError({ modelId, modelType: 'transcriptionModel' })\n }\n return provider.transcriptionModel(model)\n },\n\n speechModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.speechModel) {\n throw new NoSuchModelError({ modelId, modelType: 'speechModel' })\n }\n return provider.speechModel(model)\n },\n\n rerankingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.rerankingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' })\n }\n return provider.rerankingModel(model)\n },\n }\n}\n\n/**\n * Build internal `ProviderFactories` from user-provided `EnvProviderFactories`.\n *\n * Uses lazy-strict semantics: each factory slot is only evaluated when actually called.\n * If the user provided a factory for a given compatible mode, it is used;\n * otherwise, a clear error is thrown (no silent fallback to dynamic `require()`).\n */\nfunction buildUserFactories(userFactories: EnvProviderFactories): ProviderFactories {\n function missingFactory(key: string, fnName: string, pkg: string): never {\n throw new Error(\n `[ai-sdk-provider-env] No factory provided for \"${key}\". `\n + `When using the factories option, provide a factory for each compatibility mode you use. `\n + `Add: import { ${fnName} } from '${pkg}' and set factories: { ${key}: ${fnName} }`,\n )\n }\n\n return {\n createOpenAI: opts =>\n userFactories.openai\n ? userFactories.openai(opts)\n : missingFactory('openai', 'createOpenAI', '@ai-sdk/openai'),\n createAnthropic: opts =>\n userFactories.anthropic\n ? userFactories.anthropic(opts)\n : missingFactory('anthropic', 'createAnthropic', '@ai-sdk/anthropic'),\n createGemini: opts =>\n userFactories.gemini\n ? userFactories.gemini(opts)\n : missingFactory('gemini', 'createGoogleGenerativeAI', '@ai-sdk/google'),\n createOpenAICompatible: opts =>\n userFactories.openaiCompatible\n ? userFactories.openaiCompatible(opts)\n : missingFactory('openaiCompatible', 'createOpenAICompatible', '@ai-sdk/openai-compatible'),\n }\n}\n\n/**\n * Create a dynamic, environment-variable-driven AI SDK provider.\n *\n * Automatically resolves provider configurations from env var naming conventions,\n * with built-in preset support for quick setup.\n *\n * Env var convention (using config set `ZHIPU` with default separator `_` as example):\n * - `ZHIPU_PRESET` — use a built-in preset (BASE_URL and COMPATIBLE become optional)\n * - `ZHIPU_BASE_URL` — API base URL\n * - `ZHIPU_API_KEY` — API key (required)\n * - `ZHIPU_COMPATIBLE` — compatibility mode (defaults to `'openai-compatible'`)\n * - `ZHIPU_HEADERS` — custom HTTP headers (JSON format)\n *\n * @example\n * ```ts\n * import { createProviderRegistry } from 'ai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const registry = createProviderRegistry({\n * env: envProvider(),\n * })\n *\n * // Use a preset (only API_KEY is required)\n * // DEEPSEEK_PRESET=deepseek\n * // DEEPSEEK_API_KEY=sk-xxx\n * const model = registry.languageModel('env:deepseek/deepseek-chat')\n *\n * // Specify all parameters manually\n * // MYAPI_BASE_URL=https://api.example.com/v1\n * // MYAPI_API_KEY=xxx\n * const model2 = registry.languageModel('env:myapi/some-model')\n * ```\n *\n * @example Bundler-safe usage with explicit factories\n * ```ts\n * import { createOpenAI } from '@ai-sdk/openai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const provider = envProvider({\n * factories: { openai: createOpenAI },\n * })\n * ```\n */\nexport function envProvider(options: EnvProviderOptions = {}): ProviderV3 {\n const factories = options.factories\n ? buildUserFactories(options.factories)\n : defaultFactories\n return createEnvProvider(factories, options)\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _ai_sdk_provider0 from "@ai-sdk/provider";
1
2
  import { ProviderV3 } from "@ai-sdk/provider";
2
3
 
3
4
  //#region src/types.d.ts
@@ -83,6 +84,63 @@ interface EnvProviderDefaults {
83
84
  */
84
85
  headers?: Record<string, string>;
85
86
  }
87
+ /**
88
+ * Options passed to user-provided factory functions.
89
+ *
90
+ * This is the library's own type — it does NOT reference any optional peer dependency types,
91
+ * so your `.d.ts` output won't force consumers to install `@ai-sdk/*` packages.
92
+ */
93
+ interface EnvProviderFactoryOptions {
94
+ /** API base URL */
95
+ baseURL: string;
96
+ /** API key */
97
+ apiKey: string;
98
+ /** Custom HTTP headers */
99
+ headers?: Record<string, string>;
100
+ /** Custom fetch implementation */
101
+ fetch?: typeof globalThis.fetch;
102
+ }
103
+ /**
104
+ * Options passed to the `openai-compatible` factory function.
105
+ *
106
+ * Extends {@link EnvProviderFactoryOptions} with a `name` field
107
+ * that identifies the config set (used as the provider name).
108
+ */
109
+ interface EnvProviderNamedFactoryOptions extends EnvProviderFactoryOptions {
110
+ /** Config set name, used as the provider name */
111
+ name: string;
112
+ }
113
+ /**
114
+ * User-provided factory functions for bundler-safe provider creation.
115
+ *
116
+ * When using a bundler (e.g. `bun build --compile`), dynamic `require()` calls
117
+ * cannot resolve optional peer dependencies. Providing factories via static imports
118
+ * allows the bundler to trace and include only the providers you actually use.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * import { createOpenAI } from '@ai-sdk/openai'
123
+ * import { createAnthropic } from '@ai-sdk/anthropic'
124
+ * import { envProvider } from 'ai-sdk-provider-env'
125
+ *
126
+ * const provider = envProvider({
127
+ * factories: {
128
+ * openai: createOpenAI,
129
+ * anthropic: createAnthropic,
130
+ * },
131
+ * })
132
+ * ```
133
+ */
134
+ interface EnvProviderFactories {
135
+ /** Factory for `compatible: 'openai'` — e.g. pass `createOpenAI` from `@ai-sdk/openai` */
136
+ openai?: (options: EnvProviderFactoryOptions) => _ai_sdk_provider0.ProviderV3;
137
+ /** Factory for `compatible: 'anthropic'` — e.g. pass `createAnthropic` from `@ai-sdk/anthropic` */
138
+ anthropic?: (options: EnvProviderFactoryOptions) => _ai_sdk_provider0.ProviderV3;
139
+ /** Factory for `compatible: 'gemini'` — e.g. pass `createGoogleGenerativeAI` from `@ai-sdk/google` */
140
+ gemini?: (options: EnvProviderFactoryOptions) => _ai_sdk_provider0.ProviderV3;
141
+ /** Factory for `compatible: 'openai-compatible'` — e.g. pass `createOpenAICompatible` from `@ai-sdk/openai-compatible` */
142
+ openaiCompatible?: (options: EnvProviderNamedFactoryOptions) => _ai_sdk_provider0.ProviderV3;
143
+ }
86
144
  /**
87
145
  * Options for `envProvider()`.
88
146
  */
@@ -154,6 +212,24 @@ interface EnvProviderOptions {
154
212
  * envProvider({ presetAutoDetect: false })
155
213
  */
156
214
  presetAutoDetect?: boolean;
215
+ /**
216
+ * User-provided factory functions for bundler-safe provider creation.
217
+ *
218
+ * When set, the library uses these factories instead of dynamic `require()` calls.
219
+ * Only provide factories for the compatibility modes you actually use —
220
+ * a clear error is thrown if a missing factory is needed at runtime.
221
+ *
222
+ * @example
223
+ * ```ts
224
+ * import { createOpenAI } from '@ai-sdk/openai'
225
+ * import { envProvider } from 'ai-sdk-provider-env'
226
+ *
227
+ * const provider = envProvider({
228
+ * factories: { openai: createOpenAI },
229
+ * })
230
+ * ```
231
+ */
232
+ factories?: EnvProviderFactories;
157
233
  }
158
234
  //#endregion
159
235
  //#region src/env-provider.d.ts
@@ -189,6 +265,16 @@ interface EnvProviderOptions {
189
265
  * // MYAPI_API_KEY=xxx
190
266
  * const model2 = registry.languageModel('env:myapi/some-model')
191
267
  * ```
268
+ *
269
+ * @example Bundler-safe usage with explicit factories
270
+ * ```ts
271
+ * import { createOpenAI } from '@ai-sdk/openai'
272
+ * import { envProvider } from 'ai-sdk-provider-env'
273
+ *
274
+ * const provider = envProvider({
275
+ * factories: { openai: createOpenAI },
276
+ * })
277
+ * ```
192
278
  */
193
279
  declare function envProvider(options?: EnvProviderOptions): ProviderV3;
194
280
  //#endregion
@@ -201,5 +287,5 @@ declare function envProvider(options?: EnvProviderOptions): ProviderV3;
201
287
  */
202
288
  declare const builtinPresets: Record<string, PresetConfig>;
203
289
  //#endregion
204
- export { type ConfigSetEntry, type EnvProviderDefaults, type EnvProviderOptions, type PresetConfig, builtinPresets, envProvider };
290
+ export { type ConfigSetEntry, type EnvProviderDefaults, type EnvProviderFactories, type EnvProviderFactoryOptions, type EnvProviderNamedFactoryOptions, type EnvProviderOptions, type PresetConfig, builtinPresets, envProvider };
205
291
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/env-provider.ts","../src/presets.ts"],"mappings":";;;;;;AAMA;;;UAAiB,cAAA;EAEf;EAAA,MAAA;EAQA;;;;;EAFA,MAAA;EA0Be;EAxBf,OAAA;;;;AA2CF;;;;;EAlCE,UAAA;EA2C0B;;;;;AAqB5B;EAzDE,OAAA,GAAU,MAAA;AAAA;;;;;;UAQK,YAAA;EAmFf;EAjFA,OAAA;EAiFyB;;;;;;;;EAxEzB,UAAA;AAAA;;;;;;UAQe,mBAAA;ECuRwD;;;;;AC1UzE;;;EF4DE,KAAA,UAAe,UAAA,CAAW,KAAA;EE5D4B;;;;;;;;;;;;;EF2EtD,OAAA,GAAU,MAAA;AAAA;;;;UAMK,kBAAA;;;;;;;;;;;;;;EAcf,SAAA;;;;;;;;;;;;;;;;;;;EAoBA,OAAA,GAAU,MAAA,SAAe,cAAA;;;;;;;;;;;;;;;EAgBzB,QAAA,GAAW,mBAAA;;;;;;;;;;;;;;;;;;;EAoBX,gBAAA;AAAA;;;;;;;;;;AAtEF;;;;;;;;;;;;;;;;;;;;ACyPA;;;;;;iBAAgB,WAAA,CAAY,OAAA,GAAS,kBAAA,GAA0B,UAAA;;;;;AD5U/D;;;;cEEa,cAAA,EAAgB,MAAA,SAAe,YAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/env-provider.ts","../src/presets.ts"],"mappings":";;;;;;;;AAMA;;UAAiB,cAAA;EA0BC;EAxBhB,MAAA;EAMA;;;;;EAAA,MAAA;EAkBgB;EAhBhB,OAAA;EAwB2B;;;;AAmB7B;;;;EAlCE,UAAA;EA2Ce;;;;;;EApCf,OAAA,GAAU,MAAA;AAAA;;;;;;UAQK,YAAA;EA4Df;EA1DA,OAAA;EA0D0B;;;AAS5B;;;;;EA1DE,UAAA;AAAA;;;;;;UAQe,mBAAA;EAkF6B;;;;;;;;EAzE5C,KAAA,UAAe,UAAA,CAAW,KAAA;EAuE1B;;;;;;;;;;;;;EAxDA,OAAA,GAAU,MAAA;AAAA;;;;;;;UASK,yBAAA;EAkJiB;EAhJhC,OAAA;EAyFA;EAvFA,MAAA;EAuFyB;EArFzB,OAAA,GAAU,MAAA;EAqGC;EAnGX,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;UASX,8BAAA,SAAuC,yBAAA;ECmR7B;EDjRzB,IAAA;AAAA;;;;;;;;;AEvGF;;;;;;;;;;;;;UF+HiB,oBAAA;;EAEf,MAAA,IAAU,OAAA,EAAS,yBAAA,KAAyB,iBAAA,CAAgC,UAAA;;EAE5E,SAAA,IAAa,OAAA,EAAS,yBAAA,KAAyB,iBAAA,CAAgC,UAAA;;EAE/E,MAAA,IAAU,OAAA,EAAS,yBAAA,KAAyB,iBAAA,CAAgC,UAAA;;EAE5E,gBAAA,IAAoB,OAAA,EAAS,8BAAA,KAA8B,iBAAA,CAAgC,UAAA;AAAA;;;;UAM5E,kBAAA;;;;;;;;;;;;;;EAcf,SAAA;;;;;;;;;;;;;;;;;;;EAoBA,OAAA,GAAU,MAAA,SAAe,cAAA;;;;;;;;;;;;;;;EAgBzB,QAAA,GAAW,mBAAA;;;;;;;;;;;;;;;;;;;EAoBX,gBAAA;;;;;;;;;;;;;;;;;;EAmBA,SAAA,GAAY,oBAAA;AAAA;;;;;;;;;;;AAlJd;;;;;;;;;;;;;AAiBA;;;;;AA0BA;;;;;;;;;;;;;;;;;iBCyPgB,WAAA,CAAY,OAAA,GAAS,kBAAA,GAA0B,UAAA;;;;;;AD1X/D;;;cEEa,cAAA,EAAgB,MAAA,SAAe,YAAA"}
package/dist/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _ai_sdk_provider0 from "@ai-sdk/provider";
1
2
  import { ProviderV3 } from "@ai-sdk/provider";
2
3
 
3
4
  //#region src/types.d.ts
@@ -83,6 +84,63 @@ interface EnvProviderDefaults {
83
84
  */
84
85
  headers?: Record<string, string>;
85
86
  }
87
+ /**
88
+ * Options passed to user-provided factory functions.
89
+ *
90
+ * This is the library's own type — it does NOT reference any optional peer dependency types,
91
+ * so your `.d.ts` output won't force consumers to install `@ai-sdk/*` packages.
92
+ */
93
+ interface EnvProviderFactoryOptions {
94
+ /** API base URL */
95
+ baseURL: string;
96
+ /** API key */
97
+ apiKey: string;
98
+ /** Custom HTTP headers */
99
+ headers?: Record<string, string>;
100
+ /** Custom fetch implementation */
101
+ fetch?: typeof globalThis.fetch;
102
+ }
103
+ /**
104
+ * Options passed to the `openai-compatible` factory function.
105
+ *
106
+ * Extends {@link EnvProviderFactoryOptions} with a `name` field
107
+ * that identifies the config set (used as the provider name).
108
+ */
109
+ interface EnvProviderNamedFactoryOptions extends EnvProviderFactoryOptions {
110
+ /** Config set name, used as the provider name */
111
+ name: string;
112
+ }
113
+ /**
114
+ * User-provided factory functions for bundler-safe provider creation.
115
+ *
116
+ * When using a bundler (e.g. `bun build --compile`), dynamic `require()` calls
117
+ * cannot resolve optional peer dependencies. Providing factories via static imports
118
+ * allows the bundler to trace and include only the providers you actually use.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * import { createOpenAI } from '@ai-sdk/openai'
123
+ * import { createAnthropic } from '@ai-sdk/anthropic'
124
+ * import { envProvider } from 'ai-sdk-provider-env'
125
+ *
126
+ * const provider = envProvider({
127
+ * factories: {
128
+ * openai: createOpenAI,
129
+ * anthropic: createAnthropic,
130
+ * },
131
+ * })
132
+ * ```
133
+ */
134
+ interface EnvProviderFactories {
135
+ /** Factory for `compatible: 'openai'` — e.g. pass `createOpenAI` from `@ai-sdk/openai` */
136
+ openai?: (options: EnvProviderFactoryOptions) => _ai_sdk_provider0.ProviderV3;
137
+ /** Factory for `compatible: 'anthropic'` — e.g. pass `createAnthropic` from `@ai-sdk/anthropic` */
138
+ anthropic?: (options: EnvProviderFactoryOptions) => _ai_sdk_provider0.ProviderV3;
139
+ /** Factory for `compatible: 'gemini'` — e.g. pass `createGoogleGenerativeAI` from `@ai-sdk/google` */
140
+ gemini?: (options: EnvProviderFactoryOptions) => _ai_sdk_provider0.ProviderV3;
141
+ /** Factory for `compatible: 'openai-compatible'` — e.g. pass `createOpenAICompatible` from `@ai-sdk/openai-compatible` */
142
+ openaiCompatible?: (options: EnvProviderNamedFactoryOptions) => _ai_sdk_provider0.ProviderV3;
143
+ }
86
144
  /**
87
145
  * Options for `envProvider()`.
88
146
  */
@@ -154,6 +212,24 @@ interface EnvProviderOptions {
154
212
  * envProvider({ presetAutoDetect: false })
155
213
  */
156
214
  presetAutoDetect?: boolean;
215
+ /**
216
+ * User-provided factory functions for bundler-safe provider creation.
217
+ *
218
+ * When set, the library uses these factories instead of dynamic `require()` calls.
219
+ * Only provide factories for the compatibility modes you actually use —
220
+ * a clear error is thrown if a missing factory is needed at runtime.
221
+ *
222
+ * @example
223
+ * ```ts
224
+ * import { createOpenAI } from '@ai-sdk/openai'
225
+ * import { envProvider } from 'ai-sdk-provider-env'
226
+ *
227
+ * const provider = envProvider({
228
+ * factories: { openai: createOpenAI },
229
+ * })
230
+ * ```
231
+ */
232
+ factories?: EnvProviderFactories;
157
233
  }
158
234
  //#endregion
159
235
  //#region src/env-provider.d.ts
@@ -189,6 +265,16 @@ interface EnvProviderOptions {
189
265
  * // MYAPI_API_KEY=xxx
190
266
  * const model2 = registry.languageModel('env:myapi/some-model')
191
267
  * ```
268
+ *
269
+ * @example Bundler-safe usage with explicit factories
270
+ * ```ts
271
+ * import { createOpenAI } from '@ai-sdk/openai'
272
+ * import { envProvider } from 'ai-sdk-provider-env'
273
+ *
274
+ * const provider = envProvider({
275
+ * factories: { openai: createOpenAI },
276
+ * })
277
+ * ```
192
278
  */
193
279
  declare function envProvider(options?: EnvProviderOptions): ProviderV3;
194
280
  //#endregion
@@ -201,5 +287,5 @@ declare function envProvider(options?: EnvProviderOptions): ProviderV3;
201
287
  */
202
288
  declare const builtinPresets: Record<string, PresetConfig>;
203
289
  //#endregion
204
- export { type ConfigSetEntry, type EnvProviderDefaults, type EnvProviderOptions, type PresetConfig, builtinPresets, envProvider };
290
+ export { type ConfigSetEntry, type EnvProviderDefaults, type EnvProviderFactories, type EnvProviderFactoryOptions, type EnvProviderNamedFactoryOptions, type EnvProviderOptions, type PresetConfig, builtinPresets, envProvider };
205
291
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/env-provider.ts","../src/presets.ts"],"mappings":";;;;;;AAMA;;;UAAiB,cAAA;EAEf;EAAA,MAAA;EAQA;;;;;EAFA,MAAA;EA0Be;EAxBf,OAAA;;;;AA2CF;;;;;EAlCE,UAAA;EA2C0B;;;;;AAqB5B;EAzDE,OAAA,GAAU,MAAA;AAAA;;;;;;UAQK,YAAA;EAmFf;EAjFA,OAAA;EAiFyB;;;;;;;;EAxEzB,UAAA;AAAA;;;;;;UAQe,mBAAA;ECuRwD;;;;;AC1UzE;;;EF4DE,KAAA,UAAe,UAAA,CAAW,KAAA;EE5D4B;;;;;;;;;;;;;EF2EtD,OAAA,GAAU,MAAA;AAAA;;;;UAMK,kBAAA;;;;;;;;;;;;;;EAcf,SAAA;;;;;;;;;;;;;;;;;;;EAoBA,OAAA,GAAU,MAAA,SAAe,cAAA;;;;;;;;;;;;;;;EAgBzB,QAAA,GAAW,mBAAA;;;;;;;;;;;;;;;;;;;EAoBX,gBAAA;AAAA;;;;;;;;;;AAtEF;;;;;;;;;;;;;;;;;;;;ACyPA;;;;;;iBAAgB,WAAA,CAAY,OAAA,GAAS,kBAAA,GAA0B,UAAA;;;;;AD5U/D;;;;cEEa,cAAA,EAAgB,MAAA,SAAe,YAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/env-provider.ts","../src/presets.ts"],"mappings":";;;;;;;;AAMA;;UAAiB,cAAA;EA0BC;EAxBhB,MAAA;EAMA;;;;;EAAA,MAAA;EAkBgB;EAhBhB,OAAA;EAwB2B;;;;AAmB7B;;;;EAlCE,UAAA;EA2Ce;;;;;;EApCf,OAAA,GAAU,MAAA;AAAA;;;;;;UAQK,YAAA;EA4Df;EA1DA,OAAA;EA0D0B;;;AAS5B;;;;;EA1DE,UAAA;AAAA;;;;;;UAQe,mBAAA;EAkF6B;;;;;;;;EAzE5C,KAAA,UAAe,UAAA,CAAW,KAAA;EAuE1B;;;;;;;;;;;;;EAxDA,OAAA,GAAU,MAAA;AAAA;;;;;;;UASK,yBAAA;EAkJiB;EAhJhC,OAAA;EAyFA;EAvFA,MAAA;EAuFyB;EArFzB,OAAA,GAAU,MAAA;EAqGC;EAnGX,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;UASX,8BAAA,SAAuC,yBAAA;ECmR7B;EDjRzB,IAAA;AAAA;;;;;;;;;AEvGF;;;;;;;;;;;;;UF+HiB,oBAAA;;EAEf,MAAA,IAAU,OAAA,EAAS,yBAAA,KAAyB,iBAAA,CAAgC,UAAA;;EAE5E,SAAA,IAAa,OAAA,EAAS,yBAAA,KAAyB,iBAAA,CAAgC,UAAA;;EAE/E,MAAA,IAAU,OAAA,EAAS,yBAAA,KAAyB,iBAAA,CAAgC,UAAA;;EAE5E,gBAAA,IAAoB,OAAA,EAAS,8BAAA,KAA8B,iBAAA,CAAgC,UAAA;AAAA;;;;UAM5E,kBAAA;;;;;;;;;;;;;;EAcf,SAAA;;;;;;;;;;;;;;;;;;;EAoBA,OAAA,GAAU,MAAA,SAAe,cAAA;;;;;;;;;;;;;;;EAgBzB,QAAA,GAAW,mBAAA;;;;;;;;;;;;;;;;;;;EAoBX,gBAAA;;;;;;;;;;;;;;;;;;EAmBA,SAAA,GAAY,oBAAA;AAAA;;;;;;;;;;;AAlJd;;;;;;;;;;;;;AAiBA;;;;;AA0BA;;;;;;;;;;;;;;;;;iBCyPgB,WAAA,CAAY,OAAA,GAAS,kBAAA,GAA0B,UAAA;;;;;;AD1X/D;;;cEEa,cAAA,EAAgB,MAAA,SAAe,YAAA"}
package/dist/index.mjs CHANGED
@@ -324,6 +324,24 @@ function createEnvProvider(factories, options = {}) {
324
324
  };
325
325
  }
326
326
  /**
327
+ * Build internal `ProviderFactories` from user-provided `EnvProviderFactories`.
328
+ *
329
+ * Uses lazy-strict semantics: each factory slot is only evaluated when actually called.
330
+ * If the user provided a factory for a given compatible mode, it is used;
331
+ * otherwise, a clear error is thrown (no silent fallback to dynamic `require()`).
332
+ */
333
+ function buildUserFactories(userFactories) {
334
+ function missingFactory(key, fnName, pkg) {
335
+ throw new Error(`[ai-sdk-provider-env] No factory provided for "${key}". When using the factories option, provide a factory for each compatibility mode you use. Add: import { ${fnName} } from '${pkg}' and set factories: { ${key}: ${fnName} }`);
336
+ }
337
+ return {
338
+ createOpenAI: (opts) => userFactories.openai ? userFactories.openai(opts) : missingFactory("openai", "createOpenAI", "@ai-sdk/openai"),
339
+ createAnthropic: (opts) => userFactories.anthropic ? userFactories.anthropic(opts) : missingFactory("anthropic", "createAnthropic", "@ai-sdk/anthropic"),
340
+ createGemini: (opts) => userFactories.gemini ? userFactories.gemini(opts) : missingFactory("gemini", "createGoogleGenerativeAI", "@ai-sdk/google"),
341
+ createOpenAICompatible: (opts) => userFactories.openaiCompatible ? userFactories.openaiCompatible(opts) : missingFactory("openaiCompatible", "createOpenAICompatible", "@ai-sdk/openai-compatible")
342
+ };
343
+ }
344
+ /**
327
345
  * Create a dynamic, environment-variable-driven AI SDK provider.
328
346
  *
329
347
  * Automatically resolves provider configurations from env var naming conventions,
@@ -355,9 +373,19 @@ function createEnvProvider(factories, options = {}) {
355
373
  * // MYAPI_API_KEY=xxx
356
374
  * const model2 = registry.languageModel('env:myapi/some-model')
357
375
  * ```
376
+ *
377
+ * @example Bundler-safe usage with explicit factories
378
+ * ```ts
379
+ * import { createOpenAI } from '@ai-sdk/openai'
380
+ * import { envProvider } from 'ai-sdk-provider-env'
381
+ *
382
+ * const provider = envProvider({
383
+ * factories: { openai: createOpenAI },
384
+ * })
385
+ * ```
358
386
  */
359
387
  function envProvider(options = {}) {
360
- return createEnvProvider(defaultFactories, options);
388
+ return createEnvProvider(options.factories ? buildUserFactories(options.factories) : defaultFactories, options);
361
389
  }
362
390
 
363
391
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/factories.ts","../src/presets.ts","../src/env-provider.ts"],"sourcesContent":["import type { ProviderV3 } from '@ai-sdk/provider'\n\nexport interface ProviderOpts {\n baseURL: string\n apiKey: string\n headers?: Record<string, string>\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create an OpenAI provider.\n *\n * Dynamically requires `@ai-sdk/openai`, so it only needs to be installed when actually used.\n */\nexport function createOpenAIProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAI } = require('@ai-sdk/openai')\n return createOpenAI(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] openai compatibility mode requires @ai-sdk/openai. '\n + 'Run: npm install @ai-sdk/openai',\n )\n }\n}\n\n/**\n * Create an Anthropic provider.\n *\n * Dynamically requires `@ai-sdk/anthropic`, so it only needs to be installed when actually used.\n */\nexport function createAnthropicProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createAnthropic } = require('@ai-sdk/anthropic')\n return createAnthropic(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] anthropic compatibility mode requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n}\n\n/**\n * Create a Google Generative AI (Gemini) provider.\n *\n * Dynamically requires `@ai-sdk/google`, so it only needs to be installed when actually used.\n */\nexport function createGeminiProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createGoogleGenerativeAI } = require('@ai-sdk/google')\n return createGoogleGenerativeAI(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] gemini compatibility mode requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n}\n\n/**\n * Create an OpenAI Compatible provider.\n *\n * Dynamically requires `@ai-sdk/openai-compatible`, so it only needs to be installed when actually used.\n */\nexport function createOpenAICompatibleProvider(opts: ProviderOpts & { name: string }): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAICompatible } = require('@ai-sdk/openai-compatible')\n return createOpenAICompatible(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] openai-compatible mode requires @ai-sdk/openai-compatible. '\n + 'Run: npm install @ai-sdk/openai-compatible',\n )\n }\n}\n","import type { PresetConfig } from './types'\n\n/**\n * Built-in preset configurations for common providers.\n *\n * When using a preset, only `{PREFIX}__PRESET` and `{PREFIX}__API_KEY`\n * are required; `BASE_URL` and `COMPATIBLE` are provided by the preset.\n */\nexport const builtinPresets: Record<string, PresetConfig> = {\n // OpenAI\n openai: {\n baseURL: 'https://api.openai.com/v1',\n compatible: 'openai',\n },\n\n // Anthropic\n anthropic: {\n baseURL: 'https://api.anthropic.com',\n compatible: 'anthropic',\n },\n\n // Google AI Studio (Gemini)\n google: {\n baseURL: 'https://generativelanguage.googleapis.com/v1beta',\n compatible: 'gemini',\n },\n\n // DeepSeek\n deepseek: {\n baseURL: 'https://api.deepseek.com',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI (GLM series)\n zhipu: {\n baseURL: 'https://open.bigmodel.cn/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // Groq\n groq: {\n baseURL: 'https://api.groq.com/openai/v1',\n compatible: 'openai-compatible',\n },\n\n // Together AI\n together: {\n baseURL: 'https://api.together.xyz/v1',\n compatible: 'openai-compatible',\n },\n\n // Fireworks AI\n fireworks: {\n baseURL: 'https://api.fireworks.ai/inference/v1',\n compatible: 'openai-compatible',\n },\n\n // Mistral AI\n mistral: {\n baseURL: 'https://api.mistral.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI\n moonshot: {\n baseURL: 'https://api.moonshot.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // Perplexity\n perplexity: {\n baseURL: 'https://api.perplexity.ai',\n compatible: 'openai-compatible',\n },\n\n // OpenRouter\n openrouter: {\n baseURL: 'https://openrouter.ai/api/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow\n siliconflow: {\n baseURL: 'https://api.siliconflow.cn/v1',\n compatible: 'openai-compatible',\n },\n}\n","import type { ProviderV3 } from '@ai-sdk/provider'\nimport type { ProviderOpts } from './factories'\nimport type { EnvProviderOptions } from './types'\nimport process from 'node:process'\nimport { NoSuchModelError } from '@ai-sdk/provider'\nimport { createAnthropicProvider, createGeminiProvider, createOpenAICompatibleProvider, createOpenAIProvider } from './factories'\nimport { builtinPresets } from './presets'\n\n/**\n * Interface for provider factory functions, used for dependency injection.\n *\n * In production, `defaultFactories` delegates to the real SDK implementations.\n * In tests, fake factories can be injected to avoid module mocking.\n */\nexport interface ProviderFactories {\n createOpenAI: (opts: ProviderOpts) => ProviderV3\n createAnthropic: (opts: ProviderOpts) => ProviderV3\n createGemini: (opts: ProviderOpts) => ProviderV3\n createOpenAICompatible: (opts: ProviderOpts & { name: string }) => ProviderV3\n}\n\n/**\n * Default factories that delegate to the real implementations in `factories.ts`.\n */\nconst defaultFactories: ProviderFactories = {\n createOpenAI: createOpenAIProvider,\n createAnthropic: createAnthropicProvider,\n createGemini: createGeminiProvider,\n createOpenAICompatible: createOpenAICompatibleProvider,\n}\n\n/**\n * Internally resolved configuration with all required fields determined.\n */\ninterface ResolvedConfig {\n baseURL: string\n apiKey: string\n compatible: string\n headers?: Record<string, string>\n}\n\n/**\n * Testable core implementation that accepts injected provider factories.\n *\n * In tests, call this function directly with fake factories\n * to avoid module mocking entirely.\n */\nexport function createEnvProvider(\n factories: ProviderFactories,\n options: EnvProviderOptions = {},\n): ProviderV3 {\n const separator = options.separator ?? '_'\n const defaultFetch = options.defaults?.fetch\n const defaultHeaders = options.defaults?.headers\n\n // Cache created providers to avoid redundant initialization\n const cache = new Map<string, ProviderV3>()\n\n /**\n * Resolve baseURL and compatible from a preset name.\n */\n function resolvePreset(presetName: string): { baseURL: string, compatible: string } {\n const preset = builtinPresets[presetName]\n if (!preset) {\n const available = Object.keys(builtinPresets).join(', ')\n throw new Error(\n `[ai-sdk-provider-env] Unknown preset \"${presetName}\". Available presets: ${available}`,\n )\n }\n return {\n baseURL: preset.baseURL,\n compatible: preset.compatible ?? 'openai-compatible',\n }\n }\n\n /**\n * Resolve config set configuration from explicit configs, presets, or environment variables.\n */\n function resolveConfig(configSet: string): ResolvedConfig {\n // Explicit configs take precedence over env vars\n if (options.configs?.[configSet]) {\n const config = options.configs[configSet]\n\n // Code-based configs also support presets\n if (config.preset) {\n const preset = resolvePreset(config.preset)\n return {\n baseURL: config.baseURL ?? preset.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? preset.compatible,\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n if (!config.baseURL) {\n throw new Error(\n `[ai-sdk-provider-env] Missing baseURL in config for \"${configSet}\"`\n + ` (or set preset to use a built-in preset)`,\n )\n }\n\n return {\n baseURL: config.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? 'openai-compatible',\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n const prefix = configSet.toUpperCase()\n const env = (key: string): string | undefined => process.env[`${prefix}${separator}${key}`]\n\n const apiKey = env('API_KEY')\n if (!apiKey) {\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}API_KEY`,\n )\n }\n\n // Parse headers from env var (JSON format)\n const headersRaw = env('HEADERS')\n let headers: Record<string, string> | undefined\n if (headersRaw) {\n try {\n headers = JSON.parse(headersRaw)\n }\n catch {\n throw new Error(\n `[ai-sdk-provider-env] Invalid JSON in ${prefix}${separator}HEADERS: ${headersRaw}`,\n )\n }\n }\n\n // Check for preset\n const presetName = env('PRESET')\n if (presetName) {\n const preset = resolvePreset(presetName)\n return {\n baseURL: env('BASE_URL') ?? preset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? preset.compatible,\n ...(headers && { headers }),\n }\n }\n\n // Without a preset, try BASE_URL first\n const baseURL = env('BASE_URL')\n if (baseURL) {\n return {\n baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? 'openai-compatible',\n ...(headers && { headers }),\n }\n }\n\n // Auto-detect: if configSet name matches a built-in preset, use it automatically\n if (options.presetAutoDetect !== false) {\n const autoPreset = builtinPresets[configSet.toLowerCase()]\n if (autoPreset) {\n return {\n baseURL: autoPreset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? autoPreset.compatible ?? 'openai-compatible',\n ...(headers && { headers }),\n }\n }\n }\n\n // Error: neither BASE_URL nor a matching preset found\n const available = Object.keys(builtinPresets).join(', ')\n const presetHint = builtinPresets[configSet.toLowerCase()]\n ? ` (Note: \"${configSet}\" matches a built-in preset, but presetAutoDetect is disabled.)`\n : ''\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}BASE_URL`\n + ` (or set ${prefix}${separator}PRESET to use a preset.`\n + ` Available presets: ${available})${presetHint}`,\n )\n }\n\n /**\n * Create the underlying provider based on the compatibility mode.\n */\n function createUnderlying(configSet: string, config: ResolvedConfig): ProviderV3 {\n const { baseURL, apiKey, compatible, headers } = config\n\n // Merge headers: defaults.headers as base, config-set headers override matching keys\n const mergedHeaders = (defaultHeaders || headers)\n ? { ...defaultHeaders, ...headers }\n : undefined\n\n const baseOpts = {\n baseURL,\n apiKey,\n ...(mergedHeaders && { headers: mergedHeaders }),\n ...(defaultFetch && { fetch: defaultFetch }),\n }\n\n switch (compatible) {\n case 'openai':\n return factories.createOpenAI(baseOpts)\n case 'anthropic':\n return factories.createAnthropic(baseOpts)\n case 'gemini':\n return factories.createGemini(baseOpts)\n case 'openai-compatible':\n return factories.createOpenAICompatible({ name: configSet, ...baseOpts })\n default:\n throw new Error(\n `[ai-sdk-provider-env] Unknown compatible mode \"${compatible}\".`\n + ` Supported values: \"openai\", \"anthropic\", \"gemini\", \"openai-compatible\".`\n + ` Set COMPATIBLE=openai-compatible (or omit it) to use the OpenAI-compatible provider.`,\n )\n }\n }\n\n /**\n * Get or create a cached provider for the given config set.\n */\n function getProvider(configSet: string): ProviderV3 {\n const key = configSet.toUpperCase()\n const cached = cache.get(key)\n if (cached)\n return cached\n\n const config = resolveConfig(configSet)\n const provider = createUnderlying(configSet, config)\n cache.set(key, provider)\n return provider\n }\n\n /**\n * Parse a model ID. The first `/` separates the config set name from the actual model ID.\n */\n function parseModelId(modelId: string): { configSet: string, model: string } {\n const slashIndex = modelId.indexOf('/')\n if (slashIndex === -1) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid model ID \"${modelId}\". `\n + `Expected format: \"{configSet}/{modelId}\", e.g. \"zhipu/glm-4\"`,\n )\n }\n return {\n configSet: modelId.slice(0, slashIndex),\n model: modelId.slice(slashIndex + 1),\n }\n }\n\n return {\n specificationVersion: 'v3' as const,\n\n languageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).languageModel(model)\n },\n\n embeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).embeddingModel(model)\n },\n\n imageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).imageModel(model)\n },\n\n textEmbeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.textEmbeddingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' })\n }\n return provider.textEmbeddingModel(model)\n },\n\n transcriptionModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.transcriptionModel) {\n throw new NoSuchModelError({ modelId, modelType: 'transcriptionModel' })\n }\n return provider.transcriptionModel(model)\n },\n\n speechModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.speechModel) {\n throw new NoSuchModelError({ modelId, modelType: 'speechModel' })\n }\n return provider.speechModel(model)\n },\n\n rerankingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.rerankingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' })\n }\n return provider.rerankingModel(model)\n },\n }\n}\n\n/**\n * Create a dynamic, environment-variable-driven AI SDK provider.\n *\n * Automatically resolves provider configurations from env var naming conventions,\n * with built-in preset support for quick setup.\n *\n * Env var convention (using config set `ZHIPU` with default separator `_` as example):\n * - `ZHIPU_PRESET` — use a built-in preset (BASE_URL and COMPATIBLE become optional)\n * - `ZHIPU_BASE_URL` — API base URL\n * - `ZHIPU_API_KEY` — API key (required)\n * - `ZHIPU_COMPATIBLE` — compatibility mode (defaults to `'openai-compatible'`)\n * - `ZHIPU_HEADERS` — custom HTTP headers (JSON format)\n *\n * @example\n * ```ts\n * import { createProviderRegistry } from 'ai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const registry = createProviderRegistry({\n * env: envProvider(),\n * })\n *\n * // Use a preset (only API_KEY is required)\n * // DEEPSEEK_PRESET=deepseek\n * // DEEPSEEK_API_KEY=sk-xxx\n * const model = registry.languageModel('env:deepseek/deepseek-chat')\n *\n * // Specify all parameters manually\n * // MYAPI_BASE_URL=https://api.example.com/v1\n * // MYAPI_API_KEY=xxx\n * const model2 = registry.languageModel('env:myapi/some-model')\n * ```\n */\nexport function envProvider(options: EnvProviderOptions = {}): ProviderV3 {\n return createEnvProvider(defaultFactories, options)\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,SAAgB,qBAAqB,MAAgC;AACnE,KAAI;EAEF,MAAM,EAAE,2BAAyB,iBAAiB;AAClD,SAAO,aAAa,KAAK;SAErB;AACJ,QAAM,IAAI,MACR,2GAED;;;;;;;;AASL,SAAgB,wBAAwB,MAAgC;AACtE,KAAI;EAEF,MAAM,EAAE,8BAA4B,oBAAoB;AACxD,SAAO,gBAAgB,KAAK;SAExB;AACJ,QAAM,IAAI,MACR,oHAED;;;;;;;;AASL,SAAgB,qBAAqB,MAAgC;AACnE,KAAI;EAEF,MAAM,EAAE,uCAAqC,iBAAiB;AAC9D,SAAO,yBAAyB,KAAK;SAEjC;AACJ,QAAM,IAAI,MACR,2GAED;;;;;;;;AASL,SAAgB,+BAA+B,MAAmD;AAChG,KAAI;EAEF,MAAM,EAAE,qCAAmC,4BAA4B;AACvE,SAAO,uBAAuB,KAAK;SAE/B;AACJ,QAAM,IAAI,MACR,8HAED;;;;;;;;;;;;ACzEL,MAAa,iBAA+C;CAE1D,QAAQ;EACN,SAAS;EACT,YAAY;EACb;CAGD,WAAW;EACT,SAAS;EACT,YAAY;EACb;CAGD,QAAQ;EACN,SAAS;EACT,YAAY;EACb;CAGD,UAAU;EACR,SAAS;EACT,YAAY;EACb;CAGD,OAAO;EACL,SAAS;EACT,YAAY;EACb;CAGD,MAAM;EACJ,SAAS;EACT,YAAY;EACb;CAGD,UAAU;EACR,SAAS;EACT,YAAY;EACb;CAGD,WAAW;EACT,SAAS;EACT,YAAY;EACb;CAGD,SAAS;EACP,SAAS;EACT,YAAY;EACb;CAGD,UAAU;EACR,SAAS;EACT,YAAY;EACb;CAGD,YAAY;EACV,SAAS;EACT,YAAY;EACb;CAGD,YAAY;EACV,SAAS;EACT,YAAY;EACb;CAGD,aAAa;EACX,SAAS;EACT,YAAY;EACb;CACF;;;;;;;AC9DD,MAAM,mBAAsC;CAC1C,cAAc;CACd,iBAAiB;CACjB,cAAc;CACd,wBAAwB;CACzB;;;;;;;AAkBD,SAAgB,kBACd,WACA,UAA8B,EAAE,EACpB;CACZ,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,eAAe,QAAQ,UAAU;CACvC,MAAM,iBAAiB,QAAQ,UAAU;CAGzC,MAAM,wBAAQ,IAAI,KAAyB;;;;CAK3C,SAAS,cAAc,YAA6D;EAClF,MAAM,SAAS,eAAe;AAC9B,MAAI,CAAC,QAAQ;GACX,MAAM,YAAY,OAAO,KAAK,eAAe,CAAC,KAAK,KAAK;AACxD,SAAM,IAAI,MACR,yCAAyC,WAAW,wBAAwB,YAC7E;;AAEH,SAAO;GACL,SAAS,OAAO;GAChB,YAAY,OAAO,cAAc;GAClC;;;;;CAMH,SAAS,cAAc,WAAmC;AAExD,MAAI,QAAQ,UAAU,YAAY;GAChC,MAAM,SAAS,QAAQ,QAAQ;AAG/B,OAAI,OAAO,QAAQ;IACjB,MAAM,SAAS,cAAc,OAAO,OAAO;AAC3C,WAAO;KACL,SAAS,OAAO,WAAW,OAAO;KAClC,QAAQ,OAAO;KACf,YAAY,OAAO,cAAc,OAAO;KACxC,GAAI,OAAO,WAAW,EAAE,SAAS,OAAO,SAAS;KAClD;;AAGH,OAAI,CAAC,OAAO,QACV,OAAM,IAAI,MACR,wDAAwD,UAAU,4CAEnE;AAGH,UAAO;IACL,SAAS,OAAO;IAChB,QAAQ,OAAO;IACf,YAAY,OAAO,cAAc;IACjC,GAAI,OAAO,WAAW,EAAE,SAAS,OAAO,SAAS;IAClD;;EAGH,MAAM,SAAS,UAAU,aAAa;EACtC,MAAM,OAAO,QAAoC,QAAQ,IAAI,GAAG,SAAS,YAAY;EAErF,MAAM,SAAS,IAAI,UAAU;AAC7B,MAAI,CAAC,OACH,OAAM,IAAI,MACR,yCAAyC,SAAS,UAAU,SAC7D;EAIH,MAAM,aAAa,IAAI,UAAU;EACjC,IAAI;AACJ,MAAI,WACF,KAAI;AACF,aAAU,KAAK,MAAM,WAAW;UAE5B;AACJ,SAAM,IAAI,MACR,yCAAyC,SAAS,UAAU,WAAW,aACxE;;EAKL,MAAM,aAAa,IAAI,SAAS;AAChC,MAAI,YAAY;GACd,MAAM,SAAS,cAAc,WAAW;AACxC,UAAO;IACL,SAAS,IAAI,WAAW,IAAI,OAAO;IACnC;IACA,YAAY,IAAI,aAAa,IAAI,OAAO;IACxC,GAAI,WAAW,EAAE,SAAS;IAC3B;;EAIH,MAAM,UAAU,IAAI,WAAW;AAC/B,MAAI,QACF,QAAO;GACL;GACA;GACA,YAAY,IAAI,aAAa,IAAI;GACjC,GAAI,WAAW,EAAE,SAAS;GAC3B;AAIH,MAAI,QAAQ,qBAAqB,OAAO;GACtC,MAAM,aAAa,eAAe,UAAU,aAAa;AACzD,OAAI,WACF,QAAO;IACL,SAAS,WAAW;IACpB;IACA,YAAY,IAAI,aAAa,IAAI,WAAW,cAAc;IAC1D,GAAI,WAAW,EAAE,SAAS;IAC3B;;EAKL,MAAM,YAAY,OAAO,KAAK,eAAe,CAAC,KAAK,KAAK;EACxD,MAAM,aAAa,eAAe,UAAU,aAAa,IACrD,YAAY,UAAU,mEACtB;AACJ,QAAM,IAAI,MACR,yCAAyC,SAAS,UAAU,mBAC9C,SAAS,UAAU,6CACR,UAAU,GAAG,aACvC;;;;;CAMH,SAAS,iBAAiB,WAAmB,QAAoC;EAC/E,MAAM,EAAE,SAAS,QAAQ,YAAY,YAAY;EAGjD,MAAM,gBAAiB,kBAAkB,UACrC;GAAE,GAAG;GAAgB,GAAG;GAAS,GACjC;EAEJ,MAAM,WAAW;GACf;GACA;GACA,GAAI,iBAAiB,EAAE,SAAS,eAAe;GAC/C,GAAI,gBAAgB,EAAE,OAAO,cAAc;GAC5C;AAED,UAAQ,YAAR;GACE,KAAK,SACH,QAAO,UAAU,aAAa,SAAS;GACzC,KAAK,YACH,QAAO,UAAU,gBAAgB,SAAS;GAC5C,KAAK,SACH,QAAO,UAAU,aAAa,SAAS;GACzC,KAAK,oBACH,QAAO,UAAU,uBAAuB;IAAE,MAAM;IAAW,GAAG;IAAU,CAAC;GAC3E,QACE,OAAM,IAAI,MACR,kDAAkD,WAAW,iKAG9D;;;;;;CAOP,SAAS,YAAY,WAA+B;EAClD,MAAM,MAAM,UAAU,aAAa;EACnC,MAAM,SAAS,MAAM,IAAI,IAAI;AAC7B,MAAI,OACF,QAAO;EAGT,MAAM,WAAW,iBAAiB,WADnB,cAAc,UAAU,CACa;AACpD,QAAM,IAAI,KAAK,SAAS;AACxB,SAAO;;;;;CAMT,SAAS,aAAa,SAAuD;EAC3E,MAAM,aAAa,QAAQ,QAAQ,IAAI;AACvC,MAAI,eAAe,GACjB,OAAM,IAAI,MACR,2CAA2C,QAAQ,iEAEpD;AAEH,SAAO;GACL,WAAW,QAAQ,MAAM,GAAG,WAAW;GACvC,OAAO,QAAQ,MAAM,aAAa,EAAE;GACrC;;AAGH,QAAO;EACL,sBAAsB;EAEtB,cAAc,SAAiB;GAC7B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;AAClD,UAAO,YAAY,UAAU,CAAC,cAAc,MAAM;;EAGpD,eAAe,SAAiB;GAC9B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;AAClD,UAAO,YAAY,UAAU,CAAC,eAAe,MAAM;;EAGrD,WAAW,SAAiB;GAC1B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;AAClD,UAAO,YAAY,UAAU,CAAC,WAAW,MAAM;;EAGjD,mBAAmB,SAAiB;GAClC,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;GAClD,MAAM,WAAW,YAAY,UAAU;AACvC,OAAI,CAAC,SAAS,mBACZ,OAAM,IAAI,iBAAiB;IAAE;IAAS,WAAW;IAAkB,CAAC;AAEtE,UAAO,SAAS,mBAAmB,MAAM;;EAG3C,mBAAmB,SAAiB;GAClC,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;GAClD,MAAM,WAAW,YAAY,UAAU;AACvC,OAAI,CAAC,SAAS,mBACZ,OAAM,IAAI,iBAAiB;IAAE;IAAS,WAAW;IAAsB,CAAC;AAE1E,UAAO,SAAS,mBAAmB,MAAM;;EAG3C,YAAY,SAAiB;GAC3B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;GAClD,MAAM,WAAW,YAAY,UAAU;AACvC,OAAI,CAAC,SAAS,YACZ,OAAM,IAAI,iBAAiB;IAAE;IAAS,WAAW;IAAe,CAAC;AAEnE,UAAO,SAAS,YAAY,MAAM;;EAGpC,eAAe,SAAiB;GAC9B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;GAClD,MAAM,WAAW,YAAY,UAAU;AACvC,OAAI,CAAC,SAAS,eACZ,OAAM,IAAI,iBAAiB;IAAE;IAAS,WAAW;IAAkB,CAAC;AAEtE,UAAO,SAAS,eAAe,MAAM;;EAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCH,SAAgB,YAAY,UAA8B,EAAE,EAAc;AACxE,QAAO,kBAAkB,kBAAkB,QAAQ"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/factories.ts","../src/presets.ts","../src/env-provider.ts"],"sourcesContent":["import type { ProviderV3 } from '@ai-sdk/provider'\n\nexport interface ProviderOpts {\n baseURL: string\n apiKey: string\n headers?: Record<string, string>\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create an OpenAI provider.\n *\n * Dynamically requires `@ai-sdk/openai`, so it only needs to be installed when actually used.\n */\nexport function createOpenAIProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAI } = require('@ai-sdk/openai')\n return createOpenAI(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] openai compatibility mode requires @ai-sdk/openai. '\n + 'Run: npm install @ai-sdk/openai',\n )\n }\n}\n\n/**\n * Create an Anthropic provider.\n *\n * Dynamically requires `@ai-sdk/anthropic`, so it only needs to be installed when actually used.\n */\nexport function createAnthropicProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createAnthropic } = require('@ai-sdk/anthropic')\n return createAnthropic(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] anthropic compatibility mode requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n}\n\n/**\n * Create a Google Generative AI (Gemini) provider.\n *\n * Dynamically requires `@ai-sdk/google`, so it only needs to be installed when actually used.\n */\nexport function createGeminiProvider(opts: ProviderOpts): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createGoogleGenerativeAI } = require('@ai-sdk/google')\n return createGoogleGenerativeAI(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] gemini compatibility mode requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n}\n\n/**\n * Create an OpenAI Compatible provider.\n *\n * Dynamically requires `@ai-sdk/openai-compatible`, so it only needs to be installed when actually used.\n */\nexport function createOpenAICompatibleProvider(opts: ProviderOpts & { name: string }): ProviderV3 {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAICompatible } = require('@ai-sdk/openai-compatible')\n return createOpenAICompatible(opts)\n }\n catch {\n throw new Error(\n '[ai-sdk-provider-env] openai-compatible mode requires @ai-sdk/openai-compatible. '\n + 'Run: npm install @ai-sdk/openai-compatible',\n )\n }\n}\n","import type { PresetConfig } from './types'\n\n/**\n * Built-in preset configurations for common providers.\n *\n * When using a preset, only `{PREFIX}__PRESET` and `{PREFIX}__API_KEY`\n * are required; `BASE_URL` and `COMPATIBLE` are provided by the preset.\n */\nexport const builtinPresets: Record<string, PresetConfig> = {\n // OpenAI\n openai: {\n baseURL: 'https://api.openai.com/v1',\n compatible: 'openai',\n },\n\n // Anthropic\n anthropic: {\n baseURL: 'https://api.anthropic.com',\n compatible: 'anthropic',\n },\n\n // Google AI Studio (Gemini)\n google: {\n baseURL: 'https://generativelanguage.googleapis.com/v1beta',\n compatible: 'gemini',\n },\n\n // DeepSeek\n deepseek: {\n baseURL: 'https://api.deepseek.com',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI (GLM series)\n zhipu: {\n baseURL: 'https://open.bigmodel.cn/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // Groq\n groq: {\n baseURL: 'https://api.groq.com/openai/v1',\n compatible: 'openai-compatible',\n },\n\n // Together AI\n together: {\n baseURL: 'https://api.together.xyz/v1',\n compatible: 'openai-compatible',\n },\n\n // Fireworks AI\n fireworks: {\n baseURL: 'https://api.fireworks.ai/inference/v1',\n compatible: 'openai-compatible',\n },\n\n // Mistral AI\n mistral: {\n baseURL: 'https://api.mistral.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI\n moonshot: {\n baseURL: 'https://api.moonshot.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // Perplexity\n perplexity: {\n baseURL: 'https://api.perplexity.ai',\n compatible: 'openai-compatible',\n },\n\n // OpenRouter\n openrouter: {\n baseURL: 'https://openrouter.ai/api/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow\n siliconflow: {\n baseURL: 'https://api.siliconflow.cn/v1',\n compatible: 'openai-compatible',\n },\n}\n","import type { ProviderV3 } from '@ai-sdk/provider'\nimport type { ProviderOpts } from './factories'\nimport type { EnvProviderFactories, EnvProviderOptions } from './types'\nimport process from 'node:process'\nimport { NoSuchModelError } from '@ai-sdk/provider'\nimport { createAnthropicProvider, createGeminiProvider, createOpenAICompatibleProvider, createOpenAIProvider } from './factories'\nimport { builtinPresets } from './presets'\n\n/**\n * Interface for provider factory functions, used for dependency injection.\n *\n * In production, `defaultFactories` delegates to the real SDK implementations.\n * In tests, fake factories can be injected to avoid module mocking.\n */\nexport interface ProviderFactories {\n createOpenAI: (opts: ProviderOpts) => ProviderV3\n createAnthropic: (opts: ProviderOpts) => ProviderV3\n createGemini: (opts: ProviderOpts) => ProviderV3\n createOpenAICompatible: (opts: ProviderOpts & { name: string }) => ProviderV3\n}\n\n/**\n * Default factories that delegate to the real implementations in `factories.ts`.\n */\nconst defaultFactories: ProviderFactories = {\n createOpenAI: createOpenAIProvider,\n createAnthropic: createAnthropicProvider,\n createGemini: createGeminiProvider,\n createOpenAICompatible: createOpenAICompatibleProvider,\n}\n\n/**\n * Internally resolved configuration with all required fields determined.\n */\ninterface ResolvedConfig {\n baseURL: string\n apiKey: string\n compatible: string\n headers?: Record<string, string>\n}\n\n/**\n * Testable core implementation that accepts injected provider factories.\n *\n * In tests, call this function directly with fake factories\n * to avoid module mocking entirely.\n */\nexport function createEnvProvider(\n factories: ProviderFactories,\n options: Omit<EnvProviderOptions, 'factories'> = {},\n): ProviderV3 {\n const separator = options.separator ?? '_'\n const defaultFetch = options.defaults?.fetch\n const defaultHeaders = options.defaults?.headers\n\n // Cache created providers to avoid redundant initialization\n const cache = new Map<string, ProviderV3>()\n\n /**\n * Resolve baseURL and compatible from a preset name.\n */\n function resolvePreset(presetName: string): { baseURL: string, compatible: string } {\n const preset = builtinPresets[presetName]\n if (!preset) {\n const available = Object.keys(builtinPresets).join(', ')\n throw new Error(\n `[ai-sdk-provider-env] Unknown preset \"${presetName}\". Available presets: ${available}`,\n )\n }\n return {\n baseURL: preset.baseURL,\n compatible: preset.compatible ?? 'openai-compatible',\n }\n }\n\n /**\n * Resolve config set configuration from explicit configs, presets, or environment variables.\n */\n function resolveConfig(configSet: string): ResolvedConfig {\n // Explicit configs take precedence over env vars\n if (options.configs?.[configSet]) {\n const config = options.configs[configSet]\n\n // Code-based configs also support presets\n if (config.preset) {\n const preset = resolvePreset(config.preset)\n return {\n baseURL: config.baseURL ?? preset.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? preset.compatible,\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n if (!config.baseURL) {\n throw new Error(\n `[ai-sdk-provider-env] Missing baseURL in config for \"${configSet}\"`\n + ` (or set preset to use a built-in preset)`,\n )\n }\n\n return {\n baseURL: config.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? 'openai-compatible',\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n const prefix = configSet.toUpperCase()\n const env = (key: string): string | undefined => process.env[`${prefix}${separator}${key}`]\n\n const apiKey = env('API_KEY')\n if (!apiKey) {\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}API_KEY`,\n )\n }\n\n // Parse headers from env var (JSON format)\n const headersRaw = env('HEADERS')\n let headers: Record<string, string> | undefined\n if (headersRaw) {\n try {\n headers = JSON.parse(headersRaw)\n }\n catch {\n throw new Error(\n `[ai-sdk-provider-env] Invalid JSON in ${prefix}${separator}HEADERS: ${headersRaw}`,\n )\n }\n }\n\n // Check for preset\n const presetName = env('PRESET')\n if (presetName) {\n const preset = resolvePreset(presetName)\n return {\n baseURL: env('BASE_URL') ?? preset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? preset.compatible,\n ...(headers && { headers }),\n }\n }\n\n // Without a preset, try BASE_URL first\n const baseURL = env('BASE_URL')\n if (baseURL) {\n return {\n baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? 'openai-compatible',\n ...(headers && { headers }),\n }\n }\n\n // Auto-detect: if configSet name matches a built-in preset, use it automatically\n if (options.presetAutoDetect !== false) {\n const autoPreset = builtinPresets[configSet.toLowerCase()]\n if (autoPreset) {\n return {\n baseURL: autoPreset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? autoPreset.compatible ?? 'openai-compatible',\n ...(headers && { headers }),\n }\n }\n }\n\n // Error: neither BASE_URL nor a matching preset found\n const available = Object.keys(builtinPresets).join(', ')\n const presetHint = builtinPresets[configSet.toLowerCase()]\n ? ` (Note: \"${configSet}\" matches a built-in preset, but presetAutoDetect is disabled.)`\n : ''\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}BASE_URL`\n + ` (or set ${prefix}${separator}PRESET to use a preset.`\n + ` Available presets: ${available})${presetHint}`,\n )\n }\n\n /**\n * Create the underlying provider based on the compatibility mode.\n */\n function createUnderlying(configSet: string, config: ResolvedConfig): ProviderV3 {\n const { baseURL, apiKey, compatible, headers } = config\n\n // Merge headers: defaults.headers as base, config-set headers override matching keys\n const mergedHeaders = (defaultHeaders || headers)\n ? { ...defaultHeaders, ...headers }\n : undefined\n\n const baseOpts = {\n baseURL,\n apiKey,\n ...(mergedHeaders && { headers: mergedHeaders }),\n ...(defaultFetch && { fetch: defaultFetch }),\n }\n\n switch (compatible) {\n case 'openai':\n return factories.createOpenAI(baseOpts)\n case 'anthropic':\n return factories.createAnthropic(baseOpts)\n case 'gemini':\n return factories.createGemini(baseOpts)\n case 'openai-compatible':\n return factories.createOpenAICompatible({ name: configSet, ...baseOpts })\n default:\n throw new Error(\n `[ai-sdk-provider-env] Unknown compatible mode \"${compatible}\".`\n + ` Supported values: \"openai\", \"anthropic\", \"gemini\", \"openai-compatible\".`\n + ` Set COMPATIBLE=openai-compatible (or omit it) to use the OpenAI-compatible provider.`,\n )\n }\n }\n\n /**\n * Get or create a cached provider for the given config set.\n */\n function getProvider(configSet: string): ProviderV3 {\n const key = configSet.toUpperCase()\n const cached = cache.get(key)\n if (cached)\n return cached\n\n const config = resolveConfig(configSet)\n const provider = createUnderlying(configSet, config)\n cache.set(key, provider)\n return provider\n }\n\n /**\n * Parse a model ID. The first `/` separates the config set name from the actual model ID.\n */\n function parseModelId(modelId: string): { configSet: string, model: string } {\n const slashIndex = modelId.indexOf('/')\n if (slashIndex === -1) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid model ID \"${modelId}\". `\n + `Expected format: \"{configSet}/{modelId}\", e.g. \"zhipu/glm-4\"`,\n )\n }\n return {\n configSet: modelId.slice(0, slashIndex),\n model: modelId.slice(slashIndex + 1),\n }\n }\n\n return {\n specificationVersion: 'v3' as const,\n\n languageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).languageModel(model)\n },\n\n embeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).embeddingModel(model)\n },\n\n imageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).imageModel(model)\n },\n\n textEmbeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.textEmbeddingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' })\n }\n return provider.textEmbeddingModel(model)\n },\n\n transcriptionModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.transcriptionModel) {\n throw new NoSuchModelError({ modelId, modelType: 'transcriptionModel' })\n }\n return provider.transcriptionModel(model)\n },\n\n speechModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.speechModel) {\n throw new NoSuchModelError({ modelId, modelType: 'speechModel' })\n }\n return provider.speechModel(model)\n },\n\n rerankingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.rerankingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' })\n }\n return provider.rerankingModel(model)\n },\n }\n}\n\n/**\n * Build internal `ProviderFactories` from user-provided `EnvProviderFactories`.\n *\n * Uses lazy-strict semantics: each factory slot is only evaluated when actually called.\n * If the user provided a factory for a given compatible mode, it is used;\n * otherwise, a clear error is thrown (no silent fallback to dynamic `require()`).\n */\nfunction buildUserFactories(userFactories: EnvProviderFactories): ProviderFactories {\n function missingFactory(key: string, fnName: string, pkg: string): never {\n throw new Error(\n `[ai-sdk-provider-env] No factory provided for \"${key}\". `\n + `When using the factories option, provide a factory for each compatibility mode you use. `\n + `Add: import { ${fnName} } from '${pkg}' and set factories: { ${key}: ${fnName} }`,\n )\n }\n\n return {\n createOpenAI: opts =>\n userFactories.openai\n ? userFactories.openai(opts)\n : missingFactory('openai', 'createOpenAI', '@ai-sdk/openai'),\n createAnthropic: opts =>\n userFactories.anthropic\n ? userFactories.anthropic(opts)\n : missingFactory('anthropic', 'createAnthropic', '@ai-sdk/anthropic'),\n createGemini: opts =>\n userFactories.gemini\n ? userFactories.gemini(opts)\n : missingFactory('gemini', 'createGoogleGenerativeAI', '@ai-sdk/google'),\n createOpenAICompatible: opts =>\n userFactories.openaiCompatible\n ? userFactories.openaiCompatible(opts)\n : missingFactory('openaiCompatible', 'createOpenAICompatible', '@ai-sdk/openai-compatible'),\n }\n}\n\n/**\n * Create a dynamic, environment-variable-driven AI SDK provider.\n *\n * Automatically resolves provider configurations from env var naming conventions,\n * with built-in preset support for quick setup.\n *\n * Env var convention (using config set `ZHIPU` with default separator `_` as example):\n * - `ZHIPU_PRESET` — use a built-in preset (BASE_URL and COMPATIBLE become optional)\n * - `ZHIPU_BASE_URL` — API base URL\n * - `ZHIPU_API_KEY` — API key (required)\n * - `ZHIPU_COMPATIBLE` — compatibility mode (defaults to `'openai-compatible'`)\n * - `ZHIPU_HEADERS` — custom HTTP headers (JSON format)\n *\n * @example\n * ```ts\n * import { createProviderRegistry } from 'ai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const registry = createProviderRegistry({\n * env: envProvider(),\n * })\n *\n * // Use a preset (only API_KEY is required)\n * // DEEPSEEK_PRESET=deepseek\n * // DEEPSEEK_API_KEY=sk-xxx\n * const model = registry.languageModel('env:deepseek/deepseek-chat')\n *\n * // Specify all parameters manually\n * // MYAPI_BASE_URL=https://api.example.com/v1\n * // MYAPI_API_KEY=xxx\n * const model2 = registry.languageModel('env:myapi/some-model')\n * ```\n *\n * @example Bundler-safe usage with explicit factories\n * ```ts\n * import { createOpenAI } from '@ai-sdk/openai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const provider = envProvider({\n * factories: { openai: createOpenAI },\n * })\n * ```\n */\nexport function envProvider(options: EnvProviderOptions = {}): ProviderV3 {\n const factories = options.factories\n ? buildUserFactories(options.factories)\n : defaultFactories\n return createEnvProvider(factories, options)\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,SAAgB,qBAAqB,MAAgC;AACnE,KAAI;EAEF,MAAM,EAAE,2BAAyB,iBAAiB;AAClD,SAAO,aAAa,KAAK;SAErB;AACJ,QAAM,IAAI,MACR,2GAED;;;;;;;;AASL,SAAgB,wBAAwB,MAAgC;AACtE,KAAI;EAEF,MAAM,EAAE,8BAA4B,oBAAoB;AACxD,SAAO,gBAAgB,KAAK;SAExB;AACJ,QAAM,IAAI,MACR,oHAED;;;;;;;;AASL,SAAgB,qBAAqB,MAAgC;AACnE,KAAI;EAEF,MAAM,EAAE,uCAAqC,iBAAiB;AAC9D,SAAO,yBAAyB,KAAK;SAEjC;AACJ,QAAM,IAAI,MACR,2GAED;;;;;;;;AASL,SAAgB,+BAA+B,MAAmD;AAChG,KAAI;EAEF,MAAM,EAAE,qCAAmC,4BAA4B;AACvE,SAAO,uBAAuB,KAAK;SAE/B;AACJ,QAAM,IAAI,MACR,8HAED;;;;;;;;;;;;ACzEL,MAAa,iBAA+C;CAE1D,QAAQ;EACN,SAAS;EACT,YAAY;EACb;CAGD,WAAW;EACT,SAAS;EACT,YAAY;EACb;CAGD,QAAQ;EACN,SAAS;EACT,YAAY;EACb;CAGD,UAAU;EACR,SAAS;EACT,YAAY;EACb;CAGD,OAAO;EACL,SAAS;EACT,YAAY;EACb;CAGD,MAAM;EACJ,SAAS;EACT,YAAY;EACb;CAGD,UAAU;EACR,SAAS;EACT,YAAY;EACb;CAGD,WAAW;EACT,SAAS;EACT,YAAY;EACb;CAGD,SAAS;EACP,SAAS;EACT,YAAY;EACb;CAGD,UAAU;EACR,SAAS;EACT,YAAY;EACb;CAGD,YAAY;EACV,SAAS;EACT,YAAY;EACb;CAGD,YAAY;EACV,SAAS;EACT,YAAY;EACb;CAGD,aAAa;EACX,SAAS;EACT,YAAY;EACb;CACF;;;;;;;AC9DD,MAAM,mBAAsC;CAC1C,cAAc;CACd,iBAAiB;CACjB,cAAc;CACd,wBAAwB;CACzB;;;;;;;AAkBD,SAAgB,kBACd,WACA,UAAiD,EAAE,EACvC;CACZ,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,eAAe,QAAQ,UAAU;CACvC,MAAM,iBAAiB,QAAQ,UAAU;CAGzC,MAAM,wBAAQ,IAAI,KAAyB;;;;CAK3C,SAAS,cAAc,YAA6D;EAClF,MAAM,SAAS,eAAe;AAC9B,MAAI,CAAC,QAAQ;GACX,MAAM,YAAY,OAAO,KAAK,eAAe,CAAC,KAAK,KAAK;AACxD,SAAM,IAAI,MACR,yCAAyC,WAAW,wBAAwB,YAC7E;;AAEH,SAAO;GACL,SAAS,OAAO;GAChB,YAAY,OAAO,cAAc;GAClC;;;;;CAMH,SAAS,cAAc,WAAmC;AAExD,MAAI,QAAQ,UAAU,YAAY;GAChC,MAAM,SAAS,QAAQ,QAAQ;AAG/B,OAAI,OAAO,QAAQ;IACjB,MAAM,SAAS,cAAc,OAAO,OAAO;AAC3C,WAAO;KACL,SAAS,OAAO,WAAW,OAAO;KAClC,QAAQ,OAAO;KACf,YAAY,OAAO,cAAc,OAAO;KACxC,GAAI,OAAO,WAAW,EAAE,SAAS,OAAO,SAAS;KAClD;;AAGH,OAAI,CAAC,OAAO,QACV,OAAM,IAAI,MACR,wDAAwD,UAAU,4CAEnE;AAGH,UAAO;IACL,SAAS,OAAO;IAChB,QAAQ,OAAO;IACf,YAAY,OAAO,cAAc;IACjC,GAAI,OAAO,WAAW,EAAE,SAAS,OAAO,SAAS;IAClD;;EAGH,MAAM,SAAS,UAAU,aAAa;EACtC,MAAM,OAAO,QAAoC,QAAQ,IAAI,GAAG,SAAS,YAAY;EAErF,MAAM,SAAS,IAAI,UAAU;AAC7B,MAAI,CAAC,OACH,OAAM,IAAI,MACR,yCAAyC,SAAS,UAAU,SAC7D;EAIH,MAAM,aAAa,IAAI,UAAU;EACjC,IAAI;AACJ,MAAI,WACF,KAAI;AACF,aAAU,KAAK,MAAM,WAAW;UAE5B;AACJ,SAAM,IAAI,MACR,yCAAyC,SAAS,UAAU,WAAW,aACxE;;EAKL,MAAM,aAAa,IAAI,SAAS;AAChC,MAAI,YAAY;GACd,MAAM,SAAS,cAAc,WAAW;AACxC,UAAO;IACL,SAAS,IAAI,WAAW,IAAI,OAAO;IACnC;IACA,YAAY,IAAI,aAAa,IAAI,OAAO;IACxC,GAAI,WAAW,EAAE,SAAS;IAC3B;;EAIH,MAAM,UAAU,IAAI,WAAW;AAC/B,MAAI,QACF,QAAO;GACL;GACA;GACA,YAAY,IAAI,aAAa,IAAI;GACjC,GAAI,WAAW,EAAE,SAAS;GAC3B;AAIH,MAAI,QAAQ,qBAAqB,OAAO;GACtC,MAAM,aAAa,eAAe,UAAU,aAAa;AACzD,OAAI,WACF,QAAO;IACL,SAAS,WAAW;IACpB;IACA,YAAY,IAAI,aAAa,IAAI,WAAW,cAAc;IAC1D,GAAI,WAAW,EAAE,SAAS;IAC3B;;EAKL,MAAM,YAAY,OAAO,KAAK,eAAe,CAAC,KAAK,KAAK;EACxD,MAAM,aAAa,eAAe,UAAU,aAAa,IACrD,YAAY,UAAU,mEACtB;AACJ,QAAM,IAAI,MACR,yCAAyC,SAAS,UAAU,mBAC9C,SAAS,UAAU,6CACR,UAAU,GAAG,aACvC;;;;;CAMH,SAAS,iBAAiB,WAAmB,QAAoC;EAC/E,MAAM,EAAE,SAAS,QAAQ,YAAY,YAAY;EAGjD,MAAM,gBAAiB,kBAAkB,UACrC;GAAE,GAAG;GAAgB,GAAG;GAAS,GACjC;EAEJ,MAAM,WAAW;GACf;GACA;GACA,GAAI,iBAAiB,EAAE,SAAS,eAAe;GAC/C,GAAI,gBAAgB,EAAE,OAAO,cAAc;GAC5C;AAED,UAAQ,YAAR;GACE,KAAK,SACH,QAAO,UAAU,aAAa,SAAS;GACzC,KAAK,YACH,QAAO,UAAU,gBAAgB,SAAS;GAC5C,KAAK,SACH,QAAO,UAAU,aAAa,SAAS;GACzC,KAAK,oBACH,QAAO,UAAU,uBAAuB;IAAE,MAAM;IAAW,GAAG;IAAU,CAAC;GAC3E,QACE,OAAM,IAAI,MACR,kDAAkD,WAAW,iKAG9D;;;;;;CAOP,SAAS,YAAY,WAA+B;EAClD,MAAM,MAAM,UAAU,aAAa;EACnC,MAAM,SAAS,MAAM,IAAI,IAAI;AAC7B,MAAI,OACF,QAAO;EAGT,MAAM,WAAW,iBAAiB,WADnB,cAAc,UAAU,CACa;AACpD,QAAM,IAAI,KAAK,SAAS;AACxB,SAAO;;;;;CAMT,SAAS,aAAa,SAAuD;EAC3E,MAAM,aAAa,QAAQ,QAAQ,IAAI;AACvC,MAAI,eAAe,GACjB,OAAM,IAAI,MACR,2CAA2C,QAAQ,iEAEpD;AAEH,SAAO;GACL,WAAW,QAAQ,MAAM,GAAG,WAAW;GACvC,OAAO,QAAQ,MAAM,aAAa,EAAE;GACrC;;AAGH,QAAO;EACL,sBAAsB;EAEtB,cAAc,SAAiB;GAC7B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;AAClD,UAAO,YAAY,UAAU,CAAC,cAAc,MAAM;;EAGpD,eAAe,SAAiB;GAC9B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;AAClD,UAAO,YAAY,UAAU,CAAC,eAAe,MAAM;;EAGrD,WAAW,SAAiB;GAC1B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;AAClD,UAAO,YAAY,UAAU,CAAC,WAAW,MAAM;;EAGjD,mBAAmB,SAAiB;GAClC,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;GAClD,MAAM,WAAW,YAAY,UAAU;AACvC,OAAI,CAAC,SAAS,mBACZ,OAAM,IAAI,iBAAiB;IAAE;IAAS,WAAW;IAAkB,CAAC;AAEtE,UAAO,SAAS,mBAAmB,MAAM;;EAG3C,mBAAmB,SAAiB;GAClC,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;GAClD,MAAM,WAAW,YAAY,UAAU;AACvC,OAAI,CAAC,SAAS,mBACZ,OAAM,IAAI,iBAAiB;IAAE;IAAS,WAAW;IAAsB,CAAC;AAE1E,UAAO,SAAS,mBAAmB,MAAM;;EAG3C,YAAY,SAAiB;GAC3B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;GAClD,MAAM,WAAW,YAAY,UAAU;AACvC,OAAI,CAAC,SAAS,YACZ,OAAM,IAAI,iBAAiB;IAAE;IAAS,WAAW;IAAe,CAAC;AAEnE,UAAO,SAAS,YAAY,MAAM;;EAGpC,eAAe,SAAiB;GAC9B,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ;GAClD,MAAM,WAAW,YAAY,UAAU;AACvC,OAAI,CAAC,SAAS,eACZ,OAAM,IAAI,iBAAiB;IAAE;IAAS,WAAW;IAAkB,CAAC;AAEtE,UAAO,SAAS,eAAe,MAAM;;EAExC;;;;;;;;;AAUH,SAAS,mBAAmB,eAAwD;CAClF,SAAS,eAAe,KAAa,QAAgB,KAAoB;AACvE,QAAM,IAAI,MACR,kDAAkD,IAAI,2GAEnC,OAAO,WAAW,IAAI,yBAAyB,IAAI,IAAI,OAAO,IAClF;;AAGH,QAAO;EACL,eAAc,SACZ,cAAc,SACV,cAAc,OAAO,KAAK,GAC1B,eAAe,UAAU,gBAAgB,iBAAiB;EAChE,kBAAiB,SACf,cAAc,YACV,cAAc,UAAU,KAAK,GAC7B,eAAe,aAAa,mBAAmB,oBAAoB;EACzE,eAAc,SACZ,cAAc,SACV,cAAc,OAAO,KAAK,GAC1B,eAAe,UAAU,4BAA4B,iBAAiB;EAC5E,yBAAwB,SACtB,cAAc,mBACV,cAAc,iBAAiB,KAAK,GACpC,eAAe,oBAAoB,0BAA0B,4BAA4B;EAChG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CH,SAAgB,YAAY,UAA8B,EAAE,EAAc;AAIxE,QAAO,kBAHW,QAAQ,YACtB,mBAAmB,QAAQ,UAAU,GACrC,kBACgC,QAAQ"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-sdk-provider-env",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "description": "A dynamic, environment-variable-driven provider for Vercel AI SDK — resolves provider configurations from env var conventions at runtime",
6
6
  "author": "maou-shonen",
7
7
  "license": "MIT",