better-call 0.2.13-beta.1 → 0.2.13-beta.2
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/client.cjs +14 -0
- package/dist/client.d.cts +42 -0
- package/dist/client.d.mts +42 -0
- package/dist/client.d.ts +42 -0
- package/dist/client.mjs +12 -0
- package/dist/index.d.cts +4 -339
- package/dist/index.d.mts +4 -339
- package/dist/index.d.ts +4 -339
- package/dist/shared/better-call.342be6c5.d.cts +342 -0
- package/dist/shared/better-call.342be6c5.d.mts +342 -0
- package/dist/shared/better-call.342be6c5.d.ts +342 -0
- package/package.json +6 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,342 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { E as EndpointOptions, a as EndpointResponse, b as Endpoint, c as EndpointContext, C as CookiePrefixOptions, d as CookieOptions } from './shared/better-call.342be6c5.js';
|
|
2
|
+
export { i as Context, o as Cookie, p as CookieConstraint, H as HasRequiredKeys, l as InferResponse, I as Input, h as IsEmptyObject, J as JSONResponse, P as Prettify, g as RequiredKeysOf, R as Router, S as SignedCookie, U as UnionToIntersection, e as createEndpoint, k as createGetHeader, m as createJSON, f as createRouter, j as createSetHeader, n as fromError, q as parse, s as parseSigned, r as runValidation, t as serialize, u as serializeSigned } from './shared/better-call.342be6c5.js';
|
|
2
3
|
import { BufferSource } from 'stream/web';
|
|
3
|
-
|
|
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 {
|
|
60
|
-
/**
|
|
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
|
|
86
|
-
*/
|
|
87
|
-
use?: Endpoint[];
|
|
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
|
-
*/
|
|
144
|
-
path: Path;
|
|
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
|
-
};
|
|
287
|
-
};
|
|
288
|
-
declare function runValidation(options: EndpointOptions, context: EndpointContext<any, any>): ValidationResponse;
|
|
289
|
-
declare function fromError(error: ZodError): {
|
|
290
|
-
message: string;
|
|
291
|
-
};
|
|
292
|
-
|
|
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;
|
|
297
|
-
};
|
|
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;
|
|
302
|
-
|
|
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
|
-
};
|
|
4
|
+
import 'zod';
|
|
340
5
|
|
|
341
6
|
type MiddlewareHandler<Options extends EndpointOptions, R extends EndpointResponse> = (context: EndpointContext<any, Options>) => Promise<R>;
|
|
342
7
|
declare function createMiddleware<Opts extends EndpointOptions, R extends EndpointResponse>(optionsOrHandler: MiddlewareHandler<Opts, R>): Endpoint<MiddlewareHandler<Opts, R>, Opts>;
|
|
@@ -347,4 +12,4 @@ declare const setCookie: (header: Headers, name: string, value: string, opt?: Co
|
|
|
347
12
|
declare const setSignedCookie: (header: Headers, name: string, value: string, secret: string | BufferSource, opt?: CookieOptions) => Promise<void>;
|
|
348
13
|
declare const getSignedCookie: (header: Headers, secret: string, key: string, prefix?: CookiePrefixOptions) => Promise<string | false | undefined>;
|
|
349
14
|
|
|
350
|
-
export {
|
|
15
|
+
export { CookieOptions, CookiePrefixOptions, Endpoint, EndpointContext, EndpointResponse, createMiddleware, getCookie, getSignedCookie, setCookie, setSignedCookie };
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { ZodSchema, ZodError } from 'zod';
|
|
2
|
+
import { BufferSource } from 'stream/web';
|
|
3
|
+
|
|
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 {
|
|
60
|
+
/**
|
|
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
|
|
86
|
+
*/
|
|
87
|
+
use?: Endpoint[];
|
|
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
|
+
*/
|
|
144
|
+
path: Path;
|
|
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
|
+
};
|
|
287
|
+
};
|
|
288
|
+
declare function runValidation(options: EndpointOptions, context: EndpointContext<any, any>): ValidationResponse;
|
|
289
|
+
declare function fromError(error: ZodError): {
|
|
290
|
+
message: string;
|
|
291
|
+
};
|
|
292
|
+
|
|
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;
|
|
297
|
+
};
|
|
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;
|
|
302
|
+
|
|
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
|
+
};
|
|
340
|
+
type Router = ReturnType<typeof createRouter>;
|
|
341
|
+
|
|
342
|
+
export { type CookiePrefixOptions as C, type EndpointOptions as E, type HasRequiredKeys as H, type Input as I, type JSONResponse as J, type Prettify as P, type Router as R, type SignedCookie as S, type UnionToIntersection as U, type EndpointResponse as a, type Endpoint as b, type EndpointContext as c, type CookieOptions as d, createEndpoint as e, createRouter as f, type RequiredKeysOf as g, type IsEmptyObject as h, type Context as i, createSetHeader as j, createGetHeader as k, type InferResponse as l, createJSON as m, fromError as n, type Cookie as o, type CookieConstraint as p, parse as q, runValidation as r, parseSigned as s, serialize as t, serializeSigned as u };
|