vovk 3.0.0-beta.6 → 3.0.0-draft.100

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.
Files changed (95) hide show
  1. package/{dist/package.json → LICENSE} +4 -4
  2. package/README.md +24 -1
  3. package/dist/HttpException.d.ts +2 -2
  4. package/dist/HttpException.js +3 -3
  5. package/dist/{StreamResponse.d.ts → StreamJSONResponse.d.ts} +4 -6
  6. package/dist/{StreamResponse.js → StreamJSONResponse.js} +12 -8
  7. package/dist/VovkApp.d.ts +29 -0
  8. package/dist/VovkApp.js +188 -0
  9. package/dist/client/createRPC.d.ts +3 -0
  10. package/dist/client/createRPC.js +85 -0
  11. package/dist/client/defaultHandler.d.ts +1 -1
  12. package/dist/client/defaultHandler.js +6 -5
  13. package/dist/client/defaultStreamHandler.d.ts +2 -2
  14. package/dist/client/defaultStreamHandler.js +5 -5
  15. package/dist/client/fetcher.d.ts +3 -0
  16. package/dist/client/fetcher.js +64 -0
  17. package/dist/client/index.d.ts +3 -4
  18. package/dist/client/index.js +5 -3
  19. package/dist/client/types.d.ts +40 -37
  20. package/dist/createDecorator.d.ts +4 -2
  21. package/dist/createDecorator.js +21 -16
  22. package/dist/{createSegment.d.ts → createVovkApp.d.ts} +19 -20
  23. package/dist/createVovkApp.js +118 -0
  24. package/dist/index.d.ts +40 -42
  25. package/dist/index.js +17 -14
  26. package/dist/types.d.ts +129 -78
  27. package/dist/types.js +64 -63
  28. package/dist/utils/generateStaticAPI.d.ts +4 -0
  29. package/dist/{generateStaticAPI.js → utils/generateStaticAPI.js} +3 -4
  30. package/dist/utils/getSchema.d.ts +20 -0
  31. package/dist/utils/getSchema.js +33 -0
  32. package/dist/utils/parseQuery.d.ts +25 -0
  33. package/dist/utils/parseQuery.js +156 -0
  34. package/dist/utils/reqForm.d.ts +2 -0
  35. package/dist/utils/reqForm.js +13 -0
  36. package/dist/utils/reqMeta.d.ts +2 -3
  37. package/dist/utils/reqMeta.js +7 -7
  38. package/dist/utils/reqQuery.d.ts +1 -2
  39. package/dist/utils/reqQuery.js +5 -20
  40. package/dist/utils/serializeQuery.d.ts +13 -0
  41. package/dist/utils/serializeQuery.js +65 -0
  42. package/dist/utils/setHandlerSchema.d.ts +4 -0
  43. package/dist/utils/setHandlerSchema.js +15 -0
  44. package/dist/utils/withValidation.d.ts +20 -0
  45. package/dist/utils/withValidation.js +72 -0
  46. package/package.json +11 -4
  47. package/.DS_Store +0 -0
  48. package/.npmignore +0 -1
  49. package/.turbo/turbo-build.log +0 -6
  50. package/.turbo/turbo-ncu.log +0 -9
  51. package/HttpException.ts +0 -16
  52. package/Segment.ts +0 -238
  53. package/StreamResponse.ts +0 -61
  54. package/client/clientizeController.ts +0 -141
  55. package/client/defaultFetcher.ts +0 -60
  56. package/client/defaultHandler.ts +0 -22
  57. package/client/defaultStreamHandler.ts +0 -88
  58. package/client/index.ts +0 -9
  59. package/client/types.ts +0 -116
  60. package/createDecorator.ts +0 -65
  61. package/createSegment.ts +0 -239
  62. package/dist/.npmignore +0 -1
  63. package/dist/README.md +0 -111
  64. package/dist/Segment.d.ts +0 -27
  65. package/dist/Segment.js +0 -187
  66. package/dist/client/clientizeController.d.ts +0 -4
  67. package/dist/client/clientizeController.js +0 -92
  68. package/dist/client/defaultFetcher.d.ts +0 -4
  69. package/dist/client/defaultFetcher.js +0 -49
  70. package/dist/createSegment.js +0 -167
  71. package/dist/generateStaticAPI.d.ts +0 -3
  72. package/dist/package-lock.json +0 -472
  73. package/dist/tsconfig.tsbuildinfo +0 -1
  74. package/dist/utils/setClientValidatorsForHandler.d.ts +0 -5
  75. package/dist/utils/setClientValidatorsForHandler.js +0 -28
  76. package/dist/worker/index.d.ts +0 -3
  77. package/dist/worker/index.js +0 -7
  78. package/dist/worker/promisifyWorker.d.ts +0 -2
  79. package/dist/worker/promisifyWorker.js +0 -142
  80. package/dist/worker/types.d.ts +0 -31
  81. package/dist/worker/types.js +0 -2
  82. package/dist/worker/worker.d.ts +0 -1
  83. package/dist/worker/worker.js +0 -45
  84. package/generateStaticAPI.ts +0 -19
  85. package/index.ts +0 -59
  86. package/tsconfig.json +0 -9
  87. package/types.ts +0 -237
  88. package/utils/reqMeta.ts +0 -17
  89. package/utils/reqQuery.ts +0 -27
  90. package/utils/setClientValidatorsForHandler.ts +0 -45
  91. package/utils/shim.ts +0 -17
  92. package/worker/index.ts +0 -4
  93. package/worker/promisifyWorker.ts +0 -159
  94. package/worker/types.ts +0 -45
  95. package/worker/worker.ts +0 -55
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "vovk",
3
- "version": "3.0.0-beta.6",
3
+ "version": "3.0.0-beta.9",
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 package.json dist && cp package-lock.json dist && cp .npmignore dist && cp ../../README.md dist ",
10
+ "build": "rm -rf dist && tsc && cp {package.json,LICENSE} && cp ../../README.md dist ",
11
11
  "lint": "eslint . --fix",
