@orpc/openapi 0.0.0-next.9fe2a8b → 0.0.0-next.a05fbfd

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.
Files changed (63) hide show
  1. package/README.md +91 -0
  2. package/dist/adapters/fetch/index.d.mts +14 -0
  3. package/dist/adapters/fetch/index.d.ts +14 -0
  4. package/dist/adapters/fetch/index.mjs +10 -0
  5. package/dist/adapters/hono/index.d.mts +7 -0
  6. package/dist/adapters/hono/index.d.ts +7 -0
  7. package/dist/adapters/hono/index.mjs +10 -0
  8. package/dist/adapters/next/index.d.mts +7 -0
  9. package/dist/adapters/next/index.d.ts +7 -0
  10. package/dist/adapters/next/index.mjs +10 -0
  11. package/dist/adapters/node/index.d.mts +14 -0
  12. package/dist/adapters/node/index.d.ts +14 -0
  13. package/dist/adapters/node/index.mjs +29 -0
  14. package/dist/adapters/standard/index.d.mts +24 -0
  15. package/dist/adapters/standard/index.d.ts +24 -0
  16. package/dist/adapters/standard/index.mjs +7 -0
  17. package/dist/index.d.mts +169 -0
  18. package/dist/index.d.ts +169 -0
  19. package/dist/{index.js → index.mjs} +211 -96
  20. package/dist/shared/openapi.BHG_gu5Z.mjs +8 -0
  21. package/dist/shared/openapi.CDsfPHgw.mjs +148 -0
  22. package/dist/shared/openapi.D0VMNR6V.mjs +25 -0
  23. package/dist/shared/openapi.Dz_6xooR.d.mts +7 -0
  24. package/dist/shared/openapi.Dz_6xooR.d.ts +7 -0
  25. package/package.json +31 -33
  26. package/dist/chunk-Q2LSK6YZ.js +0 -102
  27. package/dist/chunk-SOVQ5ARD.js +0 -650
  28. package/dist/chunk-VFGNQS5W.js +0 -25
  29. package/dist/fetch.js +0 -34
  30. package/dist/hono.js +0 -34
  31. package/dist/next.js +0 -34
  32. package/dist/node.js +0 -46
  33. package/dist/src/adapters/fetch/bracket-notation.d.ts +0 -84
  34. package/dist/src/adapters/fetch/index.d.ts +0 -10
  35. package/dist/src/adapters/fetch/input-structure-compact.d.ts +0 -6
  36. package/dist/src/adapters/fetch/input-structure-detailed.d.ts +0 -11
  37. package/dist/src/adapters/fetch/openapi-handler-server.d.ts +0 -7
  38. package/dist/src/adapters/fetch/openapi-handler-serverless.d.ts +0 -7
  39. package/dist/src/adapters/fetch/openapi-handler.d.ts +0 -32
  40. package/dist/src/adapters/fetch/openapi-payload-codec.d.ts +0 -15
  41. package/dist/src/adapters/fetch/openapi-procedure-matcher.d.ts +0 -19
  42. package/dist/src/adapters/fetch/schema-coercer.d.ts +0 -10
  43. package/dist/src/adapters/hono/index.d.ts +0 -2
  44. package/dist/src/adapters/next/index.d.ts +0 -2
  45. package/dist/src/adapters/node/index.d.ts +0 -5
  46. package/dist/src/adapters/node/openapi-handler-server.d.ts +0 -7
  47. package/dist/src/adapters/node/openapi-handler-serverless.d.ts +0 -7
  48. package/dist/src/adapters/node/openapi-handler.d.ts +0 -11
  49. package/dist/src/adapters/node/types.d.ts +0 -2
  50. package/dist/src/index.d.ts +0 -12
  51. package/dist/src/json-serializer.d.ts +0 -5
  52. package/dist/src/openapi-content-builder.d.ts +0 -10
  53. package/dist/src/openapi-error.d.ts +0 -3
  54. package/dist/src/openapi-generator.d.ts +0 -67
  55. package/dist/src/openapi-input-structure-parser.d.ts +0 -22
  56. package/dist/src/openapi-output-structure-parser.d.ts +0 -18
  57. package/dist/src/openapi-parameters-builder.d.ts +0 -12
  58. package/dist/src/openapi-path-parser.d.ts +0 -8
  59. package/dist/src/openapi.d.ts +0 -3
  60. package/dist/src/schema-converter.d.ts +0 -16
  61. package/dist/src/schema-utils.d.ts +0 -11
  62. package/dist/src/schema.d.ts +0 -12
  63. package/dist/src/utils.d.ts +0 -18
@@ -1,16 +1,61 @@
1
- import {
2
- JSONSerializer,
3
- forEachAllContractProcedure,
4
- forEachContractProcedure,
5
- standardizeHTTPPath
6
- } from "./chunk-Q2LSK6YZ.js";
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';
7
13
 
