vovk 3.0.0-draft.6 → 3.0.0-draft.60

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 (92) hide show
  1. package/README.md +8 -95
  2. package/{HttpException.d.ts → dist/HttpException.d.ts} +2 -2
  3. package/{HttpException.js → dist/HttpException.js} +3 -3
  4. package/{StreamResponse.d.ts → dist/StreamJSONResponse.d.ts} +3 -3
  5. package/{StreamResponse.js → dist/StreamJSONResponse.js} +5 -5
  6. package/{Segment.d.ts → dist/VovkApp.d.ts} +3 -3
  7. package/{Segment.js → dist/VovkApp.js} +26 -23
  8. package/dist/client/createRPC.d.ts +4 -0
  9. package/{client/clientizeController.js → dist/client/createRPC.js} +21 -39
  10. package/dist/client/defaultFetcher.d.ts +4 -0
  11. package/{client → dist/client}/defaultFetcher.js +11 -10
  12. package/{client → dist/client}/defaultHandler.d.ts +1 -1
  13. package/dist/client/defaultHandler.js +22 -0
  14. package/dist/client/defaultStreamHandler.d.ts +4 -0
  15. package/{client → dist/client}/defaultStreamHandler.js +5 -5
  16. package/dist/client/index.d.ts +2 -0
  17. package/dist/client/index.js +8 -0
  18. package/dist/client/types.d.ts +103 -0
  19. package/dist/createDecorator.d.ts +4 -0
  20. package/{createDecorator.js → dist/createDecorator.js} +4 -4
  21. package/{createSegment.d.ts → dist/createVovkApp.d.ts} +2 -3
  22. package/{createSegment.js → dist/createVovkApp.js} +25 -25
  23. package/dist/index.d.ts +59 -0
  24. package/dist/index.js +22 -0
  25. package/dist/types.d.ts +145 -0
  26. package/dist/types.js +65 -0
  27. package/dist/utils/generateStaticAPI.d.ts +4 -0
  28. package/{generateStaticAPI.js → dist/utils/generateStaticAPI.js} +3 -3
  29. package/{utils → dist/utils}/getSchema.d.ts +1 -2
  30. package/{utils → dist/utils}/getSchema.js +5 -16
  31. package/dist/utils/parseQuery.d.ts +25 -0
  32. package/dist/utils/parseQuery.js +156 -0
  33. package/dist/utils/reqForm.d.ts +2 -0
  34. package/dist/utils/reqForm.js +13 -0
  35. package/{utils → dist/utils}/reqMeta.d.ts +1 -2
  36. package/{utils → dist/utils}/reqQuery.d.ts +1 -2
  37. package/dist/utils/reqQuery.js +10 -0
  38. package/dist/utils/serializeQuery.d.ts +13 -0
  39. package/dist/utils/serializeQuery.js +65 -0
  40. package/dist/utils/setClientValidatorsForHandler.d.ts +5 -0
  41. package/{utils → dist/utils}/setClientValidatorsForHandler.js +4 -6
  42. package/package.json +5 -2
  43. package/src/HttpException.ts +16 -0
  44. package/src/StreamJSONResponse.ts +61 -0
  45. package/src/VovkApp.ts +242 -0
  46. package/src/client/createRPC.ts +119 -0
  47. package/src/client/defaultFetcher.ts +59 -0
  48. package/src/client/defaultHandler.ts +23 -0
  49. package/src/client/defaultStreamHandler.ts +88 -0
  50. package/src/client/index.ts +9 -0
  51. package/src/client/types.ts +120 -0
  52. package/src/createDecorator.ts +60 -0
  53. package/src/createVovkApp.ts +167 -0
  54. package/src/index.ts +69 -0
  55. package/src/types.ts +198 -0
  56. package/src/utils/generateStaticAPI.ts +18 -0
  57. package/src/utils/getSchema.ts +35 -0
  58. package/src/utils/parseQuery.ts +160 -0
  59. package/src/utils/reqForm.ts +16 -0
  60. package/src/utils/reqMeta.ts +16 -0
  61. package/src/utils/reqQuery.ts +6 -0
  62. package/src/utils/serializeQuery.ts +69 -0
  63. package/src/utils/setClientValidatorsForHandler.ts +45 -0
  64. package/src/utils/shim.ts +17 -0
  65. package/.npmignore +0 -2
  66. package/client/clientizeController.d.ts +0 -4
  67. package/client/defaultFetcher.d.ts +0 -4
  68. package/client/defaultHandler.js +0 -21
  69. package/client/defaultStreamHandler.d.ts +0 -4
  70. package/client/index.d.ts +0 -4
  71. package/client/index.js +0 -5
  72. package/client/types.d.ts +0 -102
  73. package/createDecorator.d.ts +0 -4
  74. package/generateStaticAPI.d.ts +0 -4
  75. package/index.d.ts +0 -60
  76. package/index.js +0 -20
  77. package/types.d.ts +0 -191
  78. package/types.js +0 -65
  79. package/utils/reqQuery.js +0 -25
  80. package/utils/setClientValidatorsForHandler.d.ts +0 -5
  81. package/worker/index.d.ts +0 -3
  82. package/worker/index.js +0 -7
  83. package/worker/promisifyWorker.d.ts +0 -2
  84. package/worker/promisifyWorker.js +0 -143
  85. package/worker/types.d.ts +0 -31
  86. package/worker/types.js +0 -2
  87. package/worker/worker.d.ts +0 -1
  88. package/worker/worker.js +0 -44
  89. /package/{client → dist/client}/types.js +0 -0
  90. /package/{utils → dist/utils}/reqMeta.js +0 -0
  91. /package/{utils → dist/utils}/shim.d.ts +0 -0
  92. /package/{utils → dist/utils}/shim.js +0 -0
