vovk 3.0.0-draft.116 → 3.0.0-draft.117

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,8 @@ 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
+ console.log(path, params);
129
+ return this.#respondWithError(types_1.HttpStatus.NOT_FOUND, `x Route ${path.join('/')} is not found`);
129
130
  }
130
131
  const { staticMethod, controller } = handler;
131
132
  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,36 @@ 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
+ requires?: Record<string, string>;
126
146
  };
127
- type GenerateFrom = (string | GenerateFromTemplate)[];
128
147
  export type VovkConfig = {
129
148
  emitConfig?: boolean | (keyof VovkStrictConfig)[];
130
- clientOutDir?: string;
131
149
  schemaOutDir?: string;
132
- generateFullClient?: boolean;
133
- generateSegmentClient?: boolean;
150
+ fullClient?: ClientConfigFull;
151
+ segmentedClient?: ClientConfigSegmented;
134
152
  imports?: {
135
153
  fetcher?: string | [string, string] | [string];
136
154
  validateOnClient?: string | [string, string] | [string];
@@ -143,23 +161,24 @@ export type VovkConfig = {
143
161
  logLevel?: LogLevelNames;
144
162
  prettifyClient?: boolean;
145
163
  devHttps?: boolean;
146
- generateFrom?: GenerateFrom | ((value: GenerateFrom) => GenerateFrom);
147
- templates?: {
164
+ clientTemplateDefs?: Record<string, ClientTemplateDef>;
165
+ moduleTemplates?: {
148
166
  service?: string;
149
167
  controller?: string;
150
168
  [key: string]: string | undefined;
151
169
  };
152
170
  libs?: Record<string, KnownAny>;
153
171
  };
154
- export type VovkStrictConfig = Required<Omit<VovkConfig, 'emitConfig' | 'generateFrom' | 'libs' | 'imports'>> & {
172
+ export type VovkStrictConfig = Required<Omit<VovkConfig, 'emitConfig' | 'libs' | 'imports' | 'fullClient' | 'segmentedClient'>> & {
155
173
  emitConfig: (keyof VovkStrictConfig)[];
156
174
  imports: {
157
175
  fetcher: [string, string] | [string];
158
176
  validateOnClient: [string, string] | [string] | null;
159
177
  createRPC: [string, string] | [string];
160
178
  };
161
- generateFrom: GenerateFrom;
162
179
  libs: Record<string, KnownAny>;
180
+ fullClient: RequireFields<ClientConfigFull, 'enabled' | 'fromTemplates' | 'outDir'>;
181
+ segmentedClient: RequireFields<ClientConfigSegmented, 'enabled' | 'fromTemplates' | 'outDir'>;
163
182
  };
164
183
  export type VovkFullSchema = {
165
184
  config: Partial<VovkStrictConfig>;
@@ -226,4 +245,5 @@ export declare enum HttpStatus {
226
245
  GATEWAY_TIMEOUT = 504,
227
246
  HTTP_VERSION_NOT_SUPPORTED = 505
228
247
  }
248
+ type RequireFields<T, K extends keyof T> = T & Required<Pick<T, K>>;
229
249
  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.117",
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
  }