vovk 3.0.0-draft.3 → 3.0.0-draft.31
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/README.md +26 -25
- package/{StreamResponse.d.ts → StreamJSONResponse.d.ts} +3 -2
- package/{StreamResponse.js → StreamJSONResponse.js} +6 -5
- package/{Segment.d.ts → VovkApp.d.ts} +2 -2
- package/{Segment.js → VovkApp.js} +14 -11
- package/client/clientizeController.d.ts +1 -1
- package/client/clientizeController.js +12 -13
- package/client/defaultFetcher.js +3 -3
- package/client/defaultHandler.js +2 -1
- package/client/types.d.ts +6 -6
- package/createDecorator.js +2 -2
- package/{createSegment.d.ts → createVovkApp.d.ts} +4 -4
- package/{createSegment.js → createVovkApp.js} +25 -27
- package/index.d.ts +7 -7
- package/index.js +7 -7
- package/package.json +3 -2
- package/types.d.ts +29 -43
- package/utils/generateStaticAPI.d.ts +4 -0
- package/{generateStaticAPI.js → utils/generateStaticAPI.js} +1 -2
- package/utils/getSchema.d.ts +4 -4
- package/utils/getSchema.js +11 -11
- package/utils/reqForm.d.ts +3 -0
- package/utils/reqForm.js +13 -0
- package/utils/setClientValidatorsForHandler.d.ts +1 -1
- package/utils/setClientValidatorsForHandler.js +2 -5
- package/worker/promisifyWorker.d.ts +1 -1
- package/worker/promisifyWorker.js +18 -19
- package/worker/types.d.ts +2 -2
- package/worker/worker.js +6 -8
- package/generateStaticAPI.d.ts +0 -3
package/README.md
CHANGED
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
<a href="https://github.com/finom/vovk/actions/workflows/main.yml"><img src="https://github.com/finom/vovk/actions/workflows/main.yml/badge.svg" alt="Build status" /></a>
|
|
29
29
|
</p>
|
|
30
30
|
|
|
31
|
-
|
|
32
31
|
<br />
|
|
33
32
|
|
|
34
33
|
Example back-end Controller Class:
|
|
@@ -37,7 +36,7 @@ Example back-end Controller Class:
|
|
|
37
36
|
// /src/modules/post/PostController.ts
|
|
38
37
|
import { get, prefix, type VovkRequest } from 'vovk';
|
|
39
38
|
import PostService from './PostService';
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
@prefix('posts')
|
|
42
41
|
export default class PostController {
|
|
43
42
|
/**
|
|
@@ -47,19 +46,19 @@ export default class PostController {
|
|
|
47
46
|
@post(':postId/comments')
|
|
48
47
|
static async createComment(
|
|
49
48
|
// decorate NextRequest type with body and query types
|
|
50
|
-
req: VovkRequest<
|
|
51
|
-
{ content: string; userId: string },
|
|
52
|
-
{ notificationType: 'push' | 'email' }
|
|
53
|
-
>,
|
|
49
|
+
req: VovkRequest<{ content: string; userId: string }, { notificationType: 'push' | 'email' }>,
|
|
54
50
|
{ postId }: { postId: string } // params
|
|
55
51
|
) {
|
|
56
52
|
// use standard Next.js API to get body and query
|
|
57
53
|
const { content, userId } = await req.json();
|
|
58
54
|
const notificationType = req.nextUrl.searchParams.get('notificationType');
|
|
59
|
-
|
|
55
|
+
|
|
60
56
|
// perform the request to the database in a custom service
|
|
61
|
-
return PostService.createComment({
|
|
62
|
-
postId,
|
|
57
|
+
return PostService.createComment({
|
|
58
|
+
postId,
|
|
59
|
+
content,
|
|
60
|
+
userId,
|
|
61
|
+
notificationType,
|
|
63
62
|
});
|
|
64
63
|
}
|
|
65
64
|
}
|
|
@@ -72,23 +71,25 @@ Example component that uses the auto-generated client library:
|
|
|
72
71
|
import { useState } from 'react';
|
|
73
72
|
import { PostController } from 'vovk-client';
|
|
74
73
|
import type { VovkReturnType } from 'vovk';
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
export default function Example() {
|
|
77
76
|
const [response, setResponse] = useState<VovkReturnType<typeof PostController.createComment>>();
|
|
78
|
-
|
|
77
|
+
|
|
79
78
|
return (
|
|
80
79
|
<>
|
|
81
80
|
<button
|
|
82
|
-
onClick={async () =>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
81
|
+
onClick={async () =>
|
|
82
|
+
setResponse(
|
|
83
|
+
await PostController.createComment({
|
|
84
|
+
body: {
|
|
85
|
+
content: 'Hello, World!',
|
|
86
|
+
userId: '1',
|
|
87
|
+
},
|
|
88
|
+
params: { postId: '69' },
|
|
89
|
+
query: { notificationType: 'push' },
|
|
90
|
+
})
|
|
91
|
+
)
|
|
92
|
+
}
|
|
92
93
|
>
|
|
93
94
|
Post a comment
|
|
94
95
|
</button>
|
|
@@ -103,9 +104,9 @@ Alternatively, the resource can be fetched wit the regular `fetch` function:
|
|
|
103
104
|
```ts
|
|
104
105
|
fetch('/api/posts/69?notificationType=push', {
|
|
105
106
|
method: 'POST',
|
|
106
|
-
body: JSON.stringify({
|
|
107
|
-
content: 'Hello, World!',
|
|
108
|
-
userId: '1',
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
content: 'Hello, World!',
|
|
109
|
+
userId: '1',
|
|
109
110
|
}),
|
|
110
|
-
})
|
|
111
|
+
});
|
|
111
112
|
```
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { _KnownAny as KnownAny, _StreamAbortMessage as StreamAbortMessage } from './types';
|
|
2
2
|
import './utils/shim';
|
|
3
|
-
export declare class
|
|
3
|
+
export declare class _StreamJSONResponse<T> extends Response {
|
|
4
4
|
static defaultHeaders: {
|
|
5
|
-
'
|
|
5
|
+
'content-type': string;
|
|
6
|
+
'x-vovk-stream': string;
|
|
6
7
|
};
|
|
7
8
|
isClosed: boolean;
|
|
8
9
|
controller?: ReadableStreamDefaultController;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports._StreamJSONResponse = void 0;
|
|
4
4
|
require("./utils/shim");
|
|
5
|
-
class
|
|
5
|
+
class _StreamJSONResponse extends Response {
|
|
6
6
|
static defaultHeaders = {
|
|
7
|
-
'
|
|
7
|
+
'content-type': 'text/plain; charset=utf-8',
|
|
8
|
+
'x-vovk-stream': 'true',
|
|
8
9
|
};
|
|
9
10
|
isClosed = false;
|
|
10
11
|
controller;
|
|
@@ -23,7 +24,7 @@ class _StreamResponse extends Response {
|
|
|
23
24
|
});
|
|
24
25
|
super(readableStream, {
|
|
25
26
|
...init,
|
|
26
|
-
headers: init?.headers ??
|
|
27
|
+
headers: init?.headers ?? _StreamJSONResponse.defaultHeaders,
|
|
27
28
|
});
|
|
28
29
|
this.readableStream = readableStream;
|
|
29
30
|
this.encoder = encoder;
|
|
@@ -50,4 +51,4 @@ class _StreamResponse extends Response {
|
|
|
50
51
|
this.close();
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
|
-
exports.
|
|
54
|
+
exports._StreamJSONResponse = _StreamJSONResponse;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { _HttpMethod as HttpMethod, _HttpStatus as HttpStatus, type _RouteHandler as RouteHandler, type _VovkController as VovkController, type _DecoratorOptions as DecoratorOptions, type _VovkRequest as VovkRequest } from './types';
|
|
2
|
-
export declare class
|
|
2
|
+
export declare class _VovkApp {
|
|
3
3
|
#private;
|
|
4
4
|
private static getHeadersFromOptions;
|
|
5
|
-
|
|
5
|
+
routes: Record<HttpMethod, Map<VovkController, Record<string, RouteHandler>>>;
|
|
6
6
|
GET: (req: VovkRequest, data: {
|
|
7
7
|
params: Promise<Record<string, string[]>>;
|
|
8
8
|
}) => Promise<Response>;
|
|
@@ -4,13 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
var _a;
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.
|
|
7
|
+
exports._VovkApp = void 0;
|
|
8
8
|
const types_1 = require("./types");
|
|
9
9
|
const HttpException_1 = require("./HttpException");
|
|
10
|
-
const
|
|
10
|
+
const StreamJSONResponse_1 = require("./StreamJSONResponse");
|
|
11
11
|
const reqQuery_1 = __importDefault(require("./utils/reqQuery"));
|
|
12
12
|
const reqMeta_1 = __importDefault(require("./utils/reqMeta"));
|
|
13
|
-
|
|
13
|
+
const reqForm_1 = __importDefault(require("./utils/reqForm"));
|
|
14
|
+
class _VovkApp {
|
|
14
15
|
static getHeadersFromOptions(options) {
|
|
15
16
|
if (!options)
|
|
16
17
|
return {};
|
|
@@ -25,7 +26,7 @@ class _Segment {
|
|
|
25
26
|
};
|
|
26
27
|
return headers;
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
+
routes = {
|
|
29
30
|
GET: new Map(),
|
|
30
31
|
POST: new Map(),
|
|
31
32
|
PUT: new Map(),
|
|
@@ -50,15 +51,16 @@ class _Segment {
|
|
|
50
51
|
},
|
|
51
52
|
});
|
|
52
53
|
};
|
|
53
|
-
#respondWithError = (statusCode, message, options) => {
|
|
54
|
+
#respondWithError = (statusCode, message, options, cause) => {
|
|
54
55
|
return this.respond(statusCode, {
|
|
56
|
+
cause,
|
|
55
57
|
statusCode,
|
|
56
58
|
message,
|
|
57
59
|
isError: true,
|
|
58
60
|
}, options);
|
|
59
61
|
};
|
|
60
62
|
#callMethod = async (httpMethod, req, params) => {
|
|
61
|
-
const controllers = this.
|
|
63
|
+
const controllers = this.routes[httpMethod];
|
|
62
64
|
const methodParams = {};
|
|
63
65
|
const path = params[Object.keys(params)[0]];
|
|
64
66
|
const handlers = {};
|
|
@@ -127,6 +129,7 @@ class _Segment {
|
|
|
127
129
|
body: () => req.json(),
|
|
128
130
|
query: () => (0, reqQuery_1.default)(req),
|
|
129
131
|
meta: (meta) => (0, reqMeta_1.default)(req, meta),
|
|
132
|
+
form: () => (0, reqForm_1.default)(req),
|
|
130
133
|
};
|
|
131
134
|
try {
|
|
132
135
|
const result = await staticMethod.call(controller, req, methodParams);
|
|
@@ -137,9 +140,9 @@ class _Segment {
|
|
|
137
140
|
(Reflect.has(result, Symbol.asyncIterator) &&
|
|
138
141
|
typeof result[Symbol.asyncIterator] === 'function'));
|
|
139
142
|
if (isIterator && !(result instanceof Array)) {
|
|
140
|
-
const streamResponse = new
|
|
143
|
+
const streamResponse = new StreamJSONResponse_1._StreamJSONResponse({
|
|
141
144
|
headers: {
|
|
142
|
-
...
|
|
145
|
+
...StreamJSONResponse_1._StreamJSONResponse.defaultHeaders,
|
|
143
146
|
..._a.getHeadersFromOptions(staticMethod._options),
|
|
144
147
|
},
|
|
145
148
|
});
|
|
@@ -172,11 +175,11 @@ class _Segment {
|
|
|
172
175
|
}
|
|
173
176
|
if (err.message !== 'NEXT_REDIRECT' && err.message !== 'NEXT_NOT_FOUND') {
|
|
174
177
|
const statusCode = err.statusCode ?? types_1._HttpStatus.INTERNAL_SERVER_ERROR;
|
|
175
|
-
return this.#respondWithError(statusCode, err.message, staticMethod._options);
|
|
178
|
+
return this.#respondWithError(statusCode, err.message, staticMethod._options, err.cause);
|
|
176
179
|
}
|
|
177
180
|
throw e; // if NEXT_REDIRECT or NEXT_NOT_FOUND, rethrow it
|
|
178
181
|
}
|
|
179
182
|
};
|
|
180
183
|
}
|
|
181
|
-
exports.
|
|
182
|
-
_a =
|
|
184
|
+
exports._VovkApp = _VovkApp;
|
|
185
|
+
_a = _VovkApp;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type _VovkControllerSchema as VovkControllerSchema, type _KnownAny as KnownAny } from '../types';
|
|
2
2
|
import { type _VovkClientOptions as VovkClientOptions, type _VovkClient as VovkClient, type _VovkDefaultFetcherOptions as VovkDefaultFetcherOptions } from './types';
|
|
3
3
|
export declare const ARRAY_QUERY_KEY = "_vovkarr";
|
|
4
|
-
export declare const _clientizeController: <T, OPTS extends Record<string, KnownAny> = VovkDefaultFetcherOptions>(
|
|
4
|
+
export declare const _clientizeController: <T, OPTS extends Record<string, KnownAny> = VovkDefaultFetcherOptions>(controllerSchema: VovkControllerSchema, segmentName?: string, options?: VovkClientOptions<OPTS>) => VovkClient<T, OPTS>;
|
|
@@ -36,27 +36,26 @@ const getHandlerPath = (endpoint, params, query) => {
|
|
|
36
36
|
}
|
|
37
37
|
return `${result}${hasQuery ? '?' : ''}${searchParams.toString()}`;
|
|
38
38
|
};
|
|
39
|
-
const _clientizeController = (
|
|
40
|
-
const
|
|
39
|
+
const _clientizeController = (controllerSchema, segmentName, options) => {
|
|
40
|
+
const schema = controllerSchema;
|
|
41
41
|
const client = {};
|
|
42
|
-
if (!controller)
|
|
43
|
-
throw new Error(`Unable to clientize. Controller schema is not provided`);
|
|
44
|
-
const schema = controller._handlers;
|
|
45
42
|
if (!schema)
|
|
46
|
-
throw new Error(`Unable to clientize.
|
|
47
|
-
|
|
43
|
+
throw new Error(`Unable to clientize. Controller schema is not provided`);
|
|
44
|
+
if (!schema.handlers)
|
|
45
|
+
throw new Error(`Unable to clientize. No schema for controller ${String(schema?.controllerName)}`);
|
|
46
|
+
const controllerPrefix = trimPath(schema.prefix ?? '');
|
|
48
47
|
const { fetcher: settingsFetcher = defaultFetcher_1.default } = options ?? {};
|
|
49
|
-
for (const [staticMethodName, { path, httpMethod,
|
|
50
|
-
const getEndpoint = ({
|
|
51
|
-
const mainPrefix = (
|
|
52
|
-
(
|
|
48
|
+
for (const [staticMethodName, { path, httpMethod, validation }] of Object.entries(schema.handlers)) {
|
|
49
|
+
const getEndpoint = ({ apiRoot, params, query, }) => {
|
|
50
|
+
const mainPrefix = (apiRoot.startsWith('http://') || apiRoot.startsWith('https://') || apiRoot.startsWith('/') ? '' : '/') +
|
|
51
|
+
(apiRoot.endsWith('/') ? apiRoot : `${apiRoot}/`) +
|
|
53
52
|
(segmentName ? `${segmentName}/` : '');
|
|
54
53
|
return mainPrefix + getHandlerPath([controllerPrefix, path].filter(Boolean).join('/'), params, query);
|
|
55
54
|
};
|
|
56
55
|
const handler = (input = {}) => {
|
|
57
56
|
const fetcher = input.fetcher ?? settingsFetcher;
|
|
58
57
|
const validate = async ({ body, query, endpoint }) => {
|
|
59
|
-
await (input.validateOnClient ?? options?.validateOnClient)?.({ body, query, endpoint },
|
|
58
|
+
await (input.validateOnClient ?? options?.validateOnClient)?.({ body, query, endpoint }, validation ?? {});
|
|
60
59
|
};
|
|
61
60
|
const internalOptions = {
|
|
62
61
|
name: staticMethodName,
|
|
@@ -85,7 +84,7 @@ const _clientizeController = (givenController, segmentName, options) => {
|
|
|
85
84
|
return Promise.resolve(fetcherPromise);
|
|
86
85
|
return input.transform ? fetcherPromise.then(input.transform) : fetcherPromise;
|
|
87
86
|
};
|
|
88
|
-
// @ts-expect-error TODO
|
|
87
|
+
// @ts-expect-error TODO
|
|
89
88
|
client[staticMethodName] = handler;
|
|
90
89
|
}
|
|
91
90
|
return client;
|
package/client/defaultFetcher.js
CHANGED
|
@@ -6,8 +6,8 @@ const HttpException_1 = require("../HttpException");
|
|
|
6
6
|
exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at defaultFetcher';
|
|
7
7
|
// defaultFetcher uses HttpException class to throw errors of fake HTTP status 0 if client-side error occurs
|
|
8
8
|
// For normal HTTP errors, it uses message and status code from the response of VovkErrorResponse type
|
|
9
|
-
const defaultFetcher = async ({ httpMethod, getEndpoint, validate, defaultHandler, defaultStreamHandler }, { params, query, body,
|
|
10
|
-
const endpoint = getEndpoint({
|
|
9
|
+
const defaultFetcher = async ({ httpMethod, getEndpoint, validate, defaultHandler, defaultStreamHandler }, { params, query, body, apiRoot = '/api', ...options }) => {
|
|
10
|
+
const endpoint = getEndpoint({ apiRoot, params, query });
|
|
11
11
|
if (!options.disableClientValidation) {
|
|
12
12
|
try {
|
|
13
13
|
await validate({ body, query, endpoint });
|
|
@@ -41,7 +41,7 @@ const defaultFetcher = async ({ httpMethod, getEndpoint, validate, defaultHandle
|
|
|
41
41
|
if (response.headers.get('content-type')?.includes('application/json')) {
|
|
42
42
|
return defaultHandler(response);
|
|
43
43
|
}
|
|
44
|
-
if (response.headers.get('
|
|
44
|
+
if (response.headers.get('x-vovk-stream') === 'true') {
|
|
45
45
|
return defaultStreamHandler(response);
|
|
46
46
|
}
|
|
47
47
|
return response;
|
package/client/defaultHandler.js
CHANGED
|
@@ -14,7 +14,8 @@ const _defaultHandler = async (response) => {
|
|
|
14
14
|
}
|
|
15
15
|
if (!response.ok) {
|
|
16
16
|
// handle server errors
|
|
17
|
-
|
|
17
|
+
const errorResponse = result;
|
|
18
|
+
throw new HttpException_1._HttpException(response.status, errorResponse?.message ?? exports.DEFAULT_ERROR_MESSAGE, errorResponse?.cause);
|
|
18
19
|
}
|
|
19
20
|
return result;
|
|
20
21
|
};
|
package/client/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { _KnownAny as KnownAny, _HttpMethod as HttpMethod, _ControllerStaticMethod, _VovkControllerBody, _VovkControllerQuery, _VovkControllerParams } from '../types';
|
|
2
|
-
import {
|
|
2
|
+
import { _StreamJSONResponse as StreamJSONResponse } from '../StreamJSONResponse';
|
|
3
3
|
import type { NextResponse } from 'next/server';
|
|
4
4
|
export type _StaticMethodInput<T extends _ControllerStaticMethod> = (_VovkControllerBody<T> extends undefined | void ? {
|
|
5
5
|
body?: undefined;
|
|
@@ -24,9 +24,9 @@ export type _StreamAsyncIterator<T> = {
|
|
|
24
24
|
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
25
25
|
cancel: () => Promise<void> | void;
|
|
26
26
|
};
|
|
27
|
-
type StaticMethodReturn<T extends _ControllerStaticMethod> = ReturnType<T> extends NextResponse<infer U> | Promise<NextResponse<infer U>> ? U : ReturnType<T> extends Response | Promise<Response> ?
|
|
27
|
+
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>;
|
|
28
28
|
type StaticMethodReturnPromise<T extends _ControllerStaticMethod> = ToPromise<StaticMethodReturn<T>>;
|
|
29
|
-
type ClientMethod<T extends (...args: KnownAny[]) => void | object |
|
|
29
|
+
type ClientMethod<T extends (...args: KnownAny[]) => void | object | StreamJSONResponse<STREAM> | Promise<StreamJSONResponse<STREAM>>, OPTS extends Record<string, KnownAny>, STREAM extends KnownAny = unknown> = <R>(options: (_StaticMethodInput<T> extends {
|
|
30
30
|
body?: undefined | null;
|
|
31
31
|
query?: undefined;
|
|
32
32
|
params?: undefined;
|
|
@@ -34,7 +34,7 @@ type ClientMethod<T extends (...args: KnownAny[]) => void | object | StreamRespo
|
|
|
34
34
|
params: _StaticMethodInput<T>['params'];
|
|
35
35
|
} : unknown : _StaticMethodInput<T>) & (Partial<OPTS & {
|
|
36
36
|
transform: (staticMethodReturn: Awaited<StaticMethodReturn<T>>) => R;
|
|
37
|
-
}> | void)) => ReturnType<T> extends Promise<
|
|
37
|
+
}> | void)) => ReturnType<T> extends Promise<StreamJSONResponse<infer U>> | StreamJSONResponse<infer U> | Iterator<infer U> | AsyncIterator<infer U> ? Promise<_StreamAsyncIterator<U>> : R extends object ? Promise<R> : StaticMethodReturnPromise<T>;
|
|
38
38
|
type OmitNever<T> = {
|
|
39
39
|
[K in keyof T as T[K] extends never ? never : K]: T[K];
|
|
40
40
|
};
|
|
@@ -50,7 +50,7 @@ export type _VovkClientFetcher<OPTS extends Record<string, KnownAny> = Record<st
|
|
|
50
50
|
name: keyof T;
|
|
51
51
|
httpMethod: HttpMethod;
|
|
52
52
|
getEndpoint: (data: {
|
|
53
|
-
|
|
53
|
+
apiRoot: string;
|
|
54
54
|
params: {
|
|
55
55
|
[key: string]: string;
|
|
56
56
|
};
|
|
@@ -78,7 +78,7 @@ export interface _VovkDefaultFetcherOptions extends Omit<RequestInit, 'body' | '
|
|
|
78
78
|
reactNative?: {
|
|
79
79
|
textStreaming: boolean;
|
|
80
80
|
};
|
|
81
|
-
|
|
81
|
+
apiRoot?: string;
|
|
82
82
|
segmentName?: string;
|
|
83
83
|
disableClientValidation?: boolean;
|
|
84
84
|
validateOnClient?: _VovkValidateOnClient;
|
package/createDecorator.js
CHANGED
|
@@ -18,8 +18,8 @@ function _createDecorator(handler, initHandler) {
|
|
|
18
18
|
[propertyKey]: {
|
|
19
19
|
...handlerSchema,
|
|
20
20
|
// avoid override of path and httpMethod
|
|
21
|
-
...(initResult?.
|
|
22
|
-
...(initResult?.
|
|
21
|
+
...(initResult?.validation ? { validation: initResult.validation } : {}),
|
|
22
|
+
...(initResult?.custom ? { custom: initResult.custom } : {}),
|
|
23
23
|
},
|
|
24
24
|
};
|
|
25
25
|
const method = function method(req, params) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type _KnownAny as KnownAny, type _DecoratorOptions as DecoratorOptions, type _VovkRequest as VovkRequest } from './types';
|
|
2
|
-
export declare function
|
|
1
|
+
import { type _KnownAny as KnownAny, type _DecoratorOptions as DecoratorOptions, type _VovkRequest as VovkRequest, type _StaticClass as StaticClass } from './types';
|
|
2
|
+
export declare function _createVovkApp(): {
|
|
3
3
|
get: {
|
|
4
4
|
(givenPath?: string | undefined, options?: DecoratorOptions | undefined): ReturnType<(givenPath?: string, options?: DecoratorOptions) => (givenTarget: KnownAny, propertyKey: string) => void>;
|
|
5
5
|
auto: (options?: DecoratorOptions) => (givenTarget: KnownAny, propertyKey: string) => void;
|
|
@@ -31,8 +31,8 @@ export declare function _createSegment(): {
|
|
|
31
31
|
prefix: (givenPath?: string) => (givenTarget: KnownAny) => any;
|
|
32
32
|
initVovk: (options: {
|
|
33
33
|
segmentName?: string;
|
|
34
|
-
controllers: Record<string,
|
|
35
|
-
workers?: Record<string,
|
|
34
|
+
controllers: Record<string, StaticClass>;
|
|
35
|
+
workers?: Record<string, StaticClass>;
|
|
36
36
|
exposeValidation?: boolean;
|
|
37
37
|
emitSchema?: boolean;
|
|
38
38
|
onError?: (err: Error, req: VovkRequest) => void | Promise<void>;
|
|
@@ -3,9 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
|
|
8
|
-
const Segment_1 = require("./Segment");
|
|
6
|
+
exports._createVovkApp = _createVovkApp;
|
|
7
|
+
const VovkApp_1 = require("./VovkApp");
|
|
9
8
|
const types_1 = require("./types");
|
|
10
9
|
const getSchema_1 = __importDefault(require("./utils/getSchema"));
|
|
11
10
|
const trimPath = (path) => path.trim().replace(/^\/|\/$/g, '');
|
|
@@ -14,9 +13,9 @@ const toKebabCase = (str) => str
|
|
|
14
13
|
.replace(/([A-Z])/g, '-$1')
|
|
15
14
|
.toLowerCase()
|
|
16
15
|
.replace(/^-/, '');
|
|
17
|
-
function
|
|
18
|
-
const
|
|
19
|
-
const
|
|
16
|
+
function _createVovkApp() {
|
|
17
|
+
const vovkApp = new VovkApp_1._VovkApp();
|
|
18
|
+
const createHTTPDecorator = (httpMethod) => {
|
|
20
19
|
const assignSchema = (controller, propertyKey, path, options) => {
|
|
21
20
|
if (typeof window !== 'undefined') {
|
|
22
21
|
throw new Error('Decorators are intended for server-side use only. You have probably imported a controller on the client-side.');
|
|
@@ -27,8 +26,8 @@ function _createSegment() {
|
|
|
27
26
|
decoratorName = 'del';
|
|
28
27
|
throw new Error(`Decorator must be used on a static class method. Check the controller method named "${propertyKey}" used with @${decoratorName}.`);
|
|
29
28
|
}
|
|
30
|
-
const methods =
|
|
31
|
-
|
|
29
|
+
const methods = vovkApp.routes[httpMethod].get(controller) ?? {};
|
|
30
|
+
vovkApp.routes[httpMethod].set(controller, methods);
|
|
32
31
|
controller._handlers = {
|
|
33
32
|
...controller._handlers,
|
|
34
33
|
[propertyKey]: {
|
|
@@ -54,8 +53,8 @@ function _createSegment() {
|
|
|
54
53
|
const auto = (options) => {
|
|
55
54
|
function decorator(givenTarget, propertyKey) {
|
|
56
55
|
const controller = givenTarget;
|
|
57
|
-
const methods =
|
|
58
|
-
|
|
56
|
+
const methods = vovkApp.routes[httpMethod].get(controller) ?? {};
|
|
57
|
+
vovkApp.routes[httpMethod].set(controller, methods);
|
|
59
58
|
controller._handlers = {
|
|
60
59
|
...controller._handlers,
|
|
61
60
|
[propertyKey]: {
|
|
@@ -76,7 +75,6 @@ function _createSegment() {
|
|
|
76
75
|
return (givenTarget) => {
|
|
77
76
|
const controller = givenTarget;
|
|
78
77
|
controller._prefix = path;
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
80
78
|
return givenTarget;
|
|
81
79
|
};
|
|
82
80
|
};
|
|
@@ -92,28 +90,28 @@ function _createSegment() {
|
|
|
92
90
|
// Wait for schema to be set (it can be set after decorators are called with another setTimeout)
|
|
93
91
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
94
92
|
const schema = (0, getSchema_1.default)(options);
|
|
95
|
-
return
|
|
93
|
+
return vovkApp.respond(200, { schema });
|
|
96
94
|
}
|
|
97
|
-
return
|
|
95
|
+
return vovkApp.GET(req, data);
|
|
98
96
|
}
|
|
99
97
|
return {
|
|
100
|
-
GET: process.env.NODE_ENV === 'development' ? GET_DEV :
|
|
101
|
-
POST:
|
|
102
|
-
PUT:
|
|
103
|
-
PATCH:
|
|
104
|
-
DELETE:
|
|
105
|
-
HEAD:
|
|
106
|
-
OPTIONS:
|
|
98
|
+
GET: process.env.NODE_ENV === 'development' ? GET_DEV : vovkApp.GET,
|
|
99
|
+
POST: vovkApp.POST,
|
|
100
|
+
PUT: vovkApp.PUT,
|
|
101
|
+
PATCH: vovkApp.PATCH,
|
|
102
|
+
DELETE: vovkApp.DELETE,
|
|
103
|
+
HEAD: vovkApp.HEAD,
|
|
104
|
+
OPTIONS: vovkApp.OPTIONS,
|
|
107
105
|
};
|
|
108
106
|
};
|
|
109
107
|
return {
|
|
110
|
-
get:
|
|
111
|
-
post:
|
|
112
|
-
put:
|
|
113
|
-
patch:
|
|
114
|
-
del:
|
|
115
|
-
head:
|
|
116
|
-
options:
|
|
108
|
+
get: createHTTPDecorator(types_1._HttpMethod.GET),
|
|
109
|
+
post: createHTTPDecorator(types_1._HttpMethod.POST),
|
|
110
|
+
put: createHTTPDecorator(types_1._HttpMethod.PUT),
|
|
111
|
+
patch: createHTTPDecorator(types_1._HttpMethod.PATCH),
|
|
112
|
+
del: createHTTPDecorator(types_1._HttpMethod.DELETE),
|
|
113
|
+
head: createHTTPDecorator(types_1._HttpMethod.HEAD),
|
|
114
|
+
options: createHTTPDecorator(types_1._HttpMethod.OPTIONS),
|
|
117
115
|
prefix,
|
|
118
116
|
initVovk,
|
|
119
117
|
};
|
package/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type _VovkErrorResponse as VovkErrorResponse, type _VovkRequest as VovkRequest, type
|
|
1
|
+
import { _createVovkApp as createVovkApp } from './createVovkApp';
|
|
2
|
+
import { type _VovkErrorResponse as VovkErrorResponse, type _VovkRequest as VovkRequest, type _VovkBody as VovkBody, type _VovkQuery as VovkQuery, type _VovkParams as VovkParams, type _VovkReturnType as VovkReturnType, type _VovkYieldType as VovkYieldType, type _VovkControllerBody as VovkControllerBody, type _VovkControllerQuery as VovkControllerQuery, type _VovkControllerParams as VovkControllerParams, type _VovkControllerYieldType as VovkControllerYieldType, type _VovkSchema as VovkSchema, _HttpStatus as HttpStatus, _HttpMethod as HttpMethod } from './types';
|
|
3
3
|
import type { _VovkClientOptions as VovkClientOptions, _VovkClientFetcher as VovkClientFetcher, _VovkDefaultFetcherOptions as VovkDefaultFetcherOptions, _VovkValidateOnClient as VovkValidateOnClient } from './client/types';
|
|
4
4
|
import { _HttpException as HttpException } from './HttpException';
|
|
5
5
|
import { _createDecorator as createDecorator } from './createDecorator';
|
|
6
|
-
import {
|
|
6
|
+
import { _StreamJSONResponse as StreamJSONResponse } from './StreamJSONResponse';
|
|
7
7
|
import { worker } from './worker';
|
|
8
|
-
import { _generateStaticAPI as generateStaticAPI } from './generateStaticAPI';
|
|
9
|
-
export { type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkValidateOnClient, type VovkSchema, type VovkErrorResponse, type VovkRequest, type VovkControllerBody, type VovkControllerQuery, type VovkControllerParams, type
|
|
8
|
+
import { _generateStaticAPI as generateStaticAPI } from './utils/generateStaticAPI';
|
|
9
|
+
export { type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkValidateOnClient, type VovkSchema, type VovkErrorResponse, type VovkRequest, type VovkControllerBody, type VovkControllerQuery, type VovkControllerParams, type VovkControllerYieldType, type VovkBody, type VovkQuery, type VovkParams, type VovkYieldType, type VovkReturnType, type VovkClientOptions, StreamJSONResponse, HttpException, HttpStatus, HttpMethod, createVovkApp, createDecorator, worker, generateStaticAPI, };
|
|
10
10
|
export declare const get: {
|
|
11
11
|
(givenPath?: string | undefined, options?: import("./types")._DecoratorOptions | undefined): ReturnType<(givenPath?: string, options?: import("./types")._DecoratorOptions) => (givenTarget: import("./types")._KnownAny, propertyKey: string) => void>;
|
|
12
12
|
auto: (options?: import("./types")._DecoratorOptions) => (givenTarget: import("./types")._KnownAny, propertyKey: string) => void;
|
|
@@ -30,8 +30,8 @@ export declare const get: {
|
|
|
30
30
|
auto: (options?: import("./types")._DecoratorOptions) => (givenTarget: import("./types")._KnownAny, propertyKey: string) => void;
|
|
31
31
|
}, prefix: (givenPath?: string) => (givenTarget: import("./types")._KnownAny) => any, initVovk: (options: {
|
|
32
32
|
segmentName?: string;
|
|
33
|
-
controllers: Record<string,
|
|
34
|
-
workers?: Record<string,
|
|
33
|
+
controllers: Record<string, import("./types")._StaticClass>;
|
|
34
|
+
workers?: Record<string, import("./types")._StaticClass>;
|
|
35
35
|
exposeValidation?: boolean;
|
|
36
36
|
emitSchema?: boolean;
|
|
37
37
|
onError?: (err: Error, req: VovkRequest) => void | Promise<void>;
|
package/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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.generateStaticAPI = exports.worker = exports.createDecorator = exports.
|
|
5
|
-
const
|
|
6
|
-
Object.defineProperty(exports, "
|
|
4
|
+
exports.initVovk = exports.prefix = exports.options = exports.head = exports.del = exports.patch = exports.put = exports.post = exports.get = exports.generateStaticAPI = exports.worker = exports.createDecorator = exports.createVovkApp = exports.HttpMethod = exports.HttpStatus = exports.HttpException = exports.StreamJSONResponse = void 0;
|
|
5
|
+
const createVovkApp_1 = require("./createVovkApp");
|
|
6
|
+
Object.defineProperty(exports, "createVovkApp", { enumerable: true, get: function () { return createVovkApp_1._createVovkApp; } });
|
|
7
7
|
const types_1 = require("./types");
|
|
8
8
|
Object.defineProperty(exports, "HttpStatus", { enumerable: true, get: function () { return types_1._HttpStatus; } });
|
|
9
9
|
Object.defineProperty(exports, "HttpMethod", { enumerable: true, get: function () { return types_1._HttpMethod; } });
|
|
@@ -11,10 +11,10 @@ const HttpException_1 = require("./HttpException");
|
|
|
11
11
|
Object.defineProperty(exports, "HttpException", { enumerable: true, get: function () { return HttpException_1._HttpException; } });
|
|
12
12
|
const createDecorator_1 = require("./createDecorator");
|
|
13
13
|
Object.defineProperty(exports, "createDecorator", { enumerable: true, get: function () { return createDecorator_1._createDecorator; } });
|
|
14
|
-
const
|
|
15
|
-
Object.defineProperty(exports, "
|
|
14
|
+
const StreamJSONResponse_1 = require("./StreamJSONResponse");
|
|
15
|
+
Object.defineProperty(exports, "StreamJSONResponse", { enumerable: true, get: function () { return StreamJSONResponse_1._StreamJSONResponse; } });
|
|
16
16
|
const worker_1 = require("./worker");
|
|
17
17
|
Object.defineProperty(exports, "worker", { enumerable: true, get: function () { return worker_1.worker; } });
|
|
18
|
-
const generateStaticAPI_1 = require("./generateStaticAPI");
|
|
18
|
+
const generateStaticAPI_1 = require("./utils/generateStaticAPI");
|
|
19
19
|
Object.defineProperty(exports, "generateStaticAPI", { enumerable: true, get: function () { return generateStaticAPI_1._generateStaticAPI; } });
|
|
20
|
-
_a = (0,
|
|
20
|
+
_a = (0, createVovkApp_1._createVovkApp)(), exports.get = _a.get, exports.post = _a.post, exports.put = _a.put, exports.patch = _a.patch, exports.del = _a.del, exports.head = _a.head, exports.options = _a.options, exports.prefix = _a.prefix, exports.initVovk = _a.initVovk;
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vovk",
|
|
3
|
-
"version": "3.0.0-draft.
|
|
3
|
+
"version": "3.0.0-draft.31",
|
|
4
4
|
"description": "RESTful RPC for Next.js - Transforms Next.js into a powerful REST API platform with RPC capabilities.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/finom/vovk.git"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"build": "rm -rf dist && tsc && cp
|
|
10
|
+
"build": "shx rm -rf dist && tsc && shx cp package.json LICENSE .npmignore dist && shx cp ../../README.md dist",
|
|
11
11
|
"lint": "eslint . --fix",
|
|
12
|
+
"tsc": "tsc --noEmit",
|
|
12
13
|
"npm-publish": "if [ -z \"$NPM_TAG\" ]; then echo 'Error: NPM_TAG is not set'; exit 1; fi; cd ./dist && npm publish --tag=$NPM_TAG && cd ..",
|
|
13
14
|
"ncu": "npm-check-updates -u"
|
|
14
15
|
},
|
package/types.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { NextRequest } from 'next/server';
|
|
2
|
-
import type {
|
|
2
|
+
import type { _StreamJSONResponse as StreamJSONResponse } from './StreamJSONResponse';
|
|
3
3
|
import { _StreamAsyncIterator as StreamAsyncIterator } from './client/types';
|
|
4
4
|
export type _KnownAny = any;
|
|
5
|
+
export type _StaticClass = Function;
|
|
5
6
|
export type _VovkSchema = {
|
|
6
7
|
emitSchema: boolean;
|
|
7
8
|
segmentName: string;
|
|
@@ -9,6 +10,7 @@ export type _VovkSchema = {
|
|
|
9
10
|
controllers: Record<string, _VovkControllerSchema>;
|
|
10
11
|
};
|
|
11
12
|
export type _VovkErrorResponse = {
|
|
13
|
+
cause?: unknown;
|
|
12
14
|
statusCode: _HttpStatus;
|
|
13
15
|
message: string;
|
|
14
16
|
isError: true;
|
|
@@ -16,33 +18,37 @@ export type _VovkErrorResponse = {
|
|
|
16
18
|
export type _HandlerSchema = {
|
|
17
19
|
path: string;
|
|
18
20
|
httpMethod: _HttpMethod;
|
|
19
|
-
|
|
21
|
+
validation?: {
|
|
20
22
|
query?: _KnownAny;
|
|
21
23
|
body?: _KnownAny;
|
|
22
24
|
};
|
|
23
|
-
|
|
25
|
+
custom?: Record<string, _KnownAny>;
|
|
24
26
|
};
|
|
25
27
|
export type _VovkControllerSchema = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
controllerName: string;
|
|
29
|
+
originalControllerName: string;
|
|
30
|
+
prefix?: string;
|
|
31
|
+
handlers: Record<string, _HandlerSchema>;
|
|
30
32
|
};
|
|
31
33
|
export type _VovkWorkerSchema = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
workerName: string;
|
|
35
|
+
originalWorkerName: string;
|
|
36
|
+
handlers: Record<string, {
|
|
35
37
|
isGenerator?: true;
|
|
36
38
|
}>;
|
|
37
39
|
};
|
|
38
|
-
export type _VovkControllerInternal =
|
|
40
|
+
export type _VovkControllerInternal = {
|
|
41
|
+
_controllerName?: _VovkControllerSchema['controllerName'];
|
|
42
|
+
_prefix?: _VovkControllerSchema['prefix'];
|
|
43
|
+
_handlers: _VovkControllerSchema['handlers'];
|
|
39
44
|
_activated?: true;
|
|
40
45
|
_onError?: (err: Error, req: _VovkRequest) => void | Promise<void>;
|
|
41
46
|
};
|
|
42
|
-
export type _VovkController =
|
|
47
|
+
export type _VovkController = _StaticClass & _VovkControllerInternal & {
|
|
43
48
|
[key: string]: unknown;
|
|
44
49
|
};
|
|
45
|
-
export type _VovkWorker =
|
|
50
|
+
export type _VovkWorker = _StaticClass & {
|
|
51
|
+
_handlers: _VovkWorkerSchema['handlers'];
|
|
46
52
|
[key: string]: unknown;
|
|
47
53
|
};
|
|
48
54
|
export type _DecoratorOptions = {
|
|
@@ -62,49 +68,29 @@ export interface _VovkRequest<BODY = undefined, QUERY extends object | undefined
|
|
|
62
68
|
forEach: (callbackfn: (value: QUERY[keyof QUERY], key: keyof QUERY, searchParams: NextRequest['nextUrl']['searchParams']) => void) => void;
|
|
63
69
|
keys: () => IterableIterator<keyof QUERY>;
|
|
64
70
|
values: () => IterableIterator<QUERY[keyof QUERY]>;
|
|
65
|
-
readonly __queryType: QUERY;
|
|
66
71
|
};
|
|
67
72
|
};
|
|
68
73
|
vovk: {
|
|
69
74
|
body: () => Promise<BODY>;
|
|
70
75
|
query: () => QUERY;
|
|
71
76
|
meta: <T = Record<_KnownAny, _KnownAny>>(meta?: T | null) => T;
|
|
77
|
+
form: <T = _KnownAny>() => Promise<T>;
|
|
72
78
|
};
|
|
73
79
|
}
|
|
74
|
-
export type _ControllerStaticMethod<REQ extends _VovkRequest<
|
|
80
|
+
export type _ControllerStaticMethod<REQ extends _VovkRequest<_KnownAny, _KnownAny> = _VovkRequest<undefined, Record<string, string | string[]>>, PARAMS extends {
|
|
75
81
|
[key: string]: string;
|
|
76
82
|
} = _KnownAny> = ((req: REQ, params: PARAMS) => unknown) & {
|
|
77
83
|
_controller?: _VovkController;
|
|
78
84
|
};
|
|
79
|
-
export type _VovkControllerBody<T extends
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
export type
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
export type
|
|
86
|
-
[key: string]: string;
|
|
87
|
-
} = _KnownAny> = Parameters<T>[1];
|
|
88
|
-
export type _VovkBody<T extends (options: OPTIONS) => _KnownAny, OPTIONS extends {
|
|
89
|
-
body: B;
|
|
90
|
-
[key: string]: _KnownAny;
|
|
91
|
-
} = Parameters<T>[0], B = _KnownAny> = Parameters<T>[0]['body'];
|
|
92
|
-
export type _VovkQuery<T extends (options: OPTIONS) => _KnownAny, OPTIONS extends {
|
|
93
|
-
query: Q;
|
|
94
|
-
[key: string]: _KnownAny;
|
|
95
|
-
} = Parameters<T>[0], Q = _KnownAny> = Parameters<T>[0]['query'];
|
|
96
|
-
export type _VovkParams<T extends (options: OPTIONS) => _KnownAny, OPTIONS extends {
|
|
97
|
-
params: P;
|
|
98
|
-
[key: string]: _KnownAny;
|
|
99
|
-
} = Parameters<T>[0], P = _KnownAny> = Parameters<T>[0]['params'];
|
|
100
|
-
export type _VovkControllerReturnType<T extends _ControllerStaticMethod<REQ, PARAMS>, REQ extends _VovkRequest<undefined, _KnownAny> = Parameters<T>[0], PARAMS extends {
|
|
101
|
-
[key: string]: string;
|
|
102
|
-
} = _KnownAny> = Awaited<ReturnType<T>>;
|
|
103
|
-
export type _VovkControlerYieldType<T extends _ControllerStaticMethod<REQ, PARAMS>, REQ extends _VovkRequest<undefined, _KnownAny> = Parameters<T>[0], PARAMS extends {
|
|
104
|
-
[key: string]: string;
|
|
105
|
-
} = _KnownAny> = T extends (...args: _KnownAny[]) => AsyncGenerator<infer Y, _KnownAny, _KnownAny> ? Y : T extends (...args: _KnownAny[]) => Generator<infer Y, _KnownAny, _KnownAny> ? Y : T extends (...args: _KnownAny[]) => Promise<StreamResponse<infer Y>> | StreamResponse<infer Y> ? Y : never;
|
|
106
|
-
export type _VovkReturnType<T extends (...args: _KnownAny) => unknown> = Awaited<ReturnType<T>>;
|
|
85
|
+
export type _VovkControllerBody<T extends (...args: _KnownAny) => _KnownAny> = Awaited<ReturnType<Parameters<T>[0]['vovk']['body']>>;
|
|
86
|
+
export type _VovkControllerQuery<T extends (...args: _KnownAny) => _KnownAny> = ReturnType<Parameters<T>[0]['vovk']['query']>;
|
|
87
|
+
export type _VovkControllerParams<T extends (...args: _KnownAny) => _KnownAny> = Parameters<T>[1];
|
|
88
|
+
export type _VovkControllerYieldType<T extends (req: _VovkRequest<_KnownAny, _KnownAny>) => _KnownAny> = T extends (...args: _KnownAny[]) => AsyncGenerator<infer Y, _KnownAny, _KnownAny> ? Y : T extends (...args: _KnownAny[]) => Generator<infer Y, _KnownAny, _KnownAny> ? Y : T extends (...args: _KnownAny[]) => Promise<StreamJSONResponse<infer Y>> | StreamJSONResponse<infer Y> ? Y : never;
|
|
89
|
+
export type _VovkBody<T extends (...args: _KnownAny[]) => unknown> = Parameters<T>[0]['body'];
|
|
90
|
+
export type _VovkQuery<T extends (...args: _KnownAny[]) => unknown> = Parameters<T>[0]['query'];
|
|
91
|
+
export type _VovkParams<T extends (...args: _KnownAny[]) => unknown> = Parameters<T>[0]['params'];
|
|
107
92
|
export type _VovkYieldType<T extends (...args: _KnownAny[]) => unknown> = T extends (...args: _KnownAny[]) => Promise<StreamAsyncIterator<infer Y>> ? Y : never;
|
|
93
|
+
export type _VovkReturnType<T extends (...args: _KnownAny) => unknown> = Awaited<ReturnType<T>>;
|
|
108
94
|
export type _StreamAbortMessage = {
|
|
109
95
|
isError: true;
|
|
110
96
|
reason: _KnownAny;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports._generateStaticAPI = _generateStaticAPI;
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
5
4
|
function _generateStaticAPI(c, slug = 'vovk') {
|
|
6
5
|
const controllers = c;
|
|
7
6
|
return [
|
|
8
|
-
{ [slug]: ['
|
|
7
|
+
{ [slug]: ['_schema_'] },
|
|
9
8
|
...Object.values(controllers)
|
|
10
9
|
.map((controller) => {
|
|
11
10
|
const handlers = controller._handlers;
|
package/utils/getSchema.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { _VovkSchema as VovkSchema } from '../types';
|
|
2
|
-
export default function (options: {
|
|
1
|
+
import { _VovkSchema as VovkSchema, _StaticClass as StaticClass } from '../types';
|
|
2
|
+
export default function getSchema(options: {
|
|
3
3
|
emitSchema?: boolean;
|
|
4
4
|
segmentName?: string;
|
|
5
|
-
controllers: Record<string,
|
|
6
|
-
workers?: Record<string,
|
|
5
|
+
controllers: Record<string, StaticClass>;
|
|
6
|
+
workers?: Record<string, StaticClass>;
|
|
7
7
|
exposeValidation?: boolean;
|
|
8
8
|
}): VovkSchema;
|
package/utils/getSchema.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default =
|
|
4
|
-
function
|
|
3
|
+
exports.default = getSchema;
|
|
4
|
+
function getSchema(options) {
|
|
5
5
|
const exposeValidation = options?.exposeValidation ?? true;
|
|
6
6
|
const emitSchema = options.emitSchema ?? true;
|
|
7
7
|
const schema = {
|
|
@@ -14,24 +14,24 @@ function default_1(options) {
|
|
|
14
14
|
return schema;
|
|
15
15
|
for (const [controllerName, controller] of Object.entries(options.controllers)) {
|
|
16
16
|
schema.controllers[controllerName] = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
controllerName: controllerName,
|
|
18
|
+
originalControllerName: controller.name,
|
|
19
|
+
prefix: controller._prefix ?? '',
|
|
20
|
+
handlers: {
|
|
21
21
|
...(exposeValidation
|
|
22
22
|
? controller._handlers
|
|
23
|
-
: Object.fromEntries(Object.entries(controller._handlers).map(([key, value]) => [
|
|
23
|
+
: Object.fromEntries(Object.entries(controller._handlers ?? {}).map(([key, value]) => [
|
|
24
24
|
key,
|
|
25
|
-
{ ...value,
|
|
25
|
+
{ ...value, validation: undefined },
|
|
26
26
|
]))),
|
|
27
27
|
},
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
for (const [workerName, worker] of Object.entries(options.workers ?? {})) {
|
|
31
31
|
schema.workers[workerName] = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
workerName,
|
|
33
|
+
originalWorkerName: worker.name,
|
|
34
|
+
handlers: { ...worker._handlers },
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
return schema;
|
package/utils/reqForm.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = reqForm;
|
|
4
|
+
const formMap = new WeakMap();
|
|
5
|
+
async function reqForm(req) {
|
|
6
|
+
if (formMap.has(req)) {
|
|
7
|
+
return formMap.get(req);
|
|
8
|
+
}
|
|
9
|
+
const body = await req.formData();
|
|
10
|
+
const formData = Object.fromEntries(body.entries());
|
|
11
|
+
formMap.set(req, formData);
|
|
12
|
+
return formData;
|
|
13
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _KnownAny as KnownAny } from '../types';
|
|
2
|
-
export default function setClientValidatorsForHandler(h: (...args: KnownAny[]) => KnownAny,
|
|
2
|
+
export default function setClientValidatorsForHandler(h: (...args: KnownAny[]) => KnownAny, validation: {
|
|
3
3
|
body: unknown;
|
|
4
4
|
query: unknown;
|
|
5
5
|
}): Promise<void>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = setClientValidatorsForHandler;
|
|
4
|
-
function setClientValidatorsForHandler(h,
|
|
4
|
+
function setClientValidatorsForHandler(h, validation) {
|
|
5
5
|
return new Promise((resolve) => {
|
|
6
6
|
setTimeout(() => {
|
|
7
7
|
const controller = h._controller;
|
|
@@ -16,10 +16,7 @@ function setClientValidatorsForHandler(h, validators) {
|
|
|
16
16
|
...controller._handlers,
|
|
17
17
|
[handlerName]: {
|
|
18
18
|
...controller._handlers[handlerName],
|
|
19
|
-
|
|
20
|
-
body: validators.body,
|
|
21
|
-
query: validators.query,
|
|
22
|
-
},
|
|
19
|
+
validation,
|
|
23
20
|
},
|
|
24
21
|
};
|
|
25
22
|
resolve();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { _WorkerPromiseInstance as WorkerPromiseInstance } from './types';
|
|
2
|
-
export declare function _promisifyWorker<T extends object>(currentWorker: Worker | null,
|
|
2
|
+
export declare function _promisifyWorker<T extends object>(currentWorker: Worker | null, workerSchema: object): WorkerPromiseInstance<T>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports._promisifyWorker = _promisifyWorker;
|
|
4
|
-
function _promisifyWorker(currentWorker,
|
|
5
|
-
if (!
|
|
4
|
+
function _promisifyWorker(currentWorker, workerSchema) {
|
|
5
|
+
if (!workerSchema)
|
|
6
6
|
throw new Error('Worker schema is not provided');
|
|
7
|
-
const
|
|
7
|
+
const schema = workerSchema;
|
|
8
8
|
const instance = {
|
|
9
9
|
worker: currentWorker,
|
|
10
10
|
};
|
|
@@ -23,15 +23,11 @@ function _promisifyWorker(currentWorker, givenWorkerService) {
|
|
|
23
23
|
instance.worker = worker;
|
|
24
24
|
return instance;
|
|
25
25
|
};
|
|
26
|
-
instance.fork = (worker) =>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
for (const method of Object.keys(workerService._handlers)) {
|
|
30
|
-
const { isGenerator } = workerService._handlers[method];
|
|
31
|
-
const value = workerService[method];
|
|
26
|
+
instance.fork = (worker) => _promisifyWorker(worker, schema);
|
|
27
|
+
for (const methodName of Object.keys(schema.handlers)) {
|
|
28
|
+
const { isGenerator } = schema.handlers[methodName];
|
|
32
29
|
if (isGenerator) {
|
|
33
|
-
|
|
34
|
-
instance[method] = (...args) => {
|
|
30
|
+
const method = (...args) => {
|
|
35
31
|
const key = callsKey;
|
|
36
32
|
callsKey += 1;
|
|
37
33
|
return {
|
|
@@ -43,8 +39,8 @@ function _promisifyWorker(currentWorker, givenWorkerService) {
|
|
|
43
39
|
const messageQueue = [];
|
|
44
40
|
let messageResolver = null;
|
|
45
41
|
const onMessage = (e) => {
|
|
46
|
-
const {
|
|
47
|
-
if (k !== key || m !==
|
|
42
|
+
const { methodName: m, key: k } = e.data;
|
|
43
|
+
if (k !== key || m !== methodName) {
|
|
48
44
|
return;
|
|
49
45
|
}
|
|
50
46
|
if (messageResolver) {
|
|
@@ -69,7 +65,7 @@ function _promisifyWorker(currentWorker, givenWorkerService) {
|
|
|
69
65
|
};
|
|
70
66
|
w.addEventListener('message', onMessage);
|
|
71
67
|
w.addEventListener('error', onError);
|
|
72
|
-
w.postMessage({ key, args,
|
|
68
|
+
w.postMessage({ key, args, methodName });
|
|
73
69
|
try {
|
|
74
70
|
while (true) {
|
|
75
71
|
let message = null;
|
|
@@ -101,10 +97,11 @@ function _promisifyWorker(currentWorker, givenWorkerService) {
|
|
|
101
97
|
},
|
|
102
98
|
};
|
|
103
99
|
};
|
|
100
|
+
// @ts-expect-error TODO
|
|
101
|
+
instance[methodName] = method;
|
|
104
102
|
}
|
|
105
103
|
else {
|
|
106
|
-
|
|
107
|
-
instance[method] = (...args) => {
|
|
104
|
+
const method = (...args) => {
|
|
108
105
|
if (!instance.worker) {
|
|
109
106
|
throw new Error('Worker is not provided or terminated');
|
|
110
107
|
}
|
|
@@ -118,8 +115,8 @@ function _promisifyWorker(currentWorker, givenWorkerService) {
|
|
|
118
115
|
reject(e);
|
|
119
116
|
};
|
|
120
117
|
const onMessage = (e) => {
|
|
121
|
-
const { result, error, key: k,
|
|
122
|
-
if (k !== key || m !==
|
|
118
|
+
const { result, error, key: k, methodName: m } = e.data;
|
|
119
|
+
if (k !== key || m !== methodName) {
|
|
123
120
|
return;
|
|
124
121
|
}
|
|
125
122
|
w.removeEventListener('message', onMessage);
|
|
@@ -133,9 +130,11 @@ function _promisifyWorker(currentWorker, givenWorkerService) {
|
|
|
133
130
|
};
|
|
134
131
|
w.addEventListener('message', onMessage);
|
|
135
132
|
w.addEventListener('error', onError);
|
|
136
|
-
w.postMessage({ key, args,
|
|
133
|
+
w.postMessage({ key, args, methodName });
|
|
137
134
|
});
|
|
138
135
|
};
|
|
136
|
+
// @ts-expect-error TODO
|
|
137
|
+
instance[methodName] = method;
|
|
139
138
|
}
|
|
140
139
|
}
|
|
141
140
|
return instance;
|
package/worker/types.d.ts
CHANGED
|
@@ -17,15 +17,15 @@ export type _WorkerPromiseInstance<T> = OmitNever<_WorkerPromiseInstanceWithNeve
|
|
|
17
17
|
[Symbol.dispose]: () => void;
|
|
18
18
|
};
|
|
19
19
|
export interface _WorkerInput {
|
|
20
|
-
|
|
20
|
+
methodName: string;
|
|
21
21
|
args: unknown[];
|
|
22
22
|
key: number;
|
|
23
23
|
}
|
|
24
24
|
export interface _WorkerOutput {
|
|
25
|
+
methodName: string;
|
|
25
26
|
result?: unknown;
|
|
26
27
|
error?: unknown;
|
|
27
28
|
done?: true;
|
|
28
29
|
key: number;
|
|
29
|
-
method: string;
|
|
30
30
|
}
|
|
31
31
|
export {};
|
package/worker/worker.js
CHANGED
|
@@ -5,7 +5,6 @@ function _worker() {
|
|
|
5
5
|
return (t) => {
|
|
6
6
|
const target = t;
|
|
7
7
|
target._handlers = {};
|
|
8
|
-
// TODO: Experimental: You can pass Worker Service instead of schema to prommisify worker
|
|
9
8
|
for (const key of Object.getOwnPropertyNames(target)) {
|
|
10
9
|
const member = target[key];
|
|
11
10
|
if (typeof member === 'function') {
|
|
@@ -20,25 +19,24 @@ function _worker() {
|
|
|
20
19
|
}
|
|
21
20
|
if (typeof self === 'undefined')
|
|
22
21
|
return; // no-op in non-worker environment
|
|
23
|
-
// eslint-disable-next-line no-undef
|
|
24
22
|
const w = self;
|
|
25
23
|
w.onmessage = async (evt) => {
|
|
26
|
-
const {
|
|
24
|
+
const { methodName, args, key } = evt.data;
|
|
27
25
|
try {
|
|
28
|
-
const result = await target[
|
|
26
|
+
const result = await target[methodName](...args);
|
|
29
27
|
if (result && typeof result === 'object' && 'next' in result && typeof result.next === 'function') {
|
|
30
28
|
const iterable = result;
|
|
31
29
|
for await (const result of iterable) {
|
|
32
|
-
w.postMessage({ result, key,
|
|
30
|
+
w.postMessage({ result, key, methodName });
|
|
33
31
|
}
|
|
34
|
-
w.postMessage({ done: true, key,
|
|
32
|
+
w.postMessage({ done: true, key, methodName });
|
|
35
33
|
}
|
|
36
34
|
else {
|
|
37
|
-
w.postMessage({ result, key,
|
|
35
|
+
w.postMessage({ result, key, methodName });
|
|
38
36
|
}
|
|
39
37
|
}
|
|
40
38
|
catch (e) {
|
|
41
|
-
w.postMessage({ error: e, key,
|
|
39
|
+
w.postMessage({ error: e, key, methodName });
|
|
42
40
|
}
|
|
43
41
|
};
|
|
44
42
|
};
|
package/generateStaticAPI.d.ts
DELETED