vovk 3.0.0-draft.190 → 3.0.0-draft.192
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/cjs/index.d.ts +3 -3
- package/cjs/index.js +3 -3
- package/cjs/openapi/index.d.ts +3 -3
- package/cjs/openapi/index.js +5 -5
- package/cjs/openapi/openAPIToSchema.d.ts +1 -1
- package/cjs/openapi/openAPIToSchema.js +2 -2
- package/cjs/openapi/openAPIToVovkSchema.d.ts +15 -0
- package/cjs/openapi/openAPIToVovkSchema.js +138 -0
- package/cjs/openapi/schemaToOpenAPI.d.ts +1 -1
- package/cjs/openapi/schemaToOpenAPI.js +2 -2
- package/cjs/openapi/vovkSchemaToOpenAPI.d.ts +9 -0
- package/cjs/openapi/vovkSchemaToOpenAPI.js +237 -0
- package/cjs/types.d.ts +10 -0
- package/cjs/utils/withValidation.d.ts +2 -10
- package/mjs/index.d.ts +3 -3
- package/mjs/index.js +3 -3
- package/mjs/openapi/index.d.ts +3 -3
- package/mjs/openapi/index.js +5 -5
- package/mjs/openapi/openAPIToSchema.d.ts +1 -1
- package/mjs/openapi/openAPIToSchema.js +2 -2
- package/mjs/openapi/openAPIToVovkSchema.d.ts +15 -0
- package/mjs/openapi/openAPIToVovkSchema.js +138 -0
- package/mjs/openapi/schemaToOpenAPI.d.ts +1 -1
- package/mjs/openapi/schemaToOpenAPI.js +2 -2
- package/mjs/openapi/vovkSchemaToOpenAPI.d.ts +9 -0
- package/mjs/openapi/vovkSchemaToOpenAPI.js +237 -0
- package/mjs/types.d.ts +10 -0
- package/mjs/utils/withValidation.d.ts +2 -10
- package/package.json +1 -1
package/cjs/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createVovkApp } from './createVovkApp.js';
|
|
2
|
-
import { HttpStatus, HttpMethod, VovkSchemaIdEnum, type KnownAny, type VovkErrorResponse, type VovkRequest, type VovkBody, type VovkQuery, type VovkParams, type VovkReturnType, type VovkYieldType, type VovkOutput, type VovkIteration, type VovkSegmentSchema, type VovkControllerSchema, type VovkHandlerSchema, type VovkSchema, type VovkConfig, type VovkStrictConfig, type VovkValidationType, type VovkLLMFunction } from './types.js';
|
|
2
|
+
import { HttpStatus, HttpMethod, VovkSchemaIdEnum, type KnownAny, type VovkErrorResponse, type VovkRequest, type VovkBody, type VovkQuery, type VovkParams, type VovkReturnType, type VovkYieldType, type VovkOutput, type VovkIteration, type VovkSegmentSchema, type VovkControllerSchema, type VovkHandlerSchema, type VovkSchema, type VovkConfig, type VovkStrictConfig, type VovkValidationType, type VovkLLMFunction, type VovkTypedMethod } from './types.js';
|
|
3
3
|
import { type VovkClient, type VovkClientOptions, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkValidateOnClient, type VovkStreamAsyncIterable, createRPC, fetcher, createFetcher } from './client/index.js';
|
|
4
|
-
import { openapi,
|
|
4
|
+
import { openapi, openAPIToVovkSchema, vovkSchemaToOpenAPI } from './openapi/index.js';
|
|
5
5
|
import { HttpException } from './HttpException.js';
|
|
6
6
|
import { createDecorator } from './utils/createDecorator.js';
|
|
7
7
|
import { JSONLinesResponse } from './JSONLinesResponse.js';
|
|
@@ -10,7 +10,7 @@ import { withValidation } from './utils/withValidation.js';
|
|
|
10
10
|
import { multitenant } from './utils/multitenant.js';
|
|
11
11
|
import { createLLMFunctions } from './utils/createLLMFunctions.js';
|
|
12
12
|
import { createCodeExamples } from './utils/createCodeExamples.js';
|
|
13
|
-
export { type KnownAny, type VovkClient, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkStreamAsyncIterable, type VovkValidateOnClient, type VovkSegmentSchema, type VovkErrorResponse, type VovkRequest, type VovkOutput, type VovkIteration, type VovkBody, type VovkQuery, type VovkParams, type VovkYieldType, type VovkReturnType, type VovkClientOptions, type VovkControllerSchema, type VovkHandlerSchema, type VovkSchema, type VovkConfig, type VovkStrictConfig, type VovkValidationType, type VovkLLMFunction, VovkSchemaIdEnum, JSONLinesResponse, HttpException, HttpStatus, HttpMethod, createVovkApp, createDecorator, createRPC, fetcher, createFetcher, generateStaticAPI, withValidation, multitenant, createLLMFunctions, createCodeExamples, openapi,
|
|
13
|
+
export { type KnownAny, type VovkClient, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkStreamAsyncIterable, type VovkValidateOnClient, type VovkSegmentSchema, type VovkErrorResponse, type VovkRequest, type VovkOutput, type VovkIteration, type VovkBody, type VovkQuery, type VovkParams, type VovkYieldType, type VovkReturnType, type VovkClientOptions, type VovkControllerSchema, type VovkHandlerSchema, type VovkSchema, type VovkConfig, type VovkStrictConfig, type VovkValidationType, type VovkLLMFunction, type VovkTypedMethod, VovkSchemaIdEnum, JSONLinesResponse, HttpException, HttpStatus, HttpMethod, createVovkApp, createDecorator, createRPC, fetcher, createFetcher, generateStaticAPI, withValidation, multitenant, createLLMFunctions, createCodeExamples, openapi, openAPIToVovkSchema, vovkSchemaToOpenAPI, };
|
|
14
14
|
export declare const get: {
|
|
15
15
|
(givenPath?: string | undefined, options?: import("./types.js").DecoratorOptions | undefined): ReturnType<(givenPath?: string, options?: import("./types.js").DecoratorOptions) => (givenTarget: KnownAny, propertyKey: string) => void>;
|
|
16
16
|
auto: (options?: import("./types.js").DecoratorOptions) => (givenTarget: KnownAny, propertyKey: string) => void;
|
package/cjs/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.initVovk = exports.prefix = exports.options = exports.head = exports.del = exports.patch = exports.put = exports.post = exports.get = exports.
|
|
4
|
+
exports.initVovk = exports.prefix = exports.options = exports.head = exports.del = exports.patch = exports.put = exports.post = exports.get = exports.vovkSchemaToOpenAPI = exports.openAPIToVovkSchema = exports.openapi = exports.createCodeExamples = exports.createLLMFunctions = exports.multitenant = exports.withValidation = exports.generateStaticAPI = exports.createFetcher = exports.fetcher = exports.createRPC = exports.createDecorator = exports.createVovkApp = exports.HttpMethod = exports.HttpStatus = exports.HttpException = exports.JSONLinesResponse = exports.VovkSchemaIdEnum = void 0;
|
|
5
5
|
const createVovkApp_js_1 = require("./createVovkApp.js");
|
|
6
6
|
Object.defineProperty(exports, "createVovkApp", { enumerable: true, get: function () { return createVovkApp_js_1.createVovkApp; } });
|
|
7
7
|
const types_js_1 = require("./types.js");
|
|
@@ -14,8 +14,8 @@ Object.defineProperty(exports, "fetcher", { enumerable: true, get: function () {
|
|
|
14
14
|
Object.defineProperty(exports, "createFetcher", { enumerable: true, get: function () { return index_js_1.createFetcher; } });
|
|
15
15
|
const index_js_2 = require("./openapi/index.js");
|
|
16
16
|
Object.defineProperty(exports, "openapi", { enumerable: true, get: function () { return index_js_2.openapi; } });
|
|
17
|
-
Object.defineProperty(exports, "
|
|
18
|
-
Object.defineProperty(exports, "
|
|
17
|
+
Object.defineProperty(exports, "openAPIToVovkSchema", { enumerable: true, get: function () { return index_js_2.openAPIToVovkSchema; } });
|
|
18
|
+
Object.defineProperty(exports, "vovkSchemaToOpenAPI", { enumerable: true, get: function () { return index_js_2.vovkSchemaToOpenAPI; } });
|
|
19
19
|
const HttpException_js_1 = require("./HttpException.js");
|
|
20
20
|
Object.defineProperty(exports, "HttpException", { enumerable: true, get: function () { return HttpException_js_1.HttpException; } });
|
|
21
21
|
const createDecorator_js_1 = require("./utils/createDecorator.js");
|
package/cjs/openapi/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OperationObject } from 'openapi3-ts/oas31';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { vovkSchemaToOpenAPI } from './vovkSchemaToOpenAPI';
|
|
3
|
+
import { openAPIToVovkSchema } from './openAPIToVovkSchema';
|
|
4
4
|
import { error } from './error';
|
|
5
5
|
import type { KnownAny } from '../types';
|
|
6
6
|
type OperationObjectWithCustomProperties = OperationObject & {
|
|
@@ -10,4 +10,4 @@ export declare const openapiDecorator: (openAPIOperationObject?: OperationObject
|
|
|
10
10
|
export declare const openapi: typeof openapiDecorator & {
|
|
11
11
|
error: typeof error;
|
|
12
12
|
};
|
|
13
|
-
export {
|
|
13
|
+
export { vovkSchemaToOpenAPI, openAPIToVovkSchema };
|
package/cjs/openapi/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
5
|
-
Object.defineProperty(exports, "
|
|
6
|
-
const
|
|
7
|
-
Object.defineProperty(exports, "
|
|
3
|
+
exports.openAPIToVovkSchema = exports.vovkSchemaToOpenAPI = exports.openapi = exports.openapiDecorator = void 0;
|
|
4
|
+
const vovkSchemaToOpenAPI_1 = require("./vovkSchemaToOpenAPI");
|
|
5
|
+
Object.defineProperty(exports, "vovkSchemaToOpenAPI", { enumerable: true, get: function () { return vovkSchemaToOpenAPI_1.vovkSchemaToOpenAPI; } });
|
|
6
|
+
const openAPIToVovkSchema_1 = require("./openAPIToVovkSchema");
|
|
7
|
+
Object.defineProperty(exports, "openAPIToVovkSchema", { enumerable: true, get: function () { return openAPIToVovkSchema_1.openAPIToVovkSchema; } });
|
|
8
8
|
const error_1 = require("./error");
|
|
9
9
|
const createDecorator_1 = require("../utils/createDecorator");
|
|
10
10
|
exports.openapiDecorator = (0, createDecorator_1.createDecorator)(null, (openAPIOperationObject = {}) => {
|
|
@@ -7,7 +7,7 @@ declare const defaultGetHandlerInfo: ({ method, path, operation, defaultModuleNa
|
|
|
7
7
|
openAPIObject: OpenAPIObject;
|
|
8
8
|
defaultModuleName: string;
|
|
9
9
|
}) => [string, string];
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function openAPIToVovkSchema({ openAPIObject, getHandlerInfo, defaultModuleName, }: {
|
|
11
11
|
openAPIObject: OpenAPIObject;
|
|
12
12
|
getHandlerInfo?: typeof defaultGetHandlerInfo;
|
|
13
13
|
defaultModuleName?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.openAPIToVovkSchema = openAPIToVovkSchema;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const generateFnName_1 = require("./generateFnName");
|
|
6
6
|
function applyComponents(schema, components) {
|
|
@@ -66,7 +66,7 @@ const defaultGetHandlerInfo = ({ method, path, operation, defaultModuleName, })
|
|
|
66
66
|
: controllerName;
|
|
67
67
|
return [rpcModuleName, handlerName];
|
|
68
68
|
};
|
|
69
|
-
function
|
|
69
|
+
function openAPIToVovkSchema({ openAPIObject, getHandlerInfo = defaultGetHandlerInfo, defaultModuleName = 'api', }) {
|
|
70
70
|
const schema = {
|
|
71
71
|
$schema: types_1.VovkSchemaIdEnum.SCHEMA,
|
|
72
72
|
segments: {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OpenAPIObject, OperationObject } from 'openapi3-ts/oas31';
|
|
2
|
+
import { HttpMethod, type VovkSchema } from '../types';
|
|
3
|
+
declare const defaultGetHandlerInfo: ({ method, path, operation, defaultModuleName, }: {
|
|
4
|
+
method: HttpMethod;
|
|
5
|
+
path: string;
|
|
6
|
+
operation: OperationObject;
|
|
7
|
+
openAPIObject: OpenAPIObject;
|
|
8
|
+
defaultModuleName: string;
|
|
9
|
+
}) => [string, string];
|
|
10
|
+
export declare function openAPIToVovkSchema({ openAPIObject, getHandlerInfo, defaultModuleName, }: {
|
|
11
|
+
openAPIObject: OpenAPIObject;
|
|
12
|
+
getHandlerInfo?: typeof defaultGetHandlerInfo;
|
|
13
|
+
defaultModuleName?: string;
|
|
14
|
+
}): VovkSchema;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.openAPIToVovkSchema = openAPIToVovkSchema;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const generateFnName_1 = require("./generateFnName");
|
|
6
|
+
function applyComponents(schema, components) {
|
|
7
|
+
if (!components || !Object.keys(components).length)
|
|
8
|
+
return schema;
|
|
9
|
+
// Create a deep copy of the schema
|
|
10
|
+
const result = JSON.parse(JSON.stringify(schema));
|
|
11
|
+
// Initialize $defs if it doesn't exist
|
|
12
|
+
result.$defs = result.$defs || {};
|
|
13
|
+
// Set to track components we've added to $defs
|
|
14
|
+
const addedComponents = new Set();
|
|
15
|
+
// Process a schema object and replace $refs
|
|
16
|
+
function processSchema(obj) {
|
|
17
|
+
if (!obj || typeof obj !== 'object')
|
|
18
|
+
return obj;
|
|
19
|
+
// Create a new object/array to avoid modifying the input
|
|
20
|
+
const newObj = Array.isArray(obj) ? [...obj] : { ...obj };
|
|
21
|
+
// Check for $ref
|
|
22
|
+
if (newObj.$ref && typeof newObj.$ref === 'string' && newObj.$ref.startsWith('#/components/schemas/')) {
|
|
23
|
+
const componentName = newObj.$ref.replace('#/components/schemas/', '');
|
|
24
|
+
newObj.$ref = `#/$defs/${componentName}`;
|
|
25
|
+
// Add the component to $defs if not already added
|
|
26
|
+
if (!addedComponents.has(componentName) && components[componentName]) {
|
|
27
|
+
addedComponents.add(componentName);
|
|
28
|
+
result.$defs[componentName] = processSchema(JSON.parse(JSON.stringify(components[componentName])));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Process properties/items recursively
|
|
32
|
+
if (Array.isArray(newObj)) {
|
|
33
|
+
for (let i = 0; i < newObj.length; i++) {
|
|
34
|
+
newObj[i] = processSchema(newObj[i]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
for (const key in newObj) {
|
|
39
|
+
if (Object.prototype.hasOwnProperty.call(newObj, key)) {
|
|
40
|
+
newObj[key] = processSchema(newObj[key]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return newObj;
|
|
45
|
+
}
|
|
46
|
+
// Process the main schema
|
|
47
|
+
return processSchema(result);
|
|
48
|
+
}
|
|
49
|
+
function snakeToCamel(str) {
|
|
50
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
51
|
+
}
|
|
52
|
+
const defaultGetHandlerInfo = ({ method, path, operation, defaultModuleName, }) => {
|
|
53
|
+
const operationId = operation.operationId?.replace(/[^a-zA-Z0-9_]/g, '_') ?? null;
|
|
54
|
+
const controllerHandlerMatch = operationId?.match(/^([A-Z][a-zA-Z0-9]*)_([a-zA-Z0-9_]+)/);
|
|
55
|
+
const isSnakeCase = operationId && /^[a-z][a-z0-9_]+$/.test(operationId);
|
|
56
|
+
const [controllerName, handlerName] = controllerHandlerMatch?.slice(1, 3) ?? [
|
|
57
|
+
defaultModuleName,
|
|
58
|
+
isSnakeCase
|
|
59
|
+
? snakeToCamel(operationId)
|
|
60
|
+
: operationId?.match(/^[a-zA-Z][a-zA-Z0-9_]+$/)
|
|
61
|
+
? operationId
|
|
62
|
+
: (0, generateFnName_1.generateFnName)(method, path),
|
|
63
|
+
];
|
|
64
|
+
const rpcModuleName = controllerName.endsWith('Controller')
|
|
65
|
+
? controllerName.replace(/Controller$/, 'RPC')
|
|
66
|
+
: controllerName;
|
|
67
|
+
return [rpcModuleName, handlerName];
|
|
68
|
+
};
|
|
69
|
+
function openAPIToVovkSchema({ openAPIObject, getHandlerInfo = defaultGetHandlerInfo, defaultModuleName = 'api', }) {
|
|
70
|
+
const schema = {
|
|
71
|
+
$schema: types_1.VovkSchemaIdEnum.SCHEMA,
|
|
72
|
+
segments: {
|
|
73
|
+
'': {
|
|
74
|
+
$schema: types_1.VovkSchemaIdEnum.SEGMENT,
|
|
75
|
+
emitSchema: true,
|
|
76
|
+
segmentName: '',
|
|
77
|
+
controllers: {},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
meta: {
|
|
81
|
+
$schema: types_1.VovkSchemaIdEnum.META,
|
|
82
|
+
config: {
|
|
83
|
+
$schema: types_1.VovkSchemaIdEnum.CONFIG,
|
|
84
|
+
},
|
|
85
|
+
openapi: openAPIObject,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
const segment = schema.segments[''];
|
|
89
|
+
return Object.entries(openAPIObject.paths ?? {}).reduce((acc, [path, operations]) => {
|
|
90
|
+
Object.entries(operations).forEach(([method, operation]) => {
|
|
91
|
+
const [rpcModuleName, handlerName] = getHandlerInfo({
|
|
92
|
+
method: method.toUpperCase(),
|
|
93
|
+
path,
|
|
94
|
+
operation,
|
|
95
|
+
openAPIObject,
|
|
96
|
+
defaultModuleName,
|
|
97
|
+
});
|
|
98
|
+
segment.controllers[rpcModuleName] ??= {
|
|
99
|
+
rpcModuleName,
|
|
100
|
+
handlers: {},
|
|
101
|
+
};
|
|
102
|
+
// TODO how to utilize ReferenceObject?
|
|
103
|
+
const queryProperties = operation.parameters?.filter((p) => p.in === 'query') || [];
|
|
104
|
+
const pathProperties = operation.parameters?.filter((p) => p.in === 'path') || [];
|
|
105
|
+
const query = Array.isArray(operation.parameters)
|
|
106
|
+
? {
|
|
107
|
+
type: 'object',
|
|
108
|
+
properties: Object.fromEntries(queryProperties.map((p) => [p.name, p.schema])),
|
|
109
|
+
required: queryProperties.filter((p) => p.required).map((p) => p.name),
|
|
110
|
+
}
|
|
111
|
+
: null;
|
|
112
|
+
const params = Array.isArray(pathProperties)
|
|
113
|
+
? {
|
|
114
|
+
type: 'object',
|
|
115
|
+
properties: Object.fromEntries(pathProperties.map((p) => [p.name, p.schema])),
|
|
116
|
+
required: pathProperties.filter((p) => p.required).map((p) => p.name),
|
|
117
|
+
}
|
|
118
|
+
: null;
|
|
119
|
+
// TODO how to utilize ReferenceObject?
|
|
120
|
+
const body = operation.requestBody?.content['application/json']?.schema ?? null;
|
|
121
|
+
const output = operation.responses?.['200']?.content?.['application/json']?.schema ??
|
|
122
|
+
operation.responses?.['201']?.content?.['application/json']?.schema ??
|
|
123
|
+
null;
|
|
124
|
+
segment.controllers[rpcModuleName].handlers[handlerName] = {
|
|
125
|
+
httpMethod: method.toUpperCase(),
|
|
126
|
+
path,
|
|
127
|
+
openapi: operation,
|
|
128
|
+
validation: {
|
|
129
|
+
...(query && { query: applyComponents(query, openAPIObject.components?.schemas) }),
|
|
130
|
+
...(params && { params: applyComponents(params, openAPIObject.components?.schemas) }),
|
|
131
|
+
...(body && { body: applyComponents(body, openAPIObject.components?.schemas) }),
|
|
132
|
+
...(output && { output: applyComponents(output, openAPIObject.components?.schemas) }),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
return acc;
|
|
137
|
+
}, schema);
|
|
138
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OpenAPIObject } from 'openapi3-ts/oas31';
|
|
2
2
|
import { type CodeSamplePackageJson } from '../utils/createCodeExamples';
|
|
3
3
|
import { type VovkSchema } from '../types';
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject, package: packageJson, }: {
|
|
5
5
|
rootEntry: string;
|
|
6
6
|
schema: VovkSchema;
|
|
7
7
|
openAPIObject?: Partial<OpenAPIObject>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.vovkSchemaToOpenAPI = vovkSchemaToOpenAPI;
|
|
4
4
|
const json_schema_sampler_1 = require("@stoplight/json-schema-sampler");
|
|
5
5
|
const createCodeExamples_1 = require("../utils/createCodeExamples");
|
|
6
6
|
const types_1 = require("../types");
|
|
@@ -43,7 +43,7 @@ function extractComponents(schema) {
|
|
|
43
43
|
const processedSchema = process(schema);
|
|
44
44
|
return [processedSchema, components];
|
|
45
45
|
}
|
|
46
|
-
function
|
|
46
|
+
function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}, package: packageJson = { name: 'vovk-client' }, }) {
|
|
47
47
|
const paths = {};
|
|
48
48
|
const components = {};
|
|
49
49
|
for (const [segmentName, segmentSchema] of Object.entries(fullSchema.segments)) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { OpenAPIObject } from 'openapi3-ts/oas31';
|
|
2
|
+
import { type CodeSamplePackageJson } from '../utils/createCodeExamples';
|
|
3
|
+
import { type VovkSchema } from '../types';
|
|
4
|
+
export declare function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject, package: packageJson, }: {
|
|
5
|
+
rootEntry: string;
|
|
6
|
+
schema: VovkSchema;
|
|
7
|
+
openAPIObject?: Partial<OpenAPIObject>;
|
|
8
|
+
package?: CodeSamplePackageJson;
|
|
9
|
+
}): OpenAPIObject;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.vovkSchemaToOpenAPI = vovkSchemaToOpenAPI;
|
|
4
|
+
const json_schema_sampler_1 = require("@stoplight/json-schema-sampler");
|
|
5
|
+
const createCodeExamples_1 = require("../utils/createCodeExamples");
|
|
6
|
+
const types_1 = require("../types");
|
|
7
|
+
function extractComponents(schema) {
|
|
8
|
+
if (!schema)
|
|
9
|
+
return [undefined, {}];
|
|
10
|
+
const components = {};
|
|
11
|
+
// Function to collect components and replace $refs recursively
|
|
12
|
+
const process = (obj, path = []) => {
|
|
13
|
+
if (!obj || typeof obj !== 'object')
|
|
14
|
+
return obj;
|
|
15
|
+
// Handle arrays
|
|
16
|
+
if (Array.isArray(obj)) {
|
|
17
|
+
return obj.map((item) => process(item, path));
|
|
18
|
+
}
|
|
19
|
+
// Create a copy to modify
|
|
20
|
+
const result = {};
|
|
21
|
+
Object.entries({ ...obj.definitions, ...obj.$defs }).forEach(([key, value]) => {
|
|
22
|
+
components[key] = process(value, [...path, key]);
|
|
23
|
+
});
|
|
24
|
+
// Process all properties
|
|
25
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
26
|
+
// Skip already processed special properties
|
|
27
|
+
if (key === '$defs' || key === 'definitions')
|
|
28
|
+
continue;
|
|
29
|
+
if (key === '$ref' && typeof value === 'string') {
|
|
30
|
+
// Extract the component name from the reference
|
|
31
|
+
const refParts = value.split('/');
|
|
32
|
+
const refName = refParts[refParts.length - 1];
|
|
33
|
+
// Replace with component reference
|
|
34
|
+
result[key] = `#/components/schemas/${refName}`;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Recursively process other properties
|
|
38
|
+
result[key] = process(value, [...path, key]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
const processedSchema = process(schema);
|
|
44
|
+
return [processedSchema, components];
|
|
45
|
+
}
|
|
46
|
+
function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}, package: packageJson = { name: 'vovk-client' }, }) {
|
|
47
|
+
const paths = {};
|
|
48
|
+
const components = {};
|
|
49
|
+
for (const [segmentName, segmentSchema] of Object.entries(fullSchema.segments)) {
|
|
50
|
+
for (const c of Object.values(segmentSchema.controllers)) {
|
|
51
|
+
for (const [handlerName, h] of Object.entries(c.handlers)) {
|
|
52
|
+
if (h.openapi) {
|
|
53
|
+
const [queryValidation, queryComponents] = extractComponents(h?.validation?.query);
|
|
54
|
+
const [bodyValidation, bodyComponents] = extractComponents(h?.validation?.body);
|
|
55
|
+
const [paramsValidation, paramsComponents] = extractComponents(h?.validation?.params);
|
|
56
|
+
const [outputValidation, outputComponents] = extractComponents(h?.validation?.output);
|
|
57
|
+
const [iterationValidation, iterationComponents] = extractComponents(h?.validation?.iteration);
|
|
58
|
+
// TODO: Handle name conflicts?
|
|
59
|
+
Object.assign(components, queryComponents, bodyComponents, paramsComponents, outputComponents, iterationComponents);
|
|
60
|
+
const { ts, rs, py } = (0, createCodeExamples_1.createCodeExamples)({
|
|
61
|
+
package: packageJson,
|
|
62
|
+
handlerName,
|
|
63
|
+
handlerSchema: h,
|
|
64
|
+
controllerSchema: c,
|
|
65
|
+
});
|
|
66
|
+
const queryParameters = queryValidation && 'type' in queryValidation && 'properties' in queryValidation
|
|
67
|
+
? Object.entries(queryValidation.properties).map(([propName, propSchema]) => ({
|
|
68
|
+
name: propName,
|
|
69
|
+
in: 'query',
|
|
70
|
+
required: queryValidation.required ? queryValidation.required.includes(propName) : false,
|
|
71
|
+
schema: propSchema,
|
|
72
|
+
}))
|
|
73
|
+
: null;
|
|
74
|
+
const pathParameters = paramsValidation && 'type' in paramsValidation && 'properties' in paramsValidation
|
|
75
|
+
? Object.entries(paramsValidation.properties).map(([propName, propSchema]) => ({
|
|
76
|
+
name: propName,
|
|
77
|
+
in: 'path',
|
|
78
|
+
required: paramsValidation.required ? paramsValidation.required.includes(propName) : false,
|
|
79
|
+
schema: propSchema,
|
|
80
|
+
}))
|
|
81
|
+
: null;
|
|
82
|
+
const path = '/' +
|
|
83
|
+
[rootEntry.replace(/^\/+|\/+$/g, ''), segmentName, c.prefix, h.path]
|
|
84
|
+
.filter(Boolean)
|
|
85
|
+
.join('/')
|
|
86
|
+
.replace(/:([a-zA-Z0-9_]+)/g, '{$1}');
|
|
87
|
+
paths[path] = paths[path] ?? {};
|
|
88
|
+
const httpMethod = h.httpMethod.toLowerCase();
|
|
89
|
+
paths[path][httpMethod] ??= {};
|
|
90
|
+
paths[path][httpMethod] = {
|
|
91
|
+
...h.openapi,
|
|
92
|
+
...paths[path][httpMethod],
|
|
93
|
+
'x-codeSamples': [
|
|
94
|
+
...(paths[path][httpMethod]['x-codeSamples'] ?? []),
|
|
95
|
+
...(h.openapi['x-codeSamples'] ?? []),
|
|
96
|
+
{
|
|
97
|
+
label: 'TypeScript RPC',
|
|
98
|
+
lang: 'typescript',
|
|
99
|
+
source: ts,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
label: 'Python RPC',
|
|
103
|
+
lang: 'python',
|
|
104
|
+
source: py,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
label: 'Rust RPC',
|
|
108
|
+
lang: 'rust',
|
|
109
|
+
source: rs,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
...(queryParameters || pathParameters
|
|
113
|
+
? {
|
|
114
|
+
parameters: h.openapi.parameters ?? [...(queryParameters || []), ...(pathParameters || [])],
|
|
115
|
+
}
|
|
116
|
+
: {}),
|
|
117
|
+
...(paths[path][httpMethod].parameters
|
|
118
|
+
? {
|
|
119
|
+
parameters: paths[path][httpMethod].parameters,
|
|
120
|
+
}
|
|
121
|
+
: {}),
|
|
122
|
+
...(outputValidation && 'type' in outputValidation && 'properties' in outputValidation
|
|
123
|
+
? {
|
|
124
|
+
responses: {
|
|
125
|
+
200: {
|
|
126
|
+
description: 'description' in outputValidation ? outputValidation.description : 'Success',
|
|
127
|
+
content: {
|
|
128
|
+
'application/json': {
|
|
129
|
+
schema: outputValidation,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
...h.openapi?.responses,
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
: {}),
|
|
137
|
+
...(iterationValidation && 'type' in iterationValidation && 'properties' in iterationValidation
|
|
138
|
+
? {
|
|
139
|
+
responses: {
|
|
140
|
+
200: {
|
|
141
|
+
description: 'description' in iterationValidation ? iterationValidation.description : 'JSON Lines response',
|
|
142
|
+
content: {
|
|
143
|
+
'application/jsonl': {
|
|
144
|
+
schema: {
|
|
145
|
+
...iterationValidation,
|
|
146
|
+
examples: iterationValidation.examples ?? [
|
|
147
|
+
[
|
|
148
|
+
JSON.stringify((0, json_schema_sampler_1.sample)(iterationValidation)),
|
|
149
|
+
JSON.stringify((0, json_schema_sampler_1.sample)(iterationValidation)),
|
|
150
|
+
JSON.stringify((0, json_schema_sampler_1.sample)(iterationValidation)),
|
|
151
|
+
].join('\n'),
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
...h.openapi?.responses,
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
: {}),
|
|
161
|
+
...(paths[path][httpMethod].responses
|
|
162
|
+
? {
|
|
163
|
+
responses: paths[path][httpMethod].responses,
|
|
164
|
+
}
|
|
165
|
+
: {}),
|
|
166
|
+
...(bodyValidation && 'type' in bodyValidation && 'properties' in bodyValidation
|
|
167
|
+
? {
|
|
168
|
+
requestBody: h.openapi?.requestBody ?? {
|
|
169
|
+
description: 'description' in bodyValidation ? bodyValidation.description : 'Request body',
|
|
170
|
+
required: true,
|
|
171
|
+
content: {
|
|
172
|
+
'application/json': {
|
|
173
|
+
schema: bodyValidation,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
: {}),
|
|
179
|
+
...(paths[path][httpMethod].requestBody
|
|
180
|
+
? {
|
|
181
|
+
requestBody: paths[path][httpMethod].requestBody,
|
|
182
|
+
}
|
|
183
|
+
: {}),
|
|
184
|
+
tags: paths[path][httpMethod].tags ?? h.openapi?.tags,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
...openAPIObject,
|
|
192
|
+
openapi: '3.1.0',
|
|
193
|
+
info: {
|
|
194
|
+
title: packageJson?.description ?? 'API',
|
|
195
|
+
version: packageJson?.version ?? '0.0.1',
|
|
196
|
+
...openAPIObject?.info,
|
|
197
|
+
},
|
|
198
|
+
components: {
|
|
199
|
+
schemas: {
|
|
200
|
+
...(openAPIObject?.components?.schemas ?? components),
|
|
201
|
+
HttpStatus: {
|
|
202
|
+
type: 'integer',
|
|
203
|
+
description: 'HTTP status code',
|
|
204
|
+
enum: Object.keys(types_1.HttpStatus)
|
|
205
|
+
.map((k) => types_1.HttpStatus[k])
|
|
206
|
+
.filter(Boolean)
|
|
207
|
+
.filter((v) => typeof v === 'number'),
|
|
208
|
+
},
|
|
209
|
+
VovkErrorResponse: {
|
|
210
|
+
type: 'object',
|
|
211
|
+
description: 'Vovk error response',
|
|
212
|
+
properties: {
|
|
213
|
+
cause: {
|
|
214
|
+
description: 'Error cause of any shape',
|
|
215
|
+
},
|
|
216
|
+
statusCode: {
|
|
217
|
+
$ref: '#/components/schemas/HttpStatus',
|
|
218
|
+
},
|
|
219
|
+
message: {
|
|
220
|
+
type: 'string',
|
|
221
|
+
description: 'Error message',
|
|
222
|
+
},
|
|
223
|
+
isError: {
|
|
224
|
+
type: 'boolean',
|
|
225
|
+
const: true,
|
|
226
|
+
description: 'Indicates that this object represents an error',
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
required: ['statusCode', 'message', 'isError'],
|
|
230
|
+
additionalProperties: false,
|
|
231
|
+
},
|
|
232
|
+
...openAPIObject?.components?.schemas,
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
paths,
|
|
236
|
+
};
|
|
237
|
+
}
|
package/cjs/types.d.ts
CHANGED
|
@@ -96,6 +96,16 @@ export type ControllerStaticMethod<REQ extends VovkRequest<KnownAny, KnownAny> =
|
|
|
96
96
|
} = KnownAny> = ((req: REQ, params: PARAMS) => unknown) & {
|
|
97
97
|
_controller?: VovkController;
|
|
98
98
|
};
|
|
99
|
+
export type VovkTypedMethod<T extends (...args: KnownAny[]) => KnownAny, B = KnownAny, Q = KnownAny, P = KnownAny, O = KnownAny, I = KnownAny> = T & {
|
|
100
|
+
__types: {
|
|
101
|
+
body?: B;
|
|
102
|
+
query?: Q;
|
|
103
|
+
params?: P;
|
|
104
|
+
output?: O;
|
|
105
|
+
iteration?: I;
|
|
106
|
+
};
|
|
107
|
+
isRPC?: boolean;
|
|
108
|
+
};
|
|
99
109
|
export type VovkControllerBody<T extends (...args: KnownAny) => KnownAny> = Awaited<ReturnType<Parameters<T>[0]['vovk']['body']>>;
|
|
100
110
|
export type VovkControllerQuery<T extends (...args: KnownAny) => KnownAny> = ReturnType<Parameters<T>[0]['vovk']['query']>;
|
|
101
111
|
export type VovkControllerParams<T extends (...args: KnownAny) => KnownAny> = Parameters<T>[1] extends object ? Parameters<T>[1] : ReturnType<Parameters<T>[0]['vovk']['params']>;
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import { VovkHandlerSchema, VovkValidationType, type KnownAny, type VovkRequest } from '../types.js';
|
|
1
|
+
import { VovkHandlerSchema, VovkTypedMethod, VovkValidationType, type KnownAny, type VovkRequest } from '../types.js';
|
|
2
2
|
type VovkRequestAny = VovkRequest<KnownAny, KnownAny, KnownAny>;
|
|
3
|
-
export declare function withValidation<T extends (
|
|
4
|
-
__types: {
|
|
5
|
-
body: KnownAny;
|
|
6
|
-
query: KnownAny;
|
|
7
|
-
params: KnownAny;
|
|
8
|
-
output: KnownAny;
|
|
9
|
-
iteration: KnownAny;
|
|
10
|
-
};
|
|
11
|
-
}, BODY_MODEL, QUERY_MODEL, PARAMS_MODEL, OUTPUT_MODEL, ITERATION_MODEL>({ disableServerSideValidation, skipSchemaEmission, validateEachIteration, body, query, params, output, iteration, handle, getJSONSchemaFromModel, validate, }: {
|
|
3
|
+
export declare function withValidation<T extends VovkTypedMethod<(req: KnownAny, params: KnownAny) => KnownAny>, BODY_MODEL, QUERY_MODEL, PARAMS_MODEL, OUTPUT_MODEL, ITERATION_MODEL>({ disableServerSideValidation, skipSchemaEmission, validateEachIteration, body, query, params, output, iteration, handle, getJSONSchemaFromModel, validate, }: {
|
|
12
4
|
disableServerSideValidation?: boolean | VovkValidationType[];
|
|
13
5
|
skipSchemaEmission?: boolean | VovkValidationType[];
|
|
14
6
|
validateEachIteration?: boolean;
|
package/mjs/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createVovkApp } from './createVovkApp.js';
|
|
2
|
-
import { HttpStatus, HttpMethod, VovkSchemaIdEnum, type KnownAny, type VovkErrorResponse, type VovkRequest, type VovkBody, type VovkQuery, type VovkParams, type VovkReturnType, type VovkYieldType, type VovkOutput, type VovkIteration, type VovkSegmentSchema, type VovkControllerSchema, type VovkHandlerSchema, type VovkSchema, type VovkConfig, type VovkStrictConfig, type VovkValidationType, type VovkLLMFunction } from './types.js';
|
|
2
|
+
import { HttpStatus, HttpMethod, VovkSchemaIdEnum, type KnownAny, type VovkErrorResponse, type VovkRequest, type VovkBody, type VovkQuery, type VovkParams, type VovkReturnType, type VovkYieldType, type VovkOutput, type VovkIteration, type VovkSegmentSchema, type VovkControllerSchema, type VovkHandlerSchema, type VovkSchema, type VovkConfig, type VovkStrictConfig, type VovkValidationType, type VovkLLMFunction, type VovkTypedMethod } from './types.js';
|
|
3
3
|
import { type VovkClient, type VovkClientOptions, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkValidateOnClient, type VovkStreamAsyncIterable, createRPC, fetcher, createFetcher } from './client/index.js';
|
|
4
|
-
import { openapi,
|
|
4
|
+
import { openapi, openAPIToVovkSchema, vovkSchemaToOpenAPI } from './openapi/index.js';
|
|
5
5
|
import { HttpException } from './HttpException.js';
|
|
6
6
|
import { createDecorator } from './utils/createDecorator.js';
|
|
7
7
|
import { JSONLinesResponse } from './JSONLinesResponse.js';
|
|
@@ -10,7 +10,7 @@ import { withValidation } from './utils/withValidation.js';
|
|
|
10
10
|
import { multitenant } from './utils/multitenant.js';
|
|
11
11
|
import { createLLMFunctions } from './utils/createLLMFunctions.js';
|
|
12
12
|
import { createCodeExamples } from './utils/createCodeExamples.js';
|
|
13
|
-
export { type KnownAny, type VovkClient, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkStreamAsyncIterable, type VovkValidateOnClient, type VovkSegmentSchema, type VovkErrorResponse, type VovkRequest, type VovkOutput, type VovkIteration, type VovkBody, type VovkQuery, type VovkParams, type VovkYieldType, type VovkReturnType, type VovkClientOptions, type VovkControllerSchema, type VovkHandlerSchema, type VovkSchema, type VovkConfig, type VovkStrictConfig, type VovkValidationType, type VovkLLMFunction, VovkSchemaIdEnum, JSONLinesResponse, HttpException, HttpStatus, HttpMethod, createVovkApp, createDecorator, createRPC, fetcher, createFetcher, generateStaticAPI, withValidation, multitenant, createLLMFunctions, createCodeExamples, openapi,
|
|
13
|
+
export { type KnownAny, type VovkClient, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkStreamAsyncIterable, type VovkValidateOnClient, type VovkSegmentSchema, type VovkErrorResponse, type VovkRequest, type VovkOutput, type VovkIteration, type VovkBody, type VovkQuery, type VovkParams, type VovkYieldType, type VovkReturnType, type VovkClientOptions, type VovkControllerSchema, type VovkHandlerSchema, type VovkSchema, type VovkConfig, type VovkStrictConfig, type VovkValidationType, type VovkLLMFunction, type VovkTypedMethod, VovkSchemaIdEnum, JSONLinesResponse, HttpException, HttpStatus, HttpMethod, createVovkApp, createDecorator, createRPC, fetcher, createFetcher, generateStaticAPI, withValidation, multitenant, createLLMFunctions, createCodeExamples, openapi, openAPIToVovkSchema, vovkSchemaToOpenAPI, };
|
|
14
14
|
export declare const get: {
|
|
15
15
|
(givenPath?: string | undefined, options?: import("./types.js").DecoratorOptions | undefined): ReturnType<(givenPath?: string, options?: import("./types.js").DecoratorOptions) => (givenTarget: KnownAny, propertyKey: string) => void>;
|
|
16
16
|
auto: (options?: import("./types.js").DecoratorOptions) => (givenTarget: KnownAny, propertyKey: string) => void;
|
package/mjs/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.initVovk = exports.prefix = exports.options = exports.head = exports.del = exports.patch = exports.put = exports.post = exports.get = exports.
|
|
4
|
+
exports.initVovk = exports.prefix = exports.options = exports.head = exports.del = exports.patch = exports.put = exports.post = exports.get = exports.vovkSchemaToOpenAPI = exports.openAPIToVovkSchema = exports.openapi = exports.createCodeExamples = exports.createLLMFunctions = exports.multitenant = exports.withValidation = exports.generateStaticAPI = exports.createFetcher = exports.fetcher = exports.createRPC = exports.createDecorator = exports.createVovkApp = exports.HttpMethod = exports.HttpStatus = exports.HttpException = exports.JSONLinesResponse = exports.VovkSchemaIdEnum = void 0;
|
|
5
5
|
const createVovkApp_js_1 = require("./createVovkApp.js");
|
|
6
6
|
Object.defineProperty(exports, "createVovkApp", { enumerable: true, get: function () { return createVovkApp_js_1.createVovkApp; } });
|
|
7
7
|
const types_js_1 = require("./types.js");
|
|
@@ -14,8 +14,8 @@ Object.defineProperty(exports, "fetcher", { enumerable: true, get: function () {
|
|
|
14
14
|
Object.defineProperty(exports, "createFetcher", { enumerable: true, get: function () { return index_js_1.createFetcher; } });
|
|
15
15
|
const index_js_2 = require("./openapi/index.js");
|
|
16
16
|
Object.defineProperty(exports, "openapi", { enumerable: true, get: function () { return index_js_2.openapi; } });
|
|
17
|
-
Object.defineProperty(exports, "
|
|
18
|
-
Object.defineProperty(exports, "
|
|
17
|
+
Object.defineProperty(exports, "openAPIToVovkSchema", { enumerable: true, get: function () { return index_js_2.openAPIToVovkSchema; } });
|
|
18
|
+
Object.defineProperty(exports, "vovkSchemaToOpenAPI", { enumerable: true, get: function () { return index_js_2.vovkSchemaToOpenAPI; } });
|
|
19
19
|
const HttpException_js_1 = require("./HttpException.js");
|
|
20
20
|
Object.defineProperty(exports, "HttpException", { enumerable: true, get: function () { return HttpException_js_1.HttpException; } });
|
|
21
21
|
const createDecorator_js_1 = require("./utils/createDecorator.js");
|
package/mjs/openapi/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OperationObject } from 'openapi3-ts/oas31';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { vovkSchemaToOpenAPI } from './vovkSchemaToOpenAPI';
|
|
3
|
+
import { openAPIToVovkSchema } from './openAPIToVovkSchema';
|
|
4
4
|
import { error } from './error';
|
|
5
5
|
import type { KnownAny } from '../types';
|
|
6
6
|
type OperationObjectWithCustomProperties = OperationObject & {
|
|
@@ -10,4 +10,4 @@ export declare const openapiDecorator: (openAPIOperationObject?: OperationObject
|
|
|
10
10
|
export declare const openapi: typeof openapiDecorator & {
|
|
11
11
|
error: typeof error;
|
|
12
12
|
};
|
|
13
|
-
export {
|
|
13
|
+
export { vovkSchemaToOpenAPI, openAPIToVovkSchema };
|
package/mjs/openapi/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
5
|
-
Object.defineProperty(exports, "
|
|
6
|
-
const
|
|
7
|
-
Object.defineProperty(exports, "
|
|
3
|
+
exports.openAPIToVovkSchema = exports.vovkSchemaToOpenAPI = exports.openapi = exports.openapiDecorator = void 0;
|
|
4
|
+
const vovkSchemaToOpenAPI_1 = require("./vovkSchemaToOpenAPI");
|
|
5
|
+
Object.defineProperty(exports, "vovkSchemaToOpenAPI", { enumerable: true, get: function () { return vovkSchemaToOpenAPI_1.vovkSchemaToOpenAPI; } });
|
|
6
|
+
const openAPIToVovkSchema_1 = require("./openAPIToVovkSchema");
|
|
7
|
+
Object.defineProperty(exports, "openAPIToVovkSchema", { enumerable: true, get: function () { return openAPIToVovkSchema_1.openAPIToVovkSchema; } });
|
|
8
8
|
const error_1 = require("./error");
|
|
9
9
|
const createDecorator_1 = require("../utils/createDecorator");
|
|
10
10
|
exports.openapiDecorator = (0, createDecorator_1.createDecorator)(null, (openAPIOperationObject = {}) => {
|
|
@@ -7,7 +7,7 @@ declare const defaultGetHandlerInfo: ({ method, path, operation, defaultModuleNa
|
|
|
7
7
|
openAPIObject: OpenAPIObject;
|
|
8
8
|
defaultModuleName: string;
|
|
9
9
|
}) => [string, string];
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function openAPIToVovkSchema({ openAPIObject, getHandlerInfo, defaultModuleName, }: {
|
|
11
11
|
openAPIObject: OpenAPIObject;
|
|
12
12
|
getHandlerInfo?: typeof defaultGetHandlerInfo;
|
|
13
13
|
defaultModuleName?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.openAPIToVovkSchema = openAPIToVovkSchema;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const generateFnName_1 = require("./generateFnName");
|
|
6
6
|
function applyComponents(schema, components) {
|
|
@@ -66,7 +66,7 @@ const defaultGetHandlerInfo = ({ method, path, operation, defaultModuleName, })
|
|
|
66
66
|
: controllerName;
|
|
67
67
|
return [rpcModuleName, handlerName];
|
|
68
68
|
};
|
|
69
|
-
function
|
|
69
|
+
function openAPIToVovkSchema({ openAPIObject, getHandlerInfo = defaultGetHandlerInfo, defaultModuleName = 'api', }) {
|
|
70
70
|
const schema = {
|
|
71
71
|
$schema: types_1.VovkSchemaIdEnum.SCHEMA,
|
|
72
72
|
segments: {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OpenAPIObject, OperationObject } from 'openapi3-ts/oas31';
|
|
2
|
+
import { HttpMethod, type VovkSchema } from '../types';
|
|
3
|
+
declare const defaultGetHandlerInfo: ({ method, path, operation, defaultModuleName, }: {
|
|
4
|
+
method: HttpMethod;
|
|
5
|
+
path: string;
|
|
6
|
+
operation: OperationObject;
|
|
7
|
+
openAPIObject: OpenAPIObject;
|
|
8
|
+
defaultModuleName: string;
|
|
9
|
+
}) => [string, string];
|
|
10
|
+
export declare function openAPIToVovkSchema({ openAPIObject, getHandlerInfo, defaultModuleName, }: {
|
|
11
|
+
openAPIObject: OpenAPIObject;
|
|
12
|
+
getHandlerInfo?: typeof defaultGetHandlerInfo;
|
|
13
|
+
defaultModuleName?: string;
|
|
14
|
+
}): VovkSchema;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.openAPIToVovkSchema = openAPIToVovkSchema;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const generateFnName_1 = require("./generateFnName");
|
|
6
|
+
function applyComponents(schema, components) {
|
|
7
|
+
if (!components || !Object.keys(components).length)
|
|
8
|
+
return schema;
|
|
9
|
+
// Create a deep copy of the schema
|
|
10
|
+
const result = JSON.parse(JSON.stringify(schema));
|
|
11
|
+
// Initialize $defs if it doesn't exist
|
|
12
|
+
result.$defs = result.$defs || {};
|
|
13
|
+
// Set to track components we've added to $defs
|
|
14
|
+
const addedComponents = new Set();
|
|
15
|
+
// Process a schema object and replace $refs
|
|
16
|
+
function processSchema(obj) {
|
|
17
|
+
if (!obj || typeof obj !== 'object')
|
|
18
|
+
return obj;
|
|
19
|
+
// Create a new object/array to avoid modifying the input
|
|
20
|
+
const newObj = Array.isArray(obj) ? [...obj] : { ...obj };
|
|
21
|
+
// Check for $ref
|
|
22
|
+
if (newObj.$ref && typeof newObj.$ref === 'string' && newObj.$ref.startsWith('#/components/schemas/')) {
|
|
23
|
+
const componentName = newObj.$ref.replace('#/components/schemas/', '');
|
|
24
|
+
newObj.$ref = `#/$defs/${componentName}`;
|
|
25
|
+
// Add the component to $defs if not already added
|
|
26
|
+
if (!addedComponents.has(componentName) && components[componentName]) {
|
|
27
|
+
addedComponents.add(componentName);
|
|
28
|
+
result.$defs[componentName] = processSchema(JSON.parse(JSON.stringify(components[componentName])));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Process properties/items recursively
|
|
32
|
+
if (Array.isArray(newObj)) {
|
|
33
|
+
for (let i = 0; i < newObj.length; i++) {
|
|
34
|
+
newObj[i] = processSchema(newObj[i]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
for (const key in newObj) {
|
|
39
|
+
if (Object.prototype.hasOwnProperty.call(newObj, key)) {
|
|
40
|
+
newObj[key] = processSchema(newObj[key]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return newObj;
|
|
45
|
+
}
|
|
46
|
+
// Process the main schema
|
|
47
|
+
return processSchema(result);
|
|
48
|
+
}
|
|
49
|
+
function snakeToCamel(str) {
|
|
50
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
51
|
+
}
|
|
52
|
+
const defaultGetHandlerInfo = ({ method, path, operation, defaultModuleName, }) => {
|
|
53
|
+
const operationId = operation.operationId?.replace(/[^a-zA-Z0-9_]/g, '_') ?? null;
|
|
54
|
+
const controllerHandlerMatch = operationId?.match(/^([A-Z][a-zA-Z0-9]*)_([a-zA-Z0-9_]+)/);
|
|
55
|
+
const isSnakeCase = operationId && /^[a-z][a-z0-9_]+$/.test(operationId);
|
|
56
|
+
const [controllerName, handlerName] = controllerHandlerMatch?.slice(1, 3) ?? [
|
|
57
|
+
defaultModuleName,
|
|
58
|
+
isSnakeCase
|
|
59
|
+
? snakeToCamel(operationId)
|
|
60
|
+
: operationId?.match(/^[a-zA-Z][a-zA-Z0-9_]+$/)
|
|
61
|
+
? operationId
|
|
62
|
+
: (0, generateFnName_1.generateFnName)(method, path),
|
|
63
|
+
];
|
|
64
|
+
const rpcModuleName = controllerName.endsWith('Controller')
|
|
65
|
+
? controllerName.replace(/Controller$/, 'RPC')
|
|
66
|
+
: controllerName;
|
|
67
|
+
return [rpcModuleName, handlerName];
|
|
68
|
+
};
|
|
69
|
+
function openAPIToVovkSchema({ openAPIObject, getHandlerInfo = defaultGetHandlerInfo, defaultModuleName = 'api', }) {
|
|
70
|
+
const schema = {
|
|
71
|
+
$schema: types_1.VovkSchemaIdEnum.SCHEMA,
|
|
72
|
+
segments: {
|
|
73
|
+
'': {
|
|
74
|
+
$schema: types_1.VovkSchemaIdEnum.SEGMENT,
|
|
75
|
+
emitSchema: true,
|
|
76
|
+
segmentName: '',
|
|
77
|
+
controllers: {},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
meta: {
|
|
81
|
+
$schema: types_1.VovkSchemaIdEnum.META,
|
|
82
|
+
config: {
|
|
83
|
+
$schema: types_1.VovkSchemaIdEnum.CONFIG,
|
|
84
|
+
},
|
|
85
|
+
openapi: openAPIObject,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
const segment = schema.segments[''];
|
|
89
|
+
return Object.entries(openAPIObject.paths ?? {}).reduce((acc, [path, operations]) => {
|
|
90
|
+
Object.entries(operations).forEach(([method, operation]) => {
|
|
91
|
+
const [rpcModuleName, handlerName] = getHandlerInfo({
|
|
92
|
+
method: method.toUpperCase(),
|
|
93
|
+
path,
|
|
94
|
+
operation,
|
|
95
|
+
openAPIObject,
|
|
96
|
+
defaultModuleName,
|
|
97
|
+
});
|
|
98
|
+
segment.controllers[rpcModuleName] ??= {
|
|
99
|
+
rpcModuleName,
|
|
100
|
+
handlers: {},
|
|
101
|
+
};
|
|
102
|
+
// TODO how to utilize ReferenceObject?
|
|
103
|
+
const queryProperties = operation.parameters?.filter((p) => p.in === 'query') || [];
|
|
104
|
+
const pathProperties = operation.parameters?.filter((p) => p.in === 'path') || [];
|
|
105
|
+
const query = Array.isArray(operation.parameters)
|
|
106
|
+
? {
|
|
107
|
+
type: 'object',
|
|
108
|
+
properties: Object.fromEntries(queryProperties.map((p) => [p.name, p.schema])),
|
|
109
|
+
required: queryProperties.filter((p) => p.required).map((p) => p.name),
|
|
110
|
+
}
|
|
111
|
+
: null;
|
|
112
|
+
const params = Array.isArray(pathProperties)
|
|
113
|
+
? {
|
|
114
|
+
type: 'object',
|
|
115
|
+
properties: Object.fromEntries(pathProperties.map((p) => [p.name, p.schema])),
|
|
116
|
+
required: pathProperties.filter((p) => p.required).map((p) => p.name),
|
|
117
|
+
}
|
|
118
|
+
: null;
|
|
119
|
+
// TODO how to utilize ReferenceObject?
|
|
120
|
+
const body = operation.requestBody?.content['application/json']?.schema ?? null;
|
|
121
|
+
const output = operation.responses?.['200']?.content?.['application/json']?.schema ??
|
|
122
|
+
operation.responses?.['201']?.content?.['application/json']?.schema ??
|
|
123
|
+
null;
|
|
124
|
+
segment.controllers[rpcModuleName].handlers[handlerName] = {
|
|
125
|
+
httpMethod: method.toUpperCase(),
|
|
126
|
+
path,
|
|
127
|
+
openapi: operation,
|
|
128
|
+
validation: {
|
|
129
|
+
...(query && { query: applyComponents(query, openAPIObject.components?.schemas) }),
|
|
130
|
+
...(params && { params: applyComponents(params, openAPIObject.components?.schemas) }),
|
|
131
|
+
...(body && { body: applyComponents(body, openAPIObject.components?.schemas) }),
|
|
132
|
+
...(output && { output: applyComponents(output, openAPIObject.components?.schemas) }),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
return acc;
|
|
137
|
+
}, schema);
|
|
138
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OpenAPIObject } from 'openapi3-ts/oas31';
|
|
2
2
|
import { type CodeSamplePackageJson } from '../utils/createCodeExamples';
|
|
3
3
|
import { type VovkSchema } from '../types';
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject, package: packageJson, }: {
|
|
5
5
|
rootEntry: string;
|
|
6
6
|
schema: VovkSchema;
|
|
7
7
|
openAPIObject?: Partial<OpenAPIObject>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.vovkSchemaToOpenAPI = vovkSchemaToOpenAPI;
|
|
4
4
|
const json_schema_sampler_1 = require("@stoplight/json-schema-sampler");
|
|
5
5
|
const createCodeExamples_1 = require("../utils/createCodeExamples");
|
|
6
6
|
const types_1 = require("../types");
|
|
@@ -43,7 +43,7 @@ function extractComponents(schema) {
|
|
|
43
43
|
const processedSchema = process(schema);
|
|
44
44
|
return [processedSchema, components];
|
|
45
45
|
}
|
|
46
|
-
function
|
|
46
|
+
function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}, package: packageJson = { name: 'vovk-client' }, }) {
|
|
47
47
|
const paths = {};
|
|
48
48
|
const components = {};
|
|
49
49
|
for (const [segmentName, segmentSchema] of Object.entries(fullSchema.segments)) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { OpenAPIObject } from 'openapi3-ts/oas31';
|
|
2
|
+
import { type CodeSamplePackageJson } from '../utils/createCodeExamples';
|
|
3
|
+
import { type VovkSchema } from '../types';
|
|
4
|
+
export declare function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject, package: packageJson, }: {
|
|
5
|
+
rootEntry: string;
|
|
6
|
+
schema: VovkSchema;
|
|
7
|
+
openAPIObject?: Partial<OpenAPIObject>;
|
|
8
|
+
package?: CodeSamplePackageJson;
|
|
9
|
+
}): OpenAPIObject;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.vovkSchemaToOpenAPI = vovkSchemaToOpenAPI;
|
|
4
|
+
const json_schema_sampler_1 = require("@stoplight/json-schema-sampler");
|
|
5
|
+
const createCodeExamples_1 = require("../utils/createCodeExamples");
|
|
6
|
+
const types_1 = require("../types");
|
|
7
|
+
function extractComponents(schema) {
|
|
8
|
+
if (!schema)
|
|
9
|
+
return [undefined, {}];
|
|
10
|
+
const components = {};
|
|
11
|
+
// Function to collect components and replace $refs recursively
|
|
12
|
+
const process = (obj, path = []) => {
|
|
13
|
+
if (!obj || typeof obj !== 'object')
|
|
14
|
+
return obj;
|
|
15
|
+
// Handle arrays
|
|
16
|
+
if (Array.isArray(obj)) {
|
|
17
|
+
return obj.map((item) => process(item, path));
|
|
18
|
+
}
|
|
19
|
+
// Create a copy to modify
|
|
20
|
+
const result = {};
|
|
21
|
+
Object.entries({ ...obj.definitions, ...obj.$defs }).forEach(([key, value]) => {
|
|
22
|
+
components[key] = process(value, [...path, key]);
|
|
23
|
+
});
|
|
24
|
+
// Process all properties
|
|
25
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
26
|
+
// Skip already processed special properties
|
|
27
|
+
if (key === '$defs' || key === 'definitions')
|
|
28
|
+
continue;
|
|
29
|
+
if (key === '$ref' && typeof value === 'string') {
|
|
30
|
+
// Extract the component name from the reference
|
|
31
|
+
const refParts = value.split('/');
|
|
32
|
+
const refName = refParts[refParts.length - 1];
|
|
33
|
+
// Replace with component reference
|
|
34
|
+
result[key] = `#/components/schemas/${refName}`;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Recursively process other properties
|
|
38
|
+
result[key] = process(value, [...path, key]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
const processedSchema = process(schema);
|
|
44
|
+
return [processedSchema, components];
|
|
45
|
+
}
|
|
46
|
+
function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}, package: packageJson = { name: 'vovk-client' }, }) {
|
|
47
|
+
const paths = {};
|
|
48
|
+
const components = {};
|
|
49
|
+
for (const [segmentName, segmentSchema] of Object.entries(fullSchema.segments)) {
|
|
50
|
+
for (const c of Object.values(segmentSchema.controllers)) {
|
|
51
|
+
for (const [handlerName, h] of Object.entries(c.handlers)) {
|
|
52
|
+
if (h.openapi) {
|
|
53
|
+
const [queryValidation, queryComponents] = extractComponents(h?.validation?.query);
|
|
54
|
+
const [bodyValidation, bodyComponents] = extractComponents(h?.validation?.body);
|
|
55
|
+
const [paramsValidation, paramsComponents] = extractComponents(h?.validation?.params);
|
|
56
|
+
const [outputValidation, outputComponents] = extractComponents(h?.validation?.output);
|
|
57
|
+
const [iterationValidation, iterationComponents] = extractComponents(h?.validation?.iteration);
|
|
58
|
+
// TODO: Handle name conflicts?
|
|
59
|
+
Object.assign(components, queryComponents, bodyComponents, paramsComponents, outputComponents, iterationComponents);
|
|
60
|
+
const { ts, rs, py } = (0, createCodeExamples_1.createCodeExamples)({
|
|
61
|
+
package: packageJson,
|
|
62
|
+
handlerName,
|
|
63
|
+
handlerSchema: h,
|
|
64
|
+
controllerSchema: c,
|
|
65
|
+
});
|
|
66
|
+
const queryParameters = queryValidation && 'type' in queryValidation && 'properties' in queryValidation
|
|
67
|
+
? Object.entries(queryValidation.properties).map(([propName, propSchema]) => ({
|
|
68
|
+
name: propName,
|
|
69
|
+
in: 'query',
|
|
70
|
+
required: queryValidation.required ? queryValidation.required.includes(propName) : false,
|
|
71
|
+
schema: propSchema,
|
|
72
|
+
}))
|
|
73
|
+
: null;
|
|
74
|
+
const pathParameters = paramsValidation && 'type' in paramsValidation && 'properties' in paramsValidation
|
|
75
|
+
? Object.entries(paramsValidation.properties).map(([propName, propSchema]) => ({
|
|
76
|
+
name: propName,
|
|
77
|
+
in: 'path',
|
|
78
|
+
required: paramsValidation.required ? paramsValidation.required.includes(propName) : false,
|
|
79
|
+
schema: propSchema,
|
|
80
|
+
}))
|
|
81
|
+
: null;
|
|
82
|
+
const path = '/' +
|
|
83
|
+
[rootEntry.replace(/^\/+|\/+$/g, ''), segmentName, c.prefix, h.path]
|
|
84
|
+
.filter(Boolean)
|
|
85
|
+
.join('/')
|
|
86
|
+
.replace(/:([a-zA-Z0-9_]+)/g, '{$1}');
|
|
87
|
+
paths[path] = paths[path] ?? {};
|
|
88
|
+
const httpMethod = h.httpMethod.toLowerCase();
|
|
89
|
+
paths[path][httpMethod] ??= {};
|
|
90
|
+
paths[path][httpMethod] = {
|
|
91
|
+
...h.openapi,
|
|
92
|
+
...paths[path][httpMethod],
|
|
93
|
+
'x-codeSamples': [
|
|
94
|
+
...(paths[path][httpMethod]['x-codeSamples'] ?? []),
|
|
95
|
+
...(h.openapi['x-codeSamples'] ?? []),
|
|
96
|
+
{
|
|
97
|
+
label: 'TypeScript RPC',
|
|
98
|
+
lang: 'typescript',
|
|
99
|
+
source: ts,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
label: 'Python RPC',
|
|
103
|
+
lang: 'python',
|
|
104
|
+
source: py,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
label: 'Rust RPC',
|
|
108
|
+
lang: 'rust',
|
|
109
|
+
source: rs,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
...(queryParameters || pathParameters
|
|
113
|
+
? {
|
|
114
|
+
parameters: h.openapi.parameters ?? [...(queryParameters || []), ...(pathParameters || [])],
|
|
115
|
+
}
|
|
116
|
+
: {}),
|
|
117
|
+
...(paths[path][httpMethod].parameters
|
|
118
|
+
? {
|
|
119
|
+
parameters: paths[path][httpMethod].parameters,
|
|
120
|
+
}
|
|
121
|
+
: {}),
|
|
122
|
+
...(outputValidation && 'type' in outputValidation && 'properties' in outputValidation
|
|
123
|
+
? {
|
|
124
|
+
responses: {
|
|
125
|
+
200: {
|
|
126
|
+
description: 'description' in outputValidation ? outputValidation.description : 'Success',
|
|
127
|
+
content: {
|
|
128
|
+
'application/json': {
|
|
129
|
+
schema: outputValidation,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
...h.openapi?.responses,
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
: {}),
|
|
137
|
+
...(iterationValidation && 'type' in iterationValidation && 'properties' in iterationValidation
|
|
138
|
+
? {
|
|
139
|
+
responses: {
|
|
140
|
+
200: {
|
|
141
|
+
description: 'description' in iterationValidation ? iterationValidation.description : 'JSON Lines response',
|
|
142
|
+
content: {
|
|
143
|
+
'application/jsonl': {
|
|
144
|
+
schema: {
|
|
145
|
+
...iterationValidation,
|
|
146
|
+
examples: iterationValidation.examples ?? [
|
|
147
|
+
[
|
|
148
|
+
JSON.stringify((0, json_schema_sampler_1.sample)(iterationValidation)),
|
|
149
|
+
JSON.stringify((0, json_schema_sampler_1.sample)(iterationValidation)),
|
|
150
|
+
JSON.stringify((0, json_schema_sampler_1.sample)(iterationValidation)),
|
|
151
|
+
].join('\n'),
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
...h.openapi?.responses,
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
: {}),
|
|
161
|
+
...(paths[path][httpMethod].responses
|
|
162
|
+
? {
|
|
163
|
+
responses: paths[path][httpMethod].responses,
|
|
164
|
+
}
|
|
165
|
+
: {}),
|
|
166
|
+
...(bodyValidation && 'type' in bodyValidation && 'properties' in bodyValidation
|
|
167
|
+
? {
|
|
168
|
+
requestBody: h.openapi?.requestBody ?? {
|
|
169
|
+
description: 'description' in bodyValidation ? bodyValidation.description : 'Request body',
|
|
170
|
+
required: true,
|
|
171
|
+
content: {
|
|
172
|
+
'application/json': {
|
|
173
|
+
schema: bodyValidation,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
: {}),
|
|
179
|
+
...(paths[path][httpMethod].requestBody
|
|
180
|
+
? {
|
|
181
|
+
requestBody: paths[path][httpMethod].requestBody,
|
|
182
|
+
}
|
|
183
|
+
: {}),
|
|
184
|
+
tags: paths[path][httpMethod].tags ?? h.openapi?.tags,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
...openAPIObject,
|
|
192
|
+
openapi: '3.1.0',
|
|
193
|
+
info: {
|
|
194
|
+
title: packageJson?.description ?? 'API',
|
|
195
|
+
version: packageJson?.version ?? '0.0.1',
|
|
196
|
+
...openAPIObject?.info,
|
|
197
|
+
},
|
|
198
|
+
components: {
|
|
199
|
+
schemas: {
|
|
200
|
+
...(openAPIObject?.components?.schemas ?? components),
|
|
201
|
+
HttpStatus: {
|
|
202
|
+
type: 'integer',
|
|
203
|
+
description: 'HTTP status code',
|
|
204
|
+
enum: Object.keys(types_1.HttpStatus)
|
|
205
|
+
.map((k) => types_1.HttpStatus[k])
|
|
206
|
+
.filter(Boolean)
|
|
207
|
+
.filter((v) => typeof v === 'number'),
|
|
208
|
+
},
|
|
209
|
+
VovkErrorResponse: {
|
|
210
|
+
type: 'object',
|
|
211
|
+
description: 'Vovk error response',
|
|
212
|
+
properties: {
|
|
213
|
+
cause: {
|
|
214
|
+
description: 'Error cause of any shape',
|
|
215
|
+
},
|
|
216
|
+
statusCode: {
|
|
217
|
+
$ref: '#/components/schemas/HttpStatus',
|
|
218
|
+
},
|
|
219
|
+
message: {
|
|
220
|
+
type: 'string',
|
|
221
|
+
description: 'Error message',
|
|
222
|
+
},
|
|
223
|
+
isError: {
|
|
224
|
+
type: 'boolean',
|
|
225
|
+
const: true,
|
|
226
|
+
description: 'Indicates that this object represents an error',
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
required: ['statusCode', 'message', 'isError'],
|
|
230
|
+
additionalProperties: false,
|
|
231
|
+
},
|
|
232
|
+
...openAPIObject?.components?.schemas,
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
paths,
|
|
236
|
+
};
|
|
237
|
+
}
|
package/mjs/types.d.ts
CHANGED
|
@@ -96,6 +96,16 @@ export type ControllerStaticMethod<REQ extends VovkRequest<KnownAny, KnownAny> =
|
|
|
96
96
|
} = KnownAny> = ((req: REQ, params: PARAMS) => unknown) & {
|
|
97
97
|
_controller?: VovkController;
|
|
98
98
|
};
|
|
99
|
+
export type VovkTypedMethod<T extends (...args: KnownAny[]) => KnownAny, B = KnownAny, Q = KnownAny, P = KnownAny, O = KnownAny, I = KnownAny> = T & {
|
|
100
|
+
__types: {
|
|
101
|
+
body?: B;
|
|
102
|
+
query?: Q;
|
|
103
|
+
params?: P;
|
|
104
|
+
output?: O;
|
|
105
|
+
iteration?: I;
|
|
106
|
+
};
|
|
107
|
+
isRPC?: boolean;
|
|
108
|
+
};
|
|
99
109
|
export type VovkControllerBody<T extends (...args: KnownAny) => KnownAny> = Awaited<ReturnType<Parameters<T>[0]['vovk']['body']>>;
|
|
100
110
|
export type VovkControllerQuery<T extends (...args: KnownAny) => KnownAny> = ReturnType<Parameters<T>[0]['vovk']['query']>;
|
|
101
111
|
export type VovkControllerParams<T extends (...args: KnownAny) => KnownAny> = Parameters<T>[1] extends object ? Parameters<T>[1] : ReturnType<Parameters<T>[0]['vovk']['params']>;
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import { VovkHandlerSchema, VovkValidationType, type KnownAny, type VovkRequest } from '../types.js';
|
|
1
|
+
import { VovkHandlerSchema, VovkTypedMethod, VovkValidationType, type KnownAny, type VovkRequest } from '../types.js';
|
|
2
2
|
type VovkRequestAny = VovkRequest<KnownAny, KnownAny, KnownAny>;
|
|
3
|
-
export declare function withValidation<T extends (
|
|
4
|
-
__types: {
|
|
5
|
-
body: KnownAny;
|
|
6
|
-
query: KnownAny;
|
|
7
|
-
params: KnownAny;
|
|
8
|
-
output: KnownAny;
|
|
9
|
-
iteration: KnownAny;
|
|
10
|
-
};
|
|
11
|
-
}, BODY_MODEL, QUERY_MODEL, PARAMS_MODEL, OUTPUT_MODEL, ITERATION_MODEL>({ disableServerSideValidation, skipSchemaEmission, validateEachIteration, body, query, params, output, iteration, handle, getJSONSchemaFromModel, validate, }: {
|
|
3
|
+
export declare function withValidation<T extends VovkTypedMethod<(req: KnownAny, params: KnownAny) => KnownAny>, BODY_MODEL, QUERY_MODEL, PARAMS_MODEL, OUTPUT_MODEL, ITERATION_MODEL>({ disableServerSideValidation, skipSchemaEmission, validateEachIteration, body, query, params, output, iteration, handle, getJSONSchemaFromModel, validate, }: {
|
|
12
4
|
disableServerSideValidation?: boolean | VovkValidationType[];
|
|
13
5
|
skipSchemaEmission?: boolean | VovkValidationType[];
|
|
14
6
|
validateEachIteration?: boolean;
|