vovk 3.0.0-draft.99 → 3.0.0

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 (167) hide show
  1. package/README.md +22 -13
  2. package/bin/index.mjs +10 -0
  3. package/dist/client/createRPC.d.ts +13 -3
  4. package/dist/client/createRPC.js +112 -50
  5. package/dist/client/defaultHandler.d.ts +5 -1
  6. package/dist/client/defaultHandler.js +12 -9
  7. package/dist/client/defaultStreamHandler.d.ts +16 -4
  8. package/dist/client/defaultStreamHandler.js +259 -62
  9. package/dist/client/fetcher.d.ts +41 -3
  10. package/dist/client/fetcher.js +125 -60
  11. package/dist/client/progressive.d.ts +15 -0
  12. package/dist/client/progressive.js +56 -0
  13. package/dist/{utils → client}/serializeQuery.d.ts +2 -2
  14. package/dist/{utils → client}/serializeQuery.js +1 -4
  15. package/dist/core/HttpException.d.ts +16 -0
  16. package/dist/core/HttpException.js +26 -0
  17. package/dist/core/JSONLinesResponder.d.ts +42 -0
  18. package/dist/core/JSONLinesResponder.js +92 -0
  19. package/dist/core/controllersToStaticParams.d.ts +13 -0
  20. package/dist/core/controllersToStaticParams.js +36 -0
  21. package/dist/core/createDecorator.d.ts +12 -0
  22. package/dist/{createDecorator.js → core/createDecorator.js} +18 -12
  23. package/dist/core/decorators.d.ts +59 -0
  24. package/dist/core/decorators.js +132 -0
  25. package/dist/core/getSchema.d.ts +21 -0
  26. package/dist/core/getSchema.js +31 -0
  27. package/dist/core/initSegment.d.ts +33 -0
  28. package/dist/core/initSegment.js +35 -0
  29. package/dist/core/multitenant.d.ts +33 -0
  30. package/dist/core/multitenant.js +132 -0
  31. package/dist/core/resolveGeneratorConfigValues.d.ts +19 -0
  32. package/dist/core/resolveGeneratorConfigValues.js +59 -0
  33. package/dist/{utils → core}/setHandlerSchema.d.ts +2 -2
  34. package/dist/{utils → core}/setHandlerSchema.js +1 -4
  35. package/dist/core/toDownloadResponse.d.ts +11 -0
  36. package/dist/core/toDownloadResponse.js +25 -0
  37. package/dist/core/vovkApp.d.ts +36 -0
  38. package/dist/core/vovkApp.js +316 -0
  39. package/dist/index.d.ts +25 -59
  40. package/dist/index.js +23 -23
  41. package/dist/internal.d.ts +17 -0
  42. package/dist/internal.js +10 -0
  43. package/dist/openapi/error.d.ts +2 -0
  44. package/dist/openapi/error.js +97 -0
  45. package/dist/openapi/openAPIToVovkSchema/applyComponentsSchemas.d.ts +3 -0
  46. package/dist/openapi/openAPIToVovkSchema/applyComponentsSchemas.js +65 -0
  47. package/dist/openapi/openAPIToVovkSchema/index.d.ts +5 -0
  48. package/dist/openapi/openAPIToVovkSchema/index.js +153 -0
  49. package/dist/openapi/openAPIToVovkSchema/inlineRefs.d.ts +9 -0
  50. package/dist/openapi/openAPIToVovkSchema/inlineRefs.js +99 -0
  51. package/dist/openapi/operation.d.ts +10 -0
  52. package/dist/openapi/operation.js +19 -0
  53. package/dist/openapi/tool.d.ts +2 -0
  54. package/dist/openapi/tool.js +12 -0
  55. package/dist/openapi/vovkSchemaToOpenAPI.d.ts +21 -0
  56. package/dist/openapi/vovkSchemaToOpenAPI.js +250 -0
  57. package/dist/req/bufferBody.d.ts +1 -0
  58. package/dist/req/bufferBody.js +30 -0
  59. package/dist/req/parseBody.d.ts +4 -0
  60. package/dist/req/parseBody.js +49 -0
  61. package/dist/req/parseForm.d.ts +1 -0
  62. package/dist/req/parseForm.js +24 -0
  63. package/dist/{utils → req}/parseQuery.d.ts +1 -2
  64. package/dist/{utils → req}/parseQuery.js +2 -5
  65. package/dist/req/reqMeta.d.ts +2 -0
  66. package/dist/{utils → req}/reqMeta.js +1 -4
  67. package/dist/req/reqQuery.d.ts +2 -0
  68. package/dist/req/reqQuery.js +4 -0
  69. package/dist/req/validateContentType.d.ts +1 -0
  70. package/dist/req/validateContentType.js +32 -0
  71. package/dist/samples/createCodeSamples.d.ts +20 -0
  72. package/dist/samples/createCodeSamples.js +293 -0
  73. package/dist/samples/objectToCode.d.ts +8 -0
  74. package/dist/samples/objectToCode.js +38 -0
  75. package/dist/samples/schemaToCode.d.ts +11 -0
  76. package/dist/samples/schemaToCode.js +264 -0
  77. package/dist/samples/schemaToObject.d.ts +2 -0
  78. package/dist/samples/schemaToObject.js +164 -0
  79. package/dist/samples/schemaToTsType.d.ts +2 -0
  80. package/dist/samples/schemaToTsType.js +114 -0
  81. package/dist/tools/ToModelOutput.d.ts +8 -0
  82. package/dist/tools/ToModelOutput.js +10 -0
  83. package/dist/tools/createTool.d.ts +126 -0
  84. package/dist/tools/createTool.js +6 -0
  85. package/dist/tools/createToolFactory.d.ts +135 -0
  86. package/dist/tools/createToolFactory.js +61 -0
  87. package/dist/tools/deriveTools.d.ts +46 -0
  88. package/dist/tools/deriveTools.js +134 -0
  89. package/dist/tools/toModelOutputDefault.d.ts +7 -0
  90. package/dist/tools/toModelOutputDefault.js +7 -0
  91. package/dist/tools/toModelOutputMCP.d.ts +30 -0
  92. package/dist/tools/toModelOutputMCP.js +54 -0
  93. package/dist/tsconfig.tsbuildinfo +1 -0
  94. package/dist/types/client.d.ts +140 -0
  95. package/dist/types/client.js +1 -0
  96. package/dist/types/config.d.ts +151 -0
  97. package/dist/types/config.js +1 -0
  98. package/dist/types/core.d.ts +115 -0
  99. package/dist/types/core.js +1 -0
  100. package/dist/types/enums.d.ts +75 -0
  101. package/dist/{types.js → types/enums.js} +21 -9
  102. package/dist/types/inference.d.ts +117 -0
  103. package/dist/types/inference.js +1 -0
  104. package/dist/types/json-schema.d.ts +51 -0
  105. package/dist/types/json-schema.js +1 -0
  106. package/dist/types/operation.d.ts +5 -0
  107. package/dist/types/operation.js +1 -0
  108. package/dist/types/package.d.ts +544 -0
  109. package/dist/types/package.js +5 -0
  110. package/dist/types/request.d.ts +48 -0
  111. package/dist/types/request.js +1 -0
  112. package/dist/types/standard-schema.d.ts +117 -0
  113. package/dist/types/standard-schema.js +6 -0
  114. package/dist/types/tools.d.ts +43 -0
  115. package/dist/types/tools.js +1 -0
  116. package/dist/types/utils.d.ts +9 -0
  117. package/dist/types/utils.js +1 -0
  118. package/dist/types/validation.d.ts +48 -0
  119. package/dist/types/validation.js +1 -0
  120. package/dist/utils/camelCase.d.ts +6 -0
  121. package/dist/utils/camelCase.js +34 -0
  122. package/dist/utils/deepExtend.d.ts +53 -0
  123. package/dist/utils/deepExtend.js +128 -0
  124. package/dist/utils/fileNameToDisposition.d.ts +1 -0
  125. package/dist/utils/fileNameToDisposition.js +3 -0
  126. package/dist/utils/shim.d.ts +1 -0
  127. package/dist/utils/shim.js +1 -1
  128. package/dist/utils/toKebabCase.d.ts +1 -0
  129. package/dist/utils/toKebabCase.js +5 -0
  130. package/dist/utils/trimPath.d.ts +1 -0
  131. package/dist/utils/trimPath.js +1 -0
  132. package/dist/utils/upperFirst.d.ts +1 -0
  133. package/dist/utils/upperFirst.js +3 -0
  134. package/dist/validation/createStandardValidation.d.ts +268 -0
  135. package/dist/validation/createStandardValidation.js +45 -0
  136. package/dist/validation/createValidateOnClient.d.ts +14 -0
  137. package/dist/validation/createValidateOnClient.js +23 -0
  138. package/dist/validation/procedure.d.ts +261 -0
  139. package/dist/validation/procedure.js +8 -0
  140. package/dist/validation/withValidationLibrary.d.ts +119 -0
  141. package/dist/validation/withValidationLibrary.js +174 -0
  142. package/package.json +44 -10
  143. package/dist/HttpException.d.ts +0 -7
  144. package/dist/HttpException.js +0 -15
  145. package/dist/StreamJSONResponse.d.ts +0 -14
  146. package/dist/StreamJSONResponse.js +0 -57
  147. package/dist/VovkApp.d.ts +0 -29
  148. package/dist/VovkApp.js +0 -188
  149. package/dist/client/index.d.ts +0 -3
  150. package/dist/client/index.js +0 -7
  151. package/dist/client/types.d.ts +0 -104
  152. package/dist/client/types.js +0 -2
  153. package/dist/createDecorator.d.ts +0 -6
  154. package/dist/createVovkApp.d.ts +0 -62
  155. package/dist/createVovkApp.js +0 -118
  156. package/dist/types.d.ts +0 -220
  157. package/dist/utils/generateStaticAPI.d.ts +0 -4
  158. package/dist/utils/generateStaticAPI.js +0 -18
  159. package/dist/utils/getSchema.d.ts +0 -20
  160. package/dist/utils/getSchema.js +0 -33
  161. package/dist/utils/reqForm.d.ts +0 -2
  162. package/dist/utils/reqForm.js +0 -13
  163. package/dist/utils/reqMeta.d.ts +0 -2
  164. package/dist/utils/reqQuery.d.ts +0 -2
  165. package/dist/utils/reqQuery.js +0 -10
  166. package/dist/utils/withValidation.d.ts +0 -20
  167. package/dist/utils/withValidation.js +0 -72
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = serializeQuery;
4
1
  /**
5
2
  * Recursively build query parameters from an object.
6
3
  *
@@ -50,7 +47,7 @@ function buildParams(key, value) {
50
47
  * @param obj - The input object to be serialized
51
48
  * @returns - A bracket-based query string (without leading "?")
52
49
  */
