@temporary-name/server 1.9.3-alpha.62445d8d52a6787e7750865cd468fca8cccd3e28 → 1.9.3-alpha.62d88f5cf3908d4411b5278f1824b69334da8072
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 +5 -6
- package/dist/adapters/fetch/index.d.mts +8 -86
- package/dist/adapters/fetch/index.d.ts +8 -86
- package/dist/adapters/fetch/index.mjs +17 -157
- package/dist/adapters/node/index.d.mts +9 -64
- package/dist/adapters/node/index.d.ts +9 -64
- package/dist/adapters/node/index.mjs +15 -122
- 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 +365 -245
- package/dist/index.d.ts +365 -245
- package/dist/index.mjs +489 -359
- package/dist/openapi/index.d.mts +18 -53
- package/dist/openapi/index.d.ts +18 -53
- package/dist/openapi/index.mjs +387 -347
- package/dist/shared/server.Blt424vz.mjs +523 -0
- package/dist/shared/server.Bmxjwleq.d.ts +39 -0
- package/dist/shared/server.BnAF9pfn.mjs +339 -0
- package/dist/shared/server.C1RJffw4.mjs +30 -0
- package/dist/shared/server.CCWAen7P.mjs +156 -0
- package/dist/shared/server.CjPiuQYH.d.mts +51 -0
- package/dist/shared/server.CjPiuQYH.d.ts +51 -0
- package/dist/shared/server.DLyn62VH.d.mts +39 -0
- package/dist/shared/server.DpIhEnBO.d.mts +515 -0
- package/dist/shared/server.DpIhEnBO.d.ts +515 -0
- package/dist/shared/server.MJ43MXYj.mjs +432 -0
- package/package.json +13 -31
- package/dist/adapters/standard/index.d.mts +0 -26
- package/dist/adapters/standard/index.d.ts +0 -26
- package/dist/adapters/standard/index.mjs +0 -9
- 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.B93y_8tj.d.mts +0 -23
- package/dist/shared/server.BYYf0Wn6.mjs +0 -202
- package/dist/shared/server.C3RuMHWl.d.mts +0 -192
- package/dist/shared/server.C3RuMHWl.d.ts +0 -192
- package/dist/shared/server.CT1xhSmE.d.mts +0 -56
- package/dist/shared/server.CqTex_jI.mjs +0 -265
- package/dist/shared/server.D_fags8X.d.ts +0 -23
- package/dist/shared/server.Kxw442A9.mjs +0 -247
- package/dist/shared/server.cjcgLdr1.d.ts +0 -56
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.MJ43MXYj.mjs';
|
|
4
|
+
import { Z as ZodToJsonSchemaConverter, g as getEventIteratorSchemaDetails } from '../shared/server.Blt424vz.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,381 +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
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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}`
|
|
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}`;
|
|
390
|
+
}
|
|
391
|
+
namesByAuthConfig.set(authConfig, oasName);
|
|
392
|
+
authConfigNames.add(oasName);
|
|
393
|
+
}
|
|
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);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
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)]: [] }
|
|
455
422
|
);
|
|
423
|
+
if (security.length > 0) {
|
|
424
|
+
operationObjectRef.security = security;
|
|
425
|
+
}
|
|
426
|
+
await handleRequest(doc, operationObjectRef, def, baseSchemaConvertOptions, converter);
|
|
427
|
+
await handleSuccessResponse(doc, operationObjectRef, def, baseSchemaConvertOptions, converter);
|
|
428
|
+
await handleErrorResponse(doc, operationObjectRef, def, baseSchemaConvertOptions, converter);
|
|
429
|
+
}
|
|
430
|
+
if (typeof def.route.spec === "function") {
|
|
431
|
+
operationObjectRef = def.route.spec(operationObjectRef);
|
|
456
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;
|
|
439
|
+
}
|
|
440
|
+
errors.push(
|
|
441
|
+
`[OpenAPIGenerator] Error occurred while generating OpenAPI for procedure at path: ${stringPath}
|
|
442
|
+
${e.message}`
|
|
443
|
+
);
|
|
457
444
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
445
|
+
}
|
|
446
|
+
if (errors.length) {
|
|
447
|
+
throw new OpenAPIGeneratorError(
|
|
448
|
+
`Some error occurred during OpenAPI generation:
|
|
461
449
|
|
|
462
450
|
${errors.join("\n\n")}`
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
return jsonSerialize(doc)[0];
|
|
451
|
+
);
|
|
466
452
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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");
|
|
486
481
|
}
|
|
487
|
-
|
|
488
|
-
const [
|
|
489
|
-
|
|
490
|
-
|
|
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
|
-
}
|
|
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");
|
|
500
486
|
}
|
|
501
|
-
baseSchemaConvertOptions.components.push({
|
|
502
|
-
schema,
|
|
503
|
-
required,
|
|
504
|
-
ref: `#/components/schemas/${key}`,
|
|
505
|
-
allowedStrategies
|
|
506
|
-
});
|
|
507
487
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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}` };
|
|
518
503
|
}
|
|
519
|
-
|
|
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);
|
|
504
|
+
continue;
|
|
527
505
|
}
|
|
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);
|
|
528
514
|
}
|
|
529
|
-
return { baseSchemaConvertOptions, undefinedErrorJsonSchema };
|
|
530
515
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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) {
|
|
527
|
+
const error = new OpenAPIGeneratorError(
|
|
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.'
|
|
530
|
+
);
|
|
531
|
+
if (!isObjectSchema(pathSchema)) {
|
|
532
|
+
throw error;
|
|
533
|
+
}
|
|
534
|
+
if (!checkParamsSchema(pathSchema, dynamicParams)) {
|
|
535
|
+
throw error;
|
|
536
|
+
}
|
|
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;
|
|
543
|
+
}
|
|
544
|
+
if (!checkParamsSchema(pathSchema, [])) {
|
|
545
|
+
throw error;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
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);
|
|
534
563
|
if (details) {
|
|
535
564
|
ref.requestBody = {
|
|
536
565
|
required: true,
|
|
537
566
|
content: toOpenAPIEventIteratorContent(
|
|
538
|
-
await
|
|
539
|
-
await
|
|
567
|
+
await converter(details.yields, { ...baseSchemaConvertOptions, strategy: "input" }),
|
|
568
|
+
await converter(details.returns, { ...baseSchemaConvertOptions, strategy: "input" })
|
|
540
569
|
)
|
|
541
570
|
};
|
|
542
|
-
return;
|
|
543
|
-
}
|
|
544
|
-
const dynamicParams = getDynamicParams(def.route.path)?.map((v) => v.name);
|
|
545
|
-
let [required, schema] = await this.converter.convert(def.inputSchema, {
|
|
546
|
-
...baseSchemaConvertOptions,
|
|
547
|
-
strategy: "input",
|
|
548
|
-
minStructureDepthForRef: dynamicParams?.length ? 1 : 0
|
|
549
|
-
});
|
|
550
|
-
if (isAnySchema(schema) && !dynamicParams?.length) {
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
if (dynamicParams?.length) {
|
|
554
|
-
const error = new OpenAPIGeneratorError(
|
|
555
|
-
'When input structure is "compact", and path has dynamic params, input schema must be an object with all dynamic params as required.'
|
|
556
|
-
);
|
|
557
|
-
if (!isObjectSchema(schema)) {
|
|
558
|
-
throw error;
|
|
559
|
-
}
|
|
560
|
-
const [paramsSchema, rest] = separateObjectSchema(schema, dynamicParams);
|
|
561
|
-
schema = rest;
|
|
562
|
-
required = rest.required ? rest.required.length !== 0 : false;
|
|
563
|
-
if (!checkParamsSchema(paramsSchema, dynamicParams)) {
|
|
564
|
-
throw error;
|
|
565
|
-
}
|
|
566
|
-
ref.parameters ??= [];
|
|
567
|
-
ref.parameters.push(...toOpenAPIParameters(paramsSchema, "path"));
|
|
568
|
-
}
|
|
569
|
-
if (method === "GET") {
|
|
570
|
-
const resolvedSchema = resolveOpenAPIJsonSchemaRef(doc, schema);
|
|
571
|
-
if (!isObjectSchema(resolvedSchema)) {
|
|
572
|
-
throw new OpenAPIGeneratorError(
|
|
573
|
-
'When method is "GET", input schema must satisfy: object | any | unknown'
|
|
574
|
-
);
|
|
575
|
-
}
|
|
576
|
-
ref.parameters ??= [];
|
|
577
|
-
ref.parameters.push(...toOpenAPIParameters(resolvedSchema, "query"));
|
|
578
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
|
+
}
|
|
579
580
|
ref.requestBody = {
|
|
580
|
-
required,
|
|
581
|
-
content: toOpenAPIContent(
|
|
581
|
+
required: bodyRequired,
|
|
582
|
+
content: toOpenAPIContent(bodySchema)
|
|
582
583
|
};
|
|
583
584
|
}
|
|
584
585
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
)
|
|
605
|
-
|
|
606
|
-
|
|
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
|
+
}
|
|
632
|
+
|
|
633
|
+
But got: ${stringifyJSON(item)}
|
|
634
|
+
`);
|
|
635
|
+
if (!isObjectSchema(item)) {
|
|
636
|
+
throw error;
|
|
607
637
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
};
|
|
618
|
-
ref.responses[status].content = toOpenAPIContent(applySchemaOptionality(required, json));
|
|
619
|
-
return;
|
|
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)) {
|
|
643
|
+
throw error;
|
|
644
|
+
}
|
|
645
|
+
schemaStatus = statusSchema.const;
|
|
646
|
+
schemaDescription = statusSchema.description;
|
|
620
647
|
}
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
headers?: Record<string, unknown>,
|
|
628
|
-
body?: unknown
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
But got: ${stringifyJSON(item)}
|
|
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.
|
|
632
654
|
`);
|
|
633
|
-
|
|
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)) {
|
|
634
664
|
throw error;
|
|
635
665
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
schemaDescription = statusSchema.description;
|
|
645
|
-
}
|
|
646
|
-
const itemStatus = schemaStatus ?? status;
|
|
647
|
-
const itemDescription = schemaDescription ?? description;
|
|
648
|
-
if (handledStatuses.has(itemStatus)) {
|
|
649
|
-
throw new OpenAPIGeneratorError(`
|
|
650
|
-
When output structure is "detailed", each success status must be unique.
|
|
651
|
-
But got status: ${itemStatus} used more than once.
|
|
652
|
-
`);
|
|
653
|
-
}
|
|
654
|
-
handledStatuses.add(itemStatus);
|
|
655
|
-
ref.responses ??= {};
|
|
656
|
-
ref.responses[itemStatus] = {
|
|
657
|
-
description: itemDescription
|
|
658
|
-
};
|
|
659
|
-
if (item.properties?.headers !== void 0) {
|
|
660
|
-
const headersSchema = resolveOpenAPIJsonSchemaRef(doc, item.properties.headers);
|
|
661
|
-
if (!isObjectSchema(headersSchema)) {
|
|
662
|
-
throw error;
|
|
663
|
-
}
|
|
664
|
-
for (const key in headersSchema.properties) {
|
|
665
|
-
const headerSchema = headersSchema.properties[key];
|
|
666
|
-
if (headerSchema !== void 0) {
|
|
667
|
-
ref.responses[itemStatus].headers ??= {};
|
|
668
|
-
ref.responses[itemStatus].headers[key] = {
|
|
669
|
-
schema: toOpenAPISchema(headerSchema),
|
|
670
|
-
required: item.required?.includes("headers") && headersSchema.required?.includes(key)
|
|
671
|
-
};
|
|
672
|
-
}
|
|
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
|
+
};
|
|
673
674
|
}
|
|
674
675
|
}
|
|
675
|
-
if (item.properties?.body !== void 0) {
|
|
676
|
-
ref.responses[itemStatus].content = toOpenAPIContent(
|
|
677
|
-
applySchemaOptionality(item.required?.includes("body") ?? false, item.properties.body)
|
|
678
|
-
);
|
|
679
|
-
}
|
|
680
676
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
for (const code in errorMap) {
|
|
686
|
-
const config = errorMap[code];
|
|
687
|
-
if (!config) {
|
|
688
|
-
continue;
|
|
689
|
-
}
|
|
690
|
-
const status = fallbackORPCErrorStatus(code, config.status);
|
|
691
|
-
const message = fallbackORPCErrorMessage(code, config.message);
|
|
692
|
-
const [dataRequired, dataSchema] = await this.converter.convert(config.data, {
|
|
693
|
-
...baseSchemaConvertOptions,
|
|
694
|
-
strategy: "output"
|
|
695
|
-
});
|
|
696
|
-
errors[status] ??= [];
|
|
697
|
-
errors[status].push({
|
|
698
|
-
type: "object",
|
|
699
|
-
properties: {
|
|
700
|
-
defined: { const: true },
|
|
701
|
-
code: { const: code },
|
|
702
|
-
status: { const: status },
|
|
703
|
-
message: { type: "string", default: message },
|
|
704
|
-
data: dataSchema
|
|
705
|
-
},
|
|
706
|
-
required: dataRequired ? ["defined", "code", "status", "message", "data"] : ["defined", "code", "status", "message"]
|
|
707
|
-
});
|
|
677
|
+
if (item.properties?.body !== void 0) {
|
|
678
|
+
ref.responses[itemStatus].content = toOpenAPIContent(
|
|
679
|
+
applySchemaOptionality(item.required?.includes("body") ?? false, item.properties.body)
|
|
680
|
+
);
|
|
708
681
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
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
|
|
717
691
|
};
|
|
718
|
-
|
|
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}`);
|
|
719
722
|
}
|
|
720
723
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
const
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
} catch (e) {
|
|
729
|
-
if (e instanceof ORPCError) {
|
|
730
|
-
throw createORPCErrorFromJson(deserialize(serialize(e.toJSON(), { outputFormat: "plain" })));
|
|
731
|
-
}
|
|
732
|
-
throw e;
|
|
724
|
+
async function handleErrorResponse(doc, ref, def, baseSchemaConvertOptions, converter) {
|
|
725
|
+
const errorMap = def.errorMap;
|
|
726
|
+
const errorResponsesByStatus = {};
|
|
727
|
+
for (const mapKey in errorMap) {
|
|
728
|
+
const errorClass = errorMap[mapKey];
|
|
729
|
+
if (!errorClass) {
|
|
730
|
+
continue;
|
|
733
731
|
}
|
|
734
|
-
|
|
735
|
-
|
|
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
|
+
);
|
|
745
|
+
}
|
|
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
|
+
}
|
|
736
776
|
}
|
|
737
777
|
|
|
738
778
|
const oo = {
|
|
739
779
|
spec: customOpenAPIOperation
|
|
740
780
|
};
|
|
741
781
|
|
|
742
|
-
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 };
|