8
- // src/openapi.ts
9
- import { OpenApiBuilder } from "openapi3-ts/oas31";
14
+ const OPERATION_EXTENDER_SYMBOL = Symbol("ORPC_OPERATION_EXTENDER");
15
+ function setOperationExtender(o, extend) {
16
+ return new Proxy(o, {
17
+ get(target, prop, receiver) {
18
+ if (prop === OPERATION_EXTENDER_SYMBOL) {
19
+ return extend;
20
+ }
21
+ return Reflect.get(target, prop, receiver);
22
+ }
23
+ });
24
+ }
25
+ function getOperationExtender(o) {
26
+ return o[OPERATION_EXTENDER_SYMBOL];
27
+ }
28
+ function extendOperation(operation, procedure) {
29
+ const operationExtenders = [];
30
+ for (const errorItem of Object.values(procedure["~orpc"].errorMap)) {
31
+ const maybeExtender = getOperationExtender(errorItem);
32
+ if (maybeExtender) {
33
+ operationExtenders.push(maybeExtender);
34
+ }
35
+ }
36
+ if (isProcedure(procedure)) {
37
+ for (const middleware of procedure["~orpc"].middlewares) {
38
+ const maybeExtender = getOperationExtender(middleware);
39
+ if (maybeExtender) {
40
+ operationExtenders.push(maybeExtender);
41
+ }
42
+ }
43
+ }
44
+ let currentOperation = operation;
45
+ for (const extender of operationExtenders) {
46
+ if (typeof extender === "function") {
47
+ currentOperation = extender(currentOperation, procedure);
48
+ } else {
49
+ currentOperation = {
50
+ ...currentOperation,
51
+ ...extender
52
+ };
53
+ }
54
+ }
55
+ return currentOperation;
56
+ }
10
57
 
11
- // src/openapi-content-builder.ts
12
- import { findDeepMatches } from "@orpc/shared";
13
- var OpenAPIContentBuilder = class {
58
+ class OpenAPIContentBuilder {
14
59
  constructor(schemaUtils) {
15
60
  this.schemaUtils = schemaUtils;
16
61
  }
@@ -33,19 +78,12 @@ var OpenAPIContentBuilder = class {
33
78
  }
34
79
  return content;
35
80
  }
36
- };
81
+ }
37
82
 
38
- // src/openapi-generator.ts
39
- import { fallbackContractConfig as fallbackContractConfig2, fallbackORPCErrorStatus } from "@orpc/contract";
40
- import { group } from "@orpc/shared";
83
+ class OpenAPIError extends Error {
84
+ }
41
85
 
42
- // src/openapi-error.ts
43
- var OpenAPIError = class extends Error {
44
- };
45
-
46
- // src/openapi-input-structure-parser.ts
47
- import { fallbackContractConfig } from "@orpc/contract";
48
- var OpenAPIInputStructureParser = class {
86
+ class OpenAPIInputStructureParser {
49
87
  constructor(schemaConverter, schemaUtils, pathParser) {
50
88
  this.schemaConverter = schemaConverter;
51
89
  this.schemaUtils = schemaUtils;
@@ -136,10 +174,9 @@ var OpenAPIInputStructureParser = class {
136
174
  bodySchema: method !== "GET" ? rest : void 0
137
175
  };
138
176
  }
139
- };
177
+ }
140
178
 
141
- // src/openapi-output-structure-parser.ts
142
- var OpenAPIOutputStructureParser = class {
179
+ class OpenAPIOutputStructureParser {
143
180
  constructor(schemaConverter, schemaUtils) {
144
181
  this.schemaConverter = schemaConverter;
145
182
  this.schemaUtils = schemaUtils;
@@ -181,17 +218,15 @@ var OpenAPIOutputStructureParser = class {
181
218
  bodySchema: outputSchema
182
219
  };
183
220
  }
184
- };
221
+ }
185
222
 