package/README.md CHANGED
@@ -4,108 +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 for Next.js</strong>
8
-
7
+ <strong>REST + RPC = ♥️</strong>
9
8
  </p>
10
9
 
11
10
  <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>&nbsp;&nbsp;&nbsp;&nbsp;
19
- <a href="https://discord.gg/qdT8WEHUuP">Discord</a>&nbsp;&nbsp;&nbsp;&nbsp;
20
- <a href="https://github.com/finom/vovk-examples">Code Examples</a>&nbsp;&nbsp;&nbsp;&nbsp;
21
- <a href="https://github.com/finom/vovk-zod">vovk-zod</a>&nbsp;&nbsp;&nbsp;&nbsp;
22
- <a href="https://github.com/finom/vovk-hello-world">vovk-hello-world</a>&nbsp;&nbsp;&nbsp;&nbsp;
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>&nbsp;
27
- <a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg" alt="TypeScript" /></a>&nbsp;
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>
11
+ Back-end meta-framework for <a href="https://nextjs.org/docs/app">Next.js</a>
29
12
  </p>
30
13
 
14
+ ---
31
15
 
32
- <br />
16
+ ## vovk [![npm version](https://badge.fury.io/js/vovk.svg)](https://www.npmjs.com/package/vovk)
33
17
 
34
- Example back-end Controller Class:
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.
35
19
 
