@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.
- package/dist/chunk-KZIT2WCV.js +49 -0
- package/dist/fetch.js +78 -39
- package/dist/index.js +368 -213
- package/dist/src/fetch/base-handler.d.ts +5 -5
- package/dist/src/generator.d.ts +1 -1
- package/dist/src/utils.d.ts +16 -0
- package/package.json +7 -7
|
@@ -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
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
routingCache.
|
|
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]
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 {
|
|
3
|
-
import {
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
}
|
|
4227
|
-
|
|
4228
|
-
|
|
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
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
);
|
|
4370
|
+
const internal = contract.zz$cp;
|
|
4371
|
+
if (ignoreUndefinedPathProcedures && internal.path === void 0) {
|
|
4372
|
+
return;
|
|
4240
4373
|
}
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
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 (
|
|
4383
|
+
if (typeof inputSchema !== "object" || inputSchema.type !== "object") {
|
|
4250
4384
|
throw new Error(
|
|
4251
|
-
`
|
|
4385
|
+
`When path has parameters, input schema must be an object [${path.join(".")}]`
|
|
4252
4386
|
);
|
|
4253
4387
|
}
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
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
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
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
|
-
|
|
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: "
|
|
4321
|
-
|
|
4322
|
-
|
|
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
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
return
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
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
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
}
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
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
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
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
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
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
|
-
|
|
4389
|
-
|
|
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
|
-
|
|
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:
|
|
7
|
+
procedure: ANY_PROCEDURE | ANY_LAZY_PROCEDURE;
|
|
8
8
|
params: Record<string, string>;
|
|
9
|
-
} | undefined
|
|
10
|
-
type Routing = HonoRouter<
|
|
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;
|
package/dist/src/generator.d.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
41
|
-
"@orpc/server": "0.0.0-next.
|
|
42
|
-
"@orpc/shared": "0.0.0-next.
|
|
43
|
-
"@orpc/transformer": "0.0.0-next.
|
|
44
|
-
"@orpc/zod": "0.0.0-next.
|
|
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.
|
|
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'",
|