53
- function serializeQuery(obj) {
50
+ export function serializeQuery(obj) {
54
51
  if (!obj || typeof obj !== 'object')
55
52
  return '';
56
53
  // Collect query segments
@@ -0,0 +1,16 @@
1
+ import type { VovkErrorResponse } from '../types/core.js';
2
+ import type { HttpStatus } from '../types/enums.js';
3
+ /**
4
+ * Represents an HTTP exception with a status code and message.
5
+ * @example
6
+ * ```ts
7
+ * throw new HttpException(HttpStatus.BAD_REQUEST, 'Invalid request data');
8
+ * ```
9
+ */
10
+ export declare class HttpException extends Error {
11
+ statusCode: HttpStatus;
12
+ message: string;
13
+ cause?: unknown;
14
+ constructor(statusCode: HttpStatus, message: string, cause?: unknown);
15
+ toJSON(): VovkErrorResponse;
16
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Represents an HTTP exception with a status code and message.
3
+ * @example
4
+ * ```ts
5
+ * throw new HttpException(HttpStatus.BAD_REQUEST, 'Invalid request data');
6
+ * ```
7
+ */
8
+ export class HttpException extends Error {
9
+ statusCode;
10
+ message;
11
+ cause;
12
+ constructor(statusCode, message, cause) {
13
+ super(message);
14
+ this.statusCode = statusCode;
15
+ this.message = message;
16
+ this.cause = cause;
17
+ }
18
+ toJSON() {
19
+ return {
20
+ isError: true,
21
+ statusCode: this.statusCode,
22
+ message: this.message,
23
+ ...(this.cause ? { cause: this.cause } : {}),
24
+ };
25
+ }
26
+ }
@@ -0,0 +1,42 @@
1
+ import type { StreamAbortMessage } from '../types/core.js';
2
+ import '../utils/shim.js';
3
+ export declare abstract class Responder {
4
+ response: Response;
5
+ }
6
+ /**
7
+ * A Responder subclass for streaming JSON Lines (JSONL) data.
8
+ * @see https://vovk.dev/jsonlines
9
+ * @param request The incoming Request object.
10
+ * @param getResponse Optional function to create a custom Response object.
11
+ * @example
12
+ * ```ts
13
+ * import { JSONLinesResponder } from 'vovk';
14
+ *
15
+ * const responder = new JSONLinesResponder<MyItemType>(request, (responder) => {
16
+ * return new Response(responder.readableStream, { headers: responder.headers });
17
+ * });
18
+ *
19
+ * // Send items
20
+ * responder.send({ ... });
21
+ * // Close the stream when done
22
+ * responder.close();
23
+ * // Or throw an error
24
+ * responder.throw(new Error('Something went wrong'));
25
+ * // get the Response object, headers, etc.
26
+ * const { response, headers } = responder;
27
+ * ```
28
+ */
29
+ export declare class JSONLinesResponder<T> extends Responder {
30
+ private isClosed;
31
+ private i;
32
+ private controller?;
33
+ private readonly encoder;
34
+ readonly readableStream: ReadableStream | null;
35
+ readonly headers: Record<string, string>;
36
+ onBeforeSend: (item: T, i: number) => T | Promise<T>;
37
+ constructor(request?: Request | null, getResponse?: (responder: JSONLinesResponder<T>) => Response);
38
+ readonly send: (item: T) => Promise<void>;
39
+ sendLineOrError: (data: T | StreamAbortMessage) => void;
40
+ readonly close: () => void;
41
+ readonly throw: (e: unknown) => void;
42
+ }
@@ -0,0 +1,92 @@
1
+ import '../utils/shim.js';
2
+ export class Responder {
3
+ response;
4
+ }
5
+ /**
6
+ * A Responder subclass for streaming JSON Lines (JSONL) data.
7
+ * @see https://vovk.dev/jsonlines
8
+ * @param request The incoming Request object.
9
+ * @param getResponse Optional function to create a custom Response object.
10
+ * @example
11
+ * ```ts
12
+ * import { JSONLinesResponder } from 'vovk';
13
+ *
14
+ * const responder = new JSONLinesResponder<MyItemType>(request, (responder) => {
15
+ * return new Response(responder.readableStream, { headers: responder.headers });
16
+ * });
17
+ *
18
+ * // Send items
19
+ * responder.send({ ... });
20
+ * // Close the stream when done
21
+ * responder.close();
22
+ * // Or throw an error
23
+ * responder.throw(new Error('Something went wrong'));
24
+ * // get the Response object, headers, etc.
25
+ * const { response, headers } = responder;
26
+ * ```
27
+ */
28
+ export class JSONLinesResponder extends Responder {
29
+ isClosed = false;
30
+ i = 0;
31
+ controller;
32
+ encoder;
33
+ readableStream;
34
+ headers;
35
+ onBeforeSend = (item) => item;
36
+ constructor(request, getResponse) {
37
+ super();
38
+ const encoder = new TextEncoder();
39
+ let readableController;
40
+ const readableStream = new ReadableStream({
41
+ cancel: () => {
42
+ this.isClosed = true;
43
+ },
44
+ start: (controller) => {
45
+ readableController = controller;
46
+ },
47
+ });
48
+ const accept = request?.headers?.get('accept');
49
+ const headers = {
50
+ 'content-type': accept?.includes('application/jsonl')
51
+ ? 'application/jsonl; charset=utf-8'
52
+ : 'text/plain; charset=utf-8',
53
+ };
54
+ this.headers = headers;
55
+ this.readableStream = readableStream;
56
+ this.encoder = encoder;
57
+ this.controller = readableController;
58
+ this.response = getResponse?.(this) ?? new Response(readableStream, { headers });
59
+ request?.signal?.addEventListener('abort', this.close, { once: true });
60
+ // this will make promise on the client-side to resolve immediately, before sending the first JSON line
61
+ this.controller?.enqueue(encoder?.encode(''));
62
+ }
63
+ send = async (item) => {
64
+ try {
65
+ // onBeforeSend is set by withValidationLibrary if iteration validation is provided
66
+ // in case if data is streamed immediately in a controller/service, we're going to lose the first iteration validation
67
+ // the await with zero timeout ensures onBeforeSend is set before the first send
68
+ await new Promise((resolve) => setTimeout(resolve, 0));
69
+ this.sendLineOrError(await this.onBeforeSend(item, this.i++));
70
+ }
71
+ catch (e) {
72
+ this.throw(e);
73
+ }
74
+ };
75
+ sendLineOrError = (data) => {
76
+ const { controller, encoder } = this;
77
+ if (this.isClosed)
78
+ return;
79
+ controller?.enqueue(encoder?.encode(JSON.stringify(data) + '\n'));
80
+ };
81
+ close = () => {
82
+ const { controller } = this;
83
+ if (this.isClosed)
84
+ return;
85
+ this.isClosed = true;
86
+ controller?.close();
87
+ };
88
+ throw = (e) => {
89
+ this.sendLineOrError({ isError: true, reason: e instanceof Error ? e.message : e });
90
+ return this.close();
91
+ };
92
+ }
@@ -0,0 +1,13 @@
1
+ import type { StaticClass } from '../types/utils.js';
2
+ /**
3
+ * Generates static API of the given controllers for a static segment.
4
+ * @see https://vovk.dev/segment
5
+ * @example
6
+ * ```ts
7
+ * export function generateStaticParams() {
8
+ * return controllersToStaticParams(controllers);
9
+ * }
10
+ */
11
+ export declare function controllersToStaticParams(c: Record<string, StaticClass>, slug?: string): {
12
+ [slug]: string[];
13
+ }[];
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Generates static API of the given controllers for a static segment.
3
+ * @see https://vovk.dev/segment
4
+ * @example
5
+ * ```ts
6
+ * export function generateStaticParams() {
7
+ * return controllersToStaticParams(controllers);
8
+ * }
9
+ */
10
+ export function controllersToStaticParams(c, slug = 'vovk') {
11
+ const controllers = c;
12
+ return [
13
+ { [slug]: ['_schema_'] },
14
+ ...Object.values(controllers)
15
+ .map((controller) => {
16
+ const handlers = controller._handlers;
17
+ const splitPrefix = controller._prefix?.split('/') ?? [];
18
+ return Object.entries(handlers ?? {})
19
+ .map(([name, handler]) => {
20
+ const staticParams = controller._handlersMetadata?.[name]?.staticParams;
21
+ if (staticParams?.length) {
22
+ return staticParams.map((paramsItem) => {
23
+ let path = handler.path;
24
+ for (const [key, value] of Object.entries(paramsItem ?? {})) {
25
+ path = path.replace(`{${key}}`, value);
26
+ }
27
+ return { [slug]: [...splitPrefix, ...path.split('/')].filter(Boolean) };
28
+ });
29
+ }
30
+ return [{ [slug]: [...splitPrefix, ...handler.path.split('/')].filter(Boolean) }];
31
+ })
32
+ .flat();
33
+ })
34
+ .flat(),
35
+ ];
36
+ }
@@ -0,0 +1,12 @@
1
+ import type { VovkHandlerSchema, VovkController } from '../types/core.js';
2
+ import type { VovkRequest } from '../types/request.js';
3
+ import type { KnownAny } from '../types/utils.js';
4
+ type Next = () => Promise<unknown>;
5
+ /**
6
+ * Creates a custom decorator for Vovk controllers.
7
+ * @see https://vovk.dev/decorator
8
+ */
9
+ export declare function createDecorator<TArgs extends unknown[], TRequest = VovkRequest>(handler: null | ((this: VovkController, req: TRequest, next: Next, ...args: TArgs) => unknown), initHandler?: (this: VovkController, ...args: TArgs) => Omit<VovkHandlerSchema, 'path' | 'httpMethod'> | ((handlerSchema: VovkHandlerSchema | null, options: {
10
+ handlerName: string;
11
+ }) => Omit<Partial<VovkHandlerSchema>, 'path' | 'httpMethod'>) | null | undefined): (...args: TArgs) => (target: KnownAny, propertyKey: string) => void;
12
+ export {};
@@ -1,7 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createDecorator = createDecorator;
4
- function createDecorator(handler, initHandler) {
1
+ /**
2
+ * Creates a custom decorator for Vovk controllers.
3
+ * @see https://vovk.dev/decorator
4
+ */
5
+ export function createDecorator(handler, initHandler) {
5
6
  return function decoratorCreator(...args) {
6
7
  return function decorator(target, propertyKey) {
7
8
  const controller = target;
@@ -12,13 +13,16 @@ function createDecorator(handler, initHandler) {
12
13
  const sourceMethod = originalMethod._sourceMethod ?? originalMethod;
13
14
  const method = function method(req, params) {
14
15
  const next = async () => {
15
- return (await originalMethod.call(controller, req, params));
16
+ return await originalMethod.call(controller, req, params);
16
17
  };
17
18
  return handler ? handler.call(controller, req, next, ...args) : next();
18
19
  };
19
20
  controller[propertyKey] = method;
20
21
  method._controller = controller;
21
22
  method._sourceMethod = sourceMethod;
23
+ method.fn = originalMethod.fn;
24
+ method.definition = originalMethod.definition;
25
+ sourceMethod.wrapper = method;
22
26
  // TODO define internal method type
23
27
  originalMethod._controller = controller;
24
28
  const handlerSchema = controller._handlers?.[propertyKey] ?? null;
@@ -28,15 +32,17 @@ function createDecorator(handler, initHandler) {
28
32
  handlerName: propertyKey,
29
33
  })
30
34
  : initResultReturn;
35
+ const methodSchema = {
36
+ ...handlerSchema,
37
+ // avoid override of path and httpMethod
38
+ ...(initResult?.validation ? { validation: initResult.validation } : {}),
39
+ ...(initResult?.operationObject ? { operationObject: initResult.operationObject } : {}),
40
+ ...(initResult?.misc ? { misc: initResult.misc } : {}),
41
+ };
42
+ method.schema = methodSchema;
31
43
  controller._handlers = {
32
44
  ...controller._handlers,
33
- [propertyKey]: {
34
- ...handlerSchema,
35
- // avoid override of path and httpMethod
36
- ...(initResult?.validation ? { validation: initResult.validation } : {}),
37
- ...(initResult?.openapi ? { openapi: initResult.openapi } : {}),
38
- ...(initResult?.custom ? { custom: initResult.custom } : {}),
39
- },
45
+ [propertyKey]: methodSchema,
40
46
  };
41
47
  };
42
48
  };
@@ -0,0 +1,59 @@
1
+ import type { DecoratorOptions } from '../types/core.js';
2
+ import type { KnownAny } from '../types/utils.js';
3
+ /**
4
+ * Prefix for all routes in the controller.
5
+ */
6
+ export declare const prefix: (givenPath?: string) => (givenTarget: KnownAny) => any;
7
+ /**
8
+ * Clones metadata from parent controller to child controller.
9
+ */
10
+ export declare function cloneControllerMetadata(): <T extends new (...args: KnownAny[]) => KnownAny>(c: T) => T;
11
+ /**
12
+ * GET HTTP method decorator.
13
+ */
14
+ export declare const get: {
15
+ (givenPath?: string | undefined, options?: DecoratorOptions | undefined): (givenTarget: unknown, propertyKey: string) => void;
16
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKey: string) => void;
17
+ };
18
+ /**
19
+ * POST HTTP method decorator.
20
+ */
21
+ export declare const post: {
22
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKey: string) => void;
23
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKey: string) => void;
24
+ };
25
+ /**
26
+ * PUT HTTP method decorator.
27
+ */
28
+ export declare const put: {
29
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKey: string) => void;
30
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKey: string) => void;
31
+ };
32
+ /**
33
+ * PATCH HTTP method decorator.
34
+ */
35
+ export declare const patch: {
36
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKey: string) => void;
37
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKey: string) => void;
38
+ };
39
+ /**
40
+ * DELETE HTTP method decorator.
41
+ */
42
+ export declare const del: {
43
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKey: string) => void;
44
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKey: string) => void;
45
+ };
46
+ /**
47
+ * HEAD HTTP method decorator.
48
+ */
49
+ export declare const head: {
50
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKey: string) => void;
51
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKey: string) => void;
52
+ };
53
+ /**
54
+ * OPTIONS HTTP method decorator.
55
+ */
56
+ export declare const options: {
57
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKey: string) => void;
58
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKey: string) => void;
59
+ };
@@ -0,0 +1,132 @@
1
+ import { vovkApp } from './vovkApp.js';
2
+ import { trimPath } from '../utils/trimPath.js';
3
+ import { toKebabCase } from '../utils/toKebabCase.js';
4
+ import { HttpMethod } from '../types/enums.js';
5
+ const isClass = (func) => typeof func === 'function' && /class/.test(func.toString());
6
+ const assignSchema = ({ controller, propertyKey, path, options, httpMethod, }) => {
7
+ if (typeof window !== 'undefined') {
8
+ throw new Error('HTTP decorators can be used on server-side only. You have probably imported a controller on the client-side.');
9
+ }
10
+ if (!isClass(controller)) {
11
+ let decoratorName = httpMethod.toLowerCase();
12
+ if (decoratorName === 'delete')
13
+ decoratorName = 'del';
14
+ throw new Error(`Decorator must be used on a static class method. Check the controller method named "${propertyKey}" used with @${decoratorName}().`);
15
+ }
16
+ const methods = vovkApp.routes[httpMethod].get(controller) ?? {};
17
+ vovkApp.routes[httpMethod].set(controller, methods);
18
+ if (options?.cors) {
19
+ const optionsMethods = vovkApp.routes.OPTIONS.get(controller) ?? {};
20
+ optionsMethods[path] = (() => { });
21
+ optionsMethods[path]._options = options;
22
+ vovkApp.routes.OPTIONS.set(controller, optionsMethods);
23
+ }
24
+ const originalMethod = controller[propertyKey];
25
+ originalMethod._controller = controller;
26
+ originalMethod._sourceMethod = originalMethod._sourceMethod ?? originalMethod;
27
+ const schema = originalMethod._sourceMethod._getSchema?.(controller);
28
+ // TODO: Some of these assignments probably not needed anymore
29
+ originalMethod.schema = schema;
30
+ originalMethod.fn = originalMethod._sourceMethod?.fn;
31
+ originalMethod.definition = originalMethod._sourceMethod?.definition;
32
+ originalMethod._sourceMethod.wrapper = originalMethod;
33
+ controller._handlers = {
34
+ ...controller._handlers,
35
+ [propertyKey]: {
36
+ ...schema,
37
+ ...(controller._handlers ?? {})[propertyKey],
38
+ path,
39
+ httpMethod,
40
+ },
41
+ };
42
+ methods[path] = originalMethod;
43
+ methods[path]._options = options;
44
+ controller._handlersMetadata = {
45
+ ...controller._handlersMetadata,
46
+ [propertyKey]: {
47
+ ...(controller._handlersMetadata ?? {})[propertyKey],
48
+ staticParams: options?.staticParams,
49
+ },
50
+ };
51
+ };
52
+ function createHTTPDecorator(httpMethod) {
53
+ function decoratorFactory(givenPath = '', options) {
54
+ const path = trimPath(givenPath);
55
+ function decorator(givenTarget, propertyKey) {
56
+ const controller = givenTarget;
57
+ assignSchema({ controller, propertyKey, path, options, httpMethod });
58
+ }
59
+ return decorator;
60
+ }
61
+ const auto = (options) => {
62
+ function decorator(givenTarget, propertyKey) {
63
+ const controller = givenTarget;
64
+ // validation is already assigned at procedure function
65
+ const properties = Object.keys((controller._handlers ?? {})[propertyKey]?.validation?.params?.properties ?? {});
66
+ const kebabCasePath = toKebabCase(propertyKey);
67
+ const path = properties.length
68
+ ? `${kebabCasePath}/${properties.map((prop) => `{${prop}}`).join('/')}`
69
+ : kebabCasePath;
70
+ assignSchema({ controller, propertyKey, path, options, httpMethod });
71
+ }
72
+ return decorator;
73
+ };
74
+ const decoratorFactoryWithAuto = decoratorFactory;
75
+ decoratorFactoryWithAuto.auto = auto;
76
+ return decoratorFactoryWithAuto;
77
+ }
78
+ /**
79
+ * Prefix for all routes in the controller.
80
+ */
81
+ export const prefix = (givenPath = '') => {
82
+ const path = trimPath(givenPath);
83
+ return (givenTarget) => {
84
+ const controller = givenTarget;
85
+ controller._prefix = path;
86
+ return givenTarget;
87
+ };
88
+ };
89
+ /**
90
+ * Clones metadata from parent controller to child controller.
91
+ */
92
+ export function cloneControllerMetadata() {
93
+ return function inherit(c) {
94
+ const parent = Object.getPrototypeOf(c);
95
+ const constructor = c;
96
+ constructor._handlers = { ...parent._handlers, ...constructor._handlers };
97
+ constructor._handlersMetadata = { ...parent._handlersMetadata, ...constructor._handlersMetadata };
98
+ Object.values(vovkApp.routes).forEach((methods) => {
99
+ const parentMethods = methods.get(parent) ?? {};
100
+ methods.set(constructor, { ...parentMethods, ...methods.get(constructor) });
101
+ });
102
+ return constructor;
103
+ };
104
+ }
105
+ /**
106
+ * GET HTTP method decorator.
107
+ */
108
+ export const get = createHTTPDecorator(HttpMethod.GET);
109
+ /**
110
+ * POST HTTP method decorator.
111
+ */
112
+ export const post = createHTTPDecorator(HttpMethod.POST);
113
+ /**
114
+ * PUT HTTP method decorator.
115
+ */
116
+ export const put = createHTTPDecorator(HttpMethod.PUT);
117
+ /**
118
+ * PATCH HTTP method decorator.
119
+ */
120
+ export const patch = createHTTPDecorator(HttpMethod.PATCH);
121
+ /**
122
+ * DELETE HTTP method decorator.
123
+ */
124
+ export const del = createHTTPDecorator(HttpMethod.DELETE);
125
+ /**
126
+ * HEAD HTTP method decorator.
127
+ */
128
+ export const head = createHTTPDecorator(HttpMethod.HEAD);
129
+ /**
130
+ * OPTIONS HTTP method decorator.
131
+ */
132
+ export const options = createHTTPDecorator(HttpMethod.OPTIONS);
@@ -0,0 +1,21 @@
1
+ import type { VovkSegmentSchema, VovkController } from '../types/core.js';
2
+ import type { StaticClass } from '../types/utils.js';
3
+ export declare function getControllerSchema(controller: VovkController, rpcModuleName: string, exposeValidation: boolean): Promise<{
4
+ rpcModuleName: string;
5
+ originalControllerName: string;
6
+ prefix: string;
7
+ handlers: {
8
+ [k: string]: {
9
+ path: string;
10
+ httpMethod: string;
11
+ operationObject?: import("../internal.js").VovkOperationObject;
12
+ misc?: Record<string, unknown>;
13
+ };
14
+ };
15
+ }>;
16
+ export declare function getSchema(options: {
17
+ emitSchema?: boolean;
18
+ segmentName?: string;
19
+ controllers: Record<string, StaticClass>;
20
+ exposeValidation?: boolean;
21
+ }): Promise<VovkSegmentSchema>;
@@ -0,0 +1,31 @@
1
+ import { VovkSchemaIdEnum } from '../types/enums.js';
2
+ export async function getControllerSchema(controller, rpcModuleName, exposeValidation) {
3
+ const handlers = exposeValidation
4
+ ? (controller._handlers ?? {})
5
+ : Object.fromEntries(
6
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
7
+ Object.entries(controller._handlers ?? {}).map(([key, { validation: _v, ...value }]) => [key, value]));
8
+ return {
9
+ rpcModuleName,
10
+ originalControllerName: controller.name,
11
+ prefix: controller._prefix ?? '',
12
+ handlers,
13
+ };
14
+ }
15
+ export async function getSchema(options) {
16
+ const exposeValidation = options?.exposeValidation ?? true;
17
+ const emitSchema = options.emitSchema ?? true;
18
+ const schema = {
19
+ $schema: VovkSchemaIdEnum.SEGMENT,
20
+ emitSchema,
21
+ segmentName: options.segmentName ?? '',
22
+ segmentType: 'segment',
23
+ controllers: {},
24
+ };
25
+ if (!emitSchema)
26
+ return schema;
27
+ for (const [rpcModuleName, controller] of Object.entries(options.controllers ?? {})) {
28
+ schema.controllers[rpcModuleName] = await getControllerSchema(controller, rpcModuleName, exposeValidation);
29
+ }
30
+ return schema;
31
+ }
@@ -0,0 +1,33 @@
1
+ import type { VovkRequest } from '../types/request.js';
2
+ import type { StaticClass } from '../types/utils.js';
3
+ export declare const initSegment: (options: {
4
+ segmentName?: string;
5
+ controllers: Record<string, StaticClass>;
6
+ exposeValidation?: boolean;
7
+ emitSchema?: boolean;
8
+ onError?: (err: Error, req: VovkRequest) => void | Promise<void>;
9
+ onSuccess?: (resp: unknown, req: VovkRequest) => void | Promise<void>;
10
+ onBefore?: (req: VovkRequest) => void | Promise<void>;
11
+ }) => {
12
+ GET: (req: Request, data: {
13
+ params: Promise<Record<string, string[]>>;
14
+ }) => Promise<Response>;
15
+ POST: (req: Request, data: {
16
+ params: Promise<Record<string, string[]>>;
17
+ }) => Promise<Response>;
18
+ PUT: (req: Request, data: {
19
+ params: Promise<Record<string, string[]>>;
20
+ }) => Promise<Response>;
21
+ PATCH: (req: Request, data: {
22
+ params: Promise<Record<string, string[]>>;
23
+ }) => Promise<Response>;
24
+ DELETE: (req: Request, data: {
25
+ params: Promise<Record<string, string[]>>;
26
+ }) => Promise<Response>;
27
+ HEAD: (req: Request, data: {
28
+ params: Promise<Record<string, string[]>>;
29
+ }) => Promise<Response>;
30
+ OPTIONS: (req: Request, data: {
31
+ params: Promise<Record<string, string[]>>;
32
+ }) => Promise<Response>;
33
+ };
@@ -0,0 +1,35 @@
1
+ import { vovkApp } from './vovkApp.js';
2
+ import { trimPath } from '../utils/trimPath.js';
3
+ import { getSchema } from './getSchema.js';
4
+ export const initSegment = (options) => {
5
+ const segmentName = trimPath(options.segmentName ?? '');
6
+ options.segmentName = segmentName;
7
+ for (const [rpcModuleName, controller] of Object.entries(options.controllers ?? {})) {
8
+ controller._segmentName = segmentName;
9
+ controller._rpcModuleName = rpcModuleName;
10
+ controller._onError = options?.onError;
11
+ controller._onSuccess = options?.onSuccess;
12
+ controller._onBefore = options?.onBefore;
13
+ }
14
+ async function GET_DEV(req, data) {
15
+ const params = await data.params;
16
+ if (params[Object.keys(params)[0]]?.[0] === '_schema_') {
17
+ const schema = await getSchema(options);
18
+ return vovkApp.respond({
19
+ req,
20
+ statusCode: 200,
21
+ responseBody: { schema },
22
+ });
23
+ }
24
+ return vovkApp.GET(req, data, segmentName);
25
+ }
26
+ return {
27
+ GET: process.env.NODE_ENV === 'development' ? GET_DEV : (req, data) => vovkApp.GET(req, data, segmentName),
28
+ POST: (req, data) => vovkApp.POST(req, data, segmentName),
29
+ PUT: (req, data) => vovkApp.PUT(req, data, segmentName),
30
+ PATCH: (req, data) => vovkApp.PATCH(req, data, segmentName),
31
+ DELETE: (req, data) => vovkApp.DELETE(req, data, segmentName),
32
+ HEAD: (req, data) => vovkApp.HEAD(req, data, segmentName),
33
+ OPTIONS: (req, data) => vovkApp.OPTIONS(req, data, segmentName),
34
+ };
35
+ };
@@ -0,0 +1,33 @@
1
+ type Override = {
2
+ from: string;
3
+ to: string;
4
+ };
5
+ type Config = {
6
+ requestUrl: string;
7
+ requestHost: string;
8
+ targetHost: string;
9
+ overrides: {
10
+ [key: string]: Override[];
11
+ };
12
+ };
13
+ /**
14
+ * Multitenant function to handle subdomain and path-based routing overrides.
15
+ * @see https://vovk.dev/multitenant
16
+ */
17
+ export declare function multitenant(config: Config): {
18
+ action: null;
19
+ destination: null;
20
+ message: string;
21
+ subdomains: null;
22
+ } | {
23
+ action: "redirect";
24
+ destination: string;
25
+ message: string;
26
+ subdomains: null;
27
+ } | {
28
+ action: "rewrite";
29
+ destination: string;
30
+ message: string;
31
+ subdomains: Record<string, string> | null;
32
+ };
33
+ export {};