vovk 3.0.0-draft.95 → 3.0.0-draft.97

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.
@@ -1,14 +1,12 @@
1
+ import type { headers } from 'next/headers';
1
2
  import type { KnownAny, StreamAbortMessage } from './types';
2
3
  import './utils/shim';
3
4
  export declare class StreamJSONResponse<T> extends Response {
4
- static defaultHeaders: {
5
- 'content-type': string;
6
- };
7
5
  isClosed: boolean;
8
6
  controller?: ReadableStreamDefaultController;
9
7
  readonly encoder: TextEncoder;
10
8
  readonly readableStream: ReadableStream;
11
- constructor(init?: ResponseInit);
9
+ constructor(requestHeaders: Awaited<ReturnType<typeof headers>>, init?: ResponseInit);
12
10
  send(data: T | StreamAbortMessage): void;
13
11
  close(): void;
14
12
  throw(e: KnownAny): void;
@@ -3,14 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StreamJSONResponse = void 0;
4
4
  require("./utils/shim");
5
5
  class StreamJSONResponse extends Response {
6
- static defaultHeaders = {
7
- 'content-type': 'text/plain; x-format=jsonlines',
8
- };
9
6
  isClosed = false;
10
7
  controller;
11
8
  encoder;
12
9
  readableStream;
13
- constructor(init) {
10
+ constructor(requestHeaders, init) {
14
11
  const encoder = new TextEncoder();
15
12
  let readableController;
16
13
  const readableStream = new ReadableStream({
@@ -21,9 +18,16 @@ class StreamJSONResponse extends Response {
21
18
  readableController = controller;
22
19
  },
23
20
  });
21
+ if (!requestHeaders) {
22
+ throw new Error('Request headers are required');
23
+ }
24
+ const accept = requestHeaders.get('accept');
24
25
  super(readableStream, {
25
26
  ...init,
26
- headers: init?.headers ?? StreamJSONResponse.defaultHeaders,
27
+ headers: {
28
+ ...init?.headers,
29
+ 'Content-Type': accept?.includes('application/jsonl') ? 'application/jsonl' : 'plain/text',
30
+ },
27
31
  });
28
32
  this.readableStream = readableStream;
29
33
  this.encoder = encoder;
package/dist/VovkApp.js CHANGED
@@ -11,6 +11,7 @@ const StreamJSONResponse_1 = require("./StreamJSONResponse");
11
11
  const reqQuery_1 = __importDefault(require("./utils/reqQuery"));
12
12
  const reqMeta_1 = __importDefault(require("./utils/reqMeta"));
13
13
  const reqForm_1 = __importDefault(require("./utils/reqForm"));
14
+ const headers_1 = require("next/headers");
14
15
  class VovkApp {
15
16
  static getHeadersFromOptions(options) {
16
17
  if (!options)
@@ -143,9 +144,8 @@ class VovkApp {
143
144
  (Reflect.has(result, Symbol.asyncIterator) &&
144
145
  typeof result[Symbol.asyncIterator] === 'function'));
145
146
  if (isIterator && !(result instanceof Array)) {
146
- const streamResponse = new StreamJSONResponse_1.StreamJSONResponse({
147
+ const streamResponse = new StreamJSONResponse_1.StreamJSONResponse(await (0, headers_1.headers)(), {
147
148
  headers: {
148
- ...StreamJSONResponse_1.StreamJSONResponse.defaultHeaders,
149
149
  ..._a.getHeadersFromOptions(staticMethod._options),
150
150
  },
151
151
  });
@@ -28,6 +28,10 @@ const fetcher = async ({ httpMethod, getEndpoint, validate, defaultHandler, defa
28
28
  const init = {
29
29
  method: httpMethod,
30
30
  ...options,
31
+ headers: {
32
+ ...options.headers,
33
+ accept: 'application/jsonl, application/json',
34
+ },
31
35
  };
32
36
  if (body instanceof FormData) {
33
37
  init.body = body;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { createVovkApp } from './createVovkApp';
2
- import { HttpStatus as HttpStatus, HttpMethod as HttpMethod, type KnownAny, type VovkErrorResponse, type VovkRequest, type VovkBody, type VovkQuery, type VovkParams, type VovkReturnType, type VovkYieldType, type VovkControllerBody, type VovkControllerQuery, type VovkControllerParams, type VovkControllerYieldType, type VovkControllerOutput, type VovkSegmentSchema, type VovkControllerSchema, type VovkHandlerSchema, type VovkFullSchema, type VovkConfig, type VovkStrictConfig, type VovkEnv } from './types';
2
+ import { HttpStatus as HttpStatus, HttpMethod as HttpMethod, type KnownAny, type VovkErrorResponse, type VovkRequest, type VovkBody, type VovkQuery, type VovkParams, type VovkReturnType, type VovkYieldType, type VovkControllerBody, type VovkControllerQuery, type VovkControllerParams, type VovkControllerYieldType, type VovkControllerOutput, type VovkSegmentSchema, type VovkControllerSchema, type VovkHandlerSchema, type VovkFullSchema, type VovkConfig, type VovkStrictConfig, type VovkEnv, type VovkValidationType } from './types';
3
3
  import { type VovkClient, type VovkClientOptions, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkValidateOnClient, type VovkStreamAsyncIterable, createRPC, fetcher } from './client';
4
4
  import { HttpException } from './HttpException';
5
5
  import { createDecorator } from './createDecorator';
6
6
  import { StreamJSONResponse } from './StreamJSONResponse';
7
7
  import { generateStaticAPI } from './utils/generateStaticAPI';
8
8
  import { withValidation } from './utils/withValidation';
9
- export { type KnownAny, type VovkClient, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkStreamAsyncIterable, type VovkValidateOnClient, type VovkSegmentSchema, type VovkErrorResponse, type VovkRequest, type VovkControllerBody, type VovkControllerQuery, type VovkControllerParams, type VovkControllerYieldType, type VovkControllerOutput, type VovkBody, type VovkQuery, type VovkParams, type VovkYieldType, type VovkReturnType, type VovkClientOptions, type VovkControllerSchema, type VovkHandlerSchema, type VovkFullSchema, type VovkConfig, type VovkStrictConfig, type VovkEnv, StreamJSONResponse, HttpException, HttpStatus, HttpMethod, createVovkApp, createDecorator, createRPC, fetcher, generateStaticAPI, withValidation, };
9
+ export { type KnownAny, type VovkClient, type VovkClientFetcher, type VovkDefaultFetcherOptions, type VovkStreamAsyncIterable, type VovkValidateOnClient, type VovkSegmentSchema, type VovkErrorResponse, type VovkRequest, type VovkControllerBody, type VovkControllerQuery, type VovkControllerParams, type VovkControllerYieldType, type VovkControllerOutput, type VovkBody, type VovkQuery, type VovkParams, type VovkYieldType, type VovkReturnType, type VovkClientOptions, type VovkControllerSchema, type VovkHandlerSchema, type VovkFullSchema, type VovkConfig, type VovkStrictConfig, type VovkEnv, type VovkValidationType, StreamJSONResponse, HttpException, HttpStatus, HttpMethod, createVovkApp, createDecorator, createRPC, fetcher, generateStaticAPI, withValidation, };
10
10
  export declare const get: {
11
11
  (givenPath?: string | undefined, options?: import("./types").DecoratorOptions | undefined): ReturnType<(givenPath?: string, options?: import("./types").DecoratorOptions) => (givenTarget: KnownAny, propertyKey: string) => void>;
12
12
  auto: (options?: import("./types").DecoratorOptions) => (givenTarget: KnownAny, propertyKey: string) => void;
package/dist/types.d.ts CHANGED
@@ -10,8 +10,9 @@ export type VovkHandlerSchema = {
10
10
  validation?: {
11
11
  query?: KnownAny;
12
12
  body?: KnownAny;
13
- output?: KnownAny;
14
13
  params?: KnownAny;
14
+ output?: KnownAny;
15
+ iteration?: KnownAny;
15
16
  };
16
17
  openapi?: OperationObject;
17
18
  custom?: Record<string, KnownAny>;
@@ -82,6 +83,9 @@ export type VovkControllerYieldType<T extends (req: VovkRequest<KnownAny, KnownA
82
83
  export type VovkControllerOutput<T extends ((...args: KnownAny) => KnownAny) & {
83
84
  __output?: KnownAny;
84
85
  }> = T['__output'];
86
+ export type VovkControllerIteration<T extends ((...args: KnownAny) => KnownAny) & {
87
+ __iteration?: KnownAny;
88
+ }> = T['__iteration'];
85
89
  export type VovkBody<T extends (...args: KnownAny[]) => unknown> = Parameters<T>[0]['body'];
86
90
  export type VovkQuery<T extends (...args: KnownAny[]) => unknown> = Parameters<T>[0]['query'];
87
91
  export type VovkParams<T extends (...args: KnownAny[]) => unknown> = Parameters<T>[0]['params'];
@@ -110,12 +114,14 @@ export type VovkEnv = {
110
114
  __VOVK_START_WATCHER_IN_STANDALONE_MODE__?: 'true';
111
115
  __VOVK_EXIT__?: 'true' | 'false';
112
116
  };
113
- type GenerateFrom = (string | {
117
+ export type GenerateFromTemplate = {
114
118
  templatePath: string;
115
119
  outDir?: string;
116
120
  templateName?: string;
117
121
  fullSchema?: string | boolean;
118
- })[];
122
+ origin?: string | null;
123
+ };
124
+ type GenerateFrom = (string | GenerateFromTemplate)[];
119
125
  export type VovkConfig = {
120
126
  emitConfig?: boolean | (keyof VovkStrictConfig)[];
121
127
  clientOutDir?: string;
@@ -136,20 +142,21 @@ export type VovkConfig = {
136
142
  controller?: string;
137
143
  [key: string]: string | undefined;
138
144
  };
139
- custom?: Record<string, KnownAny>;
145
+ libs?: Record<string, KnownAny>;
140
146
  };
141
- export type VovkStrictConfig = Required<Omit<VovkConfig, 'emitConfig' | 'validateOnClientImport' | 'fetcherImport' | 'createRPCImport' | 'generateFrom' | 'custom'>> & {
147
+ export type VovkStrictConfig = Required<Omit<VovkConfig, 'emitConfig' | 'validateOnClientImport' | 'fetcherImport' | 'createRPCImport' | 'generateFrom' | 'libs'>> & {
142
148
  emitConfig: (keyof VovkStrictConfig)[];
143
149
  validateOnClientImport: string[] | null;
144
150
  fetcherImport: string[];
145
151
  createRPCImport: string[];
146
152
  generateFrom: GenerateFrom;
147
- custom: Record<string, KnownAny>;
153
+ libs: Record<string, KnownAny>;
148
154
  };
149
155
  export type VovkFullSchema = {
150
156
  config: Partial<VovkStrictConfig>;
151
157
  segments: Record<string, VovkSegmentSchema>;
152
158
  };
159
+ export type VovkValidationType = 'body' | 'query' | 'params' | 'output' | 'iteration';
153
160
  export declare enum HttpMethod {
154
161
  GET = "GET",
155
162
  POST = "POST",
@@ -1,13 +1,20 @@
1
- import { VovkHandlerSchema, 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>({ body, query, params, output, handle, getHandlerSchema, validate, }: {
1
+ import { VovkHandlerSchema, 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>({ skipServerSideValidation, skipSchemaEmission, validateEveryIteration, body, query, params, output, iteration, handle, getHandlerSchema, validate, }: {
3
+ skipServerSideValidation?: boolean | VovkValidationType[];
4
+ skipSchemaEmission?: boolean | VovkValidationType[];
5
+ validateEveryIteration?: boolean;
3
6
  body?: BODY_MODEL;
4
7
  query?: QUERY_MODEL;
5
8
  params?: PARAMS_MODEL;
6
9
  output?: OUTPUT_MODEL;
10
+ iteration?: ITERATION_MODEL;
7
11
  handle: T;
8
- getHandlerSchema?: () => Omit<VovkHandlerSchema, 'httpMethod' | 'path'>;
9
- validate: (data: KnownAny, model: NonNullable<BODY_MODEL | QUERY_MODEL | PARAMS_MODEL | OUTPUT_MODEL>, meta: {
10
- type: 'body' | 'query' | 'params' | 'output';
12
+ getHandlerSchema?: (options: {
13
+ skipSchemaEmissionKeys: VovkValidationType[];
14
+ }) => Omit<VovkHandlerSchema, 'httpMethod' | 'path'>;
15
+ validate: (data: KnownAny, model: NonNullable<BODY_MODEL | QUERY_MODEL | PARAMS_MODEL | OUTPUT_MODEL | ITERATION_MODEL>, meta: {
16
+ type: VovkValidationType;
11
17
  req: VovkRequest<KnownAny, KnownAny>;
18
+ status?: number;
12
19
  }) => KnownAny;
13
20
  }): T;
@@ -4,31 +4,61 @@ exports.withValidation = withValidation;
4
4
  const HttpException_1 = require("../HttpException");
5
5
  const types_1 = require("../types");
6
6
  const setHandlerSchema_1 = require("./setHandlerSchema");
7
- function withValidation({ body, query, params, output, handle, getHandlerSchema, validate, }) {
7
+ const validationTypes = ['body', 'query', 'params', 'output', 'iteration'];
8
+ function withValidation({ skipServerSideValidation, skipSchemaEmission, validateEveryIteration, body, query, params, output, iteration, handle, getHandlerSchema, validate, }) {
9
+ const skipServerSideValidationKeys = skipServerSideValidation === false
10
+ ? []
11
+ : skipServerSideValidation === true
12
+ ? validationTypes
13
+ : (skipServerSideValidation ?? []);
14
+ const skipSchemaEmissionKeys = skipSchemaEmission === false ? [] : skipSchemaEmission === true ? validationTypes : (skipSchemaEmission ?? []);
8
15
  const outputHandler = async (req, handlerParams) => {
9
16
  const data = await handle(req, handlerParams);
10
- if (output) {
17
+ if (output && iteration) {
18
+ throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, "Output and iteration are mutually exclusive. You can't use them together.");
19
+ }
20
+ if (output && !skipServerSideValidationKeys.includes('output')) {
11
21
  if (!data) {
12
22
  throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, 'Output is required. You probably forgot to return something from your handler.');
13
23
  }
14
24
  await validate(data, output, { type: 'output', req });
15
25
  }
26
+ if (iteration && !skipServerSideValidationKeys.includes('iteration')) {
27
+ // We assume `data` is an async iterable here; you might want to check that:
28
+ if (!data || typeof data[Symbol.asyncIterator] !== 'function') {
29
+ throw new HttpException_1.HttpException(types_1.HttpStatus.INTERNAL_SERVER_ERROR, 'Data is not an async iterable but iteration validation is defined.');
30
+ }
31
+ // Return a brand-new async generator that yields validated items
32
+ return (async function* () {
33
+ let i = 0;
34
+ for await (const item of data) {
35
+ if (validateEveryIteration || i === 0) {
36
+ await validate(item, iteration, { type: 'iteration', req, status: 200 });
37
+ }
38
+ i++;
39
+ yield item;
40
+ }
41
+ })();
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.');
45
+ }
16
46
  return data;
17
47
  };
18
48
  const resultHandler = async (req, handlerParams) => {
19
- if (body) {
49
+ if (body && !skipServerSideValidationKeys.includes('body')) {
20
50
  const data = await req.json();
21
51
  const instance = (await validate(data, body, { type: 'body', req })) ?? data;
22
52
  // redeclare to add ability to call req.json() again
23
53
  req.json = () => Promise.resolve(data);
24
54
  req.vovk.body = () => Promise.resolve(instance);
25
55
  }
26
- if (query) {
56
+ if (query && !skipServerSideValidationKeys.includes('query')) {
27
57
  const data = req.vovk.query();
28
58
  const instance = (await validate(data, query, { type: 'query', req })) ?? data;
29
59
  req.vovk.query = () => instance;
30
60
  }
31
- if (params) {
61
+ if (params && !skipServerSideValidationKeys.includes('params')) {
32
62
  const data = req.vovk.params();
33
63
  const instance = (await validate(data, params, { type: 'params', req })) ?? data;
34
64
  req.vovk.params = () => instance;
@@ -36,7 +66,7 @@ function withValidation({ body, query, params, output, handle, getHandlerSchema,
36
66
  return outputHandler(req, handlerParams);
37
67
  };
38
68
  if (getHandlerSchema) {
39
- (0, setHandlerSchema_1.setHandlerSchema)(resultHandler, getHandlerSchema());
69
+ (0, setHandlerSchema_1.setHandlerSchema)(resultHandler, getHandlerSchema({ skipSchemaEmissionKeys }));
40
70
  }
41
71
  return resultHandler;
42
72
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vovk",
3
- "version": "3.0.0-draft.95",
3
+ "version": "3.0.0-draft.97",
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.",