@orpc/openapi 0.0.0-next.da8ae32 → 0.0.0-next.df024bb
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/README.md +91 -0
- package/dist/adapters/fetch/index.d.mts +14 -0
- package/dist/adapters/fetch/index.d.ts +14 -0
- package/dist/adapters/fetch/index.mjs +10 -0
- package/dist/adapters/hono/index.d.mts +7 -0
- package/dist/adapters/hono/index.d.ts +7 -0
- package/dist/adapters/hono/index.mjs +10 -0
- package/dist/adapters/next/index.d.mts +7 -0
- package/dist/adapters/next/index.d.ts +7 -0
- package/dist/adapters/next/index.mjs +10 -0
- package/dist/adapters/node/index.d.mts +14 -0
- package/dist/adapters/node/index.d.ts +14 -0
- package/dist/adapters/node/index.mjs +31 -0
- package/dist/adapters/standard/index.d.mts +24 -0
- package/dist/adapters/standard/index.d.ts +24 -0
- package/dist/adapters/standard/index.mjs +7 -0
- package/dist/index.d.mts +169 -0
- package/dist/index.d.ts +169 -0
- package/dist/{index.js → index.mjs} +160 -101
- package/dist/shared/openapi.BHG_gu5Z.mjs +8 -0
- package/dist/shared/openapi.BcJH4F9P.mjs +27 -0
- package/dist/shared/openapi.CDsfPHgw.mjs +148 -0
- package/dist/shared/openapi.Dz_6xooR.d.mts +7 -0
- package/dist/shared/openapi.Dz_6xooR.d.ts +7 -0
- package/package.json +28 -32
- package/dist/chunk-DRV7KYES.js +0 -420
- package/dist/chunk-HC5PVG4R.js +0 -52
- package/dist/chunk-NHYWV7BW.js +0 -32
- package/dist/fetch.js +0 -9
- package/dist/hono.js +0 -9
- package/dist/next.js +0 -9
- package/dist/node.js +0 -30
- package/dist/src/adapters/fetch/index.d.ts +0 -2
- package/dist/src/adapters/fetch/openapi-handler.d.ts +0 -11
- package/dist/src/adapters/hono/index.d.ts +0 -2
- package/dist/src/adapters/next/index.d.ts +0 -2
- package/dist/src/adapters/node/index.d.ts +0 -2
- package/dist/src/adapters/node/openapi-handler.d.ts +0 -11
- package/dist/src/adapters/standard/bracket-notation.d.ts +0 -84
- package/dist/src/adapters/standard/index.d.ts +0 -6
- package/dist/src/adapters/standard/openapi-codec.d.ts +0 -15
- package/dist/src/adapters/standard/openapi-handler.d.ts +0 -7
- package/dist/src/adapters/standard/openapi-matcher.d.ts +0 -20
- package/dist/src/adapters/standard/openapi-serializer.d.ts +0 -11
- package/dist/src/index.d.ts +0 -17
- package/dist/src/json-serializer.d.ts +0 -5
- package/dist/src/openapi-content-builder.d.ts +0 -10
- package/dist/src/openapi-error.d.ts +0 -3
- package/dist/src/openapi-generator.d.ts +0 -67
- package/dist/src/openapi-input-structure-parser.d.ts +0 -22
- package/dist/src/openapi-operation-extender.d.ts +0 -7
- package/dist/src/openapi-output-structure-parser.d.ts +0 -18
- package/dist/src/openapi-parameters-builder.d.ts +0 -12
- package/dist/src/openapi-path-parser.d.ts +0 -8
- package/dist/src/openapi.d.ts +0 -3
- package/dist/src/schema-converter.d.ts +0 -16
- package/dist/src/schema-utils.d.ts +0 -11
- package/dist/src/schema.d.ts +0 -12
- package/dist/src/utils.d.ts +0 -3
- package/dist/standard.js +0 -14
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from
|
|
1
|
+
import { isProcedure, eachAllContractProcedure } from '@orpc/server';
|
|
2
|
+
import { OpenApiBuilder } from 'openapi3-ts/oas31';
|
|
3
|
+
export { OpenApiBuilder } from 'openapi3-ts/oas31';
|
|
4
|
+
import { findDeepMatches, isObject, get, omit, group } from '@orpc/shared';
|
|
5
|
+
import { fallbackORPCErrorStatus } from '@orpc/client';
|
|
6
|
+
import { fallbackContractConfig, getEventIteratorSchemaDetails } from '@orpc/contract';
|
|
7
|
+
import { OpenAPIJsonSerializer } from '@orpc/openapi-client/standard';
|
|
8
|
+
import * as draft202012 from 'json-schema-typed/draft-2020-12';
|
|
9
|
+
export { draft202012 as JSONSchema };
|
|
10
|
+
export { Format as JSONSchemaFormat } from 'json-schema-typed/draft-2020-12';
|
|
11
|
+
import { t as toOpenAPI31RoutePattern } from './shared/openapi.BHG_gu5Z.mjs';
|
|
12
|
+
export { s as standardizeHTTPPath } from './shared/openapi.BHG_gu5Z.mjs';
|
|
5
13
|
|
|
6
|
-
|
|
7
|
-
import { isProcedure } from "@orpc/server";
|
|
8
|
-
var OPERATION_EXTENDER_SYMBOL = Symbol("ORPC_OPERATION_EXTENDER");
|
|
14
|
+
const OPERATION_EXTENDER_SYMBOL = Symbol("ORPC_OPERATION_EXTENDER");
|
|
9
15
|
function setOperationExtender(o, extend) {
|
|
10
16
|
return new Proxy(o, {
|
|
11
17
|
get(target, prop, receiver) {
|
|
@@ -49,12 +55,7 @@ function extendOperation(operation, procedure) {
|
|
|
49
55
|
return currentOperation;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
import { OpenApiBuilder } from "openapi3-ts/oas31";
|
|
54
|
-
|
|
55
|
-
// src/openapi-content-builder.ts
|
|
56
|
-
import { findDeepMatches } from "@orpc/shared";
|
|
57
|
-
var OpenAPIContentBuilder = class {
|
|
58
|
+
class OpenAPIContentBuilder {
|
|
58
59
|
constructor(schemaUtils) {
|
|
59
60
|
this.schemaUtils = schemaUtils;
|
|
60
61
|
}
|
|
@@ -77,20 +78,12 @@ var OpenAPIContentBuilder = class {
|
|
|
77
78
|
}
|
|
78
79
|
return content;
|
|
79
80
|
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// src/openapi-generator.ts
|
|
83
|
-
import { fallbackContractConfig as fallbackContractConfig2, fallbackORPCErrorStatus } from "@orpc/contract";
|
|
84
|
-
import { eachAllContractProcedure } from "@orpc/server";
|
|
85
|
-
import { group } from "@orpc/shared";
|
|
81
|
+
}
|
|
86
82
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
};
|
|
83
|
+
class OpenAPIError extends Error {
|
|
84
|
+
}
|
|
90
85
|
|
|
91
|
-
|
|
92
|
-
import { fallbackContractConfig } from "@orpc/contract";
|
|
93
|
-
var OpenAPIInputStructureParser = class {
|
|
86
|
+
class OpenAPIInputStructureParser {
|
|
94
87
|
constructor(schemaConverter, schemaUtils, pathParser) {
|
|
95
88
|
this.schemaConverter = schemaConverter;
|
|
96
89
|
this.schemaUtils = schemaUtils;
|
|
@@ -181,10 +174,9 @@ var OpenAPIInputStructureParser = class {
|
|
|
181
174
|
bodySchema: method !== "GET" ? rest : void 0
|
|
182
175
|
};
|
|
183
176
|
}
|
|
184
|
-
}
|
|
177
|
+
}
|
|
185
178
|
|
|
186
|
-
|
|
187
|
-
var OpenAPIOutputStructureParser = class {
|
|
179
|
+
class OpenAPIOutputStructureParser {
|
|
188
180
|
constructor(schemaConverter, schemaUtils) {
|
|
189
181
|
this.schemaConverter = schemaConverter;
|
|
190
182
|
this.schemaUtils = schemaUtils;
|
|
@@ -226,11 +218,9 @@ var OpenAPIOutputStructureParser = class {
|
|
|
226
218
|
bodySchema: outputSchema
|
|
227
219
|
};
|
|
228
220
|
}
|
|
229
|
-
}
|
|
221
|
+
}
|
|
230
222
|
|
|
231
|
-
|
|
232
|
-
import { get, isObject, omit } from "@orpc/shared";
|
|
233
|
-
var OpenAPIParametersBuilder = class {
|
|
223
|
+
class OpenAPIParametersBuilder {
|
|
234
224
|
build(paramIn, jsonSchema, options) {
|
|
235
225
|
const parameters = [];
|
|
236
226
|
for (const name in jsonSchema.properties) {
|
|
@@ -264,10 +254,9 @@ var OpenAPIParametersBuilder = class {
|
|
|
264
254
|
}
|
|
265
255
|
return headersObject;
|
|
266
256
|
}
|
|
267
|
-
}
|
|
257
|
+
}
|
|
268
258
|
|
|
269
|
-
|
|
270
|
-
var OpenAPIPathParser = class {
|
|
259
|
+
class OpenAPIPathParser {
|
|
271
260
|
parseDynamicParams(path) {
|
|
272
261
|
const raws = path.match(/\{([^}]+)\}/g) ?? [];
|
|
273
262
|
return raws.map((raw) => {
|
|
@@ -275,10 +264,9 @@ var OpenAPIPathParser = class {
|
|
|
275
264
|
return { name, raw };
|
|
276
265
|
});
|
|
277
266
|
}
|
|
278
|
-
}
|
|
267
|
+
}
|
|
279
268
|
|
|
280
|
-
|
|
281
|
-
var CompositeSchemaConverter = class {
|
|
269
|
+
class CompositeSchemaConverter {
|
|
282
270
|
converters;
|
|
283
271
|
constructor(converters) {
|
|
284
272
|
this.converters = converters;
|
|
@@ -294,15 +282,9 @@ var CompositeSchemaConverter = class {
|
|
|
294
282
|
}
|
|
295
283
|
return {};
|
|
296
284
|
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// src/schema-utils.ts
|
|
300
|
-
import { isObject as isObject2 } from "@orpc/shared";
|
|
285
|
+
}
|
|
301
286
|
|
|
302
|
-
|
|
303
|
-
import * as JSONSchema from "json-schema-typed/draft-2020-12";
|
|
304
|
-
import { Format } from "json-schema-typed/draft-2020-12";
|
|
305
|
-
var NON_LOGIC_KEYWORDS = [
|
|
287
|
+
const NON_LOGIC_KEYWORDS = [
|
|
306
288
|
// Core Documentation Keywords
|
|
307
289
|
"$anchor",
|
|
308
290
|
"$comment",
|
|
@@ -330,13 +312,12 @@ var NON_LOGIC_KEYWORDS = [
|
|
|
330
312
|
"$dynamicRef"
|
|
331
313
|
];
|
|
332
314
|
|
|
333
|
-
|
|
334
|
-
var SchemaUtils = class {
|
|
315
|
+
class SchemaUtils {
|
|
335
316
|
isFileSchema(schema) {
|
|
336
|
-
return
|
|
317
|
+
return isObject(schema) && schema.type === "string" && typeof schema.contentMediaType === "string";
|
|
337
318
|
}
|
|
338
319
|
isObjectSchema(schema) {
|
|
339
|
-
return
|
|
320
|
+
return isObject(schema) && schema.type === "object";
|
|
340
321
|
}
|
|
341
322
|
isAnySchema(schema) {
|
|
342
323
|
return schema === true || Object.keys(schema).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
|
|
@@ -359,7 +340,7 @@ var SchemaUtils = class {
|
|
|
359
340
|
}, {});
|
|
360
341
|
matched.required = schema.required?.filter((key) => separatedProperties.includes(key));
|
|
361
342
|
matched.examples = schema.examples?.map((example) => {
|
|
362
|
-
if (!
|
|
343
|
+
if (!isObject(example)) {
|
|
363
344
|
return example;
|
|
364
345
|
}
|
|
365
346
|
return Object.entries(example).reduce((acc, [key, value]) => {
|
|
@@ -375,7 +356,7 @@ var SchemaUtils = class {
|
|
|
375
356
|
}, {});
|
|
376
357
|
rest.required = schema.required?.filter((key) => !separatedProperties.includes(key));
|
|
377
358
|
rest.examples = schema.examples?.map((example) => {
|
|
378
|
-
if (!
|
|
359
|
+
if (!isObject(example)) {
|
|
379
360
|
return example;
|
|
380
361
|
}
|
|
381
362
|
return Object.entries(example).reduce((acc, [key, value]) => {
|
|
@@ -415,10 +396,9 @@ var SchemaUtils = class {
|
|
|
415
396
|
}
|
|
416
397
|
return [matches, schema];
|
|
417
398
|
}
|
|
418
|
-
}
|
|
399
|
+
}
|
|
419
400
|
|
|
420
|
-
|
|
421
|
-
var OpenAPIGenerator = class {
|
|
401
|
+
class OpenAPIGenerator {
|
|
422
402
|
contentBuilder;
|
|
423
403
|
parametersBuilder;
|
|
424
404
|
schemaConverter;
|
|
@@ -435,7 +415,7 @@ var OpenAPIGenerator = class {
|
|
|
435
415
|
this.parametersBuilder = options?.parametersBuilder ?? new OpenAPIParametersBuilder();
|
|
436
416
|
this.schemaConverter = new CompositeSchemaConverter(options?.schemaConverters ?? []);
|
|
437
417
|
this.schemaUtils = options?.schemaUtils ?? new SchemaUtils();
|
|
438
|
-
this.jsonSerializer = options?.jsonSerializer ?? new
|
|
418
|
+
this.jsonSerializer = options?.jsonSerializer ?? new OpenAPIJsonSerializer();
|
|
439
419
|
this.contentBuilder = options?.contentBuilder ?? new OpenAPIContentBuilder(this.schemaUtils);
|
|
440
420
|
this.pathParser = new OpenAPIPathParser();
|
|
441
421
|
this.inputStructureParser = options?.inputStructureParser ?? new OpenAPIInputStructureParser(this.schemaConverter, this.schemaUtils, this.pathParser);
|
|
@@ -460,28 +440,125 @@ var OpenAPIGenerator = class {
|
|
|
460
440
|
if (this.ignoreUndefinedPathProcedures && def.route?.path === void 0) {
|
|
461
441
|
return;
|
|
462
442
|
}
|
|
463
|
-
const method =
|
|
464
|
-
const httpPath = def.route?.path ?
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
443
|
+
const method = fallbackContractConfig("defaultMethod", def.route?.method);
|
|
444
|
+
const httpPath = def.route?.path ? toOpenAPI31RoutePattern(def.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
|
|
445
|
+
const { parameters, requestBody } = (() => {
|
|
446
|
+
const eventIteratorSchemaDetails = getEventIteratorSchemaDetails(def.inputSchema);
|
|
447
|
+
if (eventIteratorSchemaDetails) {
|
|
448
|
+
const requestBody3 = {
|
|
449
|
+
required: true,
|
|
450
|
+
content: {
|
|
451
|
+
"text/event-stream": {
|
|
452
|
+
schema: {
|
|
453
|
+
oneOf: [
|
|
454
|
+
{
|
|
455
|
+
type: "object",
|
|
456
|
+
properties: {
|
|
457
|
+
event: { type: "string", const: "message" },
|
|
458
|
+
data: this.schemaConverter.convert(eventIteratorSchemaDetails.yields, { strategy: "input" }),
|
|
459
|
+
id: { type: "string" },
|
|
460
|
+
retry: { type: "number" }
|
|
461
|
+
},
|
|
462
|
+
required: ["event", "data"]
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
type: "object",
|
|
466
|
+
properties: {
|
|
467
|
+
event: { type: "string", const: "done" },
|
|
468
|
+
data: this.schemaConverter.convert(eventIteratorSchemaDetails.returns, { strategy: "input" }),
|
|
469
|
+
id: { type: "string" },
|
|
470
|
+
retry: { type: "number" }
|
|
471
|
+
},
|
|
472
|
+
required: ["event", "data"]
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
type: "object",
|
|
476
|
+
properties: {
|
|
477
|
+
event: { type: "string", const: "error" },
|
|
478
|
+
data: {},
|
|
479
|
+
id: { type: "string" },
|
|
480
|
+
retry: { type: "number" }
|
|
481
|
+
},
|
|
482
|
+
required: ["event", "data"]
|
|
483
|
+
}
|
|
484
|
+
]
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
return { requestBody: requestBody3, parameters: [] };
|
|
490
|
+
}
|
|
491
|
+
const inputStructure = fallbackContractConfig("defaultInputStructure", def.route?.inputStructure);
|
|
492
|
+
const { paramsSchema, querySchema, headersSchema, bodySchema } = this.inputStructureParser.parse(contract, inputStructure);
|
|
493
|
+
const params = paramsSchema ? this.parametersBuilder.build("path", paramsSchema, {
|
|
494
|
+
required: true
|
|
495
|
+
}) : [];
|
|
496
|
+
const query = querySchema ? this.parametersBuilder.build("query", querySchema) : [];
|
|
497
|
+
const headers = headersSchema ? this.parametersBuilder.build("header", headersSchema) : [];
|
|
498
|
+
const parameters2 = [...params, ...query, ...headers];
|
|
499
|
+
const requestBody2 = bodySchema !== void 0 ? {
|
|
500
|
+
required: this.schemaUtils.isUndefinableSchema(bodySchema),
|
|
501
|
+
content: this.contentBuilder.build(bodySchema)
|
|
502
|
+
} : void 0;
|
|
503
|
+
return { parameters: parameters2, requestBody: requestBody2 };
|
|
504
|
+
})();
|
|
505
|
+
const { responses } = (() => {
|
|
506
|
+
const eventIteratorSchemaDetails = getEventIteratorSchemaDetails(def.outputSchema);
|
|
507
|
+
if (eventIteratorSchemaDetails) {
|
|
508
|
+
const responses3 = {};
|
|
509
|
+
responses3[fallbackContractConfig("defaultSuccessStatus", def.route?.successStatus)] = {
|
|
510
|
+
description: fallbackContractConfig("defaultSuccessDescription", def.route?.successDescription),
|
|
511
|
+
content: {
|
|
512
|
+
"text/event-stream": {
|
|
513
|
+
schema: {
|
|
514
|
+
oneOf: [
|
|
515
|
+
{
|
|
516
|
+
type: "object",
|
|
517
|
+
properties: {
|
|
518
|
+
event: { type: "string", const: "message" },
|
|
519
|
+
data: this.schemaConverter.convert(eventIteratorSchemaDetails.yields, { strategy: "input" }),
|
|
520
|
+
id: { type: "string" },
|
|
521
|
+
retry: { type: "number" }
|
|
522
|
+
},
|
|
523
|
+
required: ["event", "data"]
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
type: "object",
|
|
527
|
+
properties: {
|
|
528
|
+
event: { type: "string", const: "done" },
|
|
529
|
+
data: this.schemaConverter.convert(eventIteratorSchemaDetails.returns, { strategy: "input" }),
|
|
530
|
+
id: { type: "string" },
|
|
531
|
+
retry: { type: "number" }
|
|
532
|
+
},
|
|
533
|
+
required: ["event", "data"]
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
type: "object",
|
|
537
|
+
properties: {
|
|
538
|
+
event: { type: "string", const: "error" },
|
|
539
|
+
data: {},
|
|
540
|
+
id: { type: "string" },
|
|
541
|
+
retry: { type: "number" }
|
|
542
|
+
},
|
|
543
|
+
required: ["event", "data"]
|
|
544
|
+
}
|
|
545
|
+
]
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
return { responses: responses3 };
|
|
551
|
+
}
|
|
552
|
+
const outputStructure = fallbackContractConfig("defaultOutputStructure", def.route?.outputStructure);
|
|
553
|
+
const { headersSchema: resHeadersSchema, bodySchema: resBodySchema } = this.outputStructureParser.parse(contract, outputStructure);
|
|
554
|
+
const responses2 = {};
|
|
555
|
+
responses2[fallbackContractConfig("defaultSuccessStatus", def.route?.successStatus)] = {
|
|
556
|
+
description: fallbackContractConfig("defaultSuccessDescription", def.route?.successDescription),
|
|
557
|
+
content: resBodySchema !== void 0 ? this.contentBuilder.build(resBodySchema) : void 0,
|
|
558
|
+
headers: resHeadersSchema !== void 0 ? this.parametersBuilder.buildHeadersObject(resHeadersSchema) : void 0
|
|
559
|
+
};
|
|
560
|
+
return { responses: responses2 };
|
|
561
|
+
})();
|
|
485
562
|
const errors = group(Object.entries(def.errorMap ?? {}).filter(([_, config]) => config).map(([code, config]) => ({
|
|
486
563
|
...config,
|
|
487
564
|
code,
|
|
@@ -573,30 +650,12 @@ var OpenAPIGenerator = class {
|
|
|
573
650
|
}
|
|
574
651
|
}
|
|
575
652
|
});
|
|
576
|
-
return this.jsonSerializer.serialize(builder.getSpec());
|
|
653
|
+
return this.jsonSerializer.serialize(builder.getSpec())[0];
|
|
577
654
|
}
|
|
578
|
-
}
|
|
655
|
+
}
|
|
579
656
|
|
|
580
|
-
|
|
581
|
-
var oo = {
|
|
657
|
+
const oo = {
|
|
582
658
|
spec: setOperationExtender
|
|
583
659
|
};
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
JSONSchema,
|
|
587
|
-
Format as JSONSchemaFormat,
|
|
588
|
-
JSONSerializer,
|
|
589
|
-
NON_LOGIC_KEYWORDS,
|
|
590
|
-
OpenAPIContentBuilder,
|
|
591
|
-
OpenAPIGenerator,
|
|
592
|
-
OpenAPIParametersBuilder,
|
|
593
|
-
OpenAPIPathParser,
|
|
594
|
-
OpenApiBuilder,
|
|
595
|
-
SchemaUtils,
|
|
596
|
-
extendOperation,
|
|
597
|
-
getOperationExtender,
|
|
598
|
-
oo,
|
|
599
|
-
setOperationExtender,
|
|
600
|
-
standardizeHTTPPath
|
|
601
|
-
};
|
|
602
|
-
//# sourceMappingURL=index.js.map
|
|
660
|
+
|
|
661
|
+
export { CompositeSchemaConverter, NON_LOGIC_KEYWORDS, OpenAPIContentBuilder, OpenAPIGenerator, OpenAPIParametersBuilder, OpenAPIPathParser, SchemaUtils, extendOperation, getOperationExtender, oo, setOperationExtender, toOpenAPI31RoutePattern };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
function standardizeHTTPPath(path) {
|
|
2
|
+
return `/${path.replace(/\/{2,}/g, "/").replace(/^\/|\/$/g, "")}`;
|
|
3
|
+
}
|
|
4
|
+
function toOpenAPI31RoutePattern(path) {
|
|
5
|
+
return standardizeHTTPPath(path).replace(/\{\+([^}]+)\}/g, "{$1}");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export { standardizeHTTPPath as s, toOpenAPI31RoutePattern as t };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { StandardHandler } from '@orpc/server/standard';
|
|
2
|
+
import { toStandardLazyRequest, toFetchResponse } from '@orpc/standard-server-fetch';
|
|
3
|
+
import { a as OpenAPIMatcher, O as OpenAPICodec } from './openapi.CDsfPHgw.mjs';
|
|
4
|
+
|
|
5
|
+
class OpenAPIHandler {
|
|
6
|
+
standardHandler;
|
|
7
|
+
constructor(router, options) {
|
|
8
|
+
const matcher = options?.matcher ?? new OpenAPIMatcher();
|
|
9
|
+
const codec = options?.codec ?? new OpenAPICodec();
|
|
10
|
+
this.standardHandler = new StandardHandler(router, matcher, codec, options);
|
|
11
|
+
}
|
|
12
|
+
async handle(request, ...[
|
|
13
|
+
options = {}
|
|
14
|
+
]) {
|
|
15
|
+
const standardRequest = toStandardLazyRequest(request);
|
|
16
|
+
const result = await this.standardHandler.handle(standardRequest, options);
|
|
17
|
+
if (!result.matched) {
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
matched: true,
|
|
22
|
+
response: toFetchResponse(result.response, options)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { OpenAPIHandler as O };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { fallbackContractConfig } from '@orpc/contract';
|
|
2
|
+
import { OpenAPISerializer } from '@orpc/openapi-client/standard';
|
|
3
|
+
import { isObject } from '@orpc/shared';
|
|
4
|
+
import { eachContractProcedure, convertPathToHttpPath, isProcedure, getLazyRouterPrefix, unlazy, getRouterChild, createContractedProcedure } from '@orpc/server';
|
|
5
|
+
import { createRouter, addRoute, findRoute } from 'rou3';
|
|
6
|
+
import { s as standardizeHTTPPath } from './openapi.BHG_gu5Z.mjs';
|
|
7
|
+
|
|
8
|
+
class OpenAPICodec {
|
|
9
|
+
constructor(serializer = new OpenAPISerializer()) {
|
|
10
|
+
this.serializer = serializer;
|
|
11
|
+
}
|
|
12
|
+
async decode(request, params, procedure) {
|
|
13
|
+
const inputStructure = fallbackContractConfig("defaultInputStructure", procedure["~orpc"].route.inputStructure);
|
|
14
|
+
if (inputStructure === "compact") {
|
|
15
|
+
const data = request.method === "GET" ? this.serializer.deserialize(request.url.searchParams) : this.serializer.deserialize(await request.body());
|
|
16
|
+
if (data === void 0) {
|
|
17
|
+
return params;
|
|
18
|
+
}
|
|
19
|
+
if (isObject(data)) {
|
|
20
|
+
return {
|
|
21
|
+
...params,
|
|
22
|
+
...data
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
const deserializeSearchParams = () => {
|
|
28
|
+
return this.serializer.deserialize(request.url.searchParams);
|
|
29
|
+
};
|
|
30
|
+
return {
|
|
31
|
+
params,
|
|
32
|
+
get query() {
|
|
33
|
+
const value = deserializeSearchParams();
|
|
34
|
+
Object.defineProperty(this, "query", { value, writable: true });
|
|
35
|
+
return value;
|
|
36
|
+
},
|
|
37
|
+
set query(value) {
|
|
38
|
+
Object.defineProperty(this, "query", { value, writable: true });
|
|
39
|
+
},
|
|
40
|
+
headers: request.headers,
|
|
41
|
+
body: this.serializer.deserialize(await request.body())
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
encode(output, procedure) {
|
|
45
|
+
const successStatus = fallbackContractConfig("defaultSuccessStatus", procedure["~orpc"].route.successStatus);
|
|
46
|
+
const outputStructure = fallbackContractConfig("defaultOutputStructure", procedure["~orpc"].route.outputStructure);
|
|
47
|
+
if (outputStructure === "compact") {
|
|
48
|
+
return {
|
|
49
|
+
status: successStatus,
|
|
50
|
+
headers: {},
|
|
51
|
+
body: this.serializer.serialize(output)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (!isObject(output)) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
'Invalid output structure for "detailed" output. Expected format: { body: any, headers?: Record<string, string | string[] | undefined> }'
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
status: successStatus,
|
|
61
|
+
headers: output.headers ?? {},
|
|
62
|
+
body: this.serializer.serialize(output.body)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
encodeError(error) {
|
|
66
|
+
return {
|
|
67
|
+
status: error.status,
|
|
68
|
+
headers: {},
|
|
69
|
+
body: this.serializer.serialize(error.toJSON())
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class OpenAPIMatcher {
|
|
75
|
+
tree = createRouter();
|
|
76
|
+
pendingRouters = [];
|
|
77
|
+
init(router, path = []) {
|
|
78
|
+
const laziedOptions = eachContractProcedure({
|
|
79
|
+
router,
|
|
80
|
+
path
|
|
81
|
+
}, ({ path: path2, contract }) => {
|
|
82
|
+
const method = fallbackContractConfig("defaultMethod", contract["~orpc"].route.method);
|
|
83
|
+
const httpPath = contract["~orpc"].route.path ? toRou3Pattern(contract["~orpc"].route.path) : convertPathToHttpPath(path2);
|
|
84
|
+
if (isProcedure(contract)) {
|
|
85
|
+
addRoute(this.tree, method, httpPath, {
|
|
86
|
+
path: path2,
|
|
87
|
+
contract,
|
|
88
|
+
procedure: contract,
|
|
89
|
+
// this mean dev not used contract-first so we can used contract as procedure directly
|
|
90
|
+
router
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
addRoute(this.tree, method, httpPath, {
|
|
94
|
+
path: path2,
|
|
95
|
+
contract,
|
|
96
|
+
procedure: void 0,
|
|
97
|
+
router
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
this.pendingRouters.push(...laziedOptions.map((option) => ({
|
|
102
|
+
...option,
|
|
103
|
+
httpPathPrefix: convertPathToHttpPath(option.path),
|
|
104
|
+
laziedPrefix: getLazyRouterPrefix(option.lazied)
|
|
105
|
+
})));
|
|
106
|
+
}
|
|
107
|
+
async match(method, pathname) {
|
|
108
|
+
if (this.pendingRouters.length) {
|
|
109
|
+
const newPendingRouters = [];
|
|
110
|
+
for (const pendingRouter of this.pendingRouters) {
|
|
111
|
+
if (!pendingRouter.laziedPrefix || pathname.startsWith(pendingRouter.laziedPrefix) || pathname.startsWith(pendingRouter.httpPathPrefix)) {
|
|
112
|
+
const { default: router } = await unlazy(pendingRouter.lazied);
|
|
113
|
+
this.init(router, pendingRouter.path);
|
|
114
|
+
} else {
|
|
115
|
+
newPendingRouters.push(pendingRouter);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
this.pendingRouters = newPendingRouters;
|
|
119
|
+
}
|
|
120
|
+
const match = findRoute(this.tree, method, pathname);
|
|
121
|
+
if (!match) {
|
|
122
|
+
return void 0;
|
|
123
|
+
}
|
|
124
|
+
if (!match.data.procedure) {
|
|
125
|
+
const { default: maybeProcedure } = await unlazy(getRouterChild(match.data.router, ...match.data.path));
|
|
126
|
+
if (!isProcedure(maybeProcedure)) {
|
|
127
|
+
throw new Error(`
|
|
128
|
+
[Contract-First] Missing or invalid implementation for procedure at path: ${convertPathToHttpPath(match.data.path)}.
|
|
129
|
+
Ensure that the procedure is correctly defined and matches the expected contract.
|
|
130
|
+
`);
|
|
131
|
+
}
|
|
132
|
+
match.data.procedure = createContractedProcedure(match.data.contract, maybeProcedure);
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
path: match.data.path,
|
|
136
|
+
procedure: match.data.procedure,
|
|
137
|
+
params: match.params ? decodeParams(match.params) : void 0
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function toRou3Pattern(path) {
|
|
142
|
+
return standardizeHTTPPath(path).replace(/\{\+([^}]+)\}/g, "**:$1").replace(/\{([^}]+)\}/g, ":$1");
|
|
143
|
+
}
|
|
144
|
+
function decodeParams(params) {
|
|
145
|
+
return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, decodeURIComponent(value)]));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export { OpenAPICodec as O, OpenAPIMatcher as a };
|
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.df024bb",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://orpc.unnoq.com",
|
|
7
7
|
"repository": {
|
|
@@ -15,61 +15,57 @@
|
|
|
15
15
|
],
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
18
|
-
"types": "./dist/
|
|
19
|
-
"import": "./dist/index.
|
|
20
|
-
"default": "./dist/index.
|
|
18
|
+
"types": "./dist/index.d.mts",
|
|
19
|
+
"import": "./dist/index.mjs",
|
|
20
|
+
"default": "./dist/index.mjs"
|
|
21
21
|
},
|
|
22
22
|
"./standard": {
|
|
23
|
-
"types": "./dist/
|
|
24
|
-
"import": "./dist/standard.
|
|
25
|
-
"default": "./dist/standard.
|
|
23
|
+
"types": "./dist/adapters/standard/index.d.mts",
|
|
24
|
+
"import": "./dist/adapters/standard/index.mjs",
|
|
25
|
+
"default": "./dist/adapters/standard/index.mjs"
|
|
26
26
|
},
|
|
27
27
|
"./fetch": {
|
|
28
|
-
"types": "./dist/
|
|
29
|
-
"import": "./dist/fetch.
|
|
30
|
-
"default": "./dist/fetch.
|
|
28
|
+
"types": "./dist/adapters/fetch/index.d.mts",
|
|
29
|
+
"import": "./dist/adapters/fetch/index.mjs",
|
|
30
|
+
"default": "./dist/adapters/fetch/index.mjs"
|
|
31
31
|
},
|
|
32
32
|
"./hono": {
|
|
33
|
-
"types": "./dist/
|
|
34
|
-
"import": "./dist/hono.
|
|
35
|
-
"default": "./dist/hono.
|
|
33
|
+
"types": "./dist/adapters/hono/index.d.mts",
|
|
34
|
+
"import": "./dist/adapters/hono/index.mjs",
|
|
35
|
+
"default": "./dist/adapters/hono/index.mjs"
|
|
36
36
|
},
|
|
37
37
|
"./next": {
|
|
38
|
-
"types": "./dist/
|
|
39
|
-
"import": "./dist/next.
|
|
40
|
-
"default": "./dist/next.
|
|
38
|
+
"types": "./dist/adapters/next/index.d.mts",
|
|
39
|
+
"import": "./dist/adapters/next/index.mjs",
|
|
40
|
+
"default": "./dist/adapters/next/index.mjs"
|
|
41
41
|
},
|
|
42
42
|
"./node": {
|
|
43
|
-
"types": "./dist/
|
|
44
|
-
"import": "./dist/node.
|
|
45
|
-
"default": "./dist/node.
|
|
46
|
-
},
|
|
47
|
-
"./🔒/*": {
|
|
48
|
-
"types": "./dist/src/*.d.ts"
|
|
43
|
+
"types": "./dist/adapters/node/index.d.mts",
|
|
44
|
+
"import": "./dist/adapters/node/index.mjs",
|
|
45
|
+
"default": "./dist/adapters/node/index.mjs"
|
|
49
46
|
}
|
|
50
47
|
},
|
|
51
48
|
"files": [
|
|
52
|
-
"!**/*.map",
|
|
53
|
-
"!**/*.tsbuildinfo",
|
|
54
49
|
"dist"
|
|
55
50
|
],
|
|
56
51
|
"dependencies": {
|
|
57
|
-
"escape-string-regexp": "^5.0.0",
|
|
58
|
-
"fast-content-type-parse": "^2.0.0",
|
|
59
52
|
"json-schema-typed": "^8.0.1",
|
|
60
53
|
"openapi3-ts": "^4.4.0",
|
|
61
54
|
"rou3": "^0.5.1",
|
|
62
|
-
"
|
|
63
|
-
"@orpc/
|
|
64
|
-
"@orpc/
|
|
65
|
-
"@orpc/shared": "0.0.0-next.
|
|
55
|
+
"@orpc/client": "0.0.0-next.df024bb",
|
|
56
|
+
"@orpc/openapi-client": "0.0.0-next.df024bb",
|
|
57
|
+
"@orpc/contract": "0.0.0-next.df024bb",
|
|
58
|
+
"@orpc/shared": "0.0.0-next.df024bb",
|
|
59
|
+
"@orpc/server": "0.0.0-next.df024bb",
|
|
60
|
+
"@orpc/standard-server": "0.0.0-next.df024bb",
|
|
61
|
+
"@orpc/standard-server-fetch": "0.0.0-next.df024bb",
|
|
62
|
+
"@orpc/standard-server-node": "0.0.0-next.df024bb"
|
|
66
63
|
},
|
|
67
64
|
"devDependencies": {
|
|
68
|
-
"@readme/openapi-parser": "^2.6.0",
|
|
69
65
|
"zod": "^3.24.1"
|
|
70
66
|
},
|
|
71
67
|
"scripts": {
|
|
72
|
-
"build": "
|
|
68
|
+
"build": "unbuild",
|
|
73
69
|
"build:watch": "pnpm run build --watch",
|
|
74
70
|
"type:check": "tsc -b"
|
|
75
71
|
}
|