@orpc/openapi 0.0.0-next.0a2672f → 0.0.0-next.0c8e57d
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-GEDPF5HA.js +25 -0
- package/dist/{chunk-YXHH6XHB.js → chunk-UG6W4GSA.js} +68 -57
- package/dist/{chunk-KNYXLM77.js → chunk-V4HFPIEN.js} +1 -1
- package/dist/fetch.js +6 -18
- package/dist/hono.js +34 -0
- package/dist/index.js +72 -12
- package/dist/next.js +34 -0
- package/dist/node.js +11 -11
- package/dist/src/adapters/fetch/openapi-handler.d.ts +4 -5
- package/dist/src/adapters/hono/index.d.ts +2 -0
- package/dist/src/adapters/next/index.d.ts +2 -0
- package/dist/src/adapters/node/openapi-handler.d.ts +3 -4
- package/dist/src/openapi-generator.d.ts +9 -2
- package/dist/src/openapi-input-structure-parser.d.ts +1 -1
- package/dist/src/schema.d.ts +1 -1
- package/dist/src/utils.d.ts +2 -2
- package/package.json +15 -6
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenAPIHandler
|
|
3
|
+
} from "./chunk-UG6W4GSA.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-GEDPF5HA.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
JSONSerializer,
|
|
3
3
|
forEachContractProcedure,
|
|
4
4
|
standardizeHTTPPath
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-V4HFPIEN.js";
|
|
6
6
|
|
|
7
7
|
// src/adapters/fetch/bracket-notation.ts
|
|
8
8
|
import { isPlainObject } from "@orpc/shared";
|
|
@@ -351,45 +351,58 @@ var OpenAPIPayloadCodec = class {
|
|
|
351
351
|
};
|
|
352
352
|
}
|
|
353
353
|
async decode(re) {
|
|
354
|
-
|
|
355
|
-
|
|
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;
|
|
354
|
+
try {
|
|
355
|
+
if (re instanceof Headers || re instanceof URLSearchParams || re instanceof FormData) {
|
|
356
|
+
return deserialize([...re.entries()]);
|
|
370
357
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
358
|
+
const contentType = re.headers.get("content-type");
|
|
359
|
+
const contentDisposition = re.headers.get("content-disposition");
|
|
360
|
+
const fileName = contentDisposition ? cd.parse(contentDisposition).parameters.filename : void 0;
|
|
361
|
+
if (fileName) {
|
|
362
|
+
const blob2 = await re.blob();
|
|
363
|
+
const file = new File([blob2], fileName, {
|
|
364
|
+
type: blob2.type
|
|
365
|
+
});
|
|
366
|
+
return file;
|
|
367
|
+
}
|
|
368
|
+
if (!contentType || contentType.startsWith("application/json")) {
|
|
369
|
+
if (!re.body) {
|
|
370
|
+
return void 0;
|
|
371
|
+
}
|
|
372
|
+
const text = await re.text();
|
|
373
|
+
if (!text) {
|
|
374
|
+
return void 0;
|
|
375
|
+
}
|
|
376
|
+
return JSON.parse(text);
|
|
377
|
+
}
|
|
378
|
+
if (contentType.startsWith("application/x-www-form-urlencoded")) {
|
|
379
|
+
const params = new URLSearchParams(await re.text());
|
|
380
|
+
return this.decode(params);
|
|
381
|
+
}
|
|
382
|
+
if (contentType.startsWith("text/")) {
|
|
383
|
+
const text = await re.text();
|
|
384
|
+
return text;
|
|
385
|
+
}
|
|
386
|
+
if (contentType.startsWith("multipart/form-data")) {
|
|
387
|
+
const form = await re.formData();
|
|
388
|
+
return this.decode(form);
|
|
389
|
+
}
|
|
390
|
+
const blob = await re.blob();
|
|
391
|
+
return new File([blob], "blob", {
|
|
392
|
+
type: blob.type
|
|
393
|
+
});
|
|
394
|
+
} catch (e) {
|
|
395
|
+
throw new ORPCError({
|
|
396
|
+
code: "BAD_REQUEST",
|
|
397
|
+
message: "Cannot parse request/response. Please check the request/response body and Content-Type header.",
|
|
398
|
+
cause: e
|
|
399
|
+
});
|
|
384
400
|
}
|
|
385
|
-
const blob = await re.blob();
|
|
386
|
-
return new File([blob], "blob", {
|
|
387
|
-
type: blob.type
|
|
388
|
-
});
|
|
389
401
|
}
|
|
390
402
|
};
|
|
391
403
|
|
|
392
404
|
// src/adapters/fetch/openapi-procedure-matcher.ts
|
|
405
|
+
import { fallbackContractConfig } from "@orpc/contract";
|
|
393
406
|
import { getLazyRouterPrefix, getRouterChild, isProcedure, unlazy } from "@orpc/server";
|
|
394
407
|
import { mapValues } from "@orpc/shared";
|
|
395
408
|
var OpenAPIProcedureMatcher = class {
|
|
@@ -434,7 +447,7 @@ var OpenAPIProcedureMatcher = class {
|
|
|
434
447
|
}
|
|
435
448
|
add(path, router) {
|
|
436
449
|
const lazies = forEachContractProcedure({ path, router }, ({ path: path2, contract }) => {
|
|
437
|
-
const method = contract["~orpc"].route?.method
|
|
450
|
+
const method = fallbackContractConfig("defaultMethod", contract["~orpc"].route?.method);
|
|
438
451
|
const httpPath = contract["~orpc"].route?.path ? this.convertOpenAPIPathToRouterPath(contract["~orpc"].route?.path) : `/${path2.map(encodeURIComponent).join("/")}`;
|
|
439
452
|
this.hono.add(method, httpPath, [httpPath, path2]);
|
|
440
453
|
});
|
|
@@ -473,8 +486,9 @@ var CompositeSchemaCoercer = class {
|
|
|
473
486
|
};
|
|
474
487
|
|
|
475
488
|
// src/adapters/fetch/openapi-handler.ts
|
|
489
|
+
import { fallbackContractConfig as fallbackContractConfig2 } from "@orpc/contract";
|
|
476
490
|
import { createProcedureClient, ORPCError as ORPCError2 } from "@orpc/server";
|
|
477
|
-
import { executeWithHooks, isPlainObject as isPlainObject3,
|
|
491
|
+
import { executeWithHooks, isPlainObject as isPlainObject3, trim } from "@orpc/shared";
|
|
478
492
|
var OpenAPIHandler = class {
|
|
479
493
|
constructor(hono, router, options) {
|
|
480
494
|
this.options = options;
|
|
@@ -490,13 +504,10 @@ var OpenAPIHandler = class {
|
|
|
490
504
|
inputStructureCompact;
|
|
491
505
|
inputStructureDetailed;
|
|
492
506
|
compositeSchemaCoercer;
|
|
493
|
-
|
|
494
|
-
return request.headers.get(ORPC_HANDLER_HEADER) === null;
|
|
495
|
-
}
|
|
496
|
-
async fetch(request, ...[options]) {
|
|
507
|
+
async handle(request, ...[options]) {
|
|
497
508
|
const context = options?.context;
|
|
498
509
|
const headers = request.headers;
|
|
499
|
-
const accept = headers.get("
|
|
510
|
+
const accept = headers.get("accept") || void 0;
|
|
500
511
|
const execute = async () => {
|
|
501
512
|
const url = new URL(request.url);
|
|
502
513
|
const pathname = `/${trim(url.pathname.replace(options?.prefix ?? "", ""), "/")}`;
|
|
@@ -505,22 +516,22 @@ var OpenAPIHandler = class {
|
|
|
505
516
|
const matchedMethod = customMethod || request.method;
|
|
506
517
|
const matched = await this.procedureMatcher.match(matchedMethod, pathname);
|
|
507
518
|
if (!matched) {
|
|
508
|
-
|
|
519
|
+
return { matched: false, response: void 0 };
|
|
509
520
|
}
|
|
510
521
|
const contractDef = matched.procedure["~orpc"].contract["~orpc"];
|
|
511
522
|
const input = await this.decodeInput(matched.procedure, matched.params, request);
|
|
512
523
|
const coercedInput = this.compositeSchemaCoercer.coerce(contractDef.InputSchema, input);
|
|
513
|
-
const client = createProcedureClient({
|
|
524
|
+
const client = createProcedureClient(matched.procedure, {
|
|
514
525
|
context,
|
|
515
|
-
procedure: matched.procedure,
|
|
516
526
|
path: matched.path
|
|
517
527
|
});
|
|
518
|
-
const output = await client(coercedInput, { signal:
|
|
528
|
+
const output = await client(coercedInput, { signal: request.signal });
|
|
519
529
|
const { body, headers: resHeaders } = this.encodeOutput(matched.procedure, output, accept);
|
|
520
|
-
|
|
530
|
+
const response = new Response(body, {
|
|
521
531
|
headers: resHeaders,
|
|
522
|
-
status: contractDef.route?.successStatus
|
|
532
|
+
status: fallbackContractConfig2("defaultSuccessStatus", contractDef.route?.successStatus)
|
|
523
533
|
});
|
|
534
|
+
return { matched: true, response };
|
|
524
535
|
};
|
|
525
536
|
try {
|
|
526
537
|
return await executeWithHooks({
|
|
@@ -529,50 +540,50 @@ var OpenAPIHandler = class {
|
|
|
529
540
|
input: request,
|
|
530
541
|
hooks: this.options,
|
|
531
542
|
meta: {
|
|
532
|
-
signal:
|
|
543
|
+
signal: request.signal
|
|
533
544
|
}
|
|
534
545
|
});
|
|
535
546
|
} catch (e) {
|
|
536
547
|
const error = this.convertToORPCError(e);
|
|
537
548
|
try {
|
|
538
549
|
const { body, headers: headers2 } = this.payloadCodec.encode(error.toJSON(), accept);
|
|
539
|
-
|
|
550
|
+
const response = new Response(body, {
|
|
540
551
|
status: error.status,
|
|
541
552
|
headers: headers2
|
|
542
553
|
});
|
|
554
|
+
return { matched: true, response };
|
|
543
555
|
} catch (e2) {
|
|
544
556
|
const error2 = this.convertToORPCError(e2);
|
|
545
557
|
const { body, headers: headers2 } = this.payloadCodec.encode(error2.toJSON(), void 0);
|
|
546
|
-
|
|
558
|
+
const response = new Response(body, {
|
|
547
559
|
status: error2.status,
|
|
548
560
|
headers: headers2
|
|
549
561
|
});
|
|
562
|
+
return { matched: true, response };
|
|
550
563
|
}
|
|
551
564
|
}
|
|
552
565
|
}
|
|
553
566
|
async decodeInput(procedure, params, request) {
|
|
554
|
-
const inputStructure = procedure["~orpc"].contract["~orpc"].route?.inputStructure;
|
|
567
|
+
const inputStructure = fallbackContractConfig2("defaultInputStructure", procedure["~orpc"].contract["~orpc"].route?.inputStructure);
|
|
555
568
|
const url = new URL(request.url);
|
|
556
569
|
const query = url.searchParams;
|
|
557
570
|
const headers = request.headers;
|
|
558
|
-
if (
|
|
571
|
+
if (inputStructure === "compact") {
|
|
559
572
|
return this.inputStructureCompact.build(
|
|
560
573
|
params,
|
|
561
574
|
request.method === "GET" ? await this.payloadCodec.decode(query) : await this.payloadCodec.decode(request)
|
|
562
575
|
);
|
|
563
576
|
}
|
|
564
|
-
const _expect = inputStructure;
|
|
565
577
|
const decodedQuery = await this.payloadCodec.decode(query);
|
|
566
578
|
const decodedHeaders = await this.payloadCodec.decode(headers);
|
|
567
579
|
const decodedBody = await this.payloadCodec.decode(request);
|
|
568
580
|
return this.inputStructureDetailed.build(params, decodedQuery, decodedHeaders, decodedBody);
|
|
569
581
|
}
|
|
570
582
|
encodeOutput(procedure, output, accept) {
|
|
571
|
-
const outputStructure = procedure["~orpc"].contract["~orpc"].route?.outputStructure;
|
|
572
|
-
if (
|
|
583
|
+
const outputStructure = fallbackContractConfig2("defaultOutputStructure", procedure["~orpc"].contract["~orpc"].route?.outputStructure);
|
|
584
|
+
if (outputStructure === "compact") {
|
|
573
585
|
return this.payloadCodec.encode(output, accept);
|
|
574
586
|
}
|
|
575
|
-
const _expect = outputStructure;
|
|
576
587
|
this.assertDetailedOutput(output);
|
|
577
588
|
const headers = new Headers();
|
|
578
589
|
if (output.headers) {
|
|
@@ -639,4 +650,4 @@ export {
|
|
|
639
650
|
CompositeSchemaCoercer,
|
|
640
651
|
OpenAPIHandler
|
|
641
652
|
};
|
|
642
|
-
//# sourceMappingURL=chunk-
|
|
653
|
+
//# sourceMappingURL=chunk-UG6W4GSA.js.map
|
package/dist/fetch.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenAPIServerHandler,
|
|
3
|
+
OpenAPIServerlessHandler
|
|
4
|
+
} from "./chunk-GEDPF5HA.js";
|
|
1
5
|
import {
|
|
2
6
|
CompositeSchemaCoercer,
|
|
3
7
|
InputStructureCompact,
|
|
@@ -10,24 +14,8 @@ import {
|
|
|
10
14
|
parsePath,
|
|
11
15
|
serialize,
|
|
12
16
|
stringifyPath
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
|
|
16
|
-
// src/adapters/fetch/openapi-handler-server.ts
|
|
17
|
-
import { TrieRouter } from "hono/router/trie-router";
|
|
18
|
-
var OpenAPIServerHandler = class extends OpenAPIHandler {
|
|
19
|
-
constructor(router, options) {
|
|
20
|
-
super(new TrieRouter(), router, options);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// src/adapters/fetch/openapi-handler-serverless.ts
|
|
25
|
-
import { LinearRouter } from "hono/router/linear-router";
|
|
26
|
-
var OpenAPIServerlessHandler = class extends OpenAPIHandler {
|
|
27
|
-
constructor(router, options) {
|
|
28
|
-
super(new LinearRouter(), router, options);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
17
|
+
} from "./chunk-UG6W4GSA.js";
|
|
18
|
+
import "./chunk-V4HFPIEN.js";
|
|
31
19
|
export {
|
|
32
20
|
CompositeSchemaCoercer,
|
|
33
21
|
InputStructureCompact,
|
package/dist/hono.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenAPIServerHandler,
|
|
3
|
+
OpenAPIServerlessHandler
|
|
4
|
+
} from "./chunk-GEDPF5HA.js";
|
|
5
|
+
import {
|
|
6
|
+
CompositeSchemaCoercer,
|
|
7
|
+
InputStructureCompact,
|
|
8
|
+
InputStructureDetailed,
|
|
9
|
+
OpenAPIHandler,
|
|
10
|
+
OpenAPIPayloadCodec,
|
|
11
|
+
OpenAPIProcedureMatcher,
|
|
12
|
+
deserialize,
|
|
13
|
+
escapeSegment,
|
|
14
|
+
parsePath,
|
|
15
|
+
serialize,
|
|
16
|
+
stringifyPath
|
|
17
|
+
} from "./chunk-UG6W4GSA.js";
|
|
18
|
+
import "./chunk-V4HFPIEN.js";
|
|
19
|
+
export {
|
|
20
|
+
CompositeSchemaCoercer,
|
|
21
|
+
InputStructureCompact,
|
|
22
|
+
InputStructureDetailed,
|
|
23
|
+
OpenAPIHandler,
|
|
24
|
+
OpenAPIPayloadCodec,
|
|
25
|
+
OpenAPIProcedureMatcher,
|
|
26
|
+
OpenAPIServerHandler,
|
|
27
|
+
OpenAPIServerlessHandler,
|
|
28
|
+
deserialize,
|
|
29
|
+
escapeSegment,
|
|
30
|
+
parsePath,
|
|
31
|
+
serialize,
|
|
32
|
+
stringifyPath
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=hono.js.map
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
forEachAllContractProcedure,
|
|
4
4
|
forEachContractProcedure,
|
|
5
5
|
standardizeHTTPPath
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-V4HFPIEN.js";
|
|
7
7
|
|
|
8
8
|
// src/openapi.ts
|
|
9
9
|
import { OpenApiBuilder } from "openapi3-ts/oas31";
|
|
@@ -35,11 +35,16 @@ var OpenAPIContentBuilder = class {
|
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
+
// src/openapi-generator.ts
|
|
39
|
+
import { fallbackContractConfig as fallbackContractConfig2, fallbackORPCErrorStatus } from "@orpc/contract";
|
|
40
|
+
import { group } from "@orpc/shared";
|
|
41
|
+
|
|
38
42
|
// src/openapi-error.ts
|
|
39
43
|
var OpenAPIError = class extends Error {
|
|
40
44
|
};
|
|
41
45
|
|
|
42
46
|
// src/openapi-input-structure-parser.ts
|
|
47
|
+
import { fallbackContractConfig } from "@orpc/contract";
|
|
43
48
|
var OpenAPIInputStructureParser = class {
|
|
44
49
|
constructor(schemaConverter, schemaUtils, pathParser) {
|
|
45
50
|
this.schemaConverter = schemaConverter;
|
|
@@ -48,7 +53,7 @@ var OpenAPIInputStructureParser = class {
|
|
|
48
53
|
}
|
|
49
54
|
parse(contract, structure) {
|
|
50
55
|
const inputSchema = this.schemaConverter.convert(contract["~orpc"].InputSchema, { strategy: "input" });
|
|
51
|
-
const method = contract["~orpc"].route?.method
|
|
56
|
+
const method = fallbackContractConfig("defaultMethod", contract["~orpc"].route?.method);
|
|
52
57
|
const httpPath = contract["~orpc"].route?.path;
|
|
53
58
|
if (this.schemaUtils.isAnySchema(inputSchema)) {
|
|
54
59
|
return {
|
|
@@ -289,14 +294,14 @@ var SchemaUtils = class {
|
|
|
289
294
|
return typeof schema === "object" && schema.type === "object";
|
|
290
295
|
}
|
|
291
296
|
isAnySchema(schema) {
|
|
292
|
-
return schema === true || Object.keys(schema).length === 0;
|
|
297
|
+
return schema === true || Object.keys(schema).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
|
|
293
298
|
}
|
|
294
299
|
isUndefinableSchema(schema) {
|
|
295
300
|
const [matches] = this.filterSchemaBranches(schema, (schema2) => {
|
|
296
301
|
if (typeof schema2 === "boolean") {
|
|
297
302
|
return schema2;
|
|
298
303
|
}
|
|
299
|
-
return Object.keys(schema2).length === 0;
|
|
304
|
+
return Object.keys(schema2).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
|
|
300
305
|
});
|
|
301
306
|
return matches.length > 0;
|
|
302
307
|
}
|
|
@@ -380,6 +385,7 @@ var OpenAPIGenerator = class {
|
|
|
380
385
|
errorHandlerStrategy;
|
|
381
386
|
ignoreUndefinedPathProcedures;
|
|
382
387
|
considerMissingTagDefinitionAsError;
|
|
388
|
+
strictErrorResponses;
|
|
383
389
|
constructor(options) {
|
|
384
390
|
this.parametersBuilder = options?.parametersBuilder ?? new OpenAPIParametersBuilder();
|
|
385
391
|
this.schemaConverter = new CompositeSchemaConverter(options?.schemaConverters ?? []);
|
|
@@ -392,6 +398,7 @@ var OpenAPIGenerator = class {
|
|
|
392
398
|
this.errorHandlerStrategy = options?.errorHandlerStrategy ?? "throw";
|
|
393
399
|
this.ignoreUndefinedPathProcedures = options?.ignoreUndefinedPathProcedures ?? false;
|
|
394
400
|
this.considerMissingTagDefinitionAsError = options?.considerMissingTagDefinitionAsError ?? false;
|
|
401
|
+
this.strictErrorResponses = options?.strictErrorResponses ?? true;
|
|
395
402
|
}
|
|
396
403
|
async generate(router, doc) {
|
|
397
404
|
const builder = new OpenApiBuilder({
|
|
@@ -405,10 +412,12 @@ var OpenAPIGenerator = class {
|
|
|
405
412
|
if (this.ignoreUndefinedPathProcedures && def.route?.path === void 0) {
|
|
406
413
|
return;
|
|
407
414
|
}
|
|
408
|
-
const method = def.route?.method
|
|
415
|
+
const method = fallbackContractConfig2("defaultMethod", def.route?.method);
|
|
409
416
|
const httpPath = def.route?.path ? standardizeHTTPPath(def.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
|
|
410
|
-
const
|
|
411
|
-
const
|
|
417
|
+
const inputStructure = fallbackContractConfig2("defaultInputStructure", def.route?.inputStructure);
|
|
418
|
+
const outputStructure = fallbackContractConfig2("defaultOutputStructure", def.route?.outputStructure);
|
|
419
|
+
const { paramsSchema, querySchema, headersSchema, bodySchema } = this.inputStructureParser.parse(contract, inputStructure);
|
|
420
|
+
const { headersSchema: resHeadersSchema, bodySchema: resBodySchema } = this.outputStructureParser.parse(contract, outputStructure);
|
|
412
421
|
const params = paramsSchema ? this.parametersBuilder.build("path", paramsSchema, {
|
|
413
422
|
required: true
|
|
414
423
|
}) : [];
|
|
@@ -419,8 +428,9 @@ var OpenAPIGenerator = class {
|
|
|
419
428
|
required: this.schemaUtils.isUndefinableSchema(bodySchema),
|
|
420
429
|
content: this.contentBuilder.build(bodySchema)
|
|
421
430
|
} : void 0;
|
|
422
|
-
const
|
|
423
|
-
|
|
431
|
+
const responses = {};
|
|
432
|
+
responses[fallbackContractConfig2("defaultSuccessStatus", def.route?.successStatus)] = {
|
|
433
|
+
description: fallbackContractConfig2("defaultSuccessDescription", def.route?.successDescription),
|
|
424
434
|
content: resBodySchema !== void 0 ? this.contentBuilder.build(resBodySchema, {
|
|
425
435
|
example: def.outputExample
|
|
426
436
|
}) : void 0,
|
|
@@ -428,6 +438,58 @@ var OpenAPIGenerator = class {
|
|
|
428
438
|
example: def.outputExample
|
|
429
439
|
}) : void 0
|
|
430
440
|
};
|
|
441
|
+
const errors = group(Object.entries(def.errorMap ?? {}).filter(([_, config]) => config).map(([code, config]) => ({
|
|
442
|
+
...config,
|
|
443
|
+
code,
|
|
444
|
+
status: fallbackORPCErrorStatus(code, config?.status)
|
|
445
|
+
})), (error) => error.status);
|
|
446
|
+
for (const status in errors) {
|
|
447
|
+
const configs = errors[status];
|
|
448
|
+
if (!configs || configs.length === 0) {
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
const schemas = configs.map(({ data, code, message }) => {
|
|
452
|
+
const json = {
|
|
453
|
+
type: "object",
|
|
454
|
+
properties: {
|
|
455
|
+
defined: { const: true },
|
|
456
|
+
code: { const: code },
|
|
457
|
+
status: { const: Number(status) },
|
|
458
|
+
message: { type: "string", default: message },
|
|
459
|
+
data: {}
|
|
460
|
+
},
|
|
461
|
+
required: ["defined", "code", "status", "message"]
|
|
462
|
+
};
|
|
463
|
+
if (data) {
|
|
464
|
+
const dataJson = this.schemaConverter.convert(data, { strategy: "output" });
|
|
465
|
+
json.properties.data = dataJson;
|
|
466
|
+
if (!this.schemaUtils.isUndefinableSchema(dataJson)) {
|
|
467
|
+
json.required.push("data");
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return json;
|
|
471
|
+
});
|
|
472
|
+
if (this.strictErrorResponses) {
|
|
473
|
+
schemas.push({
|
|
474
|
+
type: "object",
|
|
475
|
+
properties: {
|
|
476
|
+
defined: { const: false },
|
|
477
|
+
code: { type: "string" },
|
|
478
|
+
status: { type: "number" },
|
|
479
|
+
message: { type: "string" },
|
|
480
|
+
data: {}
|
|
481
|
+
},
|
|
482
|
+
required: ["defined", "code", "status", "message"]
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
const contentSchema = schemas.length === 1 ? schemas[0] : {
|
|
486
|
+
oneOf: schemas
|
|
487
|
+
};
|
|
488
|
+
responses[status] = {
|
|
489
|
+
description: status,
|
|
490
|
+
content: this.contentBuilder.build(contentSchema)
|
|
491
|
+
};
|
|
492
|
+
}
|
|
431
493
|
if (this.considerMissingTagDefinitionAsError && def.route?.tags) {
|
|
432
494
|
const missingTag = def.route?.tags.find((tag) => !rootTags.includes(tag));
|
|
433
495
|
if (missingTag !== void 0) {
|
|
@@ -444,9 +506,7 @@ var OpenAPIGenerator = class {
|
|
|
444
506
|
operationId: path.join("."),
|
|
445
507
|
parameters: parameters.length ? parameters : void 0,
|
|
446
508
|
requestBody,
|
|
447
|
-
responses
|
|
448
|
-
[def.route?.successStatus ?? 200]: successResponse
|
|
449
|
-
}
|
|
509
|
+
responses
|
|
450
510
|
};
|
|
451
511
|
builder.addPath(httpPath, {
|
|
452
512
|
[method.toLocaleLowerCase()]: operation
|
package/dist/next.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenAPIServerHandler,
|
|
3
|
+
OpenAPIServerlessHandler
|
|
4
|
+
} from "./chunk-GEDPF5HA.js";
|
|
5
|
+
import {
|
|
6
|
+
CompositeSchemaCoercer,
|
|
7
|
+
InputStructureCompact,
|
|
8
|
+
InputStructureDetailed,
|
|
9
|
+
OpenAPIHandler,
|
|
10
|
+
OpenAPIPayloadCodec,
|
|
11
|
+
OpenAPIProcedureMatcher,
|
|
12
|
+
deserialize,
|
|
13
|
+
escapeSegment,
|
|
14
|
+
parsePath,
|
|
15
|
+
serialize,
|
|
16
|
+
stringifyPath
|
|
17
|
+
} from "./chunk-UG6W4GSA.js";
|
|
18
|
+
import "./chunk-V4HFPIEN.js";
|
|
19
|
+
export {
|
|
20
|
+
CompositeSchemaCoercer,
|
|
21
|
+
InputStructureCompact,
|
|
22
|
+
InputStructureDetailed,
|
|
23
|
+
OpenAPIHandler,
|
|
24
|
+
OpenAPIPayloadCodec,
|
|
25
|
+
OpenAPIProcedureMatcher,
|
|
26
|
+
OpenAPIServerHandler,
|
|
27
|
+
OpenAPIServerlessHandler,
|
|
28
|
+
deserialize,
|
|
29
|
+
escapeSegment,
|
|
30
|
+
parsePath,
|
|
31
|
+
serialize,
|
|
32
|
+
stringifyPath
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=next.js.map
|
package/dist/node.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OpenAPIHandler
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-UG6W4GSA.js";
|
|
4
|
+
import "./chunk-V4HFPIEN.js";
|
|
5
5
|
|
|
6
6
|
// src/adapters/node/openapi-handler.ts
|
|
7
|
-
import { createRequest, sendResponse } from "@
|
|
8
|
-
import { ORPC_HANDLER_HEADER } from "@orpc/shared";
|
|
7
|
+
import { createRequest, sendResponse } from "@orpc/server/node";
|
|
9
8
|
var OpenAPIHandler2 = class {
|
|
10
9
|
openapiFetchHandler;
|
|
11
10
|
constructor(hono, router, options) {
|
|
12
11
|
this.openapiFetchHandler = new OpenAPIHandler(hono, router, options);
|
|
13
12
|
}
|
|
14
|
-
condition(request) {
|
|
15
|
-
return request.headers[ORPC_HANDLER_HEADER] === void 0;
|
|
16
|
-
}
|
|
17
13
|
async handle(req, res, ...[options]) {
|
|
18
|
-
const request = createRequest(req, res
|
|
14
|
+
const request = createRequest(req, res);
|
|
19
15
|
const castedOptions = options ?? {};
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
const result = await this.openapiFetchHandler.handle(request, castedOptions);
|
|
17
|
+
if (result.matched === false) {
|
|
18
|
+
return { matched: false };
|
|
19
|
+
}
|
|
20
|
+
await options?.beforeSend?.(result.response, castedOptions.context);
|
|
21
|
+
await sendResponse(res, result.response);
|
|
22
|
+
return { matched: true };
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
25
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Context, Router, WithSignal } from '@orpc/server';
|
|
2
|
-
import type {
|
|
2
|
+
import type { FetchHandler, FetchHandleRest, FetchHandleResult } from '@orpc/server/fetch';
|
|
3
3
|
import type { PublicInputStructureCompact } from './input-structure-compact';
|
|
4
4
|
import { type Hooks } from '@orpc/shared';
|
|
5
5
|
import { type PublicJSONSerializer } from '../../json-serializer';
|
|
@@ -7,7 +7,7 @@ import { type PublicInputStructureDetailed } from './input-structure-detailed';
|
|
|
7
7
|
import { type PublicOpenAPIPayloadCodec } from './openapi-payload-codec';
|
|
8
8
|
import { type Hono, type PublicOpenAPIProcedureMatcher } from './openapi-procedure-matcher';
|
|
9
9
|
import { type SchemaCoercer } from './schema-coercer';
|
|
10
|
-
export type OpenAPIHandlerOptions<T extends Context> = Hooks<Request,
|
|
10
|
+
export type OpenAPIHandlerOptions<T extends Context> = Hooks<Request, FetchHandleResult, T, WithSignal> & {
|
|
11
11
|
jsonSerializer?: PublicJSONSerializer;
|
|
12
12
|
procedureMatcher?: PublicOpenAPIProcedureMatcher;
|
|
13
13
|
payloadCodec?: PublicOpenAPIPayloadCodec;
|
|
@@ -15,7 +15,7 @@ export type OpenAPIHandlerOptions<T extends Context> = Hooks<Request, Response,
|
|
|
15
15
|
inputBuilderFull?: PublicInputStructureDetailed;
|
|
16
16
|
schemaCoercers?: SchemaCoercer[];
|
|
17
17
|
};
|
|
18
|
-
export declare class OpenAPIHandler<T extends Context> implements
|
|
18
|
+
export declare class OpenAPIHandler<T extends Context> implements FetchHandler<T> {
|
|
19
19
|
private readonly options?;
|
|
20
20
|
private readonly procedureMatcher;
|
|
21
21
|
private readonly payloadCodec;
|
|
@@ -23,8 +23,7 @@ export declare class OpenAPIHandler<T extends Context> implements ConditionalFet
|
|
|
23
23
|
private readonly inputStructureDetailed;
|
|
24
24
|
private readonly compositeSchemaCoercer;
|
|
25
25
|
constructor(hono: Hono, router: Router<T, any>, options?: NoInfer<OpenAPIHandlerOptions<T>> | undefined);
|
|
26
|
-
|
|
27
|
-
fetch(request: Request, ...[options]: [options: FetchOptions<T>] | (undefined extends T ? [] : never)): Promise<Response>;
|
|
26
|
+
handle(request: Request, ...[options]: FetchHandleRest<T>): Promise<FetchHandleResult>;
|
|
28
27
|
private decodeInput;
|
|
29
28
|
private encodeOutput;
|
|
30
29
|
private assertDetailedOutput;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { Context, Router } from '@orpc/server';
|
|
2
|
-
import type { ConditionalRequestHandler, RequestOptions } from '@orpc/server/node';
|
|
3
2
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
3
|
import type { OpenAPIHandlerOptions } from '../fetch/openapi-handler';
|
|
5
4
|
import type { Hono } from '../fetch/openapi-procedure-matcher';
|
|
6
|
-
|
|
5
|
+
import { type RequestHandler, type RequestHandleRest, type RequestHandleResult } from '@orpc/server/node';
|
|
6
|
+
export declare class OpenAPIHandler<T extends Context> implements RequestHandler<T> {
|
|
7
7
|
private readonly openapiFetchHandler;
|
|
8
8
|
constructor(hono: Hono, router: Router<T, any>, options?: NoInfer<OpenAPIHandlerOptions<T>>);
|
|
9
|
-
|
|
10
|
-
handle(req: IncomingMessage, res: ServerResponse, ...[options]: [options: RequestOptions<T>] | (undefined extends T ? [] : never)): Promise<void>;
|
|
9
|
+
handle(req: IncomingMessage, res: ServerResponse, ...[options]: RequestHandleRest<T>): Promise<RequestHandleResult>;
|
|
11
10
|
}
|
|
12
11
|
//# sourceMappingURL=openapi-handler.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { ContractRouter } from '@orpc/contract';
|
|
2
1
|
import type { ANY_ROUTER } from '@orpc/server';
|
|
3
2
|
import type { PublicOpenAPIInputStructureParser } from './openapi-input-structure-parser';
|
|
4
3
|
import type { PublicOpenAPIOutputStructureParser } from './openapi-output-structure-parser';
|
|
5
4
|
import type { PublicOpenAPIPathParser } from './openapi-path-parser';
|
|
6
5
|
import type { SchemaConverter } from './schema-converter';
|
|
6
|
+
import { type ContractRouter } from '@orpc/contract';
|
|
7
7
|
import { type PublicJSONSerializer } from './json-serializer';
|
|
8
8
|
import { type OpenAPI } from './openapi';
|
|
9
9
|
import { type PublicOpenAPIContentBuilder } from './openapi-content-builder';
|
|
@@ -40,6 +40,12 @@ export interface OpenAPIGeneratorOptions {
|
|
|
40
40
|
* @default 'throw'
|
|
41
41
|
*/
|
|
42
42
|
errorHandlerStrategy?: ErrorHandlerStrategy;
|
|
43
|
+
/**
|
|
44
|
+
* Strict error response
|
|
45
|
+
*
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
strictErrorResponses?: boolean;
|
|
43
49
|
}
|
|
44
50
|
export declare class OpenAPIGenerator {
|
|
45
51
|
private readonly contentBuilder;
|
|
@@ -53,8 +59,9 @@ export declare class OpenAPIGenerator {
|
|
|
53
59
|
private readonly errorHandlerStrategy;
|
|
54
60
|
private readonly ignoreUndefinedPathProcedures;
|
|
55
61
|
private readonly considerMissingTagDefinitionAsError;
|
|
62
|
+
private readonly strictErrorResponses;
|
|
56
63
|
constructor(options?: OpenAPIGeneratorOptions);
|
|
57
|
-
generate(router: ContractRouter | ANY_ROUTER, doc: Omit<OpenAPI.OpenAPIObject, 'openapi'>): Promise<OpenAPI.OpenAPIObject>;
|
|
64
|
+
generate(router: ContractRouter<any> | ANY_ROUTER, doc: Omit<OpenAPI.OpenAPIObject, 'openapi'>): Promise<OpenAPI.OpenAPIObject>;
|
|
58
65
|
}
|
|
59
66
|
export {};
|
|
60
67
|
//# sourceMappingURL=openapi-generator.d.ts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { ANY_CONTRACT_PROCEDURE } from '@orpc/contract';
|
|
2
1
|
import type { PublicOpenAPIPathParser } from './openapi-path-parser';
|
|
3
2
|
import type { JSONSchema, ObjectSchema } from './schema';
|
|
4
3
|
import type { SchemaConverter } from './schema-converter';
|
|
5
4
|
import type { PublicSchemaUtils } from './schema-utils';
|
|
5
|
+
import { type ANY_CONTRACT_PROCEDURE } from '@orpc/contract';
|
|
6
6
|
export interface OpenAPIInputStructureParseResult {
|
|
7
7
|
paramsSchema: ObjectSchema | undefined;
|
|
8
8
|
querySchema: ObjectSchema | undefined;
|
package/dist/src/schema.d.ts
CHANGED
|
@@ -8,5 +8,5 @@ export type FileSchema = JSONSchema.JSONSchema & {
|
|
|
8
8
|
type: 'string';
|
|
9
9
|
contentMediaType: string;
|
|
10
10
|
} & object;
|
|
11
|
-
export declare const NON_LOGIC_KEYWORDS:
|
|
11
|
+
export declare const NON_LOGIC_KEYWORDS: string[];
|
|
12
12
|
//# sourceMappingURL=schema.d.ts.map
|
package/dist/src/utils.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ContractRouter, HTTPPath, WELL_CONTRACT_PROCEDURE } from '@orpc/contract';
|
|
2
2
|
import type { ANY_PROCEDURE, ANY_ROUTER, Lazy } from '@orpc/server';
|
|
3
3
|
export interface EachLeafOptions {
|
|
4
|
-
router: ContractRouter | ANY_ROUTER;
|
|
4
|
+
router: ContractRouter<any> | ANY_ROUTER;
|
|
5
5
|
path: string[];
|
|
6
6
|
}
|
|
7
7
|
export interface EachLeafCallbackOptions {
|
|
@@ -13,6 +13,6 @@ export interface EachContractLeafResultItem {
|
|
|
13
13
|
path: string[];
|
|
14
14
|
}
|
|
15
15
|
export declare function forEachContractProcedure(options: EachLeafOptions, callback: (options: EachLeafCallbackOptions) => void, result?: EachContractLeafResultItem[], isCurrentRouterContract?: boolean): EachContractLeafResultItem[];
|
|
16
|
-
export declare function forEachAllContractProcedure(router: ContractRouter | ANY_ROUTER, callback: (options: EachLeafCallbackOptions) => void): Promise<void>;
|
|
16
|
+
export declare function forEachAllContractProcedure(router: ContractRouter<any> | ANY_ROUTER, callback: (options: EachLeafCallbackOptions) => void): Promise<void>;
|
|
17
17
|
export declare function standardizeHTTPPath(path: HTTPPath): HTTPPath;
|
|
18
18
|
//# 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.0c8e57d",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://orpc.unnoq.com",
|
|
7
7
|
"repository": {
|
|
@@ -24,6 +24,16 @@
|
|
|
24
24
|
"import": "./dist/fetch.js",
|
|
25
25
|
"default": "./dist/fetch.js"
|
|
26
26
|
},
|
|
27
|
+
"./hono": {
|
|
28
|
+
"types": "./dist/src/adapters/hono/index.d.ts",
|
|
29
|
+
"import": "./dist/hono.js",
|
|
30
|
+
"default": "./dist/hono.js"
|
|
31
|
+
},
|
|
32
|
+
"./next": {
|
|
33
|
+
"types": "./dist/src/adapters/next/index.d.ts",
|
|
34
|
+
"import": "./dist/next.js",
|
|
35
|
+
"default": "./dist/next.js"
|
|
36
|
+
},
|
|
27
37
|
"./node": {
|
|
28
38
|
"types": "./dist/src/adapters/node/index.d.ts",
|
|
29
39
|
"import": "./dist/node.js",
|
|
@@ -39,7 +49,6 @@
|
|
|
39
49
|
"dist"
|
|
40
50
|
],
|
|
41
51
|
"dependencies": {
|
|
42
|
-
"@mjackson/node-fetch-server": "^0.5.0",
|
|
43
52
|
"@standard-schema/spec": "1.0.0-beta.4",
|
|
44
53
|
"@types/content-disposition": "^0.5.8",
|
|
45
54
|
"content-disposition": "^0.5.4",
|
|
@@ -49,16 +58,16 @@
|
|
|
49
58
|
"json-schema-typed": "^8.0.1",
|
|
50
59
|
"openapi3-ts": "^4.4.0",
|
|
51
60
|
"wildcard-match": "^5.1.3",
|
|
52
|
-
"@orpc/contract": "0.0.0-next.
|
|
53
|
-
"@orpc/server": "0.0.0-next.
|
|
54
|
-
"@orpc/shared": "0.0.0-next.
|
|
61
|
+
"@orpc/contract": "0.0.0-next.0c8e57d",
|
|
62
|
+
"@orpc/server": "0.0.0-next.0c8e57d",
|
|
63
|
+
"@orpc/shared": "0.0.0-next.0c8e57d"
|
|
55
64
|
},
|
|
56
65
|
"devDependencies": {
|
|
57
66
|
"@readme/openapi-parser": "^2.6.0",
|
|
58
67
|
"zod": "^3.24.1"
|
|
59
68
|
},
|
|
60
69
|
"scripts": {
|
|
61
|
-
"build": "tsup --
|
|
70
|
+
"build": "tsup --onSuccess='tsc -b --noCheck'",
|
|
62
71
|
"build:watch": "pnpm run build --watch",
|
|
63
72
|
"type:check": "tsc -b"
|
|
64
73
|
}
|