@discomedia/utils 1.0.61 → 1.0.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1148,6 +1148,8 @@ function isOpenRouterModel(model) {
1148
1148
  'openai/gpt-5-mini',
1149
1149
  'openai/gpt-5-nano',
1150
1150
  'openai/gpt-5.1',
1151
+ 'openai/gpt-5.4',
1152
+ 'openai/gpt-5.4-pro',
1151
1153
  'openai/gpt-5.2',
1152
1154
  'openai/gpt-5.2-pro',
1153
1155
  'openai/gpt-5.1-codex',
@@ -1577,7 +1579,7 @@ function maybeObj(x) {
1577
1579
  return x ?? {};
1578
1580
  }
1579
1581
  // https://stackoverflow.com/a/34491287
1580
- function isEmptyObj(obj) {
1582
+ function isEmptyObj$1(obj) {
1581
1583
  if (!obj)
1582
1584
  return true;
1583
1585
  for (const _k in obj)
@@ -3316,6 +3318,20 @@ let Messages$1 = class Messages extends APIResource {
3316
3318
  function isChatCompletionFunctionTool(tool) {
3317
3319
  return tool !== undefined && 'function' in tool && tool.function !== undefined;
3318
3320
  }
3321
+ function makeParseableTextFormat(response_format, parser) {
3322
+ const obj = { ...response_format };
3323
+ Object.defineProperties(obj, {
3324
+ $brand: {
3325
+ value: 'auto-parseable-response-format',
3326
+ enumerable: false,
3327
+ },
3328
+ $parseRaw: {
3329
+ value: parser,
3330
+ enumerable: false,
3331
+ },
3332
+ });
3333
+ return obj;
3334
+ }
3319
3335
  function isAutoParsableResponseFormat(response_format) {
3320
3336
  return response_format?.['$brand'] === 'auto-parseable-response-format';
3321
3337
  }
@@ -5328,7 +5344,7 @@ const readEnv = (env) => {
5328
5344
  return undefined;
5329
5345
  };
5330
5346
 
5331
- var _AssistantStream_instances, _a$1, _AssistantStream_events, _AssistantStream_runStepSnapshots, _AssistantStream_messageSnapshots, _AssistantStream_messageSnapshot, _AssistantStream_finalRun, _AssistantStream_currentContentIndex, _AssistantStream_currentContent, _AssistantStream_currentToolCallIndex, _AssistantStream_currentToolCall, _AssistantStream_currentEvent, _AssistantStream_currentRunSnapshot, _AssistantStream_currentRunStepSnapshot, _AssistantStream_addEvent, _AssistantStream_endRequest, _AssistantStream_handleMessage, _AssistantStream_handleRunStep, _AssistantStream_handleEvent, _AssistantStream_accumulateRunStep, _AssistantStream_accumulateMessage, _AssistantStream_accumulateContent, _AssistantStream_handleRun;
5347
+ var _AssistantStream_instances, _a$2, _AssistantStream_events, _AssistantStream_runStepSnapshots, _AssistantStream_messageSnapshots, _AssistantStream_messageSnapshot, _AssistantStream_finalRun, _AssistantStream_currentContentIndex, _AssistantStream_currentContent, _AssistantStream_currentToolCallIndex, _AssistantStream_currentToolCall, _AssistantStream_currentEvent, _AssistantStream_currentRunSnapshot, _AssistantStream_currentRunStepSnapshot, _AssistantStream_addEvent, _AssistantStream_endRequest, _AssistantStream_handleMessage, _AssistantStream_handleRunStep, _AssistantStream_handleEvent, _AssistantStream_accumulateRunStep, _AssistantStream_accumulateMessage, _AssistantStream_accumulateContent, _AssistantStream_handleRun;
5332
5348
  class AssistantStream extends EventStream {
5333
5349
  constructor() {
5334
5350
  super(...arguments);
@@ -5403,7 +5419,7 @@ class AssistantStream extends EventStream {
5403
5419
  };
5404
5420
  }
5405
5421
  static fromReadableStream(stream) {
5406
- const runner = new _a$1();
5422
+ const runner = new _a$2();
5407
5423
  runner._run(() => runner._fromReadableStream(stream));
5408
5424
  return runner;
5409
5425
  }
@@ -5429,7 +5445,7 @@ class AssistantStream extends EventStream {
5429
5445
  return stream.toReadableStream();
5430
5446
  }
5431
5447
  static createToolAssistantStream(runId, runs, params, options) {
5432
- const runner = new _a$1();
5448
+ const runner = new _a$2();
5433
5449
  runner._run(() => runner._runToolAssistantStream(runId, runs, params, {
5434
5450
  ...options,
5435
5451
  headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'stream' },
@@ -5458,7 +5474,7 @@ class AssistantStream extends EventStream {
5458
5474
  return this._addRun(__classPrivateFieldGet(this, _AssistantStream_instances, "m", _AssistantStream_endRequest).call(this));
5459
5475
  }
5460
5476
  static createThreadAssistantStream(params, thread, options) {
5461
- const runner = new _a$1();
5477
+ const runner = new _a$2();
5462
5478
  runner._run(() => runner._threadAssistantStream(params, thread, {
5463
5479
  ...options,
5464
5480
  headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'stream' },
@@ -5466,7 +5482,7 @@ class AssistantStream extends EventStream {
5466
5482
  return runner;
5467
5483
  }
5468
5484
  static createAssistantStream(threadId, runs, params, options) {
5469
- const runner = new _a$1();
5485
+ const runner = new _a$2();
5470
5486
  runner._run(() => runner._runAssistantStream(threadId, runs, params, {
5471
5487
  ...options,
5472
5488
  headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'stream' },
@@ -5608,7 +5624,7 @@ class AssistantStream extends EventStream {
5608
5624
  return await this._createToolAssistantStream(runs, runId, params, options);
5609
5625
  }
5610
5626
  }
5611
- _a$1 = AssistantStream, _AssistantStream_addEvent = function _AssistantStream_addEvent(event) {
5627
+ _a$2 = AssistantStream, _AssistantStream_addEvent = function _AssistantStream_addEvent(event) {
5612
5628
  if (this.ended)
5613
5629
  return;
5614
5630
  __classPrivateFieldSet(this, _AssistantStream_currentEvent, event);
@@ -5786,7 +5802,7 @@ _a$1 = AssistantStream, _AssistantStream_addEvent = function _AssistantStream_ad
5786
5802
  }
5787
5803
  let data = event.data;
5788
5804
  if (data.delta) {
5789
- const accumulated = _a$1.accumulateDelta(snapshot, data.delta);
5805
+ const accumulated = _a$2.accumulateDelta(snapshot, data.delta);
5790
5806
  __classPrivateFieldGet(this, _AssistantStream_runStepSnapshots, "f")[event.data.id] = accumulated;
5791
5807
  }
5792
5808
  return __classPrivateFieldGet(this, _AssistantStream_runStepSnapshots, "f")[event.data.id];
@@ -5840,7 +5856,7 @@ _a$1 = AssistantStream, _AssistantStream_addEvent = function _AssistantStream_ad
5840
5856
  }
5841
5857
  throw Error('Tried to accumulate a non-message event');
5842
5858
  }, _AssistantStream_accumulateContent = function _AssistantStream_accumulateContent(contentElement, currentContent) {
5843
- return _a$1.accumulateDelta(currentContent, contentElement);
5859
+ return _a$2.accumulateDelta(currentContent, contentElement);
5844
5860
  }, _AssistantStream_handleRun = function _AssistantStream_handleRun(event) {
5845
5861
  __classPrivateFieldSet(this, _AssistantStream_currentRunSnapshot, event.data);
5846
5862
  switch (event.event) {
@@ -8258,7 +8274,7 @@ _Webhooks_instances = new WeakSet(), _Webhooks_validateSecret = function _Webhoo
8258
8274
  };
8259
8275
 
8260
8276
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8261
- var _OpenAI_instances, _a, _OpenAI_encoder, _OpenAI_baseURLOverridden;
8277
+ var _OpenAI_instances, _a$1, _OpenAI_encoder, _OpenAI_baseURLOverridden;
8262
8278
  /**
8263
8279
  * API Client for interfacing with the OpenAI API.
8264
8280
  */
@@ -8349,7 +8365,7 @@ class OpenAI {
8349
8365
  throw new OpenAIError("It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n");
8350
8366
  }
8351
8367
  this.baseURL = options.baseURL;
8352
- this.timeout = options.timeout ?? _a.DEFAULT_TIMEOUT /* 10 minutes */;
8368
+ this.timeout = options.timeout ?? _a$1.DEFAULT_TIMEOUT /* 10 minutes */;
8353
8369
  this.logger = options.logger ?? console;
8354
8370
  const defaultLogLevel = 'warn';
8355
8371
  // Set default logLevel early so that we can log a warning in parseLogLevel.
@@ -8437,7 +8453,7 @@ class OpenAI {
8437
8453
  new URL(path)
8438
8454
  : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
8439
8455
  const defaultQuery = this.defaultQuery();
8440
- if (!isEmptyObj(defaultQuery)) {
8456
+ if (!isEmptyObj$1(defaultQuery)) {
8441
8457
  query = { ...defaultQuery, ...query };
8442
8458
  }
8443
8459
  if (typeof query === 'object' && query && !Array.isArray(query)) {
@@ -8779,10 +8795,10 @@ class OpenAI {
8779
8795
  }
8780
8796
  }
8781
8797
  }
8782
- _a = OpenAI, _OpenAI_encoder = new WeakMap(), _OpenAI_instances = new WeakSet(), _OpenAI_baseURLOverridden = function _OpenAI_baseURLOverridden() {
8798
+ _a$1 = OpenAI, _OpenAI_encoder = new WeakMap(), _OpenAI_instances = new WeakSet(), _OpenAI_baseURLOverridden = function _OpenAI_baseURLOverridden() {
8783
8799
  return this.baseURL !== 'https://api.openai.com/v1';
8784
8800
  };
8785
- OpenAI.OpenAI = _a;
8801
+ OpenAI.OpenAI = _a$1;
8786
8802
  OpenAI.DEFAULT_TIMEOUT = 600000; // 10 minutes
8787
8803
  OpenAI.OpenAIError = OpenAIError;
8788
8804
  OpenAI.APIError = APIError;
@@ -8822,238 +8838,3050 @@ OpenAI.Containers = Containers;
8822
8838
  OpenAI.Skills = Skills;
8823
8839
  OpenAI.Videos = Videos;
8824
8840
 
8825
- // llm-openai-config.ts
8826
- const DEFAULT_MODEL = 'gpt-4.1-mini';
8827
- /** Token costs in USD per 1M tokens. Last updated Feb 2025. */
8828
- const openAiModelCosts = {
8829
- 'gpt-4o': {
8830
- inputCost: 2.5 / 1_000_000,
8831
- outputCost: 10 / 1_000_000,
8832
- },
8833
- 'gpt-4o-mini': {
8834
- inputCost: 0.15 / 1_000_000,
8835
- outputCost: 0.6 / 1_000_000,
8836
- },
8837
- 'o1-mini': {
8838
- inputCost: 1.1 / 1_000_000,
8839
- outputCost: 4.4 / 1_000_000,
8840
- },
8841
- 'o1': {
8842
- inputCost: 15 / 1_000_000,
8843
- outputCost: 60 / 1_000_000,
8844
- },
8845
- 'o3-mini': {
8846
- inputCost: 1.1 / 1_000_000,
8847
- outputCost: 4.4 / 1_000_000,
8848
- },
8849
- 'o3': {
8850
- inputCost: 2 / 1_000_000,
8851
- outputCost: 8 / 1_000_000,
8852
- },
8853
- 'gpt-4.1': {
8854
- inputCost: 2 / 1_000_000,
8855
- outputCost: 8 / 1_000_000,
8856
- },
8857
- 'gpt-4.1-mini': {
8858
- inputCost: 0.4 / 1_000_000,
8859
- outputCost: 1.6 / 1_000_000,
8860
- },
8861
- 'gpt-4.1-nano': {
8862
- inputCost: 0.1 / 1_000_000,
8863
- outputCost: 0.4 / 1_000_000,
8864
- },
8865
- 'gpt-5': {
8866
- inputCost: 1.25 / 1_000_000,
8867
- outputCost: 10 / 1_000_000,
8868
- },
8869
- 'gpt-5-mini': {
8870
- inputCost: 0.25 / 1_000_000,
8871
- outputCost: 2 / 1_000_000,
8872
- },
8873
- 'gpt-5-nano': {
8874
- inputCost: 0.05 / 1_000_000,
8875
- outputCost: 0.4 / 1_000_000,
8876
- },
8877
- 'gpt-5.1': {
8878
- inputCost: 1.25 / 1_000_000,
8879
- outputCost: 10 / 1_000_000,
8880
- },
8881
- 'gpt-5.2': {
8882
- inputCost: 1.5 / 1_000_000,
8883
- outputCost: 12 / 1_000_000,
8884
- },
8885
- 'gpt-5.2-pro': {
8886
- inputCost: 3 / 1_000_000,
8887
- outputCost: 24 / 1_000_000,
8888
- },
8889
- 'gpt-5.1-codex': {
8890
- inputCost: 1.1 / 1_000_000,
8891
- outputCost: 8.8 / 1_000_000,
8892
- },
8893
- 'gpt-5.1-codex-max': {
8894
- inputCost: 1.8 / 1_000_000,
8895
- outputCost: 14.4 / 1_000_000,
8896
- },
8897
- 'o4-mini': {
8898
- inputCost: 1.1 / 1_000_000,
8899
- outputCost: 4.4 / 1_000_000,
8900
- },
8901
- };
8902
- const deepseekModelCosts = {
8903
- 'deepseek-chat': {
8904
- inputCost: 0.27 / 1_000_000, // $0.27 per 1M tokens (Cache miss price)
8905
- cacheHitCost: 0.07 / 1_000_000, // $0.07 per 1M tokens (Cache hit price)
8906
- outputCost: 1.1 / 1_000_000, // $1.10 per 1M tokens
8907
- },
8908
- 'deepseek-reasoner': {
8909
- inputCost: 0.55 / 1_000_000, // $0.55 per 1M tokens (Cache miss price)
8910
- cacheHitCost: 0.14 / 1_000_000, // $0.14 per 1M tokens (Cache hit price)
8911
- outputCost: 2.19 / 1_000_000, // $2.19 per 1M tokens
8912
- },
8913
- };
8914
- /** Image generation costs in USD per image. Based on OpenAI pricing as of Feb 2025. */
8915
- const openAiImageCosts = {
8916
- 'gpt-image-1': 0.0075, // $0.0075 per image for gpt-image-1
8917
- 'gpt-image-1.5': 0.0075, // Assumes parity pricing with gpt-image-1 until OpenAI publishes updated rates
8918
- };
8919
- /**
8920
- * Calculates the cost of generating images using OpenAI's Images API.
8921
- *
8922
- * @param model The image generation model name.
8923
- * @param imageCount The number of images generated.
8924
- * @returns The cost of generating the images in USD.
8925
- */
8926
- function calculateImageCost(model, imageCount) {
8927
- if (typeof model !== 'string' || typeof imageCount !== 'number' || imageCount <= 0) {
8928
- return 0;
8841
+ // functions
8842
+ function getEnumValues(entries) {
8843
+ const numericValues = Object.values(entries).filter((v) => typeof v === "number");
8844
+ const values = Object.entries(entries)
8845
+ .filter(([k, _]) => numericValues.indexOf(+k) === -1)
8846
+ .map(([_, v]) => v);
8847
+ return values;
8848
+ }
8849
+
8850
+ var _a;
8851
+ class $ZodRegistry {
8852
+ constructor() {
8853
+ this._map = new WeakMap();
8854
+ this._idmap = new Map();
8855
+ }
8856
+ add(schema, ..._meta) {
8857
+ const meta = _meta[0];
8858
+ this._map.set(schema, meta);
8859
+ if (meta && typeof meta === "object" && "id" in meta) {
8860
+ this._idmap.set(meta.id, schema);
8861
+ }
8862
+ return this;
8863
+ }
8864
+ clear() {
8865
+ this._map = new WeakMap();
8866
+ this._idmap = new Map();
8867
+ return this;
8868
+ }
8869
+ remove(schema) {
8870
+ const meta = this._map.get(schema);
8871
+ if (meta && typeof meta === "object" && "id" in meta) {
8872
+ this._idmap.delete(meta.id);
8873
+ }
8874
+ this._map.delete(schema);
8875
+ return this;
8876
+ }
8877
+ get(schema) {
8878
+ // return this._map.get(schema) as any;
8879
+ // inherit metadata
8880
+ const p = schema._zod.parent;
8881
+ if (p) {
8882
+ const pm = { ...(this.get(p) ?? {}) };
8883
+ delete pm.id; // do not inherit id
8884
+ const f = { ...pm, ...this._map.get(schema) };
8885
+ return Object.keys(f).length ? f : undefined;
8886
+ }
8887
+ return this._map.get(schema);
8888
+ }
8889
+ has(schema) {
8890
+ return this._map.has(schema);
8929
8891
  }
8930
- const costPerImage = openAiImageCosts[model];
8931
- if (!costPerImage)
8932
- return 0;
8933
- return imageCount * costPerImage;
8934
8892
  }
8935
- /**
8936
- * Calculates the cost of calling a language model in USD based on the provider and model, tokens, and given costs per 1M tokens.
8937
- *
8938
- * @param provider The provider of the language model. Supported providers are 'openai' and 'deepseek'.
8939
- * @param model The name of the language model. Supported models are listed in the `openAiModelCosts` and `deepseekModelCosts` objects.
8940
- * @param inputTokens The number of input tokens passed to the language model.
8941
- * @param outputTokens The number of output tokens generated by the language model.
8942
- * @param reasoningTokens The number of output tokens generated by the language model for reasoning. This is only used for Deepseek models.
8943
- * @param cacheHitTokens The number of input tokens that were cache hits for Deepseek models.
8944
- * @returns The cost of calling the language model in USD.
8945
- */
8946
- function calculateCost(provider, model, inputTokens, outputTokens, reasoningTokens, cacheHitTokens) {
8947
- if (typeof provider !== 'string' ||
8948
- typeof model !== 'string' ||
8949
- typeof inputTokens !== 'number' ||
8950
- typeof outputTokens !== 'number' ||
8951
- (reasoningTokens !== undefined && typeof reasoningTokens !== 'number') ||
8952
- (cacheHitTokens !== undefined && typeof cacheHitTokens !== 'number')) {
8953
- return 0;
8893
+ // registries
8894
+ function registry() {
8895
+ return new $ZodRegistry();
8896
+ }
8897
+ (_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry());
8898
+ const globalRegistry = globalThis.__zod_globalRegistry;
8899
+
8900
+ // function initializeContext<T extends schemas.$ZodType>(inputs: JSONSchemaGeneratorParams<T>): ToJSONSchemaContext<T> {
8901
+ // return {
8902
+ // processor: inputs.processor,
8903
+ // metadataRegistry: inputs.metadata ?? globalRegistry,
8904
+ // target: inputs.target ?? "draft-2020-12",
8905
+ // unrepresentable: inputs.unrepresentable ?? "throw",
8906
+ // };
8907
+ // }
8908
+ function initializeContext(params) {
8909
+ // Normalize target: convert old non-hyphenated versions to hyphenated versions
8910
+ let target = params?.target ?? "draft-2020-12";
8911
+ if (target === "draft-4")
8912
+ target = "draft-04";
8913
+ if (target === "draft-7")
8914
+ target = "draft-07";
8915
+ return {
8916
+ processors: params.processors ?? {},
8917
+ metadataRegistry: params?.metadata ?? globalRegistry,
8918
+ target,
8919
+ unrepresentable: params?.unrepresentable ?? "throw",
8920
+ override: params?.override ?? (() => { }),
8921
+ io: params?.io ?? "output",
8922
+ counter: 0,
8923
+ seen: new Map(),
8924
+ cycles: params?.cycles ?? "ref",
8925
+ reused: params?.reused ?? "inline",
8926
+ external: params?.external ?? undefined,
8927
+ };
8928
+ }
8929
+ function process$1(schema, ctx, _params = { path: [], schemaPath: [] }) {
8930
+ var _a;
8931
+ const def = schema._zod.def;
8932
+ // check for schema in seens
8933
+ const seen = ctx.seen.get(schema);
8934
+ if (seen) {
8935
+ seen.count++;
8936
+ // check if cycle
8937
+ const isCycle = _params.schemaPath.includes(schema);
8938
+ if (isCycle) {
8939
+ seen.cycle = _params.path;
8940
+ }
8941
+ return seen.schema;
8942
+ }
8943
+ // initialize
8944
+ const result = { schema: {}, count: 1, cycle: undefined, path: _params.path };
8945
+ ctx.seen.set(schema, result);
8946
+ // custom method overrides default behavior
8947
+ const overrideSchema = schema._zod.toJSONSchema?.();
8948
+ if (overrideSchema) {
8949
+ result.schema = overrideSchema;
8954
8950
  }
8955
- const modelCosts = provider === 'deepseek' ? deepseekModelCosts[model] : openAiModelCosts[model];
8956
- if (!modelCosts)
8957
- return 0;
8958
- // Calculate input cost based on cache hit/miss for Deepseek
8959
- const inputCost = provider === 'deepseek' && modelCosts.cacheHitCost
8960
- ? (cacheHitTokens || 0) * modelCosts.cacheHitCost + (inputTokens - (cacheHitTokens || 0)) * modelCosts.inputCost
8961
- : inputTokens * modelCosts.inputCost;
8962
- const outputCost = outputTokens * modelCosts.outputCost;
8963
- const reasoningCost = (reasoningTokens || 0) * modelCosts.outputCost;
8964
- return inputCost + outputCost + reasoningCost;
8951
+ else {
8952
+ const params = {
8953
+ ..._params,
8954
+ schemaPath: [..._params.schemaPath, schema],
8955
+ path: _params.path,
8956
+ };
8957
+ if (schema._zod.processJSONSchema) {
8958
+ schema._zod.processJSONSchema(ctx, result.schema, params);
8959
+ }
8960
+ else {
8961
+ const _json = result.schema;
8962
+ const processor = ctx.processors[def.type];
8963
+ if (!processor) {
8964
+ throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`);
8965
+ }
8966
+ processor(schema, ctx, _json, params);
8967
+ }
8968
+ const parent = schema._zod.parent;
8969
+ if (parent) {
8970
+ // Also set ref if processor didn't (for inheritance)
8971
+ if (!result.ref)
8972
+ result.ref = parent;
8973
+ process$1(parent, ctx, params);
8974
+ ctx.seen.get(parent).isParent = true;
8975
+ }
8976
+ }
8977
+ // metadata
8978
+ const meta = ctx.metadataRegistry.get(schema);
8979
+ if (meta)
8980
+ Object.assign(result.schema, meta);
8981
+ if (ctx.io === "input" && isTransforming(schema)) {
8982
+ // examples/defaults only apply to output type of pipe
8983
+ delete result.schema.examples;
8984
+ delete result.schema.default;
8985
+ }
8986
+ // set prefault as default
8987
+ if (ctx.io === "input" && result.schema._prefault)
8988
+ (_a = result.schema).default ?? (_a.default = result.schema._prefault);
8989
+ delete result.schema._prefault;
8990
+ // pulling fresh from ctx.seen in case it was overwritten
8991
+ const _result = ctx.seen.get(schema);
8992
+ return _result.schema;
8965
8993
  }
8966
-
8967
- /**
8968
- * Fix a broken JSON string by attempting to extract and parse valid JSON content. This function is very lenient and will attempt to fix many types of JSON errors, including unbalanced brackets, missing or extra commas, improperly escaped $ signs, unquoted strings, trailing commas, missing closing brackets or braces, etc.
8969
- * @param {string} jsonStr - The broken JSON string to fix
8970
- * @returns {JsonValue} - The parsed JSON value
8971
- */
8972
- function fixBrokenJson(jsonStr) {
8973
- // Pre-process: Fix improperly escaped $ signs
8974
- jsonStr = jsonStr.replace(/\\\$/g, '$');
8975
- let index = 0;
8976
- function parse() {
8977
- const results = [];
8978
- while (index < jsonStr.length) {
8979
- skipWhitespace();
8980
- const value = parseValue();
8981
- if (value !== undefined) {
8982
- results.push(value);
8994
+ function extractDefs(ctx, schema
8995
+ // params: EmitParams
8996
+ ) {
8997
+ // iterate over seen map;
8998
+ const root = ctx.seen.get(schema);
8999
+ if (!root)
9000
+ throw new Error("Unprocessed schema. This is a bug in Zod.");
9001
+ // Track ids to detect duplicates across different schemas
9002
+ const idToSchema = new Map();
9003
+ for (const entry of ctx.seen.entries()) {
9004
+ const id = ctx.metadataRegistry.get(entry[0])?.id;
9005
+ if (id) {
9006
+ const existing = idToSchema.get(id);
9007
+ if (existing && existing !== entry[0]) {
9008
+ throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);
8983
9009
  }
8984
- else {
8985
- index++; // Skip invalid character
9010
+ idToSchema.set(id, entry[0]);
9011
+ }
9012
+ }
9013
+ // returns a ref to the schema
9014
+ // defId will be empty if the ref points to an external schema (or #)
9015
+ const makeURI = (entry) => {
9016
+ // comparing the seen objects because sometimes
9017
+ // multiple schemas map to the same seen object.
9018
+ // e.g. lazy
9019
+ // external is configured
9020
+ const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
9021
+ if (ctx.external) {
9022
+ const externalId = ctx.external.registry.get(entry[0])?.id; // ?? "__shared";// `__schema${ctx.counter++}`;
9023
+ // check if schema is in the external registry
9024
+ const uriGenerator = ctx.external.uri ?? ((id) => id);
9025
+ if (externalId) {
9026
+ return { ref: uriGenerator(externalId) };
9027
+ }
9028
+ // otherwise, add to __shared
9029
+ const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`;
9030
+ entry[1].defId = id; // set defId so it will be reused if needed
9031
+ return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` };
9032
+ }
9033
+ if (entry[1] === root) {
9034
+ return { ref: "#" };
9035
+ }
9036
+ // self-contained schema
9037
+ const uriPrefix = `#`;
9038
+ const defUriPrefix = `${uriPrefix}/${defsSegment}/`;
9039
+ const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`;
9040
+ return { defId, ref: defUriPrefix + defId };
9041
+ };
9042
+ // stored cached version in `def` property
9043
+ // remove all properties, set $ref
9044
+ const extractToDef = (entry) => {
9045
+ // if the schema is already a reference, do not extract it
9046
+ if (entry[1].schema.$ref) {
9047
+ return;
9048
+ }
9049
+ const seen = entry[1];
9050
+ const { ref, defId } = makeURI(entry);
9051
+ seen.def = { ...seen.schema };
9052
+ // defId won't be set if the schema is a reference to an external schema
9053
+ // or if the schema is the root schema
9054
+ if (defId)
9055
+ seen.defId = defId;
9056
+ // wipe away all properties except $ref
9057
+ const schema = seen.schema;
9058
+ for (const key in schema) {
9059
+ delete schema[key];
9060
+ }
9061
+ schema.$ref = ref;
9062
+ };
9063
+ // throw on cycles
9064
+ // break cycles
9065
+ if (ctx.cycles === "throw") {
9066
+ for (const entry of ctx.seen.entries()) {
9067
+ const seen = entry[1];
9068
+ if (seen.cycle) {
9069
+ throw new Error("Cycle detected: " +
9070
+ `#/${seen.cycle?.join("/")}/<root>` +
9071
+ '\n\nSet the `cycles` parameter to `"ref"` to resolve cyclical schemas with defs.');
8986
9072
  }
8987
9073
  }
8988
- return results.length === 1 ? results[0] : results;
8989
9074
  }
8990
- function parseValue() {
8991
- skipWhitespace();
8992
- const char = getChar();
8993
- if (!char)
8994
- return undefined;
8995
- if (char === '{')
8996
- return parseObject();
8997
- if (char === '[')
8998
- return parseArray();
8999
- if (char === '"' || char === "'")
9000
- return parseString();
9001
- if (char === 't' && jsonStr.slice(index, index + 4).toLowerCase() === 'true') {
9002
- index += 4;
9003
- return true;
9075
+ // extract schemas into $defs
9076
+ for (const entry of ctx.seen.entries()) {
9077
+ const seen = entry[1];
9078
+ // convert root schema to # $ref
9079
+ if (schema === entry[0]) {
9080
+ extractToDef(entry); // this has special handling for the root schema
9081
+ continue;
9004
9082
  }
9005
- if (char === 'f' && jsonStr.slice(index, index + 5).toLowerCase() === 'false') {
9006
- index += 5;
9007
- return false;
9083
+ // extract schemas that are in the external registry
9084
+ if (ctx.external) {
9085
+ const ext = ctx.external.registry.get(entry[0])?.id;
9086
+ if (schema !== entry[0] && ext) {
9087
+ extractToDef(entry);
9088
+ continue;
9089
+ }
9008
9090
  }
9009
- if (char === 'n' && jsonStr.slice(index, index + 4).toLowerCase() === 'null') {
9010
- index += 4;
9011
- return null;
9091
+ // extract schemas with `id` meta
9092
+ const id = ctx.metadataRegistry.get(entry[0])?.id;
9093
+ if (id) {
9094
+ extractToDef(entry);
9095
+ continue;
9012
9096
  }
9013
- if (/[a-zA-Z]/.test(char))
9014
- return parseString(); // Unquoted string
9015
- if (char === '-' || char === '.' || /\d/.test(char))
9016
- return parseNumber();
9017
- return undefined; // Unknown character
9018
- }
9019
- function parseObject() {
9020
- const obj = {};
9021
- index++; // Skip opening brace
9022
- skipWhitespace();
9023
- while (index < jsonStr.length && getChar() !== '}') {
9024
- skipWhitespace();
9025
- const key = parseString();
9026
- if (key === undefined) {
9027
- console.warn(`Expected key at position ${index}`);
9028
- index++;
9097
+ // break cycles
9098
+ if (seen.cycle) {
9099
+ // any
9100
+ extractToDef(entry);
9101
+ continue;
9102
+ }
9103
+ // extract reused schemas
9104
+ if (seen.count > 1) {
9105
+ if (ctx.reused === "ref") {
9106
+ extractToDef(entry);
9107
+ // biome-ignore lint:
9029
9108
  continue;
9030
9109
  }
9031
- skipWhitespace();
9032
- if (getChar() === ':') {
9033
- index++; // Skip colon
9110
+ }
9111
+ }
9112
+ }
9113
+ function finalize(ctx, schema) {
9114
+ const root = ctx.seen.get(schema);
9115
+ if (!root)
9116
+ throw new Error("Unprocessed schema. This is a bug in Zod.");
9117
+ // flatten refs - inherit properties from parent schemas
9118
+ const flattenRef = (zodSchema) => {
9119
+ const seen = ctx.seen.get(zodSchema);
9120
+ // already processed
9121
+ if (seen.ref === null)
9122
+ return;
9123
+ const schema = seen.def ?? seen.schema;
9124
+ const _cached = { ...schema };
9125
+ const ref = seen.ref;
9126
+ seen.ref = null; // prevent infinite recursion
9127
+ if (ref) {
9128
+ flattenRef(ref);
9129
+ const refSeen = ctx.seen.get(ref);
9130
+ const refSchema = refSeen.schema;
9131
+ // merge referenced schema into current
9132
+ if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) {
9133
+ // older drafts can't combine $ref with other properties
9134
+ schema.allOf = schema.allOf ?? [];
9135
+ schema.allOf.push(refSchema);
9034
9136
  }
9035
9137
  else {
9036
- console.warn(`Missing colon after key "${key}" at position ${index}`);
9138
+ Object.assign(schema, refSchema);
9037
9139
  }
9038
- skipWhitespace();
9039
- const value = parseValue();
9040
- if (value === undefined) {
9041
- console.warn(`Expected value for key "${key}" at position ${index}`);
9042
- index++;
9043
- continue;
9140
+ // restore child's own properties (child wins)
9141
+ Object.assign(schema, _cached);
9142
+ const isParentRef = zodSchema._zod.parent === ref;
9143
+ // For parent chain, child is a refinement - remove parent-only properties
9144
+ if (isParentRef) {
9145
+ for (const key in schema) {
9146
+ if (key === "$ref" || key === "allOf")
9147
+ continue;
9148
+ if (!(key in _cached)) {
9149
+ delete schema[key];
9150
+ }
9151
+ }
9044
9152
  }
9045
- obj[key] = value;
9046
- skipWhitespace();
9047
- if (getChar() === ',') {
9048
- index++; // Skip comma
9153
+ // When ref was extracted to $defs, remove properties that match the definition
9154
+ if (refSchema.$ref && refSeen.def) {
9155
+ for (const key in schema) {
9156
+ if (key === "$ref" || key === "allOf")
9157
+ continue;
9158
+ if (key in refSeen.def && JSON.stringify(schema[key]) === JSON.stringify(refSeen.def[key])) {
9159
+ delete schema[key];
9160
+ }
9161
+ }
9049
9162
  }
9050
- else {
9051
- break;
9163
+ }
9164
+ // If parent was extracted (has $ref), propagate $ref to this schema
9165
+ // This handles cases like: readonly().meta({id}).describe()
9166
+ // where processor sets ref to innerType but parent should be referenced
9167
+ const parent = zodSchema._zod.parent;
9168
+ if (parent && parent !== ref) {
9169
+ // Ensure parent is processed first so its def has inherited properties
9170
+ flattenRef(parent);
9171
+ const parentSeen = ctx.seen.get(parent);
9172
+ if (parentSeen?.schema.$ref) {
9173
+ schema.$ref = parentSeen.schema.$ref;
9174
+ // De-duplicate with parent's definition
9175
+ if (parentSeen.def) {
9176
+ for (const key in schema) {
9177
+ if (key === "$ref" || key === "allOf")
9178
+ continue;
9179
+ if (key in parentSeen.def && JSON.stringify(schema[key]) === JSON.stringify(parentSeen.def[key])) {
9180
+ delete schema[key];
9181
+ }
9182
+ }
9183
+ }
9052
9184
  }
9053
- skipWhitespace();
9054
9185
  }
9055
- if (getChar() === '}') {
9056
- index++; // Skip closing brace
9186
+ // execute overrides
9187
+ ctx.override({
9188
+ zodSchema: zodSchema,
9189
+ jsonSchema: schema,
9190
+ path: seen.path ?? [],
9191
+ });
9192
+ };
9193
+ for (const entry of [...ctx.seen.entries()].reverse()) {
9194
+ flattenRef(entry[0]);
9195
+ }
9196
+ const result = {};
9197
+ if (ctx.target === "draft-2020-12") {
9198
+ result.$schema = "https://json-schema.org/draft/2020-12/schema";
9199
+ }
9200
+ else if (ctx.target === "draft-07") {
9201
+ result.$schema = "http://json-schema.org/draft-07/schema#";
9202
+ }
9203
+ else if (ctx.target === "draft-04") {
9204
+ result.$schema = "http://json-schema.org/draft-04/schema#";
9205
+ }
9206
+ else if (ctx.target === "openapi-3.0") ;
9207
+ else ;
9208
+ if (ctx.external?.uri) {
9209
+ const id = ctx.external.registry.get(schema)?.id;
9210
+ if (!id)
9211
+ throw new Error("Schema is missing an `id` property");
9212
+ result.$id = ctx.external.uri(id);
9213
+ }
9214
+ Object.assign(result, root.def ?? root.schema);
9215
+ // build defs object
9216
+ const defs = ctx.external?.defs ?? {};
9217
+ for (const entry of ctx.seen.entries()) {
9218
+ const seen = entry[1];
9219
+ if (seen.def && seen.defId) {
9220
+ defs[seen.defId] = seen.def;
9221
+ }
9222
+ }
9223
+ // set definitions in result
9224
+ if (ctx.external) ;
9225
+ else {
9226
+ if (Object.keys(defs).length > 0) {
9227
+ if (ctx.target === "draft-2020-12") {
9228
+ result.$defs = defs;
9229
+ }
9230
+ else {
9231
+ result.definitions = defs;
9232
+ }
9233
+ }
9234
+ }
9235
+ try {
9236
+ // this "finalizes" this schema and ensures all cycles are removed
9237
+ // each call to finalize() is functionally independent
9238
+ // though the seen map is shared
9239
+ const finalized = JSON.parse(JSON.stringify(result));
9240
+ Object.defineProperty(finalized, "~standard", {
9241
+ value: {
9242
+ ...schema["~standard"],
9243
+ jsonSchema: {
9244
+ input: createStandardJSONSchemaMethod(schema, "input", ctx.processors),
9245
+ output: createStandardJSONSchemaMethod(schema, "output", ctx.processors),
9246
+ },
9247
+ },
9248
+ enumerable: false,
9249
+ writable: false,
9250
+ });
9251
+ return finalized;
9252
+ }
9253
+ catch (_err) {
9254
+ throw new Error("Error converting schema to JSON.");
9255
+ }
9256
+ }
9257
+ function isTransforming(_schema, _ctx) {
9258
+ const ctx = _ctx ?? { seen: new Set() };
9259
+ if (ctx.seen.has(_schema))
9260
+ return false;
9261
+ ctx.seen.add(_schema);
9262
+ const def = _schema._zod.def;
9263
+ if (def.type === "transform")
9264
+ return true;
9265
+ if (def.type === "array")
9266
+ return isTransforming(def.element, ctx);
9267
+ if (def.type === "set")
9268
+ return isTransforming(def.valueType, ctx);
9269
+ if (def.type === "lazy")
9270
+ return isTransforming(def.getter(), ctx);
9271
+ if (def.type === "promise" ||
9272
+ def.type === "optional" ||
9273
+ def.type === "nonoptional" ||
9274
+ def.type === "nullable" ||
9275
+ def.type === "readonly" ||
9276
+ def.type === "default" ||
9277
+ def.type === "prefault") {
9278
+ return isTransforming(def.innerType, ctx);
9279
+ }
9280
+ if (def.type === "intersection") {
9281
+ return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
9282
+ }
9283
+ if (def.type === "record" || def.type === "map") {
9284
+ return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
9285
+ }
9286
+ if (def.type === "pipe") {
9287
+ return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
9288
+ }
9289
+ if (def.type === "object") {
9290
+ for (const key in def.shape) {
9291
+ if (isTransforming(def.shape[key], ctx))
9292
+ return true;
9293
+ }
9294
+ return false;
9295
+ }
9296
+ if (def.type === "union") {
9297
+ for (const option of def.options) {
9298
+ if (isTransforming(option, ctx))
9299
+ return true;
9300
+ }
9301
+ return false;
9302
+ }
9303
+ if (def.type === "tuple") {
9304
+ for (const item of def.items) {
9305
+ if (isTransforming(item, ctx))
9306
+ return true;
9307
+ }
9308
+ if (def.rest && isTransforming(def.rest, ctx))
9309
+ return true;
9310
+ return false;
9311
+ }
9312
+ return false;
9313
+ }
9314
+ const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => {
9315
+ const { libraryOptions, target } = params ?? {};
9316
+ const ctx = initializeContext({ ...(libraryOptions ?? {}), target, io, processors });
9317
+ process$1(schema, ctx);
9318
+ extractDefs(ctx, schema);
9319
+ return finalize(ctx, schema);
9320
+ };
9321
+
9322
+ const formatMap = {
9323
+ guid: "uuid",
9324
+ url: "uri",
9325
+ datetime: "date-time",
9326
+ json_string: "json-string",
9327
+ regex: "", // do not set
9328
+ };
9329
+ // ==================== SIMPLE TYPE PROCESSORS ====================
9330
+ const stringProcessor = (schema, ctx, _json, _params) => {
9331
+ const json = _json;
9332
+ json.type = "string";
9333
+ const { minimum, maximum, format, patterns, contentEncoding } = schema._zod
9334
+ .bag;
9335
+ if (typeof minimum === "number")
9336
+ json.minLength = minimum;
9337
+ if (typeof maximum === "number")
9338
+ json.maxLength = maximum;
9339
+ // custom pattern overrides format
9340
+ if (format) {
9341
+ json.format = formatMap[format] ?? format;
9342
+ if (json.format === "")
9343
+ delete json.format; // empty format is not valid
9344
+ // JSON Schema format: "time" requires a full time with offset or Z
9345
+ // z.iso.time() does not include timezone information, so format: "time" should never be used
9346
+ if (format === "time") {
9347
+ delete json.format;
9348
+ }
9349
+ }
9350
+ if (contentEncoding)
9351
+ json.contentEncoding = contentEncoding;
9352
+ if (patterns && patterns.size > 0) {
9353
+ const regexes = [...patterns];
9354
+ if (regexes.length === 1)
9355
+ json.pattern = regexes[0].source;
9356
+ else if (regexes.length > 1) {
9357
+ json.allOf = [
9358
+ ...regexes.map((regex) => ({
9359
+ ...(ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0"
9360
+ ? { type: "string" }
9361
+ : {}),
9362
+ pattern: regex.source,
9363
+ })),
9364
+ ];
9365
+ }
9366
+ }
9367
+ };
9368
+ const numberProcessor = (schema, ctx, _json, _params) => {
9369
+ const json = _json;
9370
+ const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag;
9371
+ if (typeof format === "string" && format.includes("int"))
9372
+ json.type = "integer";
9373
+ else
9374
+ json.type = "number";
9375
+ if (typeof exclusiveMinimum === "number") {
9376
+ if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
9377
+ json.minimum = exclusiveMinimum;
9378
+ json.exclusiveMinimum = true;
9379
+ }
9380
+ else {
9381
+ json.exclusiveMinimum = exclusiveMinimum;
9382
+ }
9383
+ }
9384
+ if (typeof minimum === "number") {
9385
+ json.minimum = minimum;
9386
+ if (typeof exclusiveMinimum === "number" && ctx.target !== "draft-04") {
9387
+ if (exclusiveMinimum >= minimum)
9388
+ delete json.minimum;
9389
+ else
9390
+ delete json.exclusiveMinimum;
9391
+ }
9392
+ }
9393
+ if (typeof exclusiveMaximum === "number") {
9394
+ if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
9395
+ json.maximum = exclusiveMaximum;
9396
+ json.exclusiveMaximum = true;
9397
+ }
9398
+ else {
9399
+ json.exclusiveMaximum = exclusiveMaximum;
9400
+ }
9401
+ }
9402
+ if (typeof maximum === "number") {
9403
+ json.maximum = maximum;
9404
+ if (typeof exclusiveMaximum === "number" && ctx.target !== "draft-04") {
9405
+ if (exclusiveMaximum <= maximum)
9406
+ delete json.maximum;
9407
+ else
9408
+ delete json.exclusiveMaximum;
9409
+ }
9410
+ }
9411
+ if (typeof multipleOf === "number")
9412
+ json.multipleOf = multipleOf;
9413
+ };
9414
+ const booleanProcessor = (_schema, _ctx, json, _params) => {
9415
+ json.type = "boolean";
9416
+ };
9417
+ const bigintProcessor = (_schema, ctx, _json, _params) => {
9418
+ if (ctx.unrepresentable === "throw") {
9419
+ throw new Error("BigInt cannot be represented in JSON Schema");
9420
+ }
9421
+ };
9422
+ const symbolProcessor = (_schema, ctx, _json, _params) => {
9423
+ if (ctx.unrepresentable === "throw") {
9424
+ throw new Error("Symbols cannot be represented in JSON Schema");
9425
+ }
9426
+ };
9427
+ const nullProcessor = (_schema, ctx, json, _params) => {
9428
+ if (ctx.target === "openapi-3.0") {
9429
+ json.type = "string";
9430
+ json.nullable = true;
9431
+ json.enum = [null];
9432
+ }
9433
+ else {
9434
+ json.type = "null";
9435
+ }
9436
+ };
9437
+ const undefinedProcessor = (_schema, ctx, _json, _params) => {
9438
+ if (ctx.unrepresentable === "throw") {
9439
+ throw new Error("Undefined cannot be represented in JSON Schema");
9440
+ }
9441
+ };
9442
+ const voidProcessor = (_schema, ctx, _json, _params) => {
9443
+ if (ctx.unrepresentable === "throw") {
9444
+ throw new Error("Void cannot be represented in JSON Schema");
9445
+ }
9446
+ };
9447
+ const neverProcessor = (_schema, _ctx, json, _params) => {
9448
+ json.not = {};
9449
+ };
9450
+ const anyProcessor = (_schema, _ctx, _json, _params) => {
9451
+ // empty schema accepts anything
9452
+ };
9453
+ const unknownProcessor = (_schema, _ctx, _json, _params) => {
9454
+ // empty schema accepts anything
9455
+ };
9456
+ const dateProcessor = (_schema, ctx, _json, _params) => {
9457
+ if (ctx.unrepresentable === "throw") {
9458
+ throw new Error("Date cannot be represented in JSON Schema");
9459
+ }
9460
+ };
9461
+ const enumProcessor = (schema, _ctx, json, _params) => {
9462
+ const def = schema._zod.def;
9463
+ const values = getEnumValues(def.entries);
9464
+ // Number enums can have both string and number values
9465
+ if (values.every((v) => typeof v === "number"))
9466
+ json.type = "number";
9467
+ if (values.every((v) => typeof v === "string"))
9468
+ json.type = "string";
9469
+ json.enum = values;
9470
+ };
9471
+ const literalProcessor = (schema, ctx, json, _params) => {
9472
+ const def = schema._zod.def;
9473
+ const vals = [];
9474
+ for (const val of def.values) {
9475
+ if (val === undefined) {
9476
+ if (ctx.unrepresentable === "throw") {
9477
+ throw new Error("Literal `undefined` cannot be represented in JSON Schema");
9478
+ }
9479
+ }
9480
+ else if (typeof val === "bigint") {
9481
+ if (ctx.unrepresentable === "throw") {
9482
+ throw new Error("BigInt literals cannot be represented in JSON Schema");
9483
+ }
9484
+ else {
9485
+ vals.push(Number(val));
9486
+ }
9487
+ }
9488
+ else {
9489
+ vals.push(val);
9490
+ }
9491
+ }
9492
+ if (vals.length === 0) ;
9493
+ else if (vals.length === 1) {
9494
+ const val = vals[0];
9495
+ json.type = val === null ? "null" : typeof val;
9496
+ if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
9497
+ json.enum = [val];
9498
+ }
9499
+ else {
9500
+ json.const = val;
9501
+ }
9502
+ }
9503
+ else {
9504
+ if (vals.every((v) => typeof v === "number"))
9505
+ json.type = "number";
9506
+ if (vals.every((v) => typeof v === "string"))
9507
+ json.type = "string";
9508
+ if (vals.every((v) => typeof v === "boolean"))
9509
+ json.type = "boolean";
9510
+ if (vals.every((v) => v === null))
9511
+ json.type = "null";
9512
+ json.enum = vals;
9513
+ }
9514
+ };
9515
+ const nanProcessor = (_schema, ctx, _json, _params) => {
9516
+ if (ctx.unrepresentable === "throw") {
9517
+ throw new Error("NaN cannot be represented in JSON Schema");
9518
+ }
9519
+ };
9520
+ const templateLiteralProcessor = (schema, _ctx, json, _params) => {
9521
+ const _json = json;
9522
+ const pattern = schema._zod.pattern;
9523
+ if (!pattern)
9524
+ throw new Error("Pattern not found in template literal");
9525
+ _json.type = "string";
9526
+ _json.pattern = pattern.source;
9527
+ };
9528
+ const fileProcessor = (schema, _ctx, json, _params) => {
9529
+ const _json = json;
9530
+ const file = {
9531
+ type: "string",
9532
+ format: "binary",
9533
+ contentEncoding: "binary",
9534
+ };
9535
+ const { minimum, maximum, mime } = schema._zod.bag;
9536
+ if (minimum !== undefined)
9537
+ file.minLength = minimum;
9538
+ if (maximum !== undefined)
9539
+ file.maxLength = maximum;
9540
+ if (mime) {
9541
+ if (mime.length === 1) {
9542
+ file.contentMediaType = mime[0];
9543
+ Object.assign(_json, file);
9544
+ }
9545
+ else {
9546
+ Object.assign(_json, file); // shared props at root
9547
+ _json.anyOf = mime.map((m) => ({ contentMediaType: m })); // only contentMediaType differs
9548
+ }
9549
+ }
9550
+ else {
9551
+ Object.assign(_json, file);
9552
+ }
9553
+ };
9554
+ const successProcessor = (_schema, _ctx, json, _params) => {
9555
+ json.type = "boolean";
9556
+ };
9557
+ const customProcessor = (_schema, ctx, _json, _params) => {
9558
+ if (ctx.unrepresentable === "throw") {
9559
+ throw new Error("Custom types cannot be represented in JSON Schema");
9560
+ }
9561
+ };
9562
+ const functionProcessor = (_schema, ctx, _json, _params) => {
9563
+ if (ctx.unrepresentable === "throw") {
9564
+ throw new Error("Function types cannot be represented in JSON Schema");
9565
+ }
9566
+ };
9567
+ const transformProcessor = (_schema, ctx, _json, _params) => {
9568
+ if (ctx.unrepresentable === "throw") {
9569
+ throw new Error("Transforms cannot be represented in JSON Schema");
9570
+ }
9571
+ };
9572
+ const mapProcessor = (_schema, ctx, _json, _params) => {
9573
+ if (ctx.unrepresentable === "throw") {
9574
+ throw new Error("Map cannot be represented in JSON Schema");
9575
+ }
9576
+ };
9577
+ const setProcessor = (_schema, ctx, _json, _params) => {
9578
+ if (ctx.unrepresentable === "throw") {
9579
+ throw new Error("Set cannot be represented in JSON Schema");
9580
+ }
9581
+ };
9582
+ // ==================== COMPOSITE TYPE PROCESSORS ====================
9583
+ const arrayProcessor = (schema, ctx, _json, params) => {
9584
+ const json = _json;
9585
+ const def = schema._zod.def;
9586
+ const { minimum, maximum } = schema._zod.bag;
9587
+ if (typeof minimum === "number")
9588
+ json.minItems = minimum;
9589
+ if (typeof maximum === "number")
9590
+ json.maxItems = maximum;
9591
+ json.type = "array";
9592
+ json.items = process$1(def.element, ctx, { ...params, path: [...params.path, "items"] });
9593
+ };
9594
+ const objectProcessor = (schema, ctx, _json, params) => {
9595
+ const json = _json;
9596
+ const def = schema._zod.def;
9597
+ json.type = "object";
9598
+ json.properties = {};
9599
+ const shape = def.shape;
9600
+ for (const key in shape) {
9601
+ json.properties[key] = process$1(shape[key], ctx, {
9602
+ ...params,
9603
+ path: [...params.path, "properties", key],
9604
+ });
9605
+ }
9606
+ // required keys
9607
+ const allKeys = new Set(Object.keys(shape));
9608
+ const requiredKeys = new Set([...allKeys].filter((key) => {
9609
+ const v = def.shape[key]._zod;
9610
+ if (ctx.io === "input") {
9611
+ return v.optin === undefined;
9612
+ }
9613
+ else {
9614
+ return v.optout === undefined;
9615
+ }
9616
+ }));
9617
+ if (requiredKeys.size > 0) {
9618
+ json.required = Array.from(requiredKeys);
9619
+ }
9620
+ // catchall
9621
+ if (def.catchall?._zod.def.type === "never") {
9622
+ // strict
9623
+ json.additionalProperties = false;
9624
+ }
9625
+ else if (!def.catchall) {
9626
+ // regular
9627
+ if (ctx.io === "output")
9628
+ json.additionalProperties = false;
9629
+ }
9630
+ else if (def.catchall) {
9631
+ json.additionalProperties = process$1(def.catchall, ctx, {
9632
+ ...params,
9633
+ path: [...params.path, "additionalProperties"],
9634
+ });
9635
+ }
9636
+ };
9637
+ const unionProcessor = (schema, ctx, json, params) => {
9638
+ const def = schema._zod.def;
9639
+ // Exclusive unions (inclusive === false) use oneOf (exactly one match) instead of anyOf (one or more matches)
9640
+ // This includes both z.xor() and discriminated unions
9641
+ const isExclusive = def.inclusive === false;
9642
+ const options = def.options.map((x, i) => process$1(x, ctx, {
9643
+ ...params,
9644
+ path: [...params.path, isExclusive ? "oneOf" : "anyOf", i],
9645
+ }));
9646
+ if (isExclusive) {
9647
+ json.oneOf = options;
9648
+ }
9649
+ else {
9650
+ json.anyOf = options;
9651
+ }
9652
+ };
9653
+ const intersectionProcessor = (schema, ctx, json, params) => {
9654
+ const def = schema._zod.def;
9655
+ const a = process$1(def.left, ctx, {
9656
+ ...params,
9657
+ path: [...params.path, "allOf", 0],
9658
+ });
9659
+ const b = process$1(def.right, ctx, {
9660
+ ...params,
9661
+ path: [...params.path, "allOf", 1],
9662
+ });
9663
+ const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1;
9664
+ const allOf = [
9665
+ ...(isSimpleIntersection(a) ? a.allOf : [a]),
9666
+ ...(isSimpleIntersection(b) ? b.allOf : [b]),
9667
+ ];
9668
+ json.allOf = allOf;
9669
+ };
9670
+ const tupleProcessor = (schema, ctx, _json, params) => {
9671
+ const json = _json;
9672
+ const def = schema._zod.def;
9673
+ json.type = "array";
9674
+ const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
9675
+ const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
9676
+ const prefixItems = def.items.map((x, i) => process$1(x, ctx, {
9677
+ ...params,
9678
+ path: [...params.path, prefixPath, i],
9679
+ }));
9680
+ const rest = def.rest
9681
+ ? process$1(def.rest, ctx, {
9682
+ ...params,
9683
+ path: [...params.path, restPath, ...(ctx.target === "openapi-3.0" ? [def.items.length] : [])],
9684
+ })
9685
+ : null;
9686
+ if (ctx.target === "draft-2020-12") {
9687
+ json.prefixItems = prefixItems;
9688
+ if (rest) {
9689
+ json.items = rest;
9690
+ }
9691
+ }
9692
+ else if (ctx.target === "openapi-3.0") {
9693
+ json.items = {
9694
+ anyOf: prefixItems,
9695
+ };
9696
+ if (rest) {
9697
+ json.items.anyOf.push(rest);
9698
+ }
9699
+ json.minItems = prefixItems.length;
9700
+ if (!rest) {
9701
+ json.maxItems = prefixItems.length;
9702
+ }
9703
+ }
9704
+ else {
9705
+ json.items = prefixItems;
9706
+ if (rest) {
9707
+ json.additionalItems = rest;
9708
+ }
9709
+ }
9710
+ // length
9711
+ const { minimum, maximum } = schema._zod.bag;
9712
+ if (typeof minimum === "number")
9713
+ json.minItems = minimum;
9714
+ if (typeof maximum === "number")
9715
+ json.maxItems = maximum;
9716
+ };
9717
+ const recordProcessor = (schema, ctx, _json, params) => {
9718
+ const json = _json;
9719
+ const def = schema._zod.def;
9720
+ json.type = "object";
9721
+ // For looseRecord with regex patterns, use patternProperties
9722
+ // This correctly represents "only validate keys matching the pattern" semantics
9723
+ // and composes well with allOf (intersections)
9724
+ const keyType = def.keyType;
9725
+ const keyBag = keyType._zod.bag;
9726
+ const patterns = keyBag?.patterns;
9727
+ if (def.mode === "loose" && patterns && patterns.size > 0) {
9728
+ // Use patternProperties for looseRecord with regex patterns
9729
+ const valueSchema = process$1(def.valueType, ctx, {
9730
+ ...params,
9731
+ path: [...params.path, "patternProperties", "*"],
9732
+ });
9733
+ json.patternProperties = {};
9734
+ for (const pattern of patterns) {
9735
+ json.patternProperties[pattern.source] = valueSchema;
9736
+ }
9737
+ }
9738
+ else {
9739
+ // Default behavior: use propertyNames + additionalProperties
9740
+ if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
9741
+ json.propertyNames = process$1(def.keyType, ctx, {
9742
+ ...params,
9743
+ path: [...params.path, "propertyNames"],
9744
+ });
9745
+ }
9746
+ json.additionalProperties = process$1(def.valueType, ctx, {
9747
+ ...params,
9748
+ path: [...params.path, "additionalProperties"],
9749
+ });
9750
+ }
9751
+ // Add required for keys with discrete values (enum, literal, etc.)
9752
+ const keyValues = keyType._zod.values;
9753
+ if (keyValues) {
9754
+ const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
9755
+ if (validKeyValues.length > 0) {
9756
+ json.required = validKeyValues;
9757
+ }
9758
+ }
9759
+ };
9760
+ const nullableProcessor = (schema, ctx, json, params) => {
9761
+ const def = schema._zod.def;
9762
+ const inner = process$1(def.innerType, ctx, params);
9763
+ const seen = ctx.seen.get(schema);
9764
+ if (ctx.target === "openapi-3.0") {
9765
+ seen.ref = def.innerType;
9766
+ json.nullable = true;
9767
+ }
9768
+ else {
9769
+ json.anyOf = [inner, { type: "null" }];
9770
+ }
9771
+ };
9772
+ const nonoptionalProcessor = (schema, ctx, _json, params) => {
9773
+ const def = schema._zod.def;
9774
+ process$1(def.innerType, ctx, params);
9775
+ const seen = ctx.seen.get(schema);
9776
+ seen.ref = def.innerType;
9777
+ };
9778
+ const defaultProcessor = (schema, ctx, json, params) => {
9779
+ const def = schema._zod.def;
9780
+ process$1(def.innerType, ctx, params);
9781
+ const seen = ctx.seen.get(schema);
9782
+ seen.ref = def.innerType;
9783
+ json.default = JSON.parse(JSON.stringify(def.defaultValue));
9784
+ };
9785
+ const prefaultProcessor = (schema, ctx, json, params) => {
9786
+ const def = schema._zod.def;
9787
+ process$1(def.innerType, ctx, params);
9788
+ const seen = ctx.seen.get(schema);
9789
+ seen.ref = def.innerType;
9790
+ if (ctx.io === "input")
9791
+ json._prefault = JSON.parse(JSON.stringify(def.defaultValue));
9792
+ };
9793
+ const catchProcessor = (schema, ctx, json, params) => {
9794
+ const def = schema._zod.def;
9795
+ process$1(def.innerType, ctx, params);
9796
+ const seen = ctx.seen.get(schema);
9797
+ seen.ref = def.innerType;
9798
+ let catchValue;
9799
+ try {
9800
+ catchValue = def.catchValue(undefined);
9801
+ }
9802
+ catch {
9803
+ throw new Error("Dynamic catch values are not supported in JSON Schema");
9804
+ }
9805
+ json.default = catchValue;
9806
+ };
9807
+ const pipeProcessor = (schema, ctx, _json, params) => {
9808
+ const def = schema._zod.def;
9809
+ const innerType = ctx.io === "input" ? (def.in._zod.def.type === "transform" ? def.out : def.in) : def.out;
9810
+ process$1(innerType, ctx, params);
9811
+ const seen = ctx.seen.get(schema);
9812
+ seen.ref = innerType;
9813
+ };
9814
+ const readonlyProcessor = (schema, ctx, json, params) => {
9815
+ const def = schema._zod.def;
9816
+ process$1(def.innerType, ctx, params);
9817
+ const seen = ctx.seen.get(schema);
9818
+ seen.ref = def.innerType;
9819
+ json.readOnly = true;
9820
+ };
9821
+ const promiseProcessor = (schema, ctx, _json, params) => {
9822
+ const def = schema._zod.def;
9823
+ process$1(def.innerType, ctx, params);
9824
+ const seen = ctx.seen.get(schema);
9825
+ seen.ref = def.innerType;
9826
+ };
9827
+ const optionalProcessor = (schema, ctx, _json, params) => {
9828
+ const def = schema._zod.def;
9829
+ process$1(def.innerType, ctx, params);
9830
+ const seen = ctx.seen.get(schema);
9831
+ seen.ref = def.innerType;
9832
+ };
9833
+ const lazyProcessor = (schema, ctx, _json, params) => {
9834
+ const innerType = schema._zod.innerType;
9835
+ process$1(innerType, ctx, params);
9836
+ const seen = ctx.seen.get(schema);
9837
+ seen.ref = innerType;
9838
+ };
9839
+ // ==================== ALL PROCESSORS ====================
9840
+ const allProcessors = {
9841
+ string: stringProcessor,
9842
+ number: numberProcessor,
9843
+ boolean: booleanProcessor,
9844
+ bigint: bigintProcessor,
9845
+ symbol: symbolProcessor,
9846
+ null: nullProcessor,
9847
+ undefined: undefinedProcessor,
9848
+ void: voidProcessor,
9849
+ never: neverProcessor,
9850
+ any: anyProcessor,
9851
+ unknown: unknownProcessor,
9852
+ date: dateProcessor,
9853
+ enum: enumProcessor,
9854
+ literal: literalProcessor,
9855
+ nan: nanProcessor,
9856
+ template_literal: templateLiteralProcessor,
9857
+ file: fileProcessor,
9858
+ success: successProcessor,
9859
+ custom: customProcessor,
9860
+ function: functionProcessor,
9861
+ transform: transformProcessor,
9862
+ map: mapProcessor,
9863
+ set: setProcessor,
9864
+ array: arrayProcessor,
9865
+ object: objectProcessor,
9866
+ union: unionProcessor,
9867
+ intersection: intersectionProcessor,
9868
+ tuple: tupleProcessor,
9869
+ record: recordProcessor,
9870
+ nullable: nullableProcessor,
9871
+ nonoptional: nonoptionalProcessor,
9872
+ default: defaultProcessor,
9873
+ prefault: prefaultProcessor,
9874
+ catch: catchProcessor,
9875
+ pipe: pipeProcessor,
9876
+ readonly: readonlyProcessor,
9877
+ promise: promiseProcessor,
9878
+ optional: optionalProcessor,
9879
+ lazy: lazyProcessor,
9880
+ };
9881
+ function toJSONSchema(input, params) {
9882
+ if ("_idmap" in input) {
9883
+ // Registry case
9884
+ const registry = input;
9885
+ const ctx = initializeContext({ ...params, processors: allProcessors });
9886
+ const defs = {};
9887
+ // First pass: process all schemas to build the seen map
9888
+ for (const entry of registry._idmap.entries()) {
9889
+ const [_, schema] = entry;
9890
+ process$1(schema, ctx);
9891
+ }
9892
+ const schemas = {};
9893
+ const external = {
9894
+ registry,
9895
+ uri: params?.uri,
9896
+ defs,
9897
+ };
9898
+ // Update the context with external configuration
9899
+ ctx.external = external;
9900
+ // Second pass: emit each schema
9901
+ for (const entry of registry._idmap.entries()) {
9902
+ const [key, schema] = entry;
9903
+ extractDefs(ctx, schema);
9904
+ schemas[key] = finalize(ctx, schema);
9905
+ }
9906
+ if (Object.keys(defs).length > 0) {
9907
+ const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
9908
+ schemas.__shared = {
9909
+ [defsSegment]: defs,
9910
+ };
9911
+ }
9912
+ return { schemas };
9913
+ }
9914
+ // Single schema case
9915
+ const ctx = initializeContext({ ...params, processors: allProcessors });
9916
+ process$1(input, ctx);
9917
+ extractDefs(ctx, input);
9918
+ return finalize(ctx, input);
9919
+ }
9920
+
9921
+ const ignoreOverride = Symbol('Let zodToJsonSchema decide on which parser to use');
9922
+ const defaultOptions = {
9923
+ name: undefined,
9924
+ $refStrategy: 'root',
9925
+ effectStrategy: 'input',
9926
+ pipeStrategy: 'all',
9927
+ dateStrategy: 'format:date-time',
9928
+ mapStrategy: 'entries',
9929
+ nullableStrategy: 'from-target',
9930
+ removeAdditionalStrategy: 'passthrough',
9931
+ definitionPath: 'definitions',
9932
+ target: 'jsonSchema7',
9933
+ strictUnions: false,
9934
+ errorMessages: false,
9935
+ markdownDescription: false,
9936
+ patternStrategy: 'escape',
9937
+ applyRegexFlags: false,
9938
+ emailStrategy: 'format:email',
9939
+ base64Strategy: 'contentEncoding:base64',
9940
+ nameStrategy: 'ref',
9941
+ };
9942
+ const getDefaultOptions = (options) => {
9943
+ // We need to add `definitions` here as we may mutate it
9944
+ return (typeof options === 'string' ?
9945
+ {
9946
+ ...defaultOptions,
9947
+ basePath: ['#'],
9948
+ definitions: {},
9949
+ name: options,
9950
+ }
9951
+ : {
9952
+ ...defaultOptions,
9953
+ basePath: ['#'],
9954
+ definitions: {},
9955
+ ...options,
9956
+ });
9957
+ };
9958
+
9959
+ const zodDef = (zodSchema) => {
9960
+ return '_def' in zodSchema ? zodSchema._def : zodSchema;
9961
+ };
9962
+ function isEmptyObj(obj) {
9963
+ if (!obj)
9964
+ return true;
9965
+ for (const _k in obj)
9966
+ return false;
9967
+ return true;
9968
+ }
9969
+
9970
+ const getRefs = (options) => {
9971
+ const _options = getDefaultOptions(options);
9972
+ const currentPath = _options.name !== undefined ?
9973
+ [..._options.basePath, _options.definitionPath, _options.name]
9974
+ : _options.basePath;
9975
+ return {
9976
+ ..._options,
9977
+ currentPath: currentPath,
9978
+ propertyPath: undefined,
9979
+ seenRefs: new Set(),
9980
+ seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [
9981
+ zodDef(def),
9982
+ {
9983
+ def: zodDef(def),
9984
+ path: [..._options.basePath, _options.definitionPath, name],
9985
+ // Resolution of references will be forced even though seen, so it's ok that the schema is undefined here for now.
9986
+ jsonSchema: undefined,
9987
+ },
9988
+ ])),
9989
+ };
9990
+ };
9991
+
9992
+ function addErrorMessage(res, key, errorMessage, refs) {
9993
+ if (!refs?.errorMessages)
9994
+ return;
9995
+ if (errorMessage) {
9996
+ res.errorMessage = {
9997
+ ...res.errorMessage,
9998
+ [key]: errorMessage,
9999
+ };
10000
+ }
10001
+ }
10002
+ function setResponseValueAndErrors(res, key, value, errorMessage, refs) {
10003
+ res[key] = value;
10004
+ addErrorMessage(res, key, errorMessage, refs);
10005
+ }
10006
+
10007
+ var util;
10008
+ (function (util) {
10009
+ util.assertEqual = (_) => { };
10010
+ function assertIs(_arg) { }
10011
+ util.assertIs = assertIs;
10012
+ function assertNever(_x) {
10013
+ throw new Error();
10014
+ }
10015
+ util.assertNever = assertNever;
10016
+ util.arrayToEnum = (items) => {
10017
+ const obj = {};
10018
+ for (const item of items) {
10019
+ obj[item] = item;
10020
+ }
10021
+ return obj;
10022
+ };
10023
+ util.getValidEnumValues = (obj) => {
10024
+ const validKeys = util.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number");
10025
+ const filtered = {};
10026
+ for (const k of validKeys) {
10027
+ filtered[k] = obj[k];
10028
+ }
10029
+ return util.objectValues(filtered);
10030
+ };
10031
+ util.objectValues = (obj) => {
10032
+ return util.objectKeys(obj).map(function (e) {
10033
+ return obj[e];
10034
+ });
10035
+ };
10036
+ util.objectKeys = typeof Object.keys === "function" // eslint-disable-line ban/ban
10037
+ ? (obj) => Object.keys(obj) // eslint-disable-line ban/ban
10038
+ : (object) => {
10039
+ const keys = [];
10040
+ for (const key in object) {
10041
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
10042
+ keys.push(key);
10043
+ }
10044
+ }
10045
+ return keys;
10046
+ };
10047
+ util.find = (arr, checker) => {
10048
+ for (const item of arr) {
10049
+ if (checker(item))
10050
+ return item;
10051
+ }
10052
+ return undefined;
10053
+ };
10054
+ util.isInteger = typeof Number.isInteger === "function"
10055
+ ? (val) => Number.isInteger(val) // eslint-disable-line ban/ban
10056
+ : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val;
10057
+ function joinValues(array, separator = " | ") {
10058
+ return array.map((val) => (typeof val === "string" ? `'${val}'` : val)).join(separator);
10059
+ }
10060
+ util.joinValues = joinValues;
10061
+ util.jsonStringifyReplacer = (_, value) => {
10062
+ if (typeof value === "bigint") {
10063
+ return value.toString();
10064
+ }
10065
+ return value;
10066
+ };
10067
+ })(util || (util = {}));
10068
+ var objectUtil;
10069
+ (function (objectUtil) {
10070
+ objectUtil.mergeShapes = (first, second) => {
10071
+ return {
10072
+ ...first,
10073
+ ...second, // second overwrites first
10074
+ };
10075
+ };
10076
+ })(objectUtil || (objectUtil = {}));
10077
+ util.arrayToEnum([
10078
+ "string",
10079
+ "nan",
10080
+ "number",
10081
+ "integer",
10082
+ "float",
10083
+ "boolean",
10084
+ "date",
10085
+ "bigint",
10086
+ "symbol",
10087
+ "function",
10088
+ "undefined",
10089
+ "null",
10090
+ "array",
10091
+ "object",
10092
+ "unknown",
10093
+ "promise",
10094
+ "void",
10095
+ "never",
10096
+ "map",
10097
+ "set",
10098
+ ]);
10099
+
10100
+ util.arrayToEnum([
10101
+ "invalid_type",
10102
+ "invalid_literal",
10103
+ "custom",
10104
+ "invalid_union",
10105
+ "invalid_union_discriminator",
10106
+ "invalid_enum_value",
10107
+ "unrecognized_keys",
10108
+ "invalid_arguments",
10109
+ "invalid_return_type",
10110
+ "invalid_date",
10111
+ "invalid_string",
10112
+ "too_small",
10113
+ "too_big",
10114
+ "invalid_intersection_types",
10115
+ "not_multiple_of",
10116
+ "not_finite",
10117
+ ]);
10118
+ class ZodError extends Error {
10119
+ get errors() {
10120
+ return this.issues;
10121
+ }
10122
+ constructor(issues) {
10123
+ super();
10124
+ this.issues = [];
10125
+ this.addIssue = (sub) => {
10126
+ this.issues = [...this.issues, sub];
10127
+ };
10128
+ this.addIssues = (subs = []) => {
10129
+ this.issues = [...this.issues, ...subs];
10130
+ };
10131
+ const actualProto = new.target.prototype;
10132
+ if (Object.setPrototypeOf) {
10133
+ // eslint-disable-next-line ban/ban
10134
+ Object.setPrototypeOf(this, actualProto);
10135
+ }
10136
+ else {
10137
+ this.__proto__ = actualProto;
10138
+ }
10139
+ this.name = "ZodError";
10140
+ this.issues = issues;
10141
+ }
10142
+ format(_mapper) {
10143
+ const mapper = _mapper ||
10144
+ function (issue) {
10145
+ return issue.message;
10146
+ };
10147
+ const fieldErrors = { _errors: [] };
10148
+ const processError = (error) => {
10149
+ for (const issue of error.issues) {
10150
+ if (issue.code === "invalid_union") {
10151
+ issue.unionErrors.map(processError);
10152
+ }
10153
+ else if (issue.code === "invalid_return_type") {
10154
+ processError(issue.returnTypeError);
10155
+ }
10156
+ else if (issue.code === "invalid_arguments") {
10157
+ processError(issue.argumentsError);
10158
+ }
10159
+ else if (issue.path.length === 0) {
10160
+ fieldErrors._errors.push(mapper(issue));
10161
+ }
10162
+ else {
10163
+ let curr = fieldErrors;
10164
+ let i = 0;
10165
+ while (i < issue.path.length) {
10166
+ const el = issue.path[i];
10167
+ const terminal = i === issue.path.length - 1;
10168
+ if (!terminal) {
10169
+ curr[el] = curr[el] || { _errors: [] };
10170
+ // if (typeof el === "string") {
10171
+ // curr[el] = curr[el] || { _errors: [] };
10172
+ // } else if (typeof el === "number") {
10173
+ // const errorArray: any = [];
10174
+ // errorArray._errors = [];
10175
+ // curr[el] = curr[el] || errorArray;
10176
+ // }
10177
+ }
10178
+ else {
10179
+ curr[el] = curr[el] || { _errors: [] };
10180
+ curr[el]._errors.push(mapper(issue));
10181
+ }
10182
+ curr = curr[el];
10183
+ i++;
10184
+ }
10185
+ }
10186
+ }
10187
+ };
10188
+ processError(this);
10189
+ return fieldErrors;
10190
+ }
10191
+ static assert(value) {
10192
+ if (!(value instanceof ZodError)) {
10193
+ throw new Error(`Not a ZodError: ${value}`);
10194
+ }
10195
+ }
10196
+ toString() {
10197
+ return this.message;
10198
+ }
10199
+ get message() {
10200
+ return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2);
10201
+ }
10202
+ get isEmpty() {
10203
+ return this.issues.length === 0;
10204
+ }
10205
+ flatten(mapper = (issue) => issue.message) {
10206
+ const fieldErrors = Object.create(null);
10207
+ const formErrors = [];
10208
+ for (const sub of this.issues) {
10209
+ if (sub.path.length > 0) {
10210
+ const firstEl = sub.path[0];
10211
+ fieldErrors[firstEl] = fieldErrors[firstEl] || [];
10212
+ fieldErrors[firstEl].push(mapper(sub));
10213
+ }
10214
+ else {
10215
+ formErrors.push(mapper(sub));
10216
+ }
10217
+ }
10218
+ return { formErrors, fieldErrors };
10219
+ }
10220
+ get formErrors() {
10221
+ return this.flatten();
10222
+ }
10223
+ }
10224
+ ZodError.create = (issues) => {
10225
+ const error = new ZodError(issues);
10226
+ return error;
10227
+ };
10228
+
10229
+ var errorUtil;
10230
+ (function (errorUtil) {
10231
+ errorUtil.errToObj = (message) => typeof message === "string" ? { message } : message || {};
10232
+ // biome-ignore lint:
10233
+ errorUtil.toString = (message) => typeof message === "string" ? message : message?.message;
10234
+ })(errorUtil || (errorUtil = {}));
10235
+
10236
+ var ZodFirstPartyTypeKind;
10237
+ (function (ZodFirstPartyTypeKind) {
10238
+ ZodFirstPartyTypeKind["ZodString"] = "ZodString";
10239
+ ZodFirstPartyTypeKind["ZodNumber"] = "ZodNumber";
10240
+ ZodFirstPartyTypeKind["ZodNaN"] = "ZodNaN";
10241
+ ZodFirstPartyTypeKind["ZodBigInt"] = "ZodBigInt";
10242
+ ZodFirstPartyTypeKind["ZodBoolean"] = "ZodBoolean";
10243
+ ZodFirstPartyTypeKind["ZodDate"] = "ZodDate";
10244
+ ZodFirstPartyTypeKind["ZodSymbol"] = "ZodSymbol";
10245
+ ZodFirstPartyTypeKind["ZodUndefined"] = "ZodUndefined";
10246
+ ZodFirstPartyTypeKind["ZodNull"] = "ZodNull";
10247
+ ZodFirstPartyTypeKind["ZodAny"] = "ZodAny";
10248
+ ZodFirstPartyTypeKind["ZodUnknown"] = "ZodUnknown";
10249
+ ZodFirstPartyTypeKind["ZodNever"] = "ZodNever";
10250
+ ZodFirstPartyTypeKind["ZodVoid"] = "ZodVoid";
10251
+ ZodFirstPartyTypeKind["ZodArray"] = "ZodArray";
10252
+ ZodFirstPartyTypeKind["ZodObject"] = "ZodObject";
10253
+ ZodFirstPartyTypeKind["ZodUnion"] = "ZodUnion";
10254
+ ZodFirstPartyTypeKind["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion";
10255
+ ZodFirstPartyTypeKind["ZodIntersection"] = "ZodIntersection";
10256
+ ZodFirstPartyTypeKind["ZodTuple"] = "ZodTuple";
10257
+ ZodFirstPartyTypeKind["ZodRecord"] = "ZodRecord";
10258
+ ZodFirstPartyTypeKind["ZodMap"] = "ZodMap";
10259
+ ZodFirstPartyTypeKind["ZodSet"] = "ZodSet";
10260
+ ZodFirstPartyTypeKind["ZodFunction"] = "ZodFunction";
10261
+ ZodFirstPartyTypeKind["ZodLazy"] = "ZodLazy";
10262
+ ZodFirstPartyTypeKind["ZodLiteral"] = "ZodLiteral";
10263
+ ZodFirstPartyTypeKind["ZodEnum"] = "ZodEnum";
10264
+ ZodFirstPartyTypeKind["ZodEffects"] = "ZodEffects";
10265
+ ZodFirstPartyTypeKind["ZodNativeEnum"] = "ZodNativeEnum";
10266
+ ZodFirstPartyTypeKind["ZodOptional"] = "ZodOptional";
10267
+ ZodFirstPartyTypeKind["ZodNullable"] = "ZodNullable";
10268
+ ZodFirstPartyTypeKind["ZodDefault"] = "ZodDefault";
10269
+ ZodFirstPartyTypeKind["ZodCatch"] = "ZodCatch";
10270
+ ZodFirstPartyTypeKind["ZodPromise"] = "ZodPromise";
10271
+ ZodFirstPartyTypeKind["ZodBranded"] = "ZodBranded";
10272
+ ZodFirstPartyTypeKind["ZodPipeline"] = "ZodPipeline";
10273
+ ZodFirstPartyTypeKind["ZodReadonly"] = "ZodReadonly";
10274
+ })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
10275
+
10276
+ function parseAnyDef() {
10277
+ return {};
10278
+ }
10279
+
10280
+ function parseArrayDef(def, refs) {
10281
+ const res = {
10282
+ type: 'array',
10283
+ };
10284
+ if (def.type?._def?.typeName !== ZodFirstPartyTypeKind.ZodAny) {
10285
+ res.items = parseDef(def.type._def, {
10286
+ ...refs,
10287
+ currentPath: [...refs.currentPath, 'items'],
10288
+ });
10289
+ }
10290
+ if (def.minLength) {
10291
+ setResponseValueAndErrors(res, 'minItems', def.minLength.value, def.minLength.message, refs);
10292
+ }
10293
+ if (def.maxLength) {
10294
+ setResponseValueAndErrors(res, 'maxItems', def.maxLength.value, def.maxLength.message, refs);
10295
+ }
10296
+ if (def.exactLength) {
10297
+ setResponseValueAndErrors(res, 'minItems', def.exactLength.value, def.exactLength.message, refs);
10298
+ setResponseValueAndErrors(res, 'maxItems', def.exactLength.value, def.exactLength.message, refs);
10299
+ }
10300
+ return res;
10301
+ }
10302
+
10303
+ function parseBigintDef(def, refs) {
10304
+ const res = {
10305
+ type: 'integer',
10306
+ format: 'int64',
10307
+ };
10308
+ if (!def.checks)
10309
+ return res;
10310
+ for (const check of def.checks) {
10311
+ switch (check.kind) {
10312
+ case 'min':
10313
+ if (refs.target === 'jsonSchema7') {
10314
+ if (check.inclusive) {
10315
+ setResponseValueAndErrors(res, 'minimum', check.value, check.message, refs);
10316
+ }
10317
+ else {
10318
+ setResponseValueAndErrors(res, 'exclusiveMinimum', check.value, check.message, refs);
10319
+ }
10320
+ }
10321
+ else {
10322
+ if (!check.inclusive) {
10323
+ res.exclusiveMinimum = true;
10324
+ }
10325
+ setResponseValueAndErrors(res, 'minimum', check.value, check.message, refs);
10326
+ }
10327
+ break;
10328
+ case 'max':
10329
+ if (refs.target === 'jsonSchema7') {
10330
+ if (check.inclusive) {
10331
+ setResponseValueAndErrors(res, 'maximum', check.value, check.message, refs);
10332
+ }
10333
+ else {
10334
+ setResponseValueAndErrors(res, 'exclusiveMaximum', check.value, check.message, refs);
10335
+ }
10336
+ }
10337
+ else {
10338
+ if (!check.inclusive) {
10339
+ res.exclusiveMaximum = true;
10340
+ }
10341
+ setResponseValueAndErrors(res, 'maximum', check.value, check.message, refs);
10342
+ }
10343
+ break;
10344
+ case 'multipleOf':
10345
+ setResponseValueAndErrors(res, 'multipleOf', check.value, check.message, refs);
10346
+ break;
10347
+ }
10348
+ }
10349
+ return res;
10350
+ }
10351
+
10352
+ function parseBooleanDef() {
10353
+ return {
10354
+ type: 'boolean',
10355
+ };
10356
+ }
10357
+
10358
+ function parseBrandedDef(_def, refs) {
10359
+ return parseDef(_def.type._def, refs);
10360
+ }
10361
+
10362
+ const parseCatchDef = (def, refs) => {
10363
+ return parseDef(def.innerType._def, refs);
10364
+ };
10365
+
10366
+ function parseDateDef(def, refs, overrideDateStrategy) {
10367
+ const strategy = overrideDateStrategy ?? refs.dateStrategy;
10368
+ if (Array.isArray(strategy)) {
10369
+ return {
10370
+ anyOf: strategy.map((item, i) => parseDateDef(def, refs, item)),
10371
+ };
10372
+ }
10373
+ switch (strategy) {
10374
+ case 'string':
10375
+ case 'format:date-time':
10376
+ return {
10377
+ type: 'string',
10378
+ format: 'date-time',
10379
+ };
10380
+ case 'format:date':
10381
+ return {
10382
+ type: 'string',
10383
+ format: 'date',
10384
+ };
10385
+ case 'integer':
10386
+ return integerDateParser(def, refs);
10387
+ }
10388
+ }
10389
+ const integerDateParser = (def, refs) => {
10390
+ const res = {
10391
+ type: 'integer',
10392
+ format: 'unix-time',
10393
+ };
10394
+ if (refs.target === 'openApi3') {
10395
+ return res;
10396
+ }
10397
+ for (const check of def.checks) {
10398
+ switch (check.kind) {
10399
+ case 'min':
10400
+ setResponseValueAndErrors(res, 'minimum', check.value, // This is in milliseconds
10401
+ check.message, refs);
10402
+ break;
10403
+ case 'max':
10404
+ setResponseValueAndErrors(res, 'maximum', check.value, // This is in milliseconds
10405
+ check.message, refs);
10406
+ break;
10407
+ }
10408
+ }
10409
+ return res;
10410
+ };
10411
+
10412
+ function parseDefaultDef(_def, refs) {
10413
+ return {
10414
+ ...parseDef(_def.innerType._def, refs),
10415
+ default: _def.defaultValue(),
10416
+ };
10417
+ }
10418
+
10419
+ function parseEffectsDef(_def, refs, forceResolution) {
10420
+ return refs.effectStrategy === 'input' ? parseDef(_def.schema._def, refs, forceResolution) : {};
10421
+ }
10422
+
10423
+ function parseEnumDef(def) {
10424
+ return {
10425
+ type: 'string',
10426
+ enum: [...def.values],
10427
+ };
10428
+ }
10429
+
10430
+ const isJsonSchema7AllOfType = (type) => {
10431
+ if ('type' in type && type.type === 'string')
10432
+ return false;
10433
+ return 'allOf' in type;
10434
+ };
10435
+ function parseIntersectionDef(def, refs) {
10436
+ const allOf = [
10437
+ parseDef(def.left._def, {
10438
+ ...refs,
10439
+ currentPath: [...refs.currentPath, 'allOf', '0'],
10440
+ }),
10441
+ parseDef(def.right._def, {
10442
+ ...refs,
10443
+ currentPath: [...refs.currentPath, 'allOf', '1'],
10444
+ }),
10445
+ ].filter((x) => !!x);
10446
+ let unevaluatedProperties = refs.target === 'jsonSchema2019-09' ? { unevaluatedProperties: false } : undefined;
10447
+ const mergedAllOf = [];
10448
+ // If either of the schemas is an allOf, merge them into a single allOf
10449
+ allOf.forEach((schema) => {
10450
+ if (isJsonSchema7AllOfType(schema)) {
10451
+ mergedAllOf.push(...schema.allOf);
10452
+ if (schema.unevaluatedProperties === undefined) {
10453
+ // If one of the schemas has no unevaluatedProperties set,
10454
+ // the merged schema should also have no unevaluatedProperties set
10455
+ unevaluatedProperties = undefined;
10456
+ }
10457
+ }
10458
+ else {
10459
+ let nestedSchema = schema;
10460
+ if ('additionalProperties' in schema && schema.additionalProperties === false) {
10461
+ const { additionalProperties, ...rest } = schema;
10462
+ nestedSchema = rest;
10463
+ }
10464
+ else {
10465
+ // As soon as one of the schemas has additionalProperties set not to false, we allow unevaluatedProperties
10466
+ unevaluatedProperties = undefined;
10467
+ }
10468
+ mergedAllOf.push(nestedSchema);
10469
+ }
10470
+ });
10471
+ return mergedAllOf.length ?
10472
+ {
10473
+ allOf: mergedAllOf,
10474
+ ...unevaluatedProperties,
10475
+ }
10476
+ : undefined;
10477
+ }
10478
+
10479
+ function parseLiteralDef(def, refs) {
10480
+ const parsedType = typeof def.value;
10481
+ if (parsedType !== 'bigint' &&
10482
+ parsedType !== 'number' &&
10483
+ parsedType !== 'boolean' &&
10484
+ parsedType !== 'string') {
10485
+ return {
10486
+ type: Array.isArray(def.value) ? 'array' : 'object',
10487
+ };
10488
+ }
10489
+ if (refs.target === 'openApi3') {
10490
+ return {
10491
+ type: parsedType === 'bigint' ? 'integer' : parsedType,
10492
+ enum: [def.value],
10493
+ };
10494
+ }
10495
+ return {
10496
+ type: parsedType === 'bigint' ? 'integer' : parsedType,
10497
+ const: def.value,
10498
+ };
10499
+ }
10500
+
10501
+ let emojiRegex;
10502
+ /**
10503
+ * Generated from the regular expressions found here as of 2024-05-22:
10504
+ * https://github.com/colinhacks/zod/blob/master/src/types.ts.
10505
+ *
10506
+ * Expressions with /i flag have been changed accordingly.
10507
+ */
10508
+ const zodPatterns = {
10509
+ /**
10510
+ * `c` was changed to `[cC]` to replicate /i flag
10511
+ */
10512
+ cuid: /^[cC][^\s-]{8,}$/,
10513
+ cuid2: /^[0-9a-z]+$/,
10514
+ ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,
10515
+ /**
10516
+ * `a-z` was added to replicate /i flag
10517
+ */
10518
+ email: /^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/,
10519
+ /**
10520
+ * Constructed a valid Unicode RegExp
10521
+ *
10522
+ * Lazily instantiate since this type of regex isn't supported
10523
+ * in all envs (e.g. React Native).
10524
+ *
10525
+ * See:
10526
+ * https://github.com/colinhacks/zod/issues/2433
10527
+ * Fix in Zod:
10528
+ * https://github.com/colinhacks/zod/commit/9340fd51e48576a75adc919bff65dbc4a5d4c99b
10529
+ */
10530
+ emoji: () => {
10531
+ if (emojiRegex === undefined) {
10532
+ emojiRegex = RegExp('^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$', 'u');
10533
+ }
10534
+ return emojiRegex;
10535
+ },
10536
+ base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,
10537
+ nanoid: /^[a-zA-Z0-9_-]{21}$/,
10538
+ };
10539
+ function parseStringDef(def, refs) {
10540
+ const res = {
10541
+ type: 'string',
10542
+ };
10543
+ function processPattern(value) {
10544
+ return refs.patternStrategy === 'escape' ? escapeNonAlphaNumeric(value) : value;
10545
+ }
10546
+ if (def.checks) {
10547
+ for (const check of def.checks) {
10548
+ switch (check.kind) {
10549
+ case 'min':
10550
+ setResponseValueAndErrors(res, 'minLength', typeof res.minLength === 'number' ? Math.max(res.minLength, check.value) : check.value, check.message, refs);
10551
+ break;
10552
+ case 'max':
10553
+ setResponseValueAndErrors(res, 'maxLength', typeof res.maxLength === 'number' ? Math.min(res.maxLength, check.value) : check.value, check.message, refs);
10554
+ break;
10555
+ case 'email':
10556
+ switch (refs.emailStrategy) {
10557
+ case 'format:email':
10558
+ addFormat(res, 'email', check.message, refs);
10559
+ break;
10560
+ case 'format:idn-email':
10561
+ addFormat(res, 'idn-email', check.message, refs);
10562
+ break;
10563
+ case 'pattern:zod':
10564
+ addPattern(res, zodPatterns.email, check.message, refs);
10565
+ break;
10566
+ }
10567
+ break;
10568
+ case 'url':
10569
+ addFormat(res, 'uri', check.message, refs);
10570
+ break;
10571
+ case 'uuid':
10572
+ addFormat(res, 'uuid', check.message, refs);
10573
+ break;
10574
+ case 'regex':
10575
+ addPattern(res, check.regex, check.message, refs);
10576
+ break;
10577
+ case 'cuid':
10578
+ addPattern(res, zodPatterns.cuid, check.message, refs);
10579
+ break;
10580
+ case 'cuid2':
10581
+ addPattern(res, zodPatterns.cuid2, check.message, refs);
10582
+ break;
10583
+ case 'startsWith':
10584
+ addPattern(res, RegExp(`^${processPattern(check.value)}`), check.message, refs);
10585
+ break;
10586
+ case 'endsWith':
10587
+ addPattern(res, RegExp(`${processPattern(check.value)}$`), check.message, refs);
10588
+ break;
10589
+ case 'datetime':
10590
+ addFormat(res, 'date-time', check.message, refs);
10591
+ break;
10592
+ case 'date':
10593
+ addFormat(res, 'date', check.message, refs);
10594
+ break;
10595
+ case 'time':
10596
+ addFormat(res, 'time', check.message, refs);
10597
+ break;
10598
+ case 'duration':
10599
+ addFormat(res, 'duration', check.message, refs);
10600
+ break;
10601
+ case 'length':
10602
+ setResponseValueAndErrors(res, 'minLength', typeof res.minLength === 'number' ? Math.max(res.minLength, check.value) : check.value, check.message, refs);
10603
+ setResponseValueAndErrors(res, 'maxLength', typeof res.maxLength === 'number' ? Math.min(res.maxLength, check.value) : check.value, check.message, refs);
10604
+ break;
10605
+ case 'includes': {
10606
+ addPattern(res, RegExp(processPattern(check.value)), check.message, refs);
10607
+ break;
10608
+ }
10609
+ case 'ip': {
10610
+ if (check.version !== 'v6') {
10611
+ addFormat(res, 'ipv4', check.message, refs);
10612
+ }
10613
+ if (check.version !== 'v4') {
10614
+ addFormat(res, 'ipv6', check.message, refs);
10615
+ }
10616
+ break;
10617
+ }
10618
+ case 'emoji':
10619
+ addPattern(res, zodPatterns.emoji, check.message, refs);
10620
+ break;
10621
+ case 'ulid': {
10622
+ addPattern(res, zodPatterns.ulid, check.message, refs);
10623
+ break;
10624
+ }
10625
+ case 'base64': {
10626
+ switch (refs.base64Strategy) {
10627
+ case 'format:binary': {
10628
+ addFormat(res, 'binary', check.message, refs);
10629
+ break;
10630
+ }
10631
+ case 'contentEncoding:base64': {
10632
+ setResponseValueAndErrors(res, 'contentEncoding', 'base64', check.message, refs);
10633
+ break;
10634
+ }
10635
+ case 'pattern:zod': {
10636
+ addPattern(res, zodPatterns.base64, check.message, refs);
10637
+ break;
10638
+ }
10639
+ }
10640
+ break;
10641
+ }
10642
+ case 'nanoid': {
10643
+ addPattern(res, zodPatterns.nanoid, check.message, refs);
10644
+ }
10645
+ }
10646
+ }
10647
+ }
10648
+ return res;
10649
+ }
10650
+ const escapeNonAlphaNumeric = (value) => Array.from(value)
10651
+ .map((c) => (/[a-zA-Z0-9]/.test(c) ? c : `\\${c}`))
10652
+ .join('');
10653
+ const addFormat = (schema, value, message, refs) => {
10654
+ if (schema.format || schema.anyOf?.some((x) => x.format)) {
10655
+ if (!schema.anyOf) {
10656
+ schema.anyOf = [];
10657
+ }
10658
+ if (schema.format) {
10659
+ schema.anyOf.push({
10660
+ format: schema.format,
10661
+ ...(schema.errorMessage &&
10662
+ refs.errorMessages && {
10663
+ errorMessage: { format: schema.errorMessage.format },
10664
+ }),
10665
+ });
10666
+ delete schema.format;
10667
+ if (schema.errorMessage) {
10668
+ delete schema.errorMessage.format;
10669
+ if (Object.keys(schema.errorMessage).length === 0) {
10670
+ delete schema.errorMessage;
10671
+ }
10672
+ }
10673
+ }
10674
+ schema.anyOf.push({
10675
+ format: value,
10676
+ ...(message && refs.errorMessages && { errorMessage: { format: message } }),
10677
+ });
10678
+ }
10679
+ else {
10680
+ setResponseValueAndErrors(schema, 'format', value, message, refs);
10681
+ }
10682
+ };
10683
+ const addPattern = (schema, regex, message, refs) => {
10684
+ if (schema.pattern || schema.allOf?.some((x) => x.pattern)) {
10685
+ if (!schema.allOf) {
10686
+ schema.allOf = [];
10687
+ }
10688
+ if (schema.pattern) {
10689
+ schema.allOf.push({
10690
+ pattern: schema.pattern,
10691
+ ...(schema.errorMessage &&
10692
+ refs.errorMessages && {
10693
+ errorMessage: { pattern: schema.errorMessage.pattern },
10694
+ }),
10695
+ });
10696
+ delete schema.pattern;
10697
+ if (schema.errorMessage) {
10698
+ delete schema.errorMessage.pattern;
10699
+ if (Object.keys(schema.errorMessage).length === 0) {
10700
+ delete schema.errorMessage;
10701
+ }
10702
+ }
10703
+ }
10704
+ schema.allOf.push({
10705
+ pattern: processRegExp(regex, refs),
10706
+ ...(message && refs.errorMessages && { errorMessage: { pattern: message } }),
10707
+ });
10708
+ }
10709
+ else {
10710
+ setResponseValueAndErrors(schema, 'pattern', processRegExp(regex, refs), message, refs);
10711
+ }
10712
+ };
10713
+ // Mutate z.string.regex() in a best attempt to accommodate for regex flags when applyRegexFlags is true
10714
+ const processRegExp = (regexOrFunction, refs) => {
10715
+ const regex = typeof regexOrFunction === 'function' ? regexOrFunction() : regexOrFunction;
10716
+ if (!refs.applyRegexFlags || !regex.flags)
10717
+ return regex.source;
10718
+ // Currently handled flags
10719
+ const flags = {
10720
+ i: regex.flags.includes('i'), // Case-insensitive
10721
+ m: regex.flags.includes('m'), // `^` and `$` matches adjacent to newline characters
10722
+ s: regex.flags.includes('s'), // `.` matches newlines
10723
+ };
10724
+ // The general principle here is to step through each character, one at a time, applying mutations as flags require. We keep track when the current character is escaped, and when it's inside a group /like [this]/ or (also) a range like /[a-z]/. The following is fairly brittle imperative code; edit at your peril!
10725
+ const source = flags.i ? regex.source.toLowerCase() : regex.source;
10726
+ let pattern = '';
10727
+ let isEscaped = false;
10728
+ let inCharGroup = false;
10729
+ let inCharRange = false;
10730
+ for (let i = 0; i < source.length; i++) {
10731
+ if (isEscaped) {
10732
+ pattern += source[i];
10733
+ isEscaped = false;
10734
+ continue;
10735
+ }
10736
+ if (flags.i) {
10737
+ if (inCharGroup) {
10738
+ if (source[i].match(/[a-z]/)) {
10739
+ if (inCharRange) {
10740
+ pattern += source[i];
10741
+ pattern += `${source[i - 2]}-${source[i]}`.toUpperCase();
10742
+ inCharRange = false;
10743
+ }
10744
+ else if (source[i + 1] === '-' && source[i + 2]?.match(/[a-z]/)) {
10745
+ pattern += source[i];
10746
+ inCharRange = true;
10747
+ }
10748
+ else {
10749
+ pattern += `${source[i]}${source[i].toUpperCase()}`;
10750
+ }
10751
+ continue;
10752
+ }
10753
+ }
10754
+ else if (source[i].match(/[a-z]/)) {
10755
+ pattern += `[${source[i]}${source[i].toUpperCase()}]`;
10756
+ continue;
10757
+ }
10758
+ }
10759
+ if (flags.m) {
10760
+ if (source[i] === '^') {
10761
+ pattern += `(^|(?<=[\r\n]))`;
10762
+ continue;
10763
+ }
10764
+ else if (source[i] === '$') {
10765
+ pattern += `($|(?=[\r\n]))`;
10766
+ continue;
10767
+ }
10768
+ }
10769
+ if (flags.s && source[i] === '.') {
10770
+ pattern += inCharGroup ? `${source[i]}\r\n` : `[${source[i]}\r\n]`;
10771
+ continue;
10772
+ }
10773
+ pattern += source[i];
10774
+ if (source[i] === '\\') {
10775
+ isEscaped = true;
10776
+ }
10777
+ else if (inCharGroup && source[i] === ']') {
10778
+ inCharGroup = false;
10779
+ }
10780
+ else if (!inCharGroup && source[i] === '[') {
10781
+ inCharGroup = true;
10782
+ }
10783
+ }
10784
+ try {
10785
+ const regexTest = new RegExp(pattern);
10786
+ }
10787
+ catch {
10788
+ console.warn(`Could not convert regex pattern at ${refs.currentPath.join('/')} to a flag-independent form! Falling back to the flag-ignorant source`);
10789
+ return regex.source;
10790
+ }
10791
+ return pattern;
10792
+ };
10793
+
10794
+ function parseRecordDef(def, refs) {
10795
+ if (refs.target === 'openApi3' && def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) {
10796
+ return {
10797
+ type: 'object',
10798
+ required: def.keyType._def.values,
10799
+ properties: def.keyType._def.values.reduce((acc, key) => ({
10800
+ ...acc,
10801
+ [key]: parseDef(def.valueType._def, {
10802
+ ...refs,
10803
+ currentPath: [...refs.currentPath, 'properties', key],
10804
+ }) ?? {},
10805
+ }), {}),
10806
+ additionalProperties: false,
10807
+ };
10808
+ }
10809
+ const schema = {
10810
+ type: 'object',
10811
+ additionalProperties: parseDef(def.valueType._def, {
10812
+ ...refs,
10813
+ currentPath: [...refs.currentPath, 'additionalProperties'],
10814
+ }) ?? {},
10815
+ };
10816
+ if (refs.target === 'openApi3') {
10817
+ return schema;
10818
+ }
10819
+ if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodString && def.keyType._def.checks?.length) {
10820
+ const keyType = Object.entries(parseStringDef(def.keyType._def, refs)).reduce((acc, [key, value]) => (key === 'type' ? acc : { ...acc, [key]: value }), {});
10821
+ return {
10822
+ ...schema,
10823
+ propertyNames: keyType,
10824
+ };
10825
+ }
10826
+ else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) {
10827
+ return {
10828
+ ...schema,
10829
+ propertyNames: {
10830
+ enum: def.keyType._def.values,
10831
+ },
10832
+ };
10833
+ }
10834
+ return schema;
10835
+ }
10836
+
10837
+ function parseMapDef(def, refs) {
10838
+ if (refs.mapStrategy === 'record') {
10839
+ return parseRecordDef(def, refs);
10840
+ }
10841
+ const keys = parseDef(def.keyType._def, {
10842
+ ...refs,
10843
+ currentPath: [...refs.currentPath, 'items', 'items', '0'],
10844
+ }) || {};
10845
+ const values = parseDef(def.valueType._def, {
10846
+ ...refs,
10847
+ currentPath: [...refs.currentPath, 'items', 'items', '1'],
10848
+ }) || {};
10849
+ return {
10850
+ type: 'array',
10851
+ maxItems: 125,
10852
+ items: {
10853
+ type: 'array',
10854
+ items: [keys, values],
10855
+ minItems: 2,
10856
+ maxItems: 2,
10857
+ },
10858
+ };
10859
+ }
10860
+
10861
+ function parseNativeEnumDef(def) {
10862
+ const object = def.values;
10863
+ const actualKeys = Object.keys(def.values).filter((key) => {
10864
+ return typeof object[object[key]] !== 'number';
10865
+ });
10866
+ const actualValues = actualKeys.map((key) => object[key]);
10867
+ const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values)));
10868
+ return {
10869
+ type: parsedTypes.length === 1 ?
10870
+ parsedTypes[0] === 'string' ?
10871
+ 'string'
10872
+ : 'number'
10873
+ : ['string', 'number'],
10874
+ enum: actualValues,
10875
+ };
10876
+ }
10877
+
10878
+ function parseNeverDef() {
10879
+ return {
10880
+ not: {},
10881
+ };
10882
+ }
10883
+
10884
+ function parseNullDef(refs) {
10885
+ return refs.target === 'openApi3' ?
10886
+ {
10887
+ enum: ['null'],
10888
+ nullable: true,
10889
+ }
10890
+ : {
10891
+ type: 'null',
10892
+ };
10893
+ }
10894
+
10895
+ const primitiveMappings = {
10896
+ ZodString: 'string',
10897
+ ZodNumber: 'number',
10898
+ ZodBigInt: 'integer',
10899
+ ZodBoolean: 'boolean',
10900
+ ZodNull: 'null',
10901
+ };
10902
+ function parseUnionDef(def, refs) {
10903
+ if (refs.target === 'openApi3')
10904
+ return asAnyOf(def, refs);
10905
+ const options = def.options instanceof Map ? Array.from(def.options.values()) : def.options;
10906
+ // This blocks tries to look ahead a bit to produce nicer looking schemas with type array instead of anyOf.
10907
+ if (options.every((x) => x._def.typeName in primitiveMappings && (!x._def.checks || !x._def.checks.length))) {
10908
+ // all types in union are primitive and lack checks, so might as well squash into {type: [...]}
10909
+ const types = options.reduce((types, x) => {
10910
+ const type = primitiveMappings[x._def.typeName]; //Can be safely casted due to row 43
10911
+ return type && !types.includes(type) ? [...types, type] : types;
10912
+ }, []);
10913
+ return {
10914
+ type: types.length > 1 ? types : types[0],
10915
+ };
10916
+ }
10917
+ else if (options.every((x) => x._def.typeName === 'ZodLiteral' && !x.description)) {
10918
+ // all options literals
10919
+ const types = options.reduce((acc, x) => {
10920
+ const type = typeof x._def.value;
10921
+ switch (type) {
10922
+ case 'string':
10923
+ case 'number':
10924
+ case 'boolean':
10925
+ return [...acc, type];
10926
+ case 'bigint':
10927
+ return [...acc, 'integer'];
10928
+ case 'object':
10929
+ if (x._def.value === null)
10930
+ return [...acc, 'null'];
10931
+ case 'symbol':
10932
+ case 'undefined':
10933
+ case 'function':
10934
+ default:
10935
+ return acc;
10936
+ }
10937
+ }, []);
10938
+ if (types.length === options.length) {
10939
+ // all the literals are primitive, as far as null can be considered primitive
10940
+ const uniqueTypes = types.filter((x, i, a) => a.indexOf(x) === i);
10941
+ return {
10942
+ type: uniqueTypes.length > 1 ? uniqueTypes : uniqueTypes[0],
10943
+ enum: options.reduce((acc, x) => {
10944
+ return acc.includes(x._def.value) ? acc : [...acc, x._def.value];
10945
+ }, []),
10946
+ };
10947
+ }
10948
+ }
10949
+ else if (options.every((x) => x._def.typeName === 'ZodEnum')) {
10950
+ return {
10951
+ type: 'string',
10952
+ enum: options.reduce((acc, x) => [...acc, ...x._def.values.filter((x) => !acc.includes(x))], []),
10953
+ };
10954
+ }
10955
+ return asAnyOf(def, refs);
10956
+ }
10957
+ const asAnyOf = (def, refs) => {
10958
+ const anyOf = (def.options instanceof Map ? Array.from(def.options.values()) : def.options)
10959
+ .map((x, i) => parseDef(x._def, {
10960
+ ...refs,
10961
+ currentPath: [...refs.currentPath, 'anyOf', `${i}`],
10962
+ }))
10963
+ .filter((x) => !!x && (!refs.strictUnions || (typeof x === 'object' && Object.keys(x).length > 0)));
10964
+ return anyOf.length ? { anyOf } : undefined;
10965
+ };
10966
+
10967
+ function parseNullableDef(def, refs) {
10968
+ if (['ZodString', 'ZodNumber', 'ZodBigInt', 'ZodBoolean', 'ZodNull'].includes(def.innerType._def.typeName) &&
10969
+ (!def.innerType._def.checks || !def.innerType._def.checks.length)) {
10970
+ if (refs.target === 'openApi3' || refs.nullableStrategy === 'property') {
10971
+ return {
10972
+ type: primitiveMappings[def.innerType._def.typeName],
10973
+ nullable: true,
10974
+ };
10975
+ }
10976
+ return {
10977
+ type: [primitiveMappings[def.innerType._def.typeName], 'null'],
10978
+ };
10979
+ }
10980
+ if (refs.target === 'openApi3') {
10981
+ const base = parseDef(def.innerType._def, {
10982
+ ...refs,
10983
+ currentPath: [...refs.currentPath],
10984
+ });
10985
+ if (base && '$ref' in base)
10986
+ return { allOf: [base], nullable: true };
10987
+ return base && { ...base, nullable: true };
10988
+ }
10989
+ const base = parseDef(def.innerType._def, {
10990
+ ...refs,
10991
+ currentPath: [...refs.currentPath, 'anyOf', '0'],
10992
+ });
10993
+ return base && { anyOf: [base, { type: 'null' }] };
10994
+ }
10995
+
10996
+ function parseNumberDef(def, refs) {
10997
+ const res = {
10998
+ type: 'number',
10999
+ };
11000
+ if (!def.checks)
11001
+ return res;
11002
+ for (const check of def.checks) {
11003
+ switch (check.kind) {
11004
+ case 'int':
11005
+ res.type = 'integer';
11006
+ addErrorMessage(res, 'type', check.message, refs);
11007
+ break;
11008
+ case 'min':
11009
+ if (refs.target === 'jsonSchema7') {
11010
+ if (check.inclusive) {
11011
+ setResponseValueAndErrors(res, 'minimum', check.value, check.message, refs);
11012
+ }
11013
+ else {
11014
+ setResponseValueAndErrors(res, 'exclusiveMinimum', check.value, check.message, refs);
11015
+ }
11016
+ }
11017
+ else {
11018
+ if (!check.inclusive) {
11019
+ res.exclusiveMinimum = true;
11020
+ }
11021
+ setResponseValueAndErrors(res, 'minimum', check.value, check.message, refs);
11022
+ }
11023
+ break;
11024
+ case 'max':
11025
+ if (refs.target === 'jsonSchema7') {
11026
+ if (check.inclusive) {
11027
+ setResponseValueAndErrors(res, 'maximum', check.value, check.message, refs);
11028
+ }
11029
+ else {
11030
+ setResponseValueAndErrors(res, 'exclusiveMaximum', check.value, check.message, refs);
11031
+ }
11032
+ }
11033
+ else {
11034
+ if (!check.inclusive) {
11035
+ res.exclusiveMaximum = true;
11036
+ }
11037
+ setResponseValueAndErrors(res, 'maximum', check.value, check.message, refs);
11038
+ }
11039
+ break;
11040
+ case 'multipleOf':
11041
+ setResponseValueAndErrors(res, 'multipleOf', check.value, check.message, refs);
11042
+ break;
11043
+ }
11044
+ }
11045
+ return res;
11046
+ }
11047
+
11048
+ function decideAdditionalProperties(def, refs) {
11049
+ if (refs.removeAdditionalStrategy === 'strict') {
11050
+ return def.catchall._def.typeName === 'ZodNever' ?
11051
+ def.unknownKeys !== 'strict'
11052
+ : parseDef(def.catchall._def, {
11053
+ ...refs,
11054
+ currentPath: [...refs.currentPath, 'additionalProperties'],
11055
+ }) ?? true;
11056
+ }
11057
+ else {
11058
+ return def.catchall._def.typeName === 'ZodNever' ?
11059
+ def.unknownKeys === 'passthrough'
11060
+ : parseDef(def.catchall._def, {
11061
+ ...refs,
11062
+ currentPath: [...refs.currentPath, 'additionalProperties'],
11063
+ }) ?? true;
11064
+ }
11065
+ }
11066
+ function parseObjectDef(def, refs) {
11067
+ const result = {
11068
+ type: 'object',
11069
+ ...Object.entries(def.shape()).reduce((acc, [propName, propDef]) => {
11070
+ if (propDef === undefined || propDef._def === undefined)
11071
+ return acc;
11072
+ const propertyPath = [...refs.currentPath, 'properties', propName];
11073
+ const parsedDef = parseDef(propDef._def, {
11074
+ ...refs,
11075
+ currentPath: propertyPath,
11076
+ propertyPath,
11077
+ });
11078
+ if (parsedDef === undefined)
11079
+ return acc;
11080
+ if (refs.openaiStrictMode &&
11081
+ propDef.isOptional() &&
11082
+ !propDef.isNullable() &&
11083
+ typeof propDef._def?.defaultValue === 'undefined') {
11084
+ throw new Error(`Zod field at \`${propertyPath.join('/')}\` uses \`.optional()\` without \`.nullable()\` which is not supported by the API. See: https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#all-fields-must-be-required`);
11085
+ }
11086
+ return {
11087
+ properties: {
11088
+ ...acc.properties,
11089
+ [propName]: parsedDef,
11090
+ },
11091
+ required: propDef.isOptional() && !refs.openaiStrictMode ? acc.required : [...acc.required, propName],
11092
+ };
11093
+ }, { properties: {}, required: [] }),
11094
+ additionalProperties: decideAdditionalProperties(def, refs),
11095
+ };
11096
+ if (!result.required.length)
11097
+ delete result.required;
11098
+ return result;
11099
+ }
11100
+
11101
+ const parseOptionalDef = (def, refs) => {
11102
+ if (refs.propertyPath &&
11103
+ refs.currentPath.slice(0, refs.propertyPath.length).toString() === refs.propertyPath.toString()) {
11104
+ return parseDef(def.innerType._def, { ...refs, currentPath: refs.currentPath });
11105
+ }
11106
+ const innerSchema = parseDef(def.innerType._def, {
11107
+ ...refs,
11108
+ currentPath: [...refs.currentPath, 'anyOf', '1'],
11109
+ });
11110
+ return innerSchema ?
11111
+ {
11112
+ anyOf: [
11113
+ {
11114
+ not: {},
11115
+ },
11116
+ innerSchema,
11117
+ ],
11118
+ }
11119
+ : {};
11120
+ };
11121
+
11122
+ const parsePipelineDef = (def, refs) => {
11123
+ if (refs.pipeStrategy === 'input') {
11124
+ return parseDef(def.in._def, refs);
11125
+ }
11126
+ else if (refs.pipeStrategy === 'output') {
11127
+ return parseDef(def.out._def, refs);
11128
+ }
11129
+ const a = parseDef(def.in._def, {
11130
+ ...refs,
11131
+ currentPath: [...refs.currentPath, 'allOf', '0'],
11132
+ });
11133
+ const b = parseDef(def.out._def, {
11134
+ ...refs,
11135
+ currentPath: [...refs.currentPath, 'allOf', a ? '1' : '0'],
11136
+ });
11137
+ return {
11138
+ allOf: [a, b].filter((x) => x !== undefined),
11139
+ };
11140
+ };
11141
+
11142
+ function parsePromiseDef(def, refs) {
11143
+ return parseDef(def.type._def, refs);
11144
+ }
11145
+
11146
+ function parseSetDef(def, refs) {
11147
+ const items = parseDef(def.valueType._def, {
11148
+ ...refs,
11149
+ currentPath: [...refs.currentPath, 'items'],
11150
+ });
11151
+ const schema = {
11152
+ type: 'array',
11153
+ uniqueItems: true,
11154
+ items,
11155
+ };
11156
+ if (def.minSize) {
11157
+ setResponseValueAndErrors(schema, 'minItems', def.minSize.value, def.minSize.message, refs);
11158
+ }
11159
+ if (def.maxSize) {
11160
+ setResponseValueAndErrors(schema, 'maxItems', def.maxSize.value, def.maxSize.message, refs);
11161
+ }
11162
+ return schema;
11163
+ }
11164
+
11165
+ function parseTupleDef(def, refs) {
11166
+ if (def.rest) {
11167
+ return {
11168
+ type: 'array',
11169
+ minItems: def.items.length,
11170
+ items: def.items
11171
+ .map((x, i) => parseDef(x._def, {
11172
+ ...refs,
11173
+ currentPath: [...refs.currentPath, 'items', `${i}`],
11174
+ }))
11175
+ .reduce((acc, x) => (x === undefined ? acc : [...acc, x]), []),
11176
+ additionalItems: parseDef(def.rest._def, {
11177
+ ...refs,
11178
+ currentPath: [...refs.currentPath, 'additionalItems'],
11179
+ }),
11180
+ };
11181
+ }
11182
+ else {
11183
+ return {
11184
+ type: 'array',
11185
+ minItems: def.items.length,
11186
+ maxItems: def.items.length,
11187
+ items: def.items
11188
+ .map((x, i) => parseDef(x._def, {
11189
+ ...refs,
11190
+ currentPath: [...refs.currentPath, 'items', `${i}`],
11191
+ }))
11192
+ .reduce((acc, x) => (x === undefined ? acc : [...acc, x]), []),
11193
+ };
11194
+ }
11195
+ }
11196
+
11197
+ function parseUndefinedDef() {
11198
+ return {
11199
+ not: {},
11200
+ };
11201
+ }
11202
+
11203
+ function parseUnknownDef() {
11204
+ return {};
11205
+ }
11206
+
11207
+ const parseReadonlyDef = (def, refs) => {
11208
+ return parseDef(def.innerType._def, refs);
11209
+ };
11210
+
11211
+ function parseDef(def, refs, forceResolution = false) {
11212
+ const seenItem = refs.seen.get(def);
11213
+ if (refs.override) {
11214
+ const overrideResult = refs.override?.(def, refs, seenItem, forceResolution);
11215
+ if (overrideResult !== ignoreOverride) {
11216
+ return overrideResult;
11217
+ }
11218
+ }
11219
+ if (seenItem && !forceResolution) {
11220
+ const seenSchema = get$ref(seenItem, refs);
11221
+ if (seenSchema !== undefined) {
11222
+ if ('$ref' in seenSchema) {
11223
+ refs.seenRefs.add(seenSchema.$ref);
11224
+ }
11225
+ return seenSchema;
11226
+ }
11227
+ }
11228
+ const newItem = { def, path: refs.currentPath, jsonSchema: undefined };
11229
+ refs.seen.set(def, newItem);
11230
+ const jsonSchema = selectParser(def, def.typeName, refs, forceResolution);
11231
+ if (jsonSchema) {
11232
+ addMeta(def, refs, jsonSchema);
11233
+ }
11234
+ newItem.jsonSchema = jsonSchema;
11235
+ return jsonSchema;
11236
+ }
11237
+ const get$ref = (item, refs) => {
11238
+ switch (refs.$refStrategy) {
11239
+ case 'root':
11240
+ return { $ref: item.path.join('/') };
11241
+ // this case is needed as OpenAI strict mode doesn't support top-level `$ref`s, i.e.
11242
+ // the top-level schema *must* be `{"type": "object", "properties": {...}}` but if we ever
11243
+ // need to define a `$ref`, relative `$ref`s aren't supported, so we need to extract
11244
+ // the schema to `#/definitions/` and reference that.
11245
+ //
11246
+ // e.g. if we need to reference a schema at
11247
+ // `["#","definitions","contactPerson","properties","person1","properties","name"]`
11248
+ // then we'll extract it out to `contactPerson_properties_person1_properties_name`
11249
+ case 'extract-to-root':
11250
+ const name = item.path.slice(refs.basePath.length + 1).join('_');
11251
+ // we don't need to extract the root schema in this case, as it's already
11252
+ // been added to the definitions
11253
+ if (name !== refs.name && refs.nameStrategy === 'duplicate-ref') {
11254
+ refs.definitions[name] = item.def;
11255
+ }
11256
+ return { $ref: [...refs.basePath, refs.definitionPath, name].join('/') };
11257
+ case 'relative':
11258
+ return { $ref: getRelativePath(refs.currentPath, item.path) };
11259
+ case 'none':
11260
+ case 'seen': {
11261
+ if (item.path.length < refs.currentPath.length &&
11262
+ item.path.every((value, index) => refs.currentPath[index] === value)) {
11263
+ console.warn(`Recursive reference detected at ${refs.currentPath.join('/')}! Defaulting to any`);
11264
+ return {};
11265
+ }
11266
+ return refs.$refStrategy === 'seen' ? {} : undefined;
11267
+ }
11268
+ }
11269
+ };
11270
+ const getRelativePath = (pathA, pathB) => {
11271
+ let i = 0;
11272
+ for (; i < pathA.length && i < pathB.length; i++) {
11273
+ if (pathA[i] !== pathB[i])
11274
+ break;
11275
+ }
11276
+ return [(pathA.length - i).toString(), ...pathB.slice(i)].join('/');
11277
+ };
11278
+ const selectParser = (def, typeName, refs, forceResolution) => {
11279
+ switch (typeName) {
11280
+ case ZodFirstPartyTypeKind.ZodString:
11281
+ return parseStringDef(def, refs);
11282
+ case ZodFirstPartyTypeKind.ZodNumber:
11283
+ return parseNumberDef(def, refs);
11284
+ case ZodFirstPartyTypeKind.ZodObject:
11285
+ return parseObjectDef(def, refs);
11286
+ case ZodFirstPartyTypeKind.ZodBigInt:
11287
+ return parseBigintDef(def, refs);
11288
+ case ZodFirstPartyTypeKind.ZodBoolean:
11289
+ return parseBooleanDef();
11290
+ case ZodFirstPartyTypeKind.ZodDate:
11291
+ return parseDateDef(def, refs);
11292
+ case ZodFirstPartyTypeKind.ZodUndefined:
11293
+ return parseUndefinedDef();
11294
+ case ZodFirstPartyTypeKind.ZodNull:
11295
+ return parseNullDef(refs);
11296
+ case ZodFirstPartyTypeKind.ZodArray:
11297
+ return parseArrayDef(def, refs);
11298
+ case ZodFirstPartyTypeKind.ZodUnion:
11299
+ case ZodFirstPartyTypeKind.ZodDiscriminatedUnion:
11300
+ return parseUnionDef(def, refs);
11301
+ case ZodFirstPartyTypeKind.ZodIntersection:
11302
+ return parseIntersectionDef(def, refs);
11303
+ case ZodFirstPartyTypeKind.ZodTuple:
11304
+ return parseTupleDef(def, refs);
11305
+ case ZodFirstPartyTypeKind.ZodRecord:
11306
+ return parseRecordDef(def, refs);
11307
+ case ZodFirstPartyTypeKind.ZodLiteral:
11308
+ return parseLiteralDef(def, refs);
11309
+ case ZodFirstPartyTypeKind.ZodEnum:
11310
+ return parseEnumDef(def);
11311
+ case ZodFirstPartyTypeKind.ZodNativeEnum:
11312
+ return parseNativeEnumDef(def);
11313
+ case ZodFirstPartyTypeKind.ZodNullable:
11314
+ return parseNullableDef(def, refs);
11315
+ case ZodFirstPartyTypeKind.ZodOptional:
11316
+ return parseOptionalDef(def, refs);
11317
+ case ZodFirstPartyTypeKind.ZodMap:
11318
+ return parseMapDef(def, refs);
11319
+ case ZodFirstPartyTypeKind.ZodSet:
11320
+ return parseSetDef(def, refs);
11321
+ case ZodFirstPartyTypeKind.ZodLazy:
11322
+ return parseDef(def.getter()._def, refs);
11323
+ case ZodFirstPartyTypeKind.ZodPromise:
11324
+ return parsePromiseDef(def, refs);
11325
+ case ZodFirstPartyTypeKind.ZodNaN:
11326
+ case ZodFirstPartyTypeKind.ZodNever:
11327
+ return parseNeverDef();
11328
+ case ZodFirstPartyTypeKind.ZodEffects:
11329
+ return parseEffectsDef(def, refs, forceResolution);
11330
+ case ZodFirstPartyTypeKind.ZodAny:
11331
+ return parseAnyDef();
11332
+ case ZodFirstPartyTypeKind.ZodUnknown:
11333
+ return parseUnknownDef();
11334
+ case ZodFirstPartyTypeKind.ZodDefault:
11335
+ return parseDefaultDef(def, refs);
11336
+ case ZodFirstPartyTypeKind.ZodBranded:
11337
+ return parseBrandedDef(def, refs);
11338
+ case ZodFirstPartyTypeKind.ZodReadonly:
11339
+ return parseReadonlyDef(def, refs);
11340
+ case ZodFirstPartyTypeKind.ZodCatch:
11341
+ return parseCatchDef(def, refs);
11342
+ case ZodFirstPartyTypeKind.ZodPipeline:
11343
+ return parsePipelineDef(def, refs);
11344
+ case ZodFirstPartyTypeKind.ZodFunction:
11345
+ case ZodFirstPartyTypeKind.ZodVoid:
11346
+ case ZodFirstPartyTypeKind.ZodSymbol:
11347
+ return undefined;
11348
+ default:
11349
+ return ((_) => undefined)();
11350
+ }
11351
+ };
11352
+ const addMeta = (def, refs, jsonSchema) => {
11353
+ if (def.description) {
11354
+ jsonSchema.description = def.description;
11355
+ if (refs.markdownDescription) {
11356
+ jsonSchema.markdownDescription = def.description;
11357
+ }
11358
+ }
11359
+ return jsonSchema;
11360
+ };
11361
+
11362
+ const zodToJsonSchema = (schema, options) => {
11363
+ const refs = getRefs(options);
11364
+ const name = typeof options === 'string' ? options
11365
+ : options?.nameStrategy === 'title' ? undefined
11366
+ : options?.name;
11367
+ const main = parseDef(schema._def, name === undefined ? refs : ({
11368
+ ...refs,
11369
+ currentPath: [...refs.basePath, refs.definitionPath, name],
11370
+ }), false) ?? {};
11371
+ const title = typeof options === 'object' && options.name !== undefined && options.nameStrategy === 'title' ?
11372
+ options.name
11373
+ : undefined;
11374
+ if (title !== undefined) {
11375
+ main.title = title;
11376
+ }
11377
+ const definitions = (() => {
11378
+ if (isEmptyObj(refs.definitions)) {
11379
+ return undefined;
11380
+ }
11381
+ const definitions = {};
11382
+ const processedDefinitions = new Set();
11383
+ // the call to `parseDef()` here might itself add more entries to `.definitions`
11384
+ // so we need to continually evaluate definitions until we've resolved all of them
11385
+ //
11386
+ // we have a generous iteration limit here to avoid blowing up the stack if there
11387
+ // are any bugs that would otherwise result in us iterating indefinitely
11388
+ for (let i = 0; i < 500; i++) {
11389
+ const newDefinitions = Object.entries(refs.definitions).filter(([key]) => !processedDefinitions.has(key));
11390
+ if (newDefinitions.length === 0)
11391
+ break;
11392
+ for (const [key, schema] of newDefinitions) {
11393
+ definitions[key] =
11394
+ parseDef(zodDef(schema), { ...refs, currentPath: [...refs.basePath, refs.definitionPath, key] }, true) ?? {};
11395
+ processedDefinitions.add(key);
11396
+ }
11397
+ }
11398
+ return definitions;
11399
+ })();
11400
+ const combined = name === undefined ?
11401
+ definitions ?
11402
+ {
11403
+ ...main,
11404
+ [refs.definitionPath]: definitions,
11405
+ }
11406
+ : main
11407
+ : refs.nameStrategy === 'duplicate-ref' ?
11408
+ {
11409
+ ...main,
11410
+ ...(definitions || refs.seenRefs.size ?
11411
+ {
11412
+ [refs.definitionPath]: {
11413
+ ...definitions,
11414
+ // only actually duplicate the schema definition if it was ever referenced
11415
+ // otherwise the duplication is completely pointless
11416
+ ...(refs.seenRefs.size ? { [name]: main } : undefined),
11417
+ },
11418
+ }
11419
+ : undefined),
11420
+ }
11421
+ : {
11422
+ $ref: [...(refs.$refStrategy === 'relative' ? [] : refs.basePath), refs.definitionPath, name].join('/'),
11423
+ [refs.definitionPath]: {
11424
+ ...definitions,
11425
+ [name]: main,
11426
+ },
11427
+ };
11428
+ if (refs.target === 'jsonSchema7') {
11429
+ combined.$schema = 'http://json-schema.org/draft-07/schema#';
11430
+ }
11431
+ else if (refs.target === 'jsonSchema2019-09') {
11432
+ combined.$schema = 'https://json-schema.org/draft/2019-09/schema#';
11433
+ }
11434
+ return combined;
11435
+ };
11436
+
11437
+ function toStrictJsonSchema(schema) {
11438
+ if (schema.type !== 'object') {
11439
+ throw new Error(`Root schema must have type: 'object' but got type: ${schema.type ? `'${schema.type}'` : 'undefined'}`);
11440
+ }
11441
+ const schemaCopy = structuredClone(schema);
11442
+ return ensureStrictJsonSchema(schemaCopy, [], schemaCopy);
11443
+ }
11444
+ function isNullable(schema) {
11445
+ if (typeof schema === 'boolean') {
11446
+ return false;
11447
+ }
11448
+ if (schema.type === 'null') {
11449
+ return true;
11450
+ }
11451
+ for (const oneOfVariant of schema.oneOf ?? []) {
11452
+ if (isNullable(oneOfVariant)) {
11453
+ return true;
11454
+ }
11455
+ }
11456
+ for (const allOfVariant of schema.anyOf ?? []) {
11457
+ if (isNullable(allOfVariant)) {
11458
+ return true;
11459
+ }
11460
+ }
11461
+ return false;
11462
+ }
11463
+ /**
11464
+ * Mutates the given JSON schema to ensure it conforms to the `strict` standard
11465
+ * that the API expects.
11466
+ */
11467
+ function ensureStrictJsonSchema(jsonSchema, path, root) {
11468
+ if (typeof jsonSchema === 'boolean') {
11469
+ throw new TypeError(`Expected object schema but got boolean; path=${path.join('/')}`);
11470
+ }
11471
+ if (!isObject(jsonSchema)) {
11472
+ throw new TypeError(`Expected ${JSON.stringify(jsonSchema)} to be an object; path=${path.join('/')}`);
11473
+ }
11474
+ // Handle $defs (non-standard but sometimes used)
11475
+ const defs = jsonSchema.$defs;
11476
+ if (isObject(defs)) {
11477
+ for (const [defName, defSchema] of Object.entries(defs)) {
11478
+ ensureStrictJsonSchema(defSchema, [...path, '$defs', defName], root);
11479
+ }
11480
+ }
11481
+ // Handle definitions (draft-04 style, deprecated in draft-07 but still used)
11482
+ const definitions = jsonSchema.definitions;
11483
+ if (isObject(definitions)) {
11484
+ for (const [definitionName, definitionSchema] of Object.entries(definitions)) {
11485
+ ensureStrictJsonSchema(definitionSchema, [...path, 'definitions', definitionName], root);
11486
+ }
11487
+ }
11488
+ // Add additionalProperties: false to object types
11489
+ const typ = jsonSchema.type;
11490
+ if (typ === 'object' && !('additionalProperties' in jsonSchema)) {
11491
+ jsonSchema.additionalProperties = false;
11492
+ }
11493
+ const required = jsonSchema.required ?? [];
11494
+ // Handle object properties
11495
+ const properties = jsonSchema.properties;
11496
+ if (isObject(properties)) {
11497
+ for (const [key, value] of Object.entries(properties)) {
11498
+ if (!isNullable(value) && !required.includes(key)) {
11499
+ throw new Error(`Zod field at \`${[...path, 'properties', key].join('/')}\` uses \`.optional()\` without \`.nullable()\` which is not supported by the API. See: https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#all-fields-must-be-required`);
11500
+ }
11501
+ }
11502
+ jsonSchema.required = Object.keys(properties);
11503
+ jsonSchema.properties = Object.fromEntries(Object.entries(properties).map(([key, propSchema]) => [
11504
+ key,
11505
+ ensureStrictJsonSchema(propSchema, [...path, 'properties', key], root),
11506
+ ]));
11507
+ }
11508
+ // Handle arrays
11509
+ const items = jsonSchema.items;
11510
+ if (isObject(items)) {
11511
+ jsonSchema.items = ensureStrictJsonSchema(items, [...path, 'items'], root);
11512
+ }
11513
+ // Handle unions (anyOf)
11514
+ const anyOf = jsonSchema.anyOf;
11515
+ if (Array.isArray(anyOf)) {
11516
+ jsonSchema.anyOf = anyOf.map((variant, i) => ensureStrictJsonSchema(variant, [...path, 'anyOf', String(i)], root));
11517
+ }
11518
+ // Handle intersections (allOf)
11519
+ const allOf = jsonSchema.allOf;
11520
+ if (Array.isArray(allOf)) {
11521
+ if (allOf.length === 1) {
11522
+ const resolved = ensureStrictJsonSchema(allOf[0], [...path, 'allOf', '0'], root);
11523
+ Object.assign(jsonSchema, resolved);
11524
+ delete jsonSchema.allOf;
11525
+ }
11526
+ else {
11527
+ jsonSchema.allOf = allOf.map((entry, i) => ensureStrictJsonSchema(entry, [...path, 'allOf', String(i)], root));
11528
+ }
11529
+ }
11530
+ // Strip `null` defaults as there's no meaningful distinction
11531
+ if (jsonSchema.default === null) {
11532
+ delete jsonSchema.default;
11533
+ }
11534
+ // Handle $ref with additional properties
11535
+ const ref = jsonSchema.$ref;
11536
+ if (ref && hasMoreThanNKeys(jsonSchema, 1)) {
11537
+ if (typeof ref !== 'string') {
11538
+ throw new TypeError(`Received non-string $ref - ${ref}; path=${path.join('/')}`);
11539
+ }
11540
+ const resolved = resolveRef(root, ref);
11541
+ if (typeof resolved === 'boolean') {
11542
+ throw new Error(`Expected \`$ref: ${ref}\` to resolve to an object schema but got boolean`);
11543
+ }
11544
+ if (!isObject(resolved)) {
11545
+ throw new Error(`Expected \`$ref: ${ref}\` to resolve to an object but got ${JSON.stringify(resolved)}`);
11546
+ }
11547
+ // Properties from the json schema take priority over the ones on the `$ref`
11548
+ Object.assign(jsonSchema, { ...resolved, ...jsonSchema });
11549
+ delete jsonSchema.$ref;
11550
+ // Since the schema expanded from `$ref` might not have `additionalProperties: false` applied,
11551
+ // we call `ensureStrictJsonSchema` again to fix the inlined schema and ensure it's valid.
11552
+ return ensureStrictJsonSchema(jsonSchema, path, root);
11553
+ }
11554
+ return jsonSchema;
11555
+ }
11556
+ function resolveRef(root, ref) {
11557
+ if (!ref.startsWith('#/')) {
11558
+ throw new Error(`Unexpected $ref format ${JSON.stringify(ref)}; Does not start with #/`);
11559
+ }
11560
+ const pathParts = ref.slice(2).split('/');
11561
+ let resolved = root;
11562
+ for (const key of pathParts) {
11563
+ if (!isObject(resolved)) {
11564
+ throw new Error(`encountered non-object entry while resolving ${ref} - ${JSON.stringify(resolved)}`);
11565
+ }
11566
+ const value = resolved[key];
11567
+ if (value === undefined) {
11568
+ throw new Error(`Key ${key} not found while resolving ${ref}`);
11569
+ }
11570
+ resolved = value;
11571
+ }
11572
+ return resolved;
11573
+ }
11574
+ function isObject(obj) {
11575
+ return typeof obj === 'object' && obj !== null && !Array.isArray(obj);
11576
+ }
11577
+ function hasMoreThanNKeys(obj, n) {
11578
+ let i = 0;
11579
+ for (const _ in obj) {
11580
+ i++;
11581
+ if (i > n) {
11582
+ return true;
11583
+ }
11584
+ }
11585
+ return false;
11586
+ }
11587
+
11588
+ function zodV3ToJsonSchema(schema, options) {
11589
+ return zodToJsonSchema(schema, {
11590
+ openaiStrictMode: true,
11591
+ name: options.name,
11592
+ nameStrategy: 'duplicate-ref',
11593
+ $refStrategy: 'extract-to-root',
11594
+ nullableStrategy: 'property',
11595
+ });
11596
+ }
11597
+ function zodV4ToJsonSchema(schema) {
11598
+ return toStrictJsonSchema(toJSONSchema(schema, {
11599
+ target: 'draft-7',
11600
+ }));
11601
+ }
11602
+ function isZodV4(zodObject) {
11603
+ return '_zod' in zodObject;
11604
+ }
11605
+ function zodTextFormat(zodObject, name, props) {
11606
+ return makeParseableTextFormat({
11607
+ type: 'json_schema',
11608
+ ...props,
11609
+ name,
11610
+ strict: true,
11611
+ schema: isZodV4(zodObject) ? zodV4ToJsonSchema(zodObject) : zodV3ToJsonSchema(zodObject, { name }),
11612
+ }, (content) => zodObject.parse(JSON.parse(content)));
11613
+ }
11614
+
11615
+ // llm-openai-config.ts
11616
+ const DEFAULT_MODEL = 'gpt-4.1-mini';
11617
+ const GPT_5_4_HIGH_CONTEXT_THRESHOLD_TOKENS = 272_000;
11618
+ const GPT_5_4_HIGH_CONTEXT_INPUT_MULTIPLIER = 2;
11619
+ const GPT_5_4_HIGH_CONTEXT_OUTPUT_MULTIPLIER = 1.5;
11620
+ /** Token costs in USD per 1M tokens. Last updated Mar 2026. */
11621
+ const openAiModelCosts = {
11622
+ 'gpt-4o': {
11623
+ inputCost: 2.5 / 1_000_000,
11624
+ cacheHitCost: 1.25 / 1_000_000,
11625
+ outputCost: 10 / 1_000_000,
11626
+ },
11627
+ 'gpt-4o-mini': {
11628
+ inputCost: 0.15 / 1_000_000,
11629
+ cacheHitCost: 0.075 / 1_000_000,
11630
+ outputCost: 0.6 / 1_000_000,
11631
+ },
11632
+ 'o1-mini': {
11633
+ inputCost: 1.1 / 1_000_000,
11634
+ cacheHitCost: 0.55 / 1_000_000,
11635
+ outputCost: 4.4 / 1_000_000,
11636
+ },
11637
+ 'o1': {
11638
+ inputCost: 15 / 1_000_000,
11639
+ cacheHitCost: 7.5 / 1_000_000,
11640
+ outputCost: 60 / 1_000_000,
11641
+ },
11642
+ 'o3-mini': {
11643
+ inputCost: 1.1 / 1_000_000,
11644
+ cacheHitCost: 0.55 / 1_000_000,
11645
+ outputCost: 4.4 / 1_000_000,
11646
+ },
11647
+ 'o3': {
11648
+ inputCost: 2 / 1_000_000,
11649
+ cacheHitCost: 0.5 / 1_000_000,
11650
+ outputCost: 8 / 1_000_000,
11651
+ },
11652
+ 'gpt-4.1': {
11653
+ inputCost: 2 / 1_000_000,
11654
+ cacheHitCost: 0.5 / 1_000_000,
11655
+ outputCost: 8 / 1_000_000,
11656
+ },
11657
+ 'gpt-4.1-mini': {
11658
+ inputCost: 0.4 / 1_000_000,
11659
+ cacheHitCost: 0.1 / 1_000_000,
11660
+ outputCost: 1.6 / 1_000_000,
11661
+ },
11662
+ 'gpt-4.1-nano': {
11663
+ inputCost: 0.1 / 1_000_000,
11664
+ cacheHitCost: 0.025 / 1_000_000,
11665
+ outputCost: 0.4 / 1_000_000,
11666
+ },
11667
+ 'gpt-5': {
11668
+ inputCost: 1.25 / 1_000_000,
11669
+ cacheHitCost: 0.125 / 1_000_000,
11670
+ outputCost: 10 / 1_000_000,
11671
+ },
11672
+ 'gpt-5-mini': {
11673
+ inputCost: 0.25 / 1_000_000,
11674
+ cacheHitCost: 0.025 / 1_000_000,
11675
+ outputCost: 2 / 1_000_000,
11676
+ },
11677
+ 'gpt-5-nano': {
11678
+ inputCost: 0.05 / 1_000_000,
11679
+ cacheHitCost: 0.005 / 1_000_000,
11680
+ outputCost: 0.4 / 1_000_000,
11681
+ },
11682
+ 'gpt-5.1': {
11683
+ inputCost: 1.25 / 1_000_000,
11684
+ cacheHitCost: 0.125 / 1_000_000,
11685
+ outputCost: 10 / 1_000_000,
11686
+ },
11687
+ 'gpt-5.4': {
11688
+ inputCost: 2.5 / 1_000_000,
11689
+ cacheHitCost: 0.25 / 1_000_000,
11690
+ outputCost: 15 / 1_000_000,
11691
+ },
11692
+ 'gpt-5.4-pro': {
11693
+ inputCost: 30 / 1_000_000,
11694
+ outputCost: 180 / 1_000_000,
11695
+ },
11696
+ 'gpt-5.2': {
11697
+ inputCost: 1.75 / 1_000_000,
11698
+ cacheHitCost: 0.175 / 1_000_000,
11699
+ outputCost: 14 / 1_000_000,
11700
+ },
11701
+ 'gpt-5.2-pro': {
11702
+ inputCost: 21 / 1_000_000,
11703
+ outputCost: 168 / 1_000_000,
11704
+ },
11705
+ 'gpt-5.1-codex': {
11706
+ inputCost: 1.25 / 1_000_000,
11707
+ cacheHitCost: 0.125 / 1_000_000,
11708
+ outputCost: 10 / 1_000_000,
11709
+ },
11710
+ 'gpt-5.1-codex-max': {
11711
+ inputCost: 1.25 / 1_000_000,
11712
+ cacheHitCost: 0.125 / 1_000_000,
11713
+ outputCost: 10 / 1_000_000,
11714
+ },
11715
+ 'o4-mini': {
11716
+ inputCost: 1.1 / 1_000_000,
11717
+ cacheHitCost: 0.275 / 1_000_000,
11718
+ outputCost: 4.4 / 1_000_000,
11719
+ },
11720
+ };
11721
+ const deepseekModelCosts = {
11722
+ 'deepseek-chat': {
11723
+ inputCost: 0.27 / 1_000_000, // $0.27 per 1M tokens (Cache miss price)
11724
+ cacheHitCost: 0.07 / 1_000_000, // $0.07 per 1M tokens (Cache hit price)
11725
+ outputCost: 1.1 / 1_000_000, // $1.10 per 1M tokens
11726
+ },
11727
+ 'deepseek-reasoner': {
11728
+ inputCost: 0.55 / 1_000_000, // $0.55 per 1M tokens (Cache miss price)
11729
+ cacheHitCost: 0.14 / 1_000_000, // $0.14 per 1M tokens (Cache hit price)
11730
+ outputCost: 2.19 / 1_000_000, // $2.19 per 1M tokens
11731
+ },
11732
+ };
11733
+ function shouldUseGPT54HighContextPricing(model, inputTokens) {
11734
+ return (model === 'gpt-5.4' || model === 'gpt-5.4-pro') && inputTokens > GPT_5_4_HIGH_CONTEXT_THRESHOLD_TOKENS;
11735
+ }
11736
+ /** Image generation costs in USD per image. Based on OpenAI pricing as of Feb 2025. */
11737
+ const openAiImageCosts = {
11738
+ 'gpt-image-1': 0.0075, // $0.0075 per image for gpt-image-1
11739
+ 'gpt-image-1.5': 0.0075, // Assumes parity pricing with gpt-image-1 until OpenAI publishes updated rates
11740
+ };
11741
+ /**
11742
+ * Calculates the cost of generating images using OpenAI's Images API.
11743
+ *
11744
+ * @param model The image generation model name.
11745
+ * @param imageCount The number of images generated.
11746
+ * @returns The cost of generating the images in USD.
11747
+ */
11748
+ function calculateImageCost(model, imageCount) {
11749
+ if (typeof model !== 'string' || typeof imageCount !== 'number' || imageCount <= 0) {
11750
+ return 0;
11751
+ }
11752
+ const costPerImage = openAiImageCosts[model];
11753
+ if (!costPerImage)
11754
+ return 0;
11755
+ return imageCount * costPerImage;
11756
+ }
11757
+ /**
11758
+ * Calculates the cost of calling a language model in USD based on the provider and model, tokens, and given costs per 1M tokens.
11759
+ *
11760
+ * @param provider The provider of the language model. Supported providers are 'openai' and 'deepseek'.
11761
+ * @param model The name of the language model. Supported models are listed in the `openAiModelCosts` and `deepseekModelCosts` objects.
11762
+ * @param inputTokens The number of input tokens passed to the language model.
11763
+ * @param outputTokens The number of output tokens generated by the language model.
11764
+ * @param reasoningTokens The number of output tokens generated by the language model for reasoning.
11765
+ * @param cacheHitTokens The number of input tokens billed at cached-input rates.
11766
+ * @returns The cost of calling the language model in USD.
11767
+ */
11768
+ function calculateCost(provider, model, inputTokens, outputTokens, reasoningTokens, cacheHitTokens) {
11769
+ if (typeof provider !== 'string' ||
11770
+ typeof model !== 'string' ||
11771
+ typeof inputTokens !== 'number' ||
11772
+ typeof outputTokens !== 'number' ||
11773
+ (reasoningTokens !== undefined && typeof reasoningTokens !== 'number') ||
11774
+ (cacheHitTokens !== undefined && typeof cacheHitTokens !== 'number')) {
11775
+ return 0;
11776
+ }
11777
+ const modelCosts = provider === 'deepseek' ? deepseekModelCosts[model] : openAiModelCosts[model];
11778
+ if (!modelCosts)
11779
+ return 0;
11780
+ const boundedCacheHitTokens = Math.min(Math.max(cacheHitTokens || 0, 0), inputTokens);
11781
+ let inputCost = inputTokens * modelCosts.inputCost;
11782
+ if (typeof modelCosts.cacheHitCost === 'number' && boundedCacheHitTokens > 0) {
11783
+ inputCost = boundedCacheHitTokens * modelCosts.cacheHitCost + (inputTokens - boundedCacheHitTokens) * modelCosts.inputCost;
11784
+ }
11785
+ let outputCost = outputTokens * modelCosts.outputCost;
11786
+ let reasoningCost = (reasoningTokens || 0) * modelCosts.outputCost;
11787
+ if (provider === 'openai' && shouldUseGPT54HighContextPricing(model, inputTokens)) {
11788
+ inputCost *= GPT_5_4_HIGH_CONTEXT_INPUT_MULTIPLIER;
11789
+ outputCost *= GPT_5_4_HIGH_CONTEXT_OUTPUT_MULTIPLIER;
11790
+ reasoningCost *= GPT_5_4_HIGH_CONTEXT_OUTPUT_MULTIPLIER;
11791
+ }
11792
+ return inputCost + outputCost + reasoningCost;
11793
+ }
11794
+
11795
+ /**
11796
+ * Fix a broken JSON string by attempting to extract and parse valid JSON content. This function is very lenient and will attempt to fix many types of JSON errors, including unbalanced brackets, missing or extra commas, improperly escaped $ signs, unquoted strings, trailing commas, missing closing brackets or braces, etc.
11797
+ * @param {string} jsonStr - The broken JSON string to fix
11798
+ * @returns {JsonValue} - The parsed JSON value
11799
+ */
11800
+ function fixBrokenJson(jsonStr) {
11801
+ // Pre-process: Fix improperly escaped $ signs
11802
+ jsonStr = jsonStr.replace(/\\\$/g, '$');
11803
+ let index = 0;
11804
+ function parse() {
11805
+ const results = [];
11806
+ while (index < jsonStr.length) {
11807
+ skipWhitespace();
11808
+ const value = parseValue();
11809
+ if (value !== undefined) {
11810
+ results.push(value);
11811
+ }
11812
+ else {
11813
+ index++; // Skip invalid character
11814
+ }
11815
+ }
11816
+ return results.length === 1 ? results[0] : results;
11817
+ }
11818
+ function parseValue() {
11819
+ skipWhitespace();
11820
+ const char = getChar();
11821
+ if (!char)
11822
+ return undefined;
11823
+ if (char === '{')
11824
+ return parseObject();
11825
+ if (char === '[')
11826
+ return parseArray();
11827
+ if (char === '"' || char === "'")
11828
+ return parseString();
11829
+ if (char === 't' && jsonStr.slice(index, index + 4).toLowerCase() === 'true') {
11830
+ index += 4;
11831
+ return true;
11832
+ }
11833
+ if (char === 'f' && jsonStr.slice(index, index + 5).toLowerCase() === 'false') {
11834
+ index += 5;
11835
+ return false;
11836
+ }
11837
+ if (char === 'n' && jsonStr.slice(index, index + 4).toLowerCase() === 'null') {
11838
+ index += 4;
11839
+ return null;
11840
+ }
11841
+ if (/[a-zA-Z]/.test(char))
11842
+ return parseString(); // Unquoted string
11843
+ if (char === '-' || char === '.' || /\d/.test(char))
11844
+ return parseNumber();
11845
+ return undefined; // Unknown character
11846
+ }
11847
+ function parseObject() {
11848
+ const obj = {};
11849
+ index++; // Skip opening brace
11850
+ skipWhitespace();
11851
+ while (index < jsonStr.length && getChar() !== '}') {
11852
+ skipWhitespace();
11853
+ const key = parseString();
11854
+ if (key === undefined) {
11855
+ console.warn(`Expected key at position ${index}`);
11856
+ index++;
11857
+ continue;
11858
+ }
11859
+ skipWhitespace();
11860
+ if (getChar() === ':') {
11861
+ index++; // Skip colon
11862
+ }
11863
+ else {
11864
+ console.warn(`Missing colon after key "${key}" at position ${index}`);
11865
+ }
11866
+ skipWhitespace();
11867
+ const value = parseValue();
11868
+ if (value === undefined) {
11869
+ console.warn(`Expected value for key "${key}" at position ${index}`);
11870
+ index++;
11871
+ continue;
11872
+ }
11873
+ obj[key] = value;
11874
+ skipWhitespace();
11875
+ if (getChar() === ',') {
11876
+ index++; // Skip comma
11877
+ }
11878
+ else {
11879
+ break;
11880
+ }
11881
+ skipWhitespace();
11882
+ }
11883
+ if (getChar() === '}') {
11884
+ index++; // Skip closing brace
9057
11885
  }
9058
11886
  else {
9059
11887
  // Add a closing brace if it's missing
@@ -9358,6 +12186,8 @@ const isSupportedModel = (model) => {
9358
12186
  'gpt-5-mini',
9359
12187
  'gpt-5-nano',
9360
12188
  'gpt-5.1',
12189
+ 'gpt-5.4',
12190
+ 'gpt-5.4-pro',
9361
12191
  'gpt-5.2',
9362
12192
  'gpt-5.2-pro',
9363
12193
  'gpt-5.1-codex',
@@ -9384,6 +12214,8 @@ function supportsTemperature(model) {
9384
12214
  'gpt-5-mini',
9385
12215
  'gpt-5-nano',
9386
12216
  'gpt-5.1',
12217
+ 'gpt-5.4',
12218
+ 'gpt-5.4-pro',
9387
12219
  'gpt-5.2',
9388
12220
  'gpt-5.2-pro',
9389
12221
  'gpt-5.1-codex',
@@ -9411,6 +12243,8 @@ function isGPT5Model(model) {
9411
12243
  'gpt-5-mini',
9412
12244
  'gpt-5-nano',
9413
12245
  'gpt-5.1',
12246
+ 'gpt-5.4',
12247
+ 'gpt-5.4-pro',
9414
12248
  'gpt-5.2',
9415
12249
  'gpt-5.2-pro',
9416
12250
  'gpt-5.1-codex',
@@ -9418,6 +12252,38 @@ function isGPT5Model(model) {
9418
12252
  ];
9419
12253
  return gpt5Models.includes(model);
9420
12254
  }
12255
+ function supportsStructuredOutputs(model) {
12256
+ return normalizeModelName(model) !== 'gpt-5.4-pro';
12257
+ }
12258
+ function supportsDistillation(model) {
12259
+ return normalizeModelName(model) !== 'gpt-5.4-pro';
12260
+ }
12261
+ function isZodSchema(schema) {
12262
+ return typeof schema === 'object' && schema !== null && 'safeParse' in schema;
12263
+ }
12264
+ function buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStrict) {
12265
+ if (isZodSchema(schema)) {
12266
+ const zodFormat = zodTextFormat(schema, schemaName, schemaDescription
12267
+ ? {
12268
+ description: schemaDescription,
12269
+ }
12270
+ : undefined);
12271
+ return {
12272
+ type: 'json_schema',
12273
+ name: zodFormat.name,
12274
+ schema: zodFormat.schema,
12275
+ ...(zodFormat.description ? { description: zodFormat.description } : {}),
12276
+ ...(schemaStrict !== undefined ? { strict: schemaStrict } : { strict: zodFormat.strict }),
12277
+ };
12278
+ }
12279
+ return {
12280
+ type: 'json_schema',
12281
+ name: schemaName,
12282
+ schema,
12283
+ ...(schemaDescription ? { description: schemaDescription } : {}),
12284
+ ...(schemaStrict !== undefined ? { strict: schemaStrict } : {}),
12285
+ };
12286
+ }
9421
12287
  /**
9422
12288
  * Makes a call to OpenAI's Responses API for more advanced use cases with built-in tools.
9423
12289
  *
@@ -9460,8 +12326,15 @@ const makeResponsesAPICall = async (input, options = {}) => {
9460
12326
  input,
9461
12327
  ...cleanOptions,
9462
12328
  };
12329
+ if (requestBody.text?.format?.type === 'json_schema' && !supportsStructuredOutputs(normalizedModel)) {
12330
+ throw new Error(`Model ${normalizedModel} does not support structured outputs`);
12331
+ }
12332
+ if (requestBody.store && !supportsDistillation(normalizedModel)) {
12333
+ throw new Error(`Model ${normalizedModel} does not support distillation`);
12334
+ }
9463
12335
  // Make the API call to the Responses endpoint
9464
12336
  const response = await openai.responses.create(requestBody);
12337
+ const cacheHitTokens = response.usage?.input_tokens_details?.cached_tokens || 0;
9465
12338
  // Extract tool calls from the output
9466
12339
  const toolCalls = response.output
9467
12340
  ?.filter((item) => item.type === 'function_call')
@@ -9501,7 +12374,8 @@ const makeResponsesAPICall = async (input, options = {}) => {
9501
12374
  reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,
9502
12375
  provider: 'openai',
9503
12376
  model: normalizedModel,
9504
- cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0),
12377
+ cache_hit_tokens: cacheHitTokens,
12378
+ cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, cacheHitTokens),
9505
12379
  },
9506
12380
  tool_calls: toolCalls,
9507
12381
  ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),
@@ -9517,9 +12391,13 @@ const makeResponsesAPICall = async (input, options = {}) => {
9517
12391
  .join('') || '';
9518
12392
  // Determine the format for parsing the response
9519
12393
  let parsingFormat = 'text';
9520
- if (requestBody.text?.format?.type === 'json_object') {
12394
+ const requestedFormat = requestBody.text?.format;
12395
+ if (requestedFormat?.type === 'json_object') {
9521
12396
  parsingFormat = 'json';
9522
12397
  }
12398
+ else if (requestedFormat?.type === 'json_schema') {
12399
+ parsingFormat = requestedFormat;
12400
+ }
9523
12401
  // Handle regular responses
9524
12402
  const parsedResponse = await parseResponse(textContent, parsingFormat);
9525
12403
  if (parsedResponse === null) {
@@ -9533,7 +12411,8 @@ const makeResponsesAPICall = async (input, options = {}) => {
9533
12411
  reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,
9534
12412
  provider: 'openai',
9535
12413
  model: normalizedModel,
9536
- cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0),
12414
+ cache_hit_tokens: cacheHitTokens,
12415
+ cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, cacheHitTokens),
9537
12416
  },
9538
12417
  tool_calls: toolCalls,
9539
12418
  ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),
@@ -9556,7 +12435,7 @@ const makeResponsesAPICall = async (input, options = {}) => {
9556
12435
  * });
9557
12436
  */
9558
12437
  async function makeLLMCall(input, options = {}) {
9559
- const { apiKey, model = DEFAULT_MODEL, responseFormat = 'text', tools, useCodeInterpreter = false, useWebSearch = false, imageBase64, imageDetail = 'high', context, } = options;
12438
+ const { apiKey, model = DEFAULT_MODEL, responseFormat = 'text', schema, schemaName = 'response', schemaDescription, schemaStrict, tools, useCodeInterpreter = false, useWebSearch = false, imageBase64, imageDetail = 'high', context, } = options;
9560
12439
  // Validate model
9561
12440
  const normalizedModel = normalizeModelName(model);
9562
12441
  if (!isSupportedModel(normalizedModel)) {
@@ -9634,9 +12513,17 @@ async function makeLLMCall(input, options = {}) {
9634
12513
  responsesOptions.temperature = 0.2;
9635
12514
  }
9636
12515
  // Configure response format
9637
- if (responseFormat === 'json') {
12516
+ if (schema) {
12517
+ responsesOptions.text = {
12518
+ format: buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStrict),
12519
+ };
12520
+ }
12521
+ else if (responseFormat === 'json') {
9638
12522
  responsesOptions.text = { format: { type: 'json_object' } };
9639
12523
  }
12524
+ else if (typeof responseFormat === 'object' && responseFormat.type === 'json_schema') {
12525
+ responsesOptions.text = { format: responseFormat };
12526
+ }
9640
12527
  // Configure built-in tools
9641
12528
  if (useCodeInterpreter) {
9642
12529
  responsesOptions.tools = [{ type: 'code_interpreter', container: { type: 'auto' } }];
@@ -9665,6 +12552,8 @@ const MULTIMODAL_VISION_MODELS = new Set([
9665
12552
  'gpt-5-mini',
9666
12553
  'gpt-5-nano',
9667
12554
  'gpt-5.1',
12555
+ 'gpt-5.4',
12556
+ 'gpt-5.4-pro',
9668
12557
  'gpt-5.2',
9669
12558
  'gpt-5.2-pro',
9670
12559
  'gpt-5.1-codex',