better-call 0.2.11 → 0.2.13-beta.1

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/index.d.cts CHANGED
@@ -1,127 +1,350 @@
1
- import { E as Endpoint, a as EndpointOptions, b as EndpointResponse, P as Prettify, C as Context, I as InferUse, c as ContextTools, H as HasRequiredKeys, M as Method, d as Handler, e as InferBody, f as InferRequest, g as InferHeaders, h as InferUseOptions, R as Router, i as CookiePrefixOptions, j as CookieOptions } from './router-DIrNt-mY.cjs';
2
- export { A as APIError, u as Cookie, v as CookieConstraint, t as EndpointBody, p as InferMethod, r as InferParam, n as InferParamPath, o as InferParamWildCard, q as InferQuery, S as SignedCookie, k as createRouter, l as getBody, w as parse, x as parseSigned, y as serialize, z as serializeSigned, s as shouldSerialize, m as statusCode } from './router-DIrNt-mY.cjs';
3
- import { IncomingMessage, ServerResponse } from 'node:http';
4
- import 'zod';
1
+ import { ZodSchema, ZodError } from 'zod';
2
+ import { BufferSource } from 'stream/web';
5
3
 
6
- interface EndpointConfig {
4
+ type Cookie = Record<string, string>;
5
+ type SignedCookie = Record<string, string | false>;
6
+ type PartitionCookieConstraint = {
7
+ partition: true;
8
+ secure: true;
9
+ } | {
10
+ partition?: boolean;
11
+ secure?: boolean;
12
+ };
13
+ type SecureCookieConstraint = {
14
+ secure: true;
15
+ };
16
+ type HostCookieConstraint = {
17
+ secure: true;
18
+ path: "/";
19
+ domain?: undefined;
20
+ };
21
+ type CookieOptions = {
22
+ domain?: string;
23
+ expires?: Date;
24
+ httpOnly?: boolean;
25
+ maxAge?: number;
26
+ path?: string;
27
+ secure?: boolean;
28
+ signingSecret?: string;
29
+ sameSite?: "Strict" | "Lax" | "None" | "strict" | "lax" | "none";
30
+ partitioned?: boolean;
31
+ prefix?: CookiePrefixOptions;
32
+ } & PartitionCookieConstraint;
33
+ type CookiePrefixOptions = "host" | "secure";
34
+ type CookieConstraint<Name> = Name extends `__Secure-${string}` ? CookieOptions & SecureCookieConstraint : Name extends `__Host-${string}` ? CookieOptions & HostCookieConstraint : CookieOptions;
35
+ declare const parse: (cookie: string, name?: string) => Cookie;
36
+ declare const parseSigned: (cookie: string, secret: string | BufferSource, name?: string) => Promise<SignedCookie>;
37
+ declare const serialize: <Name extends string>(name: Name, value: string, opt?: CookieConstraint<Name>) => string;
38
+ declare const serializeSigned: (name: string, value: string, secret: string | BufferSource, opt?: CookieOptions) => Promise<string>;
39
+
40
+ /**
41
+ * Improve this type if possible
42
+ */
43
+ type Input<T> = Prettify<{
44
+ [K in keyof T as T[K] extends never ? never : undefined extends T[K] ? never : K]: T[K];
45
+ } & {
46
+ [K in keyof T as undefined extends T[K] ? K : never]?: T[K];
47
+ }>;
48
+ type RequiredKeysOf<BaseType extends object> = Exclude<{
49
+ [Key in keyof BaseType]: BaseType extends Record<Key, BaseType[Key]> ? Key : never;
50
+ }[keyof BaseType], undefined>;
51
+ type HasRequiredKeys<BaseType extends object> = RequiredKeysOf<BaseType> extends never ? false : true;
52
+ type Prettify<T> = {
53
+ [K in keyof T]: T[K];
54
+ } & {};
55
+ type IsEmptyObject<T> = keyof T extends never ? true : false;
56
+ type UnionToIntersection<Union> = (Union extends unknown ? (distributedUnion: Union) => void : never) extends (mergedIntersection: infer Intersection) => void ? Intersection & Union : never;
57
+
58
+ type Method = "GET" | "POST" | "PUT" | "DELETE" | "*";
59
+ interface EndpointOptions {
7
60
  /**
8
- * Throw when the response isn't in 200 range
61
+ * Request Method
62
+ */
63
+ method: Method | Method[];
64
+ /**
65
+ * Body Schema
66
+ */
67
+ body?: ZodSchema;
68
+ /**
69
+ * Query Schema
70
+ */
71
+ query?: ZodSchema;
72
+ /**
73
+ * If true headers will be required to be passed in the context
74
+ */
75
+ requireHeaders?: boolean;
76
+ /**
77
+ * If true request object will be required
78
+ */
79
+ requireRequest?: boolean;
80
+ /**
81
+ * Endpoint metadata
82
+ */
83
+ metadata?: Record<string, any>;
84
+ /**
85
+ * Middleware to use
9
86
  */
10
- throwOnError?: boolean;
11
- }
12
- declare function createEndpointCreator<E extends {
13
87
  use?: Endpoint[];
14
- }>(opts?: E): <Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: (ctx: Prettify<Context<Path, Opts> & InferUse<Opts["use"]> & InferUse<E["use"]> & Omit<ContextTools, "_flag">>) => Promise<R>) => {
15
- <C extends HasRequiredKeys<Context<Path, Opts>> extends true ? [Context<Path, Opts>] : [(Context<Path, Opts> | undefined)?]>(...ctx: C): Promise<C extends [{
16
- asResponse: true;
17
- }] ? Response : R extends {
18
- _flag: "json";
19
- } ? R extends {
20
- body: infer B;
21
- } ? B : null : Awaited<R>>;
88
+ }
89
+ type InferBody<Options extends EndpointOptions> = Options["body"] extends ZodSchema<infer T> ? T : never;
90
+ type InferQuery<Options extends EndpointOptions> = Options["query"] extends ZodSchema<infer T> ? T : never;
91
+ type InferParamPath<Path> = Path extends `${infer _Start}:${infer Param}/${infer Rest}` ? {
92
+ [K in Param | keyof InferParamPath<Rest>]: string;
93
+ } : Path extends `${infer _Start}:${infer Param}` ? {
94
+ [K in Param]: string;
95
+ } : Path extends `${infer _Start}/${infer Rest}` ? InferParamPath<Rest> : {};
96
+ type InferParamWildCard<Path> = Path extends `${infer _Start}/*:${infer Param}/${infer Rest}` | `${infer _Start}/**:${infer Param}/${infer Rest}` ? {
97
+ [K in Param | keyof InferParamPath<Rest>]: string;
98
+ } : Path extends `${infer _Start}/*` ? {
99
+ [K in "_"]: string;
100
+ } : Path extends `${infer _Start}/${infer Rest}` ? InferParamPath<Rest> : {};
101
+ type InferParam<Path extends string> = IsEmptyObject<InferParamPath<Path> & InferParamWildCard<Path>> extends true ? never : Prettify<InferParamPath<Path> & InferParamWildCard<Path>>;
102
+ type InferRequest<Option extends EndpointOptions> = Option["requireRequest"] extends true ? Request : Request | undefined;
103
+ type InferHeaders<Option extends EndpointOptions> = Option["requireHeaders"] extends true ? Headers : Headers | undefined;
104
+ type InferUse<Opts extends EndpointOptions["use"]> = Opts extends Endpoint[] ? UnionToIntersection<Awaited<ReturnType<Opts[number]>>> : never;
105
+ type InferMethod<Options extends EndpointOptions> = Options["method"] extends Array<Method> ? Options["method"][number] : Options["method"];
106
+
107
+ declare class APIError extends Error {
108
+ message: string;
109
+ status: number;
110
+ code: string;
111
+ headers: {};
112
+ constructor(message: string, status?: number, code?: string, headers?: {});
113
+ }
114
+
115
+ interface EndpointContext<Path extends string, Options extends EndpointOptions> {
116
+ /**
117
+ * JSON
118
+ *
119
+ * a helper function to create a JSON response with the correct headers
120
+ * and status code. If `asResponse` is set to true in the context then
121
+ * it will return a Response object instead of the JSON object.
122
+ *
123
+ * @param json - The JSON object to return
124
+ * @param routerResponse - The response object to return if `asResponse` is
125
+ * true in the context this will take precedence
126
+ */
127
+ json: <R extends Record<string, any>>(json: R, routerResponse?: {
128
+ status?: number;
129
+ headers?: Record<string, string>;
130
+ response?: Response;
131
+ } | Response) => Promise<R>;
132
+ /**
133
+ * Body
134
+ *
135
+ * The body object will be the parsed JSON from the request and validated
136
+ * against the body schema if it exists
137
+ */
138
+ body: InferBody<Options>;
139
+ /**
140
+ * Path
141
+ *
142
+ * The path of the endpoint
143
+ */
22
144
  path: Path;
23
- options: Opts;
24
- method: Method | Method[];
25
- headers: Headers;
145
+ /**
146
+ * Method
147
+ */
148
+ method: InferMethod<Options>;
149
+ /**
150
+ * Query
151
+ *
152
+ * The query object will be the parsed query string from the request
153
+ * and validated against the query schema if it exists
154
+ */
155
+ query: InferQuery<Options>;
156
+ /**
157
+ * Params
158
+ *
159
+ * If the path is `/user/:id` and the request is `/user/1` then the params will
160
+ * be `{ id: "1" }` and if the path includes a wildcard like `/user/*` then the
161
+ * params will be `{ _: "1" }` where `_` is the wildcard key. If the wildcard
162
+ * is named like `/user/**:name` then the params will be `{ name: string }`
163
+ */
164
+ params: InferParam<Path>;
165
+ /**
166
+ * Request object
167
+ *
168
+ * If `requireRequest` is set to true in the endpoint options this will be
169
+ * required
170
+ */
171
+ request: InferRequest<Options>;
172
+ /**
173
+ * Headers
174
+ *
175
+ * If `requireHeaders` is set to true in the endpoint options this will be
176
+ * required
177
+ */
178
+ headers: InferHeaders<Options>;
179
+ /**
180
+ * Middleware context
181
+ */
182
+ context: InferUse<Options["use"]>;
183
+ /**
184
+ * Set header
185
+ *
186
+ * If it's called outside of a request it will just be ignored.
187
+ */
188
+ setHeader: (key: string, value: string) => void;
189
+ /**
190
+ * Get header
191
+ *
192
+ * If it's called outside of a request it will just return null
193
+ *
194
+ * @param key - The key of the header
195
+ * @returns
196
+ */
197
+ getHeader: (key: string) => string | null;
198
+ /**
199
+ * cookie setter.
200
+ *
201
+ * If it's called outside of a request it will just be ignored.
202
+ */
203
+ setCookie: (key: string, value: string, options?: CookieOptions) => void;
204
+ /**
205
+ * Get cookie value
206
+ *
207
+ * If it's called outside of a request it will just be ignored.
208
+ */
209
+ getCookie: (key: string, prefix?: CookiePrefixOptions) => string | undefined;
210
+ /**
211
+ * Set signed cookie
212
+ */
213
+ setSignedCookie: (key: string, value: string, secret: string | BufferSource, options?: CookieOptions) => Promise<void>;
214
+ /**
215
+ * Get signed cookie value
216
+ */
217
+ getSignedCookie: (key: string, secret: string, prefix?: CookiePrefixOptions) => Promise<string | undefined | false>;
218
+ /**
219
+ * Redirect to url
220
+ */
221
+ redirect: (url: string) => APIError;
222
+ }
223
+ type Context<Path extends string, Options extends EndpointOptions> = Input<{
224
+ body: InferBody<Options>;
225
+ method?: InferMethod<Options>;
226
+ query: InferQuery<Options>;
227
+ params: InferParam<Path>;
228
+ request: InferRequest<Options>;
229
+ headers: InferHeaders<Options>;
230
+ asResponse?: boolean;
231
+ }>;
232
+ declare function createSetHeader(headers: Headers): (key: string, value: string) => void;
233
+ declare function createGetHeader(headers: Headers): (key: string) => string | null;
234
+
235
+ interface JSONResponse<R = any> {
236
+ /**
237
+ * Body of the response
238
+ * It'll be inferred as the response body.
239
+ * and on the server side this will be returned
240
+ * as a response of a handler.
241
+ */
242
+ body: R;
243
+ /**
244
+ * The actual response object
245
+ */
246
+ routerResponse: {
247
+ body?: Record<string, any>;
248
+ status?: number;
249
+ headers?: Record<string, string>;
250
+ };
251
+ /**
252
+ * Flag to identify the response type
253
+ */
254
+ _flag: "json";
255
+ }
256
+ type EndpointResponse = JSONResponse | Response | void | Record<string, any>;
257
+ type InferResponse<Ctx, R> = Ctx extends {
258
+ asResponse: true;
259
+ } ? Response : R extends JSONResponse<infer T> ? T : R;
260
+ declare function createJSON({ asResponse, response, }: {
261
+ asResponse?: boolean;
262
+ response: Response;
263
+ }): <R extends Record<string, any>>(json: R, routerResponse?: {
264
+ status?: number;
265
+ headers?: Record<string, string>;
266
+ response?: Response;
267
+ }) => Promise<R | {
268
+ body: R;
269
+ routerResponse: {
270
+ status?: number;
271
+ headers?: Record<string, string>;
272
+ response?: Response;
273
+ } | undefined;
274
+ _flag: string;
275
+ }>;
276
+ type ValidationResponse = {
277
+ data: {
278
+ body: any;
279
+ query: any;
280
+ };
281
+ error: null;
282
+ } | {
283
+ data: null;
284
+ error: {
285
+ message: string;
286
+ };
26
287
  };