12
- "npm-publish": "npm publish ./dist",
12
+ "npm-publish": "npm publish ./dist --dry-run",
13
13
  "ncu": "npm-check-updates -u"
14
14
  },
15
15
  "keywords": [
16
16
  "nextjs",
17
17
  "router"
18
18
  ],
19
- "author": "Andrii Gubanov",
19
+ "author": "Andrey Gubanov",
20
20
  "license": "MIT",
21
21
  "bugs": {
22
22
  "url": "https://github.com/finom/vovk/issues"
package/README.md CHANGED
@@ -1 +1,24 @@
1
- Description is coming soon.
1
+ <p align="center">
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>REST + RPC = ♥️</strong>
8
+ </p>
9
+
10
+ <p align="center">
11
+ Back-end meta-framework for <a href="https://nextjs.org/docs/app">Next.js</a>
12
+ </p>
13
+
14
+ ---
15
+
16
+ ## vovk [![npm version](https://badge.fury.io/js/vovk.svg)](https://www.npmjs.com/package/vovk)
17
+
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.
19
+
20
+ ```sh
21
+ npm install vovk
22
+ ```
23
+
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/).
@@ -1,5 +1,5 @@
1
- import type { _HttpStatus as HttpStatus } from './types';
2
- export declare class _HttpException extends Error {
1
+ import type { HttpStatus } from './types';
2
+ export declare class HttpException extends Error {
3
3
  statusCode: HttpStatus;
4
4
  message: string;
5
5
  cause?: unknown;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._HttpException = void 0;
4
- class _HttpException extends Error {
3
+ exports.HttpException = void 0;
4
+ class HttpException extends Error {
5
5
  statusCode;
6
6
  message;
7
7
  cause;
@@ -12,4 +12,4 @@ class _HttpException extends Error {
12
12
  this.cause = cause;
13
13
  }
14
14
  }
15
- exports._HttpException = _HttpException;
15
+ exports.HttpException = HttpException;
@@ -1,14 +1,12 @@
1
- import { _KnownAny as KnownAny, _StreamAbortMessage as StreamAbortMessage } from './types';
1
+ import type { headers } from 'next/headers';
2
+ import type { KnownAny, StreamAbortMessage } from './types';
2
3
  import './utils/shim';
3
- export declare class _StreamResponse<T> extends Response {
4
- static defaultHeaders: {
5
- 'Content-Type': string;
6
- };
4
+ export declare class StreamJSONResponse<T> extends Response {
7
5
  isClosed: boolean;
8
6
  controller?: ReadableStreamDefaultController;
9
7
  readonly encoder: TextEncoder;
10
8
  readonly readableStream: ReadableStream;
11
- constructor(init?: ResponseInit);
9
+ constructor(requestHeaders: Awaited<ReturnType<typeof headers>>, init?: ResponseInit);
12
10
  send(data: T | StreamAbortMessage): void;
13
11
  close(): void;
14
12
  throw(e: KnownAny): void;
@@ -1,16 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._StreamResponse = void 0;
3
+ exports.StreamJSONResponse = void 0;
4
4
  require("./utils/shim");
5
- class _StreamResponse extends Response {
6
- static defaultHeaders = {
7
- 'Content-Type': 'text/plain; charset=utf-8',
8
- };
5
+ class StreamJSONResponse extends Response {
9
6
  isClosed = false;
10
7
  controller;
11
8
  encoder;
12
9
  readableStream;
13
- constructor(init) {
10
+ constructor(requestHeaders, init) {
14
11
  const encoder = new TextEncoder();
15
12
  let readableController;
16
13
  const readableStream = new ReadableStream({
@@ -21,9 +18,16 @@ class _StreamResponse extends Response {
21
18
  readableController = controller;
22
19
  },
23
20
  });
21
+ if (!requestHeaders) {
22
+ throw new Error('Request headers are required');
23
+ }
24
+ const accept = requestHeaders.get('accept');
24
25
  super(readableStream, {
25
26
  ...init,
26
- headers: init?.headers ?? _StreamResponse.defaultHeaders,
27
+ headers: {
28
+ ...init?.headers,
29
+ 'Content-Type': accept?.includes('application/jsonl') ? 'application/jsonl; charset=utf-8' : 'text/plain; charset=utf-8',
30
+ },
27
31
  });
28
32
  this.readableStream = readableStream;
29
33
  this.encoder = encoder;
@@ -50,4 +54,4 @@ class _StreamResponse extends Response {
50
54
  this.close();
51
55
  }
52
56
  }
53
- exports._StreamResponse = _StreamResponse;
57
+ exports.StreamJSONResponse = StreamJSONResponse;
@@ -0,0 +1,29 @@
1
+ import type { NextRequest } from 'next/server';
2
+ import { HttpMethod, HttpStatus, type RouteHandler, type VovkController, type DecoratorOptions } from './types';
3
+ export declare class VovkApp {
4
+ #private;
5
+ private static getHeadersFromOptions;
6
+ routes: Record<HttpMethod, Map<VovkController, Record<string, RouteHandler>>>;
7
+ GET: (req: NextRequest, data: {
8
+ params: Promise<Record<string, string[]>>;
9
+ }) => Promise<Response>;
10
+ POST: (req: NextRequest, data: {
11
+ params: Promise<Record<string, string[]>>;
12
+ }) => Promise<Response>;
13
+ PUT: (req: NextRequest, data: {
14
+ params: Promise<Record<string, string[]>>;
15
+ }) => Promise<Response>;
16
+ PATCH: (req: NextRequest, data: {
17
+ params: Promise<Record<string, string[]>>;
18
+ }) => Promise<Response>;
19
+ DELETE: (req: NextRequest, data: {
20
+ params: Promise<Record<string, string[]>>;
21
+ }) => Promise<Response>;
22
+ HEAD: (req: NextRequest, data: {
23
+ params: Promise<Record<string, string[]>>;
24
+ }) => Promise<Response>;
25
+ OPTIONS: (req: NextRequest, data: {
26
+ params: Promise<Record<string, string[]>>;
27
+ }) => Promise<Response>;
28
+ respond: (status: HttpStatus, body: unknown, options?: DecoratorOptions) => Response;
29
+ }
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ var _a;
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.VovkApp = void 0;
8
+ const types_1 = require("./types");
9
+ const HttpException_1 = require("./HttpException");
10
+ const StreamJSONResponse_1 = require("./StreamJSONResponse");
11
+ const reqQuery_1 = __importDefault(require("./utils/reqQuery"));
12
+ const reqMeta_1 = __importDefault(require("./utils/reqMeta"));
13
+ const reqForm_1 = __importDefault(require("./utils/reqForm"));
14
+ const headers_1 = require("next/headers");
15
+ class VovkApp {
16
+ static getHeadersFromOptions(options) {
17
+ if (!options)
18
+ return {};
19
+ const corsHeaders = {
20
+ 'access-control-allow-origin': '*',
21
+ 'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
22
+ 'access-control-allow-headers': 'content-type, authorization',
23
+ };
24
+ const headers = {
25
+ ...(options.cors ? corsHeaders : {}),
26
+ ...(options.headers ?? {}),
27
+ };
28
+ return headers;
29
+ }
30
+ routes = {
31
+ GET: new Map(),
32
+ POST: new Map(),
33
+ PUT: new Map(),
34
+ PATCH: new Map(),
35
+ DELETE: new Map(),
36
+ HEAD: new Map(),
37
+ OPTIONS: new Map(),
38
+ };
39
+ GET = async (req, data) => this.#callMethod(types_1.HttpMethod.GET, req, await data.params);
40
+ POST = async (req, data) => this.#callMethod(types_1.HttpMethod.POST, req, await data.params);
41
+ PUT = async (req, data) => this.#callMethod(types_1.HttpMethod.PUT, req, await data.params);
42
+ PATCH = async (req, data) => this.#callMethod(types_1.HttpMethod.PATCH, req, await data.params);
43
+ DELETE = async (req, data) => this.#callMethod(types_1.HttpMethod.DELETE, req, await data.params);
44
+ HEAD = async (req, data) => this.#callMethod(types_1.HttpMethod.HEAD, req, await data.params);
45
+ OPTIONS = async (req, data) => this.#callMethod(types_1.HttpMethod.OPTIONS, req, await data.params);
46
+ respond = (status, body, options) => {
47
+ return new Response(JSON.stringify(body), {
48
+ status,
49
+ headers: {
50
+ 'content-type': 'application/json',
51
+ ..._a.getHeadersFromOptions(options),
52
+ },
53
+ });
54
+ };
55
+ #respondWithError = (statusCode, message, options, cause) => {
56
+ return this.respond(statusCode, {
57
+ cause,
58
+ statusCode,
59
+ message,
60
+ isError: true,
61
+ }, options);
62
+ };
63
+ #getHandler = ({ handlers, path, params, }) => {
64
+ const methodParams = {};
65
+ if (Object.keys(params).length === 0) {
66
+ return { handler: handlers[''], methodParams };
67
+ }
68
+ const allMethodKeys = Object.keys(handlers);
69
+ let methodKeys = [];
70
+ const pathStr = path.join('/');
71
+ methodKeys = allMethodKeys
72
+ // First, try to match literal routes exactly.
73
+ .filter((p) => {
74
+ if (p.includes(':'))
75
+ return false; // Skip parameterized paths
76
+ return p === pathStr;
77
+ });
78
+ if (!methodKeys.length) {
79
+ methodKeys = allMethodKeys.filter((p) => {
80
+ const routeSegments = p.split('/');
81
+ if (routeSegments.length !== path.length)
82
+ return false;
83
+ for (let i = 0; i < routeSegments.length; i++) {
84
+ const routeSegment = routeSegments[i];
85
+ const pathSegment = path[i];
86
+ if (routeSegment.startsWith(':')) {
87
+ const parameter = routeSegment.slice(1);
88
+ if (parameter in methodParams) {
89
+ throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Duplicate parameter "${parameter}" at ${p}`);
90
+ }
91
+ // If it's a parameterized segment, capture the parameter value.
92
+ methodParams[parameter] = pathSegment;
93
+ }
94
+ else if (routeSegment !== pathSegment) {
95
+ // If it's a literal segment and it does not match the corresponding path segment, return false.
96
+ return false;
97
+ }
98
+ }
99
+ return true;
100
+ });
101
+ }
102
+ if (methodKeys.length > 1) {
103
+ throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Conflicting routes found: ${methodKeys.join(', ')}`);
104
+ }
105
+ const [methodKey] = methodKeys;
106
+ if (methodKey) {
107
+ return { handler: handlers[methodKey], methodParams };
108
+ }
109
+ return { handler: null, methodParams };
110
+ };
111
+ #callMethod = async (httpMethod, nextReq, params) => {
112
+ const req = nextReq;
113
+ const controllers = this.routes[httpMethod];
114
+ const path = params[Object.keys(params)[0]];
115
+ const handlers = {};
116
+ controllers.forEach((staticMethods, controller) => {
117
+ const prefix = controller._prefix ?? '';
118
+ if (!controller._activated) {
119
+ throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Controller "${controller.name}" found but not activated`);
120
+ }
121
+ Object.entries(staticMethods).forEach(([path, staticMethod]) => {
122
+ const fullPath = [prefix, path].filter(Boolean).join('/');
123
+ handlers[fullPath] = { staticMethod, controller };
124
+ });
125
+ });
126
+ const { handler, methodParams } = this.#getHandler({ handlers, path, params });
127
+ if (!handler) {
128
+ return this.#respondWithError(types_1.HttpStatus.NOT_FOUND, `Route ${path.join('/')} is not found`);
129
+ }
130
+ const { staticMethod, controller } = handler;
131
+ req.vovk = {
132
+ body: () => req.json(),
133
+ query: () => (0, reqQuery_1.default)(req),
134
+ meta: (meta) => (0, reqMeta_1.default)(req, meta),
135
+ form: () => (0, reqForm_1.default)(req),
136
+ params: () => methodParams,
137
+ };
138
+ try {
139
+ const result = await staticMethod.call(controller, req, methodParams);
140
+ const isIterator = typeof result === 'object' &&
141
+ !!result &&
142
+ ((Reflect.has(result, Symbol.iterator) &&
143
+ typeof result[Symbol.iterator] === 'function') ||
144
+ (Reflect.has(result, Symbol.asyncIterator) &&
145
+ typeof result[Symbol.asyncIterator] === 'function'));
146
+ if (isIterator && !(result instanceof Array)) {
147
+ const streamResponse = new StreamJSONResponse_1.StreamJSONResponse(await (0, headers_1.headers)(), {
148
+ headers: {
149
+ ..._a.getHeadersFromOptions(staticMethod._options),
150
+ },
151
+ });
152
+ void (async () => {
153
+ try {
154
+ for await (const chunk of result) {
155
+ streamResponse.send(chunk);
156
+ }
157
+ }
158
+ catch (e) {
159
+ return streamResponse.throw(e);
160
+ }
161
+ return streamResponse.close();
162
+ })();
163
+ return streamResponse;
164
+ }
165
+ if (result instanceof Response) {
166
+ return result;
167
+ }
168
+ return this.respond(200, result ?? null, staticMethod._options);
169
+ }
170
+ catch (e) {
171
+ const err = e;
172
+ try {
173
+ await controller._onError?.(err, req);
174
+ }
175
+ catch (onErrorError) {
176
+ // eslint-disable-next-line no-console
177
+ console.error(onErrorError);
178
+ }
179
+ if (err.message !== 'NEXT_REDIRECT' && err.message !== 'NEXT_NOT_FOUND') {
180
+ const statusCode = err.statusCode || types_1.HttpStatus.INTERNAL_SERVER_ERROR;
181
+ return this.#respondWithError(statusCode, err.message, staticMethod._options, err.cause);
182
+ }
183
+ throw e; // if NEXT_REDIRECT or NEXT_NOT_FOUND, rethrow it
184
+ }
185
+ };
186
+ }
187
+ exports.VovkApp = VovkApp;
188
+ _a = VovkApp;
@@ -0,0 +1,3 @@
1
+ import type { KnownAny, VovkFullSchema } from '../types';
2
+ import type { VovkClientOptions, VovkClient, VovkDefaultFetcherOptions } from './types';
3
+ export declare const createRPC: <T, OPTS extends Record<string, KnownAny> = VovkDefaultFetcherOptions>(fullSchema: VovkFullSchema, segmentName: string, controllerName: string, options?: VovkClientOptions<OPTS>) => VovkClient<T, OPTS>;
@@ -0,0 +1,85 @@
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 = (fullSchema, segmentName, controllerName, options) => {
21
+ const segmentSchema = fullSchema.segments[segmentName];
22
+ if (!segmentSchema)
23
+ throw new Error(`Unable to create RPC object. Segment schema is missing. Check client template.`);
24
+ const controllerSchema = fullSchema.segments[segmentName]?.controllers[controllerName];
25
+ const client = {};
26
+ if (!controllerSchema)
27
+ throw new Error(`Unable to create RPC object. Controller schema is missing. Check client template.`);
28
+ const controllerPrefix = trimPath(controllerSchema.prefix ?? '');
29
+ const { fetcher: settingsFetcher = fetcher_1.fetcher } = options ?? {};
30
+ for (const [staticMethodName, handlerSchema] of Object.entries(controllerSchema.handlers)) {
31
+ const { path, httpMethod, validation } = handlerSchema;
32
+ const getEndpoint = ({ apiRoot, params, query, }) => {
33
+ const mainPrefix = (apiRoot.startsWith('http://') || apiRoot.startsWith('https://') || apiRoot.startsWith('/') ? '' : '/') +
34
+ (apiRoot.endsWith('/') ? apiRoot : `${apiRoot}/`) +
35
+ (segmentName ? `${segmentName}/` : '');
36
+ return mainPrefix + getHandlerPath([controllerPrefix, path].filter(Boolean).join('/'), params, query);
37
+ };
38
+ const handler = (input = {}) => {
39
+ const fetcher = input.fetcher ?? settingsFetcher;
40
+ const validate = async ({ body, query, params, endpoint, }) => {
41
+ const validateOnClient = input.validateOnClient ?? options?.validateOnClient;
42
+ if (validateOnClient) {
43
+ if (typeof validateOnClient !== 'function') {
44
+ throw new Error('validateOnClient must be a function');
45
+ }
46
+ await validateOnClient({ body, query, params, endpoint }, validation ?? {}, fullSchema);
47
+ }
48
+ };
49
+ const internalOptions = {
50
+ name: staticMethodName,
51
+ httpMethod: httpMethod,
52
+ getEndpoint,
53
+ validate,
54
+ defaultHandler: defaultHandler_1.defaultHandler,
55
+ defaultStreamHandler: defaultStreamHandler_1.defaultStreamHandler,
56
+ };
57
+ const internalInput = {
58
+ ...options?.defaultOptions,
59
+ ...input,
60
+ body: input.body ?? null,
61
+ query: input.query ?? {},
62
+ params: input.params ?? {},
63
+ // TS workaround
64
+ fetcher: undefined,
65
+ validateOnClient: undefined,
66
+ };
67
+ delete internalInput.fetcher;
68
+ delete internalInput.validateOnClient;
69
+ if (!fetcher)
70
+ throw new Error('Fetcher is not provided');
71
+ const fetcherPromise = fetcher(internalOptions, internalInput);
72
+ if (!(fetcherPromise instanceof Promise))
73
+ return Promise.resolve(fetcherPromise);
74
+ return input.transform ? fetcherPromise.then(input.transform) : fetcherPromise;
75
+ };
76
+ handler.schema = handlerSchema;
77
+ handler.controllerSchema = controllerSchema;
78
+ handler.segmentSchema = segmentSchema;
79
+ handler.fullSchema = fullSchema;
80
+ // @ts-expect-error TODO
81
+ client[staticMethodName] = handler;
82
+ }
83
+ return client;
84
+ };
85
+ exports.createRPC = createRPC;
@@ -1,2 +1,2 @@
1
1
  export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at defaultHandler";
2
- export declare const _defaultHandler: (response: Response) => Promise<unknown>;
2
+ export declare const defaultHandler: (response: Response) => Promise<unknown>;
@@ -1,21 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._defaultHandler = exports.DEFAULT_ERROR_MESSAGE = void 0;
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
- const _defaultHandler = async (response) => {
6
+ const defaultHandler = async (response) => {
7
7
  let result;
8
8
  try {
9
9
  result = await response.json();
10
10
  }
11
11
  catch (e) {
12
12
  // handle parsing errors
13
- throw new HttpException_1._HttpException(response.status, e?.message ?? exports.DEFAULT_ERROR_MESSAGE);
13
+ throw new HttpException_1.HttpException(response.status, e?.message ?? exports.DEFAULT_ERROR_MESSAGE);
14
14
  }
15
15
  if (!response.ok) {
16
16
  // handle server errors
17
- throw new HttpException_1._HttpException(response.status, result?.message ?? exports.DEFAULT_ERROR_MESSAGE);
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
  };
21
- exports._defaultHandler = _defaultHandler;
22
+ exports.defaultHandler = defaultHandler;
@@ -1,4 +1,4 @@
1
- import type { _StreamAsyncIterator as StreamAsyncIterator } from './types';
1
+ import type { VovkStreamAsyncIterable } from './types';
2
2
  import '../utils/shim';
3
3
  export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at defaultStreamHandler";
4
- export declare const _defaultStreamHandler: (response: Response) => Promise<StreamAsyncIterator<unknown>>;
4
+ export declare const defaultStreamHandler: (response: Response) => Promise<VovkStreamAsyncIterable<unknown>>;
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._defaultStreamHandler = exports.DEFAULT_ERROR_MESSAGE = void 0;
3
+ exports.defaultStreamHandler = exports.DEFAULT_ERROR_MESSAGE = void 0;
4
4
  const types_1 = require("../types");
5
5
  const HttpException_1 = require("../HttpException");
6
6
  require("../utils/shim");
7
7
  exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at defaultStreamHandler';
8
- const _defaultStreamHandler = async (response) => {
8
+ const defaultStreamHandler = async (response) => {
9
9
  if (!response.ok) {
10
10
  let result;
11
11
  try {
@@ -15,10 +15,10 @@ const _defaultStreamHandler = async (response) => {
15
15
  // ignore parsing errors
16
16
  }
17
17
  // handle server errors
18
- throw new HttpException_1._HttpException(response.status, result.message ?? exports.DEFAULT_ERROR_MESSAGE);
18
+ throw new HttpException_1.HttpException(response.status, result.message ?? exports.DEFAULT_ERROR_MESSAGE);
19
19
  }
20
20
  if (!response.body)
21
- throw new HttpException_1._HttpException(types_1._HttpStatus.NULL, 'Stream body is falsy. Check your controller code.');
21
+ throw new HttpException_1.HttpException(types_1.HttpStatus.NULL, 'Stream body is falsy. Check your controller code.');
22
22
  const reader = response.body.getReader();
23
23
  // if streaming is too rapid, we need to make sure that the loop is stopped
24
24
  let canceled = false;
@@ -79,4 +79,4 @@ const _defaultStreamHandler = async (response) => {
79
79
  },
80
80
  };
81
81
  };
82
- exports._defaultStreamHandler = _defaultStreamHandler;
82
+ exports.defaultStreamHandler = defaultStreamHandler;
@@ -0,0 +1,3 @@
1
+ import type { VovkDefaultFetcherOptions, VovkClientFetcher } from './types';
2
+ export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at the defaultFetcher";
3
+ export declare const fetcher: VovkClientFetcher<VovkDefaultFetcherOptions>;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetcher = exports.DEFAULT_ERROR_MESSAGE = void 0;
4
+ const types_1 = require("../types");
5
+ const HttpException_1 = require("../HttpException");
6
+ exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at the defaultFetcher';
7
+ // defaultFetcher uses HttpException class to throw errors of fake HTTP status 0 if client-side error occurs
8
+ // For normal HTTP errors, it uses message and status code from the response of VovkErrorResponse type
9
+ const fetcher = async ({ httpMethod, getEndpoint, validate, defaultHandler, defaultStreamHandler }, { params, query, body, apiRoot = '/api', ...options }) => {
10
+ const endpoint = getEndpoint({ apiRoot, params, query });
11
+ if (!options.disableClientValidation) {
12
+ try {
13
+ await validate({ body, query, params, endpoint });
14
+ }
15
+ catch (e) {
16
+ // if HttpException is thrown, rethrow it
17
+ if (e instanceof HttpException_1.HttpException)
18
+ throw e;
19
+ // otherwise, throw HttpException with status 0
20
+ throw new HttpException_1.HttpException(types_1.HttpStatus.NULL, e.message ?? exports.DEFAULT_ERROR_MESSAGE, {
21
+ body,
22
+ query,
23
+ params,
24
+ endpoint,
25
+ });
26
+ }
27
+ }
28
+ const init = {
29
+ method: httpMethod,
30
+ ...options,
31
+ headers: {
32
+ ...options.headers,
33
+ accept: 'application/jsonl, application/json',
34
+ },
35
+ };
36
+ if (body instanceof FormData) {
37
+ init.body = body;
38
+ }
39
+ else if (body) {
40
+ init.body = JSON.stringify(body);
41
+ }
42
+ let response;
43
+ try {
44
+ response = await fetch(endpoint, init);
45
+ }
46
+ catch (e) {
47
+ // handle network errors
48
+ throw new HttpException_1.HttpException(types_1.HttpStatus.NULL, e?.message ?? exports.DEFAULT_ERROR_MESSAGE, {
49
+ body,
50
+ query,
51
+ params,
52
+ endpoint,
53
+ });
54
+ }
55
+ const contentType = response.headers.get('content-type');
56
+ if (contentType?.startsWith('application/json')) {
57
+ return defaultHandler(response);
58
+ }
59
+ if (contentType?.startsWith('text/plain') && contentType.includes('x-format=jsonlines')) {
60
+ return defaultStreamHandler(response);
61
+ }
62
+ return response;
63
+ };
64
+ exports.fetcher = fetcher;
@@ -1,4 +1,3 @@
1
- import { _clientizeController as clientizeController } from './clientizeController';
2
- import type { _VovkClientFetcher as VovkClientFetcher, _VovkClientOptions as VovkClientOptions, _VovkDefaultFetcherOptions as VovkDefaultFetcherOptions } from './types';
3
- export { clientizeController };
4
- export type { VovkClientFetcher, VovkClientOptions, VovkDefaultFetcherOptions };
1
+ export { createRPC } from './createRPC';
2
+ export { fetcher } from './fetcher';
3
+ export type { VovkClient, VovkClientFetcher, VovkClientOptions, VovkDefaultFetcherOptions, VovkValidateOnClient, VovkStreamAsyncIterable, } from './types';
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.clientizeController = void 0;
4
- const clientizeController_1 = require("./clientizeController");
5
- Object.defineProperty(exports, "clientizeController", { enumerable: true, get: function () { return clientizeController_1._clientizeController; } });
3
+ exports.fetcher = exports.createRPC = void 0;
4
+ var createRPC_1 = require("./createRPC");
5
+ Object.defineProperty(exports, "createRPC", { enumerable: true, get: function () { return createRPC_1.createRPC; } });
6
+ var fetcher_1 = require("./fetcher");
7
+ Object.defineProperty(exports, "fetcher", { enumerable: true, get: function () { return fetcher_1.fetcher; } });