vovk 3.0.0-draft.116 → 3.0.0-draft.118
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/VovkApp.js +1 -1
- package/dist/client/createRPC.js +2 -2
- package/dist/createDecorator.js +1 -1
- package/dist/createVovkApp.js +10 -2
- package/dist/types.d.ts +44 -16
- package/dist/utils/generateStaticAPI.js +15 -3
- package/dist/utils/getSchema.d.ts +1 -1
- package/dist/utils/withValidation.d.ts +2 -2
- package/dist/utils/withValidation.js +4 -4
- package/package.json +3 -2
package/dist/VovkApp.js
CHANGED
|
@@ -125,7 +125,7 @@ class VovkApp {
|
|
|
125
125
|
});
|
|
126
126
|
const { handler, methodParams } = this.#getHandler({ handlers, path, params });
|
|
127
127
|
if (!handler) {
|
|
128
|
-
return this.#respondWithError(types_1.HttpStatus.NOT_FOUND,
|
|
128
|
+
return this.#respondWithError(types_1.HttpStatus.NOT_FOUND, `${Object.keys(handlers)} - Route ${path.join('/')} is not found`);
|
|
129
129
|
}
|
|
130
130
|
const { staticMethod, controller } = handler;
|
|
131
131
|
req.vovk = {
|
package/dist/client/createRPC.js
CHANGED
|
@@ -39,11 +39,11 @@ const createRPC = (fullSchema, segmentName, controllerName, options) => {
|
|
|
39
39
|
const fetcher = input.fetcher ?? settingsFetcher;
|
|
40
40
|
const validate = async ({ body, query, params, endpoint, }) => {
|
|
41
41
|
const validateOnClient = input.validateOnClient ?? options?.validateOnClient;
|
|
42
|
-
if (validateOnClient) {
|
|
42
|
+
if (validateOnClient && validation) {
|
|
43
43
|
if (typeof validateOnClient !== 'function') {
|
|
44
44
|
throw new Error('validateOnClient must be a function');
|
|
45
45
|
}
|
|
46
|
-
await validateOnClient({ body, query, params, endpoint }, validation
|
|
46
|
+
await validateOnClient({ body, query, params, endpoint }, validation, fullSchema);
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
const internalOptions = {
|
package/dist/createDecorator.js
CHANGED
|
@@ -35,7 +35,7 @@ function createDecorator(handler, initHandler) {
|
|
|
35
35
|
// avoid override of path and httpMethod
|
|
36
36
|
...(initResult?.validation ? { validation: initResult.validation } : {}),
|
|
37
37
|
...(initResult?.openapi ? { openapi: initResult.openapi } : {}),
|
|
38
|
-
...(initResult?.
|
|
38
|
+
...(initResult?.misc ? { misc: initResult.misc } : {}),
|
|
39
39
|
},
|
|
40
40
|
};
|
|
41
41
|
};
|
package/dist/createVovkApp.js
CHANGED
|
@@ -10,9 +10,10 @@ const getSchema_1 = __importDefault(require("./utils/getSchema"));
|
|
|
10
10
|
const trimPath = (path) => path.trim().replace(/^\/|\/$/g, '');
|
|
11
11
|
const isClass = (func) => typeof func === 'function' && /class/.test(func.toString());
|
|
12
12
|
const toKebabCase = (str) => str
|
|
13
|
-
.replace(/([A-Z])/g, '-$
|
|
13
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2') // Add hyphen between lowercase/digit and uppercase
|
|
14
|
+
.replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1-$2') // Add hyphen between uppercase letters if the second one is followed by a lowercase
|
|
14
15
|
.toLowerCase()
|
|
15
|
-
.replace(/^-/, '');
|
|
16
|
+
.replace(/^-/, ''); // Remove leading hyphen
|
|
16
17
|
const assignSchema = ({ controller, propertyKey, path, options, httpMethod, vovkApp, }) => {
|
|
17
18
|
if (typeof window !== 'undefined') {
|
|
18
19
|
throw new Error('Decorators are intended for server-side use only. You have probably imported a controller on the client-side.');
|
|
@@ -40,6 +41,13 @@ const assignSchema = ({ controller, propertyKey, path, options, httpMethod, vovk
|
|
|
40
41
|
};
|
|
41
42
|
methods[path] = controller[propertyKey];
|
|
42
43
|
methods[path]._options = options;
|
|
44
|
+
controller._handlersMetadata = {
|
|
45
|
+
...controller._handlersMetadata,
|
|
46
|
+
[propertyKey]: {
|
|
47
|
+
...(controller._handlersMetadata ?? {})[propertyKey],
|
|
48
|
+
staticParams: options?.staticParams,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
43
51
|
};
|
|
44
52
|
function createVovkApp() {
|
|
45
53
|
const vovkApp = new VovkApp_1.VovkApp();
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { NextRequest } from 'next/server';
|
|
2
2
|
import type { OperationObject } from 'openapi3-ts/oas31';
|
|
3
|
+
import type { PackageJson } from 'type-fest';
|
|
3
4
|
import type { JSONLinesResponse } from './JSONLinesResponse';
|
|
4
5
|
import { VovkStreamAsyncIterable } from './client/types';
|
|
5
6
|
export type KnownAny = any;
|
|
@@ -15,7 +16,7 @@ export type VovkHandlerSchema = {
|
|
|
15
16
|
iteration?: KnownAny;
|
|
16
17
|
};
|
|
17
18
|
openapi?: OperationObject;
|
|
18
|
-
|
|
19
|
+
misc?: Record<string, KnownAny>;
|
|
19
20
|
};
|
|
20
21
|
export type VovkControllerSchema = {
|
|
21
22
|
controllerName: string;
|
|
@@ -38,6 +39,9 @@ export type VovkControllerInternal = {
|
|
|
38
39
|
_controllerName?: VovkControllerSchema['controllerName'];
|
|
39
40
|
_prefix?: VovkControllerSchema['prefix'];
|
|
40
41
|
_handlers: VovkControllerSchema['handlers'];
|
|
42
|
+
_handlersMetadata?: Record<string, {
|
|
43
|
+
staticParams?: Record<string, string>[];
|
|
44
|
+
}>;
|
|
41
45
|
_activated?: true;
|
|
42
46
|
_onError?: (err: Error, req: VovkRequest) => void | Promise<void>;
|
|
43
47
|
};
|
|
@@ -47,6 +51,7 @@ export type VovkController = StaticClass & VovkControllerInternal & {
|
|
|
47
51
|
export type DecoratorOptions = {
|
|
48
52
|
cors?: boolean;
|
|
49
53
|
headers?: Record<string, string>;
|
|
54
|
+
staticParams?: Record<string, string>[];
|
|
50
55
|
before?: (this: VovkController, req: VovkRequest) => unknown;
|
|
51
56
|
};
|
|
52
57
|
export type RouteHandler = ((req: VovkRequest, params: Record<string, string>) => Response | Promise<Response> | Iterable<unknown> | AsyncIterable<unknown>) & {
|
|
@@ -99,9 +104,6 @@ export type StreamAbortMessage = {
|
|
|
99
104
|
type LogLevelNames = 'trace' | 'debug' | 'info' | 'warn' | 'error';
|
|
100
105
|
export type VovkEnv = {
|
|
101
106
|
PORT?: string;
|
|
102
|
-
VOVK_GENERATE_FULL_CLIENT?: string;
|
|
103
|
-
VOVK_GENERATE_SEGMENT_CLIENT?: string;
|
|
104
|
-
VOVK_CLIENT_OUT_DIR?: string;
|
|
105
107
|
VOVK_SCHEMA_OUT_DIR?: string;
|
|
106
108
|
VOVK_IMPORTS_FETCHER?: string;
|
|
107
109
|
VOVK_IMPORTS_VALIDATE_ON_CLIENT?: string;
|
|
@@ -117,20 +119,40 @@ export type VovkEnv = {
|
|
|
117
119
|
__VOVK_START_WATCHER_IN_STANDALONE_MODE__?: 'true';
|
|
118
120
|
__VOVK_EXIT__?: 'true' | 'false';
|
|
119
121
|
};
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
type ClientConfigCommon = {
|
|
123
|
+
enabled?: boolean;
|
|
122
124
|
outDir?: string;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
fromTemplates?: string[];
|
|
126
|
+
} & ({
|
|
127
|
+
excludeSegments?: never;
|
|
128
|
+
includeSegments?: string[];
|
|
129
|
+
} | {
|
|
130
|
+
excludeSegments?: string[];
|
|
131
|
+
includeSegments?: never;
|
|
132
|
+
});
|
|
133
|
+
type ClientConfigFull = ClientConfigCommon & {
|
|
134
|
+
package?: PackageJson;
|
|
135
|
+
};
|
|
136
|
+
type ClientConfigSegmented = ClientConfigCommon & {
|
|
137
|
+
packages?: Record<string, PackageJson>;
|
|
138
|
+
};
|
|
139
|
+
export type ClientTemplateDef = {
|
|
140
|
+
extends?: string;
|
|
141
|
+
templatePath: string;
|
|
125
142
|
origin?: string | null;
|
|
143
|
+
fullClient?: Omit<ClientConfigFull, 'fromTemplates' | 'enabled'>;
|
|
144
|
+
segmentedClient?: Omit<ClientConfigSegmented, 'fromTemplates' | 'enabled'>;
|
|
145
|
+
segmentConfig?: false | Record<string, {
|
|
146
|
+
origin?: string;
|
|
147
|
+
rootEntry?: boolean;
|
|
148
|
+
}>;
|
|
149
|
+
requires?: Record<string, string>;
|
|
126
150
|
};
|
|
127
|
-
type GenerateFrom = (string | GenerateFromTemplate)[];
|
|
128
151
|
export type VovkConfig = {
|
|
129
152
|
emitConfig?: boolean | (keyof VovkStrictConfig)[];
|
|
130
|
-
clientOutDir?: string;
|
|
131
153
|
schemaOutDir?: string;
|
|
132
|
-
|
|
133
|
-
|
|
154
|
+
fullClient?: ClientConfigFull;
|
|
155
|
+
segmentedClient?: ClientConfigSegmented;
|
|
134
156
|
imports?: {
|
|
135
157
|
fetcher?: string | [string, string] | [string];
|
|
136
158
|
validateOnClient?: string | [string, string] | [string];
|
|
@@ -143,23 +165,28 @@ export type VovkConfig = {
|
|
|
143
165
|
logLevel?: LogLevelNames;
|
|
144
166
|
prettifyClient?: boolean;
|
|
145
167
|
devHttps?: boolean;
|
|
146
|
-
|
|
147
|
-
|
|
168
|
+
clientTemplateDefs?: Record<string, ClientTemplateDef>;
|
|
169
|
+
moduleTemplates?: {
|
|
148
170
|
service?: string;
|
|
149
171
|
controller?: string;
|
|
150
172
|
[key: string]: string | undefined;
|
|
151
173
|
};
|
|
152
174
|
libs?: Record<string, KnownAny>;
|
|
175
|
+
segmentConfig?: false | Record<string, {
|
|
176
|
+
origin?: string;
|
|
177
|
+
rootEntry?: boolean;
|
|
178
|
+
}>;
|
|
153
179
|
};
|
|
154
|
-
export type VovkStrictConfig = Required<Omit<VovkConfig, 'emitConfig' | '
|
|
180
|
+
export type VovkStrictConfig = Required<Omit<VovkConfig, 'emitConfig' | 'libs' | 'imports' | 'fullClient' | 'segmentedClient'>> & {
|
|
155
181
|
emitConfig: (keyof VovkStrictConfig)[];
|
|
156
182
|
imports: {
|
|
157
183
|
fetcher: [string, string] | [string];
|
|
158
184
|
validateOnClient: [string, string] | [string] | null;
|
|
159
185
|
createRPC: [string, string] | [string];
|
|
160
186
|
};
|
|
161
|
-
generateFrom: GenerateFrom;
|
|
162
187
|
libs: Record<string, KnownAny>;
|
|
188
|
+
fullClient: RequireFields<ClientConfigFull, 'enabled' | 'fromTemplates' | 'outDir'>;
|
|
189
|
+
segmentedClient: RequireFields<ClientConfigSegmented, 'enabled' | 'fromTemplates' | 'outDir'>;
|
|
163
190
|
};
|
|
164
191
|
export type VovkFullSchema = {
|
|
165
192
|
config: Partial<VovkStrictConfig>;
|
|
@@ -226,4 +253,5 @@ export declare enum HttpStatus {
|
|
|
226
253
|
GATEWAY_TIMEOUT = 504,
|
|
227
254
|
HTTP_VERSION_NOT_SUPPORTED = 505
|
|
228
255
|
}
|
|
256
|
+
type RequireFields<T, K extends keyof T> = T & Required<Pick<T, K>>;
|
|
229
257
|
export {};
|
|
@@ -9,9 +9,21 @@ function generateStaticAPI(c, slug = 'vovk') {
|
|
|
9
9
|
.map((controller) => {
|
|
10
10
|
const handlers = controller._handlers;
|
|
11
11
|
const splitPrefix = controller._prefix?.split('/') ?? [];
|
|
12
|
-
return Object.
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
return Object.entries(handlers)
|
|
13
|
+
.map(([name, handler]) => {
|
|
14
|
+
const staticParams = controller._handlersMetadata?.[name]?.staticParams;
|
|
15
|
+
if (staticParams?.length) {
|
|
16
|
+
return staticParams.map((paramsItem) => {
|
|
17
|
+
let path = handler.path;
|
|
18
|
+
for (const [key, value] of Object.entries(paramsItem)) {
|
|
19
|
+
path = path.replace(`:${key}`, value);
|
|
20
|
+
}
|
|
21
|
+
return { [slug]: [...splitPrefix, ...path.split('/')].filter(Boolean) };
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return [{ [slug]: [...splitPrefix, ...handler.path.split('/')].filter(Boolean) }];
|
|
25
|
+
})
|
|
26
|
+
.flat();
|
|
15
27
|
})
|
|
16
28
|
.flat(),
|
|
17
29
|
];
|
|
@@ -8,7 +8,7 @@ export declare function getControllerSchema(controller: VovkController, controll
|
|
|
8
8
|
path: string;
|
|
9
9
|
httpMethod: string;
|
|
10
10
|
openapi?: import("openapi3-ts/oas31").OperationObject;
|
|
11
|
-
|
|
11
|
+
misc?: Record<string, import("../types").KnownAny>;
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
14
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { VovkValidationType, type KnownAny, type VovkRequest } from '../types';
|
|
2
|
-
export declare function withValidation<T extends (req: KnownAny, params: KnownAny) => KnownAny, BODY_MODEL, QUERY_MODEL, PARAMS_MODEL, OUTPUT_MODEL, ITERATION_MODEL>({ disableServerSideValidation, skipSchemaEmission,
|
|
2
|
+
export declare function withValidation<T extends (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, }: {
|
|
3
3
|
disableServerSideValidation?: boolean | VovkValidationType[];
|
|
4
4
|
skipSchemaEmission?: boolean | VovkValidationType[];
|
|
5
|
-
|
|
5
|
+
validateEachIteration?: boolean;
|
|
6
6
|
body?: BODY_MODEL;
|
|
7
7
|
query?: QUERY_MODEL;
|
|
8
8
|
params?: PARAMS_MODEL;
|
|
@@ -5,7 +5,7 @@ const HttpException_1 = require("../HttpException");
|
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const setHandlerSchema_1 = require("./setHandlerSchema");
|
|
7
7
|
const validationTypes = ['body', 'query', 'params', 'output', 'iteration'];
|
|
8
|
-
function withValidation({ disableServerSideValidation, skipSchemaEmission,
|
|
8
|
+
function withValidation({ disableServerSideValidation, skipSchemaEmission, validateEachIteration, body, query, params, output, iteration, handle, getJSONSchemaFromModel, validate, }) {
|
|
9
9
|
const disableServerSideValidationKeys = disableServerSideValidation === false
|
|
10
10
|
? []
|
|
11
11
|
: disableServerSideValidation === true
|
|
@@ -32,7 +32,7 @@ function withValidation({ disableServerSideValidation, skipSchemaEmission, valid
|
|
|
32
32
|
return (async function* () {
|
|
33
33
|
let i = 0;
|
|
34
34
|
for await (const item of data) {
|
|
35
|
-
if (
|
|
35
|
+
if (validateEachIteration || i === 0) {
|
|
36
36
|
await validate(item, iteration, { type: 'iteration', req, status: 200, i });
|
|
37
37
|
}
|
|
38
38
|
i++;
|
|
@@ -40,8 +40,8 @@ function withValidation({ disableServerSideValidation, skipSchemaEmission, valid
|
|
|
40
40
|
}
|
|
41
41
|
})();
|
|
42
42
|
}
|
|
43
|
-
else if (
|
|
44
|
-
throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, '
|
|
43
|
+
else if (validateEachIteration) {
|
|
44
|
+
throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, 'validateEachIteration is set but iteration is not defined.');
|
|
45
45
|
}
|
|
46
46
|
return data;
|
|
47
47
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vovk",
|
|
3
|
-
"version": "3.0.0-draft.
|
|
3
|
+
"version": "3.0.0-draft.118",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"description": "RESTful RPC for Next.js - Transforms Next.js into a powerful REST API platform with RPC capabilities.",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"next": "*"
|
|
31
31
|
},
|
|
32
32
|
"optionalDependencies": {
|
|
33
|
-
"openapi3-ts": "*"
|
|
33
|
+
"openapi3-ts": "*",
|
|
34
|
+
"type-fest": "*"
|
|
34
35
|
}
|
|
35
36
|
}
|