@discomedia/utils 1.0.62 → 1.0.64

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.cjs CHANGED
@@ -1581,7 +1581,7 @@ function maybeObj(x) {
1581
1581
  return x ?? {};
1582
1582
  }
1583
1583
  // https://stackoverflow.com/a/34491287
1584
- function isEmptyObj(obj) {
1584
+ function isEmptyObj$1(obj) {
1585
1585
  if (!obj)
1586
1586
  return true;
1587
1587
  for (const _k in obj)
@@ -1616,7 +1616,7 @@ const safeJSON = (text) => {
1616
1616
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
1617
1617
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1618
1618
 
1619
- const VERSION = '6.27.0'; // x-release-please-version
1619
+ const VERSION = '6.31.0'; // x-release-please-version
1620
1620
 
1621
1621
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
1622
1622
  const isRunningInBrowser = () => {
@@ -3320,6 +3320,20 @@ let Messages$1 = class Messages extends APIResource {
3320
3320
  function isChatCompletionFunctionTool(tool) {
3321
3321
  return tool !== undefined && 'function' in tool && tool.function !== undefined;
3322
3322
  }
3323
+ function makeParseableTextFormat(response_format, parser) {
3324
+ const obj = { ...response_format };
3325
+ Object.defineProperties(obj, {
3326
+ $brand: {
3327
+ value: 'auto-parseable-response-format',
3328
+ enumerable: false,
3329
+ },
3330
+ $parseRaw: {
3331
+ value: parser,
3332
+ enumerable: false,
3333
+ },
3334
+ });
3335
+ return obj;
3336
+ }
3323
3337
  function isAutoParsableResponseFormat(response_format) {
3324
3338
  return response_format?.['$brand'] === 'auto-parseable-response-format';
3325
3339
  }
@@ -4846,7 +4860,7 @@ class Speech extends APIResource {
4846
4860
  * const speech = await client.audio.speech.create({
4847
4861
  * input: 'input',
4848
4862
  * model: 'string',
4849
- * voice: 'ash',
4863
+ * voice: 'string',
4850
4864
  * });
4851
4865
  *
4852
4866
  * const content = await speech.blob();
@@ -5332,7 +5346,7 @@ const readEnv = (env) => {
5332
5346
  return undefined;
5333
5347
  };
5334
5348
 
5335
- 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;
5349
+ 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;
5336
5350
  class AssistantStream extends EventStream {
5337
5351
  constructor() {
5338
5352
  super(...arguments);
@@ -5407,7 +5421,7 @@ class AssistantStream extends EventStream {
5407
5421
  };
5408
5422
  }
5409
5423
  static fromReadableStream(stream) {
5410
- const runner = new _a$1();
5424
+ const runner = new _a$2();
5411
5425
  runner._run(() => runner._fromReadableStream(stream));
5412
5426
  return runner;
5413
5427
  }
@@ -5433,7 +5447,7 @@ class AssistantStream extends EventStream {
5433
5447
  return stream.toReadableStream();
5434
5448
  }
5435
5449
  static createToolAssistantStream(runId, runs, params, options) {
5436
- const runner = new _a$1();
5450
+ const runner = new _a$2();
5437
5451
  runner._run(() => runner._runToolAssistantStream(runId, runs, params, {
5438
5452
  ...options,
5439
5453
  headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'stream' },
@@ -5462,7 +5476,7 @@ class AssistantStream extends EventStream {
5462
5476
  return this._addRun(__classPrivateFieldGet(this, _AssistantStream_instances, "m", _AssistantStream_endRequest).call(this));
5463
5477
  }
5464
5478
  static createThreadAssistantStream(params, thread, options) {
5465
- const runner = new _a$1();
5479
+ const runner = new _a$2();
5466
5480
  runner._run(() => runner._threadAssistantStream(params, thread, {
5467
5481
  ...options,
5468
5482
  headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'stream' },
@@ -5470,7 +5484,7 @@ class AssistantStream extends EventStream {
5470
5484
  return runner;
5471
5485
  }
5472
5486
  static createAssistantStream(threadId, runs, params, options) {
5473
- const runner = new _a$1();
5487
+ const runner = new _a$2();
5474
5488
  runner._run(() => runner._runAssistantStream(threadId, runs, params, {
5475
5489
  ...options,
5476
5490
  headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'stream' },
@@ -5612,7 +5626,7 @@ class AssistantStream extends EventStream {
5612
5626
  return await this._createToolAssistantStream(runs, runId, params, options);
5613
5627
  }
5614
5628
  }
5615
- _a$1 = AssistantStream, _AssistantStream_addEvent = function _AssistantStream_addEvent(event) {
5629
+ _a$2 = AssistantStream, _AssistantStream_addEvent = function _AssistantStream_addEvent(event) {
5616
5630
  if (this.ended)
5617
5631
  return;
5618
5632
  __classPrivateFieldSet(this, _AssistantStream_currentEvent, event);
@@ -5790,7 +5804,7 @@ _a$1 = AssistantStream, _AssistantStream_addEvent = function _AssistantStream_ad
5790
5804
  }
5791
5805
  let data = event.data;
5792
5806
  if (data.delta) {
5793
- const accumulated = _a$1.accumulateDelta(snapshot, data.delta);
5807
+ const accumulated = _a$2.accumulateDelta(snapshot, data.delta);
5794
5808
  __classPrivateFieldGet(this, _AssistantStream_runStepSnapshots, "f")[event.data.id] = accumulated;
5795
5809
  }
5796
5810
  return __classPrivateFieldGet(this, _AssistantStream_runStepSnapshots, "f")[event.data.id];
@@ -5844,7 +5858,7 @@ _a$1 = AssistantStream, _AssistantStream_addEvent = function _AssistantStream_ad
5844
5858
  }
5845
5859
  throw Error('Tried to accumulate a non-message event');
5846
5860
  }, _AssistantStream_accumulateContent = function _AssistantStream_accumulateContent(contentElement, currentContent) {
5847
- return _a$1.accumulateDelta(currentContent, contentElement);
5861
+ return _a$2.accumulateDelta(currentContent, contentElement);
5848
5862
  }, _AssistantStream_handleRun = function _AssistantStream_handleRun(event) {
5849
5863
  __classPrivateFieldSet(this, _AssistantStream_currentRunSnapshot, event.data);
5850
5864
  switch (event.event) {
@@ -8127,7 +8141,7 @@ class Videos extends APIResource {
8127
8141
  * Create a new video generation job from a prompt and optional reference assets.
8128
8142
  */
8129
8143
  create(body, options) {
8130
- return this._client.post('/videos', maybeMultipartFormRequestOptions({ body, ...options }, this._client));
8144
+ return this._client.post('/videos', multipartFormRequestOptions({ body, ...options }, this._client));
8131
8145
  }
8132
8146
  /**
8133
8147
  * Fetch the latest metadata for a generated video.
@@ -8147,6 +8161,12 @@ class Videos extends APIResource {
8147
8161
  delete(videoID, options) {
8148
8162
  return this._client.delete(path `/videos/${videoID}`, options);
8149
8163
  }
8164
+ /**
8165
+ * Create a character from an uploaded video.
8166
+ */
8167
+ createCharacter(body, options) {
8168
+ return this._client.post('/videos/characters', multipartFormRequestOptions({ body, ...options }, this._client));
8169
+ }
8150
8170
  /**
8151
8171
  * Download the generated video bytes or a derived preview asset.
8152
8172
  *
@@ -8160,6 +8180,25 @@ class Videos extends APIResource {
8160
8180
  __binaryResponse: true,
8161
8181
  });
8162
8182
  }
8183
+ /**
8184
+ * Create a new video generation job by editing a source video or existing
8185
+ * generated video.
8186
+ */
8187
+ edit(body, options) {
8188
+ return this._client.post('/videos/edits', multipartFormRequestOptions({ body, ...options }, this._client));
8189
+ }
8190
+ /**
8191
+ * Create an extension of a completed video.
8192
+ */
8193
+ extend(body, options) {
8194
+ return this._client.post('/videos/extensions', multipartFormRequestOptions({ body, ...options }, this._client));
8195
+ }
8196
+ /**
8197
+ * Fetch a character.
8198
+ */
8199
+ getCharacter(characterID, options) {
8200
+ return this._client.get(path `/videos/characters/${characterID}`, options);
8201
+ }
8163
8202
  /**
8164
8203
  * Create a remix of a completed video using a refreshed prompt.
8165
8204
  */
@@ -8262,7 +8301,7 @@ _Webhooks_instances = new WeakSet(), _Webhooks_validateSecret = function _Webhoo
8262
8301
  };
8263
8302
 
8264
8303
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8265
- var _OpenAI_instances, _a, _OpenAI_encoder, _OpenAI_baseURLOverridden;
8304
+ var _OpenAI_instances, _a$1, _OpenAI_encoder, _OpenAI_baseURLOverridden;
8266
8305
  /**
8267
8306
  * API Client for interfacing with the OpenAI API.
8268
8307
  */
@@ -8353,7 +8392,7 @@ class OpenAI {
8353
8392
  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");
8354
8393
  }
8355
8394
  this.baseURL = options.baseURL;
8356
- this.timeout = options.timeout ?? _a.DEFAULT_TIMEOUT /* 10 minutes */;
8395
+ this.timeout = options.timeout ?? _a$1.DEFAULT_TIMEOUT /* 10 minutes */;
8357
8396
  this.logger = options.logger ?? console;
8358
8397
  const defaultLogLevel = 'warn';
8359
8398
  // Set default logLevel early so that we can log a warning in parseLogLevel.
@@ -8441,8 +8480,9 @@ class OpenAI {
8441
8480
  new URL(path)
8442
8481
  : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
8443
8482
  const defaultQuery = this.defaultQuery();
8444
- if (!isEmptyObj(defaultQuery)) {
8445
- query = { ...defaultQuery, ...query };
8483
+ const pathQuery = Object.fromEntries(url.searchParams);
8484
+ if (!isEmptyObj$1(defaultQuery) || !isEmptyObj$1(pathQuery)) {
8485
+ query = { ...pathQuery, ...defaultQuery, ...query };
8446
8486
  }
8447
8487
  if (typeof query === 'object' && query && !Array.isArray(query)) {
8448
8488
  url.search = this.stringifyQuery(query);
@@ -8783,10 +8823,10 @@ class OpenAI {
8783
8823
  }
8784
8824
  }
8785
8825
  }
8786
- _a = OpenAI, _OpenAI_encoder = new WeakMap(), _OpenAI_instances = new WeakSet(), _OpenAI_baseURLOverridden = function _OpenAI_baseURLOverridden() {
8826
+ _a$1 = OpenAI, _OpenAI_encoder = new WeakMap(), _OpenAI_instances = new WeakSet(), _OpenAI_baseURLOverridden = function _OpenAI_baseURLOverridden() {
8787
8827
  return this.baseURL !== 'https://api.openai.com/v1';
8788
8828
  };
8789
- OpenAI.OpenAI = _a;
8829
+ OpenAI.OpenAI = _a$1;
8790
8830
  OpenAI.DEFAULT_TIMEOUT = 600000; // 10 minutes
8791
8831
  OpenAI.OpenAIError = OpenAIError;
8792
8832
  OpenAI.APIError = APIError;
@@ -8826,6 +8866,2780 @@ OpenAI.Containers = Containers;
8826
8866
  OpenAI.Skills = Skills;
8827
8867
  OpenAI.Videos = Videos;
8828
8868
 
8869
+ // functions
8870
+ function getEnumValues(entries) {
8871
+ const numericValues = Object.values(entries).filter((v) => typeof v === "number");
8872
+ const values = Object.entries(entries)
8873
+ .filter(([k, _]) => numericValues.indexOf(+k) === -1)
8874
+ .map(([_, v]) => v);
8875
+ return values;
8876
+ }
8877
+
8878
+ var _a;
8879
+ class $ZodRegistry {
8880
+ constructor() {
8881
+ this._map = new WeakMap();
8882
+ this._idmap = new Map();
8883
+ }
8884
+ add(schema, ..._meta) {
8885
+ const meta = _meta[0];
8886
+ this._map.set(schema, meta);
8887
+ if (meta && typeof meta === "object" && "id" in meta) {
8888
+ this._idmap.set(meta.id, schema);
8889
+ }
8890
+ return this;
8891
+ }
8892
+ clear() {
8893
+ this._map = new WeakMap();
8894
+ this._idmap = new Map();
8895
+ return this;
8896
+ }
8897
+ remove(schema) {
8898
+ const meta = this._map.get(schema);
8899
+ if (meta && typeof meta === "object" && "id" in meta) {
8900
+ this._idmap.delete(meta.id);
8901
+ }
8902
+ this._map.delete(schema);
8903
+ return this;
8904
+ }
8905
+ get(schema) {
8906
+ // return this._map.get(schema) as any;
8907
+ // inherit metadata
8908
+ const p = schema._zod.parent;
8909
+ if (p) {
8910
+ const pm = { ...(this.get(p) ?? {}) };
8911
+ delete pm.id; // do not inherit id
8912
+ const f = { ...pm, ...this._map.get(schema) };
8913
+ return Object.keys(f).length ? f : undefined;
8914
+ }
8915
+ return this._map.get(schema);
8916
+ }
8917
+ has(schema) {
8918
+ return this._map.has(schema);
8919
+ }
8920
+ }
8921
+ // registries
8922
+ function registry() {
8923
+ return new $ZodRegistry();
8924
+ }
8925
+ (_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry());
8926
+ const globalRegistry = globalThis.__zod_globalRegistry;
8927
+
8928
+ // function initializeContext<T extends schemas.$ZodType>(inputs: JSONSchemaGeneratorParams<T>): ToJSONSchemaContext<T> {
8929
+ // return {
8930
+ // processor: inputs.processor,
8931
+ // metadataRegistry: inputs.metadata ?? globalRegistry,
8932
+ // target: inputs.target ?? "draft-2020-12",
8933
+ // unrepresentable: inputs.unrepresentable ?? "throw",
8934
+ // };
8935
+ // }
8936
+ function initializeContext(params) {
8937
+ // Normalize target: convert old non-hyphenated versions to hyphenated versions
8938
+ let target = params?.target ?? "draft-2020-12";
8939
+ if (target === "draft-4")
8940
+ target = "draft-04";
8941
+ if (target === "draft-7")
8942
+ target = "draft-07";
8943
+ return {
8944
+ processors: params.processors ?? {},
8945
+ metadataRegistry: params?.metadata ?? globalRegistry,
8946
+ target,
8947
+ unrepresentable: params?.unrepresentable ?? "throw",
8948
+ override: params?.override ?? (() => { }),
8949
+ io: params?.io ?? "output",
8950
+ counter: 0,
8951
+ seen: new Map(),
8952
+ cycles: params?.cycles ?? "ref",
8953
+ reused: params?.reused ?? "inline",
8954
+ external: params?.external ?? undefined,
8955
+ };
8956
+ }
8957
+ function process$1(schema, ctx, _params = { path: [], schemaPath: [] }) {
8958
+ var _a;
8959
+ const def = schema._zod.def;
8960
+ // check for schema in seens
8961
+ const seen = ctx.seen.get(schema);
8962
+ if (seen) {
8963
+ seen.count++;
8964
+ // check if cycle
8965
+ const isCycle = _params.schemaPath.includes(schema);
8966
+ if (isCycle) {
8967
+ seen.cycle = _params.path;
8968
+ }
8969
+ return seen.schema;
8970
+ }
8971
+ // initialize
8972
+ const result = { schema: {}, count: 1, cycle: undefined, path: _params.path };
8973
+ ctx.seen.set(schema, result);
8974
+ // custom method overrides default behavior
8975
+ const overrideSchema = schema._zod.toJSONSchema?.();
8976
+ if (overrideSchema) {
8977
+ result.schema = overrideSchema;
8978
+ }
8979
+ else {
8980
+ const params = {
8981
+ ..._params,
8982
+ schemaPath: [..._params.schemaPath, schema],
8983
+ path: _params.path,
8984
+ };
8985
+ if (schema._zod.processJSONSchema) {
8986
+ schema._zod.processJSONSchema(ctx, result.schema, params);
8987
+ }
8988
+ else {
8989
+ const _json = result.schema;
8990
+ const processor = ctx.processors[def.type];
8991
+ if (!processor) {
8992
+ throw new Error(`[toJSONSchema]: Non-representable type encountered: ${def.type}`);
8993
+ }
8994
+ processor(schema, ctx, _json, params);
8995
+ }
8996
+ const parent = schema._zod.parent;
8997
+ if (parent) {
8998
+ // Also set ref if processor didn't (for inheritance)
8999
+ if (!result.ref)
9000
+ result.ref = parent;
9001
+ process$1(parent, ctx, params);
9002
+ ctx.seen.get(parent).isParent = true;
9003
+ }
9004
+ }
9005
+ // metadata
9006
+ const meta = ctx.metadataRegistry.get(schema);
9007
+ if (meta)
9008
+ Object.assign(result.schema, meta);
9009
+ if (ctx.io === "input" && isTransforming(schema)) {
9010
+ // examples/defaults only apply to output type of pipe
9011
+ delete result.schema.examples;
9012
+ delete result.schema.default;
9013
+ }
9014
+ // set prefault as default
9015
+ if (ctx.io === "input" && result.schema._prefault)
9016
+ (_a = result.schema).default ?? (_a.default = result.schema._prefault);
9017
+ delete result.schema._prefault;
9018
+ // pulling fresh from ctx.seen in case it was overwritten
9019
+ const _result = ctx.seen.get(schema);
9020
+ return _result.schema;
9021
+ }
9022
+ function extractDefs(ctx, schema
9023
+ // params: EmitParams
9024
+ ) {
9025
+ // iterate over seen map;
9026
+ const root = ctx.seen.get(schema);
9027
+ if (!root)
9028
+ throw new Error("Unprocessed schema. This is a bug in Zod.");
9029
+ // Track ids to detect duplicates across different schemas
9030
+ const idToSchema = new Map();
9031
+ for (const entry of ctx.seen.entries()) {
9032
+ const id = ctx.metadataRegistry.get(entry[0])?.id;
9033
+ if (id) {
9034
+ const existing = idToSchema.get(id);
9035
+ if (existing && existing !== entry[0]) {
9036
+ throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);
9037
+ }
9038
+ idToSchema.set(id, entry[0]);
9039
+ }
9040
+ }
9041
+ // returns a ref to the schema
9042
+ // defId will be empty if the ref points to an external schema (or #)
9043
+ const makeURI = (entry) => {
9044
+ // comparing the seen objects because sometimes
9045
+ // multiple schemas map to the same seen object.
9046
+ // e.g. lazy
9047
+ // external is configured
9048
+ const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
9049
+ if (ctx.external) {
9050
+ const externalId = ctx.external.registry.get(entry[0])?.id; // ?? "__shared";// `__schema${ctx.counter++}`;
9051
+ // check if schema is in the external registry
9052
+ const uriGenerator = ctx.external.uri ?? ((id) => id);
9053
+ if (externalId) {
9054
+ return { ref: uriGenerator(externalId) };
9055
+ }
9056
+ // otherwise, add to __shared
9057
+ const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`;
9058
+ entry[1].defId = id; // set defId so it will be reused if needed
9059
+ return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` };
9060
+ }
9061
+ if (entry[1] === root) {
9062
+ return { ref: "#" };
9063
+ }
9064
+ // self-contained schema
9065
+ const uriPrefix = `#`;
9066
+ const defUriPrefix = `${uriPrefix}/${defsSegment}/`;
9067
+ const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`;
9068
+ return { defId, ref: defUriPrefix + defId };
9069
+ };
9070
+ // stored cached version in `def` property
9071
+ // remove all properties, set $ref
9072
+ const extractToDef = (entry) => {
9073
+ // if the schema is already a reference, do not extract it
9074
+ if (entry[1].schema.$ref) {
9075
+ return;
9076
+ }
9077
+ const seen = entry[1];
9078
+ const { ref, defId } = makeURI(entry);
9079
+ seen.def = { ...seen.schema };
9080
+ // defId won't be set if the schema is a reference to an external schema
9081
+ // or if the schema is the root schema
9082
+ if (defId)
9083
+ seen.defId = defId;
9084
+ // wipe away all properties except $ref
9085
+ const schema = seen.schema;
9086
+ for (const key in schema) {
9087
+ delete schema[key];
9088
+ }
9089
+ schema.$ref = ref;
9090
+ };
9091
+ // throw on cycles
9092
+ // break cycles
9093
+ if (ctx.cycles === "throw") {
9094
+ for (const entry of ctx.seen.entries()) {
9095
+ const seen = entry[1];
9096
+ if (seen.cycle) {
9097
+ throw new Error("Cycle detected: " +
9098
+ `#/${seen.cycle?.join("/")}/<root>` +
9099
+ '\n\nSet the `cycles` parameter to `"ref"` to resolve cyclical schemas with defs.');
9100
+ }
9101
+ }
9102
+ }
9103
+ // extract schemas into $defs
9104
+ for (const entry of ctx.seen.entries()) {
9105
+ const seen = entry[1];
9106
+ // convert root schema to # $ref
9107
+ if (schema === entry[0]) {
9108
+ extractToDef(entry); // this has special handling for the root schema
9109
+ continue;
9110
+ }
9111
+ // extract schemas that are in the external registry
9112
+ if (ctx.external) {
9113
+ const ext = ctx.external.registry.get(entry[0])?.id;
9114
+ if (schema !== entry[0] && ext) {
9115
+ extractToDef(entry);
9116
+ continue;
9117
+ }
9118
+ }
9119
+ // extract schemas with `id` meta
9120
+ const id = ctx.metadataRegistry.get(entry[0])?.id;
9121
+ if (id) {
9122
+ extractToDef(entry);
9123
+ continue;
9124
+ }
9125
+ // break cycles
9126
+ if (seen.cycle) {
9127
+ // any
9128
+ extractToDef(entry);
9129
+ continue;
9130
+ }
9131
+ // extract reused schemas
9132
+ if (seen.count > 1) {
9133
+ if (ctx.reused === "ref") {
9134
+ extractToDef(entry);
9135
+ // biome-ignore lint:
9136
+ continue;
9137
+ }
9138
+ }
9139
+ }
9140
+ }
9141
+ function finalize(ctx, schema) {
9142
+ const root = ctx.seen.get(schema);
9143
+ if (!root)
9144
+ throw new Error("Unprocessed schema. This is a bug in Zod.");
9145
+ // flatten refs - inherit properties from parent schemas
9146
+ const flattenRef = (zodSchema) => {
9147
+ const seen = ctx.seen.get(zodSchema);
9148
+ // already processed
9149
+ if (seen.ref === null)
9150
+ return;
9151
+ const schema = seen.def ?? seen.schema;
9152
+ const _cached = { ...schema };
9153
+ const ref = seen.ref;
9154
+ seen.ref = null; // prevent infinite recursion
9155
+ if (ref) {
9156
+ flattenRef(ref);
9157
+ const refSeen = ctx.seen.get(ref);
9158
+ const refSchema = refSeen.schema;
9159
+ // merge referenced schema into current
9160
+ if (refSchema.$ref && (ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0")) {
9161
+ // older drafts can't combine $ref with other properties
9162
+ schema.allOf = schema.allOf ?? [];
9163
+ schema.allOf.push(refSchema);
9164
+ }
9165
+ else {
9166
+ Object.assign(schema, refSchema);
9167
+ }
9168
+ // restore child's own properties (child wins)
9169
+ Object.assign(schema, _cached);
9170
+ const isParentRef = zodSchema._zod.parent === ref;
9171
+ // For parent chain, child is a refinement - remove parent-only properties
9172
+ if (isParentRef) {
9173
+ for (const key in schema) {
9174
+ if (key === "$ref" || key === "allOf")
9175
+ continue;
9176
+ if (!(key in _cached)) {
9177
+ delete schema[key];
9178
+ }
9179
+ }
9180
+ }
9181
+ // When ref was extracted to $defs, remove properties that match the definition
9182
+ if (refSchema.$ref && refSeen.def) {
9183
+ for (const key in schema) {
9184
+ if (key === "$ref" || key === "allOf")
9185
+ continue;
9186
+ if (key in refSeen.def && JSON.stringify(schema[key]) === JSON.stringify(refSeen.def[key])) {
9187
+ delete schema[key];
9188
+ }
9189
+ }
9190
+ }
9191
+ }
9192
+ // If parent was extracted (has $ref), propagate $ref to this schema
9193
+ // This handles cases like: readonly().meta({id}).describe()
9194
+ // where processor sets ref to innerType but parent should be referenced
9195
+ const parent = zodSchema._zod.parent;
9196
+ if (parent && parent !== ref) {
9197
+ // Ensure parent is processed first so its def has inherited properties
9198
+ flattenRef(parent);
9199
+ const parentSeen = ctx.seen.get(parent);
9200
+ if (parentSeen?.schema.$ref) {
9201
+ schema.$ref = parentSeen.schema.$ref;
9202
+ // De-duplicate with parent's definition
9203
+ if (parentSeen.def) {
9204
+ for (const key in schema) {
9205
+ if (key === "$ref" || key === "allOf")
9206
+ continue;
9207
+ if (key in parentSeen.def && JSON.stringify(schema[key]) === JSON.stringify(parentSeen.def[key])) {
9208
+ delete schema[key];
9209
+ }
9210
+ }
9211
+ }
9212
+ }
9213
+ }
9214
+ // execute overrides
9215
+ ctx.override({
9216
+ zodSchema: zodSchema,
9217
+ jsonSchema: schema,
9218
+ path: seen.path ?? [],
9219
+ });
9220
+ };
9221
+ for (const entry of [...ctx.seen.entries()].reverse()) {
9222
+ flattenRef(entry[0]);
9223
+ }
9224
+ const result = {};
9225
+ if (ctx.target === "draft-2020-12") {
9226
+ result.$schema = "https://json-schema.org/draft/2020-12/schema";
9227
+ }
9228
+ else if (ctx.target === "draft-07") {
9229
+ result.$schema = "http://json-schema.org/draft-07/schema#";
9230
+ }
9231
+ else if (ctx.target === "draft-04") {
9232
+ result.$schema = "http://json-schema.org/draft-04/schema#";
9233
+ }
9234
+ else if (ctx.target === "openapi-3.0") ;
9235
+ else ;
9236
+ if (ctx.external?.uri) {
9237
+ const id = ctx.external.registry.get(schema)?.id;
9238
+ if (!id)
9239
+ throw new Error("Schema is missing an `id` property");
9240
+ result.$id = ctx.external.uri(id);
9241
+ }
9242
+ Object.assign(result, root.def ?? root.schema);
9243
+ // build defs object
9244
+ const defs = ctx.external?.defs ?? {};
9245
+ for (const entry of ctx.seen.entries()) {
9246
+ const seen = entry[1];
9247
+ if (seen.def && seen.defId) {
9248
+ defs[seen.defId] = seen.def;
9249
+ }
9250
+ }
9251
+ // set definitions in result
9252
+ if (ctx.external) ;
9253
+ else {
9254
+ if (Object.keys(defs).length > 0) {
9255
+ if (ctx.target === "draft-2020-12") {
9256
+ result.$defs = defs;
9257
+ }
9258
+ else {
9259
+ result.definitions = defs;
9260
+ }
9261
+ }
9262
+ }
9263
+ try {
9264
+ // this "finalizes" this schema and ensures all cycles are removed
9265
+ // each call to finalize() is functionally independent
9266
+ // though the seen map is shared
9267
+ const finalized = JSON.parse(JSON.stringify(result));
9268
+ Object.defineProperty(finalized, "~standard", {
9269
+ value: {
9270
+ ...schema["~standard"],
9271
+ jsonSchema: {
9272
+ input: createStandardJSONSchemaMethod(schema, "input", ctx.processors),
9273
+ output: createStandardJSONSchemaMethod(schema, "output", ctx.processors),
9274
+ },
9275
+ },
9276
+ enumerable: false,
9277
+ writable: false,
9278
+ });
9279
+ return finalized;
9280
+ }
9281
+ catch (_err) {
9282
+ throw new Error("Error converting schema to JSON.");
9283
+ }
9284
+ }
9285
+ function isTransforming(_schema, _ctx) {
9286
+ const ctx = _ctx ?? { seen: new Set() };
9287
+ if (ctx.seen.has(_schema))
9288
+ return false;
9289
+ ctx.seen.add(_schema);
9290
+ const def = _schema._zod.def;
9291
+ if (def.type === "transform")
9292
+ return true;
9293
+ if (def.type === "array")
9294
+ return isTransforming(def.element, ctx);
9295
+ if (def.type === "set")
9296
+ return isTransforming(def.valueType, ctx);
9297
+ if (def.type === "lazy")
9298
+ return isTransforming(def.getter(), ctx);
9299
+ if (def.type === "promise" ||
9300
+ def.type === "optional" ||
9301
+ def.type === "nonoptional" ||
9302
+ def.type === "nullable" ||
9303
+ def.type === "readonly" ||
9304
+ def.type === "default" ||
9305
+ def.type === "prefault") {
9306
+ return isTransforming(def.innerType, ctx);
9307
+ }
9308
+ if (def.type === "intersection") {
9309
+ return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
9310
+ }
9311
+ if (def.type === "record" || def.type === "map") {
9312
+ return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
9313
+ }
9314
+ if (def.type === "pipe") {
9315
+ return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
9316
+ }
9317
+ if (def.type === "object") {
9318
+ for (const key in def.shape) {
9319
+ if (isTransforming(def.shape[key], ctx))
9320
+ return true;
9321
+ }
9322
+ return false;
9323
+ }
9324
+ if (def.type === "union") {
9325
+ for (const option of def.options) {
9326
+ if (isTransforming(option, ctx))
9327
+ return true;
9328
+ }
9329
+ return false;
9330
+ }
9331
+ if (def.type === "tuple") {
9332
+ for (const item of def.items) {
9333
+ if (isTransforming(item, ctx))
9334
+ return true;
9335
+ }
9336
+ if (def.rest && isTransforming(def.rest, ctx))
9337
+ return true;
9338
+ return false;
9339
+ }
9340
+ return false;
9341
+ }
9342
+ const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => {
9343
+ const { libraryOptions, target } = params ?? {};
9344
+ const ctx = initializeContext({ ...(libraryOptions ?? {}), target, io, processors });
9345
+ process$1(schema, ctx);
9346
+ extractDefs(ctx, schema);
9347
+ return finalize(ctx, schema);
9348
+ };
9349
+
9350
+ const formatMap = {
9351
+ guid: "uuid",
9352
+ url: "uri",
9353
+ datetime: "date-time",
9354
+ json_string: "json-string",
9355
+ regex: "", // do not set
9356
+ };
9357
+ // ==================== SIMPLE TYPE PROCESSORS ====================
9358
+ const stringProcessor = (schema, ctx, _json, _params) => {
9359
+ const json = _json;
9360
+ json.type = "string";
9361
+ const { minimum, maximum, format, patterns, contentEncoding } = schema._zod
9362
+ .bag;
9363
+ if (typeof minimum === "number")
9364
+ json.minLength = minimum;
9365
+ if (typeof maximum === "number")
9366
+ json.maxLength = maximum;
9367
+ // custom pattern overrides format
9368
+ if (format) {
9369
+ json.format = formatMap[format] ?? format;
9370
+ if (json.format === "")
9371
+ delete json.format; // empty format is not valid
9372
+ // JSON Schema format: "time" requires a full time with offset or Z
9373
+ // z.iso.time() does not include timezone information, so format: "time" should never be used
9374
+ if (format === "time") {
9375
+ delete json.format;
9376
+ }
9377
+ }
9378
+ if (contentEncoding)
9379
+ json.contentEncoding = contentEncoding;
9380
+ if (patterns && patterns.size > 0) {
9381
+ const regexes = [...patterns];
9382
+ if (regexes.length === 1)
9383
+ json.pattern = regexes[0].source;
9384
+ else if (regexes.length > 1) {
9385
+ json.allOf = [
9386
+ ...regexes.map((regex) => ({
9387
+ ...(ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0"
9388
+ ? { type: "string" }
9389
+ : {}),
9390
+ pattern: regex.source,
9391
+ })),
9392
+ ];
9393
+ }
9394
+ }
9395
+ };
9396
+ const numberProcessor = (schema, ctx, _json, _params) => {
9397
+ const json = _json;
9398
+ const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag;
9399
+ if (typeof format === "string" && format.includes("int"))
9400
+ json.type = "integer";
9401
+ else
9402
+ json.type = "number";
9403
+ if (typeof exclusiveMinimum === "number") {
9404
+ if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
9405
+ json.minimum = exclusiveMinimum;
9406
+ json.exclusiveMinimum = true;
9407
+ }
9408
+ else {
9409
+ json.exclusiveMinimum = exclusiveMinimum;
9410
+ }
9411
+ }
9412
+ if (typeof minimum === "number") {
9413
+ json.minimum = minimum;
9414
+ if (typeof exclusiveMinimum === "number" && ctx.target !== "draft-04") {
9415
+ if (exclusiveMinimum >= minimum)
9416
+ delete json.minimum;
9417
+ else
9418
+ delete json.exclusiveMinimum;
9419
+ }
9420
+ }
9421
+ if (typeof exclusiveMaximum === "number") {
9422
+ if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
9423
+ json.maximum = exclusiveMaximum;
9424
+ json.exclusiveMaximum = true;
9425
+ }
9426
+ else {
9427
+ json.exclusiveMaximum = exclusiveMaximum;
9428
+ }
9429
+ }
9430
+ if (typeof maximum === "number") {
9431
+ json.maximum = maximum;
9432
+ if (typeof exclusiveMaximum === "number" && ctx.target !== "draft-04") {
9433
+ if (exclusiveMaximum <= maximum)
9434
+ delete json.maximum;
9435
+ else
9436
+ delete json.exclusiveMaximum;
9437
+ }
9438
+ }
9439
+ if (typeof multipleOf === "number")
9440
+ json.multipleOf = multipleOf;
9441
+ };
9442
+ const booleanProcessor = (_schema, _ctx, json, _params) => {
9443
+ json.type = "boolean";
9444
+ };
9445
+ const bigintProcessor = (_schema, ctx, _json, _params) => {
9446
+ if (ctx.unrepresentable === "throw") {
9447
+ throw new Error("BigInt cannot be represented in JSON Schema");
9448
+ }
9449
+ };
9450
+ const symbolProcessor = (_schema, ctx, _json, _params) => {
9451
+ if (ctx.unrepresentable === "throw") {
9452
+ throw new Error("Symbols cannot be represented in JSON Schema");
9453
+ }
9454
+ };
9455
+ const nullProcessor = (_schema, ctx, json, _params) => {
9456
+ if (ctx.target === "openapi-3.0") {
9457
+ json.type = "string";
9458
+ json.nullable = true;
9459
+ json.enum = [null];
9460
+ }
9461
+ else {
9462
+ json.type = "null";
9463
+ }
9464
+ };
9465
+ const undefinedProcessor = (_schema, ctx, _json, _params) => {
9466
+ if (ctx.unrepresentable === "throw") {
9467
+ throw new Error("Undefined cannot be represented in JSON Schema");
9468
+ }
9469
+ };
9470
+ const voidProcessor = (_schema, ctx, _json, _params) => {
9471
+ if (ctx.unrepresentable === "throw") {
9472
+ throw new Error("Void cannot be represented in JSON Schema");
9473
+ }
9474
+ };
9475
+ const neverProcessor = (_schema, _ctx, json, _params) => {
9476
+ json.not = {};
9477
+ };
9478
+ const anyProcessor = (_schema, _ctx, _json, _params) => {
9479
+ // empty schema accepts anything
9480
+ };
9481
+ const unknownProcessor = (_schema, _ctx, _json, _params) => {
9482
+ // empty schema accepts anything
9483
+ };
9484
+ const dateProcessor = (_schema, ctx, _json, _params) => {
9485
+ if (ctx.unrepresentable === "throw") {
9486
+ throw new Error("Date cannot be represented in JSON Schema");
9487
+ }
9488
+ };
9489
+ const enumProcessor = (schema, _ctx, json, _params) => {
9490
+ const def = schema._zod.def;
9491
+ const values = getEnumValues(def.entries);
9492
+ // Number enums can have both string and number values
9493
+ if (values.every((v) => typeof v === "number"))
9494
+ json.type = "number";
9495
+ if (values.every((v) => typeof v === "string"))
9496
+ json.type = "string";
9497
+ json.enum = values;
9498
+ };
9499
+ const literalProcessor = (schema, ctx, json, _params) => {
9500
+ const def = schema._zod.def;
9501
+ const vals = [];
9502
+ for (const val of def.values) {
9503
+ if (val === undefined) {
9504
+ if (ctx.unrepresentable === "throw") {
9505
+ throw new Error("Literal `undefined` cannot be represented in JSON Schema");
9506
+ }
9507
+ }
9508
+ else if (typeof val === "bigint") {
9509
+ if (ctx.unrepresentable === "throw") {
9510
+ throw new Error("BigInt literals cannot be represented in JSON Schema");
9511
+ }
9512
+ else {
9513
+ vals.push(Number(val));
9514
+ }
9515
+ }
9516
+ else {
9517
+ vals.push(val);
9518
+ }
9519
+ }
9520
+ if (vals.length === 0) ;
9521
+ else if (vals.length === 1) {
9522
+ const val = vals[0];
9523
+ json.type = val === null ? "null" : typeof val;
9524
+ if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
9525
+ json.enum = [val];
9526
+ }
9527
+ else {
9528
+ json.const = val;
9529
+ }
9530
+ }
9531
+ else {
9532
+ if (vals.every((v) => typeof v === "number"))
9533
+ json.type = "number";
9534
+ if (vals.every((v) => typeof v === "string"))
9535
+ json.type = "string";
9536
+ if (vals.every((v) => typeof v === "boolean"))
9537
+ json.type = "boolean";
9538
+ if (vals.every((v) => v === null))
9539
+ json.type = "null";
9540
+ json.enum = vals;
9541
+ }
9542
+ };
9543
+ const nanProcessor = (_schema, ctx, _json, _params) => {
9544
+ if (ctx.unrepresentable === "throw") {
9545
+ throw new Error("NaN cannot be represented in JSON Schema");
9546
+ }
9547
+ };
9548
+ const templateLiteralProcessor = (schema, _ctx, json, _params) => {
9549
+ const _json = json;
9550
+ const pattern = schema._zod.pattern;
9551
+ if (!pattern)
9552
+ throw new Error("Pattern not found in template literal");
9553
+ _json.type = "string";
9554
+ _json.pattern = pattern.source;
9555
+ };
9556
+ const fileProcessor = (schema, _ctx, json, _params) => {
9557
+ const _json = json;
9558
+ const file = {
9559
+ type: "string",
9560
+ format: "binary",
9561
+ contentEncoding: "binary",
9562
+ };
9563
+ const { minimum, maximum, mime } = schema._zod.bag;
9564
+ if (minimum !== undefined)
9565
+ file.minLength = minimum;
9566
+ if (maximum !== undefined)
9567
+ file.maxLength = maximum;
9568
+ if (mime) {
9569
+ if (mime.length === 1) {
9570
+ file.contentMediaType = mime[0];
9571
+ Object.assign(_json, file);
9572
+ }
9573
+ else {
9574
+ Object.assign(_json, file); // shared props at root
9575
+ _json.anyOf = mime.map((m) => ({ contentMediaType: m })); // only contentMediaType differs
9576
+ }
9577
+ }
9578
+ else {
9579
+ Object.assign(_json, file);
9580
+ }
9581
+ };
9582
+ const successProcessor = (_schema, _ctx, json, _params) => {
9583
+ json.type = "boolean";
9584
+ };
9585
+ const customProcessor = (_schema, ctx, _json, _params) => {
9586
+ if (ctx.unrepresentable === "throw") {
9587
+ throw new Error("Custom types cannot be represented in JSON Schema");
9588
+ }
9589
+ };
9590
+ const functionProcessor = (_schema, ctx, _json, _params) => {
9591
+ if (ctx.unrepresentable === "throw") {
9592
+ throw new Error("Function types cannot be represented in JSON Schema");
9593
+ }
9594
+ };
9595
+ const transformProcessor = (_schema, ctx, _json, _params) => {
9596
+ if (ctx.unrepresentable === "throw") {
9597
+ throw new Error("Transforms cannot be represented in JSON Schema");
9598
+ }
9599
+ };
9600
+ const mapProcessor = (_schema, ctx, _json, _params) => {
9601
+ if (ctx.unrepresentable === "throw") {
9602
+ throw new Error("Map cannot be represented in JSON Schema");
9603
+ }
9604
+ };
9605
+ const setProcessor = (_schema, ctx, _json, _params) => {
9606
+ if (ctx.unrepresentable === "throw") {
9607
+ throw new Error("Set cannot be represented in JSON Schema");
9608
+ }
9609
+ };
9610
+ // ==================== COMPOSITE TYPE PROCESSORS ====================
9611
+ const arrayProcessor = (schema, ctx, _json, params) => {
9612
+ const json = _json;
9613
+ const def = schema._zod.def;
9614
+ const { minimum, maximum } = schema._zod.bag;
9615
+ if (typeof minimum === "number")
9616
+ json.minItems = minimum;
9617
+ if (typeof maximum === "number")
9618
+ json.maxItems = maximum;
9619
+ json.type = "array";
9620
+ json.items = process$1(def.element, ctx, { ...params, path: [...params.path, "items"] });
9621
+ };
9622
+ const objectProcessor = (schema, ctx, _json, params) => {
9623
+ const json = _json;
9624
+ const def = schema._zod.def;
9625
+ json.type = "object";
9626
+ json.properties = {};
9627
+ const shape = def.shape;
9628
+ for (const key in shape) {
9629
+ json.properties[key] = process$1(shape[key], ctx, {
9630
+ ...params,
9631
+ path: [...params.path, "properties", key],
9632
+ });
9633
+ }
9634
+ // required keys
9635
+ const allKeys = new Set(Object.keys(shape));
9636
+ const requiredKeys = new Set([...allKeys].filter((key) => {
9637
+ const v = def.shape[key]._zod;
9638
+ if (ctx.io === "input") {
9639
+ return v.optin === undefined;
9640
+ }
9641
+ else {
9642
+ return v.optout === undefined;
9643
+ }
9644
+ }));
9645
+ if (requiredKeys.size > 0) {
9646
+ json.required = Array.from(requiredKeys);
9647
+ }
9648
+ // catchall
9649
+ if (def.catchall?._zod.def.type === "never") {
9650
+ // strict
9651
+ json.additionalProperties = false;
9652
+ }
9653
+ else if (!def.catchall) {
9654
+ // regular
9655
+ if (ctx.io === "output")
9656
+ json.additionalProperties = false;
9657
+ }
9658
+ else if (def.catchall) {
9659
+ json.additionalProperties = process$1(def.catchall, ctx, {
9660
+ ...params,
9661
+ path: [...params.path, "additionalProperties"],
9662
+ });
9663
+ }
9664
+ };
9665
+ const unionProcessor = (schema, ctx, json, params) => {
9666
+ const def = schema._zod.def;
9667
+ // Exclusive unions (inclusive === false) use oneOf (exactly one match) instead of anyOf (one or more matches)
9668
+ // This includes both z.xor() and discriminated unions
9669
+ const isExclusive = def.inclusive === false;
9670
+ const options = def.options.map((x, i) => process$1(x, ctx, {
9671
+ ...params,
9672
+ path: [...params.path, isExclusive ? "oneOf" : "anyOf", i],
9673
+ }));
9674
+ if (isExclusive) {
9675
+ json.oneOf = options;
9676
+ }
9677
+ else {
9678
+ json.anyOf = options;
9679
+ }
9680
+ };
9681
+ const intersectionProcessor = (schema, ctx, json, params) => {
9682
+ const def = schema._zod.def;
9683
+ const a = process$1(def.left, ctx, {
9684
+ ...params,
9685
+ path: [...params.path, "allOf", 0],
9686
+ });
9687
+ const b = process$1(def.right, ctx, {
9688
+ ...params,
9689
+ path: [...params.path, "allOf", 1],
9690
+ });
9691
+ const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1;
9692
+ const allOf = [
9693
+ ...(isSimpleIntersection(a) ? a.allOf : [a]),
9694
+ ...(isSimpleIntersection(b) ? b.allOf : [b]),
9695
+ ];
9696
+ json.allOf = allOf;
9697
+ };
9698
+ const tupleProcessor = (schema, ctx, _json, params) => {
9699
+ const json = _json;
9700
+ const def = schema._zod.def;
9701
+ json.type = "array";
9702
+ const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
9703
+ const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
9704
+ const prefixItems = def.items.map((x, i) => process$1(x, ctx, {
9705
+ ...params,
9706
+ path: [...params.path, prefixPath, i],
9707
+ }));
9708
+ const rest = def.rest
9709
+ ? process$1(def.rest, ctx, {
9710
+ ...params,
9711
+ path: [...params.path, restPath, ...(ctx.target === "openapi-3.0" ? [def.items.length] : [])],
9712
+ })
9713
+ : null;
9714
+ if (ctx.target === "draft-2020-12") {
9715
+ json.prefixItems = prefixItems;
9716
+ if (rest) {
9717
+ json.items = rest;
9718
+ }
9719
+ }
9720
+ else if (ctx.target === "openapi-3.0") {
9721
+ json.items = {
9722
+ anyOf: prefixItems,
9723
+ };
9724
+ if (rest) {
9725
+ json.items.anyOf.push(rest);
9726
+ }
9727
+ json.minItems = prefixItems.length;
9728
+ if (!rest) {
9729
+ json.maxItems = prefixItems.length;
9730
+ }
9731
+ }
9732
+ else {
9733
+ json.items = prefixItems;
9734
+ if (rest) {
9735
+ json.additionalItems = rest;
9736
+ }
9737
+ }
9738
+ // length
9739
+ const { minimum, maximum } = schema._zod.bag;
9740
+ if (typeof minimum === "number")
9741
+ json.minItems = minimum;
9742
+ if (typeof maximum === "number")
9743
+ json.maxItems = maximum;
9744
+ };
9745
+ const recordProcessor = (schema, ctx, _json, params) => {
9746
+ const json = _json;
9747
+ const def = schema._zod.def;
9748
+ json.type = "object";
9749
+ // For looseRecord with regex patterns, use patternProperties
9750
+ // This correctly represents "only validate keys matching the pattern" semantics
9751
+ // and composes well with allOf (intersections)
9752
+ const keyType = def.keyType;
9753
+ const keyBag = keyType._zod.bag;
9754
+ const patterns = keyBag?.patterns;
9755
+ if (def.mode === "loose" && patterns && patterns.size > 0) {
9756
+ // Use patternProperties for looseRecord with regex patterns
9757
+ const valueSchema = process$1(def.valueType, ctx, {
9758
+ ...params,
9759
+ path: [...params.path, "patternProperties", "*"],
9760
+ });
9761
+ json.patternProperties = {};
9762
+ for (const pattern of patterns) {
9763
+ json.patternProperties[pattern.source] = valueSchema;
9764
+ }
9765
+ }
9766
+ else {
9767
+ // Default behavior: use propertyNames + additionalProperties
9768
+ if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
9769
+ json.propertyNames = process$1(def.keyType, ctx, {
9770
+ ...params,
9771
+ path: [...params.path, "propertyNames"],
9772
+ });
9773
+ }
9774
+ json.additionalProperties = process$1(def.valueType, ctx, {
9775
+ ...params,
9776
+ path: [...params.path, "additionalProperties"],
9777
+ });
9778
+ }
9779
+ // Add required for keys with discrete values (enum, literal, etc.)
9780
+ const keyValues = keyType._zod.values;
9781
+ if (keyValues) {
9782
+ const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
9783
+ if (validKeyValues.length > 0) {
9784
+ json.required = validKeyValues;
9785
+ }
9786
+ }
9787
+ };
9788
+ const nullableProcessor = (schema, ctx, json, params) => {
9789
+ const def = schema._zod.def;
9790
+ const inner = process$1(def.innerType, ctx, params);
9791
+ const seen = ctx.seen.get(schema);
9792
+ if (ctx.target === "openapi-3.0") {
9793
+ seen.ref = def.innerType;
9794
+ json.nullable = true;
9795
+ }
9796
+ else {
9797
+ json.anyOf = [inner, { type: "null" }];
9798
+ }
9799
+ };
9800
+ const nonoptionalProcessor = (schema, ctx, _json, params) => {
9801
+ const def = schema._zod.def;
9802
+ process$1(def.innerType, ctx, params);
9803
+ const seen = ctx.seen.get(schema);
9804
+ seen.ref = def.innerType;
9805
+ };
9806
+ const defaultProcessor = (schema, ctx, json, params) => {
9807
+ const def = schema._zod.def;
9808
+ process$1(def.innerType, ctx, params);
9809
+ const seen = ctx.seen.get(schema);
9810
+ seen.ref = def.innerType;
9811
+ json.default = JSON.parse(JSON.stringify(def.defaultValue));
9812
+ };
9813
+ const prefaultProcessor = (schema, ctx, json, params) => {
9814
+ const def = schema._zod.def;
9815
+ process$1(def.innerType, ctx, params);
9816
+ const seen = ctx.seen.get(schema);
9817
+ seen.ref = def.innerType;
9818
+ if (ctx.io === "input")
9819
+ json._prefault = JSON.parse(JSON.stringify(def.defaultValue));
9820
+ };
9821
+ const catchProcessor = (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
+ let catchValue;
9827
+ try {
9828
+ catchValue = def.catchValue(undefined);
9829
+ }
9830
+ catch {
9831
+ throw new Error("Dynamic catch values are not supported in JSON Schema");
9832
+ }
9833
+ json.default = catchValue;
9834
+ };
9835
+ const pipeProcessor = (schema, ctx, _json, params) => {
9836
+ const def = schema._zod.def;
9837
+ const innerType = ctx.io === "input" ? (def.in._zod.def.type === "transform" ? def.out : def.in) : def.out;
9838
+ process$1(innerType, ctx, params);
9839
+ const seen = ctx.seen.get(schema);
9840
+ seen.ref = innerType;
9841
+ };
9842
+ const readonlyProcessor = (schema, ctx, json, params) => {
9843
+ const def = schema._zod.def;
9844
+ process$1(def.innerType, ctx, params);
9845
+ const seen = ctx.seen.get(schema);
9846
+ seen.ref = def.innerType;
9847
+ json.readOnly = true;
9848
+ };
9849
+ const promiseProcessor = (schema, ctx, _json, params) => {
9850
+ const def = schema._zod.def;
9851
+ process$1(def.innerType, ctx, params);
9852
+ const seen = ctx.seen.get(schema);
9853
+ seen.ref = def.innerType;
9854
+ };
9855
+ const optionalProcessor = (schema, ctx, _json, params) => {
9856
+ const def = schema._zod.def;
9857
+ process$1(def.innerType, ctx, params);
9858
+ const seen = ctx.seen.get(schema);
9859
+ seen.ref = def.innerType;
9860
+ };
9861
+ const lazyProcessor = (schema, ctx, _json, params) => {
9862
+ const innerType = schema._zod.innerType;
9863
+ process$1(innerType, ctx, params);
9864
+ const seen = ctx.seen.get(schema);
9865
+ seen.ref = innerType;
9866
+ };
9867
+ // ==================== ALL PROCESSORS ====================
9868
+ const allProcessors = {
9869
+ string: stringProcessor,
9870
+ number: numberProcessor,
9871
+ boolean: booleanProcessor,
9872
+ bigint: bigintProcessor,
9873
+ symbol: symbolProcessor,
9874
+ null: nullProcessor,
9875
+ undefined: undefinedProcessor,
9876
+ void: voidProcessor,
9877
+ never: neverProcessor,
9878
+ any: anyProcessor,
9879
+ unknown: unknownProcessor,
9880
+ date: dateProcessor,
9881
+ enum: enumProcessor,
9882
+ literal: literalProcessor,
9883
+ nan: nanProcessor,
9884
+ template_literal: templateLiteralProcessor,
9885
+ file: fileProcessor,
9886
+ success: successProcessor,
9887
+ custom: customProcessor,
9888
+ function: functionProcessor,
9889
+ transform: transformProcessor,
9890
+ map: mapProcessor,
9891
+ set: setProcessor,
9892
+ array: arrayProcessor,
9893
+ object: objectProcessor,
9894
+ union: unionProcessor,
9895
+ intersection: intersectionProcessor,
9896
+ tuple: tupleProcessor,
9897
+ record: recordProcessor,
9898
+ nullable: nullableProcessor,
9899
+ nonoptional: nonoptionalProcessor,
9900
+ default: defaultProcessor,
9901
+ prefault: prefaultProcessor,
9902
+ catch: catchProcessor,
9903
+ pipe: pipeProcessor,
9904
+ readonly: readonlyProcessor,
9905
+ promise: promiseProcessor,
9906
+ optional: optionalProcessor,
9907
+ lazy: lazyProcessor,
9908
+ };
9909
+ function toJSONSchema(input, params) {
9910
+ if ("_idmap" in input) {
9911
+ // Registry case
9912
+ const registry = input;
9913
+ const ctx = initializeContext({ ...params, processors: allProcessors });
9914
+ const defs = {};
9915
+ // First pass: process all schemas to build the seen map
9916
+ for (const entry of registry._idmap.entries()) {
9917
+ const [_, schema] = entry;
9918
+ process$1(schema, ctx);
9919
+ }
9920
+ const schemas = {};
9921
+ const external = {
9922
+ registry,
9923
+ uri: params?.uri,
9924
+ defs,
9925
+ };
9926
+ // Update the context with external configuration
9927
+ ctx.external = external;
9928
+ // Second pass: emit each schema
9929
+ for (const entry of registry._idmap.entries()) {
9930
+ const [key, schema] = entry;
9931
+ extractDefs(ctx, schema);
9932
+ schemas[key] = finalize(ctx, schema);
9933
+ }
9934
+ if (Object.keys(defs).length > 0) {
9935
+ const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
9936
+ schemas.__shared = {
9937
+ [defsSegment]: defs,
9938
+ };
9939
+ }
9940
+ return { schemas };
9941
+ }
9942
+ // Single schema case
9943
+ const ctx = initializeContext({ ...params, processors: allProcessors });
9944
+ process$1(input, ctx);
9945
+ extractDefs(ctx, input);
9946
+ return finalize(ctx, input);
9947
+ }
9948
+
9949
+ const ignoreOverride = Symbol('Let zodToJsonSchema decide on which parser to use');
9950
+ const defaultOptions = {
9951
+ name: undefined,
9952
+ $refStrategy: 'root',
9953
+ effectStrategy: 'input',
9954
+ pipeStrategy: 'all',
9955
+ dateStrategy: 'format:date-time',
9956
+ mapStrategy: 'entries',
9957
+ nullableStrategy: 'from-target',
9958
+ removeAdditionalStrategy: 'passthrough',
9959
+ definitionPath: 'definitions',
9960
+ target: 'jsonSchema7',
9961
+ strictUnions: false,
9962
+ errorMessages: false,
9963
+ markdownDescription: false,
9964
+ patternStrategy: 'escape',
9965
+ applyRegexFlags: false,
9966
+ emailStrategy: 'format:email',
9967
+ base64Strategy: 'contentEncoding:base64',
9968
+ nameStrategy: 'ref',
9969
+ };
9970
+ const getDefaultOptions = (options) => {
9971
+ // We need to add `definitions` here as we may mutate it
9972
+ return (typeof options === 'string' ?
9973
+ {
9974
+ ...defaultOptions,
9975
+ basePath: ['#'],
9976
+ definitions: {},
9977
+ name: options,
9978
+ }
9979
+ : {
9980
+ ...defaultOptions,
9981
+ basePath: ['#'],
9982
+ definitions: {},
9983
+ ...options,
9984
+ });
9985
+ };
9986
+
9987
+ const zodDef = (zodSchema) => {
9988
+ return '_def' in zodSchema ? zodSchema._def : zodSchema;
9989
+ };
9990
+ function isEmptyObj(obj) {
9991
+ if (!obj)
9992
+ return true;
9993
+ for (const _k in obj)
9994
+ return false;
9995
+ return true;
9996
+ }
9997
+
9998
+ const getRefs = (options) => {
9999
+ const _options = getDefaultOptions(options);
10000
+ const currentPath = _options.name !== undefined ?
10001
+ [..._options.basePath, _options.definitionPath, _options.name]
10002
+ : _options.basePath;
10003
+ return {
10004
+ ..._options,
10005
+ currentPath: currentPath,
10006
+ propertyPath: undefined,
10007
+ seenRefs: new Set(),
10008
+ seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [
10009
+ zodDef(def),
10010
+ {
10011
+ def: zodDef(def),
10012
+ path: [..._options.basePath, _options.definitionPath, name],
10013
+ // Resolution of references will be forced even though seen, so it's ok that the schema is undefined here for now.
10014
+ jsonSchema: undefined,
10015
+ },
10016
+ ])),
10017
+ };
10018
+ };
10019
+
10020
+ function addErrorMessage(res, key, errorMessage, refs) {
10021
+ if (!refs?.errorMessages)
10022
+ return;
10023
+ if (errorMessage) {
10024
+ res.errorMessage = {
10025
+ ...res.errorMessage,
10026
+ [key]: errorMessage,
10027
+ };
10028
+ }
10029
+ }
10030
+ function setResponseValueAndErrors(res, key, value, errorMessage, refs) {
10031
+ res[key] = value;
10032
+ addErrorMessage(res, key, errorMessage, refs);
10033
+ }
10034
+
10035
+ var util;
10036
+ (function (util) {
10037
+ util.assertEqual = (_) => { };
10038
+ function assertIs(_arg) { }
10039
+ util.assertIs = assertIs;
10040
+ function assertNever(_x) {
10041
+ throw new Error();
10042
+ }
10043
+ util.assertNever = assertNever;
10044
+ util.arrayToEnum = (items) => {
10045
+ const obj = {};
10046
+ for (const item of items) {
10047
+ obj[item] = item;
10048
+ }
10049
+ return obj;
10050
+ };
10051
+ util.getValidEnumValues = (obj) => {
10052
+ const validKeys = util.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number");
10053
+ const filtered = {};
10054
+ for (const k of validKeys) {
10055
+ filtered[k] = obj[k];
10056
+ }
10057
+ return util.objectValues(filtered);
10058
+ };
10059
+ util.objectValues = (obj) => {
10060
+ return util.objectKeys(obj).map(function (e) {
10061
+ return obj[e];
10062
+ });
10063
+ };
10064
+ util.objectKeys = typeof Object.keys === "function" // eslint-disable-line ban/ban
10065
+ ? (obj) => Object.keys(obj) // eslint-disable-line ban/ban
10066
+ : (object) => {
10067
+ const keys = [];
10068
+ for (const key in object) {
10069
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
10070
+ keys.push(key);
10071
+ }
10072
+ }
10073
+ return keys;
10074
+ };
10075
+ util.find = (arr, checker) => {
10076
+ for (const item of arr) {
10077
+ if (checker(item))
10078
+ return item;
10079
+ }
10080
+ return undefined;
10081
+ };
10082
+ util.isInteger = typeof Number.isInteger === "function"
10083
+ ? (val) => Number.isInteger(val) // eslint-disable-line ban/ban
10084
+ : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val;
10085
+ function joinValues(array, separator = " | ") {
10086
+ return array.map((val) => (typeof val === "string" ? `'${val}'` : val)).join(separator);
10087
+ }
10088
+ util.joinValues = joinValues;
10089
+ util.jsonStringifyReplacer = (_, value) => {
10090
+ if (typeof value === "bigint") {
10091
+ return value.toString();
10092
+ }
10093
+ return value;
10094
+ };
10095
+ })(util || (util = {}));
10096
+ var objectUtil;
10097
+ (function (objectUtil) {
10098
+ objectUtil.mergeShapes = (first, second) => {
10099
+ return {
10100
+ ...first,
10101
+ ...second, // second overwrites first
10102
+ };
10103
+ };
10104
+ })(objectUtil || (objectUtil = {}));
10105
+ util.arrayToEnum([
10106
+ "string",
10107
+ "nan",
10108
+ "number",
10109
+ "integer",
10110
+ "float",
10111
+ "boolean",
10112
+ "date",
10113
+ "bigint",
10114
+ "symbol",
10115
+ "function",
10116
+ "undefined",
10117
+ "null",
10118
+ "array",
10119
+ "object",
10120
+ "unknown",
10121
+ "promise",
10122
+ "void",
10123
+ "never",
10124
+ "map",
10125
+ "set",
10126
+ ]);
10127
+
10128
+ util.arrayToEnum([
10129
+ "invalid_type",
10130
+ "invalid_literal",
10131
+ "custom",
10132
+ "invalid_union",
10133
+ "invalid_union_discriminator",
10134
+ "invalid_enum_value",
10135
+ "unrecognized_keys",
10136
+ "invalid_arguments",
10137
+ "invalid_return_type",
10138
+ "invalid_date",
10139
+ "invalid_string",
10140
+ "too_small",
10141
+ "too_big",
10142
+ "invalid_intersection_types",
10143
+ "not_multiple_of",
10144
+ "not_finite",
10145
+ ]);
10146
+ class ZodError extends Error {
10147
+ get errors() {
10148
+ return this.issues;
10149
+ }
10150
+ constructor(issues) {
10151
+ super();
10152
+ this.issues = [];
10153
+ this.addIssue = (sub) => {
10154
+ this.issues = [...this.issues, sub];
10155
+ };
10156
+ this.addIssues = (subs = []) => {
10157
+ this.issues = [...this.issues, ...subs];
10158
+ };
10159
+ const actualProto = new.target.prototype;
10160
+ if (Object.setPrototypeOf) {
10161
+ // eslint-disable-next-line ban/ban
10162
+ Object.setPrototypeOf(this, actualProto);
10163
+ }
10164
+ else {
10165
+ this.__proto__ = actualProto;
10166
+ }
10167
+ this.name = "ZodError";
10168
+ this.issues = issues;
10169
+ }
10170
+ format(_mapper) {
10171
+ const mapper = _mapper ||
10172
+ function (issue) {
10173
+ return issue.message;
10174
+ };
10175
+ const fieldErrors = { _errors: [] };
10176
+ const processError = (error) => {
10177
+ for (const issue of error.issues) {
10178
+ if (issue.code === "invalid_union") {
10179
+ issue.unionErrors.map(processError);
10180
+ }
10181
+ else if (issue.code === "invalid_return_type") {
10182
+ processError(issue.returnTypeError);
10183
+ }
10184
+ else if (issue.code === "invalid_arguments") {
10185
+ processError(issue.argumentsError);
10186
+ }
10187
+ else if (issue.path.length === 0) {
10188
+ fieldErrors._errors.push(mapper(issue));
10189
+ }
10190
+ else {
10191
+ let curr = fieldErrors;
10192
+ let i = 0;
10193
+ while (i < issue.path.length) {
10194
+ const el = issue.path[i];
10195
+ const terminal = i === issue.path.length - 1;
10196
+ if (!terminal) {
10197
+ curr[el] = curr[el] || { _errors: [] };
10198
+ // if (typeof el === "string") {
10199
+ // curr[el] = curr[el] || { _errors: [] };
10200
+ // } else if (typeof el === "number") {
10201
+ // const errorArray: any = [];
10202
+ // errorArray._errors = [];
10203
+ // curr[el] = curr[el] || errorArray;
10204
+ // }
10205
+ }
10206
+ else {
10207
+ curr[el] = curr[el] || { _errors: [] };
10208
+ curr[el]._errors.push(mapper(issue));
10209
+ }
10210
+ curr = curr[el];
10211
+ i++;
10212
+ }
10213
+ }
10214
+ }
10215
+ };
10216
+ processError(this);
10217
+ return fieldErrors;
10218
+ }
10219
+ static assert(value) {
10220
+ if (!(value instanceof ZodError)) {
10221
+ throw new Error(`Not a ZodError: ${value}`);
10222
+ }
10223
+ }
10224
+ toString() {
10225
+ return this.message;
10226
+ }
10227
+ get message() {
10228
+ return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2);
10229
+ }
10230
+ get isEmpty() {
10231
+ return this.issues.length === 0;
10232
+ }
10233
+ flatten(mapper = (issue) => issue.message) {
10234
+ const fieldErrors = Object.create(null);
10235
+ const formErrors = [];
10236
+ for (const sub of this.issues) {
10237
+ if (sub.path.length > 0) {
10238
+ const firstEl = sub.path[0];
10239
+ fieldErrors[firstEl] = fieldErrors[firstEl] || [];
10240
+ fieldErrors[firstEl].push(mapper(sub));
10241
+ }
10242
+ else {
10243
+ formErrors.push(mapper(sub));
10244
+ }
10245
+ }
10246
+ return { formErrors, fieldErrors };
10247
+ }
10248
+ get formErrors() {
10249
+ return this.flatten();
10250
+ }
10251
+ }
10252
+ ZodError.create = (issues) => {
10253
+ const error = new ZodError(issues);
10254
+ return error;
10255
+ };
10256
+
10257
+ var errorUtil;
10258
+ (function (errorUtil) {
10259
+ errorUtil.errToObj = (message) => typeof message === "string" ? { message } : message || {};
10260
+ // biome-ignore lint:
10261
+ errorUtil.toString = (message) => typeof message === "string" ? message : message?.message;
10262
+ })(errorUtil || (errorUtil = {}));
10263
+
10264
+ var ZodFirstPartyTypeKind;
10265
+ (function (ZodFirstPartyTypeKind) {
10266
+ ZodFirstPartyTypeKind["ZodString"] = "ZodString";
10267
+ ZodFirstPartyTypeKind["ZodNumber"] = "ZodNumber";
10268
+ ZodFirstPartyTypeKind["ZodNaN"] = "ZodNaN";
10269
+ ZodFirstPartyTypeKind["ZodBigInt"] = "ZodBigInt";
10270
+ ZodFirstPartyTypeKind["ZodBoolean"] = "ZodBoolean";
10271
+ ZodFirstPartyTypeKind["ZodDate"] = "ZodDate";
10272
+ ZodFirstPartyTypeKind["ZodSymbol"] = "ZodSymbol";
10273
+ ZodFirstPartyTypeKind["ZodUndefined"] = "ZodUndefined";
10274
+ ZodFirstPartyTypeKind["ZodNull"] = "ZodNull";
10275
+ ZodFirstPartyTypeKind["ZodAny"] = "ZodAny";
10276
+ ZodFirstPartyTypeKind["ZodUnknown"] = "ZodUnknown";
10277
+ ZodFirstPartyTypeKind["ZodNever"] = "ZodNever";
10278
+ ZodFirstPartyTypeKind["ZodVoid"] = "ZodVoid";
10279
+ ZodFirstPartyTypeKind["ZodArray"] = "ZodArray";
10280
+ ZodFirstPartyTypeKind["ZodObject"] = "ZodObject";
10281
+ ZodFirstPartyTypeKind["ZodUnion"] = "ZodUnion";
10282
+ ZodFirstPartyTypeKind["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion";
10283
+ ZodFirstPartyTypeKind["ZodIntersection"] = "ZodIntersection";
10284
+ ZodFirstPartyTypeKind["ZodTuple"] = "ZodTuple";
10285
+ ZodFirstPartyTypeKind["ZodRecord"] = "ZodRecord";
10286
+ ZodFirstPartyTypeKind["ZodMap"] = "ZodMap";
10287
+ ZodFirstPartyTypeKind["ZodSet"] = "ZodSet";
10288
+ ZodFirstPartyTypeKind["ZodFunction"] = "ZodFunction";
10289
+ ZodFirstPartyTypeKind["ZodLazy"] = "ZodLazy";
10290
+ ZodFirstPartyTypeKind["ZodLiteral"] = "ZodLiteral";
10291
+ ZodFirstPartyTypeKind["ZodEnum"] = "ZodEnum";
10292
+ ZodFirstPartyTypeKind["ZodEffects"] = "ZodEffects";
10293
+ ZodFirstPartyTypeKind["ZodNativeEnum"] = "ZodNativeEnum";
10294
+ ZodFirstPartyTypeKind["ZodOptional"] = "ZodOptional";
10295
+ ZodFirstPartyTypeKind["ZodNullable"] = "ZodNullable";
10296
+ ZodFirstPartyTypeKind["ZodDefault"] = "ZodDefault";
10297
+ ZodFirstPartyTypeKind["ZodCatch"] = "ZodCatch";
10298
+ ZodFirstPartyTypeKind["ZodPromise"] = "ZodPromise";
10299
+ ZodFirstPartyTypeKind["ZodBranded"] = "ZodBranded";
10300
+ ZodFirstPartyTypeKind["ZodPipeline"] = "ZodPipeline";
10301
+ ZodFirstPartyTypeKind["ZodReadonly"] = "ZodReadonly";
10302
+ })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
10303
+
10304
+ function parseAnyDef() {
10305
+ return {};
10306
+ }
10307
+
10308
+ function parseArrayDef(def, refs) {
10309
+ const res = {
10310
+ type: 'array',
10311
+ };
10312
+ if (def.type?._def?.typeName !== ZodFirstPartyTypeKind.ZodAny) {
10313
+ res.items = parseDef(def.type._def, {
10314
+ ...refs,
10315
+ currentPath: [...refs.currentPath, 'items'],
10316
+ });
10317
+ }
10318
+ if (def.minLength) {
10319
+ setResponseValueAndErrors(res, 'minItems', def.minLength.value, def.minLength.message, refs);
10320
+ }
10321
+ if (def.maxLength) {
10322
+ setResponseValueAndErrors(res, 'maxItems', def.maxLength.value, def.maxLength.message, refs);
10323
+ }
10324
+ if (def.exactLength) {
10325
+ setResponseValueAndErrors(res, 'minItems', def.exactLength.value, def.exactLength.message, refs);
10326
+ setResponseValueAndErrors(res, 'maxItems', def.exactLength.value, def.exactLength.message, refs);
10327
+ }
10328
+ return res;
10329
+ }
10330
+
10331
+ function parseBigintDef(def, refs) {
10332
+ const res = {
10333
+ type: 'integer',
10334
+ format: 'int64',
10335
+ };
10336
+ if (!def.checks)
10337
+ return res;
10338
+ for (const check of def.checks) {
10339
+ switch (check.kind) {
10340
+ case 'min':
10341
+ if (refs.target === 'jsonSchema7') {
10342
+ if (check.inclusive) {
10343
+ setResponseValueAndErrors(res, 'minimum', check.value, check.message, refs);
10344
+ }
10345
+ else {
10346
+ setResponseValueAndErrors(res, 'exclusiveMinimum', check.value, check.message, refs);
10347
+ }
10348
+ }
10349
+ else {
10350
+ if (!check.inclusive) {
10351
+ res.exclusiveMinimum = true;
10352
+ }
10353
+ setResponseValueAndErrors(res, 'minimum', check.value, check.message, refs);
10354
+ }
10355
+ break;
10356
+ case 'max':
10357
+ if (refs.target === 'jsonSchema7') {
10358
+ if (check.inclusive) {
10359
+ setResponseValueAndErrors(res, 'maximum', check.value, check.message, refs);
10360
+ }
10361
+ else {
10362
+ setResponseValueAndErrors(res, 'exclusiveMaximum', check.value, check.message, refs);
10363
+ }
10364
+ }
10365
+ else {
10366
+ if (!check.inclusive) {
10367
+ res.exclusiveMaximum = true;
10368
+ }
10369
+ setResponseValueAndErrors(res, 'maximum', check.value, check.message, refs);
10370
+ }
10371
+ break;
10372
+ case 'multipleOf':
10373
+ setResponseValueAndErrors(res, 'multipleOf', check.value, check.message, refs);
10374
+ break;
10375
+ }
10376
+ }
10377
+ return res;
10378
+ }
10379
+
10380
+ function parseBooleanDef() {
10381
+ return {
10382
+ type: 'boolean',
10383
+ };
10384
+ }
10385
+
10386
+ function parseBrandedDef(_def, refs) {
10387
+ return parseDef(_def.type._def, refs);
10388
+ }
10389
+
10390
+ const parseCatchDef = (def, refs) => {
10391
+ return parseDef(def.innerType._def, refs);
10392
+ };
10393
+
10394
+ function parseDateDef(def, refs, overrideDateStrategy) {
10395
+ const strategy = overrideDateStrategy ?? refs.dateStrategy;
10396
+ if (Array.isArray(strategy)) {
10397
+ return {
10398
+ anyOf: strategy.map((item, i) => parseDateDef(def, refs, item)),
10399
+ };
10400
+ }
10401
+ switch (strategy) {
10402
+ case 'string':
10403
+ case 'format:date-time':
10404
+ return {
10405
+ type: 'string',
10406
+ format: 'date-time',
10407
+ };
10408
+ case 'format:date':
10409
+ return {
10410
+ type: 'string',
10411
+ format: 'date',
10412
+ };
10413
+ case 'integer':
10414
+ return integerDateParser(def, refs);
10415
+ }
10416
+ }
10417
+ const integerDateParser = (def, refs) => {
10418
+ const res = {
10419
+ type: 'integer',
10420
+ format: 'unix-time',
10421
+ };
10422
+ if (refs.target === 'openApi3') {
10423
+ return res;
10424
+ }
10425
+ for (const check of def.checks) {
10426
+ switch (check.kind) {
10427
+ case 'min':
10428
+ setResponseValueAndErrors(res, 'minimum', check.value, // This is in milliseconds
10429
+ check.message, refs);
10430
+ break;
10431
+ case 'max':
10432
+ setResponseValueAndErrors(res, 'maximum', check.value, // This is in milliseconds
10433
+ check.message, refs);
10434
+ break;
10435
+ }
10436
+ }
10437
+ return res;
10438
+ };
10439
+
10440
+ function parseDefaultDef(_def, refs) {
10441
+ return {
10442
+ ...parseDef(_def.innerType._def, refs),
10443
+ default: _def.defaultValue(),
10444
+ };
10445
+ }
10446
+
10447
+ function parseEffectsDef(_def, refs, forceResolution) {
10448
+ return refs.effectStrategy === 'input' ? parseDef(_def.schema._def, refs, forceResolution) : {};
10449
+ }
10450
+
10451
+ function parseEnumDef(def) {
10452
+ return {
10453
+ type: 'string',
10454
+ enum: [...def.values],
10455
+ };
10456
+ }
10457
+
10458
+ const isJsonSchema7AllOfType = (type) => {
10459
+ if ('type' in type && type.type === 'string')
10460
+ return false;
10461
+ return 'allOf' in type;
10462
+ };
10463
+ function parseIntersectionDef(def, refs) {
10464
+ const allOf = [
10465
+ parseDef(def.left._def, {
10466
+ ...refs,
10467
+ currentPath: [...refs.currentPath, 'allOf', '0'],
10468
+ }),
10469
+ parseDef(def.right._def, {
10470
+ ...refs,
10471
+ currentPath: [...refs.currentPath, 'allOf', '1'],
10472
+ }),
10473
+ ].filter((x) => !!x);
10474
+ let unevaluatedProperties = refs.target === 'jsonSchema2019-09' ? { unevaluatedProperties: false } : undefined;
10475
+ const mergedAllOf = [];
10476
+ // If either of the schemas is an allOf, merge them into a single allOf
10477
+ allOf.forEach((schema) => {
10478
+ if (isJsonSchema7AllOfType(schema)) {
10479
+ mergedAllOf.push(...schema.allOf);
10480
+ if (schema.unevaluatedProperties === undefined) {
10481
+ // If one of the schemas has no unevaluatedProperties set,
10482
+ // the merged schema should also have no unevaluatedProperties set
10483
+ unevaluatedProperties = undefined;
10484
+ }
10485
+ }
10486
+ else {
10487
+ let nestedSchema = schema;
10488
+ if ('additionalProperties' in schema && schema.additionalProperties === false) {
10489
+ const { additionalProperties, ...rest } = schema;
10490
+ nestedSchema = rest;
10491
+ }
10492
+ else {
10493
+ // As soon as one of the schemas has additionalProperties set not to false, we allow unevaluatedProperties
10494
+ unevaluatedProperties = undefined;
10495
+ }
10496
+ mergedAllOf.push(nestedSchema);
10497
+ }
10498
+ });
10499
+ return mergedAllOf.length ?
10500
+ {
10501
+ allOf: mergedAllOf,
10502
+ ...unevaluatedProperties,
10503
+ }
10504
+ : undefined;
10505
+ }
10506
+
10507
+ function parseLiteralDef(def, refs) {
10508
+ const parsedType = typeof def.value;
10509
+ if (parsedType !== 'bigint' &&
10510
+ parsedType !== 'number' &&
10511
+ parsedType !== 'boolean' &&
10512
+ parsedType !== 'string') {
10513
+ return {
10514
+ type: Array.isArray(def.value) ? 'array' : 'object',
10515
+ };
10516
+ }
10517
+ if (refs.target === 'openApi3') {
10518
+ return {
10519
+ type: parsedType === 'bigint' ? 'integer' : parsedType,
10520
+ enum: [def.value],
10521
+ };
10522
+ }
10523
+ return {
10524
+ type: parsedType === 'bigint' ? 'integer' : parsedType,
10525
+ const: def.value,
10526
+ };
10527
+ }
10528
+
10529
+ let emojiRegex;
10530
+ /**
10531
+ * Generated from the regular expressions found here as of 2024-05-22:
10532
+ * https://github.com/colinhacks/zod/blob/master/src/types.ts.
10533
+ *
10534
+ * Expressions with /i flag have been changed accordingly.
10535
+ */
10536
+ const zodPatterns = {
10537
+ /**
10538
+ * `c` was changed to `[cC]` to replicate /i flag
10539
+ */
10540
+ cuid: /^[cC][^\s-]{8,}$/,
10541
+ cuid2: /^[0-9a-z]+$/,
10542
+ ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,
10543
+ /**
10544
+ * `a-z` was added to replicate /i flag
10545
+ */
10546
+ email: /^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/,
10547
+ /**
10548
+ * Constructed a valid Unicode RegExp
10549
+ *
10550
+ * Lazily instantiate since this type of regex isn't supported
10551
+ * in all envs (e.g. React Native).
10552
+ *
10553
+ * See:
10554
+ * https://github.com/colinhacks/zod/issues/2433
10555
+ * Fix in Zod:
10556
+ * https://github.com/colinhacks/zod/commit/9340fd51e48576a75adc919bff65dbc4a5d4c99b
10557
+ */
10558
+ emoji: () => {
10559
+ if (emojiRegex === undefined) {
10560
+ emojiRegex = RegExp('^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$', 'u');
10561
+ }
10562
+ return emojiRegex;
10563
+ },
10564
+ base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,
10565
+ nanoid: /^[a-zA-Z0-9_-]{21}$/,
10566
+ };
10567
+ function parseStringDef(def, refs) {
10568
+ const res = {
10569
+ type: 'string',
10570
+ };
10571
+ function processPattern(value) {
10572
+ return refs.patternStrategy === 'escape' ? escapeNonAlphaNumeric(value) : value;
10573
+ }
10574
+ if (def.checks) {
10575
+ for (const check of def.checks) {
10576
+ switch (check.kind) {
10577
+ case 'min':
10578
+ setResponseValueAndErrors(res, 'minLength', typeof res.minLength === 'number' ? Math.max(res.minLength, check.value) : check.value, check.message, refs);
10579
+ break;
10580
+ case 'max':
10581
+ setResponseValueAndErrors(res, 'maxLength', typeof res.maxLength === 'number' ? Math.min(res.maxLength, check.value) : check.value, check.message, refs);
10582
+ break;
10583
+ case 'email':
10584
+ switch (refs.emailStrategy) {
10585
+ case 'format:email':
10586
+ addFormat(res, 'email', check.message, refs);
10587
+ break;
10588
+ case 'format:idn-email':
10589
+ addFormat(res, 'idn-email', check.message, refs);
10590
+ break;
10591
+ case 'pattern:zod':
10592
+ addPattern(res, zodPatterns.email, check.message, refs);
10593
+ break;
10594
+ }
10595
+ break;
10596
+ case 'url':
10597
+ addFormat(res, 'uri', check.message, refs);
10598
+ break;
10599
+ case 'uuid':
10600
+ addFormat(res, 'uuid', check.message, refs);
10601
+ break;
10602
+ case 'regex':
10603
+ addPattern(res, check.regex, check.message, refs);
10604
+ break;
10605
+ case 'cuid':
10606
+ addPattern(res, zodPatterns.cuid, check.message, refs);
10607
+ break;
10608
+ case 'cuid2':
10609
+ addPattern(res, zodPatterns.cuid2, check.message, refs);
10610
+ break;
10611
+ case 'startsWith':
10612
+ addPattern(res, RegExp(`^${processPattern(check.value)}`), check.message, refs);
10613
+ break;
10614
+ case 'endsWith':
10615
+ addPattern(res, RegExp(`${processPattern(check.value)}$`), check.message, refs);
10616
+ break;
10617
+ case 'datetime':
10618
+ addFormat(res, 'date-time', check.message, refs);
10619
+ break;
10620
+ case 'date':
10621
+ addFormat(res, 'date', check.message, refs);
10622
+ break;
10623
+ case 'time':
10624
+ addFormat(res, 'time', check.message, refs);
10625
+ break;
10626
+ case 'duration':
10627
+ addFormat(res, 'duration', check.message, refs);
10628
+ break;
10629
+ case 'length':
10630
+ setResponseValueAndErrors(res, 'minLength', typeof res.minLength === 'number' ? Math.max(res.minLength, check.value) : check.value, check.message, refs);
10631
+ setResponseValueAndErrors(res, 'maxLength', typeof res.maxLength === 'number' ? Math.min(res.maxLength, check.value) : check.value, check.message, refs);
10632
+ break;
10633
+ case 'includes': {
10634
+ addPattern(res, RegExp(processPattern(check.value)), check.message, refs);
10635
+ break;
10636
+ }
10637
+ case 'ip': {
10638
+ if (check.version !== 'v6') {
10639
+ addFormat(res, 'ipv4', check.message, refs);
10640
+ }
10641
+ if (check.version !== 'v4') {
10642
+ addFormat(res, 'ipv6', check.message, refs);
10643
+ }
10644
+ break;
10645
+ }
10646
+ case 'emoji':
10647
+ addPattern(res, zodPatterns.emoji, check.message, refs);
10648
+ break;
10649
+ case 'ulid': {
10650
+ addPattern(res, zodPatterns.ulid, check.message, refs);
10651
+ break;
10652
+ }
10653
+ case 'base64': {
10654
+ switch (refs.base64Strategy) {
10655
+ case 'format:binary': {
10656
+ addFormat(res, 'binary', check.message, refs);
10657
+ break;
10658
+ }
10659
+ case 'contentEncoding:base64': {
10660
+ setResponseValueAndErrors(res, 'contentEncoding', 'base64', check.message, refs);
10661
+ break;
10662
+ }
10663
+ case 'pattern:zod': {
10664
+ addPattern(res, zodPatterns.base64, check.message, refs);
10665
+ break;
10666
+ }
10667
+ }
10668
+ break;
10669
+ }
10670
+ case 'nanoid': {
10671
+ addPattern(res, zodPatterns.nanoid, check.message, refs);
10672
+ }
10673
+ }
10674
+ }
10675
+ }
10676
+ return res;
10677
+ }
10678
+ const escapeNonAlphaNumeric = (value) => Array.from(value)
10679
+ .map((c) => (/[a-zA-Z0-9]/.test(c) ? c : `\\${c}`))
10680
+ .join('');
10681
+ const addFormat = (schema, value, message, refs) => {
10682
+ if (schema.format || schema.anyOf?.some((x) => x.format)) {
10683
+ if (!schema.anyOf) {
10684
+ schema.anyOf = [];
10685
+ }
10686
+ if (schema.format) {
10687
+ schema.anyOf.push({
10688
+ format: schema.format,
10689
+ ...(schema.errorMessage &&
10690
+ refs.errorMessages && {
10691
+ errorMessage: { format: schema.errorMessage.format },
10692
+ }),
10693
+ });
10694
+ delete schema.format;
10695
+ if (schema.errorMessage) {
10696
+ delete schema.errorMessage.format;
10697
+ if (Object.keys(schema.errorMessage).length === 0) {
10698
+ delete schema.errorMessage;
10699
+ }
10700
+ }
10701
+ }
10702
+ schema.anyOf.push({
10703
+ format: value,
10704
+ ...(message && refs.errorMessages && { errorMessage: { format: message } }),
10705
+ });
10706
+ }
10707
+ else {
10708
+ setResponseValueAndErrors(schema, 'format', value, message, refs);
10709
+ }
10710
+ };
10711
+ const addPattern = (schema, regex, message, refs) => {
10712
+ if (schema.pattern || schema.allOf?.some((x) => x.pattern)) {
10713
+ if (!schema.allOf) {
10714
+ schema.allOf = [];
10715
+ }
10716
+ if (schema.pattern) {
10717
+ schema.allOf.push({
10718
+ pattern: schema.pattern,
10719
+ ...(schema.errorMessage &&
10720
+ refs.errorMessages && {
10721
+ errorMessage: { pattern: schema.errorMessage.pattern },
10722
+ }),
10723
+ });
10724
+ delete schema.pattern;
10725
+ if (schema.errorMessage) {
10726
+ delete schema.errorMessage.pattern;
10727
+ if (Object.keys(schema.errorMessage).length === 0) {
10728
+ delete schema.errorMessage;
10729
+ }
10730
+ }
10731
+ }
10732
+ schema.allOf.push({
10733
+ pattern: processRegExp(regex, refs),
10734
+ ...(message && refs.errorMessages && { errorMessage: { pattern: message } }),
10735
+ });
10736
+ }
10737
+ else {
10738
+ setResponseValueAndErrors(schema, 'pattern', processRegExp(regex, refs), message, refs);
10739
+ }
10740
+ };
10741
+ // Mutate z.string.regex() in a best attempt to accommodate for regex flags when applyRegexFlags is true
10742
+ const processRegExp = (regexOrFunction, refs) => {
10743
+ const regex = typeof regexOrFunction === 'function' ? regexOrFunction() : regexOrFunction;
10744
+ if (!refs.applyRegexFlags || !regex.flags)
10745
+ return regex.source;
10746
+ // Currently handled flags
10747
+ const flags = {
10748
+ i: regex.flags.includes('i'), // Case-insensitive
10749
+ m: regex.flags.includes('m'), // `^` and `$` matches adjacent to newline characters
10750
+ s: regex.flags.includes('s'), // `.` matches newlines
10751
+ };
10752
+ // 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!
10753
+ const source = flags.i ? regex.source.toLowerCase() : regex.source;
10754
+ let pattern = '';
10755
+ let isEscaped = false;
10756
+ let inCharGroup = false;
10757
+ let inCharRange = false;
10758
+ for (let i = 0; i < source.length; i++) {
10759
+ if (isEscaped) {
10760
+ pattern += source[i];
10761
+ isEscaped = false;
10762
+ continue;
10763
+ }
10764
+ if (flags.i) {
10765
+ if (inCharGroup) {
10766
+ if (source[i].match(/[a-z]/)) {
10767
+ if (inCharRange) {
10768
+ pattern += source[i];
10769
+ pattern += `${source[i - 2]}-${source[i]}`.toUpperCase();
10770
+ inCharRange = false;
10771
+ }
10772
+ else if (source[i + 1] === '-' && source[i + 2]?.match(/[a-z]/)) {
10773
+ pattern += source[i];
10774
+ inCharRange = true;
10775
+ }
10776
+ else {
10777
+ pattern += `${source[i]}${source[i].toUpperCase()}`;
10778
+ }
10779
+ continue;
10780
+ }
10781
+ }
10782
+ else if (source[i].match(/[a-z]/)) {
10783
+ pattern += `[${source[i]}${source[i].toUpperCase()}]`;
10784
+ continue;
10785
+ }
10786
+ }
10787
+ if (flags.m) {
10788
+ if (source[i] === '^') {
10789
+ pattern += `(^|(?<=[\r\n]))`;
10790
+ continue;
10791
+ }
10792
+ else if (source[i] === '$') {
10793
+ pattern += `($|(?=[\r\n]))`;
10794
+ continue;
10795
+ }
10796
+ }
10797
+ if (flags.s && source[i] === '.') {
10798
+ pattern += inCharGroup ? `${source[i]}\r\n` : `[${source[i]}\r\n]`;
10799
+ continue;
10800
+ }
10801
+ pattern += source[i];
10802
+ if (source[i] === '\\') {
10803
+ isEscaped = true;
10804
+ }
10805
+ else if (inCharGroup && source[i] === ']') {
10806
+ inCharGroup = false;
10807
+ }
10808
+ else if (!inCharGroup && source[i] === '[') {
10809
+ inCharGroup = true;
10810
+ }
10811
+ }
10812
+ try {
10813
+ const regexTest = new RegExp(pattern);
10814
+ }
10815
+ catch {
10816
+ console.warn(`Could not convert regex pattern at ${refs.currentPath.join('/')} to a flag-independent form! Falling back to the flag-ignorant source`);
10817
+ return regex.source;
10818
+ }
10819
+ return pattern;
10820
+ };
10821
+
10822
+ function parseRecordDef(def, refs) {
10823
+ if (refs.target === 'openApi3' && def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) {
10824
+ return {
10825
+ type: 'object',
10826
+ required: def.keyType._def.values,
10827
+ properties: def.keyType._def.values.reduce((acc, key) => ({
10828
+ ...acc,
10829
+ [key]: parseDef(def.valueType._def, {
10830
+ ...refs,
10831
+ currentPath: [...refs.currentPath, 'properties', key],
10832
+ }) ?? {},
10833
+ }), {}),
10834
+ additionalProperties: false,
10835
+ };
10836
+ }
10837
+ const schema = {
10838
+ type: 'object',
10839
+ additionalProperties: parseDef(def.valueType._def, {
10840
+ ...refs,
10841
+ currentPath: [...refs.currentPath, 'additionalProperties'],
10842
+ }) ?? {},
10843
+ };
10844
+ if (refs.target === 'openApi3') {
10845
+ return schema;
10846
+ }
10847
+ if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodString && def.keyType._def.checks?.length) {
10848
+ const keyType = Object.entries(parseStringDef(def.keyType._def, refs)).reduce((acc, [key, value]) => (key === 'type' ? acc : { ...acc, [key]: value }), {});
10849
+ return {
10850
+ ...schema,
10851
+ propertyNames: keyType,
10852
+ };
10853
+ }
10854
+ else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) {
10855
+ return {
10856
+ ...schema,
10857
+ propertyNames: {
10858
+ enum: def.keyType._def.values,
10859
+ },
10860
+ };
10861
+ }
10862
+ return schema;
10863
+ }
10864
+
10865
+ function parseMapDef(def, refs) {
10866
+ if (refs.mapStrategy === 'record') {
10867
+ return parseRecordDef(def, refs);
10868
+ }
10869
+ const keys = parseDef(def.keyType._def, {
10870
+ ...refs,
10871
+ currentPath: [...refs.currentPath, 'items', 'items', '0'],
10872
+ }) || {};
10873
+ const values = parseDef(def.valueType._def, {
10874
+ ...refs,
10875
+ currentPath: [...refs.currentPath, 'items', 'items', '1'],
10876
+ }) || {};
10877
+ return {
10878
+ type: 'array',
10879
+ maxItems: 125,
10880
+ items: {
10881
+ type: 'array',
10882
+ items: [keys, values],
10883
+ minItems: 2,
10884
+ maxItems: 2,
10885
+ },
10886
+ };
10887
+ }
10888
+
10889
+ function parseNativeEnumDef(def) {
10890
+ const object = def.values;
10891
+ const actualKeys = Object.keys(def.values).filter((key) => {
10892
+ return typeof object[object[key]] !== 'number';
10893
+ });
10894
+ const actualValues = actualKeys.map((key) => object[key]);
10895
+ const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values)));
10896
+ return {
10897
+ type: parsedTypes.length === 1 ?
10898
+ parsedTypes[0] === 'string' ?
10899
+ 'string'
10900
+ : 'number'
10901
+ : ['string', 'number'],
10902
+ enum: actualValues,
10903
+ };
10904
+ }
10905
+
10906
+ function parseNeverDef() {
10907
+ return {
10908
+ not: {},
10909
+ };
10910
+ }
10911
+
10912
+ function parseNullDef(refs) {
10913
+ return refs.target === 'openApi3' ?
10914
+ {
10915
+ enum: ['null'],
10916
+ nullable: true,
10917
+ }
10918
+ : {
10919
+ type: 'null',
10920
+ };
10921
+ }
10922
+
10923
+ const primitiveMappings = {
10924
+ ZodString: 'string',
10925
+ ZodNumber: 'number',
10926
+ ZodBigInt: 'integer',
10927
+ ZodBoolean: 'boolean',
10928
+ ZodNull: 'null',
10929
+ };
10930
+ function parseUnionDef(def, refs) {
10931
+ if (refs.target === 'openApi3')
10932
+ return asAnyOf(def, refs);
10933
+ const options = def.options instanceof Map ? Array.from(def.options.values()) : def.options;
10934
+ // This blocks tries to look ahead a bit to produce nicer looking schemas with type array instead of anyOf.
10935
+ if (options.every((x) => x._def.typeName in primitiveMappings && (!x._def.checks || !x._def.checks.length))) {
10936
+ // all types in union are primitive and lack checks, so might as well squash into {type: [...]}
10937
+ const types = options.reduce((types, x) => {
10938
+ const type = primitiveMappings[x._def.typeName]; //Can be safely casted due to row 43
10939
+ return type && !types.includes(type) ? [...types, type] : types;
10940
+ }, []);
10941
+ return {
10942
+ type: types.length > 1 ? types : types[0],
10943
+ };
10944
+ }
10945
+ else if (options.every((x) => x._def.typeName === 'ZodLiteral' && !x.description)) {
10946
+ // all options literals
10947
+ const types = options.reduce((acc, x) => {
10948
+ const type = typeof x._def.value;
10949
+ switch (type) {
10950
+ case 'string':
10951
+ case 'number':
10952
+ case 'boolean':
10953
+ return [...acc, type];
10954
+ case 'bigint':
10955
+ return [...acc, 'integer'];
10956
+ case 'object':
10957
+ if (x._def.value === null)
10958
+ return [...acc, 'null'];
10959
+ case 'symbol':
10960
+ case 'undefined':
10961
+ case 'function':
10962
+ default:
10963
+ return acc;
10964
+ }
10965
+ }, []);
10966
+ if (types.length === options.length) {
10967
+ // all the literals are primitive, as far as null can be considered primitive
10968
+ const uniqueTypes = types.filter((x, i, a) => a.indexOf(x) === i);
10969
+ return {
10970
+ type: uniqueTypes.length > 1 ? uniqueTypes : uniqueTypes[0],
10971
+ enum: options.reduce((acc, x) => {
10972
+ return acc.includes(x._def.value) ? acc : [...acc, x._def.value];
10973
+ }, []),
10974
+ };
10975
+ }
10976
+ }
10977
+ else if (options.every((x) => x._def.typeName === 'ZodEnum')) {
10978
+ return {
10979
+ type: 'string',
10980
+ enum: options.reduce((acc, x) => [...acc, ...x._def.values.filter((x) => !acc.includes(x))], []),
10981
+ };
10982
+ }
10983
+ return asAnyOf(def, refs);
10984
+ }
10985
+ const asAnyOf = (def, refs) => {
10986
+ const anyOf = (def.options instanceof Map ? Array.from(def.options.values()) : def.options)
10987
+ .map((x, i) => parseDef(x._def, {
10988
+ ...refs,
10989
+ currentPath: [...refs.currentPath, 'anyOf', `${i}`],
10990
+ }))
10991
+ .filter((x) => !!x && (!refs.strictUnions || (typeof x === 'object' && Object.keys(x).length > 0)));
10992
+ return anyOf.length ? { anyOf } : undefined;
10993
+ };
10994
+
10995
+ function parseNullableDef(def, refs) {
10996
+ if (['ZodString', 'ZodNumber', 'ZodBigInt', 'ZodBoolean', 'ZodNull'].includes(def.innerType._def.typeName) &&
10997
+ (!def.innerType._def.checks || !def.innerType._def.checks.length)) {
10998
+ if (refs.target === 'openApi3' || refs.nullableStrategy === 'property') {
10999
+ return {
11000
+ type: primitiveMappings[def.innerType._def.typeName],
11001
+ nullable: true,
11002
+ };
11003
+ }
11004
+ return {
11005
+ type: [primitiveMappings[def.innerType._def.typeName], 'null'],
11006
+ };
11007
+ }
11008
+ if (refs.target === 'openApi3') {
11009
+ const base = parseDef(def.innerType._def, {
11010
+ ...refs,
11011
+ currentPath: [...refs.currentPath],
11012
+ });
11013
+ if (base && '$ref' in base)
11014
+ return { allOf: [base], nullable: true };
11015
+ return base && { ...base, nullable: true };
11016
+ }
11017
+ const base = parseDef(def.innerType._def, {
11018
+ ...refs,
11019
+ currentPath: [...refs.currentPath, 'anyOf', '0'],
11020
+ });
11021
+ return base && { anyOf: [base, { type: 'null' }] };
11022
+ }
11023
+
11024
+ function parseNumberDef(def, refs) {
11025
+ const res = {
11026
+ type: 'number',
11027
+ };
11028
+ if (!def.checks)
11029
+ return res;
11030
+ for (const check of def.checks) {
11031
+ switch (check.kind) {
11032
+ case 'int':
11033
+ res.type = 'integer';
11034
+ addErrorMessage(res, 'type', check.message, refs);
11035
+ break;
11036
+ case 'min':
11037
+ if (refs.target === 'jsonSchema7') {
11038
+ if (check.inclusive) {
11039
+ setResponseValueAndErrors(res, 'minimum', check.value, check.message, refs);
11040
+ }
11041
+ else {
11042
+ setResponseValueAndErrors(res, 'exclusiveMinimum', check.value, check.message, refs);
11043
+ }
11044
+ }
11045
+ else {
11046
+ if (!check.inclusive) {
11047
+ res.exclusiveMinimum = true;
11048
+ }
11049
+ setResponseValueAndErrors(res, 'minimum', check.value, check.message, refs);
11050
+ }
11051
+ break;
11052
+ case 'max':
11053
+ if (refs.target === 'jsonSchema7') {
11054
+ if (check.inclusive) {
11055
+ setResponseValueAndErrors(res, 'maximum', check.value, check.message, refs);
11056
+ }
11057
+ else {
11058
+ setResponseValueAndErrors(res, 'exclusiveMaximum', check.value, check.message, refs);
11059
+ }
11060
+ }
11061
+ else {
11062
+ if (!check.inclusive) {
11063
+ res.exclusiveMaximum = true;
11064
+ }
11065
+ setResponseValueAndErrors(res, 'maximum', check.value, check.message, refs);
11066
+ }
11067
+ break;
11068
+ case 'multipleOf':
11069
+ setResponseValueAndErrors(res, 'multipleOf', check.value, check.message, refs);
11070
+ break;
11071
+ }
11072
+ }
11073
+ return res;
11074
+ }
11075
+
11076
+ function decideAdditionalProperties(def, refs) {
11077
+ if (refs.removeAdditionalStrategy === 'strict') {
11078
+ return def.catchall._def.typeName === 'ZodNever' ?
11079
+ def.unknownKeys !== 'strict'
11080
+ : parseDef(def.catchall._def, {
11081
+ ...refs,
11082
+ currentPath: [...refs.currentPath, 'additionalProperties'],
11083
+ }) ?? true;
11084
+ }
11085
+ else {
11086
+ return def.catchall._def.typeName === 'ZodNever' ?
11087
+ def.unknownKeys === 'passthrough'
11088
+ : parseDef(def.catchall._def, {
11089
+ ...refs,
11090
+ currentPath: [...refs.currentPath, 'additionalProperties'],
11091
+ }) ?? true;
11092
+ }
11093
+ }
11094
+ function parseObjectDef(def, refs) {
11095
+ const result = {
11096
+ type: 'object',
11097
+ ...Object.entries(def.shape()).reduce((acc, [propName, propDef]) => {
11098
+ if (propDef === undefined || propDef._def === undefined)
11099
+ return acc;
11100
+ const propertyPath = [...refs.currentPath, 'properties', propName];
11101
+ const parsedDef = parseDef(propDef._def, {
11102
+ ...refs,
11103
+ currentPath: propertyPath,
11104
+ propertyPath,
11105
+ });
11106
+ if (parsedDef === undefined)
11107
+ return acc;
11108
+ if (refs.openaiStrictMode &&
11109
+ propDef.isOptional() &&
11110
+ !propDef.isNullable() &&
11111
+ typeof propDef._def?.defaultValue === 'undefined') {
11112
+ 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`);
11113
+ }
11114
+ return {
11115
+ properties: {
11116
+ ...acc.properties,
11117
+ [propName]: parsedDef,
11118
+ },
11119
+ required: propDef.isOptional() && !refs.openaiStrictMode ? acc.required : [...acc.required, propName],
11120
+ };
11121
+ }, { properties: {}, required: [] }),
11122
+ additionalProperties: decideAdditionalProperties(def, refs),
11123
+ };
11124
+ if (!result.required.length)
11125
+ delete result.required;
11126
+ return result;
11127
+ }
11128
+
11129
+ const parseOptionalDef = (def, refs) => {
11130
+ if (refs.propertyPath &&
11131
+ refs.currentPath.slice(0, refs.propertyPath.length).toString() === refs.propertyPath.toString()) {
11132
+ return parseDef(def.innerType._def, { ...refs, currentPath: refs.currentPath });
11133
+ }
11134
+ const innerSchema = parseDef(def.innerType._def, {
11135
+ ...refs,
11136
+ currentPath: [...refs.currentPath, 'anyOf', '1'],
11137
+ });
11138
+ return innerSchema ?
11139
+ {
11140
+ anyOf: [
11141
+ {
11142
+ not: {},
11143
+ },
11144
+ innerSchema,
11145
+ ],
11146
+ }
11147
+ : {};
11148
+ };
11149
+
11150
+ const parsePipelineDef = (def, refs) => {
11151
+ if (refs.pipeStrategy === 'input') {
11152
+ return parseDef(def.in._def, refs);
11153
+ }
11154
+ else if (refs.pipeStrategy === 'output') {
11155
+ return parseDef(def.out._def, refs);
11156
+ }
11157
+ const a = parseDef(def.in._def, {
11158
+ ...refs,
11159
+ currentPath: [...refs.currentPath, 'allOf', '0'],
11160
+ });
11161
+ const b = parseDef(def.out._def, {
11162
+ ...refs,
11163
+ currentPath: [...refs.currentPath, 'allOf', a ? '1' : '0'],
11164
+ });
11165
+ return {
11166
+ allOf: [a, b].filter((x) => x !== undefined),
11167
+ };
11168
+ };
11169
+
11170
+ function parsePromiseDef(def, refs) {
11171
+ return parseDef(def.type._def, refs);
11172
+ }
11173
+
11174
+ function parseSetDef(def, refs) {
11175
+ const items = parseDef(def.valueType._def, {
11176
+ ...refs,
11177
+ currentPath: [...refs.currentPath, 'items'],
11178
+ });
11179
+ const schema = {
11180
+ type: 'array',
11181
+ uniqueItems: true,
11182
+ items,
11183
+ };
11184
+ if (def.minSize) {
11185
+ setResponseValueAndErrors(schema, 'minItems', def.minSize.value, def.minSize.message, refs);
11186
+ }
11187
+ if (def.maxSize) {
11188
+ setResponseValueAndErrors(schema, 'maxItems', def.maxSize.value, def.maxSize.message, refs);
11189
+ }
11190
+ return schema;
11191
+ }
11192
+
11193
+ function parseTupleDef(def, refs) {
11194
+ if (def.rest) {
11195
+ return {
11196
+ type: 'array',
11197
+ minItems: def.items.length,
11198
+ items: def.items
11199
+ .map((x, i) => parseDef(x._def, {
11200
+ ...refs,
11201
+ currentPath: [...refs.currentPath, 'items', `${i}`],
11202
+ }))
11203
+ .reduce((acc, x) => (x === undefined ? acc : [...acc, x]), []),
11204
+ additionalItems: parseDef(def.rest._def, {
11205
+ ...refs,
11206
+ currentPath: [...refs.currentPath, 'additionalItems'],
11207
+ }),
11208
+ };
11209
+ }
11210
+ else {
11211
+ return {
11212
+ type: 'array',
11213
+ minItems: def.items.length,
11214
+ maxItems: def.items.length,
11215
+ items: def.items
11216
+ .map((x, i) => parseDef(x._def, {
11217
+ ...refs,
11218
+ currentPath: [...refs.currentPath, 'items', `${i}`],
11219
+ }))
11220
+ .reduce((acc, x) => (x === undefined ? acc : [...acc, x]), []),
11221
+ };
11222
+ }
11223
+ }
11224
+
11225
+ function parseUndefinedDef() {
11226
+ return {
11227
+ not: {},
11228
+ };
11229
+ }
11230
+
11231
+ function parseUnknownDef() {
11232
+ return {};
11233
+ }
11234
+
11235
+ const parseReadonlyDef = (def, refs) => {
11236
+ return parseDef(def.innerType._def, refs);
11237
+ };
11238
+
11239
+ function parseDef(def, refs, forceResolution = false) {
11240
+ const seenItem = refs.seen.get(def);
11241
+ if (refs.override) {
11242
+ const overrideResult = refs.override?.(def, refs, seenItem, forceResolution);
11243
+ if (overrideResult !== ignoreOverride) {
11244
+ return overrideResult;
11245
+ }
11246
+ }
11247
+ if (seenItem && !forceResolution) {
11248
+ const seenSchema = get$ref(seenItem, refs);
11249
+ if (seenSchema !== undefined) {
11250
+ if ('$ref' in seenSchema) {
11251
+ refs.seenRefs.add(seenSchema.$ref);
11252
+ }
11253
+ return seenSchema;
11254
+ }
11255
+ }
11256
+ const newItem = { def, path: refs.currentPath, jsonSchema: undefined };
11257
+ refs.seen.set(def, newItem);
11258
+ const jsonSchema = selectParser(def, def.typeName, refs, forceResolution);
11259
+ if (jsonSchema) {
11260
+ addMeta(def, refs, jsonSchema);
11261
+ }
11262
+ newItem.jsonSchema = jsonSchema;
11263
+ return jsonSchema;
11264
+ }
11265
+ const get$ref = (item, refs) => {
11266
+ switch (refs.$refStrategy) {
11267
+ case 'root':
11268
+ return { $ref: item.path.join('/') };
11269
+ // this case is needed as OpenAI strict mode doesn't support top-level `$ref`s, i.e.
11270
+ // the top-level schema *must* be `{"type": "object", "properties": {...}}` but if we ever
11271
+ // need to define a `$ref`, relative `$ref`s aren't supported, so we need to extract
11272
+ // the schema to `#/definitions/` and reference that.
11273
+ //
11274
+ // e.g. if we need to reference a schema at
11275
+ // `["#","definitions","contactPerson","properties","person1","properties","name"]`
11276
+ // then we'll extract it out to `contactPerson_properties_person1_properties_name`
11277
+ case 'extract-to-root':
11278
+ const name = item.path.slice(refs.basePath.length + 1).join('_');
11279
+ // we don't need to extract the root schema in this case, as it's already
11280
+ // been added to the definitions
11281
+ if (name !== refs.name && refs.nameStrategy === 'duplicate-ref') {
11282
+ refs.definitions[name] = item.def;
11283
+ }
11284
+ return { $ref: [...refs.basePath, refs.definitionPath, name].join('/') };
11285
+ case 'relative':
11286
+ return { $ref: getRelativePath(refs.currentPath, item.path) };
11287
+ case 'none':
11288
+ case 'seen': {
11289
+ if (item.path.length < refs.currentPath.length &&
11290
+ item.path.every((value, index) => refs.currentPath[index] === value)) {
11291
+ console.warn(`Recursive reference detected at ${refs.currentPath.join('/')}! Defaulting to any`);
11292
+ return {};
11293
+ }
11294
+ return refs.$refStrategy === 'seen' ? {} : undefined;
11295
+ }
11296
+ }
11297
+ };
11298
+ const getRelativePath = (pathA, pathB) => {
11299
+ let i = 0;
11300
+ for (; i < pathA.length && i < pathB.length; i++) {
11301
+ if (pathA[i] !== pathB[i])
11302
+ break;
11303
+ }
11304
+ return [(pathA.length - i).toString(), ...pathB.slice(i)].join('/');
11305
+ };
11306
+ const selectParser = (def, typeName, refs, forceResolution) => {
11307
+ switch (typeName) {
11308
+ case ZodFirstPartyTypeKind.ZodString:
11309
+ return parseStringDef(def, refs);
11310
+ case ZodFirstPartyTypeKind.ZodNumber:
11311
+ return parseNumberDef(def, refs);
11312
+ case ZodFirstPartyTypeKind.ZodObject:
11313
+ return parseObjectDef(def, refs);
11314
+ case ZodFirstPartyTypeKind.ZodBigInt:
11315
+ return parseBigintDef(def, refs);
11316
+ case ZodFirstPartyTypeKind.ZodBoolean:
11317
+ return parseBooleanDef();
11318
+ case ZodFirstPartyTypeKind.ZodDate:
11319
+ return parseDateDef(def, refs);
11320
+ case ZodFirstPartyTypeKind.ZodUndefined:
11321
+ return parseUndefinedDef();
11322
+ case ZodFirstPartyTypeKind.ZodNull:
11323
+ return parseNullDef(refs);
11324
+ case ZodFirstPartyTypeKind.ZodArray:
11325
+ return parseArrayDef(def, refs);
11326
+ case ZodFirstPartyTypeKind.ZodUnion:
11327
+ case ZodFirstPartyTypeKind.ZodDiscriminatedUnion:
11328
+ return parseUnionDef(def, refs);
11329
+ case ZodFirstPartyTypeKind.ZodIntersection:
11330
+ return parseIntersectionDef(def, refs);
11331
+ case ZodFirstPartyTypeKind.ZodTuple:
11332
+ return parseTupleDef(def, refs);
11333
+ case ZodFirstPartyTypeKind.ZodRecord:
11334
+ return parseRecordDef(def, refs);
11335
+ case ZodFirstPartyTypeKind.ZodLiteral:
11336
+ return parseLiteralDef(def, refs);
11337
+ case ZodFirstPartyTypeKind.ZodEnum:
11338
+ return parseEnumDef(def);
11339
+ case ZodFirstPartyTypeKind.ZodNativeEnum:
11340
+ return parseNativeEnumDef(def);
11341
+ case ZodFirstPartyTypeKind.ZodNullable:
11342
+ return parseNullableDef(def, refs);
11343
+ case ZodFirstPartyTypeKind.ZodOptional:
11344
+ return parseOptionalDef(def, refs);
11345
+ case ZodFirstPartyTypeKind.ZodMap:
11346
+ return parseMapDef(def, refs);
11347
+ case ZodFirstPartyTypeKind.ZodSet:
11348
+ return parseSetDef(def, refs);
11349
+ case ZodFirstPartyTypeKind.ZodLazy:
11350
+ return parseDef(def.getter()._def, refs);
11351
+ case ZodFirstPartyTypeKind.ZodPromise:
11352
+ return parsePromiseDef(def, refs);
11353
+ case ZodFirstPartyTypeKind.ZodNaN:
11354
+ case ZodFirstPartyTypeKind.ZodNever:
11355
+ return parseNeverDef();
11356
+ case ZodFirstPartyTypeKind.ZodEffects:
11357
+ return parseEffectsDef(def, refs, forceResolution);
11358
+ case ZodFirstPartyTypeKind.ZodAny:
11359
+ return parseAnyDef();
11360
+ case ZodFirstPartyTypeKind.ZodUnknown:
11361
+ return parseUnknownDef();
11362
+ case ZodFirstPartyTypeKind.ZodDefault:
11363
+ return parseDefaultDef(def, refs);
11364
+ case ZodFirstPartyTypeKind.ZodBranded:
11365
+ return parseBrandedDef(def, refs);
11366
+ case ZodFirstPartyTypeKind.ZodReadonly:
11367
+ return parseReadonlyDef(def, refs);
11368
+ case ZodFirstPartyTypeKind.ZodCatch:
11369
+ return parseCatchDef(def, refs);
11370
+ case ZodFirstPartyTypeKind.ZodPipeline:
11371
+ return parsePipelineDef(def, refs);
11372
+ case ZodFirstPartyTypeKind.ZodFunction:
11373
+ case ZodFirstPartyTypeKind.ZodVoid:
11374
+ case ZodFirstPartyTypeKind.ZodSymbol:
11375
+ return undefined;
11376
+ default:
11377
+ return ((_) => undefined)();
11378
+ }
11379
+ };
11380
+ const addMeta = (def, refs, jsonSchema) => {
11381
+ if (def.description) {
11382
+ jsonSchema.description = def.description;
11383
+ if (refs.markdownDescription) {
11384
+ jsonSchema.markdownDescription = def.description;
11385
+ }
11386
+ }
11387
+ return jsonSchema;
11388
+ };
11389
+
11390
+ const zodToJsonSchema = (schema, options) => {
11391
+ const refs = getRefs(options);
11392
+ const name = typeof options === 'string' ? options
11393
+ : options?.nameStrategy === 'title' ? undefined
11394
+ : options?.name;
11395
+ const main = parseDef(schema._def, name === undefined ? refs : ({
11396
+ ...refs,
11397
+ currentPath: [...refs.basePath, refs.definitionPath, name],
11398
+ }), false) ?? {};
11399
+ const title = typeof options === 'object' && options.name !== undefined && options.nameStrategy === 'title' ?
11400
+ options.name
11401
+ : undefined;
11402
+ if (title !== undefined) {
11403
+ main.title = title;
11404
+ }
11405
+ const definitions = (() => {
11406
+ if (isEmptyObj(refs.definitions)) {
11407
+ return undefined;
11408
+ }
11409
+ const definitions = {};
11410
+ const processedDefinitions = new Set();
11411
+ // the call to `parseDef()` here might itself add more entries to `.definitions`
11412
+ // so we need to continually evaluate definitions until we've resolved all of them
11413
+ //
11414
+ // we have a generous iteration limit here to avoid blowing up the stack if there
11415
+ // are any bugs that would otherwise result in us iterating indefinitely
11416
+ for (let i = 0; i < 500; i++) {
11417
+ const newDefinitions = Object.entries(refs.definitions).filter(([key]) => !processedDefinitions.has(key));
11418
+ if (newDefinitions.length === 0)
11419
+ break;
11420
+ for (const [key, schema] of newDefinitions) {
11421
+ definitions[key] =
11422
+ parseDef(zodDef(schema), { ...refs, currentPath: [...refs.basePath, refs.definitionPath, key] }, true) ?? {};
11423
+ processedDefinitions.add(key);
11424
+ }
11425
+ }
11426
+ return definitions;
11427
+ })();
11428
+ const combined = name === undefined ?
11429
+ definitions ?
11430
+ {
11431
+ ...main,
11432
+ [refs.definitionPath]: definitions,
11433
+ }
11434
+ : main
11435
+ : refs.nameStrategy === 'duplicate-ref' ?
11436
+ {
11437
+ ...main,
11438
+ ...(definitions || refs.seenRefs.size ?
11439
+ {
11440
+ [refs.definitionPath]: {
11441
+ ...definitions,
11442
+ // only actually duplicate the schema definition if it was ever referenced
11443
+ // otherwise the duplication is completely pointless
11444
+ ...(refs.seenRefs.size ? { [name]: main } : undefined),
11445
+ },
11446
+ }
11447
+ : undefined),
11448
+ }
11449
+ : {
11450
+ $ref: [...(refs.$refStrategy === 'relative' ? [] : refs.basePath), refs.definitionPath, name].join('/'),
11451
+ [refs.definitionPath]: {
11452
+ ...definitions,
11453
+ [name]: main,
11454
+ },
11455
+ };
11456
+ if (refs.target === 'jsonSchema7') {
11457
+ combined.$schema = 'http://json-schema.org/draft-07/schema#';
11458
+ }
11459
+ else if (refs.target === 'jsonSchema2019-09') {
11460
+ combined.$schema = 'https://json-schema.org/draft/2019-09/schema#';
11461
+ }
11462
+ return combined;
11463
+ };
11464
+
11465
+ function toStrictJsonSchema(schema) {
11466
+ if (schema.type !== 'object') {
11467
+ throw new Error(`Root schema must have type: 'object' but got type: ${schema.type ? `'${schema.type}'` : 'undefined'}`);
11468
+ }
11469
+ const schemaCopy = structuredClone(schema);
11470
+ return ensureStrictJsonSchema(schemaCopy, [], schemaCopy);
11471
+ }
11472
+ function isNullable(schema) {
11473
+ if (typeof schema === 'boolean') {
11474
+ return false;
11475
+ }
11476
+ if (schema.type === 'null') {
11477
+ return true;
11478
+ }
11479
+ for (const oneOfVariant of schema.oneOf ?? []) {
11480
+ if (isNullable(oneOfVariant)) {
11481
+ return true;
11482
+ }
11483
+ }
11484
+ for (const allOfVariant of schema.anyOf ?? []) {
11485
+ if (isNullable(allOfVariant)) {
11486
+ return true;
11487
+ }
11488
+ }
11489
+ return false;
11490
+ }
11491
+ /**
11492
+ * Mutates the given JSON schema to ensure it conforms to the `strict` standard
11493
+ * that the API expects.
11494
+ */
11495
+ function ensureStrictJsonSchema(jsonSchema, path, root) {
11496
+ if (typeof jsonSchema === 'boolean') {
11497
+ throw new TypeError(`Expected object schema but got boolean; path=${path.join('/')}`);
11498
+ }
11499
+ if (!isObject(jsonSchema)) {
11500
+ throw new TypeError(`Expected ${JSON.stringify(jsonSchema)} to be an object; path=${path.join('/')}`);
11501
+ }
11502
+ // Handle $defs (non-standard but sometimes used)
11503
+ const defs = jsonSchema.$defs;
11504
+ if (isObject(defs)) {
11505
+ for (const [defName, defSchema] of Object.entries(defs)) {
11506
+ ensureStrictJsonSchema(defSchema, [...path, '$defs', defName], root);
11507
+ }
11508
+ }
11509
+ // Handle definitions (draft-04 style, deprecated in draft-07 but still used)
11510
+ const definitions = jsonSchema.definitions;
11511
+ if (isObject(definitions)) {
11512
+ for (const [definitionName, definitionSchema] of Object.entries(definitions)) {
11513
+ ensureStrictJsonSchema(definitionSchema, [...path, 'definitions', definitionName], root);
11514
+ }
11515
+ }
11516
+ // Add additionalProperties: false to object types
11517
+ const typ = jsonSchema.type;
11518
+ if (typ === 'object' && !('additionalProperties' in jsonSchema)) {
11519
+ jsonSchema.additionalProperties = false;
11520
+ }
11521
+ const required = jsonSchema.required ?? [];
11522
+ // Handle object properties
11523
+ const properties = jsonSchema.properties;
11524
+ if (isObject(properties)) {
11525
+ for (const [key, value] of Object.entries(properties)) {
11526
+ if (!isNullable(value) && !required.includes(key)) {
11527
+ 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`);
11528
+ }
11529
+ }
11530
+ jsonSchema.required = Object.keys(properties);
11531
+ jsonSchema.properties = Object.fromEntries(Object.entries(properties).map(([key, propSchema]) => [
11532
+ key,
11533
+ ensureStrictJsonSchema(propSchema, [...path, 'properties', key], root),
11534
+ ]));
11535
+ }
11536
+ // Handle arrays
11537
+ const items = jsonSchema.items;
11538
+ if (isObject(items)) {
11539
+ jsonSchema.items = ensureStrictJsonSchema(items, [...path, 'items'], root);
11540
+ }
11541
+ // Handle unions (anyOf)
11542
+ const anyOf = jsonSchema.anyOf;
11543
+ if (Array.isArray(anyOf)) {
11544
+ jsonSchema.anyOf = anyOf.map((variant, i) => ensureStrictJsonSchema(variant, [...path, 'anyOf', String(i)], root));
11545
+ }
11546
+ // Handle intersections (allOf)
11547
+ const allOf = jsonSchema.allOf;
11548
+ if (Array.isArray(allOf)) {
11549
+ if (allOf.length === 1) {
11550
+ const resolved = ensureStrictJsonSchema(allOf[0], [...path, 'allOf', '0'], root);
11551
+ Object.assign(jsonSchema, resolved);
11552
+ delete jsonSchema.allOf;
11553
+ }
11554
+ else {
11555
+ jsonSchema.allOf = allOf.map((entry, i) => ensureStrictJsonSchema(entry, [...path, 'allOf', String(i)], root));
11556
+ }
11557
+ }
11558
+ // Strip `null` defaults as there's no meaningful distinction
11559
+ if (jsonSchema.default === null) {
11560
+ delete jsonSchema.default;
11561
+ }
11562
+ // Handle $ref with additional properties
11563
+ const ref = jsonSchema.$ref;
11564
+ if (ref && hasMoreThanNKeys(jsonSchema, 1)) {
11565
+ if (typeof ref !== 'string') {
11566
+ throw new TypeError(`Received non-string $ref - ${ref}; path=${path.join('/')}`);
11567
+ }
11568
+ const resolved = resolveRef(root, ref);
11569
+ if (typeof resolved === 'boolean') {
11570
+ throw new Error(`Expected \`$ref: ${ref}\` to resolve to an object schema but got boolean`);
11571
+ }
11572
+ if (!isObject(resolved)) {
11573
+ throw new Error(`Expected \`$ref: ${ref}\` to resolve to an object but got ${JSON.stringify(resolved)}`);
11574
+ }
11575
+ // Properties from the json schema take priority over the ones on the `$ref`
11576
+ Object.assign(jsonSchema, { ...resolved, ...jsonSchema });
11577
+ delete jsonSchema.$ref;
11578
+ // Since the schema expanded from `$ref` might not have `additionalProperties: false` applied,
11579
+ // we call `ensureStrictJsonSchema` again to fix the inlined schema and ensure it's valid.
11580
+ return ensureStrictJsonSchema(jsonSchema, path, root);
11581
+ }
11582
+ return jsonSchema;
11583
+ }
11584
+ function resolveRef(root, ref) {
11585
+ if (!ref.startsWith('#/')) {
11586
+ throw new Error(`Unexpected $ref format ${JSON.stringify(ref)}; Does not start with #/`);
11587
+ }
11588
+ const pathParts = ref.slice(2).split('/');
11589
+ let resolved = root;
11590
+ for (const key of pathParts) {
11591
+ if (!isObject(resolved)) {
11592
+ throw new Error(`encountered non-object entry while resolving ${ref} - ${JSON.stringify(resolved)}`);
11593
+ }
11594
+ const value = resolved[key];
11595
+ if (value === undefined) {
11596
+ throw new Error(`Key ${key} not found while resolving ${ref}`);
11597
+ }
11598
+ resolved = value;
11599
+ }
11600
+ return resolved;
11601
+ }
11602
+ function isObject(obj) {
11603
+ return typeof obj === 'object' && obj !== null && !Array.isArray(obj);
11604
+ }
11605
+ function hasMoreThanNKeys(obj, n) {
11606
+ let i = 0;
11607
+ for (const _ in obj) {
11608
+ i++;
11609
+ if (i > n) {
11610
+ return true;
11611
+ }
11612
+ }
11613
+ return false;
11614
+ }
11615
+
11616
+ function zodV3ToJsonSchema(schema, options) {
11617
+ return zodToJsonSchema(schema, {
11618
+ openaiStrictMode: true,
11619
+ name: options.name,
11620
+ nameStrategy: 'duplicate-ref',
11621
+ $refStrategy: 'extract-to-root',
11622
+ nullableStrategy: 'property',
11623
+ });
11624
+ }
11625
+ function zodV4ToJsonSchema(schema) {
11626
+ return toStrictJsonSchema(toJSONSchema(schema, {
11627
+ target: 'draft-7',
11628
+ }));
11629
+ }
11630
+ function isZodV4(zodObject) {
11631
+ return '_zod' in zodObject;
11632
+ }
11633
+ function zodTextFormat(zodObject, name, props) {
11634
+ return makeParseableTextFormat({
11635
+ type: 'json_schema',
11636
+ ...props,
11637
+ name,
11638
+ strict: true,
11639
+ schema: isZodV4(zodObject) ? zodV4ToJsonSchema(zodObject) : zodV3ToJsonSchema(zodObject, { name }),
11640
+ }, (content) => zodObject.parse(JSON.parse(content)));
11641
+ }
11642
+
8829
11643
  // llm-openai-config.ts
8830
11644
  const DEFAULT_MODEL = 'gpt-4.1-mini';
8831
11645
  const GPT_5_4_HIGH_CONTEXT_THRESHOLD_TOKENS = 272_000;
@@ -9472,6 +12286,32 @@ function supportsStructuredOutputs(model) {
9472
12286
  function supportsDistillation(model) {
9473
12287
  return normalizeModelName(model) !== 'gpt-5.4-pro';
9474
12288
  }
12289
+ function isZodSchema(schema) {
12290
+ return typeof schema === 'object' && schema !== null && 'safeParse' in schema;
12291
+ }
12292
+ function buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStrict) {
12293
+ if (isZodSchema(schema)) {
12294
+ const zodFormat = zodTextFormat(schema, schemaName, schemaDescription
12295
+ ? {
12296
+ description: schemaDescription,
12297
+ }
12298
+ : undefined);
12299
+ return {
12300
+ type: 'json_schema',
12301
+ name: zodFormat.name,
12302
+ schema: zodFormat.schema,
12303
+ ...(zodFormat.description ? { description: zodFormat.description } : {}),
12304
+ ...(schemaStrict !== undefined ? { strict: schemaStrict } : { strict: zodFormat.strict }),
12305
+ };
12306
+ }
12307
+ return {
12308
+ type: 'json_schema',
12309
+ name: schemaName,
12310
+ schema,
12311
+ ...(schemaDescription ? { description: schemaDescription } : {}),
12312
+ ...(schemaStrict !== undefined ? { strict: schemaStrict } : {}),
12313
+ };
12314
+ }
9475
12315
  /**
9476
12316
  * Makes a call to OpenAI's Responses API for more advanced use cases with built-in tools.
9477
12317
  *
@@ -9579,9 +12419,13 @@ const makeResponsesAPICall = async (input, options = {}) => {
9579
12419
  .join('') || '';
9580
12420
  // Determine the format for parsing the response
9581
12421
  let parsingFormat = 'text';
9582
- if (requestBody.text?.format?.type === 'json_object') {
12422
+ const requestedFormat = requestBody.text?.format;
12423
+ if (requestedFormat?.type === 'json_object') {
9583
12424
  parsingFormat = 'json';
9584
12425
  }
12426
+ else if (requestedFormat?.type === 'json_schema') {
12427
+ parsingFormat = requestedFormat;
12428
+ }
9585
12429
  // Handle regular responses
9586
12430
  const parsedResponse = await parseResponse(textContent, parsingFormat);
9587
12431
  if (parsedResponse === null) {
@@ -9619,7 +12463,7 @@ const makeResponsesAPICall = async (input, options = {}) => {
9619
12463
  * });
9620
12464
  */
9621
12465
  async function makeLLMCall(input, options = {}) {
9622
- const { apiKey, model = DEFAULT_MODEL, responseFormat = 'text', tools, useCodeInterpreter = false, useWebSearch = false, imageBase64, imageDetail = 'high', context, } = options;
12466
+ const { apiKey, model = DEFAULT_MODEL, responseFormat = 'text', schema, schemaName = 'response', schemaDescription, schemaStrict, tools, useCodeInterpreter = false, useWebSearch = false, imageBase64, imageDetail = 'high', context, } = options;
9623
12467
  // Validate model
9624
12468
  const normalizedModel = normalizeModelName(model);
9625
12469
  if (!isSupportedModel(normalizedModel)) {
@@ -9697,9 +12541,17 @@ async function makeLLMCall(input, options = {}) {
9697
12541
  responsesOptions.temperature = 0.2;
9698
12542
  }
9699
12543
  // Configure response format
9700
- if (responseFormat === 'json') {
12544
+ if (schema) {
12545
+ responsesOptions.text = {
12546
+ format: buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStrict),
12547
+ };
12548
+ }
12549
+ else if (responseFormat === 'json') {
9701
12550
  responsesOptions.text = { format: { type: 'json_object' } };
9702
12551
  }
12552
+ else if (typeof responseFormat === 'object' && responseFormat.type === 'json_schema') {
12553
+ responsesOptions.text = { format: responseFormat };
12554
+ }
9703
12555
  // Configure built-in tools
9704
12556
  if (useCodeInterpreter) {
9705
12557
  responsesOptions.tools = [{ type: 'code_interpreter', container: { type: 'auto' } }];
@@ -16213,7 +19065,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16213
19065
  */
16214
19066
  async getHistoricalBars(params) {
16215
19067
  const symbols = params.symbols;
16216
- symbols.join(',');
19068
+ const symbolsStr = symbols.join(',');
16217
19069
  let allBars = {};
16218
19070
  let pageToken = null;
16219
19071
  let hasMorePages = true;
@@ -16224,7 +19076,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16224
19076
  symbols.forEach((symbol) => {
16225
19077
  allBars[symbol] = [];
16226
19078
  });
16227
- log(`Starting historical bars fetch for ${symbols.length} symbols (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`);
19079
+ log(`Starting ${params.timeframe}bars fetch for ${symbols.length} symbols (${symbolsStr}), ${params.start || 'no start'} to ${params.end || 'no end'})`, { symbol: symbolsStr });
16228
19080
  while (hasMorePages) {
16229
19081
  pageCount++;
16230
19082
  const requestParams = {
@@ -16235,7 +19087,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16235
19087
  };
16236
19088
  const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
16237
19089
  if (!response.bars) {
16238
- log(`No bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
19090
+ log(`No bars data found in response for ${symbols.length} symbols`, { symbol: symbolsStr, type: 'warn' });
16239
19091
  break;
16240
19092
  }
16241
19093
  // Track currency from first response
@@ -16269,7 +19121,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16269
19121
  const dateRangeStr = earliestTimestamp && latestTimestamp
16270
19122
  ? `${new Date(earliestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${new Date(latestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
16271
19123
  : 'unknown range';
16272
- log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' });
19124
+ log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { symbol: symbolsStr, type: 'debug' });
16273
19125
  // Prevent infinite loops
16274
19126
  if (pageCount > 1000) {
16275
19127
  log(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
@@ -16280,7 +19132,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16280
19132
  const symbolCounts = Object.entries(allBars)
16281
19133
  .map(([symbol, bars]) => `${symbol}: ${bars.length}`)
16282
19134
  .join(', ');
16283
- log(`Bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`);
19135
+ log(`${params.timeframe} bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`, { symbol: symbolsStr });
16284
19136
  return {
16285
19137
  bars: allBars,
16286
19138
  next_page_token: null, // Always null since we fetch all pages
@@ -17132,6 +19984,26 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
17132
19984
  const marketDataAPI = AlpacaMarketDataAPI.getInstance();
17133
19985
 
17134
19986
  const limitPriceSlippagePercent100 = 0.1; // 0.1%
19987
+ class AlpacaRequestError extends Error {
19988
+ method;
19989
+ status;
19990
+ url;
19991
+ responseCode;
19992
+ responseDetails;
19993
+ rawResponse;
19994
+ symbol;
19995
+ constructor(params) {
19996
+ super(params.message);
19997
+ this.name = 'AlpacaRequestError';
19998
+ this.method = params.method;
19999
+ this.status = params.status ?? null;
20000
+ this.url = params.url;
20001
+ this.responseCode = params.responseCode ?? null;
20002
+ this.responseDetails = params.responseDetails ?? null;
20003
+ this.rawResponse = params.rawResponse ?? null;
20004
+ this.symbol = params.symbol;
20005
+ }
20006
+ }
17135
20007
  /**
17136
20008
  Websocket example
17137
20009
  const alpacaAPI = createAlpacaTradingAPI(credentials); // type AlpacaCredentials
@@ -17215,6 +20087,75 @@ class AlpacaTradingAPI {
17215
20087
  roundPriceForAlpaca = (price) => {
17216
20088
  return price >= 1 ? Math.round(price * 100) / 100 : Math.round(price * 10000) / 10000;
17217
20089
  };
20090
+ isJsonObject(value) {
20091
+ return value !== null && !Array.isArray(value) && typeof value === 'object';
20092
+ }
20093
+ parseAlpacaAPIErrorResponse(rawResponse) {
20094
+ if (rawResponse.trim() === '') {
20095
+ return null;
20096
+ }
20097
+ try {
20098
+ const parsedValue = JSON.parse(rawResponse);
20099
+ if (!this.isJsonObject(parsedValue)) {
20100
+ return null;
20101
+ }
20102
+ const code = parsedValue['code'];
20103
+ const message = parsedValue['message'];
20104
+ const symbol = parsedValue['symbol'];
20105
+ if (typeof code !== 'number' || typeof message !== 'string') {
20106
+ return null;
20107
+ }
20108
+ if (symbol !== undefined && typeof symbol !== 'string') {
20109
+ return null;
20110
+ }
20111
+ return parsedValue;
20112
+ }
20113
+ catch {
20114
+ return null;
20115
+ }
20116
+ }
20117
+ formatJsonValueForLog(value) {
20118
+ if (value === undefined) {
20119
+ return 'undefined';
20120
+ }
20121
+ if (Array.isArray(value)) {
20122
+ return value.map((entry) => this.formatJsonValueForLog(entry)).join(', ');
20123
+ }
20124
+ if (value === null) {
20125
+ return 'null';
20126
+ }
20127
+ if (typeof value === 'object') {
20128
+ return JSON.stringify(value);
20129
+ }
20130
+ return `${value}`;
20131
+ }
20132
+ formatAlpacaAPIErrorDetails(errorResponse) {
20133
+ return Object.entries(errorResponse)
20134
+ .filter(([key]) => key !== 'code' && key !== 'message' && key !== 'symbol')
20135
+ .map(([key, value]) => `${key}=${this.formatJsonValueForLog(value)}`)
20136
+ .join(', ');
20137
+ }
20138
+ formatRequestAction(requestContext) {
20139
+ return requestContext?.action ? `${requestContext.action} failed` : 'Alpaca request failed';
20140
+ }
20141
+ buildAlpacaAPIErrorMessage(params) {
20142
+ const { requestContext, status, url, errorResponse, rawResponse } = params;
20143
+ const action = this.formatRequestAction(requestContext);
20144
+ const message = errorResponse?.message ?? (rawResponse || 'No error body returned');
20145
+ const responseCode = errorResponse?.code ? ` (code ${errorResponse.code})` : '';
20146
+ const detailSummary = errorResponse ? this.formatAlpacaAPIErrorDetails(errorResponse) : '';
20147
+ const detailText = detailSummary !== ''
20148
+ ? ` Details: ${detailSummary}.`
20149
+ : rawResponse.trim() !== '' && errorResponse === null
20150
+ ? ` Response: ${rawResponse}.`
20151
+ : '';
20152
+ return `${action}: Alpaca API ${status}${responseCode}: ${message}.${detailText} Url: ${url}`;
20153
+ }
20154
+ buildRequestExecutionErrorMessage(params) {
20155
+ const { requestContext, url, errorMessage } = params;
20156
+ const action = this.formatRequestAction(requestContext);
20157
+ return `${action}: ${errorMessage}. Url: ${url}`;
20158
+ }
17218
20159
  handleAuthMessage(data) {
17219
20160
  if (data.status === 'authorized') {
17220
20161
  this.authenticated = true;
@@ -17442,7 +20383,7 @@ class AlpacaTradingAPI {
17442
20383
  this.ws?.on('message', handleListenResponse);
17443
20384
  });
17444
20385
  }
17445
- async makeRequest(endpoint, method = 'GET', body, queryString = '') {
20386
+ async makeRequest(endpoint, method = 'GET', body, queryString = '', requestContext) {
17446
20387
  const url = `${this.apiBaseUrl}${endpoint}${queryString}`;
17447
20388
  try {
17448
20389
  const response = await fetch(url, {
@@ -17451,9 +20392,27 @@ class AlpacaTradingAPI {
17451
20392
  body: body ? JSON.stringify(body) : undefined,
17452
20393
  });
17453
20394
  if (!response.ok) {
17454
- const errorText = await response.text();
17455
- this.log(`Alpaca API error (${response.status}): ${errorText}`, { type: 'error' });
17456
- throw new Error(`Alpaca API error (${response.status}): ${errorText}`);
20395
+ const rawResponse = await response.text();
20396
+ const errorResponse = this.parseAlpacaAPIErrorResponse(rawResponse);
20397
+ const symbol = requestContext?.symbol ?? errorResponse?.symbol;
20398
+ const error = new AlpacaRequestError({
20399
+ message: this.buildAlpacaAPIErrorMessage({
20400
+ requestContext,
20401
+ status: response.status,
20402
+ url,
20403
+ errorResponse,
20404
+ rawResponse,
20405
+ }),
20406
+ method,
20407
+ status: response.status,
20408
+ url,
20409
+ responseCode: errorResponse?.code ?? null,
20410
+ responseDetails: errorResponse,
20411
+ rawResponse,
20412
+ symbol,
20413
+ });
20414
+ this.log(error.message, { symbol, type: 'error' });
20415
+ throw error;
17457
20416
  }
17458
20417
  // Handle responses with no content (e.g., 204 No Content)
17459
20418
  if (response.status === 204 || response.headers.get('content-length') === '0') {
@@ -17461,23 +20420,37 @@ class AlpacaTradingAPI {
17461
20420
  }
17462
20421
  const contentType = response.headers.get('content-type');
17463
20422
  if (contentType && contentType.includes('application/json')) {
17464
- return await response.json();
20423
+ return (await response.json());
17465
20424
  }
17466
20425
  // For non-JSON responses, return the text content
17467
20426
  const textContent = await response.text();
17468
- return textContent || null;
20427
+ return (textContent || null);
17469
20428
  }
17470
- catch (err) {
17471
- const error = err;
17472
- this.log(`Error in makeRequest: ${error.message}. Url: ${url}`, {
17473
- source: 'AlpacaAPI',
17474
- type: 'error',
20429
+ catch (error) {
20430
+ if (error instanceof AlpacaRequestError) {
20431
+ throw error;
20432
+ }
20433
+ const normalizedError = error instanceof Error ? error : new Error(`${error}`);
20434
+ const symbol = requestContext?.symbol;
20435
+ const requestError = new AlpacaRequestError({
20436
+ message: this.buildRequestExecutionErrorMessage({
20437
+ requestContext,
20438
+ url,
20439
+ errorMessage: normalizedError.message,
20440
+ }),
20441
+ method,
20442
+ url,
20443
+ rawResponse: null,
20444
+ symbol,
17475
20445
  });
17476
- throw error;
20446
+ this.log(requestError.message, { symbol, type: 'error' });
20447
+ throw requestError;
17477
20448
  }
17478
20449
  }
17479
20450
  async getPositions(assetClass) {
17480
- const positions = (await this.makeRequest('/positions'));
20451
+ const positions = await this.makeRequest('/positions', 'GET', undefined, '', {
20452
+ action: 'Get positions',
20453
+ });
17481
20454
  if (assetClass) {
17482
20455
  return positions.filter((position) => position.asset_class === assetClass);
17483
20456
  }
@@ -17515,22 +20488,15 @@ class AlpacaTradingAPI {
17515
20488
  if (params.side)
17516
20489
  queryParams.append('side', params.side);
17517
20490
  const endpoint = `/orders${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
17518
- try {
17519
- return await this.makeRequest(endpoint);
17520
- }
17521
- catch (error) {
17522
- this.log(`Error getting orders: ${error}`, { type: 'error' });
17523
- throw error;
17524
- }
20491
+ return this.makeRequest(endpoint, 'GET', undefined, '', {
20492
+ action: 'Get orders',
20493
+ symbol: params.symbols?.join(','),
20494
+ });
17525
20495
  }
17526
20496
  async getAccountDetails() {
17527
- try {
17528
- return await this.makeRequest('/account');
17529
- }
17530
- catch (error) {
17531
- this.log(`Error getting account details: ${error}`, { type: 'error' });
17532
- throw error;
17533
- }
20497
+ return this.makeRequest('/account', 'GET', undefined, '', {
20498
+ action: 'Get account details',
20499
+ });
17534
20500
  }
17535
20501
  /**
17536
20502
  * Create a trailing stop order
@@ -17548,27 +20514,21 @@ class AlpacaTradingAPI {
17548
20514
  });
17549
20515
  const body = {
17550
20516
  symbol,
17551
- qty: Math.abs(qty),
20517
+ qty: Math.abs(qty).toString(),
17552
20518
  side,
17553
20519
  position_intent,
17554
20520
  order_class: 'simple',
17555
20521
  type: 'trailing_stop',
17556
- trail_percent: trailPercent100, // Already in decimal form (e.g., 4 for 4%)
20522
+ trail_percent: trailPercent100.toString(),
17557
20523
  time_in_force: 'gtc',
17558
20524
  };
17559
20525
  if (client_order_id !== undefined) {
17560
20526
  body.client_order_id = client_order_id;
17561
20527
  }
17562
- try {
17563
- return await this.makeRequest(`/orders`, 'POST', body);
17564
- }
17565
- catch (error) {
17566
- this.log(`Error creating trailing stop: ${error}`, {
17567
- symbol,
17568
- type: 'error',
17569
- });
17570
- throw error;
17571
- }
20528
+ return this.makeRequest('/orders', 'POST', body, '', {
20529
+ action: 'Create trailing stop order',
20530
+ symbol,
20531
+ });
17572
20532
  }
17573
20533
  /**
17574
20534
  * Create a stop order (stop or stop-limit)
@@ -17594,25 +20554,19 @@ class AlpacaTradingAPI {
17594
20554
  position_intent,
17595
20555
  order_class: 'simple',
17596
20556
  type: isStopLimit ? 'stop_limit' : 'stop',
17597
- stop_price: this.roundPriceForAlpaca(stopPrice),
20557
+ stop_price: this.roundPriceForAlpaca(stopPrice).toString(),
17598
20558
  time_in_force: 'gtc',
17599
20559
  };
17600
- if (isStopLimit) {
17601
- body.limit_price = this.roundPriceForAlpaca(limitPrice);
20560
+ if (limitPrice !== undefined) {
20561
+ body.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
17602
20562
  }
17603
20563
  if (client_order_id !== undefined) {
17604
20564
  body.client_order_id = client_order_id;
17605
20565
  }
17606
- try {
17607
- return await this.makeRequest(`/orders`, 'POST', body);
17608
- }
17609
- catch (error) {
17610
- this.log(`Error creating ${orderType} order: ${error}`, {
17611
- symbol,
17612
- type: 'error',
17613
- });
17614
- throw error;
17615
- }
20566
+ return this.makeRequest('/orders', 'POST', body, '', {
20567
+ action: `Create ${orderType} order`,
20568
+ symbol,
20569
+ });
17616
20570
  }
17617
20571
  /**
17618
20572
  * Create a market order
@@ -17638,13 +20592,10 @@ class AlpacaTradingAPI {
17638
20592
  if (client_order_id !== undefined) {
17639
20593
  body.client_order_id = client_order_id;
17640
20594
  }
17641
- try {
17642
- return await this.makeRequest('/orders', 'POST', body);
17643
- }
17644
- catch (error) {
17645
- this.log(`Error creating market order: ${error}`, { type: 'error' });
17646
- throw error;
17647
- }
20595
+ return this.makeRequest('/orders', 'POST', body, '', {
20596
+ action: 'Create market order',
20597
+ symbol,
20598
+ });
17648
20599
  }
17649
20600
  /**
17650
20601
  * Create a Market on Open (MOO) order - executes in the opening auction
@@ -17678,13 +20629,10 @@ class AlpacaTradingAPI {
17678
20629
  if (client_order_id !== undefined) {
17679
20630
  body.client_order_id = client_order_id;
17680
20631
  }
17681
- try {
17682
- return await this.makeRequest('/orders', 'POST', body);
17683
- }
17684
- catch (error) {
17685
- this.log(`Error creating MOO order: ${error}`, { type: 'error' });
17686
- throw error;
17687
- }
20632
+ return this.makeRequest('/orders', 'POST', body, '', {
20633
+ action: 'Create market on open order',
20634
+ symbol,
20635
+ });
17688
20636
  }
17689
20637
  /**
17690
20638
  * Create a Market on Close (MOC) order - executes in the closing auction
@@ -17718,13 +20666,10 @@ class AlpacaTradingAPI {
17718
20666
  if (client_order_id !== undefined) {
17719
20667
  body.client_order_id = client_order_id;
17720
20668
  }
17721
- try {
17722
- return await this.makeRequest('/orders', 'POST', body);
17723
- }
17724
- catch (error) {
17725
- this.log(`Error creating MOC order: ${error}`, { type: 'error' });
17726
- throw error;
17727
- }
20669
+ return this.makeRequest('/orders', 'POST', body, '', {
20670
+ action: 'Create market on close order',
20671
+ symbol,
20672
+ });
17728
20673
  }
17729
20674
  /**
17730
20675
  * Create an OCO (One-Cancels-Other) order with take profit and stop loss
@@ -17750,32 +20695,29 @@ class AlpacaTradingAPI {
17750
20695
  position_intent,
17751
20696
  order_class: 'oco',
17752
20697
  type: 'limit',
17753
- limit_price: this.roundPriceForAlpaca(limitPrice),
20698
+ limit_price: this.roundPriceForAlpaca(limitPrice).toString(),
17754
20699
  time_in_force: 'gtc',
17755
20700
  take_profit: {
17756
- limit_price: this.roundPriceForAlpaca(takeProfitPrice),
20701
+ limit_price: this.roundPriceForAlpaca(takeProfitPrice).toString(),
17757
20702
  },
17758
20703
  stop_loss: {
17759
- stop_price: this.roundPriceForAlpaca(stopLossPrice),
20704
+ stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
17760
20705
  },
17761
20706
  };
17762
20707
  // If stop loss limit price is provided, create stop-limit order
17763
20708
  if (stopLossLimitPrice !== undefined) {
17764
- body.stop_loss.limit_price = this.roundPriceForAlpaca(stopLossLimitPrice);
20709
+ body.stop_loss = {
20710
+ stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
20711
+ limit_price: this.roundPriceForAlpaca(stopLossLimitPrice).toString(),
20712
+ };
17765
20713
  }
17766
20714
  if (client_order_id !== undefined) {
17767
20715
  body.client_order_id = client_order_id;
17768
20716
  }
17769
- try {
17770
- return await this.makeRequest(`/orders`, 'POST', body);
17771
- }
17772
- catch (error) {
17773
- this.log(`Error creating OCO order: ${error}`, {
17774
- symbol,
17775
- type: 'error',
17776
- });
17777
- throw error;
17778
- }
20717
+ return this.makeRequest('/orders', 'POST', body, '', {
20718
+ action: 'Create OCO order',
20719
+ symbol,
20720
+ });
17779
20721
  }
17780
20722
  /**
17781
20723
  * Get the current trail percent for a symbol, assuming that it has an open position and a trailing stop order to close it. Because this relies on an orders request for one symbol, you can't do it too often.
@@ -17783,35 +20725,26 @@ class AlpacaTradingAPI {
17783
20725
  * @returns the current trail percent
17784
20726
  */
17785
20727
  async getCurrentTrailPercent(symbol) {
17786
- try {
17787
- const orders = await this.getOrders({
17788
- status: 'open',
17789
- symbols: [symbol],
20728
+ const orders = await this.getOrders({
20729
+ status: 'open',
20730
+ symbols: [symbol],
20731
+ });
20732
+ const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop' &&
20733
+ (order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
20734
+ if (!trailingStopOrder) {
20735
+ this.log(`No closing trailing stop order found for ${symbol}`, {
20736
+ symbol,
17790
20737
  });
17791
- const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop' &&
17792
- (order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
17793
- if (!trailingStopOrder) {
17794
- this.log(`No closing trailing stop order found for ${symbol}`, {
17795
- symbol,
17796
- });
17797
- return null;
17798
- }
17799
- if (!trailingStopOrder.trail_percent) {
17800
- this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
17801
- symbol,
17802
- });
17803
- return null;
17804
- }
17805
- const trailPercent = parseFloat(trailingStopOrder.trail_percent);
17806
- return trailPercent;
20738
+ return null;
17807
20739
  }
17808
- catch (error) {
17809
- this.log(`Error getting current trail percent: ${error}`, {
20740
+ if (!trailingStopOrder.trail_percent) {
20741
+ this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
17810
20742
  symbol,
17811
- type: 'error',
17812
20743
  });
17813
- throw error;
20744
+ return null;
17814
20745
  }
20746
+ const trailPercent = parseFloat(trailingStopOrder.trail_percent);
20747
+ return trailPercent;
17815
20748
  }
17816
20749
  /**
17817
20750
  * Update the trail percent for a trailing stop order
@@ -17843,18 +20776,10 @@ class AlpacaTradingAPI {
17843
20776
  this.log(`Updating trailing stop for ${symbol} from ${currentTrailPercent}% to ${trailPercent100}%`, {
17844
20777
  symbol,
17845
20778
  });
17846
- try {
17847
- await this.makeRequest(`/orders/${trailingStopOrder.id}`, 'PATCH', {
17848
- trail: trailPercent100.toString(), // Changed from trail_percent to trail
17849
- });
17850
- }
17851
- catch (error) {
17852
- this.log(`Error updating trailing stop: ${error}`, {
17853
- symbol,
17854
- type: 'error',
17855
- });
17856
- throw error;
17857
- }
20779
+ await this.makeRequest(`/orders/${trailingStopOrder.id}`, 'PATCH', { trail: trailPercent100.toString() }, '', {
20780
+ action: 'Update trailing stop order',
20781
+ symbol,
20782
+ });
17858
20783
  }
17859
20784
  /**
17860
20785
  * Cancel all open orders
@@ -17862,10 +20787,16 @@ class AlpacaTradingAPI {
17862
20787
  async cancelAllOrders() {
17863
20788
  this.log(`Canceling all open orders`);
17864
20789
  try {
17865
- await this.makeRequest('/orders', 'DELETE');
20790
+ await this.makeRequest('/orders', 'DELETE', undefined, '', {
20791
+ action: 'Cancel all open orders',
20792
+ });
17866
20793
  }
17867
20794
  catch (error) {
17868
- this.log(`Error canceling all orders: ${error}`, { type: 'error' });
20795
+ if (!(error instanceof AlpacaRequestError)) {
20796
+ this.log(`Error canceling all orders: ${error instanceof Error ? error.message : `${error}`}`, {
20797
+ type: 'error',
20798
+ });
20799
+ }
17869
20800
  }
17870
20801
  }
17871
20802
  /**
@@ -17877,15 +20808,14 @@ class AlpacaTradingAPI {
17877
20808
  async cancelOrder(orderId) {
17878
20809
  this.log(`Attempting to cancel order ${orderId}`);
17879
20810
  try {
17880
- await this.makeRequest(`/orders/${orderId}`, 'DELETE');
20811
+ await this.makeRequest(`/orders/${orderId}`, 'DELETE', undefined, '', {
20812
+ action: `Cancel order ${orderId}`,
20813
+ });
17881
20814
  this.log(`Successfully canceled order ${orderId}`);
17882
20815
  }
17883
20816
  catch (error) {
17884
20817
  // If the error is a 422, it means the order is not cancelable
17885
- if (error instanceof Error && error.message.includes('422')) {
17886
- this.log(`Order ${orderId} is not cancelable`, {
17887
- type: 'error',
17888
- });
20818
+ if (error instanceof AlpacaRequestError && error.status === 422) {
17889
20819
  throw new Error(`Order ${orderId} is not cancelable`);
17890
20820
  }
17891
20821
  // Re-throw other errors
@@ -17920,13 +20850,10 @@ class AlpacaTradingAPI {
17920
20850
  if (client_order_id !== undefined) {
17921
20851
  body.client_order_id = client_order_id;
17922
20852
  }
17923
- try {
17924
- return await this.makeRequest('/orders', 'POST', body);
17925
- }
17926
- catch (error) {
17927
- this.log(`Error creating limit order: ${error}`, { type: 'error' });
17928
- throw error;
17929
- }
20853
+ return this.makeRequest('/orders', 'POST', body, '', {
20854
+ action: 'Create limit order',
20855
+ symbol,
20856
+ });
17930
20857
  }
17931
20858
  /**
17932
20859
  * Close all equities positions
@@ -17992,7 +20919,9 @@ class AlpacaTradingAPI {
17992
20919
  }
17993
20920
  }
17994
20921
  else {
17995
- await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '');
20922
+ await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '', {
20923
+ action: 'Close all positions',
20924
+ });
17996
20925
  }
17997
20926
  }
17998
20927
  /**
@@ -18071,7 +21000,9 @@ class AlpacaTradingAPI {
18071
21000
  queryParams.append('end', params.end);
18072
21001
  if (params.date_end)
18073
21002
  queryParams.append('date_end', params.date_end);
18074
- const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}`);
21003
+ const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}`, 'GET', undefined, '', {
21004
+ action: 'Get portfolio history',
21005
+ });
18075
21006
  return response;
18076
21007
  }
18077
21008
  /**
@@ -18162,7 +21093,10 @@ class AlpacaTradingAPI {
18162
21093
  this.log(`Fetching option contracts for ${params.underlying_symbols.join(', ')}`, {
18163
21094
  symbol: params.underlying_symbols.join(', '),
18164
21095
  });
18165
- const response = (await this.makeRequest(`/options/contracts?${queryParams.toString()}`));
21096
+ const response = await this.makeRequest(`/options/contracts?${queryParams.toString()}`, 'GET', undefined, '', {
21097
+ action: 'Get option contracts',
21098
+ symbol: params.underlying_symbols.join(', '),
21099
+ });
18166
21100
  this.log(`Found ${response.option_contracts.length} option contracts`, {
18167
21101
  symbol: params.underlying_symbols.join(', '),
18168
21102
  });
@@ -18177,7 +21111,10 @@ class AlpacaTradingAPI {
18177
21111
  this.log(`Fetching option contract details for ${symbolOrId}`, {
18178
21112
  symbol: symbolOrId,
18179
21113
  });
18180
- const response = (await this.makeRequest(`/options/contracts/${symbolOrId}`));
21114
+ const response = await this.makeRequest(`/options/contracts/${symbolOrId}`, 'GET', undefined, '', {
21115
+ action: 'Get option contract details',
21116
+ symbol: symbolOrId,
21117
+ });
18181
21118
  this.log(`Found option contract details for ${symbolOrId}: ${response.name}`, {
18182
21119
  symbol: symbolOrId,
18183
21120
  });
@@ -18195,10 +21132,10 @@ class AlpacaTradingAPI {
18195
21132
  */
18196
21133
  async createOptionOrder(symbol, qty, side, position_intent, type, limitPrice) {
18197
21134
  if (!Number.isInteger(qty) || qty <= 0) {
18198
- this.log('Quantity must be a positive whole number for option orders', { type: 'error' });
21135
+ this.log('Quantity must be a positive whole number for option orders', { symbol, type: 'error' });
18199
21136
  }
18200
21137
  if (type === 'limit' && limitPrice === undefined) {
18201
- this.log('Limit price is required for limit orders', { type: 'error' });
21138
+ this.log('Limit price is required for limit orders', { symbol, type: 'error' });
18202
21139
  }
18203
21140
  this.log(`Creating ${type} option order for ${symbol}: ${side} ${qty} contracts (${position_intent})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
18204
21141
  symbol,
@@ -18216,7 +21153,10 @@ class AlpacaTradingAPI {
18216
21153
  if (type === 'limit' && limitPrice !== undefined) {
18217
21154
  orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
18218
21155
  }
18219
- return this.makeRequest('/orders', 'POST', orderData);
21156
+ return this.makeRequest('/orders', 'POST', orderData, '', {
21157
+ action: 'Create option order',
21158
+ symbol,
21159
+ });
18220
21160
  }
18221
21161
  /**
18222
21162
  * Create a multi-leg option order
@@ -18227,16 +21167,19 @@ class AlpacaTradingAPI {
18227
21167
  * @returns The created multi-leg order
18228
21168
  */
18229
21169
  async createMultiLegOptionOrder(legs, qty, type, limitPrice) {
21170
+ const legSymbols = legs.map((leg) => leg.symbol).join(', ');
18230
21171
  if (!Number.isInteger(qty) || qty <= 0) {
18231
- this.log('Quantity must be a positive whole number for option orders', { type: 'error' });
21172
+ this.log('Quantity must be a positive whole number for option orders', {
21173
+ symbol: legSymbols,
21174
+ type: 'error',
21175
+ });
18232
21176
  }
18233
21177
  if (type === 'limit' && limitPrice === undefined) {
18234
- this.log('Limit price is required for limit orders', { type: 'error' });
21178
+ this.log('Limit price is required for limit orders', { symbol: legSymbols, type: 'error' });
18235
21179
  }
18236
21180
  if (legs.length < 2) {
18237
- this.log('Multi-leg orders require at least 2 legs', { type: 'error' });
21181
+ this.log('Multi-leg orders require at least 2 legs', { symbol: legSymbols, type: 'error' });
18238
21182
  }
18239
- const legSymbols = legs.map((leg) => leg.symbol).join(', ');
18240
21183
  this.log(`Creating multi-leg ${type} option order with ${legs.length} legs (${legSymbols})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
18241
21184
  symbol: legSymbols,
18242
21185
  });
@@ -18250,7 +21193,10 @@ class AlpacaTradingAPI {
18250
21193
  if (type === 'limit' && limitPrice !== undefined) {
18251
21194
  orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
18252
21195
  }
18253
- return this.makeRequest('/orders', 'POST', orderData);
21196
+ return this.makeRequest('/orders', 'POST', orderData, '', {
21197
+ action: 'Create multi-leg option order',
21198
+ symbol: legSymbols,
21199
+ });
18254
21200
  }
18255
21201
  /**
18256
21202
  * Exercise an option contract
@@ -18261,7 +21207,10 @@ class AlpacaTradingAPI {
18261
21207
  this.log(`Exercising option contract ${symbolOrContractId}`, {
18262
21208
  symbol: symbolOrContractId,
18263
21209
  });
18264
- return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST');
21210
+ return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST', undefined, '', {
21211
+ action: 'Exercise option contract',
21212
+ symbol: symbolOrContractId,
21213
+ });
18265
21214
  }
18266
21215
  /**
18267
21216
  * Get option positions
@@ -18297,7 +21246,9 @@ class AlpacaTradingAPI {
18297
21246
  queryParams.append('date', date);
18298
21247
  }
18299
21248
  this.log(`Fetching option activities${activityType ? ` of type ${activityType}` : ''}${date ? ` for date ${date}` : ''}`);
18300
- return this.makeRequest(`/account/activities?${queryParams.toString()}`);
21249
+ return this.makeRequest(`/account/activities?${queryParams.toString()}`, 'GET', undefined, '', {
21250
+ action: 'Get option activities',
21251
+ });
18301
21252
  }
18302
21253
  /**
18303
21254
  * Create a long call spread (buy lower strike call, sell higher strike call)
@@ -18395,13 +21346,7 @@ class AlpacaTradingAPI {
18395
21346
  position_intent: 'buy_to_open',
18396
21347
  },
18397
21348
  ];
18398
- try {
18399
- return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
18400
- }
18401
- catch (error) {
18402
- this.log(`Error creating iron condor: ${error}`, { type: 'error' });
18403
- throw error;
18404
- }
21349
+ return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
18405
21350
  }
18406
21351
  /**
18407
21352
  * Create a covered call (sell call option against owned stock)
@@ -18417,13 +21362,7 @@ class AlpacaTradingAPI {
18417
21362
  });
18418
21363
  // For covered calls, we don't need to include the stock leg if we already own the shares
18419
21364
  // We just create a simple sell order for the call option
18420
- try {
18421
- return await this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
18422
- }
18423
- catch (error) {
18424
- this.log(`Error creating covered call: ${error}`, { type: 'error' });
18425
- throw error;
18426
- }
21365
+ return this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
18427
21366
  }
18428
21367
  /**
18429
21368
  * Roll an option position to a new expiration or strike
@@ -18458,13 +21397,7 @@ class AlpacaTradingAPI {
18458
21397
  position_intent: openPositionIntent,
18459
21398
  },
18460
21399
  ];
18461
- try {
18462
- return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
18463
- }
18464
- catch (error) {
18465
- this.log(`Error rolling option position: ${error}`, { type: 'error' });
18466
- throw error;
18467
- }
21400
+ return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
18468
21401
  }
18469
21402
  /**
18470
21403
  * Get option chain for a specific underlying symbol and expiration date
@@ -18488,10 +21421,12 @@ class AlpacaTradingAPI {
18488
21421
  return response.option_contracts || [];
18489
21422
  }
18490
21423
  catch (error) {
18491
- this.log(`Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : 'Unknown error'}`, {
18492
- type: 'error',
18493
- symbol: underlyingSymbol,
18494
- });
21424
+ if (!(error instanceof AlpacaRequestError)) {
21425
+ this.log(`Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
21426
+ type: 'error',
21427
+ symbol: underlyingSymbol,
21428
+ });
21429
+ }
18495
21430
  return [];
18496
21431
  }
18497
21432
  }
@@ -18522,10 +21457,12 @@ class AlpacaTradingAPI {
18522
21457
  return Array.from(expirationDates).sort();
18523
21458
  }
18524
21459
  catch (error) {
18525
- this.log(`Failed to fetch expiration dates for ${underlyingSymbol}: ${error instanceof Error ? error.message : 'Unknown error'}`, {
18526
- type: 'error',
18527
- symbol: underlyingSymbol,
18528
- });
21460
+ if (!(error instanceof AlpacaRequestError)) {
21461
+ this.log(`Failed to fetch expiration dates for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
21462
+ type: 'error',
21463
+ symbol: underlyingSymbol,
21464
+ });
21465
+ }
18529
21466
  return [];
18530
21467
  }
18531
21468
  }
@@ -18584,7 +21521,10 @@ class AlpacaTradingAPI {
18584
21521
  this.log(`Canceling open order for ${order.symbol}`, {
18585
21522
  symbol: order.symbol,
18586
21523
  });
18587
- await this.makeRequest(`/orders/${order.id}`, 'DELETE');
21524
+ await this.makeRequest(`/orders/${order.id}`, 'DELETE', undefined, '', {
21525
+ action: `Cancel option order ${order.id}`,
21526
+ symbol: order.symbol,
21527
+ });
18588
21528
  }
18589
21529
  }
18590
21530
  }
@@ -18607,13 +21547,7 @@ class AlpacaTradingAPI {
18607
21547
  const quantityToClose = qty || parseInt(position.qty);
18608
21548
  const side = position.side === 'long' ? 'sell' : 'buy';
18609
21549
  const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';
18610
- try {
18611
- return await this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
18612
- }
18613
- catch (error) {
18614
- this.log(`Error closing option position: ${error}`, { type: 'error' });
18615
- throw error;
18616
- }
21550
+ return this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
18617
21551
  }
18618
21552
  /**
18619
21553
  * Create a complete equities trade with optional stop loss and take profit
@@ -18748,16 +21682,10 @@ class AlpacaTradingAPI {
18748
21682
  this.log(logMessage, {
18749
21683
  symbol,
18750
21684
  });
18751
- try {
18752
- return await this.makeRequest('/orders', 'POST', orderData);
18753
- }
18754
- catch (error) {
18755
- this.log(`Error creating equities trade: ${error}`, {
18756
- symbol,
18757
- type: 'error',
18758
- });
18759
- throw error;
18760
- }
21685
+ return this.makeRequest('/orders', 'POST', orderData, '', {
21686
+ action: 'Create equities trade',
21687
+ symbol,
21688
+ });
18761
21689
  }
18762
21690
  }
18763
21691