vovk 3.0.0-draft.342 → 3.0.0-draft.344

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 (154) hide show
  1. package/cjs/HttpException.d.ts +7 -0
  2. package/cjs/HttpException.js +15 -0
  3. package/cjs/JSONLinesResponse.d.ts +19 -0
  4. package/cjs/JSONLinesResponse.js +93 -0
  5. package/cjs/VovkApp.d.ts +29 -0
  6. package/cjs/VovkApp.js +200 -0
  7. package/cjs/client/createRPC.d.ts +3 -0
  8. package/cjs/client/createRPC.js +137 -0
  9. package/cjs/client/defaultHandler.d.ts +6 -0
  10. package/cjs/client/defaultHandler.js +29 -0
  11. package/cjs/client/defaultStreamHandler.d.ts +9 -0
  12. package/cjs/client/defaultStreamHandler.js +96 -0
  13. package/cjs/client/fetcher.d.ts +16 -0
  14. package/cjs/client/fetcher.js +100 -0
  15. package/cjs/client/index.d.ts +4 -0
  16. package/cjs/client/index.js +10 -0
  17. package/cjs/client/progressive.d.ts +9 -0
  18. package/cjs/client/progressive.js +51 -0
  19. package/cjs/client/types.d.ts +126 -0
  20. package/cjs/client/types.js +2 -0
  21. package/cjs/createVovkApp.d.ts +63 -0
  22. package/cjs/createVovkApp.js +140 -0
  23. package/cjs/index.d.ts +65 -0
  24. package/cjs/index.js +38 -0
  25. package/cjs/openapi/error.d.ts +2 -0
  26. package/cjs/openapi/error.js +100 -0
  27. package/cjs/openapi/generateFnName.d.ts +23 -0
  28. package/cjs/openapi/generateFnName.js +81 -0
  29. package/cjs/openapi/index.d.ts +12 -0
  30. package/cjs/openapi/index.js +21 -0
  31. package/cjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.d.ts +3 -0
  32. package/cjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.js +67 -0
  33. package/cjs/openapi/openAPIToVovkSchema/index.d.ts +4 -0
  34. package/cjs/openapi/openAPIToVovkSchema/index.js +197 -0
  35. package/cjs/openapi/openAPIToVovkSchema/inlineRefs.d.ts +10 -0
  36. package/cjs/openapi/openAPIToVovkSchema/inlineRefs.js +102 -0
  37. package/cjs/openapi/vovkSchemaToOpenAPI.d.ts +9 -0
  38. package/cjs/openapi/vovkSchemaToOpenAPI.js +233 -0
  39. package/cjs/types.d.ts +405 -0
  40. package/cjs/types.js +74 -0
  41. package/cjs/utils/camelCase.d.ts +6 -0
  42. package/cjs/utils/camelCase.js +37 -0
  43. package/cjs/utils/createCodeExamples.d.ts +19 -0
  44. package/cjs/utils/createCodeExamples.js +110 -0
  45. package/cjs/utils/createDecorator.d.ts +6 -0
  46. package/cjs/utils/createDecorator.js +48 -0
  47. package/cjs/utils/createLLMTools.d.ts +44 -0
  48. package/cjs/utils/createLLMTools.js +118 -0
  49. package/cjs/utils/createStandardValidation.d.ts +81 -0
  50. package/cjs/utils/createStandardValidation.js +33 -0
  51. package/cjs/utils/generateStaticAPI.d.ts +4 -0
  52. package/cjs/utils/generateStaticAPI.js +30 -0
  53. package/cjs/utils/getJSONSchemaExample.d.ts +8 -0
  54. package/cjs/utils/getJSONSchemaExample.js +234 -0
  55. package/cjs/utils/getJSONSchemaSample.d.ts +2 -0
  56. package/cjs/utils/getJSONSchemaSample.js +167 -0
  57. package/cjs/utils/getSchema.d.ts +21 -0
  58. package/cjs/utils/getSchema.js +38 -0
  59. package/cjs/utils/multitenant.d.ts +24 -0
  60. package/cjs/utils/multitenant.js +170 -0
  61. package/cjs/utils/parseQuery.d.ts +25 -0
  62. package/cjs/utils/parseQuery.js +156 -0
  63. package/cjs/utils/reqForm.d.ts +2 -0
  64. package/cjs/utils/reqForm.js +33 -0
  65. package/cjs/utils/reqMeta.d.ts +2 -0
  66. package/cjs/utils/reqMeta.js +13 -0
  67. package/cjs/utils/reqQuery.d.ts +2 -0
  68. package/cjs/utils/reqQuery.js +10 -0
  69. package/cjs/utils/serializeQuery.d.ts +13 -0
  70. package/cjs/utils/serializeQuery.js +65 -0
  71. package/cjs/utils/setHandlerSchema.d.ts +4 -0
  72. package/cjs/utils/setHandlerSchema.js +15 -0
  73. package/cjs/utils/shim.d.ts +0 -0
  74. package/cjs/utils/shim.js +17 -0
  75. package/cjs/utils/upperFirst.d.ts +1 -0
  76. package/cjs/utils/upperFirst.js +6 -0
  77. package/cjs/utils/withValidationLibrary.d.ts +76 -0
  78. package/cjs/utils/withValidationLibrary.js +123 -0
  79. package/mjs/HttpException.d.ts +1 -1
  80. package/mjs/HttpException.js +5 -1
  81. package/mjs/JSONLinesResponse.d.ts +2 -2
  82. package/mjs/JSONLinesResponse.js +6 -2
  83. package/mjs/VovkApp.d.ts +2 -2
  84. package/mjs/VovkApp.js +30 -23
  85. package/mjs/client/createRPC.d.ts +2 -2
  86. package/mjs/client/createRPC.js +15 -8
  87. package/mjs/client/defaultHandler.d.ts +1 -1
  88. package/mjs/client/defaultHandler.js +9 -5
  89. package/mjs/client/defaultStreamHandler.d.ts +3 -3
  90. package/mjs/client/defaultStreamHandler.js +11 -7
  91. package/mjs/client/fetcher.d.ts +4 -4
  92. package/mjs/client/fetcher.js +13 -9
  93. package/mjs/client/index.d.ts +4 -4
  94. package/mjs/client/index.js +10 -3
  95. package/mjs/client/progressive.d.ts +2 -2
  96. package/mjs/client/progressive.js +4 -1
  97. package/mjs/client/types.d.ts +6 -6
  98. package/mjs/client/types.js +2 -1
  99. package/mjs/createVovkApp.d.ts +2 -2
  100. package/mjs/createVovkApp.js +19 -13
  101. package/mjs/index.d.ts +35 -35
  102. package/mjs/index.js +38 -15
  103. package/mjs/openapi/error.d.ts +2 -2
  104. package/mjs/openapi/error.js +55 -52
  105. package/mjs/openapi/generateFnName.d.ts +1 -1
  106. package/mjs/openapi/generateFnName.js +10 -5
  107. package/mjs/openapi/index.d.ts +4 -4
  108. package/mjs/openapi/index.js +11 -7
  109. package/mjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.d.ts +1 -1
  110. package/mjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.js +7 -4
  111. package/mjs/openapi/openAPIToVovkSchema/index.d.ts +1 -1
  112. package/mjs/openapi/openAPIToVovkSchema/index.js +20 -17
  113. package/mjs/openapi/openAPIToVovkSchema/inlineRefs.d.ts +1 -1
  114. package/mjs/openapi/openAPIToVovkSchema/inlineRefs.js +4 -1
  115. package/mjs/openapi/vovkSchemaToOpenAPI.d.ts +2 -2
  116. package/mjs/openapi/vovkSchemaToOpenAPI.js +13 -10
  117. package/mjs/types.d.ts +3 -3
  118. package/mjs/types.js +9 -6
  119. package/mjs/utils/camelCase.js +4 -1
  120. package/mjs/utils/createCodeExamples.d.ts +1 -1
  121. package/mjs/utils/createCodeExamples.js +8 -5
  122. package/mjs/utils/createDecorator.d.ts +1 -1
  123. package/mjs/utils/createDecorator.js +4 -1
  124. package/mjs/utils/createLLMTools.d.ts +1 -1
  125. package/mjs/utils/createLLMTools.js +4 -1
  126. package/mjs/utils/createStandardValidation.d.ts +2 -2
  127. package/mjs/utils/createStandardValidation.js +9 -6
  128. package/mjs/utils/generateStaticAPI.d.ts +1 -1
  129. package/mjs/utils/generateStaticAPI.js +4 -1
  130. package/mjs/utils/getJSONSchemaExample.d.ts +1 -1
  131. package/mjs/utils/getJSONSchemaExample.js +4 -1
  132. package/mjs/utils/getJSONSchemaSample.d.ts +1 -1
  133. package/mjs/utils/getJSONSchemaSample.js +4 -1
  134. package/mjs/utils/getSchema.d.ts +2 -2
  135. package/mjs/utils/getSchema.js +8 -4
  136. package/mjs/utils/multitenant.js +4 -1
  137. package/mjs/utils/parseQuery.d.ts +1 -1
  138. package/mjs/utils/parseQuery.js +4 -1
  139. package/mjs/utils/reqForm.d.ts +1 -1
  140. package/mjs/utils/reqForm.js +4 -1
  141. package/mjs/utils/reqMeta.d.ts +1 -1
  142. package/mjs/utils/reqMeta.js +4 -1
  143. package/mjs/utils/reqQuery.d.ts +1 -1
  144. package/mjs/utils/reqQuery.js +9 -3
  145. package/mjs/utils/serializeQuery.d.ts +1 -1
  146. package/mjs/utils/serializeQuery.js +4 -1
  147. package/mjs/utils/setHandlerSchema.d.ts +1 -1
  148. package/mjs/utils/setHandlerSchema.js +4 -1
  149. package/mjs/utils/shim.js +2 -1
  150. package/mjs/utils/upperFirst.js +4 -1
  151. package/mjs/utils/withValidationLibrary.d.ts +1 -1
  152. package/mjs/utils/withValidationLibrary.js +17 -11
  153. package/package.json +1 -5
  154. package/mjs/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,7 @@
