vovk 3.0.0 → 3.0.3

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/README.md CHANGED
@@ -9,6 +9,8 @@
9
9
  <br>
10
10
  <strong>Back-end Framework for Next.js App Router</strong>
11
11
  <br />
12
+ <em>One codebase → type-safe clients, OpenAPI, and AI tools</em>
13
+ <br />
12
14
  <a href="https://vovk.dev/">Documentation</a>
13
15
  &nbsp;&nbsp;
14
16
  <a href="https://vovk.dev/quick-install">Quick Start</a>
@@ -23,7 +25,7 @@
23
25
  The Vovk.ts runtime library with [100% self-composition](https://bundlephobia.com/result?p=vovk). It provides a wrapper for Next.js API routes, client-side tooling, utilities and types.
24
26
 
25
27
  ```sh
26
- npm install vovk openapi3-ts
28
+ npm install vovk
27
29
  ```
28
30
 
29
31
  ## Links
package/bin/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { spawn } from 'child_process';
2
+ import { spawn } from 'node:child_process';
3
3
 
4
4
  console.warn(
5
5
  `\x1b[33m🐺 Vovk CLI requires vovk-cli package. Running npx vovk-cli@latest ${process.argv.slice(2).join(' ')} instead.\x1b[0m`
@@ -87,7 +87,7 @@ export const createRPC = (givenSchema, segmentName, rpcModuleName, givenFetcher,
87
87
  !(input.body instanceof FormData || input.body instanceof URLSearchParams || input.body instanceof Blob)) {
88
88
  processedBody = new FormData();
89
89
  for (const [key, value] of Object.entries(input.body)) {
90
- if (value instanceof Array) {
90
+ if (Array.isArray(value)) {
91
91
  value.forEach((item) => {
92
92
  processedBody.append(key, item);
93
93
  });
@@ -101,7 +101,7 @@ export const readableStreamToAsyncIterable = ({ readableStream, abortController,
101
101
  if (error?.name === 'AbortError' && isAbortedWithoutError) {
102
102
  break;
103
103
  }
104
- const err = new Error('JSONLines stream error. ' + String(error));
104
+ const err = new Error(`JSONLines stream error. ${String(error)}`);
105
105
  err.cause = error;
106
106
  setStreamError(err);
107
107
  return;
@@ -113,7 +113,10 @@ export const readableStreamToAsyncIterable = ({ readableStream, abortController,
113
113
  : new TextDecoder().decode(value);
114
114
  buffer += chunk;
115
115
  let newlineIdx;
116
- while ((newlineIdx = buffer.indexOf('\n')) !== -1) {
116
+ while (true) {
117
+ newlineIdx = buffer.indexOf('\n');
118
+ if (newlineIdx === -1)
119
+ break;
117
120
  if (abortController?.signal.aborted && isAbortedWithoutError) {
118
121
  break;
119
122
  }
@@ -92,7 +92,7 @@ export function createFetcher({ prepareRequestInit, transformResponse, onSuccess
92
92
  }
93
93
  catch (e) {
94
94
  // handle network errors
95
- throw new HttpException(HttpStatus.NULL, (e?.message ?? DEFAULT_ERROR_MESSAGE) + ' ' + endpoint, {
95
+ throw new HttpException(HttpStatus.NULL, `${e?.message ?? DEFAULT_ERROR_MESSAGE} ${endpoint}`, {
96
96
  body,
97
97
  query,
98
98
  params,
@@ -53,7 +53,7 @@ export function serializeQuery(obj) {
53
53
  // Collect query segments
54
54
  const segments = [];
55
55
  for (const key in obj) {
56
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
56
+ if (Object.hasOwn(obj, key)) {
57
57
  const value = obj[key];
58
58
  segments.push(...buildParams(key, value));
59
59
  }
@@ -29,6 +29,7 @@ export class JSONLinesResponder extends Responder {
29
29
  isClosed = false;
30
30
  i = 0;
31
31
  controller;
32
+ // biome-ignore lint/correctness/noUnusedPrivateClassMembers: biome bug
32
33
  encoder;
33
34
  readableStream;
34
35
  headers;
@@ -54,6 +55,7 @@ export class JSONLinesResponder extends Responder {
54
55
  this.headers = headers;
55
56
  this.readableStream = readableStream;
56
57
  this.encoder = encoder;
58
+ // biome-ignore lint/style/noNonNullAssertion: assigned at readableStream start
57
59
  this.controller = readableController;
58
60
  this.response = getResponse?.(this) ?? new Response(readableStream, { headers });
59
61
  request?.signal?.addEventListener('abort', this.close, { once: true });
@@ -76,7 +78,7 @@ export class JSONLinesResponder extends Responder {
76
78
  const { controller, encoder } = this;
77
79
  if (this.isClosed)
78
80
  return;
79
- controller?.enqueue(encoder?.encode(JSON.stringify(data) + '\n'));
81
+ controller?.enqueue(encoder?.encode(`${JSON.stringify(data)}\n`));
80
82
  };
81
83
  close = () => {
82
84
  const { controller } = this;
@@ -11,12 +11,10 @@ export function controllersToStaticParams(c, slug = 'vovk') {
11
11
  const controllers = c;
12
12
  return [
13
13
  { [slug]: ['_schema_'] },
14
- ...Object.values(controllers)
15
- .map((controller) => {
14
+ ...Object.values(controllers).flatMap((controller) => {
16
15
  const handlers = controller._handlers;
17
16
  const splitPrefix = controller._prefix?.split('/') ?? [];
18
- return Object.entries(handlers ?? {})
19
- .map(([name, handler]) => {
17
+ return Object.entries(handlers ?? {}).flatMap(([name, handler]) => {
20
18
  const staticParams = controller._handlersMetadata?.[name]?.staticParams;
21
19
  if (staticParams?.length) {
22
20
  return staticParams.map((paramsItem) => {
@@ -28,9 +26,7 @@ export function controllersToStaticParams(c, slug = 'vovk') {
28
26
  });
29
27
  }
30
28
  return [{ [slug]: [...splitPrefix, ...handler.path.split('/')].filter(Boolean) }];
31
- })
32
- .flat();
33
- })
34
- .flat(),
29
+ });
30
+ }),
35
31
  ];
36
32
  }
@@ -2,11 +2,17 @@ import type { VovkHandlerSchema, VovkController } from '../types/core.js';
2
2
  import type { VovkRequest } from '../types/request.js';
3
3
  import type { KnownAny } from '../types/utils.js';
4
4
  type Next = () => Promise<unknown>;
5
+ /** Minimal shape shared by all TC39 Stage 3 decorator context objects. */
6
+ type _Stage3Context = {
7
+ kind: string;
8
+ name: string | symbol;
9
+ addInitializer: (fn: () => void) => void;
10
+ };
5
11
  /**
6
12
  * Creates a custom decorator for Vovk controllers.
7
13
  * @see https://vovk.dev/decorator
8
14
  */
9
15
  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
16
  handlerName: string;
11
- }) => Omit<Partial<VovkHandlerSchema>, 'path' | 'httpMethod'>) | null | undefined): (...args: TArgs) => (target: KnownAny, propertyKey: string) => void;
17
+ }) => Omit<Partial<VovkHandlerSchema>, 'path' | 'httpMethod'>) | null | undefined): (...args: TArgs) => (target: KnownAny, propertyKeyOrContext: string | _Stage3Context) => void;
12
18
  export {};
@@ -4,46 +4,57 @@
4
4
  */
5
5
  export function createDecorator(handler, initHandler) {
6
6
  return function decoratorCreator(...args) {
7
- return function decorator(target, propertyKey) {
8
- const controller = target;
9
- const originalMethod = controller[propertyKey];
10
- if (typeof originalMethod !== 'function') {
11
- throw new Error(`Unable to decorate: ${propertyKey} is not a function`);
7
+ return function decorator(target, propertyKeyOrContext) {
8
+ if (typeof propertyKeyOrContext === 'object' && propertyKeyOrContext !== null && 'kind' in propertyKeyOrContext) {
9
+ // TC39 Stage 3 decorator — defer to addInitializer where `this` is the class
10
+ const propertyKey = String(propertyKeyOrContext.name);
11
+ propertyKeyOrContext.addInitializer(function () {
12
+ applyDecorator(this, propertyKey);
13
+ });
14
+ return;
12
15
  }
13
- const sourceMethod = originalMethod._sourceMethod ?? originalMethod;
14
- const method = function method(req, params) {
15
- const next = async () => {
16
- return await originalMethod.call(controller, req, params);
16
+ // Experimental decorator target is the class for static members
17
+ applyDecorator(target, propertyKeyOrContext);
18
+ function applyDecorator(controller, propertyKey) {
19
+ const originalMethod = controller[propertyKey];
20
+ if (typeof originalMethod !== 'function') {
21
+ throw new Error(`Unable to decorate: ${propertyKey} is not a function`);
22
+ }
23
+ const sourceMethod = originalMethod._sourceMethod ?? originalMethod;
24
+ const method = function method(req, params) {
25
+ const next = async () => {
26
+ return await originalMethod.call(controller, req, params);
27
+ };
28
+ return handler ? handler.call(controller, req, next, ...args) : next();
17
29
  };
18
- return handler ? handler.call(controller, req, next, ...args) : next();
19
- };
20
- controller[propertyKey] = method;
21
- method._controller = controller;
22
- method._sourceMethod = sourceMethod;
23
- method.fn = originalMethod.fn;
24
- method.definition = originalMethod.definition;
25
- sourceMethod.wrapper = method;
26
- // TODO define internal method type
27
- originalMethod._controller = controller;
28
- const handlerSchema = controller._handlers?.[propertyKey] ?? null;
29
- const initResultReturn = initHandler?.call(controller, ...args);
30
- const initResult = typeof initResultReturn === 'function'
31
- ? initResultReturn(handlerSchema, {
32
- handlerName: propertyKey,
33
- })
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;
43
- controller._handlers = {
44
- ...controller._handlers,
45
- [propertyKey]: methodSchema,
46
- };
30
+ controller[propertyKey] = method;
31
+ method._controller = controller;
32
+ method._sourceMethod = sourceMethod;
33
+ method.fn = originalMethod.fn;
34
+ method.definition = originalMethod.definition;
35
+ sourceMethod.wrapper = method;
36
+ // TODO define internal method type
37
+ originalMethod._controller = controller;
38
+ const handlerSchema = controller._handlers?.[propertyKey] ?? null;
39
+ const initResultReturn = initHandler?.call(controller, ...args);
40
+ const initResult = typeof initResultReturn === 'function'
41
+ ? initResultReturn(handlerSchema, {
42
+ handlerName: propertyKey,
43
+ })
44
+ : initResultReturn;
45
+ const methodSchema = {
46
+ ...handlerSchema,
47
+ // avoid override of path and httpMethod
48
+ ...(initResult?.validation ? { validation: initResult.validation } : {}),
49
+ ...(initResult?.operationObject ? { operationObject: initResult.operationObject } : {}),
50
+ ...(initResult?.misc ? { misc: initResult.misc } : {}),
51
+ };
52
+ method.schema = methodSchema;
53
+ controller._handlers = {
54
+ ...controller._handlers,
55
+ [propertyKey]: methodSchema,
56
+ };
57
+ }
47
58
  };
48
59
  };
49
60
  }
@@ -1,59 +1,66 @@
1
1
  import type { DecoratorOptions } from '../types/core.js';
2
2
  import type { KnownAny } from '../types/utils.js';
3
+ /** Minimal shape shared by all TC39 Stage 3 decorator context objects. */
4
+ type _Stage3Context = {
5
+ kind: string;
6
+ name: string | symbol;
7
+ addInitializer: (fn: () => void) => void;
8
+ };
3
9
  /**
4
10
  * Prefix for all routes in the controller.
5
11
  */
6
- export declare const prefix: (givenPath?: string) => (givenTarget: KnownAny) => any;
12
+ export declare const prefix: (givenPath?: string) => (givenTarget: KnownAny, _context?: KnownAny) => any;
7
13
  /**
8
14
  * Clones metadata from parent controller to child controller.
9
15
  */
10
- export declare function cloneControllerMetadata(): <T extends new (...args: KnownAny[]) => KnownAny>(c: T) => T;
16
+ export declare function cloneControllerMetadata(): <T extends new (...args: KnownAny[]) => KnownAny>(c: T, _context?: KnownAny) => T;
11
17
  /**
12
18
  * GET HTTP method decorator.
13
19
  */
14
20
  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;
21
+ (givenPath?: string | undefined, options?: DecoratorOptions | undefined): (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
22
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
17
23
  };
18
24
  /**
19
25
  * POST HTTP method decorator.
20
26
  */
21
27
  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;
28
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
29
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
24
30
  };
25
31
  /**
26
32
  * PUT HTTP method decorator.
27
33
  */
28
34
  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;
35
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
36
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
31
37
  };
32
38
  /**
33
39
  * PATCH HTTP method decorator.
34
40
  */
35
41
  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;
42
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
43
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
38
44
  };
39
45
  /**
40
46
  * DELETE HTTP method decorator.
41
47
  */
42
48
  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;
49
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
50
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
45
51
  };
46
52
  /**
47
53
  * HEAD HTTP method decorator.
48
54
  */
49
55
  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;
56
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
57
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
52
58
  };
53
59
  /**
54
60
  * OPTIONS HTTP method decorator.
55
61
  */
56
62
  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;
63
+ (givenPath?: string | undefined, options?: Omit<DecoratorOptions, "staticParams"> | undefined): (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
64
+ auto: (options?: DecoratorOptions) => (givenTarget: unknown, propertyKeyOrContext: string | _Stage3Context) => void;
59
65
  };
66
+ export {};
@@ -3,6 +3,8 @@ import { trimPath } from '../utils/trimPath.js';
3
3
  import { toKebabCase } from '../utils/toKebabCase.js';
4
4
  import { HttpMethod } from '../types/enums.js';
5
5
  const isClass = (func) => typeof func === 'function' && /class/.test(func.toString());
6
+ /** Detects whether the second decorator argument is a TC39 Stage 3 context object. */
7
+ const _isStage3 = (arg) => typeof arg === 'object' && arg !== null && 'kind' in arg;
6
8
  const assignSchema = ({ controller, propertyKey, path, options, httpMethod, }) => {
7
9
  if (typeof window !== 'undefined') {
8
10
  throw new Error('HTTP decorators can be used on server-side only. You have probably imported a controller on the client-side.');
@@ -34,7 +36,7 @@ const assignSchema = ({ controller, propertyKey, path, options, httpMethod, }) =
34
36
  ...controller._handlers,
35
37
  [propertyKey]: {
36
38
  ...schema,
37
- ...(controller._handlers ?? {})[propertyKey],
39
+ ...controller._handlers?.[propertyKey],
38
40
  path,
39
41
  httpMethod,
40
42
  },
@@ -44,7 +46,7 @@ const assignSchema = ({ controller, propertyKey, path, options, httpMethod, }) =
44
46
  controller._handlersMetadata = {
45
47
  ...controller._handlersMetadata,
46
48
  [propertyKey]: {
47
- ...(controller._handlersMetadata ?? {})[propertyKey],
49
+ ...controller._handlersMetadata?.[propertyKey],
48
50
  staticParams: options?.staticParams,
49
51
  },
50
52
  };
@@ -52,22 +54,43 @@ const assignSchema = ({ controller, propertyKey, path, options, httpMethod, }) =
52
54
  function createHTTPDecorator(httpMethod) {
53
55
  function decoratorFactory(givenPath = '', options) {
54
56
  const path = trimPath(givenPath);
55
- function decorator(givenTarget, propertyKey) {
57
+ function decorator(givenTarget, propertyKeyOrContext) {
58
+ if (_isStage3(propertyKeyOrContext)) {
59
+ const propertyKey = String(propertyKeyOrContext.name);
60
+ propertyKeyOrContext.addInitializer(function () {
61
+ assignSchema({ controller: this, propertyKey, path, options, httpMethod });
62
+ });
63
+ return;
64
+ }
56
65
  const controller = givenTarget;
57
- assignSchema({ controller, propertyKey, path, options, httpMethod });
66
+ assignSchema({ controller, propertyKey: propertyKeyOrContext, path, options, httpMethod });
58
67
  }
59
68
  return decorator;
60
69
  }
61
70
  const auto = (options) => {
62
- function decorator(givenTarget, propertyKey) {
71
+ function decorator(givenTarget, propertyKeyOrContext) {
72
+ if (_isStage3(propertyKeyOrContext)) {
73
+ const propertyKey = String(propertyKeyOrContext.name);
74
+ propertyKeyOrContext.addInitializer(function () {
75
+ const controller = this;
76
+ // validation is already assigned at procedure function
77
+ const properties = Object.keys(controller._handlers?.[propertyKey]?.validation?.params?.properties ?? {});
78
+ const kebabCasePath = toKebabCase(propertyKey);
79
+ const path = properties.length
80
+ ? `${kebabCasePath}/${properties.map((prop) => `{${prop}}`).join('/')}`
81
+ : kebabCasePath;
82
+ assignSchema({ controller, propertyKey, path, options, httpMethod });
83
+ });
84
+ return;
85
+ }
63
86
  const controller = givenTarget;
64
87
  // validation is already assigned at procedure function
65
- const properties = Object.keys((controller._handlers ?? {})[propertyKey]?.validation?.params?.properties ?? {});
66
- const kebabCasePath = toKebabCase(propertyKey);
88
+ const properties = Object.keys(controller._handlers?.[propertyKeyOrContext]?.validation?.params?.properties ?? {});
89
+ const kebabCasePath = toKebabCase(propertyKeyOrContext);
67
90
  const path = properties.length
68
91
  ? `${kebabCasePath}/${properties.map((prop) => `{${prop}}`).join('/')}`
69
92
  : kebabCasePath;
70
- assignSchema({ controller, propertyKey, path, options, httpMethod });
93
+ assignSchema({ controller, propertyKey: propertyKeyOrContext, path, options, httpMethod });
71
94
  }
72
95
  return decorator;
73
96
  };
@@ -80,7 +103,7 @@ function createHTTPDecorator(httpMethod) {
80
103
  */
81
104
  export const prefix = (givenPath = '') => {
82
105
  const path = trimPath(givenPath);
83
- return (givenTarget) => {
106
+ return (givenTarget, _context) => {
84
107
  const controller = givenTarget;
85
108
  controller._prefix = path;
86
109
  return givenTarget;
@@ -90,16 +113,16 @@ export const prefix = (givenPath = '') => {
90
113
  * Clones metadata from parent controller to child controller.
91
114
  */
92
115
  export function cloneControllerMetadata() {
93
- return function inherit(c) {
116
+ return function inherit(c, _context) {
94
117
  const parent = Object.getPrototypeOf(c);
95
- const constructor = c;
96
- constructor._handlers = { ...parent._handlers, ...constructor._handlers };
97
- constructor._handlersMetadata = { ...parent._handlersMetadata, ...constructor._handlersMetadata };
118
+ const controller = c;
119
+ controller._handlers = { ...parent._handlers, ...controller._handlers };
120
+ controller._handlersMetadata = { ...parent._handlersMetadata, ...controller._handlersMetadata };
98
121
  Object.values(vovkApp.routes).forEach((methods) => {
99
122
  const parentMethods = methods.get(parent) ?? {};
100
- methods.set(constructor, { ...parentMethods, ...methods.get(constructor) });
123
+ methods.set(controller, { ...parentMethods, ...methods.get(controller) });
101
124
  });
102
- return constructor;
125
+ return controller;
103
126
  };
104
127
  }
105
128
  /**
@@ -115,6 +115,8 @@ class VovkApp {
115
115
  const candidateRoutes = routesByLength.get(pathLength) || [];
116
116
  for (const p of candidateRoutes) {
117
117
  const routeSegments = this.#routeSegmentsCache.get(p);
118
+ if (!routeSegments)
119
+ continue; // This should never happen, fix TS error
118
120
  const params = {};
119
121
  // Fast path for routes with parameters
120
122
  const paramPositions = this.#routeParamPositionsCache.get(p);
@@ -261,7 +263,7 @@ class VovkApp {
261
263
  }
262
264
  const isIterator = typeof result === 'object' &&
263
265
  !!result &&
264
- !(result instanceof Array) &&
266
+ !Array.isArray(result) &&
265
267
  ((Reflect.has(result, Symbol.iterator) &&
266
268
  typeof result[Symbol.iterator] === 'function') ||
267
269
  (Reflect.has(result, Symbol.asyncIterator) &&
@@ -1,2 +1,6 @@
1
1
  import { HttpStatus } from '../types/enums.js';
2
- export declare const error: (status: HttpStatus, message: string) => (target: import("../types/utils.js").KnownAny, propertyKey: string) => void;
2
+ export declare const error: (status: HttpStatus, message: string) => (target: import("../types/utils.js").KnownAny, propertyKeyOrContext: string | {
3
+ kind: string;
4
+ name: string | symbol;
5
+ addInitializer: (fn: () => void) => void;
6
+ }) => void;
@@ -37,7 +37,7 @@ export function applyComponentsSchemas(schema, components, mixinName) {
37
37
  const $ref = newObj.$ref;
38
38
  if ($ref && typeof $ref === 'string' && $ref.startsWith(`#/${key}/`)) {
39
39
  const componentName = $ref.replace(`#/${key}/`, '');
40
- if (components[componentName]) {
40
+ if (components?.[componentName]) {
41
41
  newObj.$ref = `#/$defs/${componentName}`;
42
42
  newObj['x-tsType'] ??= `Mixins.${upperFirst(camelCase(mixinName))}.${upperFirst(camelCase(componentName))}`;
43
43
  }
@@ -45,7 +45,7 @@ export function applyComponentsSchemas(schema, components, mixinName) {
45
45
  delete newObj.$ref; // Remove $ref if component not found (Telegram API has Type $refs that is not defined in components)
46
46
  }
47
47
  // Add the component to $defs if not already added
48
- if (!addedComponents.has(componentName) && components[componentName]) {
48
+ if (!addedComponents.has(componentName) && components?.[componentName]) {
49
49
  addedComponents.add(componentName);
50
50
  if (result.$defs) {
51
51
  result.$defs[componentName] = processSchema(cloneJSON(components[componentName]));
@@ -54,7 +54,7 @@ export function applyComponentsSchemas(schema, components, mixinName) {
54
54
  }
55
55
  // Process properties recursively
56
56
  for (const key in newObj) {
57
- if (Object.prototype.hasOwnProperty.call(newObj, key)) {
57
+ if (Object.hasOwn(newObj, key)) {
58
58
  newObj[key] = processSchema(newObj[key]);
59
59
  }
60
60
  }
@@ -1,10 +1,26 @@
1
1
  import type { VovkOperationObject } from '../types/operation.js';
2
- export declare const operationDecorator: (openAPIOperationObject?: VovkOperationObject | undefined) => (target: import("../types/utils.js").KnownAny, propertyKey: string) => void;
2
+ export declare const operationDecorator: (openAPIOperationObject?: VovkOperationObject | undefined) => (target: import("../types/utils.js").KnownAny, propertyKeyOrContext: string | {
3
+ kind: string;
4
+ name: string | symbol;
5
+ addInitializer: (fn: () => void) => void;
6
+ }) => void;
3
7
  /**
4
8
  * OpenAPI operation decorator to add metadata to API operations. Also includes `error` and `tool` utilities.
5
9
  * @see https://vovk.dev/openapi
6
10
  */
7
- export declare const operation: ((openAPIOperationObject?: VovkOperationObject | undefined) => (target: import("../types/utils.js").KnownAny, propertyKey: string) => void) & {
8
- error: (status: import("../index.js").HttpStatus, message: string) => (target: import("../types/utils.js").KnownAny, propertyKey: string) => void;
9
- tool: (toolOptions: import("../types/tools.js").VovkToolOptions) => (target: import("../types/utils.js").KnownAny, propertyKey: string) => void;
11
+ export declare const operation: ((openAPIOperationObject?: VovkOperationObject | undefined) => (target: import("../types/utils.js").KnownAny, propertyKeyOrContext: string | {
12
+ kind: string;
13
+ name: string | symbol;
14
+ addInitializer: (fn: () => void) => void;
15
+ }) => void) & {
16
+ error: (status: import("../index.js").HttpStatus, message: string) => (target: import("../types/utils.js").KnownAny, propertyKeyOrContext: string | {
17
+ kind: string;
18
+ name: string | symbol;
19
+ addInitializer: (fn: () => void) => void;
20
+ }) => void;
21
+ tool: (toolOptions: import("../types/tools.js").VovkToolOptions) => (target: import("../types/utils.js").KnownAny, propertyKeyOrContext: string | {
22
+ kind: string;
23
+ name: string | symbol;
24
+ addInitializer: (fn: () => void) => void;
25
+ }) => void;
10
26
  };
@@ -1,2 +1,6 @@
1
1
  import type { VovkToolOptions } from '../types/tools.js';
2
- export declare const tool: (toolOptions: VovkToolOptions) => (target: import("../types/utils.js").KnownAny, propertyKey: string) => void;
2
+ export declare const tool: (toolOptions: VovkToolOptions) => (target: import("../types/utils.js").KnownAny, propertyKeyOrContext: string | {
3
+ kind: string;
4
+ name: string | symbol;
5
+ addInitializer: (fn: () => void) => void;
6
+ }) => void;
@@ -91,7 +91,7 @@ export function vovkSchemaToOpenAPI({ config, rootEntry = 'api', schema: fullSch
91
91
  }))
92
92
  : null;
93
93
  const path = h.misc?.originalPath ??
94
- '/' + [rootEntry.replace(/^\/+|\/+$/g, ''), segmentName, c.prefix, h.path].filter(Boolean).join('/');
94
+ `/${[rootEntry.replace(/^\/+|\/+$/g, ''), segmentName, c.prefix, h.path].filter(Boolean).join('/')}`;
95
95
  paths[path] = paths[path] ?? {};
96
96
  const httpMethod = h.httpMethod.toLowerCase();
97
97
  paths[path][httpMethod] ??= {};
@@ -19,7 +19,10 @@ function parseKey(key) {
19
19
  // Now capture all bracket parts: [something], [0], []
20
20
  const bracketRegex = /\[([^[\]]*)\]/g;
21
21
  let match;
22
- while ((match = bracketRegex.exec(key)) !== null) {
22
+ while (true) {
23
+ match = bracketRegex.exec(key);
24
+ if (match === null)
25
+ break;
23
26
  // match[1] is the content inside the brackets
24
27
  segments.push(match[1]);
25
28
  }
@@ -44,7 +47,7 @@ function setValue(obj, path, value) {
44
47
  }
45
48
  current.push(value);
46
49
  }
47
- else if (!isNaN(Number(segment))) {
50
+ else if (!Number.isNaN(Number(segment))) {
48
51
  // Numeric segment => array index
49
52
  const idx = Number(segment);
50
53
  if (!Array.isArray(current)) {
@@ -70,9 +73,9 @@ function setValue(obj, path, value) {
70
73
  // for the next segment. We'll push something and move current to that.
71
74
  if (current.length === 0) {
72
75
  // nothing in array yet
73
- current.push(typeof nextSegment === 'string' && !isNaN(Number(nextSegment)) ? [] : {});
76
+ current.push(typeof nextSegment === 'string' && !Number.isNaN(Number(nextSegment)) ? [] : {});
74
77
  }
75
- else if (typeof nextSegment === 'string' && !isNaN(Number(nextSegment))) {
78
+ else if (typeof nextSegment === 'string' && !Number.isNaN(Number(nextSegment))) {
76
79
  // next is numeric => we want an array
77
80
  if (!Array.isArray(current[current.length - 1])) {
78
81
  current[current.length - 1] = [];
@@ -86,7 +89,7 @@ function setValue(obj, path, value) {
86
89
  }
87
90
  current = current[current.length - 1];
88
91
  }
89
- else if (!isNaN(Number(segment))) {
92
+ else if (!Number.isNaN(Number(segment))) {
90
93
  // segment is numeric => array index
91
94
  const idx = Number(segment);
92
95
  if (!Array.isArray(current)) {
@@ -94,7 +97,7 @@ function setValue(obj, path, value) {
94
97
  }
95
98
  if (current[idx] === undefined) {
96
99
  // Create placeholder for next segment
97
- current[idx] = typeof nextSegment === 'string' && !isNaN(Number(nextSegment)) ? [] : {};
100
+ current[idx] = typeof nextSegment === 'string' && !Number.isNaN(Number(nextSegment)) ? [] : {};
98
101
  }
99
102
  current = current[idx];
100
103
  }
@@ -102,7 +105,7 @@ function setValue(obj, path, value) {
102
105
  // segment is an object key
103
106
  if (current[segment] === undefined) {
104
107
  // Create placeholder
105
- current[segment] = typeof nextSegment === 'string' && !isNaN(Number(nextSegment)) ? [] : {};
108
+ current[segment] = typeof nextSegment === 'string' && !Number.isNaN(Number(nextSegment)) ? [] : {};
106
109
  }
107
110
  current = current[segment];
108
111
  }
@@ -81,7 +81,7 @@ ${[
81
81
  }`
82
82
  : '';
83
83
  const TS_CODE = `import { ${rpcName} } from '${packageName}';
84
- ${bodyValidation && isForm(bodyValidation) ? getTsFormSample(bodyValidation) + '\n' : ''}
84
+ ${bodyValidation && isForm(bodyValidation) ? `${getTsFormSample(bodyValidation)}\n` : ''}
85
85
  ${iterationValidation ? 'using' : 'const'} response = await ${rpcName}.${handlerName}(${tsArgs});
86
86
  ${outputValidation
87
87
  ? `
@@ -220,7 +220,7 @@ use serde_json::{
220
220
  json
221
221
  };
222
222
  ${iterationValidation ? 'use futures_util::StreamExt;\n' : ''}${bodyValidation && isForm(bodyValidation) ? `use reqwest::multipart;\n` : ''}#[tokio::main]
223
- async fn main() {${bodyValidation && isForm(bodyValidation) ? '\n ' + getRsFormSample(bodyValidation) + '\n' : ''}
223
+ async fn main() {${bodyValidation && isForm(bodyValidation) ? `\n ${getRsFormSample(bodyValidation)}\n` : ''}
224
224
  let response = ${rpcNameSnake}::${handlerNameSnake}(
225
225
  ${bodyValidation ? getBody(bodyValidation) : '()'}, /* body */
226
226
  ${queryValidation ? serdeUnwrap(getRsJSONSample(queryValidation)) : '()'}, /* query */
@@ -47,7 +47,7 @@ export function getSampleValue(schema, rootSchema, ignoreBinary) {
47
47
  }
48
48
  if (schema.allOf && schema.allOf.length > 0) {
49
49
  // Merge all schemas in allOf
50
- const mergedSchema = schema.allOf.reduce((acc, s) => ({ ...acc, ...s }), {});
50
+ const mergedSchema = schema.allOf.reduce((acc, s) => Object.assign(acc, s), {});
51
51
  return getSampleValue(mergedSchema, rootSchema, ignoreBinary);
52
52
  }
53
53
  // Handle different types
@@ -235,7 +235,7 @@ function handleObject(schema, rootSchema, ignoreBinary) {
235
235
  if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
236
236
  const value = getSampleValue(schema.additionalProperties, rootSchema, ignoreBinary);
237
237
  if (value !== undefined) {
238
- result['additionalProp'] = value;
238
+ result.additionalProp = value;
239
239
  }
240
240
  }
241
241
  return result;
@@ -32,7 +32,7 @@ export function schemaToObject(schema, rootSchema) {
32
32
  }
33
33
  if (schema.allOf && schema.allOf.length > 0) {
34
34
  // Merge all schemas in allOf
35
- const mergedSchema = schema.allOf.reduce((acc, s) => ({ ...acc, ...s }), {});
35
+ const mergedSchema = schema.allOf.reduce((acc, s) => Object.assign(acc, s), {});
36
36
  return schemaToObject(mergedSchema, rootSchema);
37
37
  }
38
38
  // Handle different types
@@ -148,7 +148,7 @@ function handleObject(schema, rootSchema) {
148
148
  }
149
149
  // Handle additionalProperties
150
150
  if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
151
- result['additionalProp'] = schemaToObject(schema.additionalProperties, rootSchema);
151
+ result.additionalProp = schemaToObject(schema.additionalProperties, rootSchema);
152
152
  }
153
153
  return result;
154
154
  }
@@ -1,2 +1,2 @@
1
- import { VovkJSONSchemaBase } from 'vovk';
1
+ import type { VovkJSONSchemaBase } from 'vovk';
2
2
  export declare function schemaToTsType(jsonSchema: VovkJSONSchemaBase | boolean): string;
@@ -9,6 +9,7 @@ export function createToolFactory({ toJSONSchema, }) {
9
9
  title,
10
10
  description,
11
11
  get parameters() {
12
+ // biome-ignore lint/suspicious/noAssignInExpressions: TODO
12
13
  return (parameters ??= inputSchema ? toJSONSchema(inputSchema, { validationType: 'tool-input', target }) : {});
13
14
  },
14
15
  inputSchema: inputSchema,
@@ -1,4 +1,4 @@
1
- import { DefaultModelOutput } from './toModelOutputDefault.js';
1
+ import type { DefaultModelOutput } from './toModelOutputDefault.js';
2
2
  import type { VovkRequest } from '../types/request.js';
3
3
  import type { VovkToolDerived, ToModelOutputFn } from '../types/tools.js';
4
4
  type DerivedToolInput = {
@@ -111,8 +111,7 @@ const makeTool = ({ moduleName, handlerName, module, meta, toModelOutput, onExec
111
111
  };
112
112
  export function deriveTools(options) {
113
113
  const { modules, meta, toModelOutput = ToModelOutput.DEFAULT, onExecute = (result) => result, onError = () => { }, } = options;
114
- const tools = Object.entries(modules ?? {})
115
- .map(([moduleName, module]) => {
114
+ const tools = Object.entries(modules ?? {}).flatMap(([moduleName, module]) => {
116
115
  return Object.entries(module ?? {})
117
116
  .filter(([, handler]) => handler?.schema?.operationObject && !handler?.schema?.operationObject?.['x-tool']?.hidden)
118
117
  .map(([handlerName]) => makeTool({
@@ -124,8 +123,7 @@ export function deriveTools(options) {
124
123
  onExecute,
125
124
  onError,
126
125
  }));
127
- })
128
- .flat();
126
+ });
129
127
  const toolsByName = Object.fromEntries(tools.map((tool) => [tool.name, tool]));
130
128
  return {
131
129
  tools,
@@ -10,28 +10,27 @@ import type { BodyTypeFromContentType, ContentType, VovkValidateOnClient } from
10
10
  type OmitNullable<T> = {
11
11
  [K in keyof T as T[K] extends null | undefined ? never : K]: T[K];
12
12
  };
13
- type Empty = {};
14
13
  export type StaticMethodInput<T extends ((req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => KnownAny) & {
15
14
  __types?: {
16
15
  contentType: ContentType[];
17
16
  };
18
17
  }> = OmitNullable<(Parameters<T>[0] extends VovkRequest<infer TBody, infer TQuery, infer TParams> ? (T['__types'] extends {
19
18
  contentType: infer CT extends ContentType[];
20
- } ? unknown extends TBody ? Empty : {
19
+ } ? unknown extends TBody ? unknown : {
21
20
  body: BodyTypeFromContentType<CT, TBody>;
22
21
  } : TBody extends Record<KnownAny, KnownAny> ? {
23
22
  body: TBody;
24
- } : Empty) & (TQuery extends Record<KnownAny, KnownAny> ? {
23
+ } : unknown) & (TQuery extends Record<KnownAny, KnownAny> ? {
25
24
  query: TQuery;
26
- } : Empty) & (TParams extends Record<KnownAny, KnownAny> ? {
25
+ } : unknown) & (TParams extends Record<KnownAny, KnownAny> ? {
27
26
  params: TParams;
28
- } : Empty) & {
27
+ } : unknown) & {
29
28
  meta?: {
30
29
  [key: string]: KnownAny;
31
30
  };
32
- } : Empty) & (Parameters<T>[1] extends Record<KnownAny, KnownAny> ? {
31
+ } : unknown) & (Parameters<T>[1] extends Record<KnownAny, KnownAny> ? {
33
32
  params: Parameters<T>[1];
34
- } : Empty)>;
33
+ } : unknown)>;
35
34
  type ToPromise<T> = T extends PromiseLike<unknown> ? T : Promise<T>;
36
35
  export type VovkStreamAsyncIterable<T> = {
37
36
  status: number;
@@ -49,7 +48,7 @@ type ActualReturnType<T extends ControllerStaticMethod> = T extends {
49
48
  } ? R : ReturnType<T>;
50
49
  type StaticMethodReturn<T extends ControllerStaticMethod> = IsNextJs extends true ? ActualReturnType<T> extends NextResponse<infer U> | Promise<NextResponse<infer U>> ? U : ActualReturnType<T> extends Response | Promise<Response> ? Awaited<ActualReturnType<T>> : ActualReturnType<T> : ActualReturnType<T> extends Response | Promise<Response> ? Awaited<ActualReturnType<T>> : ActualReturnType<T>;
51
50
  type StaticMethodReturnPromise<T extends ControllerStaticMethod> = ToPromise<StaticMethodReturn<T>>;
52
- type StaticMethodOptions<T extends (req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => void | object | JSONLinesResponder<TStreamIteration> | Promise<JSONLinesResponder<TStreamIteration>>, TFetcherOptions extends Record<string, KnownAny>, TStreamIteration, R, F extends VovkFetcherOptions<KnownAny>> = Partial<TFetcherOptions & {
51
+ type StaticMethodOptions<T extends (req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => undefined | object | JSONLinesResponder<TStreamIteration> | Promise<JSONLinesResponder<TStreamIteration>>, TFetcherOptions extends Record<string, KnownAny>, TStreamIteration, R, F extends VovkFetcherOptions<KnownAny>> = Partial<TFetcherOptions & {
53
52
  transform: (staticMethodReturn: T extends {
54
53
  __types: {
55
54
  iteration: infer U;
@@ -57,12 +56,12 @@ type StaticMethodOptions<T extends (req: VovkRequest<KnownAny, KnownAny, KnownAn
57
56
  } ? unknown extends U ? Awaited<StaticMethodReturn<T>> : VovkStreamAsyncIterable<U> : Awaited<StaticMethodReturn<T>> extends JSONLinesResponder<infer U> ? VovkStreamAsyncIterable<U> : Awaited<StaticMethodReturn<T>>, resp: Response) => R;
58
57
  fetcher: VovkFetcher<F>;
59
58
  }>;
60
- export type ClientMethodReturn<T extends (req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => void | object | JSONLinesResponder<TStreamIteration> | Promise<JSONLinesResponder<TStreamIteration>>, TStreamIteration, R> = R extends object ? Promise<Awaited<R>> : T extends {
59
+ export type ClientMethodReturn<T extends (req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => undefined | object | JSONLinesResponder<TStreamIteration> | Promise<JSONLinesResponder<TStreamIteration>>, TStreamIteration, R> = R extends object ? Promise<Awaited<R>> : T extends {
61
60
  __types: {
62
61
  iteration: infer U;
63
62
  };
64
63
  } ? unknown extends U ? StaticMethodReturnPromise<T> : Promise<VovkStreamAsyncIterable<U>> : ActualReturnType<T> extends Promise<JSONLinesResponder<infer U>> | JSONLinesResponder<infer U> | Iterator<infer U> | AsyncIterator<infer U> ? Promise<VovkStreamAsyncIterable<U>> : StaticMethodReturnPromise<T>;
65
- export type ClientMethod<T extends ((req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => void | object | JSONLinesResponder<TStreamIteration> | Promise<JSONLinesResponder<TStreamIteration>>) & {
64
+ export type ClientMethod<T extends ((req: VovkRequest<KnownAny, KnownAny, KnownAny>, params: KnownAny) => undefined | object | JSONLinesResponder<TStreamIteration> | Promise<JSONLinesResponder<TStreamIteration>>) & {
66
65
  __types?: {
67
66
  body: KnownAny;
68
67
  query: KnownAny;
@@ -1,5 +1,5 @@
1
- import { KnownAny } from './utils.js';
2
- import { ContentType } from './validation.js';
1
+ import type { KnownAny } from './utils.js';
2
+ import type { ContentType } from './validation.js';
3
3
  type Type = 'object' | 'array' | 'string' | 'number' | 'boolean' | 'null' | 'integer';
4
4
  /**
5
5
  * Base JSON Schema type used in Vovk.ts for validation and code generation.
@@ -1,5 +1,5 @@
1
1
  // Convert any value to string
2
- function toString(value) {
2
+ function valToString(value) {
3
3
  return value == null ? '' : String(value);
4
4
  }
5
5
  // Regex to match words (including Unicode letters & digits)
@@ -18,7 +18,7 @@ function unicodeWords(str) {
18
18
  * @returns {string}
19
19
  */
20
20
  export function camelCase(input) {
21
- const str = toString(input);
21
+ const str = valToString(input);
22
22
  // replace separators with space
23
23
  const sanitized = str.replace(/[\s_-]+/g, ' ').trim();
24
24
  const words = unicodeWords(sanitized);
@@ -24,17 +24,18 @@
24
24
  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25
25
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
26
  */
27
+ import type { KnownAny } from '../types/utils.js';
27
28
  type DeepPartial<T> = {
28
29
  [P in keyof T]?: T[P] extends (infer U)[] ? DeepPartial<U>[] : T[P] extends object ? DeepPartial<T[P]> : T[P];
29
30
  };
30
31
  type SpecificValue = Buffer | Date | RegExp;
31
- declare function isSpecificValue(val: any): val is SpecificValue;
32
+ declare function isSpecificValue(val: KnownAny): val is SpecificValue;
32
33
  declare function cloneSpecificValue(val: SpecificValue): SpecificValue;
33
34
  /**
34
35
  * Recursive cloning array.
35
36
  */
36
- declare function deepCloneArray<T = any>(arr: T[]): T[];
37
- declare function safeGetProperty<T extends object>(object: T, property: PropertyKey): any;
37
+ declare function deepCloneArray<T = KnownAny>(arr: T[]): T[];
38
+ declare function safeGetProperty<T extends object>(object: T, property: PropertyKey): KnownAny;
38
39
  /**
39
40
  * Extending object that entered in first argument.
40
41
  *
@@ -48,6 +49,6 @@ declare function deepExtend<T extends object>(...args: [T, ...Partial<T>[]]): T;
48
49
  declare function deepExtend<T extends object, U extends object>(target: T, source: U): T & U;
49
50
  declare function deepExtend<T extends object, U extends object, V extends object>(target: T, source1: U, source2: V): T & U & V;
50
51
  declare function deepExtend<T extends object, U extends object, V extends object, W extends object>(target: T, source1: U, source2: V, source3: W): T & U & V & W;
51
- declare function deepExtend<T extends object>(target: T, ...sources: any[]): T;
52
+ declare function deepExtend<T extends object>(target: T, ...sources: KnownAny[]): T;
52
53
  export { deepExtend, deepCloneArray, isSpecificValue, cloneSpecificValue, safeGetProperty };
53
54
  export type { DeepPartial, SpecificValue };
@@ -25,7 +25,6 @@
25
25
  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26
26
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
27
  */
28
- 'use strict';
29
28
  function isSpecificValue(val) {
30
29
  return val instanceof Buffer || val instanceof Date || val instanceof RegExp;
31
30
  }
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  ],
8
8
  "main": "./dist/index.js",
9
9
  "types": "./dist/index.d.ts",
10
- "version": "3.0.0",
10
+ "version": "3.0.3",
11
11
  "bin": {
12
12
  "vovk-cli-npx": "./bin/index.mjs"
13
13
  },
@@ -42,7 +42,7 @@
42
42
  "postbuild": "chmod +x ./bin/index.mjs",
43
43
  "build": "rm -f *.tsbuildinfo && tsc",
44
44
  "rm-dist": "rm -rf mjs cjs",
45
- "lint": "eslint . --fix",
45
+ "lint": "biome check --fix",
46
46
  "tsc": "tsc --noEmit",
47
47
  "npm-publish": "if [ -z \"$NPM_TAG\" ]; then echo 'Error: NPM_TAG is not set'; exit 1; fi; npm publish --tag=$NPM_TAG",
48
48
  "ncu": "npm-check-updates -u"