@orpc/openapi 0.34.0 → 0.35.0
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-BHJYKXQL.js +52 -0
- package/dist/chunk-HQ34JZI7.js +32 -0
- package/dist/chunk-M5HOHBLW.js +432 -0
- package/dist/fetch.js +5 -30
- package/dist/hono.js +5 -30
- package/dist/index.js +6 -6
- package/dist/next.js +5 -30
- package/dist/node.js +18 -34
- package/dist/src/adapters/fetch/index.d.ts +0 -8
- package/dist/src/adapters/fetch/openapi-handler.d.ts +6 -28
- package/dist/src/adapters/node/index.d.ts +0 -3
- package/dist/src/adapters/node/openapi-handler.d.ts +7 -8
- package/dist/src/adapters/standard/index.d.ts +7 -0
- package/dist/src/adapters/standard/openapi-codec.d.ts +18 -0
- package/dist/src/adapters/standard/openapi-handler.d.ts +7 -0
- package/dist/src/adapters/standard/openapi-matcher.d.ts +20 -0
- package/dist/src/adapters/standard/openapi-serializer.d.ts +11 -0
- package/dist/src/openapi-generator.d.ts +1 -1
- package/dist/src/utils.d.ts +1 -16
- package/dist/standard.js +16 -0
- package/package.json +10 -5
- package/dist/chunk-Q2LSK6YZ.js +0 -102
- package/dist/chunk-SOVQ5ARD.js +0 -650
- package/dist/chunk-VFGNQS5W.js +0 -25
- package/dist/src/adapters/fetch/input-structure-compact.d.ts +0 -6
- package/dist/src/adapters/fetch/input-structure-detailed.d.ts +0 -11
- package/dist/src/adapters/fetch/openapi-handler-server.d.ts +0 -7
- package/dist/src/adapters/fetch/openapi-handler-serverless.d.ts +0 -7
- package/dist/src/adapters/fetch/openapi-payload-codec.d.ts +0 -15
- package/dist/src/adapters/fetch/openapi-procedure-matcher.d.ts +0 -19
- package/dist/src/adapters/node/openapi-handler-server.d.ts +0 -7
- package/dist/src/adapters/node/openapi-handler-serverless.d.ts +0 -7
- package/dist/src/adapters/node/types.d.ts +0 -2
- /package/dist/src/adapters/{fetch → standard}/bracket-notation.d.ts +0 -0
- /package/dist/src/adapters/{fetch → standard}/schema-coercer.d.ts +0 -0
package/dist/chunk-SOVQ5ARD.js
DELETED
@@ -1,650 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
JSONSerializer,
|
3
|
-
forEachContractProcedure,
|
4
|
-
standardizeHTTPPath
|
5
|
-
} from "./chunk-Q2LSK6YZ.js";
|
6
|
-
|
7
|
-
// src/adapters/fetch/bracket-notation.ts
|
8
|
-
import { isPlainObject } from "@orpc/shared";
|
9
|
-
function serialize(payload, parentKey = "") {
|
10
|
-
if (!Array.isArray(payload) && !isPlainObject(payload))
|
11
|
-
return [["", payload]];
|
12
|
-
const result = [];
|
13
|
-
function helper(value, path) {
|
14
|
-
if (Array.isArray(value)) {
|
15
|
-
value.forEach((item, index) => {
|
16
|
-
helper(item, [...path, String(index)]);
|
17
|
-
});
|
18
|
-
} else if (isPlainObject(value)) {
|
19
|
-
for (const [key, val] of Object.entries(value)) {
|
20
|
-
helper(val, [...path, key]);
|
21
|
-
}
|
22
|
-
} else {
|
23
|
-
result.push([stringifyPath(path), value]);
|
24
|
-
}
|
25
|
-
}
|
26
|
-
helper(payload, parentKey ? [parentKey] : []);
|
27
|
-
return result;
|
28
|
-
}
|
29
|
-
function deserialize(entities) {
|
30
|
-
if (entities.length === 0) {
|
31
|
-
return void 0;
|
32
|
-
}
|
33
|
-
const isRootArray = entities.every(([path]) => path === "");
|
34
|
-
const result = isRootArray ? [] : {};
|
35
|
-
const arrayPushPaths = /* @__PURE__ */ new Set();
|
36
|
-
for (const [path, _] of entities) {
|
37
|
-
const segments = parsePath(path);
|
38
|
-
const base = segments.slice(0, -1).join(".");
|
39
|
-
const last = segments[segments.length - 1];
|
40
|
-
if (last === "") {
|
41
|
-
arrayPushPaths.add(base);
|
42
|
-
} else {
|
43
|
-
arrayPushPaths.delete(base);
|
44
|
-
}
|
45
|
-
}
|
46
|
-
function setValue(obj, segments, value, fullPath) {
|
47
|
-
const [first, ...rest_] = segments;
|
48
|
-
if (Array.isArray(obj) && first === "") {
|
49
|
-
;
|
50
|
-
obj.push(value);
|
51
|
-
return;
|
52
|
-
}
|
53
|
-
const objAsRecord = obj;
|
54
|
-
if (rest_.length === 0) {
|
55
|
-
objAsRecord[first] = value;
|
56
|
-
return;
|
57
|
-
}
|
58
|
-
const rest = rest_;
|
59
|
-
if (rest[0] === "") {
|
60
|
-
const pathToCheck = segments.slice(0, -1).join(".");
|
61
|
-
if (rest.length === 1 && arrayPushPaths.has(pathToCheck)) {
|
62
|
-
if (!(first in objAsRecord)) {
|
63
|
-
objAsRecord[first] = [];
|
64
|
-
}
|
65
|
-
if (Array.isArray(objAsRecord[first])) {
|
66
|
-
;
|
67
|
-
objAsRecord[first].push(value);
|
68
|
-
return;
|
69
|
-
}
|
70
|
-
}
|
71
|
-
if (!(first in objAsRecord)) {
|
72
|
-
objAsRecord[first] = {};
|
73
|
-
}
|
74
|
-
const target = objAsRecord[first];
|
75
|
-
target[""] = value;
|
76
|
-
return;
|
77
|
-
}
|
78
|
-
if (!(first in objAsRecord)) {
|
79
|
-
objAsRecord[first] = {};
|
80
|
-
}
|
81
|
-
setValue(
|
82
|
-
objAsRecord[first],
|
83
|
-
rest,
|
84
|
-
value,
|
85
|
-
fullPath
|
86
|
-
);
|
87
|
-
}
|
88
|
-
for (const [path, value] of entities) {
|
89
|
-
const segments = parsePath(path);
|
90
|
-
setValue(result, segments, value, path);
|
91
|
-
}
|
92
|
-
return result;
|
93
|
-
}
|
94
|
-
function escapeSegment(segment) {
|
95
|
-
return segment.replace(/[\\[\]]/g, (match) => {
|
96
|
-
switch (match) {
|
97
|
-
case "\\":
|
98
|
-
return "\\\\";
|
99
|
-
case "[":
|
100
|
-
return "\\[";
|
101
|
-
case "]":
|
102
|
-
return "\\]";
|
103
|
-
default:
|
104
|
-
return match;
|
105
|
-
}
|
106
|
-
});
|
107
|
-
}
|
108
|
-
function stringifyPath(path) {
|
109
|
-
const [first, ...rest] = path;
|
110
|
-
const firstSegment = escapeSegment(first);
|
111
|
-
const base = first === "" ? "" : firstSegment;
|
112
|
-
return rest.reduce(
|
113
|
-
(result, segment) => `${result}[${escapeSegment(segment)}]`,
|
114
|
-
base
|
115
|
-
);
|
116
|
-
}
|
117
|
-
function parsePath(path) {
|
118
|
-
if (path === "")
|
119
|
-
return [""];
|
120
|
-
const result = [];
|
121
|
-
let currentSegment = "";
|
122
|
-
let inBracket = false;
|
123
|
-
let bracketContent = "";
|
124
|
-
let backslashCount = 0;
|
125
|
-
for (let i = 0; i < path.length; i++) {
|
126
|
-
const char = path[i];
|
127
|
-
if (char === "\\") {
|
128
|
-
backslashCount++;
|
129
|
-
continue;
|
130
|
-
}
|
131
|
-
if (backslashCount > 0) {
|
132
|
-
const literalBackslashes = "\\".repeat(Math.floor(backslashCount / 2));
|
133
|
-
if (char === "[" || char === "]") {
|
134
|
-
if (backslashCount % 2 === 1) {
|
135
|
-
if (inBracket) {
|
136
|
-
bracketContent += literalBackslashes + char;
|
137
|
-
} else {
|
138
|
-
currentSegment += literalBackslashes + char;
|
139
|
-
}
|
140
|
-
} else {
|
141
|
-
if (inBracket) {
|
142
|
-
bracketContent += literalBackslashes;
|
143
|
-
} else {
|
144
|
-
currentSegment += literalBackslashes;
|
145
|
-
}
|
146
|
-
if (char === "[" && !inBracket) {
|
147
|
-
if (currentSegment !== "" || result.length === 0) {
|
148
|
-
result.push(currentSegment);
|
149
|
-
}
|
150
|
-
inBracket = true;
|
151
|
-
bracketContent = "";
|
152
|
-
currentSegment = "";
|
153
|
-
} else if (char === "]" && inBracket) {
|
154
|
-
result.push(bracketContent);
|
155
|
-
inBracket = false;
|
156
|
-
bracketContent = "";
|
157
|
-
} else {
|
158
|
-
if (inBracket) {
|
159
|
-
bracketContent += char;
|
160
|
-
} else {
|
161
|
-
currentSegment += char;
|
162
|
-
}
|
163
|
-
}
|
164
|
-
}
|
165
|
-
} else {
|
166
|
-
const allBackslashes = "\\".repeat(backslashCount);
|
167
|
-
if (inBracket) {
|
168
|
-
bracketContent += allBackslashes + char;
|
169
|
-
} else {
|
170
|
-
currentSegment += allBackslashes + char;
|
171
|
-
}
|
172
|
-
}
|
173
|
-
backslashCount = 0;
|
174
|
-
continue;
|
175
|
-
}
|
176
|
-
if (char === "[" && !inBracket) {
|
177
|
-
if (currentSegment !== "" || result.length === 0) {
|
178
|
-
result.push(currentSegment);
|
179
|
-
}
|
180
|
-
inBracket = true;
|
181
|
-
bracketContent = "";
|
182
|
-
currentSegment = "";
|
183
|
-
continue;
|
184
|
-
}
|
185
|
-
if (char === "]" && inBracket) {
|
186
|
-
result.push(bracketContent);
|
187
|
-
inBracket = false;
|
188
|
-
bracketContent = "";
|
189
|
-
continue;
|
190
|
-
}
|
191
|
-
if (inBracket) {
|
192
|
-
bracketContent += char;
|
193
|
-
} else {
|
194
|
-
currentSegment += char;
|
195
|
-
}
|
196
|
-
}
|
197
|
-
if (backslashCount > 0) {
|
198
|
-
const remainingBackslashes = "\\".repeat(backslashCount);
|
199
|
-
if (inBracket) {
|
200
|
-
bracketContent += remainingBackslashes;
|
201
|
-
} else {
|
202
|
-
currentSegment += remainingBackslashes;
|
203
|
-
}
|
204
|
-
}
|
205
|
-
if (inBracket) {
|
206
|
-
if (currentSegment !== "" || result.length === 0) {
|
207
|
-
result.push(currentSegment);
|
208
|
-
}
|
209
|
-
result.push(`[${bracketContent}`);
|
210
|
-
} else if (currentSegment !== "" || result.length === 0) {
|
211
|
-
result.push(currentSegment);
|
212
|
-
}
|
213
|
-
return result;
|
214
|
-
}
|
215
|
-
|
216
|
-
// src/adapters/fetch/input-structure-compact.ts
|
217
|
-
import { isPlainObject as isPlainObject2 } from "@orpc/shared";
|
218
|
-
var InputStructureCompact = class {
|
219
|
-
build(params, payload) {
|
220
|
-
if (Object.keys(params).length === 0) {
|
221
|
-
return payload;
|
222
|
-
}
|
223
|
-
if (!isPlainObject2(payload)) {
|
224
|
-
return params;
|
225
|
-
}
|
226
|
-
return {
|
227
|
-
...params,
|
228
|
-
...payload
|
229
|
-
};
|
230
|
-
}
|
231
|
-
};
|
232
|
-
|
233
|
-
// src/adapters/fetch/input-structure-detailed.ts
|
234
|
-
var InputStructureDetailed = class {
|
235
|
-
build(params, query, headers, body) {
|
236
|
-
return {
|
237
|
-
params,
|
238
|
-
query,
|
239
|
-
headers,
|
240
|
-
body
|
241
|
-
};
|
242
|
-
}
|
243
|
-
};
|
244
|
-
|
245
|
-
// src/adapters/fetch/openapi-payload-codec.ts
|
246
|
-
import { ORPCError } from "@orpc/server";
|
247
|
-
import { findDeepMatches } from "@orpc/shared";
|
248
|
-
import cd from "content-disposition";
|
249
|
-
import { safeParse } from "fast-content-type-parse";
|
250
|
-
import wcmatch from "wildcard-match";
|
251
|
-
var OpenAPIPayloadCodec = class {
|
252
|
-
constructor(jsonSerializer) {
|
253
|
-
this.jsonSerializer = jsonSerializer;
|
254
|
-
}
|
255
|
-
encode(payload, accept) {
|
256
|
-
const typeMatchers = (accept?.split(",").map(safeParse) ?? [{ type: "*/*" }]).map(({ type }) => wcmatch(type));
|
257
|
-
if (payload instanceof Blob) {
|
258
|
-
const contentType = payload.type || "application/octet-stream";
|
259
|
-
if (typeMatchers.some((isMatch) => isMatch(contentType))) {
|
260
|
-
const headers = new Headers({
|
261
|
-
"Content-Type": contentType
|
262
|
-
});
|
263
|
-
if (payload instanceof File && payload.name) {
|
264
|
-
headers.append("Content-Disposition", cd(payload.name));
|
265
|
-
}
|
266
|
-
return {
|
267
|
-
body: payload,
|
268
|
-
headers
|
269
|
-
};
|
270
|
-
}
|
271
|
-
}
|
272
|
-
const handledPayload = this.jsonSerializer.serialize(payload);
|
273
|
-
const hasBlobs = findDeepMatches((v) => v instanceof Blob, handledPayload).values.length > 0;
|
274
|
-
const isExpectedMultipartFormData = typeMatchers.some(
|
275
|
-
(isMatch) => isMatch("multipart/form-data")
|
276
|
-
);
|
277
|
-
if (hasBlobs && isExpectedMultipartFormData) {
|
278
|
-
return this.encodeAsFormData(handledPayload);
|
279
|
-
}
|
280
|
-
if (typeMatchers.some((isMatch) => isMatch("application/json"))) {
|
281
|
-
return this.encodeAsJSON(handledPayload);
|
282
|
-
}
|
283
|
-
if (typeMatchers.some(
|
284
|
-
(isMatch) => isMatch("application/x-www-form-urlencoded")
|
285
|
-
)) {
|
286
|
-
return this.encodeAsURLSearchParams(handledPayload);
|
287
|
-
}
|
288
|
-
if (isExpectedMultipartFormData) {
|
289
|
-
return this.encodeAsFormData(handledPayload);
|
290
|
-
}
|
291
|
-
throw new ORPCError("NOT_ACCEPTABLE", {
|
292
|
-
message: `Unsupported content-type: ${accept}`
|
293
|
-
});
|
294
|
-
}
|
295
|
-
encodeAsJSON(payload) {
|
296
|
-
if (payload === void 0) {
|
297
|
-
return {
|
298
|
-
body: void 0,
|
299
|
-
headers: new Headers({
|
300
|
-
"content-type": "application/json"
|
301
|
-
})
|
302
|
-
};
|
303
|
-
}
|
304
|
-
return {
|
305
|
-
body: JSON.stringify(payload),
|
306
|
-
headers: new Headers({
|
307
|
-
"content-type": "application/json"
|
308
|
-
})
|
309
|
-
};
|
310
|
-
}
|
311
|
-
encodeAsFormData(payload) {
|
312
|
-
const form = new FormData();
|
313
|
-
for (const [path, value] of serialize(payload)) {
|
314
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
315
|
-
form.append(path, value.toString());
|
316
|
-
} else if (value === null) {
|
317
|
-
form.append(path, "null");
|
318
|
-
} else if (value instanceof Date) {
|
319
|
-
form.append(
|
320
|
-
path,
|
321
|
-
Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString()
|
322
|
-
);
|
323
|
-
} else if (value instanceof Blob) {
|
324
|
-
form.append(path, value);
|
325
|
-
}
|
326
|
-
}
|
327
|
-
return {
|
328
|
-
body: form
|
329
|
-
};
|
330
|
-
}
|
331
|
-
encodeAsURLSearchParams(payload) {
|
332
|
-
const params = new URLSearchParams();
|
333
|
-
for (const [path, value] of serialize(payload)) {
|
334
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
335
|
-
params.append(path, value.toString());
|
336
|
-
} else if (value === null) {
|
337
|
-
params.append(path, "null");
|
338
|
-
} else if (value instanceof Date) {
|
339
|
-
params.append(
|
340
|
-
path,
|
341
|
-
Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString()
|
342
|
-
);
|
343
|
-
}
|
344
|
-
}
|
345
|
-
return {
|
346
|
-
body: params.toString(),
|
347
|
-
headers: new Headers({
|
348
|
-
"content-type": "application/x-www-form-urlencoded"
|
349
|
-
})
|
350
|
-
};
|
351
|
-
}
|
352
|
-
async decode(re) {
|
353
|
-
try {
|
354
|
-
if (re instanceof Headers || re instanceof URLSearchParams || re instanceof FormData) {
|
355
|
-
return deserialize([...re.entries()]);
|
356
|
-
}
|
357
|
-
const contentType = re.headers.get("content-type");
|
358
|
-
const contentDisposition = re.headers.get("content-disposition");
|
359
|
-
const fileName = contentDisposition ? cd.parse(contentDisposition).parameters.filename : void 0;
|
360
|
-
if (fileName) {
|
361
|
-
const blob2 = await re.blob();
|
362
|
-
const file = new File([blob2], fileName, {
|
363
|
-
type: blob2.type
|
364
|
-
});
|
365
|
-
return file;
|
366
|
-
}
|
367
|
-
if (!contentType || contentType.startsWith("application/json")) {
|
368
|
-
if (!re.body) {
|
369
|
-
return void 0;
|
370
|
-
}
|
371
|
-
const text = await re.text();
|
372
|
-
if (!text) {
|
373
|
-
return void 0;
|
374
|
-
}
|
375
|
-
return JSON.parse(text);
|
376
|
-
}
|
377
|
-
if (contentType.startsWith("application/x-www-form-urlencoded")) {
|
378
|
-
const params = new URLSearchParams(await re.text());
|
379
|
-
return this.decode(params);
|
380
|
-
}
|
381
|
-
if (contentType.startsWith("text/")) {
|
382
|
-
const text = await re.text();
|
383
|
-
return text;
|
384
|
-
}
|
385
|
-
if (contentType.startsWith("multipart/form-data")) {
|
386
|
-
const form = await re.formData();
|
387
|
-
return this.decode(form);
|
388
|
-
}
|
389
|
-
const blob = await re.blob();
|
390
|
-
return new File([blob], "blob", {
|
391
|
-
type: blob.type
|
392
|
-
});
|
393
|
-
} catch (e) {
|
394
|
-
throw new ORPCError("BAD_REQUEST", {
|
395
|
-
message: "Cannot parse request/response. Please check the request/response body and Content-Type header.",
|
396
|
-
cause: e
|
397
|
-
});
|
398
|
-
}
|
399
|
-
}
|
400
|
-
};
|
401
|
-
|
402
|
-
// src/adapters/fetch/openapi-procedure-matcher.ts
|
403
|
-
import { fallbackContractConfig } from "@orpc/contract";
|
404
|
-
import { getLazyRouterPrefix, getRouterChild, isProcedure, unlazy } from "@orpc/server";
|
405
|
-
import { mapValues } from "@orpc/shared";
|
406
|
-
var OpenAPIProcedureMatcher = class {
|
407
|
-
constructor(hono, router) {
|
408
|
-
this.hono = hono;
|
409
|
-
this.router = router;
|
410
|
-
this.pendingRouters = [{ path: [], router }];
|
411
|
-
}
|
412
|
-
pendingRouters;
|
413
|
-
async match(method, pathname) {
|
414
|
-
await this.handlePendingRouters(pathname);
|
415
|
-
const [matches, paramStash] = this.hono.match(method, pathname);
|
416
|
-
const [match] = matches.sort((a, b) => {
|
417
|
-
const slashCountA = a[0][0].split("/").length;
|
418
|
-
const slashCountB = b[0][0].split("/").length;
|
419
|
-
if (slashCountA !== slashCountB) {
|
420
|
-
return slashCountB - slashCountA;
|
421
|
-
}
|
422
|
-
const paramsCountA = Object.keys(a[1]).length;
|
423
|
-
const paramsCountB = Object.keys(b[1]).length;
|
424
|
-
return paramsCountA - paramsCountB;
|
425
|
-
});
|
426
|
-
if (!match) {
|
427
|
-
return void 0;
|
428
|
-
}
|
429
|
-
const path = match[0][1];
|
430
|
-
const params = paramStash ? mapValues(
|
431
|
-
match[1],
|
432
|
-
// if paramStash is defined, then match[1] is ParamIndexMap
|
433
|
-
(v) => paramStash[v]
|
434
|
-
) : match[1];
|
435
|
-
const { default: maybeProcedure } = await unlazy(getRouterChild(this.router, ...path));
|
436
|
-
if (!isProcedure(maybeProcedure)) {
|
437
|
-
return void 0;
|
438
|
-
}
|
439
|
-
return {
|
440
|
-
path,
|
441
|
-
procedure: maybeProcedure,
|
442
|
-
params: { ...params }
|
443
|
-
// normalize params from hono
|
444
|
-
};
|
445
|
-
}
|
446
|
-
add(path, router) {
|
447
|
-
const lazies = forEachContractProcedure({ path, router }, ({ path: path2, contract }) => {
|
448
|
-
const method = fallbackContractConfig("defaultMethod", contract["~orpc"].route?.method);
|
449
|
-
const httpPath = contract["~orpc"].route?.path ? this.convertOpenAPIPathToRouterPath(contract["~orpc"].route?.path) : `/${path2.map(encodeURIComponent).join("/")}`;
|
450
|
-
this.hono.add(method, httpPath, [httpPath, path2]);
|
451
|
-
});
|
452
|
-
this.pendingRouters.push(...lazies);
|
453
|
-
}
|
454
|
-
async handlePendingRouters(pathname) {
|
455
|
-
const newPendingLazyRouters = [];
|
456
|
-
for (const item of this.pendingRouters) {
|
457
|
-
const lazyPrefix = getLazyRouterPrefix(item.router);
|
458
|
-
if (lazyPrefix && !pathname.startsWith(lazyPrefix) && !pathname.startsWith(`/${item.path.map(encodeURIComponent).join("/")}`)) {
|
459
|
-
newPendingLazyRouters.push(item);
|
460
|
-
continue;
|
461
|
-
}
|
462
|
-
const { default: router } = await unlazy(item.router);
|
463
|
-
this.add(item.path, router);
|
464
|
-
}
|
465
|
-
this.pendingRouters = newPendingLazyRouters;
|
466
|
-
}
|
467
|
-
convertOpenAPIPathToRouterPath(path) {
|
468
|
-
return standardizeHTTPPath(path).replace(/\{([^}]+)\}/g, ":$1");
|
469
|
-
}
|
470
|
-
};
|
471
|
-
|
472
|
-
// src/adapters/fetch/schema-coercer.ts
|
473
|
-
var CompositeSchemaCoercer = class {
|
474
|
-
constructor(coercers) {
|
475
|
-
this.coercers = coercers;
|
476
|
-
}
|
477
|
-
coerce(schema, value) {
|
478
|
-
let current = value;
|
479
|
-
for (const coercer of this.coercers) {
|
480
|
-
current = coercer.coerce(schema, current);
|
481
|
-
}
|
482
|
-
return current;
|
483
|
-
}
|
484
|
-
};
|
485
|
-
|
486
|
-
// src/adapters/fetch/openapi-handler.ts
|
487
|
-
import { fallbackContractConfig as fallbackContractConfig2 } from "@orpc/contract";
|
488
|
-
import { createProcedureClient, ORPCError as ORPCError2 } from "@orpc/server";
|
489
|
-
import { executeWithHooks, isPlainObject as isPlainObject3, trim } from "@orpc/shared";
|
490
|
-
var OpenAPIHandler = class {
|
491
|
-
constructor(hono, router, options) {
|
492
|
-
this.options = options;
|
493
|
-
const jsonSerializer = options?.jsonSerializer ?? new JSONSerializer();
|
494
|
-
this.procedureMatcher = options?.procedureMatcher ?? new OpenAPIProcedureMatcher(hono, router);
|
495
|
-
this.payloadCodec = options?.payloadCodec ?? new OpenAPIPayloadCodec(jsonSerializer);
|
496
|
-
this.inputStructureCompact = options?.inputBuilderSimple ?? new InputStructureCompact();
|
497
|
-
this.inputStructureDetailed = options?.inputBuilderFull ?? new InputStructureDetailed();
|
498
|
-
this.compositeSchemaCoercer = new CompositeSchemaCoercer(options?.schemaCoercers ?? []);
|
499
|
-
}
|
500
|
-
procedureMatcher;
|
501
|
-
payloadCodec;
|
502
|
-
inputStructureCompact;
|
503
|
-
inputStructureDetailed;
|
504
|
-
compositeSchemaCoercer;
|
505
|
-
async handle(request, ...[options]) {
|
506
|
-
const context = options?.context ?? {};
|
507
|
-
const headers = request.headers;
|
508
|
-
const accept = headers.get("accept") || void 0;
|
509
|
-
const execute = async () => {
|
510
|
-
const url = new URL(request.url);
|
511
|
-
const pathname = `/${trim(url.pathname.replace(options?.prefix ?? "", ""), "/")}`;
|
512
|
-
const query = url.searchParams;
|
513
|
-
const customMethod = request.method === "POST" ? query.get("method")?.toUpperCase() : void 0;
|
514
|
-
const matchedMethod = customMethod || request.method;
|
515
|
-
const matched = await this.procedureMatcher.match(matchedMethod, pathname);
|
516
|
-
if (!matched) {
|
517
|
-
return { matched: false, response: void 0 };
|
518
|
-
}
|
519
|
-
const def = matched.procedure["~orpc"];
|
520
|
-
const input = await this.decodeInput(matched.procedure, matched.params, request);
|
521
|
-
const coercedInput = this.compositeSchemaCoercer.coerce(def.inputSchema, input);
|
522
|
-
const client = createProcedureClient(matched.procedure, {
|
523
|
-
context,
|
524
|
-
path: matched.path
|
525
|
-
});
|
526
|
-
const output = await client(coercedInput, { signal: request.signal });
|
527
|
-
const { body, headers: resHeaders } = this.encodeOutput(matched.procedure, output, accept);
|
528
|
-
const response = new Response(body, {
|
529
|
-
headers: resHeaders,
|
530
|
-
status: fallbackContractConfig2("defaultSuccessStatus", def.route?.successStatus)
|
531
|
-
});
|
532
|
-
return { matched: true, response };
|
533
|
-
};
|
534
|
-
try {
|
535
|
-
return await executeWithHooks({
|
536
|
-
context,
|
537
|
-
execute,
|
538
|
-
input: request,
|
539
|
-
hooks: this.options,
|
540
|
-
meta: {
|
541
|
-
signal: request.signal
|
542
|
-
}
|
543
|
-
});
|
544
|
-
} catch (e) {
|
545
|
-
const error = this.convertToORPCError(e);
|
546
|
-
try {
|
547
|
-
const { body, headers: headers2 } = this.payloadCodec.encode(error.toJSON(), accept);
|
548
|
-
const response = new Response(body, {
|
549
|
-
status: error.status,
|
550
|
-
headers: headers2
|
551
|
-
});
|
552
|
-
return { matched: true, response };
|
553
|
-
} catch (e2) {
|
554
|
-
const error2 = this.convertToORPCError(e2);
|
555
|
-
const { body, headers: headers2 } = this.payloadCodec.encode(error2.toJSON(), void 0);
|
556
|
-
const response = new Response(body, {
|
557
|
-
status: error2.status,
|
558
|
-
headers: headers2
|
559
|
-
});
|
560
|
-
return { matched: true, response };
|
561
|
-
}
|
562
|
-
}
|
563
|
-
}
|
564
|
-
async decodeInput(procedure, params, request) {
|
565
|
-
const inputStructure = fallbackContractConfig2("defaultInputStructure", procedure["~orpc"].route.inputStructure);
|
566
|
-
const url = new URL(request.url);
|
567
|
-
const query = url.searchParams;
|
568
|
-
const headers = request.headers;
|
569
|
-
if (inputStructure === "compact") {
|
570
|
-
return this.inputStructureCompact.build(
|
571
|
-
params,
|
572
|
-
request.method === "GET" ? await this.payloadCodec.decode(query) : await this.payloadCodec.decode(request)
|
573
|
-
);
|
574
|
-
}
|
575
|
-
const decodedQuery = await this.payloadCodec.decode(query);
|
576
|
-
const decodedHeaders = await this.payloadCodec.decode(headers);
|
577
|
-
const decodedBody = await this.payloadCodec.decode(request);
|
578
|
-
return this.inputStructureDetailed.build(params, decodedQuery, decodedHeaders, decodedBody);
|
579
|
-
}
|
580
|
-
encodeOutput(procedure, output, accept) {
|
581
|
-
const outputStructure = fallbackContractConfig2("defaultOutputStructure", procedure["~orpc"].route.outputStructure);
|
582
|
-
if (outputStructure === "compact") {
|
583
|
-
return this.payloadCodec.encode(output, accept);
|
584
|
-
}
|
585
|
-
this.assertDetailedOutput(output);
|
586
|
-
const headers = new Headers();
|
587
|
-
if (output.headers) {
|
588
|
-
for (const [key, value] of Object.entries(output.headers)) {
|
589
|
-
headers.append(key, value);
|
590
|
-
}
|
591
|
-
}
|
592
|
-
const { body, headers: encodedHeaders } = this.payloadCodec.encode(output.body, accept);
|
593
|
-
if (encodedHeaders) {
|
594
|
-
for (const [key, value] of encodedHeaders.entries()) {
|
595
|
-
headers.append(key, value);
|
596
|
-
}
|
597
|
-
}
|
598
|
-
return { body, headers };
|
599
|
-
}
|
600
|
-
assertDetailedOutput(output) {
|
601
|
-
const error = new Error(`
|
602
|
-
Invalid output structure for 'detailed' output.
|
603
|
-
Expected format:
|
604
|
-
{
|
605
|
-
body?: unknown; // The main response content (optional)
|
606
|
-
headers?: { // Additional headers (optional)
|
607
|
-
[key: string]: string;
|
608
|
-
};
|
609
|
-
}
|
610
|
-
|
611
|
-
Example:
|
612
|
-
{
|
613
|
-
body: { message: "Success" },
|
614
|
-
headers: { "X-Custom-Header": "Custom-Value" },
|
615
|
-
}
|
616
|
-
|
617
|
-
Fix: Ensure your output matches the expected structure.
|
618
|
-
`);
|
619
|
-
if (!isPlainObject3(output) || Object.keys(output).some((key) => key !== "body" && key !== "headers")) {
|
620
|
-
throw error;
|
621
|
-
}
|
622
|
-
if (output.headers !== void 0 && !isPlainObject3(output.headers)) {
|
623
|
-
throw error;
|
624
|
-
}
|
625
|
-
if (output.headers && Object.entries(output.headers).some(([key, value]) => typeof key !== "string" || typeof value !== "string")) {
|
626
|
-
throw error;
|
627
|
-
}
|
628
|
-
}
|
629
|
-
convertToORPCError(e) {
|
630
|
-
return e instanceof ORPCError2 ? e : new ORPCError2("INTERNAL_SERVER_ERROR", {
|
631
|
-
message: "Internal server error",
|
632
|
-
cause: e
|
633
|
-
});
|
634
|
-
}
|
635
|
-
};
|
636
|
-
|
637
|
-
export {
|
638
|
-
serialize,
|
639
|
-
deserialize,
|
640
|
-
escapeSegment,
|
641
|
-
stringifyPath,
|
642
|
-
parsePath,
|
643
|
-
InputStructureCompact,
|
644
|
-
InputStructureDetailed,
|
645
|
-
OpenAPIPayloadCodec,
|
646
|
-
OpenAPIProcedureMatcher,
|
647
|
-
CompositeSchemaCoercer,
|
648
|
-
OpenAPIHandler
|
649
|
-
};
|
650
|
-
//# sourceMappingURL=chunk-SOVQ5ARD.js.map
|
package/dist/chunk-VFGNQS5W.js
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
OpenAPIHandler
|
3
|
-
} from "./chunk-SOVQ5ARD.js";
|
4
|
-
|
5
|
-
// src/adapters/fetch/openapi-handler-server.ts
|
6
|
-
import { TrieRouter } from "hono/router/trie-router";
|
7
|
-
var OpenAPIServerHandler = class extends OpenAPIHandler {
|
8
|
-
constructor(router, options) {
|
9
|
-
super(new TrieRouter(), router, options);
|
10
|
-
}
|
11
|
-
};
|
12
|
-
|
13
|
-
// src/adapters/fetch/openapi-handler-serverless.ts
|
14
|
-
import { LinearRouter } from "hono/router/linear-router";
|
15
|
-
var OpenAPIServerlessHandler = class extends OpenAPIHandler {
|
16
|
-
constructor(router, options) {
|
17
|
-
super(new LinearRouter(), router, options);
|
18
|
-
}
|
19
|
-
};
|
20
|
-
|
21
|
-
export {
|
22
|
-
OpenAPIServerHandler,
|
23
|
-
OpenAPIServerlessHandler
|
24
|
-
};
|
25
|
-
//# sourceMappingURL=chunk-VFGNQS5W.js.map
|
@@ -1,6 +0,0 @@
|
|
1
|
-
import type { Params } from 'hono/router';
|
2
|
-
export declare class InputStructureCompact {
|
3
|
-
build(params: Params, payload: unknown): unknown;
|
4
|
-
}
|
5
|
-
export type PublicInputStructureCompact = Pick<InputStructureCompact, keyof InputStructureCompact>;
|
6
|
-
//# sourceMappingURL=input-structure-compact.d.ts.map
|
@@ -1,11 +0,0 @@
|
|
1
|
-
import type { Params } from 'hono/router';
|
2
|
-
export declare class InputStructureDetailed {
|
3
|
-
build(params: Params, query: unknown, headers: unknown, body: unknown): {
|
4
|
-
params: Params;
|
5
|
-
query: unknown;
|
6
|
-
headers: unknown;
|
7
|
-
body: unknown;
|
8
|
-
};
|
9
|
-
}
|
10
|
-
export type PublicInputStructureDetailed = Pick<InputStructureDetailed, keyof InputStructureDetailed>;
|
11
|
-
//# sourceMappingURL=input-structure-detailed.d.ts.map
|
@@ -1,7 +0,0 @@
|
|
1
|
-
import type { Context, Router } from '@orpc/server';
|
2
|
-
import type { OpenAPIHandlerOptions } from './openapi-handler';
|
3
|
-
import { OpenAPIHandler } from './openapi-handler';
|
4
|
-
export declare class OpenAPIServerHandler<T extends Context> extends OpenAPIHandler<T> {
|
5
|
-
constructor(router: Router<T, any>, options?: NoInfer<OpenAPIHandlerOptions<T>>);
|
6
|
-
}
|
7
|
-
//# sourceMappingURL=openapi-handler-server.d.ts.map
|