better-call 0.3.3-beta.6 → 1.0.0-beta.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.
@@ -0,0 +1,1209 @@
1
+ import { StandardSchemaV1 } from '@standard-schema/spec';
2
+
3
+ declare const _statusCode: {
4
+ OK: number;
5
+ CREATED: number;
6
+ ACCEPTED: number;
7
+ NO_CONTENT: number;
8
+ MULTIPLE_CHOICES: number;
9
+ MOVED_PERMANENTLY: number;
10
+ FOUND: number;
11
+ SEE_OTHER: number;
12
+ NOT_MODIFIED: number;
13
+ TEMPORARY_REDIRECT: number;
14
+ BAD_REQUEST: number;
15
+ UNAUTHORIZED: number;
16
+ PAYMENT_REQUIRED: number;
17
+ FORBIDDEN: number;
18
+ NOT_FOUND: number;
19
+ METHOD_NOT_ALLOWED: number;
20
+ NOT_ACCEPTABLE: number;
21
+ PROXY_AUTHENTICATION_REQUIRED: number;
22
+ REQUEST_TIMEOUT: number;
23
+ CONFLICT: number;
24
+ GONE: number;
25
+ LENGTH_REQUIRED: number;
26
+ PRECONDITION_FAILED: number;
27
+ PAYLOAD_TOO_LARGE: number;
28
+ URI_TOO_LONG: number;
29
+ UNSUPPORTED_MEDIA_TYPE: number;
30
+ RANGE_NOT_SATISFIABLE: number;
31
+ EXPECTATION_FAILED: number;
32
+ "I'M_A_TEAPOT": number;
33
+ MISDIRECTED_REQUEST: number;
34
+ UNPROCESSABLE_ENTITY: number;
35
+ LOCKED: number;
36
+ FAILED_DEPENDENCY: number;
37
+ TOO_EARLY: number;
38
+ UPGRADE_REQUIRED: number;
39
+ PRECONDITION_REQUIRED: number;
40
+ TOO_MANY_REQUESTS: number;
41
+ REQUEST_HEADER_FIELDS_TOO_LARGE: number;
42
+ UNAVAILABLE_FOR_LEGAL_REASONS: number;
43
+ INTERNAL_SERVER_ERROR: number;
44
+ NOT_IMPLEMENTED: number;
45
+ BAD_GATEWAY: number;
46
+ SERVICE_UNAVAILABLE: number;
47
+ GATEWAY_TIMEOUT: number;
48
+ HTTP_VERSION_NOT_SUPPORTED: number;
49
+ VARIANT_ALSO_NEGOTIATES: number;
50
+ INSUFFICIENT_STORAGE: number;
51
+ LOOP_DETECTED: number;
52
+ NOT_EXTENDED: number;
53
+ NETWORK_AUTHENTICATION_REQUIRED: number;
54
+ };
55
+ type Status = 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511;
56
+ declare class APIError extends Error {
57
+ status: keyof typeof _statusCode | Status;
58
+ body: ({
59
+ message?: string;
60
+ code?: string;
61
+ } & Record<string, any>) | undefined;
62
+ headers: HeadersInit;
63
+ statusCode: number;
64
+ constructor(status?: keyof typeof _statusCode | Status, body?: ({
65
+ message?: string;
66
+ code?: string;
67
+ } & Record<string, any>) | undefined, headers?: HeadersInit, statusCode?: number);
68
+ }
69
+
70
+ /**
71
+ * Improve this type if possible
72
+ */
73
+ type Input<T> = Prettify<{
74
+ [K in keyof T as T[K] extends never ? never : undefined extends T[K] ? never : K]: T[K];
75
+ } & {
76
+ [K in keyof T as undefined extends T[K] ? K : never]?: T[K];
77
+ }>;
78
+ type RequiredKeysOf<BaseType extends object> = Exclude<{
79
+ [Key in keyof BaseType]: BaseType extends Record<Key, BaseType[Key]> ? Key : never;
80
+ }[keyof BaseType], undefined>;
81
+ type HasRequiredKeys<BaseType extends object> = RequiredKeysOf<BaseType> extends never ? false : true;
82
+ type Prettify<T> = {
83
+ [K in keyof T]: T[K];
84
+ } & {};
85
+ type IsEmptyObject<T> = keyof T extends never ? true : false;
86
+ type UnionToIntersection<Union> = (Union extends unknown ? (distributedUnion: Union) => void : never) extends (mergedIntersection: infer Intersection) => void ? Intersection & Union : never;
87
+ type InferParamPath<Path> = Path extends `${infer _Start}:${infer Param}/${infer Rest}` ? {
88
+ [K in Param | keyof InferParamPath<Rest>]: string;
89
+ } : Path extends `${infer _Start}:${infer Param}` ? {
90
+ [K in Param]: string;
91
+ } : Path extends `${infer _Start}/${infer Rest}` ? InferParamPath<Rest> : {};
92
+ type InferParamWildCard<Path> = Path extends `${infer _Start}/*:${infer Param}/${infer Rest}` | `${infer _Start}/**:${infer Param}/${infer Rest}` ? {
93
+ [K in Param | keyof InferParamPath<Rest>]: string;
94
+ } : Path extends `${infer _Start}/*` ? {
95
+ [K in "_"]: string;
96
+ } : Path extends `${infer _Start}/${infer Rest}` ? InferParamPath<Rest> : {};
97
+
98
+ interface MiddlewareOptions extends Omit<EndpointOptions, "method"> {
99
+ }
100
+ type MiddlewareResponse = null | void | undefined | Record<string, any>;
101
+ type MiddlewareContext<Options extends MiddlewareOptions, Context = {}> = EndpointContext<string, Options & {
102
+ method: "*";
103
+ }> & {
104
+ /**
105
+ * Method
106
+ *
107
+ * The request method
108
+ */
109
+ method: string;
110
+ /**
111
+ * Path
112
+ *
113
+ * The path of the endpoint
114
+ */
115
+ path: string;
116
+ /**
117
+ * Body
118
+ *
119
+ * The body object will be the parsed JSON from the request and validated
120
+ * against the body schema if it exists
121
+ */
122
+ body: InferMiddlewareBody<Options>;
123
+ /**
124
+ * Query
125
+ *
126
+ * The query object will be the parsed query string from the request
127
+ * and validated against the query schema if it exists
128
+ */
129
+ query: InferMiddlewareQuery<Options>;
130
+ /**
131
+ * Params
132
+ *
133
+ * If the path is `/user/:id` and the request is `/user/1` then the
134
+ * params will
135
+ * be `{ id: "1" }` and if the path includes a wildcard like `/user/*`
136
+ * then the
137
+ * params will be `{ _: "1" }` where `_` is the wildcard key. If the
138
+ * wildcard
139
+ * is named like `/user/**:name` then the params will be `{ name: string }`
140
+ */
141
+ params: string;
142
+ /**
143
+ * Request object
144
+ *
145
+ * If `requireRequest` is set to true in the endpoint options this will be
146
+ * required
147
+ */
148
+ request: InferRequest<Options>;
149
+ /**
150
+ * Headers
151
+ *
152
+ * If `requireHeaders` is set to true in the endpoint options this will be
153
+ * required
154
+ */
155
+ headers: InferHeaders<Options>;
156
+ /**
157
+ * Set header
158
+ *
159
+ * If it's called outside of a request it will just be ignored.
160
+ */
161
+ setHeader: (key: string, value: string) => void;
162
+ /**
163
+ * Get header
164
+ *
165
+ * If it's called outside of a request it will just return null
166
+ *
167
+ * @param key - The key of the header
168
+ * @returns
169
+ */
170
+ getHeader: (key: string) => string | null;
171
+ /**
172
+ * JSON
173
+ *
174
+ * a helper function to create a JSON response with
175
+ * the correct headers
176
+ * and status code. If `asResponse` is set to true in
177
+ * the context then
178
+ * it will return a Response object instead of the
179
+ * JSON object.
180
+ *
181
+ * @param json - The JSON object to return
182
+ * @param routerResponse - The response object to
183
+ * return if `asResponse` is
184
+ * true in the context this will take precedence
185
+ */
186
+ json: <R extends Record<string, any> | null>(json: R, routerResponse?: {
187
+ status?: number;
188
+ headers?: Record<string, string>;
189
+ response?: Response;
190
+ } | Response) => Promise<R>;
191
+ /**
192
+ * Middleware context
193
+ */
194
+ context: Prettify<Context>;
195
+ };
196
+ declare function createMiddleware<Options extends MiddlewareOptions, R>(options: Options, handler: (context: MiddlewareContext<Options>) => Promise<R>): <InputCtx extends MiddlewareInputContext<Options>>(inputContext: InputCtx) => Promise<R>;
197
+ declare function createMiddleware<Options extends MiddlewareOptions, R>(handler: (context: MiddlewareContext<Options>) => Promise<R>): <InputCtx extends MiddlewareInputContext<Options>>(inputContext: InputCtx) => Promise<R>;
198
+ declare namespace createMiddleware {
199
+ var create: <E extends {
200
+ use?: Middleware[];
201
+ }>(opts?: E) => {
202
+ <Options extends MiddlewareOptions, R>(options: Options, handler: (ctx: MiddlewareContext<Options, InferUse<E["use"]>>) => Promise<R>): (inputContext: MiddlewareInputContext<Options>) => Promise<R>;
203
+ <Options extends MiddlewareOptions, R_1>(handler: (ctx: MiddlewareContext<Options, InferUse<E["use"]>>) => Promise<R_1>): (inputContext: MiddlewareInputContext<Options>) => Promise<R_1>;
204
+ };
205
+ }
206
+ type MiddlewareInputContext<Options extends MiddlewareOptions> = Input<{
207
+ /**
208
+ * Payload
209
+ */
210
+ body: InferBody<Options>;
211
+ /**
212
+ * Query Params
213
+ */
214
+ query: InferQuery<Options>;
215
+ /**
216
+ * Request Object
217
+ */
218
+ request: InferRequest<Options>;
219
+ /**
220
+ * Headers
221
+ */
222
+ headers: InferHeaders<Options>;
223
+ /**
224
+ * Return a `Response` object
225
+ */
226
+ asResponse?: boolean;
227
+ /**
228
+ * include headers on the return
229
+ */
230
+ returnHeaders?: boolean;
231
+ /**
232
+ * Middlewares to use
233
+ */
234
+ use?: Middleware[];
235
+ }>;
236
+ type Middleware<Options extends MiddlewareOptions = MiddlewareOptions, Handler extends (inputCtx: any) => Promise<any> = any> = Handler & {
237
+ options: Options;
238
+ };
239
+
240
+ type CookiePrefixOptions = "host" | "secure";
241
+ type CookieOptions = {
242
+ /**
243
+ * Domain of the cookie
244
+ *
245
+ * The Domain attribute specifies which server can receive a cookie. If specified, cookies are
246
+ * available on the specified server and its subdomains. If the it is not
247
+ * specified, the cookies are available on the server that sets it but not on
248
+ * its subdomains.
249
+ *
250
+ * @example
251
+ * `domain: "example.com"`
252
+ */
253
+ domain?: string;
254
+ /**
255
+ * A lifetime of a cookie. Permanent cookies are deleted after the date specified in the
256
+ * Expires attribute:
257
+ *
258
+ * Expires has been available for longer than Max-Age, however Max-Age is less error-prone, and
259
+ * takes precedence when both are set. The rationale behind this is that when you set an
260
+ * Expires date and time, they're relative to the client the cookie is being set on. If the
261
+ * server is set to a different time, this could cause errors
262
+ */
263
+ expires?: Date;
264
+ /**
265
+ * Forbids JavaScript from accessing the cookie, for example, through the Document.cookie
266
+ * property. Note that a cookie that has been created with HttpOnly will still be sent with
267
+ * JavaScript-initiated requests, for example, when calling XMLHttpRequest.send() or fetch().
268
+ * This mitigates attacks against cross-site scripting
269
+ */
270
+ httpOnly?: boolean;
271
+ /**
272
+ * Indicates the number of seconds until the cookie expires. A zero or negative number will
273
+ * expire the cookie immediately. If both Expires and Max-Age are set, Max-Age has precedence.
274
+ *
275
+ * @example 604800 - 7 days
276
+ */
277
+ maxAge?: number;
278
+ /**
279
+ * Indicates the path that must exist in the requested URL for the browser to send the Cookie
280
+ * header.
281
+ *
282
+ * @example
283
+ * "/docs"
284
+ * // -> the request paths /docs, /docs/, /docs/Web/, and /docs/Web/HTTP will all match. the request paths /, /fr/docs will not match.
285
+ */
286
+ path?: string;
287
+ /**
288
+ * Indicates that the cookie is sent to the server only when a request is made with the https:
289
+ * scheme (except on localhost), and therefore, is more resistant to man-in-the-middle attacks.
290
+ */
291
+ secure?: boolean;
292
+ /**
293
+ * Controls whether or not a cookie is sent with cross-site requests, providing some protection
294
+ * against cross-site request forgery attacks (CSRF).
295
+ *
296
+ * Strict - Means that the browser sends the cookie only for same-site requests, that is,
297
+ * requests originating from the same site that set the cookie. If a request originates from a
298
+ * different domain or scheme (even with the same domain), no cookies with the SameSite=Strict
299
+ * attribute are sent.
300
+ *
301
+ * Lax - Means that the cookie is not sent on cross-site requests, such as on requests to load
302
+ * images or frames, but is sent when a user is navigating to the origin site from an external
303
+ * site (for example, when following a link). This is the default behavior if the SameSite
304
+ * attribute is not specified.
305
+ *
306
+ * None - Means that the browser sends the cookie with both cross-site and same-site requests.
307
+ * The Secure attribute must also be set when setting this value.
308
+ */
309
+ sameSite?: "Strict" | "Lax" | "None" | "strict" | "lax" | "none";
310
+ /**
311
+ * Indicates that the cookie should be stored using partitioned storage. Note that if this is
312
+ * set, the Secure directive must also be set.
313
+ *
314
+ * @see https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies
315
+ */
316
+ partitioned?: boolean;
317
+ /**
318
+ * Cooke Prefix
319
+ *
320
+ * - secure: `__Secure-` -> `__Secure-cookie-name`
321
+ * - host: `__Host-` -> `__Host-cookie-name`
322
+ *
323
+ * `secure` must be set to true to use prefixes
324
+ */
325
+ prefix?: CookiePrefixOptions;
326
+ };
327
+ declare const getCookieKey: (key: string, prefix?: CookiePrefixOptions) => string | undefined;
328
+ declare function parseCookies(cookieHeader: string): Map<string, string>;
329
+ declare const serializeCookie: (key: string, value: string, opt?: CookieOptions) => string;
330
+ declare const serializeSignedCookie: (key: string, value: string, secret: string, opt?: CookieOptions) => Promise<string>;
331
+
332
+ type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
333
+ type Method = HTTPMethod | "*";
334
+ type InferBodyInput<Options extends EndpointOptions | MiddlewareOptions> = Options["metadata"] extends {
335
+ $Infer: {
336
+ body: infer Body;
337
+ };
338
+ } ? Body : Options["body"] extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Options["body"]> : undefined;
339
+ type InferBody<Options extends EndpointOptions | MiddlewareOptions> = Options["metadata"] extends {
340
+ $Infer: {
341
+ body: infer Body;
342
+ };
343
+ } ? Body : Options["body"] extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<Options["body"]> : any;
344
+ type InferQueryInput<Options extends EndpointOptions | MiddlewareOptions> = Options["metadata"] extends {
345
+ $Infer: {
346
+ query: infer Query;
347
+ };
348
+ } ? Query : Options["query"] extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Options["query"]> : Record<string, any> | undefined;
349
+ type InferQuery<Options extends EndpointOptions | MiddlewareOptions> = Options["metadata"] extends {
350
+ $Infer: {
351
+ query: infer Query;
352
+ };
353
+ } ? Query : Options["query"] extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<Options["query"]> : Record<string, any> | undefined;
354
+ type InferMethod<Options extends EndpointOptions> = Options["method"] extends Array<Method> ? Options["method"][number] : Options["method"] extends "*" ? HTTPMethod : Options["method"];
355
+ type InferInputMethod<Options extends EndpointOptions> = Options["method"] extends Array<Method> ? Options["method"][number] : Options["method"] extends "*" ? HTTPMethod : Options["method"] | undefined;
356
+ type InferParam<Path extends string> = IsEmptyObject<InferParamPath<Path> & InferParamWildCard<Path>> extends true ? Record<string, any> | undefined : Prettify<InferParamPath<Path> & InferParamWildCard<Path>>;
357
+ type InferRequest<Option extends EndpointOptions | MiddlewareOptions> = Option["requireRequest"] extends true ? Request : Request | undefined;
358
+ type InferHeaders<Option extends EndpointOptions | MiddlewareOptions> = Option["requireHeaders"] extends true ? Headers : Headers | undefined;
359
+ type InferHeadersInput<Option extends EndpointOptions | MiddlewareOptions> = Option["requireHeaders"] extends true ? HeadersInit : HeadersInit | undefined;
360
+ type InferUse<Opts extends EndpointOptions["use"]> = Opts extends Middleware[] ? UnionToIntersection<Awaited<ReturnType<Opts[number]>>> : {};
361
+ type InferMiddlewareBody<Options extends MiddlewareOptions> = Options["body"] extends StandardSchemaV1<infer T> ? T : any;
362
+ type InferMiddlewareQuery<Options extends MiddlewareOptions> = Options["query"] extends StandardSchemaV1<infer T> ? T : Record<string, any> | undefined;
363
+ type InputContext<Path extends string, Options extends EndpointOptions> = Input<{
364
+ /**
365
+ * Payload
366
+ */
367
+ body: InferBodyInput<Options>;
368
+ /**
369
+ * Request Method
370
+ */
371
+ method: InferInputMethod<Options>;
372
+ /**
373
+ * Query Params
374
+ */
375
+ query: InferQueryInput<Options>;
376
+ /**
377
+ * Dynamic Params
378
+ */
379
+ params: InferParam<Path>;
380
+ /**
381
+ * Request Object
382
+ */
383
+ request: InferRequest<Options>;
384
+ /**
385
+ * Headers
386
+ */
387
+ headers: InferHeadersInput<Options>;
388
+ /**
389
+ * Return a `Response` object
390
+ */
391
+ asResponse?: boolean;
392
+ /**
393
+ * include headers on the return
394
+ */
395
+ returnHeaders?: boolean;
396
+ /**
397
+ * Middlewares to use
398
+ */
399
+ use?: Middleware[];
400
+ /**
401
+ * Customize the path
402
+ */
403
+ path?: string;
404
+ }>;
405
+ declare const createInternalContext: (context: InputContext<any, any>, { options, path, }: {
406
+ options: EndpointOptions;
407
+ path: string;
408
+ }) => Promise<{
409
+ body: any;
410
+ query: any;
411
+ path: string;
412
+ context: {};
413
+ returned: any;
414
+ headers: HeadersInit | undefined;
415
+ request: Request | undefined;
416
+ params: Record<string, any> | undefined;
417
+ method: any;
418
+ setHeader: (key: string, value: string) => void;
419
+ getHeader: (key: string) => string | null;
420
+ getCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;
421
+ getSignedCookie: (key: string, secret: string, prefix?: CookiePrefixOptions) => Promise<string | false | null>;
422
+ setCookie: (key: string, value: string, options?: CookieOptions) => string;
423
+ setSignedCookie: (key: string, value: string, secret: string, options?: CookieOptions) => Promise<string>;
424
+ redirect: (url: string) => APIError;
425
+ error: (status: keyof typeof _statusCode | Status, body?: {
426
+ message?: string;
427
+ code?: string;
428
+ } | undefined, headers?: HeadersInit) => APIError;
429
+ json: (json: Record<string, any>, routerResponse?: {
430
+ status?: number;
431
+ headers?: Record<string, string>;
432
+ response?: Response;
433
+ body?: Record<string, string>;
434
+ } | Response) => Record<string, any>;
435
+ responseHeaders: Headers;
436
+ asResponse?: boolean | undefined;
437
+ returnHeaders?: boolean | undefined;
438
+ use?: Middleware[] | undefined;
439
+ }>;
440
+
441
+ type OpenAPISchemaType = "string" | "number" | "integer" | "boolean" | "array" | "object";
442
+ interface OpenAPIParameter {
443
+ in: "query" | "path" | "header" | "cookie";
444
+ name?: string;
445
+ description?: string;
446
+ required?: boolean;
447
+ schema?: {
448
+ type: OpenAPISchemaType;
449
+ format?: string;
450
+ items?: {
451
+ type: OpenAPISchemaType;
452
+ };
453
+ enum?: string[];
454
+ minLength?: number;
455
+ description?: string;
456
+ default?: string;
457
+ example?: string;
458
+ };
459
+ }
460
+ interface Path {
461
+ get?: {
462
+ tags?: string[];
463
+ operationId?: string;
464
+ description?: string;
465
+ security?: [{
466
+ bearerAuth: string[];
467
+ }];
468
+ parameters?: OpenAPIParameter[];
469
+ responses?: {
470
+ [key in string]: {
471
+ description?: string;
472
+ content: {
473
+ "application/json": {
474
+ schema: {
475
+ type?: OpenAPISchemaType;
476
+ properties?: Record<string, any>;
477
+ required?: string[];
478
+ $ref?: string;
479
+ };
480
+ };
481
+ };
482
+ };
483
+ };
484
+ };
485
+ post?: {
486
+ tags?: string[];
487
+ operationId?: string;
488
+ description?: string;
489
+ security?: [{
490
+ bearerAuth: string[];
491
+ }];
492
+ parameters?: OpenAPIParameter[];
493
+ requestBody?: {
494
+ content: {
495
+ "application/json": {
496
+ schema: {
497
+ type?: OpenAPISchemaType;
498
+ properties?: Record<string, any>;
499
+ required?: string[];
500
+ $ref?: string;
501
+ };
502
+ };
503
+ };
504
+ };
505
+ responses?: {
506
+ [key in string]: {
507
+ description?: string;
508
+ content: {
509
+ "application/json": {
510
+ schema: {
511
+ type?: OpenAPISchemaType;
512
+ properties?: Record<string, any>;
513
+ required?: string[];
514
+ $ref?: string;
515
+ };
516
+ };
517
+ };
518
+ };
519
+ };
520
+ };
521
+ }
522
+ declare function generator(endpoints: Record<string, Endpoint>, config?: {
523
+ url: string;
524
+ }): Promise<{
525
+ openapi: string;
526
+ info: {
527
+ title: string;
528
+ description: string;
529
+ version: string;
530
+ };
531
+ components: {
532
+ schemas: {};
533
+ };
534
+ security: {
535
+ apiKeyCookie: never[];
536
+ }[];
537
+ servers: {
538
+ url: string | undefined;
539
+ }[];
540
+ tags: {
541
+ name: string;
542
+ description: string;
543
+ }[];
544
+ paths: Record<string, Path>;
545
+ }>;
546
+ declare const getHTML: (apiReference: Record<string, any>, config?: {
547
+ logo?: string;
548
+ theme?: string;
549
+ title?: string;
550
+ description?: string;
551
+ }) => string;
552
+
553
+ interface EndpointOptions {
554
+ /**
555
+ * Request Method
556
+ */
557
+ method: Method | Method[];
558
+ /**
559
+ * Body Schema
560
+ */
561
+ body?: StandardSchemaV1;
562
+ /**
563
+ * Query Schema
564
+ */
565
+ query?: StandardSchemaV1;
566
+ /**
567
+ * If true headers will be required to be passed in the context
568
+ */
569
+ requireHeaders?: boolean;
570
+ /**
571
+ * If true request object will be required
572
+ */
573
+ requireRequest?: boolean;
574
+ /**
575
+ * Clone the request object from the router
576
+ */
577
+ cloneRequest?: boolean;
578
+ /**
579
+ * Endpoint metadata
580
+ */
581
+ metadata?: {
582
+ /**
583
+ * Open API definition
584
+ */
585
+ openAPI?: {
586
+ summary?: string;
587
+ description?: string;
588
+ tags?: string[];
589
+ operationId?: string;
590
+ parameters?: OpenAPIParameter[];
591
+ requestBody?: {
592
+ content: {
593
+ "application/json": {
594
+ schema: {
595
+ type?: OpenAPISchemaType;
596
+ properties?: Record<string, any>;
597
+ required?: string[];
598
+ $ref?: string;
599
+ };
600
+ };
601
+ };
602
+ };
603
+ responses?: {
604
+ [status: string]: {
605
+ description: string;
606
+ content?: {
607
+ "application/json"?: {
608
+ schema: {
609
+ type?: OpenAPISchemaType;
610
+ properties?: Record<string, any>;
611
+ required?: string[];
612
+ $ref?: string;
613
+ };
614
+ };
615
+ "text/plain"?: {
616
+ schema?: {
617
+ type?: OpenAPISchemaType;
618
+ properties?: Record<string, any>;
619
+ required?: string[];
620
+ $ref?: string;
621
+ };
622
+ };
623
+ "text/html"?: {
624
+ schema?: {
625
+ type?: OpenAPISchemaType;
626
+ properties?: Record<string, any>;
627
+ required?: string[];
628
+ $ref?: string;
629
+ };
630
+ };
631
+ };
632
+ };
633
+ };
634
+ };
635
+ /**
636
+ * Infer body and query type from ts interface
637
+ *
638
+ * useful for generic and dynamic types
639
+ *
640
+ * @example
641
+ * ```ts
642
+ * const endpoint = createEndpoint("/path", {
643
+ * method: "POST",
644
+ * body: z.record(z.string()),
645
+ * $Infer: {
646
+ * body: {} as {
647
+ * type: InferTypeFromOptions<Option> // custom type inference
648
+ * }
649
+ * }
650
+ * }, async(ctx)=>{
651
+ * const body = ctx.body
652
+ * })
653
+ * ```
654
+ */
655
+ $Infer?: {
656
+ /**
657
+ * Body
658
+ */
659
+ body?: any;
660
+ /**
661
+ * Query
662
+ */
663
+ query?: Record<string, any>;
664
+ };
665
+ /**
666
+ * If enabled, endpoint won't be exposed over a router
667
+ */
668
+ SERVER_ONLY?: boolean;
669
+ /**
670
+ * Extra metadata
671
+ */
672
+ [key: string]: any;
673
+ };
674
+ /**
675
+ * List of middlewares to use
676
+ */
677
+ use?: Middleware[];
678
+ }
679
+ type EndpointContext<Path extends string, Options extends EndpointOptions, Context = {}> = {
680
+ /**
681
+ * Method
682
+ *
683
+ * The request method
684
+ */
685
+ method: InferMethod<Options>;
686
+ /**
687
+ * Path
688
+ *
689
+ * The path of the endpoint
690
+ */
691
+ path: Path;
692
+ /**
693
+ * Body
694
+ *
695
+ * The body object will be the parsed JSON from the request and validated
696
+ * against the body schema if it exists.
697
+ */
698
+ body: InferBody<Options>;
699
+ /**
700
+ * Query
701
+ *
702
+ * The query object will be the parsed query string from the request
703
+ * and validated against the query schema if it exists
704
+ */
705
+ query: InferQuery<Options>;
706
+ /**
707
+ * Params
708
+ *
709
+ * If the path is `/user/:id` and the request is `/user/1` then the params will
710
+ * be `{ id: "1" }` and if the path includes a wildcard like `/user/*` then the
711
+ * params will be `{ _: "1" }` where `_` is the wildcard key. If the wildcard
712
+ * is named like `/user/**:name` then the params will be `{ name: string }`
713
+ */
714
+ params: InferParam<Path>;
715
+ /**
716
+ * Request object
717
+ *
718
+ * If `requireRequest` is set to true in the endpoint options this will be
719
+ * required
720
+ */
721
+ request: InferRequest<Options>;
722
+ /**
723
+ * Headers
724
+ *
725
+ * If `requireHeaders` is set to true in the endpoint options this will be
726
+ * required
727
+ */
728
+ headers: InferHeaders<Options>;
729
+ /**
730
+ * Set header
731
+ *
732
+ * If it's called outside of a request it will just be ignored.
733
+ */
734
+ setHeader: (key: string, value: string) => void;
735
+ /**
736
+ * Get header
737
+ *
738
+ * If it's called outside of a request it will just return null
739
+ *
740
+ * @param key - The key of the header
741
+ * @returns
742
+ */
743
+ getHeader: (key: string) => string | null;
744
+ /**
745
+ * Get a cookie value from the request
746
+ *
747
+ * @param key - The key of the cookie
748
+ * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`
749
+ * @returns - The value of the cookie
750
+ */
751
+ getCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;
752
+ /**
753
+ * Get a signed cookie value from the request
754
+ *
755
+ * @param key - The key of the cookie
756
+ * @param secret - The secret of the signed cookie
757
+ * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`
758
+ * @returns
759
+ */
760
+ getSignedCookie: (key: string, secret: string, prefix?: CookiePrefixOptions) => Promise<string | null>;
761
+ /**
762
+ * Set a cookie value in the response
763
+ *
764
+ * @param key - The key of the cookie
765
+ * @param value - The value to set
766
+ * @param options - The options of the cookie
767
+ * @returns - The cookie string
768
+ */
769
+ setCookie: (key: string, value: string, options?: CookieOptions) => string;
770
+ /**
771
+ * Set signed cookie
772
+ *
773
+ * @param key - The key of the cookie
774
+ * @param value - The value to set
775
+ * @param secret - The secret to sign the cookie with
776
+ * @param options - The options of the cookie
777
+ * @returns - The cookie string
778
+ */
779
+ setSignedCookie: (key: string, value: string, secret: string, options?: CookieOptions) => Promise<string>;
780
+ /**
781
+ * JSON
782
+ *
783
+ * a helper function to create a JSON response with
784
+ * the correct headers
785
+ * and status code. If `asResponse` is set to true in
786
+ * the context then
787
+ * it will return a Response object instead of the
788
+ * JSON object.
789
+ *
790
+ * @param json - The JSON object to return
791
+ * @param routerResponse - The response object to
792
+ * return if `asResponse` is
793
+ * true in the context this will take precedence
794
+ */
795
+ json: <R extends Record<string, any> | null>(json: R, routerResponse?: {
796
+ status?: number;
797
+ headers?: Record<string, string>;
798
+ response?: Response;
799
+ body?: Record<string, string>;
800
+ } | Response) => Promise<R>;
801
+ /**
802
+ * Middleware context
803
+ */
804
+ context: Prettify<Context & InferUse<Options["use"]>>;
805
+ /**
806
+ * Redirect to a new URL
807
+ */
808
+ redirect: (url: string) => APIError;
809
+ /**
810
+ * Return error
811
+ */
812
+ error: (status: keyof typeof _statusCode | Status, body?: {
813
+ message?: string;
814
+ code?: string;
815
+ } & Record<string, any>, headers?: HeadersInit) => APIError;
816
+ };
817
+ declare const createEndpoint: {
818
+ <Path extends string, Options extends EndpointOptions, R>(path: Path, options: Options, handler: (context: EndpointContext<Path, Options>) => Promise<R>): {
819
+ <Context extends InputContext<Path, Options>>(...inputCtx: HasRequiredKeys<Context> extends true ? [Context] : [Context?]): Promise<Context["asResponse"] extends true ? Response : Context["returnHeaders"] extends true ? {
820
+ headers: Headers;
821
+ response: R;
822
+ } : R>;
823
+ options: Options;
824
+ path: Path;
825
+ };
826
+ create<E extends {
827
+ use?: Middleware[];
828
+ }>(opts?: E): <Path extends string, Opts extends EndpointOptions, R>(path: Path, options: Opts, handler: (ctx: EndpointContext<Path, Opts, InferUse<E["use"]>>) => Promise<R>) => {
829
+ <Context extends ({
830
+ body: InferBodyInput<Opts & {
831
+ use: any[];
832
+ }>;
833
+ method: InferInputMethod<Opts & {
834
+ use: any[];
835
+ }>;
836
+ query: InferQueryInput<Opts & {
837
+ use: any[];
838
+ }>;
839
+ params: InferParam<Path>;
840
+ request: InferRequest<Opts & {
841
+ use: any[];
842
+ }>;
843
+ headers: InferHeadersInput<Opts & {
844
+ use: any[];
845
+ }>;
846
+ asResponse?: boolean;
847
+ returnHeaders?: boolean;
848
+ use?: Middleware[];
849
+ path?: string;
850
+ } extends infer T_3 ? { [K_1 in keyof T_3 as {
851
+ body: InferBodyInput<Opts & {
852
+ use: any[];
853
+ }>;
854
+ method: InferInputMethod<Opts & {
855
+ use: any[];
856
+ }>;
857
+ query: InferQueryInput<Opts & {
858
+ use: any[];
859
+ }>;
860
+ params: InferParam<Path>;
861
+ request: InferRequest<Opts & {
862
+ use: any[];
863
+ }>;
864
+ headers: InferHeadersInput<Opts & {
865
+ use: any[];
866
+ }>;
867
+ asResponse?: boolean;
868
+ returnHeaders?: boolean;
869
+ use?: Middleware[];
870
+ path?: string;
871
+ }[K_1] extends never ? never : undefined extends {
872
+ body: InferBodyInput<Opts & {
873
+ use: any[];
874
+ }>;
875
+ method: InferInputMethod<Opts & {
876
+ use: any[];
877
+ }>;
878
+ query: InferQueryInput<Opts & {
879
+ use: any[];
880
+ }>;
881
+ params: InferParam<Path>;
882
+ request: InferRequest<Opts & {
883
+ use: any[];
884
+ }>;
885
+ headers: InferHeadersInput<Opts & {
886
+ use: any[];
887
+ }>;
888
+ asResponse?: boolean;
889
+ returnHeaders?: boolean;
890
+ use?: Middleware[];
891
+ path?: string;
892
+ }[K_1] ? never : K_1]: {
893
+ body: InferBodyInput<Opts & {
894
+ use: any[];
895
+ }>;
896
+ method: InferInputMethod<Opts & {
897
+ use: any[];
898
+ }>;
899
+ query: InferQueryInput<Opts & {
900
+ use: any[];
901
+ }>;
902
+ params: InferParam<Path>;
903
+ request: InferRequest<Opts & {
904
+ use: any[];
905
+ }>;
906
+ headers: InferHeadersInput<Opts & {
907
+ use: any[];
908
+ }>;
909
+ asResponse?: boolean;
910
+ returnHeaders?: boolean;
911
+ use?: Middleware[];
912
+ path?: string;
913
+ }[K_1]; } : never) & ({
914
+ body: InferBodyInput<Opts & {
915
+ use: any[];
916
+ }>;
917
+ method: InferInputMethod<Opts & {
918
+ use: any[];
919
+ }>;
920
+ query: InferQueryInput<Opts & {
921
+ use: any[];
922
+ }>;
923
+ params: InferParam<Path>;
924
+ request: InferRequest<Opts & {
925
+ use: any[];
926
+ }>;
927
+ headers: InferHeadersInput<Opts & {
928
+ use: any[];
929
+ }>;
930
+ asResponse?: boolean;
931
+ returnHeaders?: boolean;
932
+ use?: Middleware[];
933
+ path?: string;
934
+ } extends infer T_4 ? { [K_2 in keyof T_4 as undefined extends {
935
+ body: InferBodyInput<Opts & {
936
+ use: any[];
937
+ }>;
938
+ method: InferInputMethod<Opts & {
939
+ use: any[];
940
+ }>;
941
+ query: InferQueryInput<Opts & {
942
+ use: any[];
943
+ }>;
944
+ params: InferParam<Path>;
945
+ request: InferRequest<Opts & {
946
+ use: any[];
947
+ }>;
948
+ headers: InferHeadersInput<Opts & {
949
+ use: any[];
950
+ }>;
951
+ asResponse?: boolean;
952
+ returnHeaders?: boolean;
953
+ use?: Middleware[];
954
+ path?: string;
955
+ }[K_2] ? K_2 : never]?: {
956
+ body: InferBodyInput<Opts & {
957
+ use: any[];
958
+ }>;
959
+ method: InferInputMethod<Opts & {
960
+ use: any[];
961
+ }>;
962
+ query: InferQueryInput<Opts & {
963
+ use: any[];
964
+ }>;
965
+ params: InferParam<Path>;
966
+ request: InferRequest<Opts & {
967
+ use: any[];
968
+ }>;
969
+ headers: InferHeadersInput<Opts & {
970
+ use: any[];
971
+ }>;
972
+ asResponse?: boolean;
973
+ returnHeaders?: boolean;
974
+ use?: Middleware[];
975
+ path?: string;
976
+ }[K_2] | undefined; } : never) extends infer T ? { [K in keyof T]: (({
977
+ body: InferBodyInput<Opts & {
978
+ use: any[];
979
+ }>;
980
+ method: InferInputMethod<Opts & {
981
+ use: any[];
982
+ }>;
983
+ query: InferQueryInput<Opts & {
984
+ use: any[];
985
+ }>;
986
+ params: InferParam<Path>;
987
+ request: InferRequest<Opts & {
988
+ use: any[];
989
+ }>;
990
+ headers: InferHeadersInput<Opts & {
991
+ use: any[];
992
+ }>;
993
+ asResponse?: boolean;
994
+ returnHeaders?: boolean;
995
+ use?: Middleware[];
996
+ path?: string;
997
+ } extends infer T_1 ? { [K_1 in keyof T_1 as {
998
+ body: InferBodyInput<Opts & {
999
+ use: any[];
1000
+ }>;
1001
+ method: InferInputMethod<Opts & {
1002
+ use: any[];
1003
+ }>;
1004
+ query: InferQueryInput<Opts & {
1005
+ use: any[];
1006
+ }>;
1007
+ params: InferParam<Path>;
1008
+ request: InferRequest<Opts & {
1009
+ use: any[];
1010
+ }>;
1011
+ headers: InferHeadersInput<Opts & {
1012
+ use: any[];
1013
+ }>;
1014
+ asResponse?: boolean;
1015
+ returnHeaders?: boolean;
1016
+ use?: Middleware[];
1017
+ path?: string;
1018
+ }[K_1] extends never ? never : undefined extends {
1019
+ body: InferBodyInput<Opts & {
1020
+ use: any[];
1021
+ }>;
1022
+ method: InferInputMethod<Opts & {
1023
+ use: any[];
1024
+ }>;
1025
+ query: InferQueryInput<Opts & {
1026
+ use: any[];
1027
+ }>;
1028
+ params: InferParam<Path>;
1029
+ request: InferRequest<Opts & {
1030
+ use: any[];
1031
+ }>;
1032
+ headers: InferHeadersInput<Opts & {
1033
+ use: any[];
1034
+ }>;
1035
+ asResponse?: boolean;
1036
+ returnHeaders?: boolean;
1037
+ use?: Middleware[];
1038
+ path?: string;
1039
+ }[K_1] ? never : K_1]: {
1040
+ body: InferBodyInput<Opts & {
1041
+ use: any[];
1042
+ }>;
1043
+ method: InferInputMethod<Opts & {
1044
+ use: any[];
1045
+ }>;
1046
+ query: InferQueryInput<Opts & {
1047
+ use: any[];
1048
+ }>;
1049
+ params: InferParam<Path>;
1050
+ request: InferRequest<Opts & {
1051
+ use: any[];
1052
+ }>;
1053
+ headers: InferHeadersInput<Opts & {
1054
+ use: any[];
1055
+ }>;
1056
+ asResponse?: boolean;
1057
+ returnHeaders?: boolean;
1058
+ use?: Middleware[];
1059
+ path?: string;
1060
+ }[K_1]; } : never) & ({
1061
+ body: InferBodyInput<Opts & {
1062
+ use: any[];
1063
+ }>;
1064
+ method: InferInputMethod<Opts & {
1065
+ use: any[];
1066
+ }>;
1067
+ query: InferQueryInput<Opts & {
1068
+ use: any[];
1069
+ }>;
1070
+ params: InferParam<Path>;
1071
+ request: InferRequest<Opts & {
1072
+ use: any[];
1073
+ }>;
1074
+ headers: InferHeadersInput<Opts & {
1075
+ use: any[];
1076
+ }>;
1077
+ asResponse?: boolean;
1078
+ returnHeaders?: boolean;
1079
+ use?: Middleware[];
1080
+ path?: string;
1081
+ } extends infer T_2 ? { [K_2 in keyof T_2 as undefined extends {
1082
+ body: InferBodyInput<Opts & {
1083
+ use: any[];
1084
+ }>;
1085
+ method: InferInputMethod<Opts & {
1086
+ use: any[];
1087
+ }>;
1088
+ query: InferQueryInput<Opts & {
1089
+ use: any[];
1090
+ }>;
1091
+ params: InferParam<Path>;
1092
+ request: InferRequest<Opts & {
1093
+ use: any[];
1094
+ }>;
1095
+ headers: InferHeadersInput<Opts & {
1096
+ use: any[];
1097
+ }>;
1098
+ asResponse?: boolean;
1099
+ returnHeaders?: boolean;
1100
+ use?: Middleware[];
1101
+ path?: string;
1102
+ }[K_2] ? K_2 : never]?: {
1103
+ body: InferBodyInput<Opts & {
1104
+ use: any[];
1105
+ }>;
1106
+ method: InferInputMethod<Opts & {
1107
+ use: any[];
1108
+ }>;
1109
+ query: InferQueryInput<Opts & {
1110
+ use: any[];
1111
+ }>;
1112
+ params: InferParam<Path>;
1113
+ request: InferRequest<Opts & {
1114
+ use: any[];
1115
+ }>;
1116
+ headers: InferHeadersInput<Opts & {
1117
+ use: any[];
1118
+ }>;
1119
+ asResponse?: boolean;
1120
+ returnHeaders?: boolean;
1121
+ use?: Middleware[];
1122
+ path?: string;
1123
+ }[K_2] | undefined; } : never))[K]; } : never>(...inputCtx: HasRequiredKeys<Context> extends true ? [Context] : [(Context | undefined)?]): Promise<Context["asResponse"] extends true ? Response : Context["returnHeaders"] extends true ? {
1124
+ headers: Headers;
1125
+ response: R;
1126
+ } : R>;
1127
+ options: Opts & {
1128
+ use: any[];
1129
+ };
1130
+ path: Path;
1131
+ };
1132
+ };
1133
+ type Endpoint<Path extends string = string, Options extends EndpointOptions = EndpointOptions, Handler extends (inputCtx: any) => Promise<any> = (inputCtx: any) => Promise<any>> = Handler & {
1134
+ options: Options;
1135
+ path: Path;
1136
+ };
1137
+
1138
+ interface RouterConfig {
1139
+ throwError?: boolean;
1140
+ onError?: (e: unknown) => void | Promise<void> | Response | Promise<Response>;
1141
+ basePath?: string;
1142
+ routerMiddleware?: Array<{
1143
+ path: string;
1144
+ middleware: Middleware;
1145
+ }>;
1146
+ /**
1147
+ * additional Context that needs to passed to endpoints
1148
+ *
1149
+ * this will be available on `ctx.context` on endpoints
1150
+ */
1151
+ routerContext?: Record<string, any>;
1152
+ /**
1153
+ * A callback to run before any response
1154
+ */
1155
+ onResponse?: (res: Response) => any | Promise<any>;
1156
+ /**
1157
+ * A callback to run before any request
1158
+ */
1159
+ onRequest?: (req: Request) => any | Promise<any>;
1160
+ /**
1161
+ * Open API route configuration
1162
+ */
1163
+ openAPI?: {
1164
+ /**
1165
+ * Disable openapi route
1166
+ *
1167
+ * @default false
1168
+ */
1169
+ disabled?: boolean;
1170
+ /**
1171
+ * A path to display open api using scalar
1172
+ *
1173
+ * @default "/api/reference"
1174
+ */
1175
+ path?: string;
1176
+ /**
1177
+ * Scalar Configuration
1178
+ */
1179
+ scalar?: {
1180
+ /**
1181
+ * Title
1182
+ * @default "Open API Reference"
1183
+ */
1184
+ title?: string;
1185
+ /**
1186
+ * Description
1187
+ *
1188
+ * @default "Better Call Open API Reference"
1189
+ */
1190
+ description?: string;
1191
+ /**
1192
+ * Logo URL
1193
+ */
1194
+ logo?: string;
1195
+ /**
1196
+ * Scalar theme
1197
+ * @default "saturn"
1198
+ */
1199
+ theme?: string;
1200
+ };
1201
+ };
1202
+ }
1203
+ declare const createRouter: <E extends Record<string, Endpoint>, Config extends RouterConfig>(endpoints: E, config?: Config) => {
1204
+ handler: (request: Request) => Promise<Response>;
1205
+ endpoints: E;
1206
+ };
1207
+ type Router = ReturnType<typeof createRouter>;
1208
+
1209
+ export { APIError as A, type InferHeaders as B, type CookiePrefixOptions as C, type InferHeadersInput as D, type EndpointOptions as E, type InferUse as F, type InferMiddlewareBody as G, type HTTPMethod as H, type InferBodyInput as I, type InferMiddlewareQuery as J, type InputContext as K, createInternalContext as L, type MiddlewareOptions as M, type HasRequiredKeys as N, type OpenAPISchemaType as O, type Path as P, type RouterConfig as R, type Status as S, type UnionToIntersection as U, _statusCode as _, type EndpointContext as a, type Endpoint as b, createEndpoint as c, type MiddlewareResponse as d, type MiddlewareContext as e, createMiddleware as f, type MiddlewareInputContext as g, type Middleware as h, createRouter as i, type Router as j, type CookieOptions as k, getCookieKey as l, serializeSignedCookie as m, type OpenAPIParameter as n, generator as o, parseCookies as p, getHTML as q, type Method as r, serializeCookie as s, type InferBody as t, type InferQueryInput as u, type InferQuery as v, type InferMethod as w, type InferInputMethod as x, type InferParam as y, type InferRequest as z };