36
- ```ts
37
- // /src/modules/post/PostController.ts
38
- import { get, prefix, type VovkRequest } from 'vovk';
39
- import PostService from './PostService';
40
-
41
- @prefix('posts')
42
- export default class PostController {
43
- /**
44
- * Create a comment on a post
45
- * POST /api/posts/:postId/comments
46
- */
47
- @post(':postId/comments')
48
- static async createComment(
49
- // decorate NextRequest type with body and query types
50
- req: VovkRequest<
51
- { content: string; userId: string },
52
- { notificationType: 'push' | 'email' }
53
- >,
54
- { postId }: { postId: string } // params
55
- ) {
56
- // use standard Next.js API to get body and query
57
- const { content, userId } = await req.json();
58
- const notificationType = req.nextUrl.searchParams.get('notificationType');
59
-
60
- // perform the request to the database in a custom service
61
- return PostService.createComment({
62
- postId, content, userId, notificationType,
63
- });
64
- }
65
- }
20
+ ```sh
21
+ npm install vovk
66
22
  ```
67
23
 
68
- Example component that uses the auto-generated client library:
69
-
70
- ```tsx
71
- 'use client';
72
- import { useState } from 'react';
73
- import { PostController } from 'vovk-client';
74
- import type { VovkReturnType } from 'vovk';
75
-
76
- export default function Example() {
77
- const [response, setResponse] = useState<VovkReturnType<typeof PostController.createComment>>();
78
-
79
- return (
80
- <>
81
- <button
82
- onClick={async () => 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
- Post a comment
94
- </button>
95
- <div>{JSON.stringify(response)}</div>
96
- </>
97
- );
98
- }
99
- ```
100
-
101
- Alternatively, the resource can be fetched wit the regular `fetch` function:
102
-
103
- ```ts
104
- fetch('/api/posts/69?notificationType=push', {
105
- method: 'POST',
106
- body: JSON.stringify({
107
- content: 'Hello, World!',
108
- userId: '1',
109
- }),
110
- })
111
- ```
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,8 +1,8 @@
1
- import { _KnownAny as KnownAny, _StreamAbortMessage as StreamAbortMessage } from './types';
1
+ import type { KnownAny, StreamAbortMessage } from './types';
2
2
  import './utils/shim';
3
- export declare class _StreamResponse<T> extends Response {
3
+ export declare class StreamJSONResponse<T> extends Response {
4
4
  static defaultHeaders: {
5
- 'Content-Type': string;
5
+ 'content-type': string;
6
6
  };
7
7
  isClosed: boolean;
8
8
  controller?: ReadableStreamDefaultController;
@@ -1,10 +1,10 @@
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 {
5
+ class StreamJSONResponse extends Response {
6
6
  static defaultHeaders = {
7
- 'Content-Type': 'text/plain; charset=utf-8',
7
+ 'content-type': 'application/jsonl',
8
8
  };
9
9
  isClosed = false;
10
10
  controller;
@@ -23,7 +23,7 @@ class _StreamResponse extends Response {
23
23
  });
24
24
  super(readableStream, {
25
25
  ...init,
26
- headers: init?.headers ?? _StreamResponse.defaultHeaders,
26
+ headers: init?.headers ?? StreamJSONResponse.defaultHeaders,
27
27
  });
28
28
  this.readableStream = readableStream;
29
29
  this.encoder = encoder;
@@ -50,4 +50,4 @@ class _StreamResponse extends Response {
50
50
  this.close();
51
51
  }
52
52
  }
53
- exports._StreamResponse = _StreamResponse;
53
+ exports.StreamJSONResponse = StreamJSONResponse;
@@ -1,8 +1,8 @@
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 _Segment {
1
+ import { HttpMethod, HttpStatus, type RouteHandler, type VovkController, type DecoratorOptions, type VovkRequest } from './types';
2
+ export declare class VovkApp {
3
3
  #private;
4
4
  private static getHeadersFromOptions;
5
- _routes: Record<HttpMethod, Map<VovkController, Record<string, RouteHandler>>>;
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._Segment = void 0;
7
+ exports.VovkApp = void 0;
8
8
  const types_1 = require("./types");
9
9
  const HttpException_1 = require("./HttpException");
10
- const StreamResponse_1 = require("./StreamResponse");
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
- class _Segment {
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
- _routes = {
29
+ routes = {
29
30
  GET: new Map(),
30
31
  POST: new Map(),
31
32
  PUT: new Map(),
@@ -34,13 +35,13 @@ class _Segment {
34
35
  HEAD: new Map(),
35
36
  OPTIONS: new Map(),
36
37
  };
37
- GET = async (req, data) => this.#callMethod(types_1._HttpMethod.GET, req, await data.params);
38
- POST = async (req, data) => this.#callMethod(types_1._HttpMethod.POST, req, await data.params);
39
- PUT = async (req, data) => this.#callMethod(types_1._HttpMethod.PUT, req, await data.params);
40
- PATCH = async (req, data) => this.#callMethod(types_1._HttpMethod.PATCH, req, await data.params);
41
- DELETE = async (req, data) => this.#callMethod(types_1._HttpMethod.DELETE, req, await data.params);
42
- HEAD = async (req, data) => this.#callMethod(types_1._HttpMethod.HEAD, req, await data.params);
43
- OPTIONS = async (req, data) => this.#callMethod(types_1._HttpMethod.OPTIONS, req, await data.params);
38
+ GET = async (req, data) => this.#callMethod(types_1.HttpMethod.GET, req, await data.params);
39
+ POST = async (req, data) => this.#callMethod(types_1.HttpMethod.POST, req, await data.params);
40
+ PUT = async (req, data) => this.#callMethod(types_1.HttpMethod.PUT, req, await data.params);
41
+ PATCH = async (req, data) => this.#callMethod(types_1.HttpMethod.PATCH, req, await data.params);
42
+ DELETE = async (req, data) => this.#callMethod(types_1.HttpMethod.DELETE, req, await data.params);
43
+ HEAD = async (req, data) => this.#callMethod(types_1.HttpMethod.HEAD, req, await data.params);
44
+ OPTIONS = async (req, data) => this.#callMethod(types_1.HttpMethod.OPTIONS, req, await data.params);
44
45
  respond = (status, body, options) => {
45
46
  return new Response(JSON.stringify(body), {
46
47
  status,
@@ -50,22 +51,23 @@ 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._routes[httpMethod];
63
+ const controllers = this.routes[httpMethod];
62
64
  const methodParams = {};
63
65
  const path = params[Object.keys(params)[0]];
64
66
  const handlers = {};
65
67
  controllers.forEach((staticMethods, controller) => {
66
68
  const prefix = controller._prefix ?? '';
67
69
  if (!controller._activated) {
68
- throw new HttpException_1._HttpException(types_1._HttpStatus.INTERNAL_SERVER_ERROR, `Controller "${controller.name}" found but not activated`);
70
+ throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Controller "${controller.name}" found but not activated`);
69
71
  }