1
+ import type { HttpStatus } from './types';
2
+ export declare class HttpException extends Error {
3
+ statusCode: HttpStatus;
4
+ message: string;
5
+ cause?: unknown;
6
+ constructor(statusCode: HttpStatus, message: string, cause?: unknown);
7
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpException = void 0;
4
+ class HttpException extends Error {
5
+ statusCode;
6
+ message;
7
+ cause;
8
+ constructor(statusCode, message, cause) {
9
+ super(message);
10
+ this.statusCode = statusCode;
11
+ this.message = message;
12
+ this.cause = cause;
13
+ }
14
+ }
15
+ exports.HttpException = HttpException;
@@ -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;
@@ -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
+ }
package/cjs/VovkApp.js ADDED
@@ -0,0 +1,200 @@
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 JSONLinesResponse_1 = require("./JSONLinesResponse");
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
+ class VovkApp {
15
+ static getHeadersFromOptions(options) {
16
+ if (!options)
17
+ return {};
18
+ const corsHeaders = {
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
+ };
23
+ const headers = {
24
+ ...(options.cors ? corsHeaders : {}),
25
+ ...(options.headers ?? {}),
26
+ };
27
+ return headers;
28
+ }
29
+ routes = {
30
+ GET: new Map(),
31
+ POST: new Map(),
32
+ PUT: new Map(),
33
+ PATCH: new Map(),
34
+ DELETE: new Map(),
35
+ HEAD: new Map(),
36
+ OPTIONS: new Map(),
37
+ };
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);
45
+ respond = (status, body, options) => {
46
+ return new Response(JSON.stringify(body), {
47
+ status,
48
+ headers: {
49
+ 'content-type': 'application/json',
50
+ ..._a.getHeadersFromOptions(options),
51
+ },
52
+ });
53
+ };
54
+ #respondWithError = (statusCode, message, options, cause) => {
55
+ return this.respond(statusCode, {
56
+ cause,
57
+ statusCode,
58
+ message,
59
+ isError: true,
60
+ }, options);
61
+ };
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;
122
+ const controllers = this.routes[httpMethod];
123
+ const path = params[Object.keys(params)[0]];
124
+ const handlers = {};
125
+ const xMeta = nextReq.headers.get('x-meta');
126
+ const xMetaHeader = xMeta && JSON.parse(xMeta);
127
+ if (xMetaHeader)
128
+ (0, reqMeta_1.default)(req, { xMetaHeader });
129
+ controllers.forEach((staticMethods, controller) => {
130
+ const prefix = controller._prefix ?? '';
131
+ Object.entries(staticMethods ?? {}).forEach(([path, staticMethod]) => {
132
+ const fullPath = [prefix, path].filter(Boolean).join('/');
133
+ handlers[fullPath] = { staticMethod, controller };
134
+ });
135
+ });
136
+ const { handler, methodParams } = this.#getHandler({ handlers, path, params });
137
+ if (!handler) {
138
+ return this.#respondWithError(types_1.HttpStatus.NOT_FOUND, `${Object.keys(handlers)} - Route ${path.join('/')} is not found`);
139
+ }
140
+ const { staticMethod, controller } = handler;
141
+ req.vovk = {
142
+ body: () => req.json(),
143
+ query: () => (0, reqQuery_1.default)(req),
144
+ meta: (meta) => (0, reqMeta_1.default)(req, meta),
145
+ form: () => (0, reqForm_1.default)(req),
146
+ params: () => methodParams,
147
+ };
148
+ try {
149
+ await staticMethod._options?.before?.call(controller, req);
150
+ const result = await staticMethod.call(controller, req, methodParams);
151
+ if (result instanceof Response) {
152
+ return result;
153
+ }
154
+ const isIterator = typeof result === 'object' &&
155
+ !!result &&
156
+ !(result instanceof Array) &&
157
+ ((Reflect.has(result, Symbol.iterator) &&
158
+ typeof result[Symbol.iterator] === 'function') ||
159
+ (Reflect.has(result, Symbol.asyncIterator) &&
160
+ typeof result[Symbol.asyncIterator] === 'function'));
161
+ if (isIterator) {
162
+ const streamResponse = new JSONLinesResponse_1.JSONLinesResponse(req, {
163
+ headers: {
164
+ ..._a.getHeadersFromOptions(staticMethod._options),
165
+ },
166
+ });
167
+ void (async () => {
168
+ try {
169
+ for await (const chunk of result) {
170
+ streamResponse.send(chunk);
171
+ }
172
+ }
173
+ catch (e) {
174
+ return streamResponse.throw(e);
175
+ }
176
+ return streamResponse.close();
177
+ })();
178
+ return streamResponse;
179
+ }
180
+ return this.respond(200, result ?? null, staticMethod._options);
181
+ }
182
+ catch (e) {
183
+ const err = e;
184
+ try {
185
+ await controller._onError?.(err, req);
186
+ }
187
+ catch (onErrorError) {
188
+ // eslint-disable-next-line no-console
189
+ console.error(onErrorError);
190
+ }
191
+ if (err.message !== 'NEXT_REDIRECT' && err.message !== 'NEXT_NOT_FOUND') {
192
+ const statusCode = err.statusCode || types_1.HttpStatus.INTERNAL_SERVER_ERROR;
193
+ return this.#respondWithError(statusCode, err.message, staticMethod._options, err.cause);
194
+ }
195
+ throw e; // if NEXT_REDIRECT or NEXT_NOT_FOUND, rethrow it
196
+ }
197
+ };
198
+ }
199
+ exports.VovkApp = VovkApp;
200
+ _a = VovkApp;
@@ -0,0 +1,3 @@
1
+ import type { KnownAny, VovkSchema } from '../types';
2
+ import type { VovkClient, VovkClientFetcher, VovkDefaultFetcherOptions } from './types';
3
+ export declare const createRPC: <T, OPTS extends Record<string, KnownAny> = Record<string, never>>(schema: VovkSchema, segmentName: string, rpcModuleName: string, fetcher?: VovkClientFetcher<OPTS>, options?: VovkDefaultFetcherOptions<OPTS>) => VovkClient<T, OPTS>;
@@ -0,0 +1,137 @@
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 = (schema, segmentName, rpcModuleName, fetcher = fetcher_1.fetcher, options) => {
21
+ const segmentNamePath = options?.segmentNameOverride ?? segmentName;
22
+ const segmentSchema = schema.segments[segmentName];
23
+ if (!segmentSchema)
24
+ throw new Error(`Unable to create RPC module. Segment schema is missing for segment "${segmentName}".`);
25
+ const controllerSchema = schema.segments[segmentName]?.controllers[rpcModuleName];
26
+ const client = {};
27
+ if (!controllerSchema) {
28
+ throw new Error(`Unable to create RPC module. Controller schema is missing for module "${rpcModuleName}" from segment "${segmentName}".`);
29
+ }
30
+ const controllerPrefix = trimPath(controllerSchema.prefix ?? '');
31
+ for (const [staticMethodName, handlerSchema] of Object.entries(controllerSchema.handlers ?? {})) {
32
+ const { path, httpMethod, validation } = handlerSchema;
33
+ const getEndpoint = ({ apiRoot, params, query, }) => {
34
+ const forceApiRoot = controllerSchema.forceApiRoot ?? segmentSchema.forceApiRoot;
35
+ apiRoot = apiRoot ?? forceApiRoot ?? options?.apiRoot ?? '/api';
36
+ const endpoint = [
37
+ apiRoot.startsWith('http://') || apiRoot.startsWith('https://') || apiRoot.startsWith('/') ? '' : '/',
38
+ apiRoot,
39
+ forceApiRoot ? '' : segmentNamePath,
40
+ getHandlerPath([controllerPrefix, path].filter(Boolean).join('/'), params, query),
41
+ ]
42
+ .filter(Boolean)
43
+ .join('/')
44
+ .replace(/([^:])\/+/g, '$1/'); // replace // by / but not for protocols (http://, https://)
45
+ return endpoint;
46
+ };
47
+ const handler = (async (input = {}) => {
48
+ const validate = async ({ body, query, params, endpoint, }) => {
49
+ const validateOnClient = input.validateOnClient ?? options?.validateOnClient;
50
+ if (validateOnClient && validation) {
51
+ if (typeof validateOnClient !== 'function') {
52
+ throw new Error('validateOnClient must be a function');
53
+ }
54
+ await validateOnClient({ body, query, params, endpoint }, validation, schema);
55
+ }
56
+ };
57
+ const internalOptions = {
58
+ name: staticMethodName,
59
+ httpMethod: httpMethod,
60
+ getEndpoint,
61
+ validate,
62
+ defaultHandler: defaultHandler_1.defaultHandler,
63
+ defaultStreamHandler: defaultStreamHandler_1.defaultStreamHandler,
64
+ schema: handlerSchema,
65
+ };
66
+ const internalInput = {
67
+ ...options,
68
+ ...input,
69
+ body: input.body ?? null,
70
+ query: input.query ?? {},
71
+ params: input.params ?? {},
72
+ meta: input.meta,
73
+ };
74
+ if (!fetcher)
75
+ throw new Error('Fetcher is not provided');
76
+ const [respData, resp] = await fetcher(internalOptions, internalInput);
77
+ return input.transform ? input.transform(respData, resp) : respData;
78
+ });
79
+ handler.schema = handlerSchema;
80
+ handler.controllerSchema = controllerSchema;
81
+ handler.segmentSchema = segmentSchema;
82
+ handler.fullSchema = schema;
83
+ handler.isRPC = true;
84
+ handler.path = [segmentNamePath, controllerPrefix, path].filter(Boolean).join('/');
85
+ // React Query integration
86
+ handler.queryKey = (key) => [
87
+ handler.segmentSchema.segmentName,
88
+ handler.controllerSchema.prefix ?? '',
89
+ handler.controllerSchema.rpcModuleName,
90
+ handler.schema.path,
91
+ handler.schema.httpMethod,
92
+ ...(key ?? []),
93
+ ];
94
+ handler.mutationKey = (key) => ['mutation', ...handler.queryKey(key)];
95
+ handler.queryOptions = ((input, opts) => {
96
+ const queryKey = handler.queryKey([input]);
97
+ return {
98
+ queryFn: async ({ client }) => {
99
+ const result = await handler(input);
100
+ if (Symbol.asyncIterator in result) {
101
+ void (async () => {
102
+ for await (const chunk of result) {
103
+ client.setQueryData(queryKey, (data) => [...data, chunk]);
104
+ }
105
+ })();
106
+ return [];
107
+ }
108
+ return result;
109
+ },
110
+ queryKey,
111
+ ...opts,
112
+ };
113
+ });
114
+ handler.mutationOptions = ((opts) => {
115
+ return {
116
+ mutationFn: async (input) => {
117
+ const result = await handler(input);
118
+ if (Symbol.asyncIterator in result) {
119
+ const chunks = [];
120
+ void (async () => {
121
+ for await (const chunk of result) {
122
+ chunks.push(chunk);
123
+ }
124
+ })();
125
+ }
126
+ return result;
127
+ },
128
+ mutationKey: handler.mutationKey(),
129
+ ...opts,
130
+ };
131
+ });
132
+ // @ts-expect-error TODO
133
+ client[staticMethodName] = handler;
134
+ }
135
+ return client;
136
+ };
137
+ exports.createRPC = createRPC;
@@ -0,0 +1,6 @@
1
+ import { VovkHandlerSchema } from '../types';
2
+ export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at defaultHandler";
3
+ export declare const defaultHandler: ({ response, schema }: {
4
+ response: Response;
5
+ schema: VovkHandlerSchema;
6
+ }) => Promise<unknown>;
@@ -0,0 +1,29 @@
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
+ // 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 }) => {
11
+ let result;
12
+ try {
13
+ result = await response.json();
14
+ }
15
+ catch (e) {
16
+ // handle parsing errors
17
+ throw new HttpException_1.HttpException(response.status, e?.message ?? exports.DEFAULT_ERROR_MESSAGE);
18
+ }
19
+ if (!response.ok) {
20
+ const errorKey = schema.openapi && 'x-errorMessageKey' in schema.openapi
21
+ ? schema.openapi['x-errorMessageKey']
22
+ : 'message';
23
+ // handle server errors
24
+ const errorResponse = result;
25
+ throw new HttpException_1.HttpException(response.status, getNestedValue(errorResponse, errorKey) ?? exports.DEFAULT_ERROR_MESSAGE, errorResponse?.cause ?? JSON.stringify(result));
26
+ }
27
+ return result;
28
+ };
29
+ exports.defaultHandler = defaultHandler;
@@ -0,0 +1,9 @@
1
+ import { VovkHandlerSchema } from '../types';
2
+ import type { VovkStreamAsyncIterable } from './types';
3
+ import '../utils/shim';
4
+ export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at defaultStreamHandler";
5
+ export declare const defaultStreamHandler: ({ response, controller, }: {
6
+ response: Response;
7
+ controller: AbortController;
8
+ schema: VovkHandlerSchema;
9
+ }) => Promise<VovkStreamAsyncIterable<unknown>>;
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultStreamHandler = exports.DEFAULT_ERROR_MESSAGE = void 0;
4
+ const types_1 = require("../types");
5
+ const HttpException_1 = require("../HttpException");
6
+ require("../utils/shim");
7
+ exports.DEFAULT_ERROR_MESSAGE = 'Unknown error at defaultStreamHandler';
8
+ const defaultStreamHandler = async ({ response, controller, }) => {
9
+ if (!response.ok) {
10
+ let result;
11
+ try {
12
+ result = await response.json();
13
+ }
14
+ catch {
15
+ // ignore parsing errors
16
+ }
17
+ // handle server errors
18
+ throw new HttpException_1.HttpException(response.status, result.message ?? exports.DEFAULT_ERROR_MESSAGE);
19
+ }
20
+ if (!response.body)
21
+ throw new HttpException_1.HttpException(types_1.HttpStatus.NULL, 'Stream body is falsy. Check your controller code.');
22
+ const reader = response.body.getReader();
23
+ // if streaming is too rapid, we need to make sure that the loop is stopped
24
+ let canceled = false;
25
+ const subscribers = new Set();
26
+ async function* asyncIterator() {
27
+ let prepend = '';
28
+ let i = 0;
29
+ while (true) {
30
+ let value;
31
+ try {
32
+ let done;
33
+ ({ value, done } = await reader.read());
34
+ if (done)
35
+ break;
36
+ }
37
+ catch (error) {
38
+ await reader.cancel();
39
+ const err = new Error('Stream error. ' + String(error));
40
+ err.cause = error;
41
+ throw err;
42
+ }
43
+ // typeof value === 'number' is a workaround for React Native
44
+ const string = typeof value === 'number' ? String.fromCharCode(value) : new TextDecoder().decode(value);
45
+ prepend += string;
46
+ const lines = prepend.split('\n').filter(Boolean);
47
+ for (const line of lines) {
48
+ let data;
49
+ try {
50
+ data = JSON.parse(line);
51
+ prepend = '';
52
+ }
53
+ catch {
54
+ break;
55
+ }
56
+ if (data) {
57
+ subscribers.forEach((cb) => {
58
+ if (!canceled)
59
+ cb(data, i);
60
+ });
61
+ i++;
62
+ if ('isError' in data && 'reason' in data) {
63
+ const upcomingError = data.reason;
64
+ await reader.cancel();
65
+ if (typeof upcomingError === 'string') {
66
+ throw new Error(upcomingError);
67
+ }
68
+ throw upcomingError;
69
+ }
70
+ else if (!canceled) {
71
+ yield data;
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ return {
78
+ status: response.status,
79
+ [Symbol.asyncIterator]: asyncIterator,
80
+ [Symbol.dispose]: () => controller.abort(),
81
+ [Symbol.asyncDispose]: () => controller.abort(),
82
+ onIterate: (cb) => {
83
+ if (canceled)
84
+ return () => { };
85
+ subscribers.add(cb);
86
+ return () => {
87
+ subscribers.delete(cb);
88
+ };
89
+ },
90
+ abort: () => {
91
+ canceled = true;
92
+ return controller.abort();
93
+ },
94
+ };
95
+ };
96
+ exports.defaultStreamHandler = defaultStreamHandler;
@@ -0,0 +1,16 @@
1
+ import type { VovkDefaultFetcherOptions, VovkClientFetcher } from './types';
2
+ import { KnownAny } from '../types';
3
+ import { HttpException } from '../HttpException';
4
+ export declare const DEFAULT_ERROR_MESSAGE = "Unknown error at default fetcher";
5
+ export declare function createFetcher<T>({ prepareRequestInit, transformResponse, onError, }?: {
6
+ prepareRequestInit?: (init: RequestInit, options: VovkDefaultFetcherOptions<T>) => RequestInit | Promise<RequestInit>;
7
+ transformResponse?: (respData: KnownAny, options: VovkDefaultFetcherOptions<T>, response: Response, init: RequestInit) => unknown | Promise<unknown>;
8
+ onError?: (error: HttpException, options: VovkDefaultFetcherOptions<T>, response: Response | null, init: RequestInit | null, respData: unknown | null) => void | Promise<void>;
9
+ }): VovkClientFetcher<VovkDefaultFetcherOptions<T>>;
10
+ export declare const fetcher: VovkClientFetcher<{
11
+ apiRoot?: string;
12
+ disableClientValidation?: boolean;
13
+ validateOnClient?: import("./types").VovkValidateOnClient;
14
+ interpretAs?: string;
15
+ init?: RequestInit;
16
+ }>;