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