vovk 3.0.0-draft.21 → 3.0.0-draft.211
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/LICENSE +1 -1
- package/README.md +8 -96
- package/bin/index.mjs +8 -0
- package/{HttpException.d.ts → cjs/HttpException.d.ts} +2 -2
- package/{HttpException.js → cjs/HttpException.js} +3 -3
- package/cjs/JSONLinesResponse.d.ts +14 -0
- package/{StreamJSONResponse.js → cjs/JSONLinesResponse.js} +15 -10
- package/{Segment.d.ts → cjs/VovkApp.d.ts} +11 -10
- package/cjs/VovkApp.js +189 -0
- package/cjs/client/createRPC.d.ts +3 -0
- package/cjs/client/createRPC.js +87 -0
- package/{client → cjs/client}/defaultHandler.d.ts +1 -1
- package/cjs/client/defaultHandler.js +22 -0
- package/cjs/client/defaultStreamHandler.d.ts +4 -0
- package/{client → cjs/client}/defaultStreamHandler.js +11 -12
- package/cjs/client/fetcher.d.ts +13 -0
- package/cjs/client/fetcher.js +90 -0
- package/cjs/client/index.d.ts +3 -0
- package/cjs/client/index.js +8 -0
- package/cjs/client/types.d.ts +111 -0
- package/{createSegment.d.ts → cjs/createVovkApp.d.ts} +11 -10
- package/cjs/createVovkApp.js +132 -0
- package/cjs/index.d.ts +65 -0
- package/cjs/index.js +37 -0
- package/cjs/openapi/error.d.ts +2 -0
- package/cjs/openapi/error.js +100 -0
- package/cjs/openapi/generateFnName.d.ts +23 -0
- package/cjs/openapi/generateFnName.js +81 -0
- package/cjs/openapi/index.d.ts +12 -0
- package/cjs/openapi/index.js +21 -0
- package/cjs/openapi/openAPIToVovkSchema.d.ts +2 -0
- package/cjs/openapi/openAPIToVovkSchema.js +197 -0
- package/cjs/openapi/vovkSchemaToOpenAPI.d.ts +9 -0
- package/cjs/openapi/vovkSchemaToOpenAPI.js +237 -0
- package/cjs/types.d.ts +364 -0
- package/cjs/types.js +74 -0
- package/cjs/utils/camelCase.d.ts +6 -0
- package/cjs/utils/camelCase.js +37 -0
- package/cjs/utils/createCodeExamples.d.ts +19 -0
- package/cjs/utils/createCodeExamples.js +114 -0
- package/cjs/utils/createDecorator.d.ts +6 -0
- package/{createDecorator.js → cjs/utils/createDecorator.js} +24 -16
- package/cjs/utils/createLLMFunctions.d.ts +20 -0
- package/cjs/utils/createLLMFunctions.js +100 -0
- package/cjs/utils/generateStaticAPI.d.ts +4 -0
- package/cjs/utils/generateStaticAPI.js +30 -0
- package/cjs/utils/getSchema.d.ts +21 -0
- package/cjs/utils/getSchema.js +43 -0
- package/cjs/utils/multitenant.d.ts +24 -0
- package/cjs/utils/multitenant.js +170 -0
- package/cjs/utils/parseQuery.d.ts +25 -0
- package/cjs/utils/parseQuery.js +156 -0
- package/cjs/utils/reqForm.d.ts +2 -0
- package/cjs/utils/reqForm.js +33 -0
- package/{utils → cjs/utils}/reqMeta.d.ts +1 -2
- package/cjs/utils/reqQuery.d.ts +2 -0
- package/cjs/utils/reqQuery.js +10 -0
- package/cjs/utils/serializeQuery.d.ts +13 -0
- package/cjs/utils/serializeQuery.js +65 -0
- package/cjs/utils/setHandlerSchema.d.ts +4 -0
- package/cjs/utils/setHandlerSchema.js +15 -0
- package/cjs/utils/withStandard.d.ts +51 -0
- package/cjs/utils/withStandard.js +30 -0
- package/cjs/utils/withValidationLibrary.d.ts +49 -0
- package/cjs/utils/withValidationLibrary.js +123 -0
- package/mjs/HttpException.d.ts +7 -0
- package/mjs/HttpException.js +15 -0
- package/mjs/JSONLinesResponse.d.ts +14 -0
- package/mjs/JSONLinesResponse.js +59 -0
- package/mjs/VovkApp.d.ts +29 -0
- package/mjs/VovkApp.js +189 -0
- package/mjs/client/createRPC.d.ts +3 -0
- package/mjs/client/createRPC.js +87 -0
- package/mjs/client/defaultHandler.d.ts +2 -0
- package/mjs/client/defaultHandler.js +22 -0
- package/mjs/client/defaultStreamHandler.d.ts +4 -0
- package/mjs/client/defaultStreamHandler.js +81 -0
- package/mjs/client/fetcher.d.ts +13 -0
- package/mjs/client/fetcher.js +90 -0
- package/mjs/client/index.d.ts +3 -0
- package/mjs/client/index.js +8 -0
- package/mjs/client/types.d.ts +111 -0
- package/mjs/createVovkApp.d.ts +63 -0
- package/mjs/createVovkApp.js +132 -0
- package/mjs/index.d.ts +65 -0
- package/mjs/index.js +37 -0
- package/mjs/openapi/error.d.ts +2 -0
- package/mjs/openapi/error.js +100 -0
- package/mjs/openapi/generateFnName.d.ts +23 -0
- package/mjs/openapi/generateFnName.js +81 -0
- package/mjs/openapi/index.d.ts +12 -0
- package/mjs/openapi/index.js +21 -0
- package/mjs/openapi/openAPIToVovkSchema.d.ts +2 -0
- package/mjs/openapi/openAPIToVovkSchema.js +197 -0
- package/mjs/openapi/vovkSchemaToOpenAPI.d.ts +9 -0
- package/mjs/openapi/vovkSchemaToOpenAPI.js +237 -0
- package/mjs/types.d.ts +364 -0
- package/mjs/types.js +74 -0
- package/mjs/utils/camelCase.d.ts +6 -0
- package/mjs/utils/camelCase.js +37 -0
- package/mjs/utils/createCodeExamples.d.ts +19 -0
- package/mjs/utils/createCodeExamples.js +114 -0
- package/mjs/utils/createDecorator.d.ts +6 -0
- package/mjs/utils/createDecorator.js +46 -0
- package/mjs/utils/createLLMFunctions.d.ts +20 -0
- package/mjs/utils/createLLMFunctions.js +100 -0
- package/mjs/utils/generateStaticAPI.d.ts +4 -0
- package/mjs/utils/generateStaticAPI.js +30 -0
- package/mjs/utils/getSchema.d.ts +21 -0
- package/mjs/utils/getSchema.js +43 -0
- package/mjs/utils/multitenant.d.ts +24 -0
- package/mjs/utils/multitenant.js +170 -0
- package/mjs/utils/parseQuery.d.ts +25 -0
- package/mjs/utils/parseQuery.js +156 -0
- package/mjs/utils/reqForm.d.ts +2 -0
- package/mjs/utils/reqForm.js +33 -0
- package/mjs/utils/reqMeta.d.ts +2 -0
- package/mjs/utils/reqMeta.js +13 -0
- package/mjs/utils/reqQuery.d.ts +2 -0
- package/mjs/utils/reqQuery.js +10 -0
- package/mjs/utils/serializeQuery.d.ts +13 -0
- package/mjs/utils/serializeQuery.js +65 -0
- package/mjs/utils/setHandlerSchema.d.ts +4 -0
- package/mjs/utils/setHandlerSchema.js +15 -0
- package/mjs/utils/shim.d.ts +1 -0
- package/mjs/utils/shim.js +18 -0
- package/mjs/utils/withStandard.d.ts +51 -0
- package/mjs/utils/withStandard.js +30 -0
- package/mjs/utils/withValidationLibrary.d.ts +49 -0
- package/mjs/utils/withValidationLibrary.js +123 -0
- package/package.json +30 -5
- package/.npmignore +0 -2
- package/Segment.js +0 -182
- package/StreamJSONResponse.d.ts +0 -17
- package/client/clientizeController.d.ts +0 -4
- package/client/clientizeController.js +0 -92
- package/client/defaultFetcher.d.ts +0 -4
- package/client/defaultFetcher.js +0 -49
- package/client/defaultHandler.js +0 -21
- package/client/defaultStreamHandler.d.ts +0 -4
- package/client/index.d.ts +0 -4
- package/client/index.js +0 -5
- package/client/types.d.ts +0 -100
- package/createDecorator.d.ts +0 -4
- package/createSegment.js +0 -118
- package/generateStaticAPI.d.ts +0 -4
- package/generateStaticAPI.js +0 -18
- package/index.d.ts +0 -60
- package/index.js +0 -20
- package/types.d.ts +0 -155
- package/types.js +0 -65
- package/utils/getSchema.d.ts +0 -8
- package/utils/getSchema.js +0 -38
- package/utils/reqQuery.d.ts +0 -3
- package/utils/reqQuery.js +0 -25
- package/utils/setClientValidatorsForHandler.d.ts +0 -5
- package/utils/setClientValidatorsForHandler.js +0 -28
- package/worker/index.d.ts +0 -3
- package/worker/index.js +0 -7
- package/worker/promisifyWorker.d.ts +0 -2
- package/worker/promisifyWorker.js +0 -141
- package/worker/types.d.ts +0 -31
- package/worker/worker.d.ts +0 -1
- package/worker/worker.js +0 -43
- /package/{client → cjs/client}/types.js +0 -0
- /package/{utils → cjs/utils}/reqMeta.js +0 -0
- /package/{utils → cjs/utils}/shim.d.ts +0 -0
- /package/{utils → cjs/utils}/shim.js +0 -0
- /package/{worker → mjs/client}/types.js +0 -0
package/mjs/VovkApp.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
var _a;
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.VovkApp = void 0;
|
|
8
|
+
const types_js_1 = require("./types.js");
|
|
9
|
+
const HttpException_js_1 = require("./HttpException.js");
|
|
10
|
+
const JSONLinesResponse_js_1 = require("./JSONLinesResponse.js");
|
|
11
|
+
const reqQuery_js_1 = __importDefault(require("./utils/reqQuery.js"));
|
|
12
|
+
const reqMeta_js_1 = __importDefault(require("./utils/reqMeta.js"));
|
|
13
|
+
const reqForm_js_1 = __importDefault(require("./utils/reqForm.js"));
|
|
14
|
+
const headers_1 = require("next/headers");
|
|
15
|
+
class VovkApp {
|
|
16
|
+
static getHeadersFromOptions(options) {
|
|
17
|
+
if (!options)
|
|
18
|
+
return {};
|
|
19
|
+
const corsHeaders = {
|
|
20
|
+
'access-control-allow-origin': '*',
|
|
21
|
+
'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
|
|
22
|
+
'access-control-allow-headers': 'content-type, authorization',
|
|
23
|
+
};
|
|
24
|
+
const headers = {
|
|
25
|
+
...(options.cors ? corsHeaders : {}),
|
|
26
|
+
...(options.headers ?? {}),
|
|
27
|
+
};
|
|
28
|
+
return headers;
|
|
29
|
+
}
|
|
30
|
+
routes = {
|
|
31
|
+
GET: new Map(),
|
|
32
|
+
POST: new Map(),
|
|
33
|
+
PUT: new Map(),
|
|
34
|
+
PATCH: new Map(),
|
|
35
|
+
DELETE: new Map(),
|
|
36
|
+
HEAD: new Map(),
|
|
37
|
+
OPTIONS: new Map(),
|
|
38
|
+
};
|
|
39
|
+
GET = async (req, data) => this.#callMethod(types_js_1.HttpMethod.GET, req, await data.params);
|
|
40
|
+
POST = async (req, data) => this.#callMethod(types_js_1.HttpMethod.POST, req, await data.params);
|
|
41
|
+
PUT = async (req, data) => this.#callMethod(types_js_1.HttpMethod.PUT, req, await data.params);
|
|
42
|
+
PATCH = async (req, data) => this.#callMethod(types_js_1.HttpMethod.PATCH, req, await data.params);
|
|
43
|
+
DELETE = async (req, data) => this.#callMethod(types_js_1.HttpMethod.DELETE, req, await data.params);
|
|
44
|
+
HEAD = async (req, data) => this.#callMethod(types_js_1.HttpMethod.HEAD, req, await data.params);
|
|
45
|
+
OPTIONS = async (req, data) => this.#callMethod(types_js_1.HttpMethod.OPTIONS, req, await data.params);
|
|
46
|
+
respond = (status, body, options) => {
|
|
47
|
+
return new Response(JSON.stringify(body), {
|
|
48
|
+
status,
|
|
49
|
+
headers: {
|
|
50
|
+
'content-type': 'application/json',
|
|
51
|
+
..._a.getHeadersFromOptions(options),
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
#respondWithError = (statusCode, message, options, cause) => {
|
|
56
|
+
return this.respond(statusCode, {
|
|
57
|
+
cause,
|
|
58
|
+
statusCode,
|
|
59
|
+
message,
|
|
60
|
+
isError: true,
|
|
61
|
+
}, options);
|
|
62
|
+
};
|
|
63
|
+
#getHandler = ({ handlers, path, params, }) => {
|
|
64
|
+
const methodParams = {};
|
|
65
|
+
if (Object.keys(params).length === 0) {
|
|
66
|
+
return { handler: handlers[''], methodParams };
|
|
67
|
+
}
|
|
68
|
+
const allMethodKeys = Object.keys(handlers);
|
|
69
|
+
let methodKeys = [];
|
|
70
|
+
const pathStr = path.join('/');
|
|
71
|
+
methodKeys = allMethodKeys
|
|
72
|
+
// First, try to match literal routes exactly.
|
|
73
|
+
.filter((p) => {
|
|
74
|
+
if (p.includes(':'))
|
|
75
|
+
return false; // Skip parameterized paths
|
|
76
|
+
return p === pathStr;
|
|
77
|
+
});
|
|
78
|
+
if (!methodKeys.length) {
|
|
79
|
+
methodKeys = allMethodKeys.filter((p) => {
|
|
80
|
+
const routeSegments = p.split('/');
|
|
81
|
+
if (routeSegments.length !== path.length)
|
|
82
|
+
return false;
|
|
83
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
|
84
|
+
const routeSegment = routeSegments[i];
|
|
85
|
+
const pathSegment = path[i];
|
|
86
|
+
if (routeSegment.startsWith(':')) {
|
|
87
|
+
const parameter = routeSegment.slice(1);
|
|
88
|
+
if (parameter in methodParams) {
|
|
89
|
+
throw new HttpException_js_1.HttpException(types_js_1.HttpStatus.INTERNAL_SERVER_ERROR, `Duplicate parameter "${parameter}" at ${p}`);
|
|
90
|
+
}
|
|
91
|
+
// If it's a parameterized segment, capture the parameter value.
|
|
92
|
+
methodParams[parameter] = pathSegment;
|
|
93
|
+
}
|
|
94
|
+
else if (routeSegment !== pathSegment) {
|
|
95
|
+
// If it's a literal segment and it does not match the corresponding path segment, return false.
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (methodKeys.length > 1) {
|
|
103
|
+
throw new HttpException_js_1.HttpException(types_js_1.HttpStatus.INTERNAL_SERVER_ERROR, `Conflicting routes found: ${methodKeys.join(', ')}`);
|
|
104
|
+
}
|
|
105
|
+
const [methodKey] = methodKeys;
|
|
106
|
+
if (methodKey) {
|
|
107
|
+
return { handler: handlers[methodKey], methodParams };
|
|
108
|
+
}
|
|
109
|
+
return { handler: null, methodParams };
|
|
110
|
+
};
|
|
111
|
+
#callMethod = async (httpMethod, nextReq, params) => {
|
|
112
|
+
const req = nextReq;
|
|
113
|
+
const controllers = this.routes[httpMethod];
|
|
114
|
+
const path = params[Object.keys(params)[0]];
|
|
115
|
+
const handlers = {};
|
|
116
|
+
controllers.forEach((staticMethods, controller) => {
|
|
117
|
+
const prefix = controller._prefix ?? '';
|
|
118
|
+
if (!controller._activated) {
|
|
119
|
+
throw new HttpException_js_1.HttpException(types_js_1.HttpStatus.INTERNAL_SERVER_ERROR, `Controller "${controller.name}" found but not activated`);
|
|
120
|
+
}
|
|
121
|
+
Object.entries(staticMethods ?? {}).forEach(([path, staticMethod]) => {
|
|
122
|
+
const fullPath = [prefix, path].filter(Boolean).join('/');
|
|
123
|
+
handlers[fullPath] = { staticMethod, controller };
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
const { handler, methodParams } = this.#getHandler({ handlers, path, params });
|
|
127
|
+
if (!handler) {
|
|
128
|
+
return this.#respondWithError(types_js_1.HttpStatus.NOT_FOUND, `${Object.keys(handlers)} - Route ${path.join('/')} is not found`);
|
|
129
|
+
}
|
|
130
|
+
const { staticMethod, controller } = handler;
|
|
131
|
+
req.vovk = {
|
|
132
|
+
body: () => req.json(),
|
|
133
|
+
query: () => (0, reqQuery_js_1.default)(req),
|
|
134
|
+
meta: (meta) => (0, reqMeta_js_1.default)(req, meta),
|
|
135
|
+
form: () => (0, reqForm_js_1.default)(req),
|
|
136
|
+
params: () => methodParams,
|
|
137
|
+
};
|
|
138
|
+
try {
|
|
139
|
+
await staticMethod._options?.before?.call(controller, req);
|
|
140
|
+
const result = await staticMethod.call(controller, req, methodParams);
|
|
141
|
+
const isIterator = typeof result === 'object' &&
|
|
142
|
+
!!result &&
|
|
143
|
+
((Reflect.has(result, Symbol.iterator) &&
|
|
144
|
+
typeof result[Symbol.iterator] === 'function') ||
|
|
145
|
+
(Reflect.has(result, Symbol.asyncIterator) &&
|
|
146
|
+
typeof result[Symbol.asyncIterator] === 'function'));
|
|
147
|
+
if (isIterator && !(result instanceof Array)) {
|
|
148
|
+
const streamResponse = new JSONLinesResponse_js_1.JSONLinesResponse(await (0, headers_1.headers)(), {
|
|
149
|
+
headers: {
|
|
150
|
+
..._a.getHeadersFromOptions(staticMethod._options),
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
void (async () => {
|
|
154
|
+
try {
|
|
155
|
+
for await (const chunk of result) {
|
|
156
|
+
streamResponse.send(chunk);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
return streamResponse.throw(e);
|
|
161
|
+
}
|
|
162
|
+
return streamResponse.close();
|
|
163
|
+
})();
|
|
164
|
+
return streamResponse;
|
|
165
|
+
}
|
|
166
|
+
if (result instanceof Response) {
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
return this.respond(200, result ?? null, staticMethod._options);
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
const err = e;
|
|
173
|
+
try {
|
|
174
|
+
await controller._onError?.(err, req);
|
|
175
|
+
}
|
|
176
|
+
catch (onErrorError) {
|
|
177
|
+
// eslint-disable-next-line no-console
|
|
178
|
+
console.error(onErrorError);
|
|
179
|
+
}
|
|
180
|
+
if (err.message !== 'NEXT_REDIRECT' && err.message !== 'NEXT_NOT_FOUND') {
|
|
181
|
+
const statusCode = err.statusCode || types_js_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
182
|
+
return this.#respondWithError(statusCode, err.message, staticMethod._options, err.cause);
|
|
183
|
+
}
|
|
184
|
+
throw e; // if NEXT_REDIRECT or NEXT_NOT_FOUND, rethrow it
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
exports.VovkApp = VovkApp;
|
|
189
|
+
_a = VovkApp;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { KnownAny, VovkSchema } from '../types.js';
|
|
2
|
+
import type { VovkClient, VovkClientFetcher, VovkDefaultFetcherOptions } from './types.js';
|
|
3
|
+
export declare const createRPC: <T, OPTS extends Record<string, KnownAny> = Record<string, never>>(schema: VovkSchema, segmentName: string, rpcModuleName: string, fetcher?: VovkClientFetcher<OPTS>, options?: VovkDefaultFetcherOptions<OPTS>) => VovkClient<T, OPTS>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createRPC = void 0;
|
|
7
|
+
const fetcher_js_1 = require("./fetcher.js");
|
|
8
|
+
const defaultHandler_js_1 = require("./defaultHandler.js");
|
|
9
|
+
const defaultStreamHandler_js_1 = require("./defaultStreamHandler.js");
|
|
10
|
+
const serializeQuery_js_1 = __importDefault(require("../utils/serializeQuery.js"));
|
|
11
|
+
const trimPath = (path) => path.trim().replace(/^\/|\/$/g, '');
|
|
12
|
+
const getHandlerPath = (endpoint, params, query) => {
|
|
13
|
+
let result = endpoint;
|
|
14
|
+
const queryStr = query ? (0, serializeQuery_js_1.default)(query) : null;
|
|
15
|
+
for (const [key, value] of Object.entries(params ?? {})) {
|
|
16
|
+
result = result.replace(`:${key}`, value);
|
|
17
|
+
}
|
|
18
|
+
return `${result}${queryStr ? '?' : ''}${queryStr}`;
|
|
19
|
+
};
|
|
20
|
+
const createRPC = (schema, segmentName, rpcModuleName, fetcher = fetcher_js_1.fetcher, options) => {
|
|
21
|
+
const segmentNamePath = options?.segmentNameOverride ?? segmentName;
|
|
22
|
+
const segmentSchema = schema.segments[segmentName];
|
|
23
|
+
if (!segmentSchema)
|
|
24
|
+
throw new Error(`Unable to create RPC module. Segment schema is missing. Check client template.`);
|
|
25
|
+
const controllerSchema = schema.segments[segmentName]?.controllers[rpcModuleName];
|
|
26
|
+
const client = {};
|
|
27
|
+
if (!controllerSchema)
|
|
28
|
+
throw new Error(`Unable to create RPC module. Controller schema is missing. Check client template.`);
|
|
29
|
+
const controllerPrefix = trimPath(controllerSchema.prefix ?? '');
|
|
30
|
+
for (const [staticMethodName, handlerSchema] of Object.entries(controllerSchema.handlers ?? {})) {
|
|
31
|
+
const { path, httpMethod, validation } = handlerSchema;
|
|
32
|
+
const getEndpoint = ({ apiRoot, params, query, }) => {
|
|
33
|
+
apiRoot ??= options?.apiRoot ?? '/api';
|
|
34
|
+
const endpoint = [
|
|
35
|
+
apiRoot.startsWith('http://') || apiRoot.startsWith('https://') || apiRoot.startsWith('/') ? '' : '/',
|
|
36
|
+
apiRoot,
|
|
37
|
+
segmentNamePath,
|
|
38
|
+
getHandlerPath([controllerPrefix, path].filter(Boolean).join('/'), params, query),
|
|
39
|
+
]
|
|
40
|
+
.filter(Boolean)
|
|
41
|
+
.join('/');
|
|
42
|
+
return endpoint;
|
|
43
|
+
};
|
|
44
|
+
const handler = (input = {}) => {
|
|
45
|
+
const validate = async ({ body, query, params, endpoint, }) => {
|
|
46
|
+
const validateOnClient = input.validateOnClient ?? options?.validateOnClient;
|
|
47
|
+
if (validateOnClient && validation) {
|
|
48
|
+
if (typeof validateOnClient !== 'function') {
|
|
49
|
+
throw new Error('validateOnClient must be a function');
|
|
50
|
+
}
|
|
51
|
+
await validateOnClient({ body, query, params, endpoint }, validation, schema);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const internalOptions = {
|
|
55
|
+
name: staticMethodName,
|
|
56
|
+
httpMethod: httpMethod,
|
|
57
|
+
getEndpoint,
|
|
58
|
+
validate,
|
|
59
|
+
defaultHandler: defaultHandler_js_1.defaultHandler,
|
|
60
|
+
defaultStreamHandler: defaultStreamHandler_js_1.defaultStreamHandler,
|
|
61
|
+
};
|
|
62
|
+
const internalInput = {
|
|
63
|
+
...options,
|
|
64
|
+
...input,
|
|
65
|
+
body: input.body ?? null,
|
|
66
|
+
query: input.query ?? {},
|
|
67
|
+
params: input.params ?? {},
|
|
68
|
+
};
|
|
69
|
+
if (!fetcher)
|
|
70
|
+
throw new Error('Fetcher is not provided');
|
|
71
|
+
const fetcherPromise = fetcher(internalOptions, internalInput);
|
|
72
|
+
if (!(fetcherPromise instanceof Promise))
|
|
73
|
+
return Promise.resolve(fetcherPromise);
|
|
74
|
+
return input.transform ? fetcherPromise.then(input.transform) : fetcherPromise;
|
|
75
|
+
};
|
|
76
|
+
handler.schema = handlerSchema;
|
|
77
|
+
handler.controllerSchema = controllerSchema;
|
|
78
|
+
handler.segmentSchema = segmentSchema;
|
|
79
|
+
handler.fullSchema = schema;
|
|
80
|
+
handler.isRPC = true;
|
|
81
|
+
handler.path = [segmentNamePath, controllerPrefix, path].filter(Boolean).join('/');
|
|
82
|
+
// @ts-expect-error TODO
|
|
83
|
+
client[staticMethodName] = handler;
|
|
84
|
+
}
|
|
85
|
+
return client;
|
|
86
|
+
};
|
|
87
|
+
exports.createRPC = createRPC;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultHandler = exports.DEFAULT_ERROR_MESSAGE = void 0;
|
|
4
|
+
const HttpException_js_1 = require("../HttpException.js");
|
|
5
|
+
exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at defaultHandler';
|
|
6
|
+
const defaultHandler = async (response) => {
|
|
7
|
+
let result;
|
|
8
|
+
try {
|
|
9
|
+
result = await response.json();
|
|
10
|
+
}
|
|
11
|
+
catch (e) {
|
|
12
|
+
// handle parsing errors
|
|
13
|
+
throw new HttpException_js_1.HttpException(response.status, e?.message ?? exports.DEFAULT_ERROR_MESSAGE);
|
|
14
|
+
}
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
// handle server errors
|
|
17
|
+
const errorResponse = result;
|
|
18
|
+
throw new HttpException_js_1.HttpException(response.status, errorResponse?.message ?? exports.DEFAULT_ERROR_MESSAGE, errorResponse?.cause);
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
};
|
|
22
|
+
exports.defaultHandler = defaultHandler;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { VovkStreamAsyncIterable } from './types.js';
|
|
2
|
+
import '../utils/shim.js';
|
|
3
|
+
export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at defaultStreamHandler";
|
|
4
|
+
export declare const defaultStreamHandler: (response: Response) => Promise<VovkStreamAsyncIterable<unknown>>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultStreamHandler = exports.DEFAULT_ERROR_MESSAGE = void 0;
|
|
4
|
+
const types_js_1 = require("../types.js");
|
|
5
|
+
const HttpException_js_1 = require("../HttpException.js");
|
|
6
|
+
require("../utils/shim.js");
|
|
7
|
+
exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at defaultStreamHandler';
|
|
8
|
+
const defaultStreamHandler = async (response) => {
|
|
9
|
+
if (!response.ok) {
|
|
10
|
+
let result;
|
|
11
|
+
try {
|
|
12
|
+
result = await response.json();
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// ignore parsing errors
|
|
16
|
+
}
|
|
17
|
+
// handle server errors
|
|
18
|
+
throw new HttpException_js_1.HttpException(response.status, result.message ?? exports.DEFAULT_ERROR_MESSAGE);
|
|
19
|
+
}
|
|
20
|
+
if (!response.body)
|
|
21
|
+
throw new HttpException_js_1.HttpException(types_js_1.HttpStatus.NULL, 'Stream body is falsy. Check your controller code.');
|
|
22
|
+
const reader = response.body.getReader();
|
|
23
|
+
// if streaming is too rapid, we need to make sure that the loop is stopped
|
|
24
|
+
let canceled = false;
|
|
25
|
+
async function* asyncIterator() {
|
|
26
|
+
let prepend = '';
|
|
27
|
+
while (true) {
|
|
28
|
+
let value;
|
|
29
|
+
try {
|
|
30
|
+
let done;
|
|
31
|
+
({ value, done } = await reader.read());
|
|
32
|
+
if (done)
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
await reader.cancel();
|
|
37
|
+
const err = new Error('Stream error. ' + String(error));
|
|
38
|
+
err.cause = error;
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
// typeof value === 'number' is a workaround for React Native
|
|
42
|
+
const string = typeof value === 'number' ? String.fromCharCode(value) : new TextDecoder().decode(value);
|
|
43
|
+
prepend += string;
|
|
44
|
+
const lines = prepend.split('\n').filter(Boolean);
|
|
45
|
+
for (const line of lines) {
|
|
46
|
+
let data;
|
|
47
|
+
try {
|
|
48
|
+
data = JSON.parse(line);
|
|
49
|
+
prepend = '';
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
if (data) {
|
|
55
|
+
if ('isError' in data && 'reason' in data) {
|
|
56
|
+
const upcomingError = data.reason;
|
|
57
|
+
await reader.cancel();
|
|
58
|
+
if (typeof upcomingError === 'string') {
|
|
59
|
+
throw new Error(upcomingError);
|
|
60
|
+
}
|
|
61
|
+
throw upcomingError;
|
|
62
|
+
}
|
|
63
|
+
else if (!canceled) {
|
|
64
|
+
yield data;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
status: response.status,
|
|
72
|
+
[Symbol.asyncIterator]: asyncIterator,
|
|
73
|
+
[Symbol.dispose]: () => reader.cancel(),
|
|
74
|
+
[Symbol.asyncDispose]: () => reader.cancel(),
|
|
75
|
+
cancel: () => {
|
|
76
|
+
canceled = true;
|
|
77
|
+
return reader.cancel();
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
exports.defaultStreamHandler = defaultStreamHandler;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { VovkDefaultFetcherOptions, VovkClientFetcher } from './types.js';
|
|
2
|
+
export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at default fetcher";
|
|
3
|
+
export declare function createFetcher<T>({ prepareRequestInit, transformResponse, }?: {
|
|
4
|
+
prepareRequestInit?: (init: RequestInit, options: VovkDefaultFetcherOptions<T>) => RequestInit | Promise<RequestInit> | void | Promise<void>;
|
|
5
|
+
transformResponse?: (resp: unknown, options: VovkDefaultFetcherOptions<T>, init: RequestInit) => unknown;
|
|
6
|
+
}): VovkClientFetcher<VovkDefaultFetcherOptions<T>>;
|
|
7
|
+
export declare const fetcher: VovkClientFetcher<{
|
|
8
|
+
apiRoot?: string;
|
|
9
|
+
disableClientValidation?: boolean;
|
|
10
|
+
validateOnClient?: import("./types.js").VovkValidateOnClient;
|
|
11
|
+
interpretAs?: string;
|
|
12
|
+
init?: RequestInit;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetcher = exports.DEFAULT_ERROR_MESSAGE = void 0;
|
|
4
|
+
exports.createFetcher = createFetcher;
|
|
5
|
+
const types_js_1 = require("../types.js");
|
|
6
|
+
const HttpException_js_1 = require("../HttpException.js");
|
|
7
|
+
exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at default fetcher';
|
|
8
|
+
function createFetcher({ prepareRequestInit, transformResponse, } = {}) {
|
|
9
|
+
// fetcher uses HttpException class to throw errors of fake HTTP status 0 if client-side error occurs
|
|
10
|
+
// For normal HTTP errors, it uses message and status code from the response of VovkErrorResponse type
|
|
11
|
+
const newFetcher = async ({ httpMethod, getEndpoint, validate, defaultHandler, defaultStreamHandler }, options) => {
|
|
12
|
+
const { params, query, body, apiRoot, disableClientValidation, init, interpretAs } = options;
|
|
13
|
+
const endpoint = getEndpoint({ apiRoot, params, query });
|
|
14
|
+
const unusedParams = new URL(endpoint.startsWith('/') ? `http://localhost${endpoint}` : endpoint).pathname
|
|
15
|
+
.split('/')
|
|
16
|
+
.filter((segment) => segment.startsWith(':'));
|
|
17
|
+
if (unusedParams.length) {
|
|
18
|
+
throw new HttpException_js_1.HttpException(types_js_1.HttpStatus.NULL, `Unused params: ${unusedParams.join(', ')} in ${endpoint}`, {
|
|
19
|
+
body,
|
|
20
|
+
query,
|
|
21
|
+
params,
|
|
22
|
+
endpoint,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (!disableClientValidation) {
|
|
26
|
+
try {
|
|
27
|
+
await validate({ body, query, params, endpoint });
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
// if HttpException is thrown, rethrow it
|
|
31
|
+
if (e instanceof HttpException_js_1.HttpException)
|
|
32
|
+
throw e;
|
|
33
|
+
// otherwise, throw HttpException with status 0
|
|
34
|
+
throw new HttpException_js_1.HttpException(types_js_1.HttpStatus.NULL, e.message ?? exports.DEFAULT_ERROR_MESSAGE, {
|
|
35
|
+
body,
|
|
36
|
+
query,
|
|
37
|
+
params,
|
|
38
|
+
endpoint,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
let requestInit = {
|
|
43
|
+
method: httpMethod,
|
|
44
|
+
...init,
|
|
45
|
+
headers: {
|
|
46
|
+
accept: 'application/jsonl, application/json',
|
|
47
|
+
...init?.headers,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
if (body instanceof FormData) {
|
|
51
|
+
requestInit.body = body;
|
|
52
|
+
}
|
|
53
|
+
else if (body) {
|
|
54
|
+
requestInit.body = JSON.stringify(body);
|
|
55
|
+
}
|
|
56
|
+
requestInit = prepareRequestInit
|
|
57
|
+
? ((await prepareRequestInit(requestInit, options)) ?? requestInit)
|
|
58
|
+
: requestInit;
|
|
59
|
+
let response;
|
|
60
|
+
try {
|
|
61
|
+
response = await fetch(endpoint, requestInit);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
// handle network errors
|
|
65
|
+
throw new HttpException_js_1.HttpException(types_js_1.HttpStatus.NULL, (e?.message ?? exports.DEFAULT_ERROR_MESSAGE) + ' ' + endpoint, {
|
|
66
|
+
body,
|
|
67
|
+
query,
|
|
68
|
+
params,
|
|
69
|
+
endpoint,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const contentType = interpretAs ?? response.headers.get('content-type');
|
|
73
|
+
let resp;
|
|
74
|
+
if (contentType?.startsWith('application/jsonl')) {
|
|
75
|
+
resp = defaultStreamHandler(response);
|
|
76
|
+
}
|
|
77
|
+
else if (contentType?.startsWith('application/json')) {
|
|
78
|
+
resp = defaultHandler(response);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
resp = response;
|
|
82
|
+
}
|
|
83
|
+
resp = await resp;
|
|
84
|
+
return transformResponse
|
|
85
|
+
? ((await transformResponse(resp, options, requestInit)) ?? resp)
|
|
86
|
+
: resp;
|
|
87
|
+
};
|
|
88
|
+
return newFetcher;
|
|
89
|
+
}
|
|
90
|
+
exports.fetcher = createFetcher();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createFetcher = exports.fetcher = exports.createRPC = void 0;
|
|
4
|
+
var createRPC_js_1 = require("./createRPC.js");
|
|
5
|
+
Object.defineProperty(exports, "createRPC", { enumerable: true, get: function () { return createRPC_js_1.createRPC; } });
|
|
6
|
+
var fetcher_js_1 = require("./fetcher.js");
|
|
7
|
+
Object.defineProperty(exports, "fetcher", { enumerable: true, get: function () { return fetcher_js_1.fetcher; } });
|
|
8
|
+
Object.defineProperty(exports, "createFetcher", { enumerable: true, get: function () { return fetcher_js_1.createFetcher; } });
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { KnownAny, HttpMethod, ControllerStaticMethod, VovkHandlerSchema, VovkControllerSchema, VovkSegmentSchema, VovkSchema, VovkRequest } from '../types.js';
|
|
2
|
+
import type { JSONLinesResponse } from '../JSONLinesResponse.js';
|
|
3
|
+
import type { NextResponse } from 'next/server';
|
|
4
|
+
type OmitNullable<T> = {
|
|
5
|
+
[K in keyof T as T[K] extends null | undefined ? never : K]: T[K];
|
|
6
|
+
};
|
|
7
|
+
type Empty = {};
|
|
8
|
+
export type StaticMethodInput<T extends ((req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => KnownAny) & {
|
|
9
|
+
__types?: {
|
|
10
|
+
isForm: boolean;
|
|
11
|
+
};
|
|
12
|
+
}> = OmitNullable<(Parameters<T>[0] extends VovkRequest<infer BODY, infer QUERY, infer PARAMS> ? (BODY extends Record<KnownAny, KnownAny> ? {
|
|
13
|
+
body: NonNullable<T['__types']>['isForm'] extends true ? FormData : BODY;
|
|
14
|
+
} : Empty) & (QUERY extends Record<KnownAny, KnownAny> ? {
|
|
15
|
+
query: QUERY;
|
|
16
|
+
} : Empty) & (PARAMS extends Record<KnownAny, KnownAny> ? {
|
|
17
|
+
params: PARAMS;
|
|
18
|
+
} : Empty) : Empty) & (Parameters<T>[1] extends Record<KnownAny, KnownAny> ? {
|
|
19
|
+
params: Parameters<T>[1];
|
|
20
|
+
} : Empty)>;
|
|
21
|
+
type ToPromise<T> = T extends PromiseLike<unknown> ? T : Promise<T>;
|
|
22
|
+
export type VovkStreamAsyncIterable<T> = {
|
|
23
|
+
status: number;
|
|
24
|
+
[Symbol.dispose](): Promise<void> | void;
|
|
25
|
+
[Symbol.asyncDispose](): Promise<void> | void;
|
|
26
|
+
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
27
|
+
cancel: () => Promise<void> | void;
|
|
28
|
+
};
|
|
29
|
+
type StaticMethodReturn<T extends ControllerStaticMethod> = ReturnType<T> extends NextResponse<infer U> | Promise<NextResponse<infer U>> ? U : ReturnType<T> extends Response | Promise<Response> ? Awaited<ReturnType<T>> : ReturnType<T>;
|
|
30
|
+
type StaticMethodReturnPromise<T extends ControllerStaticMethod> = ToPromise<StaticMethodReturn<T>>;
|
|
31
|
+
type StaticMethodOptions<T extends (req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => void | object | JSONLinesResponse<STREAM> | Promise<JSONLinesResponse<STREAM>>, OPTS extends Record<string, KnownAny>, STREAM, R, F extends VovkDefaultFetcherOptions<KnownAny>> = Partial<OPTS & {
|
|
32
|
+
transform: (staticMethodReturn: Awaited<StaticMethodReturn<T>>) => R;
|
|
33
|
+
fetcher: VovkClientFetcher<F>;
|
|
34
|
+
}>;
|
|
35
|
+
type ClientMethodReturn<T extends (req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => void | object | JSONLinesResponse<STREAM> | Promise<JSONLinesResponse<STREAM>>, STREAM, R> = ReturnType<T> extends Promise<JSONLinesResponse<infer U>> | JSONLinesResponse<infer U> | Iterator<infer U> | AsyncIterator<infer U> ? Promise<VovkStreamAsyncIterable<U>> : R extends object ? Promise<Awaited<R>> : StaticMethodReturnPromise<T>;
|
|
36
|
+
type ClientMethod<T extends ((req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => void | object | JSONLinesResponse<STREAM> | Promise<JSONLinesResponse<STREAM>>) & {
|
|
37
|
+
__types?: {
|
|
38
|
+
body: KnownAny;
|
|
39
|
+
query: KnownAny;
|
|
40
|
+
params: KnownAny;
|
|
41
|
+
output: KnownAny;
|
|
42
|
+
iteration: KnownAny;
|
|
43
|
+
isForm: boolean;
|
|
44
|
+
};
|
|
45
|
+
}, OPTS extends Record<string, KnownAny>, STREAM extends KnownAny = unknown> = (IsEmptyObject<StaticMethodInput<T>> extends true ? <R, F extends VovkDefaultFetcherOptions<KnownAny> = VovkDefaultFetcherOptions<OPTS>>(options?: Prettify<StaticMethodOptions<T, OPTS, STREAM, R, F>>) => ClientMethodReturn<T, STREAM, R> : <R, F extends VovkDefaultFetcherOptions<KnownAny> = VovkDefaultFetcherOptions<OPTS>>(options: Prettify<StaticMethodInput<T> & StaticMethodOptions<T, OPTS, STREAM, R, F>>) => ClientMethodReturn<T, STREAM, R>) & {
|
|
46
|
+
isRPC: true;
|
|
47
|
+
path: string;
|
|
48
|
+
schema: VovkHandlerSchema;
|
|
49
|
+
controllerSchema: VovkControllerSchema;
|
|
50
|
+
segmentSchema: VovkSegmentSchema;
|
|
51
|
+
fullSchema: VovkSchema;
|
|
52
|
+
__types: T['__types'];
|
|
53
|
+
};
|
|
54
|
+
type OmitNever<T> = {
|
|
55
|
+
[K in keyof T as T[K] extends never ? never : K]: T[K];
|
|
56
|
+
};
|
|
57
|
+
type VovkClientWithNever<T, OPTS extends {
|
|
58
|
+
[key: string]: KnownAny;
|
|
59
|
+
}> = {
|
|
60
|
+
[K in keyof T]: T[K] extends (...args: KnownAny) => KnownAny ? ClientMethod<T[K], OPTS> : never;
|
|
61
|
+
};
|
|
62
|
+
export type VovkClient<T, OPTS extends {
|
|
63
|
+
[key: string]: KnownAny;
|
|
64
|
+
}> = OmitNever<VovkClientWithNever<T, OPTS>>;
|
|
65
|
+
export type VovkClientFetcher<OPTS> = (options: {
|
|
66
|
+
name: string;
|
|
67
|
+
httpMethod: HttpMethod;
|
|
68
|
+
getEndpoint: (data: {
|
|
69
|
+
apiRoot: string | undefined;
|
|
70
|
+
params: {
|
|
71
|
+
[key: string]: string;
|
|
72
|
+
};
|
|
73
|
+
query: {
|
|
74
|
+
[key: string]: string;
|
|
75
|
+
};
|
|
76
|
+
}) => string;
|
|
77
|
+
validate: (input: {
|
|
78
|
+
body?: unknown;
|
|
79
|
+
query?: unknown;
|
|
80
|
+
params?: unknown;
|
|
81
|
+
endpoint: string;
|
|
82
|
+
}) => void | Promise<void>;
|
|
83
|
+
defaultStreamHandler: (response: Response) => Promise<VovkStreamAsyncIterable<unknown>>;
|
|
84
|
+
defaultHandler: (response: Response) => Promise<unknown>;
|
|
85
|
+
}, input: {
|
|
86
|
+
body: unknown;
|
|
87
|
+
query: {
|
|
88
|
+
[key: string]: string;
|
|
89
|
+
};
|
|
90
|
+
params: {
|
|
91
|
+
[key: string]: string;
|
|
92
|
+
};
|
|
93
|
+
} & OPTS) => KnownAny;
|
|
94
|
+
export type VovkDefaultFetcherOptions<T> = T & {
|
|
95
|
+
apiRoot?: string;
|
|
96
|
+
disableClientValidation?: boolean;
|
|
97
|
+
validateOnClient?: VovkValidateOnClient;
|
|
98
|
+
interpretAs?: string;
|
|
99
|
+
init?: RequestInit;
|
|
100
|
+
};
|
|
101
|
+
export type VovkValidateOnClient = (input: {
|
|
102
|
+
body?: unknown;
|
|
103
|
+
query?: unknown;
|
|
104
|
+
params?: unknown;
|
|
105
|
+
endpoint: string;
|
|
106
|
+
}, validation: Omit<Exclude<VovkHandlerSchema['validation'], undefined>, 'output' | 'iteration'>, fullSchema: VovkSchema) => void | Promise<void>;
|
|
107
|
+
type IsEmptyObject<T> = T extends object ? keyof T extends never ? true : false : false;
|
|
108
|
+
type Prettify<T> = {
|
|
109
|
+
[K in keyof T]: T[K];
|
|
110
|
+
} & {};
|
|
111
|
+
export {};
|