@orpc/openapi 0.0.0-next.55d0b4f → 0.0.0-next.571d5d7

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.
@@ -0,0 +1,49 @@
1
+ // src/utils.ts
2
+ import { isContractProcedure } from "@orpc/contract";
3
+ import { isLazy, isProcedure, ROUTER_CONTRACT_SYMBOL } from "@orpc/server";
4
+ function eachContractProcedureLeaf(options, callback, result = [], isCurrentRouterContract = false) {
5
+ if (!isCurrentRouterContract && ROUTER_CONTRACT_SYMBOL in options.router && options.router[ROUTER_CONTRACT_SYMBOL]) {
6
+ return eachContractProcedureLeaf(
7
+ {
8
+ path: options.path,
9
+ router: options.router[ROUTER_CONTRACT_SYMBOL]
10
+ },
11
+ callback,
12
+ result,
13
+ true
14
+ );
15
+ }
16
+ if (isLazy(options.router)) {
17
+ result.push({
18
+ lazy: options.router,
19
+ path: options.path
20
+ });
21
+ } else if (isProcedure(options.router)) {
22
+ callback({
23
+ contract: options.router.zz$p.contract,
24
+ path: options.path
25
+ });
26
+ } else if (isContractProcedure(options.router)) {
27
+ callback({
28
+ contract: options.router,
29
+ path: options.path
30
+ });
31
+ } else {
32
+ for (const key in options.router) {
33
+ eachContractProcedureLeaf(
34
+ {
35
+ router: options.router[key],
36
+ path: [...options.path, key]
37
+ },
38
+ callback,
39
+ result
40
+ );
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+
46
+ export {
47
+ eachContractProcedureLeaf
48
+ };
49
+ //# sourceMappingURL=chunk-KZIT2WCV.js.map
package/dist/fetch.js CHANGED
@@ -1,7 +1,11 @@
1
+ import {
2
+ eachContractProcedureLeaf
3
+ } from "./chunk-KZIT2WCV.js";
4
+
1
5
  // src/fetch/base-handler.ts
2
6
  import { ORPC_HEADER, standardizeHTTPPath } from "@orpc/contract";
3
- import { createProcedureCaller, isProcedure, ORPCError } from "@orpc/server";
4
- import { isPlainObject, mapValues, trim, value } from "@orpc/shared";
7
+ import { createProcedureCaller, isLazy, isProcedure, LAZY_LOADER_SYMBOL, LAZY_ROUTER_PREFIX_SYMBOL, ORPCError } from "@orpc/server";
8
+ import { executeWithHooks, isPlainObject, mapValues, trim, value } from "@orpc/shared";
5
9
  import { OpenAPIDeserializer, OpenAPISerializer, zodCoerce } from "@orpc/transformer";
6
10
  function createOpenAPIHandler(createHonoRouter) {
7
11
  const resolveRouter = createResolveRouter(createHonoRouter);
@@ -17,12 +21,18 @@ function createOpenAPIHandler(createHonoRouter) {
17
21
  const pathname = `/${trim(url.pathname.replace(options.prefix ?? "", ""), "/")}`;
18
22
  const customMethod = options.request.method === "POST" ? url.searchParams.get("method")?.toUpperCase() : void 0;
19
23
  const method = customMethod || options.request.method;
20
- const match = resolveRouter(options.router, method, pathname);
24
+ const match = await resolveRouter(options.router, method, pathname);
21
25
  if (!match) {
22
26
  throw new ORPCError({ code: "NOT_FOUND", message: "Not found" });
23
27
  }
24
- const procedure = match.procedure;
28
+ const procedure = isLazy(match.procedure) ? (await match.procedure[LAZY_LOADER_SYMBOL]()).default : match.procedure;
25
29
  const path = match.path;
30
+ if (!isProcedure(procedure)) {
31
+ throw new ORPCError({
32
+ code: "NOT_FOUND",
33
+ message: "Not found"
34
+ });
35
+ }
26
36
  const params = procedure.zz$p.contract.zz$cp.InputSchema ? zodCoerce(
27
37
  procedure.zz$p.contract.zz$cp.InputSchema,
28
38
  match.params,
@@ -35,7 +45,7 @@ function createOpenAPIHandler(createHonoRouter) {
35
45
  procedure,
36
46
  path
37
47
  });
38
- const output = await caller(mergedInput);
48
+ const output = await caller(mergedInput, { signal: options.signal });
39
49
  const { body, headers } = serializer.serialize(output);
40
50
  return new Response(body, {
41
51
  status: 200,
@@ -43,10 +53,15 @@ function createOpenAPIHandler(createHonoRouter) {
43
53
  });
44
54
  };
45
55
  try {
46
- return await options.hooks?.(context, {
47
- next: handler,
48
- response: (response) => response
49
- }) ?? await handler();
56
+ return await executeWithHooks({
57
+ context,
58
+ hooks: options,
59
+ execute: handler,
60
+ input: options.request,
61
+ meta: {
62
+ signal: options.signal
63
+ }
64
+ });
50
65
  } catch (e) {
51
66
  const error = toORPCError(e);
52
67
  try {
@@ -69,27 +84,44 @@ function createOpenAPIHandler(createHonoRouter) {
69
84
  };
70
85
  }
71
86
  var routingCache = /* @__PURE__ */ new Map();
87
+ var pendingCache = /* @__PURE__ */ new Map();
72
88
  function createResolveRouter(createHonoRouter) {
73
- return (router, method, pathname) => {
74
- let routing = routingCache.get(router);
75
- if (!routing) {
76
- routing = createHonoRouter();
77
- const addRouteRecursively = (routing2, router2, basePath) => {
78
- for (const key in router2) {
79
- const currentPath = [...basePath, key];
80
- const item = router2[key];
81
- if (isProcedure(item)) {
82
- const method2 = item.zz$p.contract.zz$cp.method ?? "POST";
83
- const path2 = item.zz$p.contract.zz$cp.path ? openAPIPathToRouterPath(item.zz$p.contract.zz$cp.path) : `/${currentPath.map(encodeURIComponent).join("/")}`;
84
- routing2.add(method2, path2, [currentPath, item]);
85
- } else {
86
- addRouteRecursively(routing2, item, currentPath);
87
- }
88
- }
89
- };
90
- addRouteRecursively(routing, router, []);
91
- routingCache.set(router, routing);
89
+ const addRoutes = (routing, pending, options) => {
90
+ const lazies = eachContractProcedureLeaf(options, ({ path, contract }) => {
91
+ const method = contract.zz$cp.method ?? "POST";
92
+ const httpPath = contract.zz$cp.path ? openAPIPathToRouterPath(contract.zz$cp.path) : `/${path.map(encodeURIComponent).join("/")}`;
93
+ routing.add(method, httpPath, path);
94
+ });
95
+ pending.ref.push(...lazies);
96
+ };
97
+ return async (router, method, pathname) => {
98
+ const pending = (() => {
99
+ let pending2 = pendingCache.get(router);
100
+ if (!pending2) {
101
+ pending2 = { ref: [] };
102
+ pendingCache.set(router, pending2);
103
+ }
104
+ return pending2;
105
+ })();
106
+ const routing = (() => {
107
+ let routing2 = routingCache.get(router);
108
+ if (!routing2) {
109
+ routing2 = createHonoRouter();
110
+ routingCache.set(router, routing2);
111
+ addRoutes(routing2, pending, { router, path: [] });
112
+ }
113
+ return routing2;
114
+ })();
115
+ const newPending = [];
116
+ for (const item of pending.ref) {
117
+ if (LAZY_ROUTER_PREFIX_SYMBOL in item.lazy && item.lazy[LAZY_ROUTER_PREFIX_SYMBOL] && !pathname.startsWith(item.lazy[LAZY_ROUTER_PREFIX_SYMBOL]) && !pathname.startsWith(`/${item.path.map(encodeURIComponent).join("/")}`)) {
118
+ newPending.push(item);
119
+ continue;
120
+ }
121
+ const router2 = (await item.lazy[LAZY_LOADER_SYMBOL]()).default;
122
+ addRoutes(routing, pending, { path: item.path, router: router2 });
92
123
  }
124
+ pending.ref = newPending;
93
125
  const [matches, params_] = routing.match(method, pathname);
94
126
  const [match] = matches.sort((a, b) => {
95
127
  return Object.keys(a[1]).length - Object.keys(b[1]).length;
@@ -97,18 +129,25 @@ function createResolveRouter(createHonoRouter) {
97
129
  if (!match) {
98
130
  return void 0;
99
131
  }
100
- const path = match[0][0];
101
- const procedure = match[0][1];
132
+ const path = match[0];
102
133
  const params = params_ ? mapValues(
103
134
  match[1],
104
135
  (v) => params_[v]
105
136
  ) : match[1];
106
- return {
137
+ let current = router;
138
+ for (const segment of path) {
139
+ if (typeof current !== "object" && typeof current !== "function" || !current) {
140
+ current = void 0;
141
+ break;
142
+ }
143
+ current = current[segment];
144
+ }
145
+ return isProcedure(current) || isLazy(current) ? {
107
146
  path,
108
- procedure,
147
+ procedure: current,
109
148
  params: { ...params }
110
149
  // params from hono not a normal object, so we need spread here
111
- };
150
+ } : void 0;
112
151
  };
113
152
  }
114
153
  function mergeParamsAndInput(coercedParams, input) {
@@ -148,13 +187,13 @@ function openAPIPathToRouterPath(path) {
148
187
  return standardizeHTTPPath(path).replace(/\{([^}]+)\}/g, ":$1");
149
188
  }
150
189
 
151
- // ../../node_modules/.pnpm/hono@4.6.12/node_modules/hono/dist/router.js
190
+ // ../../node_modules/.pnpm/hono@4.6.13/node_modules/hono/dist/router.js
152
191
  var METHOD_NAME_ALL = "ALL";
153
192
  var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
154
193
  var UnsupportedPathError = class extends Error {
155
194
  };
156
195
 
157
- // ../../node_modules/.pnpm/hono@4.6.12/node_modules/hono/dist/utils/url.js
196
+ // ../../node_modules/.pnpm/hono@4.6.13/node_modules/hono/dist/utils/url.js
158
197
  var checkOptionalParameter = (path) => {
159
198
  if (!path.match(/\:.+\?$/)) {
160
199
  return null;
@@ -183,7 +222,7 @@ var checkOptionalParameter = (path) => {
183
222
  return results.filter((v, i, a) => a.indexOf(v) === i);
184
223
  };
185
224
 
186
- // ../../node_modules/.pnpm/hono@4.6.12/node_modules/hono/dist/router/reg-exp-router/node.js
225
+ // ../../node_modules/.pnpm/hono@4.6.13/node_modules/hono/dist/router/reg-exp-router/node.js
187
226
  var LABEL_REG_EXP_STR = "[^/]+";
188
227
  var ONLY_WILDCARD_REG_EXP_STR = ".*";
189
228
  var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
@@ -288,7 +327,7 @@ var Node = class {
288
327
  }
289
328
  };
290
329
 
291
- // ../../node_modules/.pnpm/hono@4.6.12/node_modules/hono/dist/router/reg-exp-router/trie.js
330
+ // ../../node_modules/.pnpm/hono@4.6.13/node_modules/hono/dist/router/reg-exp-router/trie.js
292
331
  var Trie = class {
293
332
  #context = { varIndex: 0 };
294
333
  #root = new Node();
@@ -344,7 +383,7 @@ var Trie = class {
344
383
  }
345
384
  };
346
385
 
347
- // ../../node_modules/.pnpm/hono@4.6.12/node_modules/hono/dist/router/reg-exp-router/router.js
386
+ // ../../node_modules/.pnpm/hono@4.6.13/node_modules/hono/dist/router/reg-exp-router/router.js
348
387
  var emptyParam = [];
349
388
  var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
350
389
  var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
@@ -545,7 +584,7 @@ function createOpenAPIServerHandler() {
545
584
  return createOpenAPIHandler(() => new RegExpRouter());
546
585
  }
547
586
 
548
- // ../../node_modules/.pnpm/hono@4.6.12/node_modules/hono/dist/router/linear-router/router.js
587
+ // ../../node_modules/.pnpm/hono@4.6.13/node_modules/hono/dist/router/linear-router/router.js
549
588
  var emptyParams = /* @__PURE__ */ Object.create(null);
550
589
  var splitPathRe = /\/(:\w+(?:{(?:(?:{[\d,]+})|[^}])+})?)|\/[^\/\?]+|(\?)/g;
551
590
  var splitByStarRe = /\*/;
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
+ import {
2
+ eachContractProcedureLeaf
3
+ } from "./chunk-KZIT2WCV.js";
4
+
1
5
  // src/generator.ts
2
- import { eachContractRouterLeaf } from "@orpc/contract";
3
- import { toContractRouter } from "@orpc/server";
6
+ import { isContractProcedure } from "@orpc/contract";
7
+ import { LAZY_LOADER_SYMBOL } from "@orpc/server";
4
8
  import { findDeepMatches, isPlainObject, omit } from "@orpc/shared";
5
9
  import { preSerialize } from "@orpc/transformer";
6
10
  import {
@@ -18,7 +22,7 @@ import {
18
22
  Format
19
23
  } from "json-schema-typed/draft-2020-12";
20
24
 
21
- // ../../node_modules/.pnpm/zod@3.23.8/node_modules/zod/lib/index.mjs
25
+ // ../../node_modules/.pnpm/zod@3.24.1/node_modules/zod/lib/index.mjs
22
26
  var util;
23
27
  (function(util2) {
24
28
  util2.assertEqual = (val) => val;
@@ -169,6 +173,9 @@ var ZodIssueCode = util.arrayToEnum([
169
173
  "not_finite"
170
174
  ]);
171
175
  var ZodError = class _ZodError extends Error {
176
+ get errors() {
177
+ return this.issues;
178
+ }
172
179
  constructor(issues) {
173
180
  super();
174
181
  this.issues = [];
@@ -187,9 +194,6 @@ var ZodError = class _ZodError extends Error {
187
194
  this.name = "ZodError";
188
195
  this.issues = issues;
189
196
  }
190
- get errors() {
191
- return this.issues;
192
- }
193
197
  format(_mapper) {
194
198
  const mapper = _mapper || function(issue) {
195
199
  return issue.message;
@@ -396,8 +400,11 @@ function addIssueToContext(ctx, issueData) {
396
400
  path: ctx.path,
397
401
  errorMaps: [
398
402
  ctx.common.contextualErrorMap,
403
+ // contextual error map is first priority
399
404
  ctx.schemaErrorMap,
405
+ // then schema-bound map if available
400
406
  overrideMap,
407
+ // then global override map
401
408
  overrideMap === errorMap ? void 0 : errorMap
402
409
  // then global default map
403
410
  ].filter((x) => !!x)
@@ -548,34 +555,6 @@ function processCreateParams(params) {
548
555
  return { errorMap: customMap, description };
549
556
  }
550
557
  var ZodType = class {
551
- constructor(def) {
552
- this.spa = this.safeParseAsync;
553
- this._def = def;
554
- this.parse = this.parse.bind(this);
555
- this.safeParse = this.safeParse.bind(this);
556
- this.parseAsync = this.parseAsync.bind(this);
557
- this.safeParseAsync = this.safeParseAsync.bind(this);
558
- this.spa = this.spa.bind(this);
559
- this.refine = this.refine.bind(this);
560
- this.refinement = this.refinement.bind(this);
561
- this.superRefine = this.superRefine.bind(this);
562
- this.optional = this.optional.bind(this);
563
- this.nullable = this.nullable.bind(this);
564
- this.nullish = this.nullish.bind(this);
565
- this.array = this.array.bind(this);
566
- this.promise = this.promise.bind(this);
567
- this.or = this.or.bind(this);
568
- this.and = this.and.bind(this);
569
- this.transform = this.transform.bind(this);
570
- this.brand = this.brand.bind(this);
571
- this.default = this.default.bind(this);
572
- this.catch = this.catch.bind(this);
573
- this.describe = this.describe.bind(this);
574
- this.pipe = this.pipe.bind(this);
575
- this.readonly = this.readonly.bind(this);
576
- this.isNullable = this.isNullable.bind(this);
577
- this.isOptional = this.isOptional.bind(this);
578
- }
579
558
  get description() {
580
559
  return this._def.description;
581
560
  }
@@ -639,6 +618,43 @@ var ZodType = class {
639
618
  const result = this._parseSync({ data, path: ctx.path, parent: ctx });
640
619
  return handleResult(ctx, result);
641
620
  }
621
+ "~validate"(data) {
622
+ var _a, _b;
623
+ const ctx = {
624
+ common: {
625
+ issues: [],
626
+ async: !!this["~standard"].async
627
+ },
628
+ path: [],
629
+ schemaErrorMap: this._def.errorMap,
630
+ parent: null,
631
+ data,
632
+ parsedType: getParsedType(data)
633
+ };
634
+ if (!this["~standard"].async) {
635
+ try {
636
+ const result = this._parseSync({ data, path: [], parent: ctx });
637
+ return isValid(result) ? {
638
+ value: result.value
639
+ } : {
640
+ issues: ctx.common.issues
641
+ };
642
+ } catch (err) {
643
+ if ((_b = (_a = err === null || err === void 0 ? void 0 : err.message) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === null || _b === void 0 ? void 0 : _b.includes("encountered")) {
644
+ this["~standard"].async = true;
645
+ }
646
+ ctx.common = {
647
+ issues: [],
648
+ async: true
649
+ };
650
+ }
651
+ }
652
+ return this._parseAsync({ data, path: [], parent: ctx }).then((result) => isValid(result) ? {
653
+ value: result.value
654
+ } : {
655
+ issues: ctx.common.issues
656
+ });
657
+ }
642
658
  async parseAsync(data, params) {
643
659
  const result = await this.safeParseAsync(data, params);
644
660
  if (result.success)
@@ -716,6 +732,39 @@ var ZodType = class {
716
732
  superRefine(refinement) {
717
733
  return this._refinement(refinement);
718
734
  }
735
+ constructor(def) {
736
+ this.spa = this.safeParseAsync;
737
+ this._def = def;
738
+ this.parse = this.parse.bind(this);
739
+ this.safeParse = this.safeParse.bind(this);
740
+ this.parseAsync = this.parseAsync.bind(this);
741
+ this.safeParseAsync = this.safeParseAsync.bind(this);
742
+ this.spa = this.spa.bind(this);
743
+ this.refine = this.refine.bind(this);
744
+ this.refinement = this.refinement.bind(this);
745
+ this.superRefine = this.superRefine.bind(this);
746
+ this.optional = this.optional.bind(this);
747
+ this.nullable = this.nullable.bind(this);
748
+ this.nullish = this.nullish.bind(this);
749
+ this.array = this.array.bind(this);
750
+ this.promise = this.promise.bind(this);
751
+ this.or = this.or.bind(this);
752
+ this.and = this.and.bind(this);
753
+ this.transform = this.transform.bind(this);
754
+ this.brand = this.brand.bind(this);
755
+ this.default = this.default.bind(this);
756
+ this.catch = this.catch.bind(this);
757
+ this.describe = this.describe.bind(this);
758
+ this.pipe = this.pipe.bind(this);
759
+ this.readonly = this.readonly.bind(this);
760
+ this.isNullable = this.isNullable.bind(this);
761
+ this.isOptional = this.isOptional.bind(this);
762
+ this["~standard"] = {
763
+ version: 1,
764
+ vendor: "zod",
765
+ validate: (data) => this["~validate"](data)
766
+ };
767
+ }
719
768
  optional() {
720
769
  return ZodOptional.create(this, this._def);
721
770
  }
@@ -726,7 +775,7 @@ var ZodType = class {
726
775
  return this.nullable().optional();
727
776
  }
728
777
  array() {
729
- return ZodArray.create(this, this._def);
778
+ return ZodArray.create(this);
730
779
  }
731
780
  promise() {
732
781
  return ZodPromise.create(this, this._def);
@@ -792,16 +841,20 @@ var ZodType = class {
792
841
  };
793
842
  var cuidRegex = /^c[^\s-]{8,}$/i;
794
843
  var cuid2Regex = /^[0-9a-z]+$/;
795
- var ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/;
844
+ var ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/i;
796
845
  var uuidRegex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i;
797
846
  var nanoidRegex = /^[a-z0-9_-]{21}$/i;
847
+ var jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/;
798
848
  var durationRegex = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/;
799
849
  var emailRegex = /^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i;
800
850
  var _emojiRegex = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`;
801
851
  var emojiRegex;
802
852
  var ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
803
- var ipv6Regex = /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/;
853
+ var ipv4CidrRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/;
854
+ var ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
855
+ var ipv6CidrRegex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
804
856
  var base64Regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
857
+ var base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/;
805
858
  var dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
806
859
  var dateRegex = new RegExp(`^${dateRegexSource}$`);
807
860
  function timeRegexSource(args) {
@@ -834,6 +887,33 @@ function isValidIP(ip, version) {
834
887
  }
835
888
  return false;
836
889
  }
890
+ function isValidJWT(jwt, alg) {
891
+ if (!jwtRegex.test(jwt))
892
+ return false;
893
+ try {
894
+ const [header] = jwt.split(".");
895
+ const base64 = header.replace(/-/g, "+").replace(/_/g, "/").padEnd(header.length + (4 - header.length % 4) % 4, "=");
896
+ const decoded = JSON.parse(atob(base64));
897
+ if (typeof decoded !== "object" || decoded === null)
898
+ return false;
899
+ if (!decoded.typ || !decoded.alg)
900
+ return false;
901
+ if (alg && decoded.alg !== alg)
902
+ return false;
903
+ return true;
904
+ } catch (_a) {
905
+ return false;
906
+ }
907
+ }
908
+ function isValidCidr(ip, version) {
909
+ if ((version === "v4" || !version) && ipv4CidrRegex.test(ip)) {
910
+ return true;
911
+ }
912
+ if ((version === "v6" || !version) && ipv6CidrRegex.test(ip)) {
913
+ return true;
914
+ }
915
+ return false;
916
+ }
837
917
  var ZodString = class _ZodString extends ZodType {
838
918
  _parse(input) {
839
919
  if (this._def.coerce) {
@@ -1090,6 +1170,26 @@ var ZodString = class _ZodString extends ZodType {
1090
1170
  });
1091
1171
  status.dirty();
1092
1172
  }
1173
+ } else if (check.kind === "jwt") {
1174
+ if (!isValidJWT(input.data, check.alg)) {
1175
+ ctx = this._getOrReturnCtx(input, ctx);
1176
+ addIssueToContext(ctx, {
1177
+ validation: "jwt",
1178
+ code: ZodIssueCode.invalid_string,
1179
+ message: check.message
1180
+ });
1181
+ status.dirty();
1182
+ }
1183
+ } else if (check.kind === "cidr") {
1184
+ if (!isValidCidr(input.data, check.version)) {
1185
+ ctx = this._getOrReturnCtx(input, ctx);
1186
+ addIssueToContext(ctx, {
1187
+ validation: "cidr",
1188
+ code: ZodIssueCode.invalid_string,
1189
+ message: check.message
1190
+ });
1191
+ status.dirty();
1192
+ }
1093
1193
  } else if (check.kind === "base64") {
1094
1194
  if (!base64Regex.test(input.data)) {
1095
1195
  ctx = this._getOrReturnCtx(input, ctx);
@@ -1100,6 +1200,16 @@ var ZodString = class _ZodString extends ZodType {
1100
1200
  });
1101
1201
  status.dirty();
1102
1202
  }
1203
+ } else if (check.kind === "base64url") {
1204
+ if (!base64urlRegex.test(input.data)) {
1205
+ ctx = this._getOrReturnCtx(input, ctx);
1206
+ addIssueToContext(ctx, {
1207
+ validation: "base64url",
1208
+ code: ZodIssueCode.invalid_string,
1209
+ message: check.message
1210
+ });
1211
+ status.dirty();
1212
+ }
1103
1213
  } else {
1104
1214
  util.assertNever(check);
1105
1215
  }
@@ -1146,9 +1256,21 @@ var ZodString = class _ZodString extends ZodType {
1146
1256
  base64(message) {
1147
1257
  return this._addCheck({ kind: "base64", ...errorUtil.errToObj(message) });
1148
1258
  }
1259
+ base64url(message) {
1260
+ return this._addCheck({
1261
+ kind: "base64url",
1262
+ ...errorUtil.errToObj(message)
1263
+ });
1264
+ }
1265
+ jwt(options) {
1266
+ return this._addCheck({ kind: "jwt", ...errorUtil.errToObj(options) });
1267
+ }
1149
1268
  ip(options) {
1150
1269
  return this._addCheck({ kind: "ip", ...errorUtil.errToObj(options) });
1151
1270
  }
1271
+ cidr(options) {
1272
+ return this._addCheck({ kind: "cidr", ...errorUtil.errToObj(options) });
1273
+ }
1152
1274
  datetime(options) {
1153
1275
  var _a, _b;
1154
1276
  if (typeof options === "string") {
@@ -1239,8 +1361,7 @@ var ZodString = class _ZodString extends ZodType {
1239
1361
  });
1240
1362
  }
1241
1363
  /**
1242
- * @deprecated Use z.string().min(1) instead.
1243
- * @see {@link ZodString.min}
1364
+ * Equivalent to `.min(1)`
1244
1365
  */
1245
1366
  nonempty(message) {
1246
1367
  return this.min(1, errorUtil.errToObj(message));
@@ -1302,9 +1423,15 @@ var ZodString = class _ZodString extends ZodType {
1302
1423
  get isIP() {
1303
1424
  return !!this._def.checks.find((ch) => ch.kind === "ip");
1304
1425
  }
1426
+ get isCIDR() {
1427
+ return !!this._def.checks.find((ch) => ch.kind === "cidr");
1428
+ }
1305
1429
  get isBase64() {
1306
1430
  return !!this._def.checks.find((ch) => ch.kind === "base64");
1307
1431
  }
1432
+ get isBase64url() {
1433
+ return !!this._def.checks.find((ch) => ch.kind === "base64url");
1434
+ }
1308
1435
  get minLength() {
1309
1436
  let min = null;
1310
1437
  for (const ch of this._def.checks) {
@@ -1582,17 +1709,15 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
1582
1709
  }
1583
1710
  _parse(input) {
1584
1711
  if (this._def.coerce) {
1585
- input.data = BigInt(input.data);
1712
+ try {
1713
+ input.data = BigInt(input.data);
1714
+ } catch (_a) {
1715
+ return this._getInvalidInput(input);
1716
+ }
1586
1717
  }
1587
1718
  const parsedType = this._getType(input);
1588
1719
  if (parsedType !== ZodParsedType.bigint) {
1589
- const ctx2 = this._getOrReturnCtx(input);
1590
- addIssueToContext(ctx2, {
1591
- code: ZodIssueCode.invalid_type,
1592
- expected: ZodParsedType.bigint,
1593
- received: ctx2.parsedType
1594
- });
1595
- return INVALID;
1720
+ return this._getInvalidInput(input);
1596
1721
  }
1597
1722
  let ctx = void 0;
1598
1723
  const status = new ParseStatus();
@@ -1639,6 +1764,15 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
1639
1764
  }
1640
1765
  return { status: status.value, value: input.data };
1641
1766
  }
1767
+ _getInvalidInput(input) {
1768
+ const ctx = this._getOrReturnCtx(input);
1769
+ addIssueToContext(ctx, {
1770
+ code: ZodIssueCode.invalid_type,
1771
+ expected: ZodParsedType.bigint,
1772
+ received: ctx.parsedType
1773
+ });
1774
+ return INVALID;
1775
+ }
1642
1776
  gte(value, message) {
1643
1777
  return this.setLimit("min", value, true, errorUtil.toString(message));
1644
1778
  }
@@ -3917,6 +4051,12 @@ function zodToJsonSchema(schema, options) {
3917
4051
  case "ip":
3918
4052
  json.format = Format.IPv4;
3919
4053
  break;
4054
+ case "jwt":
4055
+ json.pattern = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$";
4056
+ break;
4057
+ case "base64url":
4058
+ json.pattern = "^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$";
4059
+ break;
3920
4060
  default: {
3921
4061
  const _expect = check.kind;
3922
4062
  }
@@ -4210,7 +4350,7 @@ function extractJSONSchema(schema, check, matches = []) {
4210
4350
  }
4211
4351
 
4212
4352
  // src/generator.ts
4213
- function generateOpenAPI(opts, options) {
4353
+ async function generateOpenAPI(opts, options) {
4214
4354
  const throwOnMissingTagDefinition = options?.throwOnMissingTagDefinition ?? false;
4215
4355
  const ignoreUndefinedPathProcedures = options?.ignoreUndefinedPathProcedures ?? false;
4216
4356
  const builder = new OpenApiBuilder({
@@ -4218,197 +4358,212 @@ function generateOpenAPI(opts, options) {
4218
4358
  openapi: "3.1.0"
4219
4359
  });
4220
4360
  const rootTags = opts.tags?.map((tag) => tag.name) ?? [];
4221
- const router = toContractRouter(opts.router);
4222
- eachContractRouterLeaf(router, (procedure, path_) => {
4223
- const internal = procedure.zz$cp;
4224
- if (ignoreUndefinedPathProcedures && internal.path === void 0) {
4225
- return;
4226
- }
4227
- const path = internal.path ?? `/${path_.map(encodeURIComponent).join("/")}`;
4228
- const method = internal.method ?? "POST";
4229
- let inputSchema = internal.InputSchema ? zodToJsonSchema(internal.InputSchema, { mode: "input" }) : {};
4230
- const outputSchema = internal.OutputSchema ? zodToJsonSchema(internal.OutputSchema, { mode: "output" }) : {};
4231
- const params = (() => {
4232
- const names = path.match(/\{([^}]+)\}/g);
4233
- if (!names || !names.length) {
4234
- return void 0;
4361
+ const pending = [{
4362
+ path: [],
4363
+ router: opts.router
4364
+ }];
4365
+ for (const item of pending) {
4366
+ const lazies = eachContractProcedureLeaf(item, ({ contract, path }) => {
4367
+ if (!isContractProcedure(contract)) {
4368
+ return;
4235
4369
  }
4236
- if (typeof inputSchema !== "object" || inputSchema.type !== "object") {
4237
- throw new Error(
4238
- `When path has parameters, input schema must be an object [${path_.join(".")}]`
4239
- );
4370
+ const internal = contract.zz$cp;
4371
+ if (ignoreUndefinedPathProcedures && internal.path === void 0) {
4372
+ return;
4240
4373
  }
4241
- return names.map((raw) => raw.slice(1, -1)).map((name) => {
4242
- let schema = inputSchema.properties?.[name];
4243
- const required = inputSchema.required?.includes(name);
4244
- if (schema === void 0) {
4245
- throw new Error(
4246
- `Parameter ${name} is missing in input schema [${path_.join(".")}]`
4247
- );
4374
+ const httpPath = internal.path ?? `/${path.map(encodeURIComponent).join("/")}`;
4375
+ const method = internal.method ?? "POST";
4376
+ let inputSchema = internal.InputSchema ? zodToJsonSchema(internal.InputSchema, { mode: "input" }) : {};
4377
+ const outputSchema = internal.OutputSchema ? zodToJsonSchema(internal.OutputSchema, { mode: "output" }) : {};
4378
+ const params = (() => {
4379
+ const names = httpPath.match(/\{([^}]+)\}/g);
4380
+ if (!names || !names.length) {
4381
+ return void 0;
4248
4382
  }
4249
- if (!required) {
4383
+ if (typeof inputSchema !== "object" || inputSchema.type !== "object") {
4250
4384
  throw new Error(
4251
- `Parameter ${name} must be required in input schema [${path_.join(".")}]`
4385
+ `When path has parameters, input schema must be an object [${path.join(".")}]`
4252
4386
  );
4253
4387
  }
4254
- const examples = inputSchema.examples?.filter((example) => {
4255
- return isPlainObject(example) && name in example;
4256
- }).map((example) => {
4257
- return example[name];
4258
- });
4259
- schema = {
4260
- examples: examples?.length ? examples : void 0,
4261
- ...schema === true ? {} : schema === false ? UNSUPPORTED_JSON_SCHEMA : schema
4262
- };
4263
- inputSchema = {
4264
- ...inputSchema,
4265
- properties: inputSchema.properties ? Object.entries(inputSchema.properties).reduce(
4266
- (acc, [key, value]) => {
4267
- if (key !== name) {
4268
- acc[key] = value;
4269
- }
4270
- return acc;
4271
- },
4272
- {}
4273
- ) : void 0,
4274
- required: inputSchema.required?.filter((v) => v !== name),
4275
- examples: inputSchema.examples?.map((example) => {
4276
- if (!isPlainObject(example))
4277
- return example;
4278
- return Object.entries(example).reduce(
4279
- (acc, [key, value]) => {
4280
- if (key !== name) {
4281
- acc[key] = value;
4282
- }
4283
- return acc;
4284
- },
4285
- {}
4388
+ return names.map((raw) => raw.slice(1, -1)).map((name) => {
4389
+ let schema = inputSchema.properties?.[name];
4390
+ const required = inputSchema.required?.includes(name);
4391
+ if (schema === void 0) {
4392
+ throw new Error(
4393
+ `Parameter ${name} is missing in input schema [${path.join(".")}]`
4286
4394
  );
4287
- })
4288
- };
4289
- return {
4290
- name,
4291
- in: "path",
4292
- required: true,
4293
- schema,
4294
- example: internal.inputExample?.[name]
4295
- };
4296
- });
4297
- })();
4298
- const query = (() => {
4299
- if (method !== "GET" || Object.keys(inputSchema).length === 0) {
4300
- return void 0;
4301
- }
4302
- if (typeof inputSchema !== "object" || inputSchema.type !== "object") {
4303
- throw new Error(
4304
- `When method is GET, input schema must be an object [${path_.join(".")}]`
4305
- );
4306
- }
4307
- return Object.entries(inputSchema.properties ?? {}).map(
4308
- ([name, schema]) => {
4395
+ }
4396
+ if (!required) {
4397
+ throw new Error(
4398
+ `Parameter ${name} must be required in input schema [${path.join(".")}]`
4399
+ );
4400
+ }
4309
4401
  const examples = inputSchema.examples?.filter((example) => {
4310
4402
  return isPlainObject(example) && name in example;
4311
4403
  }).map((example) => {
4312
4404
  return example[name];
4313
4405
  });
4314
- const schema_ = {
4406
+ schema = {
4315
4407
  examples: examples?.length ? examples : void 0,
4316
4408
  ...schema === true ? {} : schema === false ? UNSUPPORTED_JSON_SCHEMA : schema
4317
4409
  };
4410
+ inputSchema = {
4411
+ ...inputSchema,
4412
+ properties: inputSchema.properties ? Object.entries(inputSchema.properties).reduce(
4413
+ (acc, [key, value]) => {
4414
+ if (key !== name) {
4415
+ acc[key] = value;
4416
+ }
4417
+ return acc;
4418
+ },
4419
+ {}
4420
+ ) : void 0,
4421
+ required: inputSchema.required?.filter((v) => v !== name),
4422
+ examples: inputSchema.examples?.map((example) => {
4423
+ if (!isPlainObject(example))
4424
+ return example;
4425
+ return Object.entries(example).reduce(
4426
+ (acc, [key, value]) => {
4427
+ if (key !== name) {
4428
+ acc[key] = value;
4429
+ }
4430
+ return acc;
4431
+ },
4432
+ {}
4433
+ );
4434
+ })
4435
+ };
4318
4436
  return {
4319
4437
  name,
4320
- in: "query",
4321
- style: "deepObject",
4322
- required: inputSchema?.required?.includes(name) ?? false,
4323
- schema: schema_,
4438
+ in: "path",
4439
+ required: true,
4440
+ schema,
4324
4441
  example: internal.inputExample?.[name]
4325
4442
  };
4443
+ });
4444
+ })();
4445
+ const query = (() => {
4446
+ if (method !== "GET" || Object.keys(inputSchema).length === 0) {
4447
+ return void 0;
4326
4448
  }
4327
- );
4328
- })();
4329
- const parameters = [...params ?? [], ...query ?? []];
4330
- const requestBody = (() => {
4331
- if (method === "GET") {
4332
- return void 0;
4333
- }
4334
- const { schema, matches } = extractJSONSchema(inputSchema, isFileSchema);
4335
- const files = matches;
4336
- const isStillHasFileSchema = findDeepMatches(isFileSchema, schema).values.length > 0;
4337
- if (files.length) {
4338
- parameters.push({
4339
- name: "content-disposition",
4340
- in: "header",
4341
- required: schema === void 0,
4342
- schema: {
4343
- type: "string",
4344
- pattern: "filename",
4345
- example: 'filename="file.png"',
4346
- description: "To define the file name. Required when the request body is a file."
4449
+ if (typeof inputSchema !== "object" || inputSchema.type !== "object") {
4450
+ throw new Error(
4451
+ `When method is GET, input schema must be an object [${path.join(".")}]`
4452
+ );
4453
+ }
4454
+ return Object.entries(inputSchema.properties ?? {}).map(
4455
+ ([name, schema]) => {
4456
+ const examples = inputSchema.examples?.filter((example) => {
4457
+ return isPlainObject(example) && name in example;
4458
+ }).map((example) => {
4459
+ return example[name];
4460
+ });
4461
+ const schema_ = {
4462
+ examples: examples?.length ? examples : void 0,
4463
+ ...schema === true ? {} : schema === false ? UNSUPPORTED_JSON_SCHEMA : schema
4464
+ };
4465
+ return {
4466
+ name,
4467
+ in: "query",
4468
+ style: "deepObject",
4469
+ required: inputSchema?.required?.includes(name) ?? false,
4470
+ schema: schema_,
4471
+ example: internal.inputExample?.[name]
4472
+ };
4347
4473
  }
4348
- });
4349
- }
4350
- const content = {};
4351
- for (const file of files) {
4352
- content[file.contentMediaType] = {
4353
- schema: file
4354
- };
4355
- }
4356
- if (schema !== void 0) {
4357
- content[isStillHasFileSchema ? "multipart/form-data" : "application/json"] = {
4358
- schema,
4359
- example: internal.inputExample
4360
- };
4361
- }
4362
- return {
4363
- required: Boolean(internal.InputSchema?.isOptional()),
4364
- content
4365
- };
4366
- })();
4367
- const successResponse = (() => {
4368
- const { schema, matches } = extractJSONSchema(outputSchema, isFileSchema);
4369
- const files = matches;
4370
- const isStillHasFileSchema = findDeepMatches(isFileSchema, schema).values.length > 0;
4371
- const content = {};
4372
- for (const file of files) {
4373
- content[file.contentMediaType] = {
4374
- schema: file
4474
+ );
4475
+ })();
4476
+ const parameters = [...params ?? [], ...query ?? []];
4477
+ const requestBody = (() => {
4478
+ if (method === "GET") {
4479
+ return void 0;
4480
+ }
4481
+ const { schema, matches } = extractJSONSchema(inputSchema, isFileSchema);
4482
+ const files = matches;
4483
+ const isStillHasFileSchema = findDeepMatches(isFileSchema, schema).values.length > 0;
4484
+ if (files.length) {
4485
+ parameters.push({
4486
+ name: "content-disposition",
4487
+ in: "header",
4488
+ required: schema === void 0,
4489
+ schema: {
4490
+ type: "string",
4491
+ pattern: "filename",
4492
+ example: 'filename="file.png"',
4493
+ description: "To define the file name. Required when the request body is a file."
4494
+ }
4495
+ });
4496
+ }
4497
+ const content = {};
4498
+ for (const file of files) {
4499
+ content[file.contentMediaType] = {
4500
+ schema: file
4501
+ };
4502
+ }
4503
+ if (schema !== void 0) {
4504
+ content[isStillHasFileSchema ? "multipart/form-data" : "application/json"] = {
4505
+ schema,
4506
+ example: internal.inputExample
4507
+ };
4508
+ }
4509
+ return {
4510
+ required: Boolean(internal.InputSchema?.isOptional()),
4511
+ content
4375
4512
  };
4376
- }
4377
- if (schema !== void 0) {
4378
- content[isStillHasFileSchema ? "multipart/form-data" : "application/json"] = {
4379
- schema,
4380
- example: internal.outputExample
4513
+ })();
4514
+ const successResponse = (() => {
4515
+ const { schema, matches } = extractJSONSchema(outputSchema, isFileSchema);
4516
+ const files = matches;
4517
+ const isStillHasFileSchema = findDeepMatches(isFileSchema, schema).values.length > 0;
4518
+ const content = {};
4519
+ for (const file of files) {
4520
+ content[file.contentMediaType] = {
4521
+ schema: file
4522
+ };
4523
+ }
4524
+ if (schema !== void 0) {
4525
+ content[isStillHasFileSchema ? "multipart/form-data" : "application/json"] = {
4526
+ schema,
4527
+ example: internal.outputExample
4528
+ };
4529
+ }
4530
+ return {
4531
+ description: "OK",
4532
+ content
4381
4533
  };
4534
+ })();
4535
+ if (throwOnMissingTagDefinition && internal.tags) {
4536
+ const missingTag = internal.tags.find((tag) => !rootTags.includes(tag));
4537
+ if (missingTag !== void 0) {
4538
+ throw new Error(
4539
+ `Tag "${missingTag}" is missing definition. Please define it in OpenAPI root tags object. [${path.join(".")}]`
4540
+ );
4541
+ }
4382
4542
  }
4383
- return {
4384
- description: "OK",
4385
- content
4543
+ const operation = {
4544
+ summary: internal.summary,
4545
+ description: internal.description,
4546
+ deprecated: internal.deprecated,
4547
+ tags: internal.tags,
4548
+ operationId: path.join("."),
4549
+ parameters: parameters.length ? parameters : void 0,
4550
+ requestBody,
4551
+ responses: {
4552
+ 200: successResponse
4553
+ }
4386
4554
  };
4387
- })();
4388
- if (throwOnMissingTagDefinition && internal.tags) {
4389
- const missingTag = internal.tags.find((tag) => !rootTags.includes(tag));
4390
- if (missingTag !== void 0) {
4391
- throw new Error(
4392
- `Tag "${missingTag}" is missing definition. Please define it in OpenAPI root tags object. [${path_.join(".")}]`
4393
- );
4394
- }
4395
- }
4396
- const operation = {
4397
- summary: internal.summary,
4398
- description: internal.description,
4399
- deprecated: internal.deprecated,
4400
- tags: internal.tags,
4401
- operationId: path_.join("."),
4402
- parameters: parameters.length ? parameters : void 0,
4403
- requestBody,
4404
- responses: {
4405
- 200: successResponse
4406
- }
4407
- };
4408
- builder.addPath(path, {
4409
- [method.toLocaleLowerCase()]: operation
4555
+ builder.addPath(httpPath, {
4556
+ [method.toLocaleLowerCase()]: operation
4557
+ });
4410
4558
  });
4411
- });
4559
+ for (const lazy of lazies) {
4560
+ const router = (await lazy.lazy[LAZY_LOADER_SYMBOL]()).default;
4561
+ pending.push({
4562
+ path: lazy.path,
4563
+ router
4564
+ });
4565
+ }
4566
+ }
4412
4567
  return preSerialize(builder.getSpec());
4413
4568
  }
4414
4569
  function isFileSchema(schema) {
@@ -1,13 +1,13 @@
1
1
  import type { HTTPPath } from '@orpc/contract';
2
+ import type { ANY_LAZY_PROCEDURE, ANY_PROCEDURE, Router } from '@orpc/server';
2
3
  import type { FetchHandler } from '@orpc/server/fetch';
3
4
  import type { Router as HonoRouter } from 'hono/router';
4
- import { type Procedure, type Router } from '@orpc/server';
5
- export type ResolveRouter = (router: Router<any>, method: string, pathname: string) => {
5
+ export type ResolveRouter = (router: Router<any>, method: string, pathname: string) => Promise<{
6
6
  path: string[];
7
- procedure: Procedure<any, any, any, any, any>;
7
+ procedure: ANY_PROCEDURE | ANY_LAZY_PROCEDURE;
8
8
  params: Record<string, string>;
9
- } | undefined;
10
- type Routing = HonoRouter<[string[], Procedure<any, any, any, any, any>]>;
9
+ } | undefined>;
10
+ type Routing = HonoRouter<string[]>;
11
11
  export declare function createOpenAPIHandler(createHonoRouter: () => Routing): FetchHandler;
12
12
  export declare function createResolveRouter(createHonoRouter: () => Routing): ResolveRouter;
13
13
  export declare function openAPIPathToRouterPath(path: HTTPPath): string;
@@ -20,5 +20,5 @@ export interface GenerateOpenAPIOptions {
20
20
  }
21
21
  export declare function generateOpenAPI(opts: {
22
22
  router: ContractRouter | Router<any>;
23
- } & Omit<OpenAPIObject, 'openapi'>, options?: GenerateOpenAPIOptions): OpenAPIObject;
23
+ } & Omit<OpenAPIObject, 'openapi'>, options?: GenerateOpenAPIOptions): Promise<OpenAPIObject>;
24
24
  //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1,16 @@
1
+ import type { ContractProcedure, ContractRouter, WELL_CONTRACT_PROCEDURE } from '@orpc/contract';
2
+ import type { ANY_LAZY_PROCEDURE, ANY_PROCEDURE, Lazy, Router } from '@orpc/server';
3
+ export interface EachLeafOptions {
4
+ router: ANY_PROCEDURE | Router<any> | ContractRouter | ContractProcedure<any, any>;
5
+ path: string[];
6
+ }
7
+ export interface EachLeafCallbackOptions {
8
+ contract: WELL_CONTRACT_PROCEDURE;
9
+ path: string[];
10
+ }
11
+ export interface EachContractLeafResultItem {
12
+ lazy: ANY_LAZY_PROCEDURE | Lazy<Router<any>>;
13
+ path: string[];
14
+ }
15
+ export declare function eachContractProcedureLeaf(options: EachLeafOptions, callback: (options: EachLeafCallbackOptions) => void, result?: EachContractLeafResultItem[], isCurrentRouterContract?: boolean): EachContractLeafResultItem[];
16
+ //# sourceMappingURL=utils.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/openapi",
3
3
  "type": "module",
4
- "version": "0.0.0-next.55d0b4f",
4
+ "version": "0.0.0-next.571d5d7",
5
5
  "license": "MIT",
6
6
  "homepage": "https://orpc.unnoq.com",
7
7
  "repository": {
@@ -37,16 +37,16 @@
37
37
  "escape-string-regexp": "^5.0.0",
38
38
  "json-schema-typed": "^8.0.1",
39
39
  "openapi3-ts": "^4.4.0",
40
- "@orpc/contract": "0.0.0-next.55d0b4f",
41
- "@orpc/server": "0.0.0-next.55d0b4f",
42
- "@orpc/shared": "0.0.0-next.55d0b4f",
43
- "@orpc/transformer": "0.0.0-next.55d0b4f",
44
- "@orpc/zod": "0.0.0-next.55d0b4f"
40
+ "@orpc/contract": "0.0.0-next.571d5d7",
41
+ "@orpc/server": "0.0.0-next.571d5d7",
42
+ "@orpc/shared": "0.0.0-next.571d5d7",
43
+ "@orpc/transformer": "0.0.0-next.571d5d7",
44
+ "@orpc/zod": "0.0.0-next.571d5d7"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@readme/openapi-parser": "^2.6.0",
48
48
  "hono": "^4.6.12",
49
- "zod": "^3.23.8"
49
+ "zod": "^3.24.1"
50
50
  },
51
51
  "scripts": {
52
52
  "build": "tsup --clean --sourcemap --entry.index=src/index.ts --entry.fetch=src/fetch/index.ts --format=esm --onSuccess='tsc -b --noCheck'",