@neon/ai-sdk-provider 0.5.0 → 0.7.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
@@ -12,9 +12,11 @@ Model ids use the canonical Neon (unprefixed) form — `claude-sonnet-4-6`, `gpt
12
12
  npm install @neon/ai-sdk-provider ai@^6
13
13
  ```
14
14
 
15
+ > **Requirements:** Node.js >= 20.19.
16
+
15
17
  ## Configuration
16
18
 
17
- The gateway URL is branch-scoped, so both values come from the Neon Console (your project → a branch → **AI Gateway** tab), or from `neonctl env pull` / `neon dev`:
19
+ The gateway URL is branch-scoped, so both values come from the Neon Console (your project → a branch → **AI Gateway** tab), or from `neon env pull` / `neon dev`:
18
20
 
19
21
  ```bash
20
22
  NEON_AI_GATEWAY_BASE_URL="https://<branch-id>-api.ai.<region>.aws.neon.tech"
@@ -94,7 +96,7 @@ for await (const part of result.fullStream) {
94
96
  Against a live branch with AI Gateway enabled:
95
97
 
96
98
  ```bash
97
- cp .env.example .env # fill NEON_AI_GATEWAY_BASE_URL + NEON_AI_GATEWAY_TOKEN from `neonctl env pull`
99
+ cp .env.example .env # fill NEON_AI_GATEWAY_BASE_URL + NEON_AI_GATEWAY_TOKEN from `neon env pull`
98
100
  pnpm test:e2e
