vovk 3.0.0-draft.116 → 3.0.0-draft.118

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/VovkApp.js CHANGED
@@ -125,7 +125,7 @@ class VovkApp {
125
125
  });
126
126
  const { handler, methodParams } = this.#getHandler({ handlers, path, params });
127
127
  if (!handler) {
128
- return this.#respondWithError(types_1.HttpStatus.NOT_FOUND, `Route ${path.join('/')} is not found`);
128
+ return this.#respondWithError(types_1.HttpStatus.NOT_FOUND, `${Object.keys(handlers)} - Route ${path.join('/')} is not found`);
129
129
  }
130
130
  const { staticMethod, controller } = handler;
131
131
  req.vovk = {
@@ -39,11 +39,11 @@ const createRPC = (fullSchema, segmentName, controllerName, options) => {
39
39
  const fetcher = input.fetcher ?? settingsFetcher;
40
40
  const validate = async ({ body, query, params, endpoint, }) => {
41
41
  const validateOnClient = input.validateOnClient ?? options?.validateOnClient;
42
- if (validateOnClient) {
42
+ if (validateOnClient && validation) {
43
43
  if (typeof validateOnClient !== 'function') {
44
44
  throw new Error('validateOnClient must be a function');
45
45
  }
46
- await validateOnClient({ body, query, params, endpoint }, validation ?? {}, fullSchema);
46
+ await validateOnClient({ body, query, params, endpoint }, validation, fullSchema);
47
47
  }
48
48
  };
49
49
  const internalOptions = {
@@ -35,7 +35,7 @@ function createDecorator(handler, initHandler) {
35
35
  // avoid override of path and httpMethod
36
36
  ...(initResult?.validation ? { validation: initResult.validation } : {}),
37
37
  ...(initResult?.openapi ? { openapi: initResult.openapi } : {}),
38
- ...(initResult?.custom ? { custom: initResult.custom } : {}),
38
+ ...(initResult?.misc ? { misc: initResult.misc } : {}),
39
39
  },
40
40
  };
41
41
  };
@@ -10,9 +10,10 @@ const getSchema_1 = __importDefault(require("./utils/getSchema"));
10
10
  const trimPath = (path) => path.trim().replace(/^\/|\/$/g, '');
11
11
  const isClass = (func) => typeof func === 'function' && /class/.test(func.toString());
12
12
  const toKebabCase = (str) => str
13
- .replace(/([A-Z])/g, '-$1')
13
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2') // Add hyphen between lowercase/digit and uppercase
14
+ .replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1-$2') // Add hyphen between uppercase letters if the second one is followed by a lowercase
14
15
  .toLowerCase()
15
- .replace(/^-/, '');
16
+ .replace(/^-/, ''); // Remove leading hyphen
16
17
  const assignSchema = ({ controller, propertyKey, path, options, httpMethod, vovkApp, }) => {
17
18
  if (typeof window !== 'undefined') {
18
19
  throw new Error('Decorators are intended for server-side use only. You have probably imported a controller on the client-side.');
@@ -40,6 +41,13 @@ const assignSchema = ({ controller, propertyKey, path, options, httpMethod, vovk
40
41
  };
41
42
  methods[path] = controller[propertyKey];
42
43
  methods[path]._options = options;
44
+ controller._handlersMetadata = {
45
+ ...controller._handlersMetadata,
46
+ [propertyKey]: {
47
+ ...(controller._handlersMetadata ?? {})[propertyKey],
48
+ staticParams: options?.staticParams,
49
+ },
50
+ };
43
51
  };
44
52
  function createVovkApp() {
45
53
  const vovkApp = new VovkApp_1.VovkApp();
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { NextRequest } from 'next/server';
2
2
  import type { OperationObject } from 'openapi3-ts/oas31';
3
+ import type { PackageJson } from 'type-fest';
3
4
  import type { JSONLinesResponse } from './JSONLinesResponse';
4
5
  import { VovkStreamAsyncIterable } from './client/types';
5
6
  export type KnownAny = any;
@@ -15,7 +16,7 @@ export type VovkHandlerSchema = {
15
16
  iteration?: KnownAny;
16
17
  };
17
18
  openapi?: OperationObject;
18
- custom?: Record<string, KnownAny>;
19
+ misc?: Record<string, KnownAny>;
19
20
  };
20
21
  export type VovkControllerSchema = {
21
22
  controllerName: string;
@@ -38,6 +39,9 @@ export type VovkControllerInternal = {
38
39
  _controllerName?: VovkControllerSchema['controllerName'];
39
40
  _prefix?: VovkControllerSchema['prefix'];
40
41
  _handlers: VovkControllerSchema['handlers'];
42
+ _handlersMetadata?: Record<string, {
43
+ staticParams?: Record<string, string>[];
44
+ }>;
41
45
  _activated?: true;
42
46
  _onError?: (err: Error, req: VovkRequest) => void | Promise<void>;
43
47
  };
@@ -47,6 +51,7 @@ export type VovkController = StaticClass & VovkControllerInternal & {
47
51
  export type DecoratorOptions = {
48
52
  cors?: boolean;
49
53
  headers?: Record<string, string>;
54
+ staticParams?: Record<string, string>[];
50
55
  before?: (this: VovkController, req: VovkRequest) => unknown;
51
56
  };
52
57
  export type RouteHandler = ((req: VovkRequest, params: Record<string, string>) => Response | Promise<Response> | Iterable<unknown> | AsyncIterable<unknown>) & {
@@ -99,9 +104,6 @@ export type StreamAbortMessage = {
99
104
  type LogLevelNames = 'trace' | 'debug' | 'info' | 'warn' | 'error';
100
105
  export type VovkEnv = {
101
106
  PORT?: string;
102
- VOVK_GENERATE_FULL_CLIENT?: string;
103
- VOVK_GENERATE_SEGMENT_CLIENT?: string;
104
- VOVK_CLIENT_OUT_DIR?: string;
105
107
  VOVK_SCHEMA_OUT_DIR?: string;
106
108
  VOVK_IMPORTS_FETCHER?: string;
107
109
  VOVK_IMPORTS_VALIDATE_ON_CLIENT?: string;
@@ -117,20 +119,40 @@ export type VovkEnv = {
117
119
  __VOVK_START_WATCHER_IN_STANDALONE_MODE__?: 'true';
118
120
  __VOVK_EXIT__?: 'true' | 'false';
119
121
  };
120
- export type GenerateFromTemplate = {
121
- templateGlob: string | null;
122
+ type ClientConfigCommon = {
123
+ enabled?: boolean;
122
124
  outDir?: string;
123
- templateName?: string;
124
- fullSchemaJSON?: string | boolean;
125
+ fromTemplates?: string[];
126
+ } & ({
127
+ excludeSegments?: never;
128
+ includeSegments?: string[];
129
+ } | {
130
+ excludeSegments?: string[];
131
+ includeSegments?: never;
132
+ });
133
+ type ClientConfigFull = ClientConfigCommon & {
134
+ package?: PackageJson;
135
+ };
136
+ type ClientConfigSegmented = ClientConfigCommon & {
137
+ packages?: Record<string, PackageJson>;
138
+ };
139
+ export type ClientTemplateDef = {
140
+ extends?: string;
141
+ templatePath: string;
125
142
  origin?: string | null;
143
+ fullClient?: Omit<ClientConfigFull, 'fromTemplates' | 'enabled'>;
144
+ segmentedClient?: Omit<ClientConfigSegmented, 'fromTemplates' | 'enabled'>;
145
+ segmentConfig?: false | Record<string, {
146
+ origin?: string;
147
+ rootEntry?: boolean;
148
+ }>;
149
+ requires?: Record<string, string>;
126
150
  };
127
- type GenerateFrom = (string | GenerateFromTemplate)[];
128
151
  export type VovkConfig = {
129
152
  emitConfig?: boolean | (keyof VovkStrictConfig)[];
130
- clientOutDir?: string;
131
153
  schemaOutDir?: string;
132
- generateFullClient?: boolean;
133
- generateSegmentClient?: boolean;
154
+ fullClient?: ClientConfigFull;
155
+ segmentedClient?: ClientConfigSegmented;
134
156
  imports?: {
135
157
  fetcher?: string | [string, string] | [string];
136
158
  validateOnClient?: string | [string, string] | [string];
@@ -143,23 +165,28 @@ export type VovkConfig = {
143
165
  logLevel?: LogLevelNames;
144
166
  prettifyClient?: boolean;
145
167
  devHttps?: boolean;
146
- generateFrom?: GenerateFrom | ((value: GenerateFrom) => GenerateFrom);
147
- templates?: {
168
+ clientTemplateDefs?: Record<string, ClientTemplateDef>;
169
+ moduleTemplates?: {
148
170
  service?: string;
149
171
  controller?: string;
150
172
  [key: string]: string | undefined;
151
173
  };
152
174
  libs?: Record<string, KnownAny>;
175
+ segmentConfig?: false | Record<string, {
176
+ origin?: string;
177
+ rootEntry?: boolean;
178
+ }>;
153
179
  };
154
- export type VovkStrictConfig = Required<Omit<VovkConfig, 'emitConfig' | 'generateFrom' | 'libs' | 'imports'>> & {
180
+ export type VovkStrictConfig = Required<Omit<VovkConfig, 'emitConfig' | 'libs' | 'imports' | 'fullClient' | 'segmentedClient'>> & {
155
181
  emitConfig: (keyof VovkStrictConfig)[];
156
182
  imports: {
157
183
  fetcher: [string, string] | [string];
158
184
  validateOnClient: [string, string] | [string] | null;
159
185
  createRPC: [string, string] | [string];
160
186
  };
161
- generateFrom: GenerateFrom;
162
187
  libs: Record<string, KnownAny>;
188
+ fullClient: RequireFields<ClientConfigFull, 'enabled' | 'fromTemplates' | 'outDir'>;
189
+ segmentedClient: RequireFields<ClientConfigSegmented, 'enabled' | 'fromTemplates' | 'outDir'>;
163
190
  };
164
191
  export type VovkFullSchema = {
165
192
  config: Partial<VovkStrictConfig>;
@@ -226,4 +253,5 @@ export declare enum HttpStatus {
226
253
  GATEWAY_TIMEOUT = 504,
227
254
  HTTP_VERSION_NOT_SUPPORTED = 505
228
255
  }
256
+ type RequireFields<T, K extends keyof T> = T & Required<Pick<T, K>>;
229
257
  export {};
@@ -9,9 +9,21 @@ function generateStaticAPI(c, slug = 'vovk') {
9
9
  .map((controller) => {
10
10
  const handlers = controller._handlers;
11
11
  const splitPrefix = controller._prefix?.split('/') ?? [];
12
- return Object.values(handlers).map((handler) => {
13
- return { [slug]: [...splitPrefix, ...handler.path.split('/')].filter(Boolean) };
14
- });
12
+ return Object.entries(handlers)
13
+ .map(([name, handler]) => {
14
+ const staticParams = controller._handlersMetadata?.[name]?.staticParams;
15
+ if (staticParams?.length) {
16
+ return staticParams.map((paramsItem) => {
17
+ let path = handler.path;
18
+ for (const [key, value] of Object.entries(paramsItem)) {
19
+ path = path.replace(`:${key}`, value);
20
+ }
21
+ return { [slug]: [...splitPrefix, ...path.split('/')].filter(Boolean) };
22
+ });
23
+ }
24
+ return [{ [slug]: [...splitPrefix, ...handler.path.split('/')].filter(Boolean) }];
25
+ })
26
+ .flat();
15
27
  })
16
28
  .flat(),
17
29
  ];
@@ -8,7 +8,7 @@ export declare function getControllerSchema(controller: VovkController, controll
8
8
  path: string;
9
9
  httpMethod: string;
10
10
  openapi?: import("openapi3-ts/oas31").OperationObject;
11
- custom?: Record<string, import("../types").KnownAny>;
11
+ misc?: Record<string, import("../types").KnownAny>;
12
12
  };
13
13
  };
14
14
  };
@@ -1,8 +1,8 @@
1
1
  import { VovkValidationType, type KnownAny, type VovkRequest } from '../types';
2
- export declare function withValidation<T extends (req: KnownAny, params: KnownAny) => KnownAny, BODY_MODEL, QUERY_MODEL, PARAMS_MODEL, OUTPUT_MODEL, ITERATION_MODEL>({ disableServerSideValidation, skipSchemaEmission, validateEveryIteration, body, query, params, output, iteration, handle, getJSONSchemaFromModel, validate, }: {
2
+ export declare function withValidation<T extends (req: KnownAny, params: KnownAny) => KnownAny, BODY_MODEL, QUERY_MODEL, PARAMS_MODEL, OUTPUT_MODEL, ITERATION_MODEL>({ disableServerSideValidation, skipSchemaEmission, validateEachIteration, body, query, params, output, iteration, handle, getJSONSchemaFromModel, validate, }: {
3
3
  disableServerSideValidation?: boolean | VovkValidationType[];
4
4
  skipSchemaEmission?: boolean | VovkValidationType[];
5
- validateEveryIteration?: boolean;
5
+ validateEachIteration?: boolean;
6
6
  body?: BODY_MODEL;
7
7
  query?: QUERY_MODEL;
8
8
  params?: PARAMS_MODEL;
@@ -5,7 +5,7 @@ const HttpException_1 = require("../HttpException");
5
5
  const types_1 = require("../types");
6
6
  const setHandlerSchema_1 = require("./setHandlerSchema");
7
7
  const validationTypes = ['body', 'query', 'params', 'output', 'iteration'];
8
- function withValidation({ disableServerSideValidation, skipSchemaEmission, validateEveryIteration, body, query, params, output, iteration, handle, getJSONSchemaFromModel, validate, }) {
8
+ function withValidation({ disableServerSideValidation, skipSchemaEmission, validateEachIteration, body, query, params, output, iteration, handle, getJSONSchemaFromModel, validate, }) {
9
9
  const disableServerSideValidationKeys = disableServerSideValidation === false
10
10
  ? []
11
11
  : disableServerSideValidation === true
@@ -32,7 +32,7 @@ function withValidation({ disableServerSideValidation, skipSchemaEmission, valid
32
32
  return (async function* () {
33
33
  let i = 0;
34
34
  for await (const item of data) {
35
- if (validateEveryIteration || i === 0) {
35
+ if (validateEachIteration || i === 0) {
36
36
  await validate(item, iteration, { type: 'iteration', req, status: 200, i });
37
37
  }
38
38
  i++;
@@ -40,8 +40,8 @@ function withValidation({ disableServerSideValidation, skipSchemaEmission, valid
40
40
  }
41
41
  })();
42
42
  }
43
- else if (validateEveryIteration) {
44
- throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, 'validateEveryIteration is set but iteration is not defined.');
43
+ else if (validateEachIteration) {
44
+ throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, 'validateEachIteration is set but iteration is not defined.');
45
45
  }
46
46
  return data;
47
47
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vovk",
3
- "version": "3.0.0-draft.116",
3
+ "version": "3.0.0-draft.118",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "description": "RESTful RPC for Next.js - Transforms Next.js into a powerful REST API platform with RPC capabilities.",
@@ -30,6 +30,7 @@
30
30
  "next": "*"
31
31
  },
32
32
  "optionalDependencies": {
33
- "openapi3-ts": "*"
33
+ "openapi3-ts": "*",
34
+ "type-fest": "*"
34
35
  }
35
36
  }