vovk 3.0.0-draft.48 → 3.0.0-draft.50
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/.DS_Store +0 -0
- package/.npmignore +2 -1
- package/.turbo/turbo-build.log +6 -0
- package/.turbo/turbo-ncu.log +9 -0
- package/.turbo/turbo-tsc.log +6 -0
- package/README.md +1 -112
- package/{StreamJSONResponse.d.ts → dist/StreamJSONResponse.d.ts} +1 -1
- package/dist/client/createRPC.d.ts +4 -0
- package/{client/clientizeController.js → dist/client/createRPC.js} +3 -3
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +5 -0
- package/{index.d.ts → dist/index.d.ts} +5 -4
- package/{index.js → dist/index.js} +6 -1
- package/{utils → dist/utils}/generateStaticAPI.d.ts +1 -1
- package/{utils → dist/utils}/getSchema.d.ts +1 -1
- package/{utils → dist/utils}/reqForm.d.ts +1 -2
- package/{utils → dist/utils}/reqMeta.d.ts +1 -2
- package/{utils → dist/utils}/reqQuery.d.ts +1 -2
- package/{utils → dist/utils}/reqQuery.js +3 -3
- package/dist/utils/setClientValidatorsForHandler.d.ts +5 -0
- package/{utils → dist/utils}/setClientValidatorsForHandler.js +2 -1
- package/dist/worker/createWPC.d.ts +2 -0
- package/{worker/promisifyWorker.js → dist/worker/createWPC.js} +3 -3
- package/dist/worker/index.d.ts +3 -0
- package/dist/worker/index.js +7 -0
- package/package.json +4 -2
- package/src/HttpException.ts +16 -0
- package/src/StreamJSONResponse.ts +62 -0
- package/src/VovkApp.ts +242 -0
- package/src/client/createRPC.ts +133 -0
- package/src/client/defaultFetcher.ts +57 -0
- package/src/client/defaultHandler.ts +23 -0
- package/src/client/defaultStreamHandler.ts +88 -0
- package/src/client/index.ts +5 -0
- package/src/client/types.ts +115 -0
- package/src/createDecorator.ts +60 -0
- package/src/createVovkApp.ts +167 -0
- package/src/index.ts +66 -0
- package/src/types.ts +215 -0
- package/src/utils/generateStaticAPI.ts +18 -0
- package/src/utils/getSchema.ts +48 -0
- package/src/utils/reqForm.ts +16 -0
- package/src/utils/reqMeta.ts +16 -0
- package/src/utils/reqQuery.ts +26 -0
- package/src/utils/setClientValidatorsForHandler.ts +45 -0
- package/src/utils/shim.ts +17 -0
- package/src/worker/createWPC.ts +156 -0
- package/src/worker/index.ts +4 -0
- package/src/worker/types.ts +45 -0
- package/src/worker/worker.ts +53 -0
- package/client/clientizeController.d.ts +0 -4
- package/client/index.d.ts +0 -4
- package/client/index.js +0 -5
- package/utils/setClientValidatorsForHandler.d.ts +0 -5
- package/worker/index.d.ts +0 -3
- package/worker/index.js +0 -7
- package/worker/promisifyWorker.d.ts +0 -2
- /package/{HttpException.d.ts → dist/HttpException.d.ts} +0 -0
- /package/{HttpException.js → dist/HttpException.js} +0 -0
- /package/{StreamJSONResponse.js → dist/StreamJSONResponse.js} +0 -0
- /package/{VovkApp.d.ts → dist/VovkApp.d.ts} +0 -0
- /package/{VovkApp.js → dist/VovkApp.js} +0 -0
- /package/{client → dist/client}/defaultFetcher.d.ts +0 -0
- /package/{client → dist/client}/defaultFetcher.js +0 -0
- /package/{client → dist/client}/defaultHandler.d.ts +0 -0
- /package/{client → dist/client}/defaultHandler.js +0 -0
- /package/{client → dist/client}/defaultStreamHandler.d.ts +0 -0
- /package/{client → dist/client}/defaultStreamHandler.js +0 -0
- /package/{client → dist/client}/types.d.ts +0 -0
- /package/{client → dist/client}/types.js +0 -0
- /package/{createDecorator.d.ts → dist/createDecorator.d.ts} +0 -0
- /package/{createDecorator.js → dist/createDecorator.js} +0 -0
- /package/{createVovkApp.d.ts → dist/createVovkApp.d.ts} +0 -0
- /package/{createVovkApp.js → dist/createVovkApp.js} +0 -0
- /package/{types.d.ts → dist/types.d.ts} +0 -0
- /package/{types.js → dist/types.js} +0 -0
- /package/{utils → dist/utils}/generateStaticAPI.js +0 -0
- /package/{utils → dist/utils}/getSchema.js +0 -0
- /package/{utils → dist/utils}/reqForm.js +0 -0
- /package/{utils → dist/utils}/reqMeta.js +0 -0
- /package/{utils → dist/utils}/shim.d.ts +0 -0
- /package/{utils → dist/utils}/shim.js +0 -0
- /package/{worker → dist/worker}/types.d.ts +0 -0
- /package/{worker → dist/worker}/types.js +0 -0
- /package/{worker → dist/worker}/worker.d.ts +0 -0
- /package/{worker → dist/worker}/worker.js +0 -0
package/.DS_Store
ADDED
|
Binary file
|
package/.npmignore
CHANGED
package/README.md
CHANGED
|
@@ -1,112 +1 @@
|
|
|
1
|
-
|
|
2
|
-
<picture>
|
|
3
|
-
<source width="300" media="(prefers-color-scheme: dark)" srcset="https://vovk.dev/vovk-logo-white.svg">
|
|
4
|
-
<source width="300" media="(prefers-color-scheme: light)" srcset="https://vovk.dev/vovk-logo.svg">
|
|
5
|
-
<img width="300" alt="vovk" src="https://vovk.dev/vovk-logo.svg">
|
|
6
|
-
</picture><br>
|
|
7
|
-
<strong>RESTful RPC for Next.js</strong>
|
|
8
|
-
|
|
9
|
-
</p>
|
|
10
|
-
|
|
11
|
-
<p align="center">
|
|
12
|
-
Transforms <a href="https://nextjs.org/docs/app">Next.js</a> into a powerful REST API platform with RPC capabilities.
|
|
13
|
-
<br><br>
|
|
14
|
-
ℹ️ Improved syntax for Zod and DTO validation is coming soon. Stay tuned!
|
|
15
|
-
</p>
|
|
16
|
-
|
|
17
|
-
<p align="center">
|
|
18
|
-
<a href="https://vovk.dev/">Documentation</a>
|
|
19
|
-
<a href="https://discord.gg/qdT8WEHUuP">Discord</a>
|
|
20
|
-
<a href="https://github.com/finom/vovk-examples">Code Examples</a>
|
|
21
|
-
<a href="https://github.com/finom/vovk-zod">vovk-zod</a>
|
|
22
|
-
<a href="https://github.com/finom/vovk-hello-world">vovk-hello-world</a>
|
|
23
|
-
<a href="https://github.com/finom/vovk-react-native-example">vovk-react-native-example</a>
|
|
24
|
-
</p>
|
|
25
|
-
<p align="center">
|
|
26
|
-
<a href="https://www.npmjs.com/package/vovk"><img src="https://badge.fury.io/js/vovk.svg" alt="npm version" /></a>
|
|
27
|
-
<a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg" alt="TypeScript" /></a>
|
|
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
|
-
</p>
|
|
30
|
-
|
|
31
|
-
<br />
|
|
32
|
-
|
|
33
|
-
Example back-end Controller Class:
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
// /src/modules/post/PostController.ts
|
|
37
|
-
import { get, prefix, type VovkRequest } from 'vovk';
|
|
38
|
-
import PostService from './PostService';
|
|
39
|
-
|
|
40
|
-
@prefix('posts')
|
|
41
|
-
export default class PostController {
|
|
42
|
-
/**
|
|
43
|
-
* Create a comment on a post
|
|
44
|
-
* POST /api/posts/:postId/comments
|
|
45
|
-
*/
|
|
46
|
-
@post(':postId/comments')
|
|
47
|
-
static async createComment(
|
|
48
|
-
// decorate NextRequest type with body and query types
|
|
49
|
-
req: VovkRequest<{ content: string; userId: string }, { notificationType: 'push' | 'email' }>,
|
|
50
|
-
{ postId }: { postId: string } // params
|
|
51
|
-
) {
|
|
52
|
-
// use standard Next.js API to get body and query
|
|
53
|
-
const { content, userId } = await req.json();
|
|
54
|
-
const notificationType = req.nextUrl.searchParams.get('notificationType');
|
|
55
|
-
|
|
56
|
-
// perform the request to the database in a custom service
|
|
57
|
-
return PostService.createComment({
|
|
58
|
-
postId,
|
|
59
|
-
content,
|
|
60
|
-
userId,
|
|
61
|
-
notificationType,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Example component that uses the auto-generated client library:
|
|
68
|
-
|
|
69
|
-
```tsx
|
|
70
|
-
'use client';
|
|
71
|
-
import { useState } from 'react';
|
|
72
|
-
import { PostController } from 'vovk-client';
|
|
73
|
-
import type { VovkReturnType } from 'vovk';
|
|
74
|
-
|
|
75
|
-
export default function Example() {
|
|
76
|
-
const [response, setResponse] = useState<VovkReturnType<typeof PostController.createComment>>();
|
|
77
|
-
|
|
78
|
-
return (
|
|
79
|
-
<>
|
|
80
|
-
<button
|
|
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
|
-
}
|
|
93
|
-
>
|
|
94
|
-
Post a comment
|
|
95
|
-
</button>
|
|
96
|
-
<div>{JSON.stringify(response)}</div>
|
|
97
|
-
</>
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Alternatively, the resource can be fetched wit the regular `fetch` function:
|
|
103
|
-
|
|
104
|
-
```ts
|
|
105
|
-
fetch('/api/posts/69?notificationType=push', {
|
|
106
|
-
method: 'POST',
|
|
107
|
-
body: JSON.stringify({
|
|
108
|
-
content: 'Hello, World!',
|
|
109
|
-
userId: '1',
|
|
110
|
-
}),
|
|
111
|
-
});
|
|
112
|
-
```
|
|
1
|
+
Description is coming soon.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type VovkControllerSchema, type KnownAny } from '../types';
|
|
2
|
+
import { type VovkClientOptions, type VovkClient, type VovkDefaultFetcherOptions } from './types';
|
|
3
|
+
export declare const ARRAY_QUERY_KEY = "_vovkarr";
|
|
4
|
+
export declare const createRPC: <T, OPTS extends Record<string, KnownAny> = VovkDefaultFetcherOptions>(controllerSchema: VovkControllerSchema, segmentName?: string, options?: VovkClientOptions<OPTS>) => VovkClient<T, OPTS>;
|
|
@@ -3,7 +3,7 @@ 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.
|
|
6
|
+
exports.createRPC = exports.ARRAY_QUERY_KEY = void 0;
|
|
7
7
|
const defaultFetcher_1 = __importDefault(require("./defaultFetcher"));
|
|
8
8
|
const defaultHandler_1 = require("./defaultHandler");
|
|
9
9
|
const defaultStreamHandler_1 = require("./defaultStreamHandler");
|
|
@@ -37,7 +37,7 @@ const getHandlerPath = (endpoint, params, query) => {
|
|
|
37
37
|
}
|
|
38
38
|
return `${result}${hasQuery ? '?' : ''}${searchParams.toString()}`;
|
|
39
39
|
};
|
|
40
|
-
const
|
|
40
|
+
const createRPC = (controllerSchema, segmentName, options) => {
|
|
41
41
|
const schema = controllerSchema;
|
|
42
42
|
const client = {};
|
|
43
43
|
if (!schema)
|
|
@@ -90,4 +90,4 @@ const clientizeController = (controllerSchema, segmentName, options) => {
|
|
|
90
90
|
}
|
|
91
91
|
return client;
|
|
92
92
|
};
|
|
93
|
-
exports.
|
|
93
|
+
exports.createRPC = createRPC;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { createRPC } from './createRPC';
|
|
2
|
+
import type { VovkClientFetcher, VovkClientOptions, VovkDefaultFetcherOptions, VovkValidateOnClient } from './types';
|
|
3
|
+
export { createRPC };
|
|
4
|
+
export type { VovkClientFetcher, VovkClientOptions, VovkDefaultFetcherOptions, VovkValidateOnClient };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRPC = void 0;
|
|
4
|
+
const createRPC_1 = require("./createRPC");
|
|
5
|
+
Object.defineProperty(exports, "createRPC", { enumerable: true, get: function () { return createRPC_1.createRPC; } });
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { createVovkApp } from './createVovkApp';
|
|
2
|
-
import { HttpStatus as HttpStatus, HttpMethod as HttpMethod, type VovkErrorResponse, type VovkRequest, type VovkBody, type VovkQuery, type VovkParams, type VovkReturnType, type VovkYieldType, type VovkControllerBody, type VovkControllerQuery, type VovkControllerParams, type VovkControllerYieldType, type VovkSchema } from './types';
|
|
3
|
-
import
|
|
2
|
+
import { HttpStatus as HttpStatus, HttpMethod as HttpMethod, type VovkErrorResponse, type VovkRequest, type VovkBody, type VovkQuery, type VovkParams, type VovkReturnType, type VovkYieldType, type VovkControllerBody, type VovkControllerQuery, type VovkControllerParams, type VovkControllerYieldType, type VovkSchema, type VovkWorkerSchema, type VovkControllerSchema } from './types';
|
|
3
|
+
import { type VovkClientOptions, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkValidateOnClient, createRPC } from './client';
|
|
4
4
|
import { HttpException } from './HttpException';
|
|
5
5
|
import { createDecorator } from './createDecorator';
|
|
6
6
|
import { StreamJSONResponse } from './StreamJSONResponse';
|
|
7
|
-
import { worker } from './worker';
|
|
7
|
+
import { worker, createWPC } from './worker';
|
|
8
8
|
import { generateStaticAPI } from './utils/generateStaticAPI';
|
|
9
|
-
|
|
9
|
+
import { setClientValidatorsForHandler } from './utils/setClientValidatorsForHandler';
|
|
10
|
+
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, type VovkWorkerSchema, type VovkControllerSchema, StreamJSONResponse, HttpException, HttpStatus, HttpMethod, createVovkApp, createDecorator, worker, createWPC, createRPC, generateStaticAPI, setClientValidatorsForHandler, };
|
|
10
11
|
export declare const get: {
|
|
11
12
|
(givenPath?: string | undefined, options?: import("./types").DecoratorOptions | undefined): ReturnType<(givenPath?: string, options?: import("./types").DecoratorOptions) => (givenTarget: import("./types").KnownAny, propertyKey: string) => void>;
|
|
12
13
|
auto: (options?: import("./types").DecoratorOptions) => (givenTarget: import("./types").KnownAny, propertyKey: string) => void;
|
|
@@ -1,12 +1,14 @@
|
|
|
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.createVovkApp = exports.HttpMethod = exports.HttpStatus = exports.HttpException = exports.StreamJSONResponse = void 0;
|
|
4
|
+
exports.initVovk = exports.prefix = exports.options = exports.head = exports.del = exports.patch = exports.put = exports.post = exports.get = exports.setClientValidatorsForHandler = exports.generateStaticAPI = exports.createRPC = exports.createWPC = exports.worker = exports.createDecorator = exports.createVovkApp = exports.HttpMethod = exports.HttpStatus = exports.HttpException = exports.StreamJSONResponse = void 0;
|
|
5
5
|
const createVovkApp_1 = require("./createVovkApp");
|
|
6
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; } });
|
|
10
|
+
const client_1 = require("./client");
|
|
11
|
+
Object.defineProperty(exports, "createRPC", { enumerable: true, get: function () { return client_1.createRPC; } });
|
|
10
12
|
const HttpException_1 = require("./HttpException");
|
|
11
13
|
Object.defineProperty(exports, "HttpException", { enumerable: true, get: function () { return HttpException_1.HttpException; } });
|
|
12
14
|
const createDecorator_1 = require("./createDecorator");
|
|
@@ -15,6 +17,9 @@ const StreamJSONResponse_1 = require("./StreamJSONResponse");
|
|
|
15
17
|
Object.defineProperty(exports, "StreamJSONResponse", { enumerable: true, get: function () { return StreamJSONResponse_1.StreamJSONResponse; } });
|
|
16
18
|
const worker_1 = require("./worker");
|
|
17
19
|
Object.defineProperty(exports, "worker", { enumerable: true, get: function () { return worker_1.worker; } });
|
|
20
|
+
Object.defineProperty(exports, "createWPC", { enumerable: true, get: function () { return worker_1.createWPC; } });
|
|
18
21
|
const generateStaticAPI_1 = require("./utils/generateStaticAPI");
|
|
19
22
|
Object.defineProperty(exports, "generateStaticAPI", { enumerable: true, get: function () { return generateStaticAPI_1.generateStaticAPI; } });
|
|
23
|
+
const setClientValidatorsForHandler_1 = require("./utils/setClientValidatorsForHandler");
|
|
24
|
+
Object.defineProperty(exports, "setClientValidatorsForHandler", { enumerable: true, get: function () { return setClientValidatorsForHandler_1.setClientValidatorsForHandler; } });
|
|
20
25
|
_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;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = reqQuery;
|
|
4
|
-
const
|
|
4
|
+
const createRPC_1 = require("../client/createRPC");
|
|
5
5
|
function reqQuery(req) {
|
|
6
|
-
const queryArr = req.nextUrl.searchParams.get(
|
|
6
|
+
const queryArr = req.nextUrl.searchParams.get(createRPC_1.ARRAY_QUERY_KEY)?.split(',') ?? null;
|
|
7
7
|
const entries = [...req.nextUrl.searchParams.entries()];
|
|
8
8
|
const query = entries.reduce((acc, [key, value]) => {
|
|
9
|
-
if (key ===
|
|
9
|
+
if (key === createRPC_1.ARRAY_QUERY_KEY)
|
|
10
10
|
return acc;
|
|
11
11
|
if (queryArr?.includes(key)) {
|
|
12
12
|
if (!(key in acc)) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.setClientValidatorsForHandler = setClientValidatorsForHandler;
|
|
4
4
|
function setClientValidatorsForHandler(h, validation) {
|
|
5
5
|
return new Promise((resolve) => {
|
|
6
|
+
// the setTimeout is necessary to ensure that the _controller is already defined
|
|
6
7
|
setTimeout(() => {
|
|
7
8
|
const controller = h._controller;
|
|
8
9
|
if (!controller) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
function
|
|
3
|
+
exports.createWPC = createWPC;
|
|
4
|
+
function createWPC(currentWorker, workerSchema) {
|
|
5
5
|
if (!workerSchema)
|
|
6
6
|
throw new Error('Worker schema is not provided');
|
|
7
7
|
const schema = workerSchema;
|
|
@@ -23,7 +23,7 @@ function promisifyWorker(currentWorker, workerSchema) {
|
|
|
23
23
|
instance.worker = worker;
|
|
24
24
|
return instance;
|
|
25
25
|
};
|
|
26
|
-
instance.fork = (worker) =>
|
|
26
|
+
instance.fork = (worker) => createWPC(worker, schema);
|
|
27
27
|
for (const methodName of Object.keys(schema.handlers)) {
|
|
28
28
|
const { isGenerator } = schema.handlers[methodName];
|
|
29
29
|
if (isGenerator) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWPC = exports.worker = void 0;
|
|
4
|
+
const worker_1 = require("./worker");
|
|
5
|
+
Object.defineProperty(exports, "worker", { enumerable: true, get: function () { return worker_1.worker; } });
|
|
6
|
+
const createWPC_1 = require("./createWPC");
|
|
7
|
+
Object.defineProperty(exports, "createWPC", { enumerable: true, get: function () { return createWPC_1.createWPC; } });
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vovk",
|
|
3
|
-
"version": "3.0.0-draft.
|
|
3
|
+
"version": "3.0.0-draft.50",
|
|
4
|
+
"main": "dist/index.js",
|
|
4
5
|
"description": "RESTful RPC for Next.js - Transforms Next.js into a powerful REST API platform with RPC capabilities.",
|
|
5
6
|
"repository": {
|
|
6
7
|
"type": "git",
|
|
7
8
|
"url": "git+https://github.com/finom/vovk.git"
|
|
8
9
|
},
|
|
9
10
|
"scripts": {
|
|
10
|
-
"build": "
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"rm-dist": "shx rm -rf dist",
|
|
11
13
|
"lint": "eslint . --fix",
|
|
12
14
|
"tsc": "tsc --noEmit",
|
|
13
15
|
"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 ..",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HttpStatus } from './types';
|
|
2
|
+
|
|
3
|
+
export class HttpException extends Error {
|
|
4
|
+
statusCode: HttpStatus;
|
|
5
|
+
|
|
6
|
+
message: string;
|
|
7
|
+
|
|
8
|
+
cause?: unknown;
|
|
9
|
+
|
|
10
|
+
constructor(statusCode: HttpStatus, message: string, cause?: unknown) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.statusCode = statusCode;
|
|
13
|
+
this.message = message;
|
|
14
|
+
this.cause = cause;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { KnownAny, StreamAbortMessage } from './types';
|
|
2
|
+
import './utils/shim';
|
|
3
|
+
|
|
4
|
+
export class StreamJSONResponse<T> extends Response {
|
|
5
|
+
public static defaultHeaders = {
|
|
6
|
+
'content-type': 'text/plain; charset=utf-8',
|
|
7
|
+
'x-vovk-stream': 'true',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
public isClosed = false;
|
|
11
|
+
|
|
12
|
+
public controller?: ReadableStreamDefaultController;
|
|
13
|
+
|
|
14
|
+
public readonly encoder: TextEncoder;
|
|
15
|
+
|
|
16
|
+
public readonly readableStream: ReadableStream;
|
|
17
|
+
|
|
18
|
+
constructor(init?: ResponseInit) {
|
|
19
|
+
const encoder = new TextEncoder();
|
|
20
|
+
let readableController: ReadableStreamDefaultController;
|
|
21
|
+
|
|
22
|
+
const readableStream = new ReadableStream({
|
|
23
|
+
cancel: () => {
|
|
24
|
+
this.isClosed = true;
|
|
25
|
+
},
|
|
26
|
+
start: (controller) => {
|
|
27
|
+
readableController = controller;
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
super(readableStream, {
|
|
32
|
+
...init,
|
|
33
|
+
headers: init?.headers ?? StreamJSONResponse.defaultHeaders,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
this.readableStream = readableStream;
|
|
37
|
+
this.encoder = encoder;
|
|
38
|
+
this.controller = readableController!;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public send(data: T | StreamAbortMessage) {
|
|
42
|
+
const { controller, encoder } = this;
|
|
43
|
+
if (this.isClosed) return;
|
|
44
|
+
return controller?.enqueue(encoder.encode(JSON.stringify(data) + '\n'));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public close() {
|
|
48
|
+
const { controller } = this;
|
|
49
|
+
if (this.isClosed) return;
|
|
50
|
+
this.isClosed = true;
|
|
51
|
+
controller?.close();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public throw(e: KnownAny) {
|
|
55
|
+
this.send({ isError: true, reason: e instanceof Error ? e.message : (e as unknown) });
|
|
56
|
+
return this.close();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public [Symbol.dispose]() {
|
|
60
|
+
this.close();
|
|
61
|
+
}
|
|
62
|
+
}
|