@temporary-name/server 1.9.3-alpha.6f8b694b2a090fe0182bfd5f16d29ca20f259307 → 1.9.3-alpha.72daecd600ae901064d3c4f8ab780582c1335ffe
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/adapters/aws-lambda/index.d.mts +5 -7
- package/dist/adapters/aws-lambda/index.d.ts +5 -7
- package/dist/adapters/aws-lambda/index.mjs +6 -9
- package/dist/adapters/fetch/index.d.mts +8 -86
- package/dist/adapters/fetch/index.d.ts +8 -86
- package/dist/adapters/fetch/index.mjs +18 -160
- package/dist/adapters/node/index.d.mts +9 -64
- package/dist/adapters/node/index.d.ts +9 -64
- package/dist/adapters/node/index.mjs +16 -125
- package/dist/handler/index.d.mts +28 -0
- package/dist/handler/index.d.ts +28 -0
- package/dist/handler/index.mjs +8 -0
- package/dist/helpers/index.mjs +3 -29
- package/dist/index.d.mts +373 -493
- package/dist/index.d.ts +373 -493
- package/dist/index.mjs +547 -469
- package/dist/openapi/index.d.mts +18 -53
- package/dist/openapi/index.d.ts +18 -53
- package/dist/openapi/index.mjs +384 -378
- package/dist/shared/server.BwcJq6aP.d.mts +808 -0
- package/dist/shared/server.BwcJq6aP.d.ts +808 -0
- package/dist/shared/server.C1RJffw4.mjs +30 -0
- package/dist/shared/server.CjPiuQYH.d.mts +51 -0
- package/dist/shared/server.CjPiuQYH.d.ts +51 -0
- package/dist/shared/server.D1LXM1bf.mjs +523 -0
- package/dist/shared/server.DEC2sW8B.mjs +496 -0
- package/dist/shared/server.Deg5phAY.d.ts +39 -0
- package/dist/shared/server.H11763QX.mjs +315 -0
- package/dist/shared/server.gSXsB9Bn.mjs +156 -0
- package/dist/shared/server.hAH-LVh_.d.mts +39 -0
- package/package.json +13 -30
- package/dist/adapters/standard/index.d.mts +0 -42
- package/dist/adapters/standard/index.d.ts +0 -42
- package/dist/adapters/standard/index.mjs +0 -11
- package/dist/plugins/index.d.mts +0 -160
- package/dist/plugins/index.d.ts +0 -160
- package/dist/plugins/index.mjs +0 -288
- package/dist/shared/server.BEHw7Eyx.mjs +0 -247
- package/dist/shared/server.BKSOrA6h.d.mts +0 -192
- package/dist/shared/server.BKSOrA6h.d.ts +0 -192
- package/dist/shared/server.BKh8I1Ny.mjs +0 -239
- package/dist/shared/server.BeuTpcmO.d.mts +0 -23
- package/dist/shared/server.C1fnTLq0.d.mts +0 -57
- package/dist/shared/server.CQyYNJ1H.d.ts +0 -57
- package/dist/shared/server.DLsti1Pv.mjs +0 -293
- package/dist/shared/server.SLLuK6_v.d.ts +0 -23
package/dist/openapi/index.mjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import '@temporary-name/standard-server';
|
|
1
|
+
import { isObject, stringifyJSON, findDeepMatches, clone, value, fallbackContractConfig, toHttpPath, assertNever } from '@temporary-name/shared';
|
|
2
|
+
import * as z from '@temporary-name/zod';
|
|
3
|
+
import { s as standardizeHTTPPath, r as resolveContractProcedures, g as getDynamicParams, i as isAPIErrorStatus } from '../shared/server.DEC2sW8B.mjs';
|
|
4
|
+
import { Z as ZodToJsonSchemaConverter, g as getEventIteratorSchemaDetails } from '../shared/server.D1LXM1bf.mjs';
|
|
6
5
|
import { TypeName } from '@temporary-name/interop/json-schema-typed/draft-2020-12';
|
|
7
6
|
export { ContentEncoding as JSONSchemaContentEncoding, Format as JSONSchemaFormat, TypeName as JSONSchemaTypeName } from '@temporary-name/interop/json-schema-typed/draft-2020-12';
|
|
7
|
+
import '@temporary-name/standard-server';
|
|
8
|
+
import '@temporary-name/server/openapi';
|
|
9
|
+
import 'zod/v4/core';
|
|
8
10
|
|
|
9
11
|
const OPERATION_EXTENDER_SYMBOL = Symbol("ORPC_OPERATION_EXTENDER");
|
|
10
12
|
function customOpenAPIOperation(o, extend) {
|
|
@@ -22,20 +24,12 @@ function getCustomOpenAPIOperation(o) {
|
|
|
22
24
|
}
|
|
23
25
|
function applyCustomOpenAPIOperation(operation, contract) {
|
|
24
26
|
const operationCustoms = [];
|
|
25
|
-
for (const
|
|
26
|
-
const maybeExtender =
|
|
27
|
+
for (const middleware of contract["~orpc"].middlewares) {
|
|
28
|
+
const maybeExtender = getCustomOpenAPIOperation(middleware);
|
|
27
29
|
if (maybeExtender) {
|
|
28
30
|
operationCustoms.push(maybeExtender);
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
|
-
if (isProcedure(contract)) {
|
|
32
|
-
for (const middleware of contract["~orpc"].middlewares) {
|
|
33
|
-
const maybeExtender = getCustomOpenAPIOperation(middleware);
|
|
34
|
-
if (maybeExtender) {
|
|
35
|
-
operationCustoms.push(maybeExtender);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
33
|
let currentOperation = operation;
|
|
40
34
|
for (const custom of operationCustoms) {
|
|
41
35
|
if (typeof custom === "function") {
|
|
@@ -362,415 +356,427 @@ function resolveOpenAPIJsonSchemaRef(doc, schema) {
|
|
|
362
356
|
return resolved ?? schema;
|
|
363
357
|
}
|
|
364
358
|
|
|
365
|
-
class CompositeSchemaConverter {
|
|
366
|
-
converters;
|
|
367
|
-
constructor(converters) {
|
|
368
|
-
this.converters = converters;
|
|
369
|
-
}
|
|
370
|
-
async convert(schema, options) {
|
|
371
|
-
for (const converter of this.converters) {
|
|
372
|
-
if (await converter.condition(schema, options)) {
|
|
373
|
-
return converter.convert(schema, options);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
return [false, {}];
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
359
|
class OpenAPIGeneratorError extends Error {
|
|
381
360
|
}
|
|
382
|
-
|
|
383
|
-
converter;
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
options.commonSchemas
|
|
407
|
-
);
|
|
408
|
-
const contracts = [];
|
|
409
|
-
await resolveContractProcedures({ path: [], router }, (traverseOptions) => {
|
|
410
|
-
if (!value(filter, traverseOptions)) {
|
|
411
|
-
return;
|
|
361
|
+
async function generateOpenApiSpec(router, options = {}) {
|
|
362
|
+
const converter = typeof options.schemaConverter === "function" ? options.schemaConverter : new ZodToJsonSchemaConverter(options.schemaConverter ?? {}).convert;
|
|
363
|
+
const filter = options.filter ?? (({ contract, path }) => {
|
|
364
|
+
return !(options.exclude?.(contract, path) ?? false);
|
|
365
|
+
});
|
|
366
|
+
const doc = {
|
|
367
|
+
...clone(options.spec),
|
|
368
|
+
info: options.spec?.info ?? { title: "API Reference", version: "0.0.0" },
|
|
369
|
+
openapi: "3.1.1"
|
|
370
|
+
};
|
|
371
|
+
const { baseSchemaConvertOptions } = await resolveCommonSchemas(doc, options.commonSchemas, converter);
|
|
372
|
+
const contracts = [];
|
|
373
|
+
await resolveContractProcedures({ path: [], router }, (traverseOptions) => {
|
|
374
|
+
if (!value(filter, traverseOptions)) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
contracts.push(traverseOptions);
|
|
378
|
+
});
|
|
379
|
+
const namesByAuthConfig = /* @__PURE__ */ new Map();
|
|
380
|
+
const authConfigNames = /* @__PURE__ */ new Set();
|
|
381
|
+
for (const { contract } of contracts) {
|
|
382
|
+
for (const authConfig of contract["~orpc"].authConfigs) {
|
|
383
|
+
if (authConfig.type === "none" || namesByAuthConfig.has(authConfig)) {
|
|
384
|
+
continue;
|
|
412
385
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const stringPath = path.join(".");
|
|
418
|
-
try {
|
|
419
|
-
const def = contract["~orpc"];
|
|
420
|
-
const method = toOpenAPIMethod(fallbackContractConfig("defaultMethod", def.route.method));
|
|
421
|
-
const httpPath = toOpenAPIPath(def.route.path ?? toHttpPath(path));
|
|
422
|
-
let operationObjectRef;
|
|
423
|
-
if (def.route.spec !== void 0 && typeof def.route.spec !== "function") {
|
|
424
|
-
operationObjectRef = def.route.spec;
|
|
425
|
-
} else {
|
|
426
|
-
operationObjectRef = {
|
|
427
|
-
operationId: def.route.operationId ?? stringPath,
|
|
428
|
-
summary: def.route.summary,
|
|
429
|
-
description: def.route.description,
|
|
430
|
-
deprecated: def.route.deprecated,
|
|
431
|
-
tags: def.route.tags?.map((tag) => tag)
|
|
432
|
-
};
|
|
433
|
-
await this.#request(doc, operationObjectRef, def, baseSchemaConvertOptions);
|
|
434
|
-
await this.#successResponse(doc, operationObjectRef, def, baseSchemaConvertOptions);
|
|
435
|
-
await this.#errorResponse(
|
|
436
|
-
operationObjectRef,
|
|
437
|
-
def,
|
|
438
|
-
baseSchemaConvertOptions,
|
|
439
|
-
undefinedErrorJsonSchema
|
|
440
|
-
);
|
|
441
|
-
}
|
|
442
|
-
if (typeof def.route.spec === "function") {
|
|
443
|
-
operationObjectRef = def.route.spec(operationObjectRef);
|
|
444
|
-
}
|
|
445
|
-
doc.paths ??= {};
|
|
446
|
-
doc.paths[httpPath] ??= {};
|
|
447
|
-
doc.paths[httpPath][method] = applyCustomOpenAPIOperation(operationObjectRef, contract);
|
|
448
|
-
} catch (e) {
|
|
449
|
-
if (!(e instanceof OpenAPIGeneratorError)) {
|
|
450
|
-
throw e;
|
|
451
|
-
}
|
|
452
|
-
errors.push(
|
|
453
|
-
`[OpenAPIGenerator] Error occurred while generating OpenAPI for procedure at path: ${stringPath}
|
|
454
|
-
${e.message}`
|
|
455
|
-
);
|
|
386
|
+
const oasNameBase = authConfig.oasName ?? `${authConfig.type}Auth`;
|
|
387
|
+
let oasName = oasNameBase;
|
|
388
|
+
for (let i = 2; authConfigNames.has(oasName); i++) {
|
|
389
|
+
oasName = `${oasNameBase}${i}`;
|
|
456
390
|
}
|
|
391
|
+
namesByAuthConfig.set(authConfig, oasName);
|
|
392
|
+
authConfigNames.add(oasName);
|
|
457
393
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
);
|
|
394
|
+
}
|
|
395
|
+
if (namesByAuthConfig.size > 0) {
|
|
396
|
+
doc.components ??= {};
|
|
397
|
+
const schemes = doc.components.securitySchemes ??= {};
|
|
398
|
+
for (const [authConfig, name] of namesByAuthConfig) {
|
|
399
|
+
schemes[name] ??= authConfigToSecurityScheme(authConfig);
|
|
464
400
|
}
|
|
465
|
-
return jsonSerialize(doc)[0];
|
|
466
401
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
if (strategy === "input") {
|
|
491
|
-
const [outputRequired, outputJson] = await this.converter.convert(schema, { strategy: "output" });
|
|
492
|
-
if (outputRequired === required && stringifyJSON(outputJson) === stringifyJSON(json)) {
|
|
493
|
-
allowedStrategies.push("output");
|
|
494
|
-
}
|
|
495
|
-
} else if (strategy === "output") {
|
|
496
|
-
const [inputRequired, inputJson] = await this.converter.convert(schema, { strategy: "input" });
|
|
497
|
-
if (inputRequired === required && stringifyJSON(inputJson) === stringifyJSON(json)) {
|
|
498
|
-
allowedStrategies.push("input");
|
|
499
|
-
}
|
|
402
|
+
const errors = [];
|
|
403
|
+
for (const { contract, path } of contracts) {
|
|
404
|
+
const stringPath = path.join(".");
|
|
405
|
+
try {
|
|
406
|
+
const def = contract["~orpc"];
|
|
407
|
+
const method = toOpenAPIMethod(fallbackContractConfig("defaultMethod", def.route.method));
|
|
408
|
+
const httpPath = toOpenAPIPath(def.route.path ?? toHttpPath(path));
|
|
409
|
+
let operationObjectRef;
|
|
410
|
+
if (def.route.spec !== void 0 && typeof def.route.spec !== "function") {
|
|
411
|
+
operationObjectRef = def.route.spec;
|
|
412
|
+
} else {
|
|
413
|
+
operationObjectRef = {
|
|
414
|
+
operationId: def.route.operationId ?? stringPath,
|
|
415
|
+
summary: def.route.summary,
|
|
416
|
+
description: def.route.description,
|
|
417
|
+
deprecated: def.route.deprecated,
|
|
418
|
+
tags: def.route.tags?.map((tag) => tag)
|
|
419
|
+
};
|
|
420
|
+
const security = def.authConfigs.map(
|
|
421
|
+
(authConfig) => authConfig.type === "none" ? {} : { [namesByAuthConfig.get(authConfig)]: [] }
|
|
422
|
+
);
|
|
423
|
+
if (security.length > 0) {
|
|
424
|
+
operationObjectRef.security = security;
|
|
500
425
|
}
|
|
501
|
-
baseSchemaConvertOptions
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
ref: `#/components/schemas/${key}`,
|
|
505
|
-
allowedStrategies
|
|
506
|
-
});
|
|
426
|
+
await handleRequest(doc, operationObjectRef, def, baseSchemaConvertOptions, converter);
|
|
427
|
+
await handleSuccessResponse(doc, operationObjectRef, def, baseSchemaConvertOptions, converter);
|
|
428
|
+
await handleErrorResponse(doc, operationObjectRef, def, baseSchemaConvertOptions, converter);
|
|
507
429
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
continue;
|
|
518
|
-
}
|
|
519
|
-
const { schema, strategy = "input" } = options;
|
|
520
|
-
const [, json] = await this.converter.convert(schema, {
|
|
521
|
-
...baseSchemaConvertOptions,
|
|
522
|
-
strategy,
|
|
523
|
-
minStructureDepthForRef: 1
|
|
524
|
-
// not allow use $ref for root schemas
|
|
525
|
-
});
|
|
526
|
-
doc.components.schemas[key] = toOpenAPISchema(json);
|
|
430
|
+
if (typeof def.route.spec === "function") {
|
|
431
|
+
operationObjectRef = def.route.spec(operationObjectRef);
|
|
432
|
+
}
|
|
433
|
+
doc.paths ??= {};
|
|
434
|
+
doc.paths[httpPath] ??= {};
|
|
435
|
+
doc.paths[httpPath][method] = applyCustomOpenAPIOperation(operationObjectRef, contract);
|
|
436
|
+
} catch (e) {
|
|
437
|
+
if (!(e instanceof OpenAPIGeneratorError)) {
|
|
438
|
+
throw e;
|
|
527
439
|
}
|
|
440
|
+
errors.push(
|
|
441
|
+
`[OpenAPIGenerator] Error occurred while generating OpenAPI for procedure at path: ${stringPath}
|
|
442
|
+
${e.message}`
|
|
443
|
+
);
|
|
528
444
|
}
|
|
529
|
-
return { baseSchemaConvertOptions, undefinedErrorJsonSchema };
|
|
530
445
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
446
|
+
if (errors.length) {
|
|
447
|
+
throw new OpenAPIGeneratorError(
|
|
448
|
+
`Some error occurred during OpenAPI generation:
|
|
449
|
+
|
|
450
|
+
${errors.join("\n\n")}`
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
return doc;
|
|
454
|
+
}
|
|
455
|
+
async function resolveCommonSchemas(doc, commonSchemas, converter) {
|
|
456
|
+
let undefinedErrorJsonSchema = {
|
|
457
|
+
type: "object",
|
|
458
|
+
properties: {
|
|
459
|
+
code: { type: "string" },
|
|
460
|
+
status: { type: "number" },
|
|
461
|
+
message: { type: "string" },
|
|
462
|
+
data: {}
|
|
463
|
+
},
|
|
464
|
+
required: ["code", "status", "message"]
|
|
465
|
+
};
|
|
466
|
+
const baseSchemaConvertOptions = {};
|
|
467
|
+
if (commonSchemas) {
|
|
468
|
+
baseSchemaConvertOptions.components = [];
|
|
469
|
+
for (const key in commonSchemas) {
|
|
470
|
+
const options = commonSchemas[key];
|
|
471
|
+
if (options.schema === void 0) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
const { schema, strategy = "input" } = options;
|
|
475
|
+
const [required, json] = await converter(schema, { strategy });
|
|
476
|
+
const allowedStrategies = [strategy];
|
|
477
|
+
if (strategy === "input") {
|
|
478
|
+
const [outputRequired, outputJson] = await converter(schema, { strategy: "output" });
|
|
479
|
+
if (outputRequired === required && stringifyJSON(outputJson) === stringifyJSON(json)) {
|
|
480
|
+
allowedStrategies.push("output");
|
|
561
481
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
throw error2;
|
|
482
|
+
} else if (strategy === "output") {
|
|
483
|
+
const [inputRequired, inputJson] = await converter(schema, { strategy: "input" });
|
|
484
|
+
if (inputRequired === required && stringifyJSON(inputJson) === stringifyJSON(json)) {
|
|
485
|
+
allowedStrategies.push("input");
|
|
567
486
|
}
|
|
568
|
-
ref.parameters ??= [];
|
|
569
|
-
ref.parameters.push(...toOpenAPIParameters(paramsSchema, "path"));
|
|
570
487
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
488
|
+
baseSchemaConvertOptions.components.push({
|
|
489
|
+
schema,
|
|
490
|
+
required,
|
|
491
|
+
ref: `#/components/schemas/${key}`,
|
|
492
|
+
allowedStrategies
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
doc.components ??= {};
|
|
496
|
+
doc.components.schemas ??= {};
|
|
497
|
+
for (const key in commonSchemas) {
|
|
498
|
+
const options = commonSchemas[key];
|
|
499
|
+
if (options.schema === void 0) {
|
|
500
|
+
if (options.error === "UndefinedError") {
|
|
501
|
+
doc.components.schemas[key] = toOpenAPISchema(undefinedErrorJsonSchema);
|
|
502
|
+
undefinedErrorJsonSchema = { $ref: `#/components/schemas/${key}` };
|
|
577
503
|
}
|
|
578
|
-
|
|
579
|
-
ref.parameters.push(...toOpenAPIParameters(resolvedSchema, "query"));
|
|
580
|
-
} else {
|
|
581
|
-
ref.requestBody = {
|
|
582
|
-
required,
|
|
583
|
-
content: toOpenAPIContent(schema)
|
|
584
|
-
};
|
|
504
|
+
continue;
|
|
585
505
|
}
|
|
586
|
-
|
|
506
|
+
const { schema, strategy = "input" } = options;
|
|
507
|
+
const [, json] = await converter(schema, {
|
|
508
|
+
...baseSchemaConvertOptions,
|
|
509
|
+
strategy,
|
|
510
|
+
minStructureDepthForRef: 1
|
|
511
|
+
// not allow use $ref for root schemas
|
|
512
|
+
});
|
|
513
|
+
doc.components.schemas[key] = toOpenAPISchema(json);
|
|
587
514
|
}
|
|
515
|
+
}
|
|
516
|
+
return { baseSchemaConvertOptions, undefinedErrorJsonSchema };
|
|
517
|
+
}
|
|
518
|
+
async function handleRequest(doc, ref, def, baseSchemaConvertOptions, converter) {
|
|
519
|
+
const method = fallbackContractConfig("defaultMethod", def.route.method);
|
|
520
|
+
const dynamicParams = getDynamicParams(def.route.path)?.map((v) => v.name);
|
|
521
|
+
const [_pathRequired, pathSchema] = await converter(def.schemas.pathSchema, {
|
|
522
|
+
...baseSchemaConvertOptions,
|
|
523
|
+
strategy: "input",
|
|
524
|
+
minStructureDepthForRef: 1
|
|
525
|
+
});
|
|
526
|
+
if (dynamicParams?.length) {
|
|
588
527
|
const error = new OpenAPIGeneratorError(
|
|
589
|
-
|
|
528
|
+
// TODO: fix this error
|
|
529
|
+
'When input structure is "compact", and path has dynamic params, input schema must be an object with all dynamic params as required.'
|
|
590
530
|
);
|
|
591
|
-
if (!isObjectSchema(
|
|
531
|
+
if (!isObjectSchema(pathSchema)) {
|
|
592
532
|
throw error;
|
|
593
533
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
throw new OpenAPIGeneratorError(
|
|
597
|
-
'When input structure is "detailed" and path has dynamic params, the "params" schema must be an object with all dynamic params as required.'
|
|
598
|
-
);
|
|
534
|
+
if (!checkParamsSchema(pathSchema, dynamicParams)) {
|
|
535
|
+
throw error;
|
|
599
536
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
}
|
|
607
|
-
const parameterIn = from === "params" ? "path" : from === "headers" ? "header" : "query";
|
|
608
|
-
ref.parameters ??= [];
|
|
609
|
-
ref.parameters.push(...toOpenAPIParameters(resolvedSchema, parameterIn));
|
|
610
|
-
}
|
|
537
|
+
ref.parameters ??= [];
|
|
538
|
+
ref.parameters.push(...toOpenAPIParameters(pathSchema, "path"));
|
|
539
|
+
} else {
|
|
540
|
+
const error = new OpenAPIGeneratorError("Params set via path do not match those on the route");
|
|
541
|
+
if (!isObjectSchema(pathSchema)) {
|
|
542
|
+
throw error;
|
|
611
543
|
}
|
|
612
|
-
if (
|
|
613
|
-
|
|
614
|
-
required: schema.required?.includes("body"),
|
|
615
|
-
content: toOpenAPIContent(schema.properties.body)
|
|
616
|
-
};
|
|
544
|
+
if (!checkParamsSchema(pathSchema, [])) {
|
|
545
|
+
throw error;
|
|
617
546
|
}
|
|
618
547
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
548
|
+
const [_queryRequired, querySchema] = await converter(def.schemas.querySchema, {
|
|
549
|
+
...baseSchemaConvertOptions,
|
|
550
|
+
strategy: "input",
|
|
551
|
+
minStructureDepthForRef: 0
|
|
552
|
+
});
|
|
553
|
+
if (!isAnySchema(querySchema)) {
|
|
554
|
+
const resolvedSchema = resolveOpenAPIJsonSchemaRef(doc, querySchema);
|
|
555
|
+
if (!isObjectSchema(resolvedSchema)) {
|
|
556
|
+
throw new OpenAPIGeneratorError("Query param schema must satisfy: object | any | unknown");
|
|
557
|
+
}
|
|
558
|
+
ref.parameters ??= [];
|
|
559
|
+
ref.parameters.push(...toOpenAPIParameters(resolvedSchema, "query"));
|
|
560
|
+
}
|
|
561
|
+
if (method !== "GET") {
|
|
562
|
+
const details = getEventIteratorSchemaDetails(def.schemas.bodySchema);
|
|
563
|
+
if (details) {
|
|
564
|
+
ref.requestBody = {
|
|
565
|
+
required: true,
|
|
629
566
|
content: toOpenAPIEventIteratorContent(
|
|
630
|
-
await
|
|
631
|
-
|
|
632
|
-
strategy: "output"
|
|
633
|
-
}),
|
|
634
|
-
await this.converter.convert(eventIteratorSchemaDetails.returns, {
|
|
635
|
-
...baseSchemaConvertOptions,
|
|
636
|
-
strategy: "output"
|
|
637
|
-
})
|
|
567
|
+
await converter(details.yields, { ...baseSchemaConvertOptions, strategy: "input" }),
|
|
568
|
+
await converter(details.returns, { ...baseSchemaConvertOptions, strategy: "input" })
|
|
638
569
|
)
|
|
639
570
|
};
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
ref.
|
|
650
|
-
|
|
571
|
+
} else {
|
|
572
|
+
const [bodyRequired, bodySchema] = await converter(def.schemas.bodySchema, {
|
|
573
|
+
...baseSchemaConvertOptions,
|
|
574
|
+
strategy: "input",
|
|
575
|
+
minStructureDepthForRef: 0
|
|
576
|
+
});
|
|
577
|
+
if (isAnySchema(bodySchema)) {
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
ref.requestBody = {
|
|
581
|
+
required: bodyRequired,
|
|
582
|
+
content: toOpenAPIContent(bodySchema)
|
|
651
583
|
};
|
|
652
|
-
ref.responses[status].content = toOpenAPIContent(applySchemaOptionality(required, json));
|
|
653
|
-
return;
|
|
654
584
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
async function handleSuccessResponse(doc, ref, def, baseSchemaConvertOptions, converter) {
|
|
588
|
+
const outputSchema = def.schemas.outputSchema;
|
|
589
|
+
const status = fallbackContractConfig("defaultSuccessStatus", def.route.successStatus);
|
|
590
|
+
const description = fallbackContractConfig("defaultSuccessDescription", def.route?.successDescription);
|
|
591
|
+
const eventIteratorSchemaDetails = getEventIteratorSchemaDetails(outputSchema);
|
|
592
|
+
const outputStructure = fallbackContractConfig("defaultOutputStructure", def.route.outputStructure);
|
|
593
|
+
if (eventIteratorSchemaDetails) {
|
|
594
|
+
ref.responses ??= {};
|
|
595
|
+
ref.responses[status] = {
|
|
596
|
+
description,
|
|
597
|
+
content: toOpenAPIEventIteratorContent(
|
|
598
|
+
await converter(eventIteratorSchemaDetails.yields, {
|
|
599
|
+
...baseSchemaConvertOptions,
|
|
600
|
+
strategy: "output"
|
|
601
|
+
}),
|
|
602
|
+
await converter(eventIteratorSchemaDetails.returns, {
|
|
603
|
+
...baseSchemaConvertOptions,
|
|
604
|
+
strategy: "output"
|
|
605
|
+
})
|
|
606
|
+
)
|
|
607
|
+
};
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const [required, json] = await converter(outputSchema, {
|
|
611
|
+
...baseSchemaConvertOptions,
|
|
612
|
+
strategy: "output",
|
|
613
|
+
minStructureDepthForRef: outputStructure === "detailed" ? 1 : 0
|
|
614
|
+
});
|
|
615
|
+
if (outputStructure === "compact") {
|
|
616
|
+
ref.responses ??= {};
|
|
617
|
+
ref.responses[status] = {
|
|
618
|
+
description
|
|
619
|
+
};
|
|
620
|
+
ref.responses[status].content = toOpenAPIContent(applySchemaOptionality(required, json));
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
const handledStatuses = /* @__PURE__ */ new Set();
|
|
624
|
+
for (const item of expandUnionSchema(json)) {
|
|
625
|
+
const error = new OpenAPIGeneratorError(`
|
|
626
|
+
When output structure is "detailed", output schema must satisfy:
|
|
627
|
+
{
|
|
628
|
+
status?: number, // must be a literal number and in the range of 200-399
|
|
629
|
+
headers?: Record<string, unknown>,
|
|
630
|
+
body?: unknown
|
|
631
|
+
}
|
|
664
632
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
633
|
+
But got: ${stringifyJSON(item)}
|
|
634
|
+
`);
|
|
635
|
+
if (!isObjectSchema(item)) {
|
|
636
|
+
throw error;
|
|
637
|
+
}
|
|
638
|
+
let schemaStatus;
|
|
639
|
+
let schemaDescription;
|
|
640
|
+
if (item.properties?.status !== void 0) {
|
|
641
|
+
const statusSchema = resolveOpenAPIJsonSchemaRef(doc, item.properties.status);
|
|
642
|
+
if (typeof statusSchema !== "object" || statusSchema.const === void 0 || typeof statusSchema.const !== "number" || !Number.isInteger(statusSchema.const) || isAPIErrorStatus(statusSchema.const)) {
|
|
668
643
|
throw error;
|
|
669
644
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
645
|
+
schemaStatus = statusSchema.const;
|
|
646
|
+
schemaDescription = statusSchema.description;
|
|
647
|
+
}
|
|
648
|
+
const itemStatus = schemaStatus ?? status;
|
|
649
|
+
const itemDescription = schemaDescription ?? description;
|
|
650
|
+
if (handledStatuses.has(itemStatus)) {
|
|
651
|
+
throw new OpenAPIGeneratorError(`
|
|
652
|
+
When output structure is "detailed", each success status must be unique.
|
|
653
|
+
But got status: ${itemStatus} used more than once.
|
|
654
|
+
`);
|
|
655
|
+
}
|
|
656
|
+
handledStatuses.add(itemStatus);
|
|
657
|
+
ref.responses ??= {};
|
|
658
|
+
ref.responses[itemStatus] = {
|
|
659
|
+
description: itemDescription
|
|
660
|
+
};
|
|
661
|
+
if (item.properties?.headers !== void 0) {
|
|
662
|
+
const headersSchema = resolveOpenAPIJsonSchemaRef(doc, item.properties.headers);
|
|
663
|
+
if (!isObjectSchema(headersSchema)) {
|
|
664
|
+
throw error;
|
|
687
665
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
throw error;
|
|
697
|
-
}
|
|
698
|
-
for (const key in headersSchema.properties) {
|
|
699
|
-
const headerSchema = headersSchema.properties[key];
|
|
700
|
-
if (headerSchema !== void 0) {
|
|
701
|
-
ref.responses[itemStatus].headers ??= {};
|
|
702
|
-
ref.responses[itemStatus].headers[key] = {
|
|
703
|
-
schema: toOpenAPISchema(headerSchema),
|
|
704
|
-
required: item.required?.includes("headers") && headersSchema.required?.includes(key)
|
|
705
|
-
};
|
|
706
|
-
}
|
|
666
|
+
for (const key in headersSchema.properties) {
|
|
667
|
+
const headerSchema = headersSchema.properties[key];
|
|
668
|
+
if (headerSchema !== void 0) {
|
|
669
|
+
ref.responses[itemStatus].headers ??= {};
|
|
670
|
+
ref.responses[itemStatus].headers[key] = {
|
|
671
|
+
schema: toOpenAPISchema(headerSchema),
|
|
672
|
+
required: item.required?.includes("headers") && headersSchema.required?.includes(key)
|
|
673
|
+
};
|
|
707
674
|
}
|
|
708
675
|
}
|
|
709
|
-
if (item.properties?.body !== void 0) {
|
|
710
|
-
ref.responses[itemStatus].content = toOpenAPIContent(
|
|
711
|
-
applySchemaOptionality(item.required?.includes("body") ?? false, item.properties.body)
|
|
712
|
-
);
|
|
713
|
-
}
|
|
714
676
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
for (const code in errorMap) {
|
|
720
|
-
const config = errorMap[code];
|
|
721
|
-
if (!config) {
|
|
722
|
-
continue;
|
|
723
|
-
}
|
|
724
|
-
const status = fallbackORPCErrorStatus(code, config.status);
|
|
725
|
-
const message = fallbackORPCErrorMessage(code, config.message);
|
|
726
|
-
const [dataRequired, dataSchema] = await this.converter.convert(config.data, {
|
|
727
|
-
...baseSchemaConvertOptions,
|
|
728
|
-
strategy: "output"
|
|
729
|
-
});
|
|
730
|
-
errors[status] ??= [];
|
|
731
|
-
errors[status].push({
|
|
732
|
-
type: "object",
|
|
733
|
-
properties: {
|
|
734
|
-
defined: { const: true },
|
|
735
|
-
code: { const: code },
|
|
736
|
-
status: { const: status },
|
|
737
|
-
message: { type: "string", default: message },
|
|
738
|
-
data: dataSchema
|
|
739
|
-
},
|
|
740
|
-
required: dataRequired ? ["defined", "code", "status", "message", "data"] : ["defined", "code", "status", "message"]
|
|
741
|
-
});
|
|
677
|
+
if (item.properties?.body !== void 0) {
|
|
678
|
+
ref.responses[itemStatus].content = toOpenAPIContent(
|
|
679
|
+
applySchemaOptionality(item.required?.includes("body") ?? false, item.properties.body)
|
|
680
|
+
);
|
|
742
681
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
function authConfigToSecurityScheme(authConfig) {
|
|
685
|
+
switch (authConfig.type) {
|
|
686
|
+
case "basic":
|
|
687
|
+
return {
|
|
688
|
+
type: "http",
|
|
689
|
+
scheme: "basic",
|
|
690
|
+
description: authConfig.oasDescription
|
|
751
691
|
};
|
|
752
|
-
|
|
692
|
+
case "bearer":
|
|
693
|
+
return {
|
|
694
|
+
type: "http",
|
|
695
|
+
scheme: "bearer",
|
|
696
|
+
description: authConfig.oasDescription,
|
|
697
|
+
bearerFormat: authConfig.oasBearerFormat
|
|
698
|
+
};
|
|
699
|
+
case "header":
|
|
700
|
+
return {
|
|
701
|
+
type: "apiKey",
|
|
702
|
+
in: "header",
|
|
703
|
+
name: authConfig.name,
|
|
704
|
+
description: authConfig.oasDescription
|
|
705
|
+
};
|
|
706
|
+
case "query":
|
|
707
|
+
return {
|
|
708
|
+
type: "apiKey",
|
|
709
|
+
in: "query",
|
|
710
|
+
name: authConfig.name,
|
|
711
|
+
description: authConfig.oasDescription
|
|
712
|
+
};
|
|
713
|
+
case "cookie":
|
|
714
|
+
return {
|
|
715
|
+
type: "apiKey",
|
|
716
|
+
in: "cookie",
|
|
717
|
+
name: authConfig.name,
|
|
718
|
+
description: authConfig.oasDescription
|
|
719
|
+
};
|
|
720
|
+
default:
|
|
721
|
+
assertNever(authConfig, `Unsupported auth config type: ${authConfig.type}`);
|
|
753
722
|
}
|
|
754
723
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
724
|
+
async function handleErrorResponse(doc, ref, def, baseSchemaConvertOptions, converter) {
|
|
725
|
+
const errorMap = def.errorMap;
|
|
726
|
+
const errorResponsesByStatus = {};
|
|
727
|
+
for (const code in errorMap) {
|
|
728
|
+
const errorClass = errorMap[code];
|
|
729
|
+
if (!errorClass) {
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
const status = errorClass.status;
|
|
733
|
+
const type = errorClass.type;
|
|
734
|
+
const defaultMessage = errorClass.defaultMessage;
|
|
735
|
+
errorResponsesByStatus[status] ??= { status, errorSchemaVariants: [] };
|
|
736
|
+
const extraZod = z.object(errorClass.extraSchema).strict();
|
|
737
|
+
const [, extraSchema] = await converter(extraZod, {
|
|
738
|
+
...baseSchemaConvertOptions,
|
|
739
|
+
strategy: "output"
|
|
740
|
+
});
|
|
741
|
+
if (!isObjectSchema(extraSchema)) {
|
|
742
|
+
throw new OpenAPIGeneratorError(
|
|
743
|
+
`Error response extra schema must be an object, but got: ${stringifyJSON(extraSchema)}`
|
|
744
|
+
);
|
|
767
745
|
}
|
|
768
|
-
|
|
769
|
-
|
|
746
|
+
errorResponsesByStatus[status].errorSchemaVariants.push({
|
|
747
|
+
type: "object",
|
|
748
|
+
properties: {
|
|
749
|
+
type: { const: type },
|
|
750
|
+
message: { type: "string", default: defaultMessage },
|
|
751
|
+
...extraSchema.properties
|
|
752
|
+
},
|
|
753
|
+
required: ["type", "message", ...extraSchema.required ?? []]
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
ref.responses ??= {};
|
|
757
|
+
for (const statusString in errorResponsesByStatus) {
|
|
758
|
+
const errorResponse = errorResponsesByStatus[statusString];
|
|
759
|
+
if (statusString === "500") {
|
|
760
|
+
console.log(
|
|
761
|
+
errorResponse.errorSchemaVariants,
|
|
762
|
+
toOpenAPIContent({
|
|
763
|
+
oneOf: errorResponse.errorSchemaVariants
|
|
764
|
+
})
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
ref.responses[statusString] = {
|
|
768
|
+
description: statusString,
|
|
769
|
+
content: toOpenAPIContent(
|
|
770
|
+
errorResponse.errorSchemaVariants.length === 1 ? errorResponse.errorSchemaVariants[0] : {
|
|
771
|
+
oneOf: errorResponse.errorSchemaVariants
|
|
772
|
+
}
|
|
773
|
+
)
|
|
774
|
+
};
|
|
775
|
+
}
|
|
770
776
|
}
|
|
771
777
|
|
|
772
778
|
const oo = {
|
|
773
779
|
spec: customOpenAPIOperation
|
|
774
780
|
};
|
|
775
781
|
|
|
776
|
-
export {
|
|
782
|
+
export { LOGIC_KEYWORDS, applyCustomOpenAPIOperation, applySchemaOptionality, checkParamsSchema, customOpenAPIOperation, expandArrayableSchema, expandUnionSchema, filterSchemaBranches, generateOpenApiSpec, getCustomOpenAPIOperation, isAnySchema, isFileSchema, isObjectSchema, isPrimitiveSchema, oo, resolveOpenAPIJsonSchemaRef, separateObjectSchema, toOpenAPIContent, toOpenAPIEventIteratorContent, toOpenAPIMethod, toOpenAPIParameters, toOpenAPIPath, toOpenAPISchema };
|