vovk 3.0.0-draft.41 → 3.0.0-draft.411
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/cjs/JSONLinesResponse.d.ts +19 -0
- package/cjs/JSONLinesResponse.js +93 -0
- package/{VovkApp.d.ts → cjs/VovkApp.d.ts} +9 -8
- package/{VovkApp.js → cjs/VovkApp.js} +89 -66
- package/cjs/client/createRPC.d.ts +5 -0
- package/cjs/client/createRPC.js +108 -0
- package/cjs/client/defaultHandler.d.ts +6 -0
- package/{client → cjs/client}/defaultHandler.js +9 -2
- package/cjs/client/defaultStreamHandler.d.ts +9 -0
- package/{client → cjs/client}/defaultStreamHandler.js +45 -13
- package/cjs/client/fetcher.d.ts +19 -0
- package/cjs/client/fetcher.js +98 -0
- package/cjs/client/index.d.ts +4 -0
- package/cjs/client/index.js +10 -0
- package/cjs/client/progressive.d.ts +9 -0
- package/cjs/client/progressive.js +54 -0
- package/cjs/client/types.d.ts +119 -0
- package/{createVovkApp.d.ts → cjs/createVovkApp.d.ts} +17 -16
- package/cjs/createVovkApp.js +140 -0
- package/cjs/index.d.ts +67 -0
- package/cjs/index.js +42 -0
- package/cjs/openapi/error.d.ts +2 -0
- package/cjs/openapi/error.js +100 -0
- package/cjs/openapi/index.d.ts +8 -0
- package/cjs/openapi/index.js +21 -0
- package/cjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.d.ts +3 -0
- package/cjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.js +67 -0
- package/cjs/openapi/openAPIToVovkSchema/index.d.ts +4 -0
- package/cjs/openapi/openAPIToVovkSchema/index.js +138 -0
- package/cjs/openapi/openAPIToVovkSchema/inlineRefs.d.ts +10 -0
- package/cjs/openapi/openAPIToVovkSchema/inlineRefs.js +102 -0
- package/cjs/openapi/vovkSchemaToOpenAPI.d.ts +8 -0
- package/cjs/openapi/vovkSchemaToOpenAPI.js +237 -0
- package/cjs/types.d.ts +436 -0
- package/{types.js → cjs/types.js} +13 -4
- package/cjs/utils/camelCase.d.ts +6 -0
- package/cjs/utils/camelCase.js +37 -0
- package/cjs/utils/createCodeExamples.d.ts +20 -0
- package/cjs/utils/createCodeExamples.js +309 -0
- package/cjs/utils/createDecorator.d.ts +6 -0
- package/{createDecorator.js → cjs/utils/createDecorator.js} +24 -14
- package/cjs/utils/createLLMTools.d.ts +48 -0
- package/cjs/utils/createLLMTools.js +165 -0
- package/cjs/utils/createStandardValidation.d.ts +82 -0
- package/cjs/utils/createStandardValidation.js +34 -0
- package/cjs/utils/createValidateOnClient.d.ts +7 -0
- package/cjs/utils/createValidateOnClient.js +19 -0
- package/cjs/utils/deepExtend.d.ts +54 -0
- package/cjs/utils/deepExtend.js +134 -0
- package/{utils → cjs/utils}/generateStaticAPI.d.ts +2 -2
- package/cjs/utils/generateStaticAPI.js +30 -0
- package/cjs/utils/getGeneratorConfig.d.ts +18 -0
- package/cjs/utils/getGeneratorConfig.js +57 -0
- package/cjs/utils/getJSONSchemaExample.d.ts +11 -0
- package/cjs/utils/getJSONSchemaExample.js +265 -0
- package/cjs/utils/getJSONSchemaSample.d.ts +2 -0
- package/cjs/utils/getJSONSchemaSample.js +167 -0
- package/cjs/utils/getSampleFromObject.d.ts +9 -0
- package/cjs/utils/getSampleFromObject.js +41 -0
- package/cjs/utils/getSchema.d.ts +21 -0
- package/cjs/utils/getSchema.js +38 -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/{utils → cjs/utils}/reqForm.d.ts +1 -2
- 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/upperFirst.d.ts +1 -0
- package/cjs/utils/upperFirst.js +6 -0
- package/cjs/utils/withValidationLibrary.d.ts +77 -0
- package/cjs/utils/withValidationLibrary.js +124 -0
- package/mjs/HttpException.d.ts +7 -0
- package/mjs/HttpException.js +15 -0
- package/mjs/JSONLinesResponse.d.ts +19 -0
- package/mjs/JSONLinesResponse.js +93 -0
- package/mjs/VovkApp.d.ts +29 -0
- package/mjs/VovkApp.js +208 -0
- package/mjs/client/createRPC.d.ts +5 -0
- package/mjs/client/createRPC.js +108 -0
- package/mjs/client/defaultHandler.d.ts +6 -0
- package/mjs/client/defaultHandler.js +29 -0
- package/mjs/client/defaultStreamHandler.d.ts +9 -0
- package/mjs/client/defaultStreamHandler.js +114 -0
- package/mjs/client/fetcher.d.ts +19 -0
- package/mjs/client/fetcher.js +98 -0
- package/mjs/client/index.d.ts +4 -0
- package/mjs/client/index.js +10 -0
- package/mjs/client/progressive.d.ts +9 -0
- package/mjs/client/progressive.js +54 -0
- package/mjs/client/types.d.ts +119 -0
- package/mjs/createVovkApp.d.ts +63 -0
- package/mjs/createVovkApp.js +140 -0
- package/mjs/index.d.ts +67 -0
- package/mjs/index.js +42 -0
- package/mjs/openapi/error.d.ts +2 -0
- package/mjs/openapi/error.js +100 -0
- package/mjs/openapi/index.d.ts +8 -0
- package/mjs/openapi/index.js +21 -0
- package/mjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.d.ts +3 -0
- package/mjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.js +67 -0
- package/mjs/openapi/openAPIToVovkSchema/index.d.ts +4 -0
- package/mjs/openapi/openAPIToVovkSchema/index.js +138 -0
- package/mjs/openapi/openAPIToVovkSchema/inlineRefs.d.ts +10 -0
- package/mjs/openapi/openAPIToVovkSchema/inlineRefs.js +102 -0
- package/mjs/openapi/vovkSchemaToOpenAPI.d.ts +8 -0
- package/mjs/openapi/vovkSchemaToOpenAPI.js +237 -0
- package/mjs/types.d.ts +436 -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 +20 -0
- package/mjs/utils/createCodeExamples.js +309 -0
- package/mjs/utils/createDecorator.d.ts +6 -0
- package/mjs/utils/createDecorator.js +48 -0
- package/mjs/utils/createLLMTools.d.ts +48 -0
- package/mjs/utils/createLLMTools.js +165 -0
- package/mjs/utils/createStandardValidation.d.ts +82 -0
- package/mjs/utils/createStandardValidation.js +34 -0
- package/mjs/utils/createValidateOnClient.d.ts +7 -0
- package/mjs/utils/createValidateOnClient.js +19 -0
- package/mjs/utils/deepExtend.d.ts +54 -0
- package/mjs/utils/deepExtend.js +134 -0
- package/mjs/utils/generateStaticAPI.d.ts +4 -0
- package/mjs/utils/generateStaticAPI.js +30 -0
- package/mjs/utils/getGeneratorConfig.d.ts +18 -0
- package/mjs/utils/getGeneratorConfig.js +57 -0
- package/mjs/utils/getJSONSchemaExample.d.ts +11 -0
- package/mjs/utils/getJSONSchemaExample.js +265 -0
- package/mjs/utils/getJSONSchemaSample.d.ts +2 -0
- package/mjs/utils/getJSONSchemaSample.js +167 -0
- package/mjs/utils/getSampleFromObject.d.ts +9 -0
- package/mjs/utils/getSampleFromObject.js +41 -0
- package/mjs/utils/getSchema.d.ts +21 -0
- package/mjs/utils/getSchema.js +38 -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/upperFirst.d.ts +1 -0
- package/mjs/utils/upperFirst.js +6 -0
- package/mjs/utils/withValidationLibrary.d.ts +77 -0
- package/mjs/utils/withValidationLibrary.js +124 -0
- package/package.json +28 -6
- package/.npmignore +0 -2
- package/StreamJSONResponse.d.ts +0 -17
- package/StreamJSONResponse.js +0 -54
- package/client/clientizeController.d.ts +0 -4
- package/client/clientizeController.js +0 -93
- package/client/defaultFetcher.d.ts +0 -4
- package/client/defaultFetcher.js +0 -49
- package/client/defaultHandler.d.ts +0 -2
- 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 -108
- package/createDecorator.d.ts +0 -4
- package/createVovkApp.js +0 -118
- package/index.d.ts +0 -60
- package/index.js +0 -20
- package/types.d.ts +0 -157
- package/utils/generateStaticAPI.js +0 -18
- package/utils/getSchema.d.ts +0 -8
- package/utils/getSchema.js +0 -38
- package/utils/reqForm.js +0 -13
- 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 -25
- 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/{HttpException.d.ts → cjs/HttpException.d.ts} +0 -0
- /package/{HttpException.js → cjs/HttpException.js} +0 -0
- /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/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -4,109 +4,21 @@
|
|
|
4
4
|
<source width="300" media="(prefers-color-scheme: light)" srcset="https://vovk.dev/vovk-logo.svg">
|
|
5
5
|
<img width="300" alt="vovk" src="https://vovk.dev/vovk-logo.svg">
|
|
6
6
|
</picture><br>
|
|
7
|
-
<strong>RESTful RPC
|
|
8
|
-
|
|
7
|
+
<strong>RESTful + RPC = ♥️</strong>
|
|
9
8
|
</p>
|
|
10
9
|
|
|
11
10
|
<p align="center">
|
|
12
|
-
|
|
13
|
-
<br><br>
|
|
14
|
-
ℹ️ Improved syntax for Zod and DTO validation is coming soon. Stay tuned!
|
|
11
|
+
Back-end meta-framework for <a href="https://nextjs.org/docs/app">Next.js</a>
|
|
15
12
|
</p>
|
|
16
13
|
|
|
17
|
-
|
|
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>
|
|
14
|
+
---
|
|
30
15
|
|
|
31
|
-
|
|
16
|
+
## vovk [](https://www.npmjs.com/package/vovk)
|
|
32
17
|
|
|
33
|
-
|
|
18
|
+
The main library with [zero dependencies](https://bundlephobia.com/result?p=vovk) that's going to be used in production. It provides a wrapper for Next.js API routes, internal RPC API, utilities and types.
|
|
34
19
|
|
|
35
|
-
```
|
|
36
|
-
|
|
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
|
-
}
|
|
20
|
+
```sh
|
|
21
|
+
npm install vovk
|
|
65
22
|
```
|
|
66
23
|
|
|
67
|
-
|
|
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
|
-
```
|
|
24
|
+
For more information, please visit the [getting started guide](https://vovk.dev/getting-started) or check out the [Vovk.ts examples](https://vovk-examples.vercel.app/).
|
package/bin/index.mjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
|
|
4
|
+
console.warn(`Vovk CLI requires vovk-cli package. Running "npx vovk-cli ${process.argv.slice(2).join(' ')}" instead.`);
|
|
5
|
+
|
|
6
|
+
spawn('npx', ['vovk-cli', ...process.argv.slice(2)], { stdio: 'inherit' }).on('exit', (code) => {
|
|
7
|
+
process.exit(code);
|
|
8
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { KnownAny, StreamAbortMessage } from './types';
|
|
2
|
+
import './utils/shim';
|
|
3
|
+
export declare class JSONLinesResponse<T> extends Response {
|
|
4
|
+
isClosed: boolean;
|
|
5
|
+
controller?: ReadableStreamDefaultController | null;
|
|
6
|
+
readonly encoder: TextEncoder | null;
|
|
7
|
+
readonly readableStream: ReadableStream | null;
|
|
8
|
+
private iteratorQueue;
|
|
9
|
+
private iteratorResolvers;
|
|
10
|
+
constructor(request?: Request, init?: ResponseInit);
|
|
11
|
+
send: (data: T | StreamAbortMessage) => void;
|
|
12
|
+
close: () => void;
|
|
13
|
+
throw: (e: KnownAny) => void;
|
|
14
|
+
[Symbol.dispose]: () => void;
|
|
15
|
+
[Symbol.asyncDispose]: () => void;
|
|
16
|
+
[Symbol.asyncIterator]: () => {
|
|
17
|
+
next: () => Promise<IteratorResult<T | StreamAbortMessage>>;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JSONLinesResponse = void 0;
|
|
4
|
+
require("./utils/shim");
|
|
5
|
+
class JSONLinesResponse extends Response {
|
|
6
|
+
isClosed = false;
|
|
7
|
+
controller;
|
|
8
|
+
encoder;
|
|
9
|
+
readableStream;
|
|
10
|
+
iteratorQueue = [];
|
|
11
|
+
iteratorResolvers = [];
|
|
12
|
+
constructor(request, init) {
|
|
13
|
+
const encoder = new TextEncoder();
|
|
14
|
+
let readableController;
|
|
15
|
+
const readableStream = new ReadableStream({
|
|
16
|
+
cancel: () => {
|
|
17
|
+
this.isClosed = true;
|
|
18
|
+
},
|
|
19
|
+
start: (controller) => {
|
|
20
|
+
readableController = controller;
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
const accept = request?.headers?.get('accept');
|
|
24
|
+
super(readableStream, {
|
|
25
|
+
...init,
|
|
26
|
+
headers: {
|
|
27
|
+
'content-type': !request || accept?.includes('application/jsonl')
|
|
28
|
+
? 'application/jsonl; charset=utf-8'
|
|
29
|
+
: 'text/plain; charset=utf-8',
|
|
30
|
+
...init?.headers,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
this.readableStream = request ? readableStream : null;
|
|
34
|
+
this.encoder = request ? encoder : null;
|
|
35
|
+
this.controller = request ? readableController : null;
|
|
36
|
+
request?.signal?.addEventListener('abort', this.close, { once: true });
|
|
37
|
+
}
|
|
38
|
+
send = (data) => {
|
|
39
|
+
const { controller, encoder } = this;
|
|
40
|
+
if (this.isClosed)
|
|
41
|
+
return;
|
|
42
|
+
// Enqueue to the ReadableStream
|
|
43
|
+
controller?.enqueue(encoder?.encode(JSON.stringify(data) + '\n'));
|
|
44
|
+
// Handle async iterator consumers
|
|
45
|
+
if (this.iteratorResolvers.length > 0) {
|
|
46
|
+
// If there's a pending next() call, resolve it immediately
|
|
47
|
+
const resolve = this.iteratorResolvers.shift();
|
|
48
|
+
resolve({ value: data, done: false });
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Otherwise, queue the value for later consumption
|
|
52
|
+
this.iteratorQueue.push(data);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
close = () => {
|
|
56
|
+
const { controller } = this;
|
|
57
|
+
if (this.isClosed)
|
|
58
|
+
return;
|
|
59
|
+
this.isClosed = true;
|
|
60
|
+
controller?.close();
|
|
61
|
+
// Resolve all pending iterator next() calls with done: true
|
|
62
|
+
while (this.iteratorResolvers.length > 0) {
|
|
63
|
+
const resolve = this.iteratorResolvers.shift();
|
|
64
|
+
resolve({ done: true, value: undefined });
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
throw = (e) => {
|
|
68
|
+
this.send({ isError: true, reason: e instanceof Error ? e.message : e });
|
|
69
|
+
return this.close();
|
|
70
|
+
};
|
|
71
|
+
[Symbol.dispose] = () => this.close();
|
|
72
|
+
[Symbol.asyncDispose] = () => this.close();
|
|
73
|
+
[Symbol.asyncIterator] = () => {
|
|
74
|
+
return {
|
|
75
|
+
next: async () => {
|
|
76
|
+
// If we have queued values, return them immediately
|
|
77
|
+
if (this.iteratorQueue.length > 0) {
|
|
78
|
+
const value = this.iteratorQueue.shift();
|
|
79
|
+
return { value, done: false };
|
|
80
|
+
}
|
|
81
|
+
// If the stream is closed and no more values, we're done
|
|
82
|
+
if (this.isClosed) {
|
|
83
|
+
return { done: true, value: undefined };
|
|
84
|
+
}
|
|
85
|
+
// Otherwise, wait for the next value or close
|
|
86
|
+
return new Promise((resolve) => {
|
|
87
|
+
this.iteratorResolvers.push(resolve);
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
exports.JSONLinesResponse = JSONLinesResponse;
|
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { NextRequest } from 'next/server';
|
|
2
|
+
import { HttpMethod, HttpStatus, type RouteHandler, type VovkController, type DecoratorOptions } from './types';
|
|
2
3
|
export declare class VovkApp {
|
|
3
4
|
#private;
|
|
4
5
|
private static getHeadersFromOptions;
|
|
5
6
|
routes: Record<HttpMethod, Map<VovkController, Record<string, RouteHandler>>>;
|
|
6
|
-
GET: (req:
|
|
7
|
+
GET: (req: NextRequest, data: {
|
|
7
8
|
params: Promise<Record<string, string[]>>;
|
|
8
9
|
}) => Promise<Response>;
|
|
9
|
-
POST: (req:
|
|
10
|
+
POST: (req: NextRequest, data: {
|
|
10
11
|
params: Promise<Record<string, string[]>>;
|
|
11
12
|
}) => Promise<Response>;
|
|
12
|
-
PUT: (req:
|
|
13
|
+
PUT: (req: NextRequest, data: {
|
|
13
14
|
params: Promise<Record<string, string[]>>;
|
|
14
15
|
}) => Promise<Response>;
|
|
15
|
-
PATCH: (req:
|
|
16
|
+
PATCH: (req: NextRequest, data: {
|
|
16
17
|
params: Promise<Record<string, string[]>>;
|
|
17
18
|
}) => Promise<Response>;
|
|
18
|
-
DELETE: (req:
|
|
19
|
+
DELETE: (req: NextRequest, data: {
|
|
19
20
|
params: Promise<Record<string, string[]>>;
|
|
20
21
|
}) => Promise<Response>;
|
|
21
|
-
HEAD: (req:
|
|
22
|
+
HEAD: (req: NextRequest, data: {
|
|
22
23
|
params: Promise<Record<string, string[]>>;
|
|
23
24
|
}) => Promise<Response>;
|
|
24
|
-
OPTIONS: (req:
|
|
25
|
+
OPTIONS: (req: NextRequest, data: {
|
|
25
26
|
params: Promise<Record<string, string[]>>;
|
|
26
27
|
}) => Promise<Response>;
|
|
27
28
|
respond: (status: HttpStatus, body: unknown, options?: DecoratorOptions) => Response;
|
|
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.VovkApp = void 0;
|
|
8
8
|
const types_1 = require("./types");
|
|
9
9
|
const HttpException_1 = require("./HttpException");
|
|
10
|
-
const
|
|
10
|
+
const JSONLinesResponse_1 = require("./JSONLinesResponse");
|
|
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"));
|
|
@@ -16,9 +16,9 @@ class VovkApp {
|
|
|
16
16
|
if (!options)
|
|
17
17
|
return {};
|
|
18
18
|
const corsHeaders = {
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
19
|
+
'access-control-allow-origin': '*',
|
|
20
|
+
'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
|
|
21
|
+
'access-control-allow-headers': 'content-type, authorization',
|
|
22
22
|
};
|
|
23
23
|
const headers = {
|
|
24
24
|
...(options.cors ? corsHeaders : {}),
|
|
@@ -46,7 +46,7 @@ class VovkApp {
|
|
|
46
46
|
return new Response(JSON.stringify(body), {
|
|
47
47
|
status,
|
|
48
48
|
headers: {
|
|
49
|
-
'
|
|
49
|
+
'content-type': 'application/json',
|
|
50
50
|
..._a.getHeadersFromOptions(options),
|
|
51
51
|
},
|
|
52
52
|
});
|
|
@@ -59,70 +59,91 @@ class VovkApp {
|
|
|
59
59
|
isError: true,
|
|
60
60
|
}, options);
|
|
61
61
|
};
|
|
62
|
-
#
|
|
62
|
+
#getHandler = ({ handlers, path, params, }) => {
|
|
63
|
+
let methodParams = {};
|
|
64
|
+
if (Object.keys(params).length === 0) {
|
|
65
|
+
return { handler: handlers[''], methodParams };
|
|
66
|
+
}
|
|
67
|
+
const allMethodKeys = Object.keys(handlers);
|
|
68
|
+
let methodKeys = [];
|
|
69
|
+
const pathStr = path.join('/');
|
|
70
|
+
methodKeys = allMethodKeys
|
|
71
|
+
// First, try to match literal routes exactly.
|
|
72
|
+
.filter((p) => {
|
|
73
|
+
if (p.includes('{'))
|
|
74
|
+
return false; // Skip parameterized paths
|
|
75
|
+
return p === pathStr;
|
|
76
|
+
});
|
|
77
|
+
if (!methodKeys.length) {
|
|
78
|
+
methodKeys = allMethodKeys.filter((p) => {
|
|
79
|
+
const routeSegments = p.split('/');
|
|
80
|
+
if (routeSegments.length !== path.length)
|
|
81
|
+
return false;
|
|
82
|
+
const params = {};
|
|
83
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
|
84
|
+
const routeSegment = routeSegments[i];
|
|
85
|
+
const pathSegment = path[i];
|
|
86
|
+
if (routeSegment.includes('{')) {
|
|
87
|
+
// const parameter = routeSegment.slice(1);
|
|
88
|
+
const regexPattern = routeSegment
|
|
89
|
+
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // Escape special chars
|
|
90
|
+
.replace(/\\{(\w+)\\}/g, '(?<$1>[^/]+)'); // Replace {var} with named groups
|
|
91
|
+
const values = pathSegment.match(new RegExp(`^${regexPattern}$`))?.groups ?? {};
|
|
92
|
+
for (const parameter in values) {
|
|
93
|
+
if (!Object.prototype.hasOwnProperty.call(values, parameter))
|
|
94
|
+
continue;
|
|
95
|
+
if (parameter in params) {
|
|
96
|
+
throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Duplicate parameter "${parameter}" at ${p}`);
|
|
97
|
+
}
|
|
98
|
+
// If it's a parameterized segment, capture the parameter value.
|
|
99
|
+
params[parameter] = values[parameter];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (routeSegment !== pathSegment) {
|
|
103
|
+
// If it's a literal segment and it does not match the corresponding path segment, return false.
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
methodParams = params;
|
|
108
|
+
return true;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (methodKeys.length > 1) {
|
|
112
|
+
throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Conflicting routes found: ${methodKeys.join(', ')}`);
|
|
113
|
+
}
|
|
114
|
+
const [methodKey] = methodKeys;
|
|
115
|
+
if (methodKey) {
|
|
116
|
+
return { handler: handlers[methodKey], methodParams };
|
|
117
|
+
}
|
|
118
|
+
return { handler: null, methodParams };
|
|
119
|
+
};
|
|
120
|
+
#callMethod = async (httpMethod, nextReq, params) => {
|
|
121
|
+
const req = nextReq;
|
|
63
122
|
const controllers = this.routes[httpMethod];
|
|
64
|
-
const methodParams = {};
|
|
65
123
|
const path = params[Object.keys(params)[0]];
|
|
66
124
|
const handlers = {};
|
|
125
|
+
let headerList;
|
|
126
|
+
try {
|
|
127
|
+
headerList = nextReq.headers;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// this is static rendering environment, headers are not available
|
|
131
|
+
headerList = null;
|
|
132
|
+
}
|
|
133
|
+
const xMeta = headerList?.get('x-meta');
|
|
134
|
+
const xMetaHeader = xMeta && JSON.parse(xMeta);
|
|
135
|
+
if (xMetaHeader)
|
|
136
|
+
(0, reqMeta_1.default)(req, { xMetaHeader });
|
|
67
137
|
controllers.forEach((staticMethods, controller) => {
|
|
68
138
|
const prefix = controller._prefix ?? '';
|
|
69
|
-
|
|
70
|
-
throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Controller "${controller.name}" found but not activated`);
|
|
71
|
-
}
|
|
72
|
-
Object.entries(staticMethods).forEach(([path, staticMethod]) => {
|
|
139
|
+
Object.entries(staticMethods ?? {}).forEach(([path, staticMethod]) => {
|
|
73
140
|
const fullPath = [prefix, path].filter(Boolean).join('/');
|
|
74
141
|
handlers[fullPath] = { staticMethod, controller };
|
|
75
142
|
});
|
|
76
143
|
});
|
|
77
|
-
const
|
|
78
|
-
if (Object.keys(params).length === 0) {
|
|
79
|
-
return handlers[''];
|
|
80
|
-
}
|
|
81
|
-
const allMethodKeys = Object.keys(handlers);
|
|
82
|
-
let methodKeys = [];
|
|
83
|
-
methodKeys = allMethodKeys
|
|
84
|
-
// First, try to match literal routes exactly.
|
|
85
|
-
.filter((p) => {
|
|
86
|
-
if (p.includes(':'))
|
|
87
|
-
return false; // Skip parameterized paths
|
|
88
|
-
return p === path.join('/');
|
|
89
|
-
});
|
|
90
|
-
if (!methodKeys.length) {
|
|
91
|
-
methodKeys = allMethodKeys.filter((p) => {
|
|
92
|
-
const routeSegments = p.split('/');
|
|
93
|
-
if (routeSegments.length !== path.length)
|
|
94
|
-
return false;
|
|
95
|
-
for (let i = 0; i < routeSegments.length; i++) {
|
|
96
|
-
const routeSegment = routeSegments[i];
|
|
97
|
-
const pathSegment = path[i];
|
|
98
|
-
if (routeSegment.startsWith(':')) {
|
|
99
|
-
const parameter = routeSegment.slice(1);
|
|
100
|
-
if (parameter in methodParams) {
|
|
101
|
-
throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Duplicate parameter "${parameter}"`);
|
|
102
|
-
}
|
|
103
|
-
// If it's a parameterized segment, capture the parameter value.
|
|
104
|
-
methodParams[parameter] = pathSegment;
|
|
105
|
-
}
|
|
106
|
-
else if (routeSegment !== pathSegment) {
|
|
107
|
-
// If it's a literal segment and it does not match the corresponding path segment, return false.
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return true;
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
if (methodKeys.length > 1) {
|
|
115
|
-
throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Conflicting routes found: ${methodKeys.join(', ')}`);
|
|
116
|
-
}
|
|
117
|
-
const [methodKey] = methodKeys;
|
|
118
|
-
if (methodKey) {
|
|
119
|
-
return handlers[methodKey];
|
|
120
|
-
}
|
|
121
|
-
return null;
|
|
122
|
-
};
|
|
123
|
-
const handler = getHandler();
|
|
144
|
+
const { handler, methodParams } = this.#getHandler({ handlers, path, params });
|
|
124
145
|
if (!handler) {
|
|
125
|
-
return this.#respondWithError(types_1.HttpStatus.NOT_FOUND,
|
|
146
|
+
return this.#respondWithError(types_1.HttpStatus.NOT_FOUND, `${Object.keys(handlers)} - Route ${path.join('/')} is not found`);
|
|
126
147
|
}
|
|
127
148
|
const { staticMethod, controller } = handler;
|
|
128
149
|
req.vovk = {
|
|
@@ -130,19 +151,24 @@ class VovkApp {
|
|
|
130
151
|
query: () => (0, reqQuery_1.default)(req),
|
|
131
152
|
meta: (meta) => (0, reqMeta_1.default)(req, meta),
|
|
132
153
|
form: () => (0, reqForm_1.default)(req),
|
|
154
|
+
params: () => methodParams,
|
|
133
155
|
};
|
|
134
156
|
try {
|
|
157
|
+
await staticMethod._options?.before?.call(controller, req);
|
|
135
158
|
const result = await staticMethod.call(controller, req, methodParams);
|
|
159
|
+
if (result instanceof Response) {
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
136
162
|
const isIterator = typeof result === 'object' &&
|
|
137
163
|
!!result &&
|
|
164
|
+
!(result instanceof Array) &&
|
|
138
165
|
((Reflect.has(result, Symbol.iterator) &&
|
|
139
166
|
typeof result[Symbol.iterator] === 'function') ||
|
|
140
167
|
(Reflect.has(result, Symbol.asyncIterator) &&
|
|
141
168
|
typeof result[Symbol.asyncIterator] === 'function'));
|
|
142
|
-
if (isIterator
|
|
143
|
-
const streamResponse = new
|
|
169
|
+
if (isIterator) {
|
|
170
|
+
const streamResponse = new JSONLinesResponse_1.JSONLinesResponse(req, {
|
|
144
171
|
headers: {
|
|
145
|
-
...StreamJSONResponse_1.StreamJSONResponse.defaultHeaders,
|
|
146
172
|
..._a.getHeadersFromOptions(staticMethod._options),
|
|
147
173
|
},
|
|
148
174
|
});
|
|
@@ -159,9 +185,6 @@ class VovkApp {
|
|
|
159
185
|
})();
|
|
160
186
|
return streamResponse;
|
|
161
187
|
}
|
|
162
|
-
if (result instanceof Response) {
|
|
163
|
-
return result;
|
|
164
|
-
}
|
|
165
188
|
return this.respond(200, result ?? null, staticMethod._options);
|
|
166
189
|
}
|
|
167
190
|
catch (e) {
|
|
@@ -174,7 +197,7 @@ class VovkApp {
|
|
|
174
197
|
console.error(onErrorError);
|
|
175
198
|
}
|
|
176
199
|
if (err.message !== 'NEXT_REDIRECT' && err.message !== 'NEXT_NOT_FOUND') {
|
|
177
|
-
const statusCode = err.statusCode
|
|
200
|
+
const statusCode = err.statusCode || types_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
178
201
|
return this.#respondWithError(statusCode, err.message, staticMethod._options, err.cause);
|
|
179
202
|
}
|
|
180
203
|
throw e; // if NEXT_REDIRECT or NEXT_NOT_FOUND, rethrow it
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { KnownAny } from '../types';
|
|
2
|
+
import type { VovkClient, VovkClientFetcher, VovkDefaultFetcherOptions } from './types';
|
|
3
|
+
export declare const createRPC: <T, OPTS extends Record<string, KnownAny> = Record<string, never>>(givenSchema: unknown, segmentName: string, rpcModuleName: string, givenFetcher?: VovkClientFetcher<OPTS> | Promise<{
|
|
4
|
+
fetcher: VovkClientFetcher<OPTS>;
|
|
5
|
+
}>, options?: VovkDefaultFetcherOptions<OPTS>) => VovkClient<T, OPTS>;
|
|
@@ -0,0 +1,108 @@
|
|
|
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_1 = require("./fetcher");
|
|
8
|
+
const defaultHandler_1 = require("./defaultHandler");
|
|
9
|
+
const defaultStreamHandler_1 = require("./defaultStreamHandler");
|
|
10
|
+
const serializeQuery_1 = __importDefault(require("../utils/serializeQuery"));
|
|
11
|
+
const trimPath = (path) => path.trim().replace(/^\/|\/$/g, '');
|
|
12
|
+
const getHandlerPath = (endpoint, params, query) => {
|
|
13
|
+
let result = endpoint;
|
|
14
|
+
const queryStr = query ? (0, serializeQuery_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 = (givenSchema, segmentName, rpcModuleName, givenFetcher, options) => {
|
|
21
|
+
const schema = givenSchema; // fixes incompatibilities with JSON module
|
|
22
|
+
// fetcher ??= defaultFetcher as NonNullable<typeof fetcher>;
|
|
23
|
+
const segmentNamePath = options?.segmentNameOverride ?? segmentName;
|
|
24
|
+
const segmentSchema = schema.segments[segmentName];
|
|
25
|
+
if (!segmentSchema)
|
|
26
|
+
throw new Error(`Unable to create RPC module. Segment schema is missing for segment "${segmentName}".`);
|
|
27
|
+
const controllerSchema = schema.segments[segmentName]?.controllers[rpcModuleName];
|
|
28
|
+
const client = {};
|
|
29
|
+
if (!controllerSchema) {
|
|
30
|
+
throw new Error(`Unable to create RPC module. Controller schema is missing for module "${rpcModuleName}" from segment "${segmentName}".`);
|
|
31
|
+
}
|
|
32
|
+
const controllerPrefix = trimPath(controllerSchema.prefix ?? '');
|
|
33
|
+
for (const [staticMethodName, handlerSchema] of Object.entries(controllerSchema.handlers ?? {})) {
|
|
34
|
+
const { path, httpMethod, validation } = handlerSchema;
|
|
35
|
+
const getEndpoint = ({ apiRoot, params, query }) => {
|
|
36
|
+
const forceApiRoot = controllerSchema.forceApiRoot ?? segmentSchema.forceApiRoot;
|
|
37
|
+
apiRoot = apiRoot ?? forceApiRoot ?? options?.apiRoot ?? '/api';
|
|
38
|
+
const endpoint = [
|
|
39
|
+
apiRoot.startsWith('http://') || apiRoot.startsWith('https://') || apiRoot.startsWith('/') ? '' : '/',
|
|
40
|
+
apiRoot,
|
|
41
|
+
forceApiRoot ? '' : segmentNamePath,
|
|
42
|
+
getHandlerPath([controllerPrefix, path].filter(Boolean).join('/'), params, query),
|
|
43
|
+
]
|
|
44
|
+
.filter(Boolean)
|
|
45
|
+
.join('/')
|
|
46
|
+
.replace(/([^:])\/+/g, '$1/'); // replace // by / but not for protocols (http://, https://)
|
|
47
|
+
return endpoint;
|
|
48
|
+
};
|
|
49
|
+
const handler = (async (input = {}) => {
|
|
50
|
+
const fetcher = givenFetcher instanceof Promise
|
|
51
|
+
? (await givenFetcher).fetcher
|
|
52
|
+
: (givenFetcher ?? fetcher_1.fetcher);
|
|
53
|
+
const validate = async (validationInput, { endpoint, }) => {
|
|
54
|
+
const validateOnClient = input.validateOnClient ??
|
|
55
|
+
(options?.validateOnClient instanceof Promise
|
|
56
|
+
? (await options?.validateOnClient)?.validateOnClient
|
|
57
|
+
: options?.validateOnClient);
|
|
58
|
+
if (validateOnClient && validation) {
|
|
59
|
+
if (typeof validateOnClient !== 'function') {
|
|
60
|
+
throw new Error('validateOnClient must be a function');
|
|
61
|
+
}
|
|
62
|
+
return ((await validateOnClient({ ...validationInput }, validation, { fullSchema: schema, endpoint })) ??
|
|
63
|
+
validationInput);
|
|
64
|
+
}
|
|
65
|
+
return validationInput;
|
|
66
|
+
};
|
|
67
|
+
const internalOptions = {
|
|
68
|
+
name: staticMethodName,
|
|
69
|
+
httpMethod: httpMethod,
|
|
70
|
+
getEndpoint,
|
|
71
|
+
validate,
|
|
72
|
+
defaultHandler: defaultHandler_1.defaultHandler,
|
|
73
|
+
defaultStreamHandler: defaultStreamHandler_1.defaultStreamHandler,
|
|
74
|
+
schema: handlerSchema,
|
|
75
|
+
};
|
|
76
|
+
const internalInput = {
|
|
77
|
+
...options,
|
|
78
|
+
...input,
|
|
79
|
+
body: input.body ?? null,
|
|
80
|
+
query: input.query ?? {},
|
|
81
|
+
params: input.params ?? {},
|
|
82
|
+
};
|
|
83
|
+
if (!fetcher)
|
|
84
|
+
throw new Error('Fetcher is not provided');
|
|
85
|
+
const [respData, resp] = await fetcher(internalOptions, internalInput);
|
|
86
|
+
return input.transform ? input.transform(respData, resp) : respData;
|
|
87
|
+
});
|
|
88
|
+
// TODO use Object.freeze, Object.seal or Object.defineProperty to avoid mutation
|
|
89
|
+
handler.schema = handlerSchema;
|
|
90
|
+
handler.controllerSchema = controllerSchema;
|
|
91
|
+
handler.segmentSchema = segmentSchema;
|
|
92
|
+
handler.fullSchema = schema;
|
|
93
|
+
handler.isRPC = true;
|
|
94
|
+
handler.path = [segmentNamePath, controllerPrefix, path].filter(Boolean).join('/');
|
|
95
|
+
handler.queryKey = (key) => [
|
|
96
|
+
handler.segmentSchema.segmentName,
|
|
97
|
+
handler.controllerSchema.prefix ?? '',
|
|
98
|
+
handler.controllerSchema.rpcModuleName,
|
|
99
|
+
handler.schema.path,
|
|
100
|
+
handler.schema.httpMethod,
|
|
101
|
+
...(key ?? []),
|
|
102
|
+
];
|
|
103
|
+
// @ts-expect-error TODO
|
|
104
|
+
client[staticMethodName] = handler;
|
|
105
|
+
}
|
|
106
|
+
return client;
|
|
107
|
+
};
|
|
108
|
+
exports.createRPC = createRPC;
|
|
@@ -3,7 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.defaultHandler = exports.DEFAULT_ERROR_MESSAGE = void 0;
|
|
4
4
|
const HttpException_1 = require("../HttpException");
|
|
5
5
|
exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at defaultHandler';
|
|
6
|
-
|
|
6
|
+
// Helper function to get a value from an object using dot notation path
|
|
7
|
+
const getNestedValue = (obj, path) => {
|
|
8
|
+
return path.split('.').reduce((o, key) => (o && typeof o === 'object' ? o[key] : undefined), obj);
|
|
9
|
+
};
|
|
10
|
+
const defaultHandler = async ({ response, schema }) => {
|
|
7
11
|
let result;
|
|
8
12
|
try {
|
|
9
13
|
result = await response.json();
|
|
@@ -13,9 +17,12 @@ const defaultHandler = async (response) => {
|
|
|
13
17
|
throw new HttpException_1.HttpException(response.status, e?.message ?? exports.DEFAULT_ERROR_MESSAGE);
|
|
14
18
|
}
|
|
15
19
|
if (!response.ok) {
|
|
20
|
+
const errorKey = schema.operationObject && 'x-errorMessageKey' in schema.operationObject
|
|
21
|
+
? schema.operationObject['x-errorMessageKey']
|
|
22
|
+
: 'message';
|
|
16
23
|
// handle server errors
|
|
17
24
|
const errorResponse = result;
|
|
18
|
-
throw new HttpException_1.HttpException(response.status, errorResponse
|
|
25
|
+
throw new HttpException_1.HttpException(response.status, getNestedValue(errorResponse, errorKey) ?? exports.DEFAULT_ERROR_MESSAGE, errorResponse?.cause ?? JSON.stringify(result));
|
|
19
26
|
}
|
|
20
27
|
return result;
|
|
21
28
|
};
|