186
- // src/openapi-parameters-builder.ts
187
- import { get, isPlainObject, omit } from "@orpc/shared";
188
- var OpenAPIParametersBuilder = class {
223
+ class OpenAPIParametersBuilder {
189
224
  build(paramIn, jsonSchema, options) {
190
225
  const parameters = [];
191
226
  for (const name in jsonSchema.properties) {
192
227
  const schema = jsonSchema.properties[name];
193
228
  const paramExamples = jsonSchema.examples?.filter((example) => {
194
- return isPlainObject(example) && name in example;
229
+ return isObject(example) && name in example;
195
230
  }).map((example) => {
196
231
  return example[name];
197
232
  });
@@ -219,10 +254,9 @@ var OpenAPIParametersBuilder = class {
219
254
  }
220
255
  return headersObject;
221
256
  }
222
- };
257
+ }
223
258
 
224
- // src/openapi-path-parser.ts
225
- var OpenAPIPathParser = class {
259
+ class OpenAPIPathParser {
226
260
  parseDynamicParams(path) {
227
261
  const raws = path.match(/\{([^}]+)\}/g) ?? [];
228
262
  return raws.map((raw) => {
@@ -230,10 +264,9 @@ var OpenAPIPathParser = class {
230
264
  return { name, raw };
231
265
  });
232
266
  }
233
- };
267
+ }
234
268
 
235
- // src/schema-converter.ts
236
- var CompositeSchemaConverter = class {
269
+ class CompositeSchemaConverter {
237
270
  converters;
238
271
  constructor(converters) {
239
272
  this.converters = converters;
@@ -249,15 +282,9 @@ var CompositeSchemaConverter = class {
249
282
  }
250
283
  return {};
251
284
  }
252
- };
253
-
254
- // src/schema-utils.ts
255
- import { isPlainObject as isPlainObject2 } from "@orpc/shared";
285
+ }
256
286
 
257
- // src/schema.ts
258
- import * as JSONSchema from "json-schema-typed/draft-2020-12";
259
- import { Format } from "json-schema-typed/draft-2020-12";
260
- var NON_LOGIC_KEYWORDS = [
287
+ const NON_LOGIC_KEYWORDS = [
261
288
  // Core Documentation Keywords
262
289
  "$anchor",
263
290
  "$comment",
@@ -285,13 +312,12 @@ var NON_LOGIC_KEYWORDS = [
285
312
  "$dynamicRef"
286
313
  ];
287
314
 
288
- // src/schema-utils.ts
289
- var SchemaUtils = class {
315
+ class SchemaUtils {
290
316
  isFileSchema(schema) {
291
- return typeof schema === "object" && schema.type === "string" && typeof schema.contentMediaType === "string";
317
+ return isObject(schema) && schema.type === "string" && typeof schema.contentMediaType === "string";
292
318
  }
293
319
  isObjectSchema(schema) {
294
- return typeof schema === "object" && schema.type === "object";
320
+ return isObject(schema) && schema.type === "object";
295
321
  }
296
322
  isAnySchema(schema) {
297
323
  return schema === true || Object.keys(schema).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
@@ -314,7 +340,7 @@ var SchemaUtils = class {
314
340
  }, {});
315
341
  matched.required = schema.required?.filter((key) => separatedProperties.includes(key));
316
342
  matched.examples = schema.examples?.map((example) => {
317
- if (!isPlainObject2(example)) {
343
+ if (!isObject(example)) {
318
344
  return example;
319
345
  }
320
346
  return Object.entries(example).reduce((acc, [key, value]) => {
@@ -330,7 +356,7 @@ var SchemaUtils = class {
330
356
  }, {});
331
357
  rest.required = schema.required?.filter((key) => !separatedProperties.includes(key));
332
358
  rest.examples = schema.examples?.map((example) => {
333
- if (!isPlainObject2(example)) {
359
+ if (!isObject(example)) {
334
360
  return example;
335
361
  }
336
362
  return Object.entries(example).reduce((acc, [key, value]) => {
@@ -370,10 +396,9 @@ var SchemaUtils = class {
370
396
  }
371
397
  return [matches, schema];
372
398
  }
373
- };
399
+ }
374
400
 
375
- // src/openapi-generator.ts
376
- var OpenAPIGenerator = class {
401
+ class OpenAPIGenerator {
377
402
  contentBuilder;
378
403
  parametersBuilder;
379
404
  schemaConverter;
@@ -390,7 +415,7 @@ var OpenAPIGenerator = class {
390
415
  this.parametersBuilder = options?.parametersBuilder ?? new OpenAPIParametersBuilder();
391
416
  this.schemaConverter = new CompositeSchemaConverter(options?.schemaConverters ?? []);
392
417
  this.schemaUtils = options?.schemaUtils ?? new SchemaUtils();
393
- this.jsonSerializer = options?.jsonSerializer ?? new JSONSerializer();
418
+ this.jsonSerializer = options?.jsonSerializer ?? new OpenAPIJsonSerializer();
394
419
  this.contentBuilder = options?.contentBuilder ?? new OpenAPIContentBuilder(this.schemaUtils);
395
420
  this.pathParser = new OpenAPIPathParser();
396
421
  this.inputStructureParser = options?.inputStructureParser ?? new OpenAPIInputStructureParser(this.schemaConverter, this.schemaUtils, this.pathParser);
@@ -406,34 +431,134 @@ var OpenAPIGenerator = class {
406
431
  openapi: "3.1.1"
407
432
  });
408
433
  const rootTags = doc.tags?.map((tag) => tag.name) ?? [];
409
- await forEachAllContractProcedure(router, ({ contract, path }) => {
434
+ await eachAllContractProcedure({
435
+ path: [],
436
+ router
437
+ }, ({ contract, path }) => {
410
438
  try {
411
439
  const def = contract["~orpc"];
412
440
  if (this.ignoreUndefinedPathProcedures && def.route?.path === void 0) {
413
441
  return;
414
442
  }
415
- const method = fallbackContractConfig2("defaultMethod", def.route?.method);
416
- const httpPath = def.route?.path ? standardizeHTTPPath(def.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
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);
421
- const params = paramsSchema ? this.parametersBuilder.build("path", paramsSchema, {
422
- required: true
423
- }) : [];
424
- const query = querySchema ? this.parametersBuilder.build("query", querySchema) : [];
425
- const headers = headersSchema ? this.parametersBuilder.build("header", headersSchema) : [];
426
- const parameters = [...params, ...query, ...headers];
427
- const requestBody = bodySchema !== void 0 ? {
428
- required: this.schemaUtils.isUndefinableSchema(bodySchema),
429
- content: this.contentBuilder.build(bodySchema)
430
- } : void 0;
431
- const responses = {};
432
- responses[fallbackContractConfig2("defaultSuccessStatus", def.route?.successStatus)] = {
433
- description: fallbackContractConfig2("defaultSuccessDescription", def.route?.successDescription),
434
- content: resBodySchema !== void 0 ? this.contentBuilder.build(resBodySchema) : void 0,
435
- headers: resHeadersSchema !== void 0 ? this.parametersBuilder.buildHeadersObject(resHeadersSchema) : void 0
436
- };
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
+ })();
437
562
  const errors = group(Object.entries(def.errorMap ?? {}).filter(([_, config]) => config).map(([code, config]) => ({
438
563
  ...config,
439
564
  code,
@@ -504,8 +629,9 @@ var OpenAPIGenerator = class {
504
629
  requestBody,
505
630
  responses
506
631
  };
632
+ const extendedOperation = extendOperation(operation, contract);
507
633
  builder.addPath(httpPath, {
508
- [method.toLocaleLowerCase()]: operation
634
+ [method.toLocaleLowerCase()]: extendedOperation
509
635
  });
510
636
  } catch (e) {
511
637
  if (e instanceof OpenAPIError) {
@@ -524,23 +650,12 @@ var OpenAPIGenerator = class {
524
650
  }
525
651
  }
526
652
  });
527
- return this.jsonSerializer.serialize(builder.getSpec());
653
+ return this.jsonSerializer.serialize(builder.getSpec())[0];
528
654
  }
655
+ }
656
+
657
+ const oo = {
658
+ spec: setOperationExtender
529
659
  };
530
- export {
531
- CompositeSchemaConverter,
532
- JSONSchema,
533
- Format as JSONSchemaFormat,
534
- JSONSerializer,
535
- NON_LOGIC_KEYWORDS,
536
- OpenAPIContentBuilder,
537
- OpenAPIGenerator,
538
- OpenAPIParametersBuilder,
539
- OpenAPIPathParser,
540
- OpenApiBuilder,
541
- SchemaUtils,
542
- forEachAllContractProcedure,
543
- forEachContractProcedure,
544
- standardizeHTTPPath
545
- };
546
- //# 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,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 };
@@ -0,0 +1,25 @@
1
+ import { StandardHandler } from '@orpc/server/standard';
2
+ import { toStandardRequest, 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, ...[options]) {
13
+ const standardRequest = toStandardRequest(request);
14
+ const result = await this.standardHandler.handle(standardRequest, options);
15
+ if (!result.matched) {
16
+ return result;
17
+ }
18
+ return {
19
+ matched: true,
20
+ response: toFetchResponse(result.response, options)
21
+ };
22
+ }
23
+ }
24
+
25
+ export { OpenAPIHandler as O };
@@ -0,0 +1,7 @@
1
+ import { Context } from '@orpc/server';
2
+ import { RPCHandlerOptions } from '@orpc/server/standard';
3
+
4
+ interface OpenAPIHandlerOptions<T extends Context> extends RPCHandlerOptions<T> {
5
+ }
6
+
7
+ export type { OpenAPIHandlerOptions as O };
@@ -0,0 +1,7 @@
1
+ import { Context } from '@orpc/server';
2
+ import { RPCHandlerOptions } from '@orpc/server/standard';
3
+
4
+ interface OpenAPIHandlerOptions<T extends Context> extends RPCHandlerOptions<T> {
5
+ }
6
+
7
+ export type { OpenAPIHandlerOptions as O };