27
- declare function createEndpoint<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: Handler<Path, Opts, R>): {
28
- <C extends HasRequiredKeys<Context<Path, Opts>> extends true ? [Context<Path, Opts>] : [Context<Path, Opts>?]>(...ctx: C): Promise<C extends [{
29
- asResponse: true;
30
- }] ? Response : R extends {
31
- _flag: "json";
32
- } ? R extends {
33
- body: infer B;
34
- } ? B : null : Awaited<R>>;
35
- path: Path;
36
- options: Opts;
37
- method: Method | Method[];
38
- headers: Headers;
288
+ declare function runValidation(options: EndpointOptions, context: EndpointContext<any, any>): ValidationResponse;
289
+ declare function fromError(error: ZodError): {
290
+ message: string;
39
291
  };
40
292
 
41
- type MiddlewareHandler<Opts extends EndpointOptions, R extends EndpointResponse, Extra extends Record<string, any> = {}> = (ctx: Prettify<InferBody<Opts> & InferRequest<Opts> & InferHeaders<Opts> & {
42
- params?: Record<string, string>;
43
- query?: Record<string, string>;
44
- } & ContextTools> & Extra) => Promise<R>;
45
- declare function createMiddleware<Opts extends EndpointOptions, R extends EndpointResponse>(optionsOrHandler: MiddlewareHandler<Opts, R>): Endpoint<Handler<string, Opts, R>, Opts>;
46
- declare function createMiddleware<Opts extends Omit<EndpointOptions, "method">, R extends EndpointResponse>(optionsOrHandler: Opts, handler: MiddlewareHandler<Opts & {
47
- method: "*";
48
- }, R>): Endpoint<Handler<string, Opts & {
49
- method: "*";
50
- }, R>, Opts & {
51
- method: "*";
52
- }>;
53
- declare const createMiddlewareCreator: <E extends {
54
- use?: Endpoint[];
55
- }>(opts?: E) => {
56
- <Opts extends EndpointOptions, R extends EndpointResponse>(optionsOrHandler: (ctx: InferBody<Opts, Opts["body"] & (undefined extends InferUseOptions<Opts>["body"] ? {} : InferUseOptions<Opts>["body"])> & InferUse<E["use"]> & InferRequest<Opts, Opts["requireRequest"]> & InferHeaders<Opts, Opts["requireHeaders"]> & {
57
- params?: Record<string, string>;
58
- query?: Record<string, string>;
59
- } & ContextTools extends infer T ? { [key in keyof T]: (InferBody<Opts, Opts["body"] & (undefined extends InferUseOptions<Opts>["body"] ? {} : InferUseOptions<Opts>["body"])> & InferUse<E["use"]> & InferRequest<Opts, Opts["requireRequest"]> & InferHeaders<Opts, Opts["requireHeaders"]> & {
60
- params?: Record<string, string>;
61
- query?: Record<string, string>;
62
- } & ContextTools)[key]; } : never) => Promise<R>): Endpoint<Handler<string, Opts, R>, Opts>;
63
- <Opts extends Omit<EndpointOptions, "method">, R_1 extends EndpointResponse>(optionsOrHandler: Opts, handler: (ctx: InferBody<Opts & {
64
- method: "*";
65
- }, (Opts & {
66
- method: "*";
67
- })["body"] & (undefined extends InferUseOptions<Opts & {
68
- method: "*";
69
- }>["body"] ? {} : InferUseOptions<Opts & {
70
- method: "*";
71
- }>["body"])> & InferUse<E["use"]> & InferRequest<Opts & {
72
- method: "*";
73
- }, (Opts & {
74
- method: "*";
75
- })["requireRequest"]> & InferHeaders<Opts & {
76
- method: "*";
77
- }, (Opts & {
78
- method: "*";
79
- })["requireHeaders"]> & {
80
- params?: Record<string, string>;
81
- query?: Record<string, string>;
82
- } & ContextTools extends infer T ? { [key in keyof T]: (InferBody<Opts & {
83
- method: "*";
84
- }, (Opts & {
85
- method: "*";
86
- })["body"] & (undefined extends InferUseOptions<Opts & {
87
- method: "*";
88
- }>["body"] ? {} : InferUseOptions<Opts & {
89
- method: "*";
90
- }>["body"])> & InferUse<E["use"]> & InferRequest<Opts & {
91
- method: "*";
92
- }, (Opts & {
93
- method: "*";
94
- })["requireRequest"]> & InferHeaders<Opts & {
95
- method: "*";
96
- }, (Opts & {
97
- method: "*";
98
- })["requireHeaders"]> & {
99
- params?: Record<string, string>;
100
- query?: Record<string, string>;
101
- } & ContextTools)[key]; } : never) => Promise<R_1>): Endpoint<Handler<string, Opts & {
102
- method: "*";
103
- }, R_1>, Opts & {
104
- method: "*";
105
- }>;
293
+ declare const createEndpoint: <Path extends string, Options extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Options, handler: (context: EndpointContext<Path, Options>) => Promise<R>) => {
294
+ <Ctx extends Context<Path, Options>>(...inputCtx: HasRequiredKeys<Ctx> extends true ? [Ctx] : [Ctx?]): Promise<Ctx["asResponse"] extends true ? Response : R>;
295
+ path: Path;
296
+ options: Options;
106
297
  };
107
- type Middleware<Opts extends EndpointOptions = EndpointOptions, R extends EndpointResponse = EndpointResponse> = (opts: Opts, handler: (ctx: {
108
- body?: InferBody<Opts>;
109
- params?: Record<string, string>;
110
- query?: Record<string, string>;
111
- }) => Promise<R>) => Endpoint;
298
+ type Endpoint<Handler extends (ctx: any) => Promise<any> = (ctx: any) => Promise<any>, Options extends EndpointOptions = EndpointOptions> = {
299
+ path: string;
300
+ options: Options;
301
+ } & Handler;
112
302
 
113
- declare function getRequest({ request, base, bodySizeLimit, }: {
114
- base: string;
115
- bodySizeLimit?: number;
116
- request: IncomingMessage;
117
- }): Request;
118
- declare function setResponse(res: ServerResponse, response: Response): Promise<void>;
303
+ interface RouterConfig {
304
+ /**
305
+ * Throw error if error occurred other than APIError
306
+ */
307
+ throwError?: boolean;
308
+ /**
309
+ * Handle error
310
+ */
311
+ onError?: (e: unknown) => void | Promise<void> | Response | Promise<Response>;
312
+ /**
313
+ * Base path for the router
314
+ */
315
+ basePath?: string;
316
+ /**
317
+ * Middlewares for the router
318
+ */
319
+ routerMiddleware?: {
320
+ path: string;
321
+ middleware: Endpoint;
322
+ }[];
323
+ /**
324
+ * On response interceptor
325
+ */
326
+ onResponse?: (res: Response) => any | Promise<any>;
327
+ /**
328
+ * On request interceptor
329
+ */
330
+ onRequest?: (req: Request) => any | Promise<any>;
331
+ /**
332
+ * Extra context to pass to the handler
333
+ */
334
+ extraContext?: Record<string, any>;
335
+ }
336
+ declare const createRouter: <E extends Record<string, Endpoint>, Config extends RouterConfig>(endpoints: E, config?: Config) => {
337
+ handler: (request: Request) => Promise<Response>;
338
+ endpoints: E;
339
+ };
119
340
 
120
- declare function toNodeHandler(handler: Router["handler"]): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
341
+ type MiddlewareHandler<Options extends EndpointOptions, R extends EndpointResponse> = (context: EndpointContext<any, Options>) => Promise<R>;
342
+ declare function createMiddleware<Opts extends EndpointOptions, R extends EndpointResponse>(optionsOrHandler: MiddlewareHandler<Opts, R>): Endpoint<MiddlewareHandler<Opts, R>, Opts>;
343
+ declare function createMiddleware<Opts extends EndpointOptions, R extends EndpointResponse>(optionsOrHandler: Opts, handler: MiddlewareHandler<Opts, R>): Endpoint<MiddlewareHandler<Opts, R>, Opts>;
121
344
 
122
345
  declare const getCookie: (cookie: string, key: string, prefix?: CookiePrefixOptions) => string | undefined;
123
346
  declare const setCookie: (header: Headers, name: string, value: string, opt?: CookieOptions) => void;
124
347
  declare const setSignedCookie: (header: Headers, name: string, value: string, secret: string | BufferSource, opt?: CookieOptions) => Promise<void>;
125
348
  declare const getSignedCookie: (header: Headers, secret: string, key: string, prefix?: CookiePrefixOptions) => Promise<string | false | undefined>;
126
349
 
127
- export { Context, ContextTools, CookieOptions, CookiePrefixOptions, Endpoint, type EndpointConfig, EndpointOptions, EndpointResponse, Handler, InferBody, InferHeaders, InferRequest, InferUse, InferUseOptions, Method, type Middleware, type MiddlewareHandler, Prettify, Router, createEndpoint, createEndpointCreator, createMiddleware, createMiddlewareCreator, getCookie, getRequest, getSignedCookie, setCookie, setResponse, setSignedCookie, toNodeHandler };
350
+ export { type Context, type Cookie, type CookieConstraint, type CookieOptions, type CookiePrefixOptions, type Endpoint, type EndpointContext, type EndpointResponse, type HasRequiredKeys, type InferResponse, type Input, type IsEmptyObject, type JSONResponse, type Prettify, type RequiredKeysOf, type SignedCookie, type UnionToIntersection, createEndpoint, createGetHeader, createJSON, createMiddleware, createRouter, createSetHeader, fromError, getCookie, getSignedCookie, parse, parseSigned, runValidation, serialize, serializeSigned, setCookie, setSignedCookie };