99
101
  ```
100
102
 
@@ -5,7 +5,7 @@ import { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3GenerateRes
5
5
 
6
6
  /**
7
7
  * Language model for Anthropic models served via the Neon AI Gateway's native
8
- * Messages API (`/ai-gateway/anthropic/v1/messages`). Unlocks streaming
8
+ * Messages API (`/anthropic/v1/messages`). Unlocks streaming
9
9
  * structured output and native reasoning for Claude.
10
10
  *
11
11
  * The shared Anthropic model defaults to fine-grained tool-input streaming
@@ -2,7 +2,7 @@ import { AnthropicMessagesLanguageModel } from "@ai-sdk/anthropic/internal";
2
2
  //#region src/lib/neon-anthropic-language-model.ts
3
3
  /**
4
4
  * Language model for Anthropic models served via the Neon AI Gateway's native
5
- * Messages API (`/ai-gateway/anthropic/v1/messages`). Unlocks streaming
5
+ * Messages API (`/anthropic/v1/messages`). Unlocks streaming
6
6
  * structured output and native reasoning for Claude.
7
7
  *
8
8
  * The shared Anthropic model defaults to fine-grained tool-input streaming
@@ -1 +1 @@
1
- {"version":3,"file":"neon-anthropic-language-model.js","names":[],"sources":["../../src/lib/neon-anthropic-language-model.ts"],"sourcesContent":["import { AnthropicMessagesLanguageModel } from \"@ai-sdk/anthropic/internal\";\nimport type {\n\tLanguageModelV3,\n\tLanguageModelV3CallOptions,\n\tLanguageModelV3GenerateResult,\n\tLanguageModelV3StreamResult,\n} from \"@ai-sdk/provider\";\n\n/**\n * Language model for Anthropic models served via the Neon AI Gateway's native\n * Messages API (`/ai-gateway/anthropic/v1/messages`). Unlocks streaming\n * structured output and native reasoning for Claude.\n *\n * The shared Anthropic model defaults to fine-grained tool-input streaming\n * (`eager_input_streaming: true`) on streaming tool calls, which the gateway\n * rejects (`Extra inputs are not permitted`). We disable it via the model's own\n * `toolStreaming` option so streaming tool calls work. Users can still override.\n */\nexport class NeonAnthropicLanguageModel\n\textends AnthropicMessagesLanguageModel\n\timplements LanguageModelV3\n{\n\tprivate withGatewayCompat(\n\t\toptions: LanguageModelV3CallOptions,\n\t): LanguageModelV3CallOptions {\n\t\tconst anthropic = options.providerOptions?.anthropic;\n\t\t// Respect an explicit user setting.\n\t\tif (anthropic != null && \"toolStreaming\" in anthropic) {\n\t\t\treturn options;\n\t\t}\n\t\treturn {\n\t\t\t...options,\n\t\t\tproviderOptions: {\n\t\t\t\t...options.providerOptions,\n\t\t\t\tanthropic: { ...anthropic, toolStreaming: false },\n\t\t\t},\n\t\t};\n\t}\n\n\toverride doGenerate(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3GenerateResult> {\n\t\treturn super.doGenerate(this.withGatewayCompat(options));\n\t}\n\n\toverride doStream(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3StreamResult> {\n\t\treturn super.doStream(this.withGatewayCompat(options));\n\t}\n}\n"],"mappings":";;;;;;;;;;;;AAkBA,IAAa,6BAAb,cACS,+BAET;CACC,kBACC,SAC6B;EAC7B,MAAM,YAAY,QAAQ,iBAAiB;EAE3C,IAAI,aAAa,QAAQ,mBAAmB,WAC3C,OAAO;EAER,OAAO;GACN,GAAG;GACH,iBAAiB;IAChB,GAAG,QAAQ;IACX,WAAW;KAAE,GAAG;KAAW,eAAe;IAAM;GACjD;EACD;CACD;CAEA,WACC,SACyC;EACzC,OAAO,MAAM,WAAW,KAAK,kBAAkB,OAAO,CAAC;CACxD;CAEA,SACC,SACuC;EACvC,OAAO,MAAM,SAAS,KAAK,kBAAkB,OAAO,CAAC;CACtD;AACD"}
1
+ {"version":3,"file":"neon-anthropic-language-model.js","names":[],"sources":["../../src/lib/neon-anthropic-language-model.ts"],"sourcesContent":["import { AnthropicMessagesLanguageModel } from \"@ai-sdk/anthropic/internal\";\nimport type {\n\tLanguageModelV3,\n\tLanguageModelV3CallOptions,\n\tLanguageModelV3GenerateResult,\n\tLanguageModelV3StreamResult,\n} from \"@ai-sdk/provider\";\n\n/**\n * Language model for Anthropic models served via the Neon AI Gateway's native\n * Messages API (`/anthropic/v1/messages`). Unlocks streaming\n * structured output and native reasoning for Claude.\n *\n * The shared Anthropic model defaults to fine-grained tool-input streaming\n * (`eager_input_streaming: true`) on streaming tool calls, which the gateway\n * rejects (`Extra inputs are not permitted`). We disable it via the model's own\n * `toolStreaming` option so streaming tool calls work. Users can still override.\n */\nexport class NeonAnthropicLanguageModel\n\textends AnthropicMessagesLanguageModel\n\timplements LanguageModelV3\n{\n\tprivate withGatewayCompat(\n\t\toptions: LanguageModelV3CallOptions,\n\t): LanguageModelV3CallOptions {\n\t\tconst anthropic = options.providerOptions?.anthropic;\n\t\t// Respect an explicit user setting.\n\t\tif (anthropic != null && \"toolStreaming\" in anthropic) {\n\t\t\treturn options;\n\t\t}\n\t\treturn {\n\t\t\t...options,\n\t\t\tproviderOptions: {\n\t\t\t\t...options.providerOptions,\n\t\t\t\tanthropic: { ...anthropic, toolStreaming: false },\n\t\t\t},\n\t\t};\n\t}\n\n\toverride doGenerate(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3GenerateResult> {\n\t\treturn super.doGenerate(this.withGatewayCompat(options));\n\t}\n\n\toverride doStream(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3StreamResult> {\n\t\treturn super.doStream(this.withGatewayCompat(options));\n\t}\n}\n"],"mappings":";;;;;;;;;;;;AAkBA,IAAa,6BAAb,cACS,+BAET;CACC,kBACC,SAC6B;EAC7B,MAAM,YAAY,QAAQ,iBAAiB;EAE3C,IAAI,aAAa,QAAQ,mBAAmB,WAC3C,OAAO;EAER,OAAO;GACN,GAAG;GACH,iBAAiB;IAChB,GAAG,QAAQ;IACX,WAAW;KAAE,GAAG;KAAW,eAAe;IAAM;GACjD;EACD;CACD;CAEA,WACC,SACyC;EACzC,OAAO,MAAM,WAAW,KAAK,kBAAkB,OAAO,CAAC;CACxD;CAEA,SACC,SACuC;EACvC,OAAO,MAAM,SAAS,KAAK,kBAAkB,OAAO,CAAC;CACtD;AACD"}
@@ -5,7 +5,7 @@ import { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3GenerateRes
5
5
 
6
6
  /**
7
7
  * Language model for OpenAI models served via the Neon AI Gateway's native
8
- * Responses API (`/ai-gateway/openai/v1/responses`). This route is required for
8
+ * Responses API (`/openai/v1/responses`). This route is required for
9
9
  * models that are only served natively (e.g. Codex) and unlocks native
10
10
  * reasoning and the image-generation tool.
11
11
  *
@@ -2,7 +2,7 @@ import { OpenAIResponsesLanguageModel } from "@ai-sdk/openai/internal";
2
2
  //#region src/lib/neon-responses-language-model.ts
3
3
  /**
4
4
  * Language model for OpenAI models served via the Neon AI Gateway's native
5
- * Responses API (`/ai-gateway/openai/v1/responses`). This route is required for
5
+ * Responses API (`/openai/v1/responses`). This route is required for
6
6
  * models that are only served natively (e.g. Codex) and unlocks native
7
7
  * reasoning and the image-generation tool.
8
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"neon-responses-language-model.js","names":[],"sources":["../../src/lib/neon-responses-language-model.ts"],"sourcesContent":["import { OpenAIResponsesLanguageModel } from \"@ai-sdk/openai/internal\";\nimport type {\n\tLanguageModelV3,\n\tLanguageModelV3CallOptions,\n\tLanguageModelV3GenerateResult,\n\tLanguageModelV3StreamResult,\n} from \"@ai-sdk/provider\";\n\n/**\n * Language model for OpenAI models served via the Neon AI Gateway's native\n * Responses API (`/ai-gateway/openai/v1/responses`). This route is required for\n * models that are only served natively (e.g. Codex) and unlocks native\n * reasoning and the image-generation tool.\n *\n * The shared OpenAI Responses model shapes a request based on whether the model\n * is a reasoning model, but its detection is brittle here: the gateway also\n * accepts the legacy `databricks-` prefix, which defeats the upstream bare-id\n * (`gpt-5`) match. For the GPT-5 reasoning family we set the model's own\n * `forceReasoning` provider option so it applies the correct reasoning behavior\n * for both id forms. Users can still override it.\n */\nexport class NeonResponsesLanguageModel\n\textends OpenAIResponsesLanguageModel\n\timplements LanguageModelV3\n{\n\tprivate get isReasoningFamily(): boolean {\n\t\treturn /gpt-5/.test(this.modelId.toLowerCase());\n\t}\n\n\tprivate withForcedReasoning(\n\t\toptions: LanguageModelV3CallOptions,\n\t): LanguageModelV3CallOptions {\n\t\tif (!this.isReasoningFamily) {\n\t\t\treturn options;\n\t\t}\n\t\tconst openai = options.providerOptions?.openai;\n\t\t// Respect an explicit user setting.\n\t\tif (openai != null && \"forceReasoning\" in openai) {\n\t\t\treturn options;\n\t\t}\n\t\treturn {\n\t\t\t...options,\n\t\t\tproviderOptions: {\n\t\t\t\t...options.providerOptions,\n\t\t\t\topenai: { ...openai, forceReasoning: true },\n\t\t\t},\n\t\t};\n\t}\n\n\toverride doGenerate(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3GenerateResult> {\n\t\treturn super.doGenerate(this.withForcedReasoning(options));\n\t}\n\n\toverride doStream(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3StreamResult> {\n\t\treturn super.doStream(this.withForcedReasoning(options));\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,IAAa,6BAAb,cACS,6BAET;CACC,IAAY,oBAA6B;EACxC,OAAO,QAAQ,KAAK,KAAK,QAAQ,YAAY,CAAC;CAC/C;CAEA,oBACC,SAC6B;EAC7B,IAAI,CAAC,KAAK,mBACT,OAAO;EAER,MAAM,SAAS,QAAQ,iBAAiB;EAExC,IAAI,UAAU,QAAQ,oBAAoB,QACzC,OAAO;EAER,OAAO;GACN,GAAG;GACH,iBAAiB;IAChB,GAAG,QAAQ;IACX,QAAQ;KAAE,GAAG;KAAQ,gBAAgB;IAAK;GAC3C;EACD;CACD;CAEA,WACC,SACyC;EACzC,OAAO,MAAM,WAAW,KAAK,oBAAoB,OAAO,CAAC;CAC1D;CAEA,SACC,SACuC;EACvC,OAAO,MAAM,SAAS,KAAK,oBAAoB,OAAO,CAAC;CACxD;AACD"}
1
+ {"version":3,"file":"neon-responses-language-model.js","names":[],"sources":["../../src/lib/neon-responses-language-model.ts"],"sourcesContent":["import { OpenAIResponsesLanguageModel } from \"@ai-sdk/openai/internal\";\nimport type {\n\tLanguageModelV3,\n\tLanguageModelV3CallOptions,\n\tLanguageModelV3GenerateResult,\n\tLanguageModelV3StreamResult,\n} from \"@ai-sdk/provider\";\n\n/**\n * Language model for OpenAI models served via the Neon AI Gateway's native\n * Responses API (`/openai/v1/responses`). This route is required for\n * models that are only served natively (e.g. Codex) and unlocks native\n * reasoning and the image-generation tool.\n *\n * The shared OpenAI Responses model shapes a request based on whether the model\n * is a reasoning model, but its detection is brittle here: the gateway also\n * accepts the legacy `databricks-` prefix, which defeats the upstream bare-id\n * (`gpt-5`) match. For the GPT-5 reasoning family we set the model's own\n * `forceReasoning` provider option so it applies the correct reasoning behavior\n * for both id forms. Users can still override it.\n */\nexport class NeonResponsesLanguageModel\n\textends OpenAIResponsesLanguageModel\n\timplements LanguageModelV3\n{\n\tprivate get isReasoningFamily(): boolean {\n\t\treturn /gpt-5/.test(this.modelId.toLowerCase());\n\t}\n\n\tprivate withForcedReasoning(\n\t\toptions: LanguageModelV3CallOptions,\n\t): LanguageModelV3CallOptions {\n\t\tif (!this.isReasoningFamily) {\n\t\t\treturn options;\n\t\t}\n\t\tconst openai = options.providerOptions?.openai;\n\t\t// Respect an explicit user setting.\n\t\tif (openai != null && \"forceReasoning\" in openai) {\n\t\t\treturn options;\n\t\t}\n\t\treturn {\n\t\t\t...options,\n\t\t\tproviderOptions: {\n\t\t\t\t...options.providerOptions,\n\t\t\t\topenai: { ...openai, forceReasoning: true },\n\t\t\t},\n\t\t};\n\t}\n\n\toverride doGenerate(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3GenerateResult> {\n\t\treturn super.doGenerate(this.withForcedReasoning(options));\n\t}\n\n\toverride doStream(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3StreamResult> {\n\t\treturn super.doStream(this.withForcedReasoning(options));\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,IAAa,6BAAb,cACS,6BAET;CACC,IAAY,oBAA6B;EACxC,OAAO,QAAQ,KAAK,KAAK,QAAQ,YAAY,CAAC;CAC/C;CAEA,oBACC,SAC6B;EAC7B,IAAI,CAAC,KAAK,mBACT,OAAO;EAER,MAAM,SAAS,QAAQ,iBAAiB;EAExC,IAAI,UAAU,QAAQ,oBAAoB,QACzC,OAAO;EAER,OAAO;GACN,GAAG;GACH,iBAAiB;IAChB,GAAG,QAAQ;IACX,QAAQ;KAAE,GAAG;KAAQ,gBAAgB;IAAK;GAC3C;EACD;CACD;CAEA,WACC,SACyC;EACzC,OAAO,MAAM,WAAW,KAAK,oBAAoB,OAAO,CAAC;CAC1D;CAEA,SACC,SACuC;EACvC,OAAO,MAAM,SAAS,KAAK,oBAAoB,OAAO,CAAC;CACxD;AACD"}
@@ -13,7 +13,7 @@ import { z } from "zod/v4";
13
13
  *
14
14
  * `createNeon()` returns a provider that routes each model to the best gateway
15
15
  * endpoint based on its id (Anthropic → native Messages, OpenAI → native
16
- * Responses incl. Codex, everything else → unified MLflow), so a single
16
+ * Responses incl. Codex, everything else → unified Chat Completions), so a single
17
17
  * `neon('claude-...')` call (same base URL + token) reaches the whole catalog.
18
18
  * Ids use the canonical Neon (unprefixed) form; the legacy `databricks-` prefix
19
19
  * is also accepted. Configure with the branch-scoped `NEON_AI_GATEWAY_BASE_URL` +
@@ -70,21 +70,21 @@ function createNeon(options = {}) {
70
70
  }, `neondatabase/ai-sdk-provider/${VERSION}`);
71
71
  const createAnthropicModel = (modelId) => new NeonAnthropicLanguageModel(modelId, {
72
72
  provider: "neon.anthropic",
73
- baseURL: `${getHost()}/ai-gateway/anthropic/v1`,
73
+ baseURL: `${getHost()}/anthropic/v1`,
74
74
  headers: () => getHeaders({ "anthropic-version": "2023-06-01" }),
75
75
  fetch: options.fetch,
76
76
  generateId
77
77
  });
78
78
  const createOpenAIModel = (modelId) => new NeonResponsesLanguageModel(modelId, {
79
79
  provider: "neon.openai.responses",
80
- url: ({ path }) => `${getHost()}/ai-gateway/openai/v1${path}`,
80
+ url: ({ path }) => `${getHost()}/openai/v1${path}`,
81
81
  headers: getHeaders,
82
82
  fetch: options.fetch,
83
83
  fileIdPrefixes: ["file-"]
84
84
  });
85
85
  const createChatModel = (modelId) => new NeonChatLanguageModel(modelId, {
86
86
  provider: "neon.chat",
87
- url: ({ path }) => `${getHost()}/ai-gateway/mlflow/v1${path}`,
87
+ url: ({ path }) => `${getHost()}/v1${path}`,
88
88
  headers: getHeaders,
89
89
  fetch: options.fetch,
90
90
  errorStructure: neonErrorStructure,
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","names":["openaiProvider"],"sources":["../../src/lib/provider.ts"],"sourcesContent":["/**\n * Community Vercel AI SDK provider for the Neon AI Gateway.\n *\n * `createNeon()` returns a provider that routes each model to the best gateway\n * endpoint based on its id (Anthropic → native Messages, OpenAI → native\n * Responses incl. Codex, everything else → unified MLflow), so a single\n * `neon('claude-...')` call (same base URL + token) reaches the whole catalog.\n * Ids use the canonical Neon (unprefixed) form; the legacy `databricks-` prefix\n * is also accepted. Configure with the branch-scoped `NEON_AI_GATEWAY_BASE_URL` +\n * `NEON_AI_GATEWAY_TOKEN` emitted by `neonctl env pull` / `neon dev`, or pass\n * `baseURL` / `apiKey` explicitly.\n */\nimport { openai as openaiProvider } from \"@ai-sdk/openai\";\nimport type { ProviderErrorStructure } from \"@ai-sdk/openai-compatible\";\nimport {\n\ttype LanguageModelV3,\n\tNoSuchModelError,\n\ttype ProviderV3,\n} from \"@ai-sdk/provider\";\nimport {\n\ttype FetchFunction,\n\tgenerateId,\n\tloadApiKey,\n\tloadSetting,\n\twithoutTrailingSlash,\n\twithUserAgentSuffix,\n} from \"@ai-sdk/provider-utils\";\nimport { z } from \"zod/v4\";\nimport { NeonAnthropicLanguageModel } from \"./neon-anthropic-language-model.js\";\nimport { NeonChatLanguageModel } from \"./neon-chat-language-model.js\";\nimport type { NeonChatModelId } from \"./neon-chat-options.js\";\nimport { getNeonModelRoute } from \"./neon-model-capabilities.js\";\nimport { NeonResponsesLanguageModel } from \"./neon-responses-language-model.js\";\nimport { VERSION } from \"./version.js\";\n\nconst neonErrorSchema = z.object({\n\terror: z.object({\n\t\tmessage: z.string(),\n\t\ttype: z.string().nullish(),\n\t\tparam: z.unknown().nullish(),\n\t\tcode: z.unknown().nullish(),\n\t}),\n});\n\nexport type NeonErrorData = z.infer<typeof neonErrorSchema>;\n\nconst neonErrorStructure: ProviderErrorStructure<NeonErrorData> = {\n\terrorSchema: neonErrorSchema,\n\terrorToMessage: (data) => data.error.message,\n};\n\n/**\n * Recursively remove the JSON Schema `$schema` marker, which some gateway\n * backends (notably Gemini) reject in tool/structured-output schemas. Other\n * backends ignore its absence, so stripping it everywhere is safe.\n */\nfunction stripJsonSchemaMarker(value: unknown): unknown {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(stripJsonSchemaMarker);\n\t}\n\tif (value !== null && typeof value === \"object\") {\n\t\tconst result: Record<string, unknown> = {};\n\t\tfor (const [key, entry] of Object.entries(value)) {\n\t\t\tif (key === \"$schema\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult[key] = stripJsonSchemaMarker(entry);\n\t\t}\n\t\treturn result;\n\t}\n\treturn value;\n}\n\nfunction transformNeonRequestBody(\n\targs: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst transformed = { ...args };\n\tif (transformed.tools != null) {\n\t\ttransformed.tools = stripJsonSchemaMarker(transformed.tools);\n\t}\n\tif (transformed.response_format != null) {\n\t\ttransformed.response_format = stripJsonSchemaMarker(\n\t\t\ttransformed.response_format,\n\t\t);\n\t}\n\treturn transformed;\n}\n\nexport interface NeonProviderSettings {\n\t/**\n\t * Neon AI Gateway base URL — the branch-scoped host root, e.g.\n\t * `https://<branch-id>-api.ai.<region>.aws.neon.tech`. The gateway paths are\n\t * appended internally. Falls back to the `NEON_AI_GATEWAY_BASE_URL` env var.\n\t */\n\tbaseURL?: string;\n\n\t/**\n\t * Neon AI Gateway platform token (the `nt_live_...` value). Falls back to the\n\t * `NEON_AI_GATEWAY_TOKEN` env var.\n\t */\n\tapiKey?: string;\n\n\t/** Custom headers to include in the requests. */\n\theaders?: Record<string, string>;\n\n\t/** Custom fetch implementation (e.g. for testing or middleware). */\n\tfetch?: FetchFunction;\n}\n\nexport interface NeonProvider extends ProviderV3 {\n\t/** Creates a Neon AI Gateway model for text generation. */\n\t(modelId: NeonChatModelId): LanguageModelV3;\n\n\t/** Creates a Neon AI Gateway model for text generation. */\n\tlanguageModel(modelId: NeonChatModelId): LanguageModelV3;\n\n\t/** Creates a Neon AI Gateway chat model for text generation. */\n\tchat(modelId: NeonChatModelId): LanguageModelV3;\n\n\t/** OpenAI Responses tools (e.g. `imageGeneration`) for OpenAI-routed models. */\n\ttools: typeof openaiProvider.tools;\n\n\t/** @deprecated Use `embeddingModel` instead. */\n\ttextEmbeddingModel(modelId: string): never;\n}\n\nexport function createNeon(options: NeonProviderSettings = {}): NeonProvider {\n\t// Resolved lazily so that `createNeon()` and the default `neon` instance do\n\t// not throw at import time when configuration comes from the environment.\n\tconst getHost = () =>\n\t\twithoutTrailingSlash(\n\t\t\tloadSetting({\n\t\t\t\tsettingValue: options.baseURL,\n\t\t\t\tenvironmentVariableName: \"NEON_AI_GATEWAY_BASE_URL\",\n\t\t\t\tsettingName: \"baseURL\",\n\t\t\t\tdescription: \"Neon AI Gateway base URL\",\n\t\t\t}),\n\t\t);\n\n\tconst getHeaders = (extra?: Record<string, string>) =>\n\t\twithUserAgentSuffix(\n\t\t\t{\n\t\t\t\tAuthorization: `Bearer ${loadApiKey({\n\t\t\t\t\tapiKey: options.apiKey,\n\t\t\t\t\tenvironmentVariableName: \"NEON_AI_GATEWAY_TOKEN\",\n\t\t\t\t\tdescription: \"Neon AI Gateway token\",\n\t\t\t\t})}`,\n\t\t\t\t...extra,\n\t\t\t\t...options.headers,\n\t\t\t},\n\t\t\t`neondatabase/ai-sdk-provider/${VERSION}`,\n\t\t);\n\n\t// Anthropic models -> native Messages API.\n\tconst createAnthropicModel = (modelId: NeonChatModelId) =>\n\t\tnew NeonAnthropicLanguageModel(modelId, {\n\t\t\tprovider: \"neon.anthropic\",\n\t\t\tbaseURL: `${getHost()}/ai-gateway/anthropic/v1`,\n\t\t\theaders: () => getHeaders({ \"anthropic-version\": \"2023-06-01\" }),\n\t\t\tfetch: options.fetch,\n\t\t\tgenerateId,\n\t\t});\n\n\t// OpenAI models (incl. Codex, only served natively) -> Responses API.\n\tconst createOpenAIModel = (modelId: NeonChatModelId) =>\n\t\tnew NeonResponsesLanguageModel(modelId, {\n\t\t\tprovider: \"neon.openai.responses\",\n\t\t\turl: ({ path }) => `${getHost()}/ai-gateway/openai/v1${path}`,\n\t\t\theaders: getHeaders,\n\t\t\tfetch: options.fetch,\n\t\t\tfileIdPrefixes: [\"file-\"],\n\t\t});\n\n\t// Everything else (Gemini, Llama, Qwen, gpt-oss, ...) -> unified MLflow\n\t// endpoint. Gemini is here because its native endpoint can't stream.\n\tconst createChatModel = (modelId: NeonChatModelId) =>\n\t\tnew NeonChatLanguageModel(modelId, {\n\t\t\tprovider: \"neon.chat\",\n\t\t\turl: ({ path }) => `${getHost()}/ai-gateway/mlflow/v1${path}`,\n\t\t\theaders: getHeaders,\n\t\t\tfetch: options.fetch,\n\t\t\terrorStructure: neonErrorStructure,\n\t\t\ttransformRequestBody: transformNeonRequestBody,\n\t\t\tsupportsStructuredOutputs: true,\n\t\t});\n\n\tconst createLanguageModel = (modelId: NeonChatModelId): LanguageModelV3 => {\n\t\tswitch (getNeonModelRoute(modelId)) {\n\t\t\tcase \"anthropic\":\n\t\t\t\treturn createAnthropicModel(modelId);\n\t\t\tcase \"openai\":\n\t\t\t\treturn createOpenAIModel(modelId);\n\t\t\tdefault:\n\t\t\t\treturn createChatModel(modelId);\n\t\t}\n\t};\n\n\tconst provider = (modelId: NeonChatModelId) => createLanguageModel(modelId);\n\n\tprovider.specificationVersion = \"v3\" as const;\n\tprovider.languageModel = createLanguageModel;\n\tprovider.chat = createLanguageModel;\n\tprovider.tools = openaiProvider.tools;\n\n\tprovider.embeddingModel = (modelId: string) => {\n\t\tthrow new NoSuchModelError({ modelId, modelType: \"embeddingModel\" });\n\t};\n\tprovider.textEmbeddingModel = provider.embeddingModel;\n\tprovider.imageModel = (modelId: string) => {\n\t\tthrow new NoSuchModelError({ modelId, modelType: \"imageModel\" });\n\t};\n\n\treturn provider;\n}\n\n/** Default Neon provider instance (reads `NEON_AI_GATEWAY_*` env vars). */\nexport const neon = createNeon();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAM,qBAA4D;CACjE,aAZuB,EAAE,OAAO,EAChC,OAAO,EAAE,OAAO;EACf,SAAS,EAAE,OAAO;EAClB,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ;EACzB,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ;EAC3B,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ;CAC3B,CAAC,EACF,CAK4B;CAC3B,iBAAiB,SAAS,KAAK,MAAM;AACtC;;;;;;AAOA,SAAS,sBAAsB,OAAyB;CACvD,IAAI,MAAM,QAAQ,KAAK,GACtB,OAAO,MAAM,IAAI,qBAAqB;CAEvC,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;EAChD,MAAM,SAAkC,CAAC;EACzC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;GACjD,IAAI,QAAQ,WACX;GAED,OAAO,OAAO,sBAAsB,KAAK;EAC1C;EACA,OAAO;CACR;CACA,OAAO;AACR;AAEA,SAAS,yBACR,MAC0B;CAC1B,MAAM,cAAc,EAAE,GAAG,KAAK;CAC9B,IAAI,YAAY,SAAS,MACxB,YAAY,QAAQ,sBAAsB,YAAY,KAAK;CAE5D,IAAI,YAAY,mBAAmB,MAClC,YAAY,kBAAkB,sBAC7B,YAAY,eACb;CAED,OAAO;AACR;AAwCA,SAAgB,WAAW,UAAgC,CAAC,GAAiB;CAG5E,MAAM,gBACL,qBACC,YAAY;EACX,cAAc,QAAQ;EACtB,yBAAyB;EACzB,aAAa;EACb,aAAa;CACd,CAAC,CACF;CAED,MAAM,cAAc,UACnB,oBACC;EACC,eAAe,UAAU,WAAW;GACnC,QAAQ,QAAQ;GAChB,yBAAyB;GACzB,aAAa;EACd,CAAC;EACD,GAAG;EACH,GAAG,QAAQ;CACZ,GACA,gCAAgC,SACjC;CAGD,MAAM,wBAAwB,YAC7B,IAAI,2BAA2B,SAAS;EACvC,UAAU;EACV,SAAS,GAAG,QAAQ,EAAE;EACtB,eAAe,WAAW,EAAE,qBAAqB,aAAa,CAAC;EAC/D,OAAO,QAAQ;EACf;CACD,CAAC;CAGF,MAAM,qBAAqB,YAC1B,IAAI,2BAA2B,SAAS;EACvC,UAAU;EACV,MAAM,EAAE,WAAW,GAAG,QAAQ,EAAE,uBAAuB;EACvD,SAAS;EACT,OAAO,QAAQ;EACf,gBAAgB,CAAC,OAAO;CACzB,CAAC;CAIF,MAAM,mBAAmB,YACxB,IAAI,sBAAsB,SAAS;EAClC,UAAU;EACV,MAAM,EAAE,WAAW,GAAG,QAAQ,EAAE,uBAAuB;EACvD,SAAS;EACT,OAAO,QAAQ;EACf,gBAAgB;EAChB,sBAAsB;EACtB,2BAA2B;CAC5B,CAAC;CAEF,MAAM,uBAAuB,YAA8C;EAC1E,QAAQ,kBAAkB,OAAO,GAAjC;GACC,KAAK,aACJ,OAAO,qBAAqB,OAAO;GACpC,KAAK,UACJ,OAAO,kBAAkB,OAAO;GACjC,SACC,OAAO,gBAAgB,OAAO;EAChC;CACD;CAEA,MAAM,YAAY,YAA6B,oBAAoB,OAAO;CAE1E,SAAS,uBAAuB;CAChC,SAAS,gBAAgB;CACzB,SAAS,OAAO;CAChB,SAAS,QAAQA,OAAe;CAEhC,SAAS,kBAAkB,YAAoB;EAC9C,MAAM,IAAI,iBAAiB;GAAE;GAAS,WAAW;EAAiB,CAAC;CACpE;CACA,SAAS,qBAAqB,SAAS;CACvC,SAAS,cAAc,YAAoB;EAC1C,MAAM,IAAI,iBAAiB;GAAE;GAAS,WAAW;EAAa,CAAC;CAChE;CAEA,OAAO;AACR;;AAGA,MAAa,OAAO,WAAW"}
1
+ {"version":3,"file":"provider.js","names":["openaiProvider"],"sources":["../../src/lib/provider.ts"],"sourcesContent":["/**\n * Community Vercel AI SDK provider for the Neon AI Gateway.\n *\n * `createNeon()` returns a provider that routes each model to the best gateway\n * endpoint based on its id (Anthropic → native Messages, OpenAI → native\n * Responses incl. Codex, everything else → unified Chat Completions), so a single\n * `neon('claude-...')` call (same base URL + token) reaches the whole catalog.\n * Ids use the canonical Neon (unprefixed) form; the legacy `databricks-` prefix\n * is also accepted. Configure with the branch-scoped `NEON_AI_GATEWAY_BASE_URL` +\n * `NEON_AI_GATEWAY_TOKEN` emitted by `neonctl env pull` / `neon dev`, or pass\n * `baseURL` / `apiKey` explicitly.\n */\nimport { openai as openaiProvider } from \"@ai-sdk/openai\";\nimport type { ProviderErrorStructure } from \"@ai-sdk/openai-compatible\";\nimport {\n\ttype LanguageModelV3,\n\tNoSuchModelError,\n\ttype ProviderV3,\n} from \"@ai-sdk/provider\";\nimport {\n\ttype FetchFunction,\n\tgenerateId,\n\tloadApiKey,\n\tloadSetting,\n\twithoutTrailingSlash,\n\twithUserAgentSuffix,\n} from \"@ai-sdk/provider-utils\";\nimport { z } from \"zod/v4\";\nimport { NeonAnthropicLanguageModel } from \"./neon-anthropic-language-model.js\";\nimport { NeonChatLanguageModel } from \"./neon-chat-language-model.js\";\nimport type { NeonChatModelId } from \"./neon-chat-options.js\";\nimport { getNeonModelRoute } from \"./neon-model-capabilities.js\";\nimport { NeonResponsesLanguageModel } from \"./neon-responses-language-model.js\";\nimport { VERSION } from \"./version.js\";\n\nconst neonErrorSchema = z.object({\n\terror: z.object({\n\t\tmessage: z.string(),\n\t\ttype: z.string().nullish(),\n\t\tparam: z.unknown().nullish(),\n\t\tcode: z.unknown().nullish(),\n\t}),\n});\n\nexport type NeonErrorData = z.infer<typeof neonErrorSchema>;\n\nconst neonErrorStructure: ProviderErrorStructure<NeonErrorData> = {\n\terrorSchema: neonErrorSchema,\n\terrorToMessage: (data) => data.error.message,\n};\n\n/**\n * Recursively remove the JSON Schema `$schema` marker, which some gateway\n * backends (notably Gemini) reject in tool/structured-output schemas. Other\n * backends ignore its absence, so stripping it everywhere is safe.\n */\nfunction stripJsonSchemaMarker(value: unknown): unknown {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(stripJsonSchemaMarker);\n\t}\n\tif (value !== null && typeof value === \"object\") {\n\t\tconst result: Record<string, unknown> = {};\n\t\tfor (const [key, entry] of Object.entries(value)) {\n\t\t\tif (key === \"$schema\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult[key] = stripJsonSchemaMarker(entry);\n\t\t}\n\t\treturn result;\n\t}\n\treturn value;\n}\n\nfunction transformNeonRequestBody(\n\targs: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst transformed = { ...args };\n\tif (transformed.tools != null) {\n\t\ttransformed.tools = stripJsonSchemaMarker(transformed.tools);\n\t}\n\tif (transformed.response_format != null) {\n\t\ttransformed.response_format = stripJsonSchemaMarker(\n\t\t\ttransformed.response_format,\n\t\t);\n\t}\n\treturn transformed;\n}\n\nexport interface NeonProviderSettings {\n\t/**\n\t * Neon AI Gateway base URL — the branch-scoped host root, e.g.\n\t * `https://<branch-id>-api.ai.<region>.aws.neon.tech`. The gateway paths are\n\t * appended internally. Falls back to the `NEON_AI_GATEWAY_BASE_URL` env var.\n\t */\n\tbaseURL?: string;\n\n\t/**\n\t * Neon AI Gateway platform token (the `nt_live_...` value). Falls back to the\n\t * `NEON_AI_GATEWAY_TOKEN` env var.\n\t */\n\tapiKey?: string;\n\n\t/** Custom headers to include in the requests. */\n\theaders?: Record<string, string>;\n\n\t/** Custom fetch implementation (e.g. for testing or middleware). */\n\tfetch?: FetchFunction;\n}\n\nexport interface NeonProvider extends ProviderV3 {\n\t/** Creates a Neon AI Gateway model for text generation. */\n\t(modelId: NeonChatModelId): LanguageModelV3;\n\n\t/** Creates a Neon AI Gateway model for text generation. */\n\tlanguageModel(modelId: NeonChatModelId): LanguageModelV3;\n\n\t/** Creates a Neon AI Gateway chat model for text generation. */\n\tchat(modelId: NeonChatModelId): LanguageModelV3;\n\n\t/** OpenAI Responses tools (e.g. `imageGeneration`) for OpenAI-routed models. */\n\ttools: typeof openaiProvider.tools;\n\n\t/** @deprecated Use `embeddingModel` instead. */\n\ttextEmbeddingModel(modelId: string): never;\n}\n\nexport function createNeon(options: NeonProviderSettings = {}): NeonProvider {\n\t// Resolved lazily so that `createNeon()` and the default `neon` instance do\n\t// not throw at import time when configuration comes from the environment.\n\tconst getHost = () =>\n\t\twithoutTrailingSlash(\n\t\t\tloadSetting({\n\t\t\t\tsettingValue: options.baseURL,\n\t\t\t\tenvironmentVariableName: \"NEON_AI_GATEWAY_BASE_URL\",\n\t\t\t\tsettingName: \"baseURL\",\n\t\t\t\tdescription: \"Neon AI Gateway base URL\",\n\t\t\t}),\n\t\t);\n\n\tconst getHeaders = (extra?: Record<string, string>) =>\n\t\twithUserAgentSuffix(\n\t\t\t{\n\t\t\t\tAuthorization: `Bearer ${loadApiKey({\n\t\t\t\t\tapiKey: options.apiKey,\n\t\t\t\t\tenvironmentVariableName: \"NEON_AI_GATEWAY_TOKEN\",\n\t\t\t\t\tdescription: \"Neon AI Gateway token\",\n\t\t\t\t})}`,\n\t\t\t\t...extra,\n\t\t\t\t...options.headers,\n\t\t\t},\n\t\t\t`neondatabase/ai-sdk-provider/${VERSION}`,\n\t\t);\n\n\t// Anthropic models -> native Messages API.\n\tconst createAnthropicModel = (modelId: NeonChatModelId) =>\n\t\tnew NeonAnthropicLanguageModel(modelId, {\n\t\t\tprovider: \"neon.anthropic\",\n\t\t\tbaseURL: `${getHost()}/anthropic/v1`,\n\t\t\theaders: () => getHeaders({ \"anthropic-version\": \"2023-06-01\" }),\n\t\t\tfetch: options.fetch,\n\t\t\tgenerateId,\n\t\t});\n\n\t// OpenAI models (incl. Codex, only served natively) -> Responses API.\n\tconst createOpenAIModel = (modelId: NeonChatModelId) =>\n\t\tnew NeonResponsesLanguageModel(modelId, {\n\t\t\tprovider: \"neon.openai.responses\",\n\t\t\turl: ({ path }) => `${getHost()}/openai/v1${path}`,\n\t\t\theaders: getHeaders,\n\t\t\tfetch: options.fetch,\n\t\t\tfileIdPrefixes: [\"file-\"],\n\t\t});\n\n\t// Everything else (Gemini, Llama, Qwen, gpt-oss, ...) -> unified Chat\n\t// Completions endpoint. Gemini is here because its native endpoint can't stream.\n\tconst createChatModel = (modelId: NeonChatModelId) =>\n\t\tnew NeonChatLanguageModel(modelId, {\n\t\t\tprovider: \"neon.chat\",\n\t\t\turl: ({ path }) => `${getHost()}/v1${path}`,\n\t\t\theaders: getHeaders,\n\t\t\tfetch: options.fetch,\n\t\t\terrorStructure: neonErrorStructure,\n\t\t\ttransformRequestBody: transformNeonRequestBody,\n\t\t\tsupportsStructuredOutputs: true,\n\t\t});\n\n\tconst createLanguageModel = (modelId: NeonChatModelId): LanguageModelV3 => {\n\t\tswitch (getNeonModelRoute(modelId)) {\n\t\t\tcase \"anthropic\":\n\t\t\t\treturn createAnthropicModel(modelId);\n\t\t\tcase \"openai\":\n\t\t\t\treturn createOpenAIModel(modelId);\n\t\t\tdefault:\n\t\t\t\treturn createChatModel(modelId);\n\t\t}\n\t};\n\n\tconst provider = (modelId: NeonChatModelId) => createLanguageModel(modelId);\n\n\tprovider.specificationVersion = \"v3\" as const;\n\tprovider.languageModel = createLanguageModel;\n\tprovider.chat = createLanguageModel;\n\tprovider.tools = openaiProvider.tools;\n\n\tprovider.embeddingModel = (modelId: string) => {\n\t\tthrow new NoSuchModelError({ modelId, modelType: \"embeddingModel\" });\n\t};\n\tprovider.textEmbeddingModel = provider.embeddingModel;\n\tprovider.imageModel = (modelId: string) => {\n\t\tthrow new NoSuchModelError({ modelId, modelType: \"imageModel\" });\n\t};\n\n\treturn provider;\n}\n\n/** Default Neon provider instance (reads `NEON_AI_GATEWAY_*` env vars). */\nexport const neon = createNeon();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAM,qBAA4D;CACjE,aAZuB,EAAE,OAAO,EAChC,OAAO,EAAE,OAAO;EACf,SAAS,EAAE,OAAO;EAClB,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ;EACzB,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ;EAC3B,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ;CAC3B,CAAC,EACF,CAK4B;CAC3B,iBAAiB,SAAS,KAAK,MAAM;AACtC;;;;;;AAOA,SAAS,sBAAsB,OAAyB;CACvD,IAAI,MAAM,QAAQ,KAAK,GACtB,OAAO,MAAM,IAAI,qBAAqB;CAEvC,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;EAChD,MAAM,SAAkC,CAAC;EACzC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;GACjD,IAAI,QAAQ,WACX;GAED,OAAO,OAAO,sBAAsB,KAAK;EAC1C;EACA,OAAO;CACR;CACA,OAAO;AACR;AAEA,SAAS,yBACR,MAC0B;CAC1B,MAAM,cAAc,EAAE,GAAG,KAAK;CAC9B,IAAI,YAAY,SAAS,MACxB,YAAY,QAAQ,sBAAsB,YAAY,KAAK;CAE5D,IAAI,YAAY,mBAAmB,MAClC,YAAY,kBAAkB,sBAC7B,YAAY,eACb;CAED,OAAO;AACR;AAwCA,SAAgB,WAAW,UAAgC,CAAC,GAAiB;CAG5E,MAAM,gBACL,qBACC,YAAY;EACX,cAAc,QAAQ;EACtB,yBAAyB;EACzB,aAAa;EACb,aAAa;CACd,CAAC,CACF;CAED,MAAM,cAAc,UACnB,oBACC;EACC,eAAe,UAAU,WAAW;GACnC,QAAQ,QAAQ;GAChB,yBAAyB;GACzB,aAAa;EACd,CAAC;EACD,GAAG;EACH,GAAG,QAAQ;CACZ,GACA,gCAAgC,SACjC;CAGD,MAAM,wBAAwB,YAC7B,IAAI,2BAA2B,SAAS;EACvC,UAAU;EACV,SAAS,GAAG,QAAQ,EAAE;EACtB,eAAe,WAAW,EAAE,qBAAqB,aAAa,CAAC;EAC/D,OAAO,QAAQ;EACf;CACD,CAAC;CAGF,MAAM,qBAAqB,YAC1B,IAAI,2BAA2B,SAAS;EACvC,UAAU;EACV,MAAM,EAAE,WAAW,GAAG,QAAQ,EAAE,YAAY;EAC5C,SAAS;EACT,OAAO,QAAQ;EACf,gBAAgB,CAAC,OAAO;CACzB,CAAC;CAIF,MAAM,mBAAmB,YACxB,IAAI,sBAAsB,SAAS;EAClC,UAAU;EACV,MAAM,EAAE,WAAW,GAAG,QAAQ,EAAE,KAAK;EACrC,SAAS;EACT,OAAO,QAAQ;EACf,gBAAgB;EAChB,sBAAsB;EACtB,2BAA2B;CAC5B,CAAC;CAEF,MAAM,uBAAuB,YAA8C;EAC1E,QAAQ,kBAAkB,OAAO,GAAjC;GACC,KAAK,aACJ,OAAO,qBAAqB,OAAO;GACpC,KAAK,UACJ,OAAO,kBAAkB,OAAO;GACjC,SACC,OAAO,gBAAgB,OAAO;EAChC;CACD;CAEA,MAAM,YAAY,YAA6B,oBAAoB,OAAO;CAE1E,SAAS,uBAAuB;CAChC,SAAS,gBAAgB;CACzB,SAAS,OAAO;CAChB,SAAS,QAAQA,OAAe;CAEhC,SAAS,kBAAkB,YAAoB;EAC9C,MAAM,IAAI,iBAAiB;GAAE;GAAS,WAAW;EAAiB,CAAC;CACpE;CACA,SAAS,qBAAqB,SAAS;CACvC,SAAS,cAAc,YAAoB;EAC1C,MAAM,IAAI,iBAAiB;GAAE;GAAS,WAAW;EAAa,CAAC;CAChE;CAEA,OAAO;AACR;;AAGA,MAAa,OAAO,WAAW"}
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.5.0";
2
+ var version = "0.7.0";
3
3
  //#endregion
4
4
  export { version };
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neon/ai-sdk-provider",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Community Vercel AI SDK provider for the Neon AI Gateway.",
5
5
  "keywords": [
6
6
  "neon",
@@ -38,16 +38,16 @@
38
38
  ],
39
39
  "devDependencies": {
40
40
  "@types/node": "^20.19.0",
41
- "@vitest/coverage-v8": "3.0.9",
41
+ "@vitest/coverage-v8": "^3.0.9",
42
42
  "ai": "6.0.132",
43
43
  "console-fail-test": "0.5.0",
44
44
  "tsdown": "^0.14.1",
45
- "typescript": "^5.8.2",
45
+ "typescript": "^5.9.0",
46
46
  "vitest": "^3.0.9",
47
47
  "zod": "^4.4.3"
48
48
  },
49
49
  "engines": {
50
- "node": ">=22"
50
+ "node": ">=20.19.0"
51
51
  },
52
52
  "publishConfig": {
53
53
  "provenance": false