70
72
  Object.entries(staticMethods).forEach(([path, staticMethod]) => {
71
73
  const fullPath = [prefix, path].filter(Boolean).join('/');
@@ -96,7 +98,7 @@ class _Segment {
96
98
  if (routeSegment.startsWith(':')) {
97
99
  const parameter = routeSegment.slice(1);
98
100
  if (parameter in methodParams) {
99
- throw new HttpException_1._HttpException(types_1._HttpStatus.INTERNAL_SERVER_ERROR, `Duplicate parameter "${parameter}"`);
101
+ throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Duplicate parameter "${parameter}"`);
100
102
  }
101
103
  // If it's a parameterized segment, capture the parameter value.
102
104
  methodParams[parameter] = pathSegment;
@@ -110,7 +112,7 @@ class _Segment {
110
112
  });
111
113
  }
112
114
  if (methodKeys.length > 1) {
113
- throw new HttpException_1._HttpException(types_1._HttpStatus.INTERNAL_SERVER_ERROR, `Conflicting routes found: ${methodKeys.join(', ')}`);
115
+ throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, `Conflicting routes found: ${methodKeys.join(', ')}`);
114
116
  }
115
117
  const [methodKey] = methodKeys;
116
118
  if (methodKey) {
@@ -120,13 +122,14 @@ class _Segment {
120
122
  };
121
123
  const handler = getHandler();
122
124
  if (!handler) {
123
- return this.#respondWithError(types_1._HttpStatus.NOT_FOUND, `Route ${path.join('/')} is not found`);
125
+ return this.#respondWithError(types_1.HttpStatus.NOT_FOUND, `Route ${path.join('/')} is not found`);
124
126
  }
125
127
  const { staticMethod, controller } = handler;
126
128
  req.vovk = {
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 StreamResponse_1._StreamResponse({
143
+ const streamResponse = new StreamJSONResponse_1.StreamJSONResponse({
141
144
  headers: {
142
- ...StreamResponse_1._StreamResponse.defaultHeaders,
145
+ ...StreamJSONResponse_1.StreamJSONResponse.defaultHeaders,
143
146
  ..._a.getHeadersFromOptions(staticMethod._options),
144
147
  },
145
148
  });
@@ -171,12 +174,12 @@ class _Segment {
171
174
  console.error(onErrorError);
172
175
  }
173
176
  if (err.message !== 'NEXT_REDIRECT' && err.message !== 'NEXT_NOT_FOUND') {
174
- const statusCode = err.statusCode ?? types_1._HttpStatus.INTERNAL_SERVER_ERROR;
175
- return this.#respondWithError(statusCode, err.message, staticMethod._options);
177
+ const statusCode = err.statusCode ?? types_1.HttpStatus.INTERNAL_SERVER_ERROR;
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._Segment = _Segment;
182
- _a = _Segment;
184
+ exports.VovkApp = VovkApp;
185
+ _a = VovkApp;
@@ -0,0 +1,4 @@
1
+ import { type VovkControllerSchema, type KnownAny } from '../types';
2
+ import { type VovkClientOptions, type VovkClient, type VovkDefaultFetcherOptions } from './types';
3
+ declare const createRPC: <T, OPTS extends Record<string, KnownAny> = VovkDefaultFetcherOptions>(controllerSchema: VovkControllerSchema, segmentName?: string, options?: VovkClientOptions<OPTS>) => VovkClient<T, OPTS>;
4
+ export default createRPC;
@@ -3,68 +3,48 @@ 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._clientizeController = exports.ARRAY_QUERY_KEY = void 0;
7
6
  const defaultFetcher_1 = __importDefault(require("./defaultFetcher"));
8
7
  const defaultHandler_1 = require("./defaultHandler");
9
8
  const defaultStreamHandler_1 = require("./defaultStreamHandler");
10
- exports.ARRAY_QUERY_KEY = '_vovkarr';
9
+ const serializeQuery_1 = __importDefault(require("../utils/serializeQuery"));
11
10
  const trimPath = (path) => path.trim().replace(/^\/|\/$/g, '');
12
11
  const getHandlerPath = (endpoint, params, query) => {
13
12
  let result = endpoint;
14
13
  for (const [key, value] of Object.entries(params ?? {})) {
15
14
  result = result.replace(`:${key}`, value);
16
15
  }
17
- const searchParams = new URLSearchParams();
18
- let hasQuery = false;
19
- const arrayKeys = [];
20
- for (const [key, value] of Object.entries(query ?? {})) {
21
- if (typeof value === 'undefined')
22
- continue;
23
- if (value instanceof Array) {
24
- arrayKeys.push(key);
25
- for (const val of value) {
26
- searchParams.append(key, val);
27
- }
28
- }
29
- else {
30
- searchParams.set(key, value);
31
- }
32
- hasQuery = true;
33
- }
34
- if (arrayKeys.length) {
35
- searchParams.set(exports.ARRAY_QUERY_KEY, arrayKeys.join(','));
36
- }
37
- return `${result}${hasQuery ? '?' : ''}${searchParams.toString()}`;
16
+ const queryStr = query ? (0, serializeQuery_1.default)(query) : null;
17
+ return `${result}${queryStr ? '?' : ''}${queryStr}`;
38
18
  };
39
- const _clientizeController = (givenController, segmentName, options) => {
40
- const controller = givenController;
19
+ const createRPC = (controllerSchema, segmentName, options) => {
20
+ const schema = controllerSchema;
41
21
  const client = {};
42
- if (!controller)
43
- throw new Error(`Unable to clientize. Controller schema is not provided`);
44
- const schema = controller._handlers;
45
22
  if (!schema)
46
- throw new Error(`Unable to clientize. No schema for controller ${String(controller?._controllerName)}`);
47
- const controllerPrefix = trimPath(controller._prefix ?? '');
23
+ throw new Error(`Unable to clientize. Controller schema is not provided`);
24
+ if (!schema.handlers)
25
+ throw new Error(`Unable to clientize. No schema for controller ${String(schema?.controllerName)} provided`);
26
+ const controllerPrefix = trimPath(schema.prefix ?? '');
48
27
  const { fetcher: settingsFetcher = defaultFetcher_1.default } = options ?? {};
49
- for (const [staticMethodName, { path, httpMethod, clientValidators }] of Object.entries(schema)) {
50
- const getEndpoint = ({ prefix, params, query, }) => {
51
- const mainPrefix = (prefix.startsWith('http://') || prefix.startsWith('https://') || prefix.startsWith('/') ? '' : '/') +
52
- (prefix.endsWith('/') ? prefix : `${prefix}/`) +
28
+ for (const [staticMethodName, handlerSchema] of Object.entries(schema.handlers)) {
29
+ const { path, httpMethod, validation } = handlerSchema;
30
+ const getEndpoint = ({ apiRoot, params, query, }) => {
31
+ const mainPrefix = (apiRoot.startsWith('http://') || apiRoot.startsWith('https://') || apiRoot.startsWith('/') ? '' : '/') +
32
+ (apiRoot.endsWith('/') ? apiRoot : `${apiRoot}/`) +
53
33
  (segmentName ? `${segmentName}/` : '');
54
34
  return mainPrefix + getHandlerPath([controllerPrefix, path].filter(Boolean).join('/'), params, query);
55
35
  };
56
36
  const handler = (input = {}) => {
57
37
  const fetcher = input.fetcher ?? settingsFetcher;
58
38
  const validate = async ({ body, query, endpoint }) => {
59
- await (input.validateOnClient ?? options?.validateOnClient)?.({ body, query, endpoint }, clientValidators ?? {});
39
+ await (input.validateOnClient ?? options?.validateOnClient)?.({ body, query, endpoint }, validation ?? {});
60
40
  };
61
41
  const internalOptions = {
62
42
  name: staticMethodName,
63
43
  httpMethod,
64
44
  getEndpoint,
65
45
  validate,
66
- defaultHandler: defaultHandler_1._defaultHandler,
67
- defaultStreamHandler: defaultStreamHandler_1._defaultStreamHandler,
46
+ defaultHandler: defaultHandler_1.defaultHandler,
47
+ defaultStreamHandler: defaultStreamHandler_1.defaultStreamHandler,
68
48
  };
69
49
  const internalInput = {
70
50
  ...options?.defaultOptions,
@@ -85,9 +65,11 @@ const _clientizeController = (givenController, segmentName, options) => {
85
65
  return Promise.resolve(fetcherPromise);
86
66
  return input.transform ? fetcherPromise.then(input.transform) : fetcherPromise;
87
67
  };
88
- // @ts-expect-error TODO: Fix this
68
+ handler.schema = handlerSchema;
69
+ handler.controllerSchema = schema;
70
+ // @ts-expect-error TODO
89
71
  client[staticMethodName] = handler;
90
72
  }
91
73
  return client;
92
74
  };
93
- exports._clientizeController = _clientizeController;
75
+ exports.default = createRPC;
@@ -0,0 +1,4 @@
1
+ import type { VovkDefaultFetcherOptions, VovkClientFetcher } from './types';
2
+ export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at the defaultFetcher";
3
+ declare const defaultFetcher: VovkClientFetcher<VovkDefaultFetcherOptions>;
4
+ export default defaultFetcher;
@@ -3,21 +3,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_ERROR_MESSAGE = void 0;
4
4
  const types_1 = require("../types");
5
5
  const HttpException_1 = require("../HttpException");
6
- exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at defaultFetcher';
6
+ exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at the 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, prefix = '/api', ...options }) => {
10
- const endpoint = getEndpoint({ prefix, params, query });
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 });
14
14
  }
15
15
  catch (e) {
16
16
  // if HttpException is thrown, rethrow it
17
- if (e instanceof HttpException_1._HttpException)
17
+ if (e instanceof HttpException_1.HttpException)
18
18
  throw e;
19
19
  // otherwise, throw HttpException with status 0
20
- throw new HttpException_1._HttpException(types_1._HttpStatus.NULL, e.message ?? exports.DEFAULT_ERROR_MESSAGE);
20
+ throw new HttpException_1.HttpException(types_1.HttpStatus.NULL, e.message ?? exports.DEFAULT_ERROR_MESSAGE);
21
21
  }
22
22
  }
23
23
  const init = {
@@ -36,14 +36,15 @@ const defaultFetcher = async ({ httpMethod, getEndpoint, validate, defaultHandle
36
36
  }
37
37
  catch (e) {
38
38
  // handle network errors
39
- throw new HttpException_1._HttpException(types_1._HttpStatus.NULL, e?.message ?? exports.DEFAULT_ERROR_MESSAGE);
39
+ throw new HttpException_1.HttpException(types_1.HttpStatus.NULL, e?.message ?? exports.DEFAULT_ERROR_MESSAGE);
40
40
  }
41
- if (response.headers.get('content-type')?.includes('application/json')) {
42
- return defaultHandler(response);
43
- }
44
- if (response.headers.get('content-type')?.includes('text/plain; charset=utf-8')) {
41
+ const contentType = response.headers.get('content-type');
42
+ if (contentType?.includes('application/jsonl')) {
45
43
  return defaultStreamHandler(response);
46
44
  }
45
+ if (contentType?.includes('application/json')) {
46
+ return defaultHandler(response);
47
+ }
47
48
  return response;
48
49
  };
49
50
  exports.default = defaultFetcher;
@@ -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>;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultHandler = exports.DEFAULT_ERROR_MESSAGE = void 0;
4
+ const HttpException_1 = require("../HttpException");
5
+ exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at defaultHandler';
6
+ const defaultHandler = async (response) => {
7
+ let result;
8
+ try {
9
+ result = await response.json();
10
+ }
11
+ catch (e) {
12
+ // handle parsing errors
13
+ throw new HttpException_1.HttpException(response.status, e?.message ?? exports.DEFAULT_ERROR_MESSAGE);
14
+ }
15
+ if (!response.ok) {
16
+ // handle server errors
17
+ const errorResponse = result;
18
+ throw new HttpException_1.HttpException(response.status, errorResponse?.message ?? exports.DEFAULT_ERROR_MESSAGE, errorResponse?.cause);
19
+ }
20
+ return result;
21
+ };
22
+ exports.defaultHandler = defaultHandler;
@@ -0,0 +1,4 @@
1
+ import type { VovkStreamAsyncIterable } from './types';
2
+ import '../utils/shim';
3
+ export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at defaultStreamHandler";
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,2 @@
1
+ export { default as createRPC } from './createRPC';
2
+ export type { VovkClient, VovkClientFetcher, VovkClientOptions, VovkDefaultFetcherOptions, VovkValidateOnClient, VovkStreamAsyncIterable, } from './types';
@@ -0,0 +1,8 @@
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
+ var createRPC_1 = require("./createRPC");
8
+ Object.defineProperty(exports, "createRPC", { enumerable: true, get: function () { return __importDefault(createRPC_1).default; } });