better-call 1.3.3 → 2.0.0-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.
Files changed (59) hide show
  1. package/dist/client.cjs.map +1 -1
  2. package/dist/client.d.cts +13 -17
  3. package/dist/client.d.mts +13 -17
  4. package/dist/client.mjs.map +1 -1
  5. package/dist/context.cjs +10 -9
  6. package/dist/context.cjs.map +1 -1
  7. package/dist/context.d.cts +129 -323
  8. package/dist/context.d.mts +129 -323
  9. package/dist/context.mjs +10 -9
  10. package/dist/context.mjs.map +1 -1
  11. package/dist/cookies.cjs +1 -1
  12. package/dist/cookies.d.cts +1 -12
  13. package/dist/cookies.d.mts +1 -12
  14. package/dist/cookies.mjs +1 -1
  15. package/dist/crypto.cjs.map +1 -1
  16. package/dist/crypto.mjs.map +1 -1
  17. package/dist/endpoint.cjs +21 -7
  18. package/dist/endpoint.cjs.map +1 -1
  19. package/dist/endpoint.d.cts +197 -392
  20. package/dist/endpoint.d.mts +197 -392
  21. package/dist/endpoint.mjs +21 -7
  22. package/dist/endpoint.mjs.map +1 -1
  23. package/dist/error.cjs +1 -1
  24. package/dist/error.cjs.map +1 -1
  25. package/dist/error.mjs +1 -1
  26. package/dist/error.mjs.map +1 -1
  27. package/dist/helper.d.cts +2 -3
  28. package/dist/helper.d.mts +2 -3
  29. package/dist/index.cjs +3 -10
  30. package/dist/index.d.cts +9 -8
  31. package/dist/index.d.mts +9 -8
  32. package/dist/index.mjs +3 -4
  33. package/dist/middleware.cjs +59 -13
  34. package/dist/middleware.cjs.map +1 -1
  35. package/dist/middleware.d.cts +85 -42
  36. package/dist/middleware.d.mts +85 -42
  37. package/dist/middleware.mjs +59 -13
  38. package/dist/middleware.mjs.map +1 -1
  39. package/dist/node.cjs.map +1 -1
  40. package/dist/node.d.cts +1 -1
  41. package/dist/node.d.mts +1 -1
  42. package/dist/node.mjs.map +1 -1
  43. package/dist/openapi.cjs.map +1 -1
  44. package/dist/openapi.d.cts +1 -1
  45. package/dist/openapi.d.mts +1 -1
  46. package/dist/openapi.mjs.map +1 -1
  47. package/dist/router.cjs.map +1 -1
  48. package/dist/router.mjs.map +1 -1
  49. package/dist/to-response.cjs +1 -1
  50. package/dist/to-response.cjs.map +1 -1
  51. package/dist/to-response.mjs +1 -1
  52. package/dist/to-response.mjs.map +1 -1
  53. package/dist/types.d.cts +142 -0
  54. package/dist/types.d.mts +142 -0
  55. package/dist/validator.cjs +1 -1
  56. package/dist/validator.cjs.map +1 -1
  57. package/dist/validator.mjs +1 -1
  58. package/dist/validator.mjs.map +1 -1
  59. package/package.json +3 -3
@@ -1,341 +1,147 @@
1
- import { InferParamPath, InferParamWildCard, IsEmptyObject, Prettify, UnionToIntersection } from "./helper.mjs";
2
- import { StandardSchemaV1 } from "./standard-schema.mjs";
3
- import { Status, statusCodes } from "./error.mjs";
4
1
  import { CookieOptions, CookiePrefixOptions } from "./cookies.mjs";
5
- import { Middleware, MiddlewareOptions } from "./middleware.mjs";
6
- import { EndpointOptions } from "./endpoint.mjs";
2
+ import { APIError, Status, statusCodes } from "./error.mjs";
3
+ import { Prettify } from "./helper.mjs";
4
+ import { InferParam, InferUse, ResolveBody, ResolveMethod, ResolveQuery } from "./types.mjs";
5
+ import { Middleware } from "./middleware.mjs";
7
6
 
8
7
  //#region src/context.d.ts
9
- type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
10
- type Method = HTTPMethod | "*";
11
- type InferBodyInput<Options extends EndpointOptions | MiddlewareOptions, Body = (Options["metadata"] extends {
12
- $Infer: {
13
- body: infer B;
14
- };
15
- } ? B : Options["body"] extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Options["body"]> : undefined)> = undefined extends Body ? {
16
- body?: Body;
17
- } : {
18
- body: Body;
19
- };
20
- type InferBody<Options extends EndpointOptions | MiddlewareOptions> = Options["metadata"] extends {
21
- $Infer: {
22
- body: infer Body;
23
- };
24
- } ? Body : Options["body"] extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<Options["body"]> : any;
25
- type InferQueryInput<Options extends EndpointOptions | MiddlewareOptions, Query = (Options["metadata"] extends {
26
- $Infer: {
27
- query: infer Query;
28
- };
29
- } ? Query : Options["query"] extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Options["query"]> : Record<string, any> | undefined)> = undefined extends Query ? {
30
- query?: Query;
31
- } : {
32
- query: Query;
33
- };
34
- type InferQuery<Options extends EndpointOptions | MiddlewareOptions> = Options["metadata"] extends {
35
- $Infer: {
36
- query: infer Query;
37
- };
38
- } ? Query : Options["query"] extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<Options["query"]> : Record<string, any> | undefined;
39
- type InferMethod<Options extends EndpointOptions> = Options["method"] extends Array<Method> ? Options["method"][number] : Options["method"] extends "*" ? HTTPMethod : Options["method"];
40
- type InferInputMethod<Options extends EndpointOptions, Method = (Options["method"] extends Array<any> ? Options["method"][number] | undefined : Options["method"] extends "*" ? HTTPMethod : Options["method"] | undefined)> = undefined extends Method ? {
41
- method?: Method;
42
- } : {
43
- method: Method;
44
- };
45
- type InferParam<Path extends string> = [Path] extends [never] ? Record<string, any> | undefined : IsEmptyObject<InferParamPath<Path> & InferParamWildCard<Path>> extends true ? Record<string, any> | undefined : Prettify<InferParamPath<Path> & InferParamWildCard<Path>>;
46
- type InferParamInput<Path extends string> = [Path] extends [never] ? {
47
- params?: Record<string, any>;
48
- } : IsEmptyObject<InferParamPath<Path> & InferParamWildCard<Path>> extends true ? {
49
- params?: Record<string, any>;
50
- } : {
51
- params: Prettify<InferParamPath<Path> & InferParamWildCard<Path>>;
52
- };
53
- type InferRequest<Option extends EndpointOptions | MiddlewareOptions> = Option["requireRequest"] extends true ? Request : Request | undefined;
54
- type InferRequestInput<Option extends EndpointOptions | MiddlewareOptions> = Option["requireRequest"] extends true ? {
55
- request: Request;
56
- } : {
57
- request?: Request;
58
- };
59
- type InferHeaders<Option extends EndpointOptions | MiddlewareOptions> = Option["requireHeaders"] extends true ? Headers : Headers | undefined;
60
- type InferHeadersInput<Option extends EndpointOptions | MiddlewareOptions> = Option["requireHeaders"] extends true ? {
61
- headers: HeadersInit;
62
- } : {
63
- headers?: HeadersInit;
64
- };
65
- type InferUse<Opts extends EndpointOptions["use"]> = Opts extends Middleware[] ? UnionToIntersection<Awaited<ReturnType<Opts[number]>>> : {};
66
- type InferMiddlewareBody<Options extends MiddlewareOptions> = Options["body"] extends StandardSchemaV1<infer T> ? T : any;
67
- type InferMiddlewareQuery<Options extends MiddlewareOptions> = Options["query"] extends StandardSchemaV1<infer T> ? T : Record<string, any> | undefined;
68
- type InputContext<Path extends string, Options extends EndpointOptions> = InferBodyInput<Options> & InferInputMethod<Options> & InferQueryInput<Options> & InferParamInput<Path> & InferRequestInput<Options> & InferHeadersInput<Options> & {
69
- asResponse?: boolean;
70
- returnHeaders?: boolean;
71
- returnStatus?: boolean;
72
- use?: Middleware[];
73
- path?: string;
74
- context?: Record<string, any>;
75
- };
76
- declare const createInternalContext: (context: InputContext<any, any>, {
77
- options,
78
- path
79
- }: {
80
- options: EndpointOptions;
81
- path?: string;
82
- }) => Promise<{
83
- body: any;
84
- query: any;
85
- path: string;
86
- context: Record<string, any>;
87
- returned: any;
88
- headers: HeadersInit | undefined;
89
- request: Request | undefined;
90
- params: Record<string, any> | undefined;
91
- method: any;
8
+ type EndpointContext<Path extends string, M, BodySchema extends object | undefined, QuerySchema extends object | undefined, Use extends Middleware[], ReqHeaders extends boolean, ReqRequest extends boolean, Context = {}, Meta = undefined> = {
9
+ /**
10
+ * Method
11
+ *
12
+ * The request method
13
+ */
14
+ method: ResolveMethod<M>;
15
+ /**
16
+ * Path
17
+ *
18
+ * The path of the endpoint
19
+ */
20
+ path: Path;
21
+ /**
22
+ * Body
23
+ *
24
+ * The body object will be the parsed JSON from the request and validated
25
+ * against the body schema if it exists.
26
+ */
27
+ body: ResolveBody<BodySchema, Meta>;
28
+ /**
29
+ * Query
30
+ *
31
+ * The query object will be the parsed query string from the request
32
+ * and validated against the query schema if it exists
33
+ */
34
+ query: ResolveQuery<QuerySchema, Meta>;
35
+ /**
36
+ * Params
37
+ *
38
+ * If the path is `/user/:id` and the request is `/user/1` then the params will
39
+ * be `{ id: "1" }` and if the path includes a wildcard like `/user/*` then the
40
+ * params will be `{ _: "1" }` where `_` is the wildcard key. If the wildcard
41
+ * is named like `/user/**:name` then the params will be `{ name: string }`
42
+ */
43
+ params: InferParam<Path>;
44
+ /**
45
+ * Request object
46
+ *
47
+ * If `requireRequest` is set to true in the endpoint options this will be
48
+ * required
49
+ */
50
+ request: ReqRequest extends true ? Request : Request | undefined;
51
+ /**
52
+ * Headers
53
+ *
54
+ * If `requireHeaders` is set to true in the endpoint options this will be
55
+ * required
56
+ */
57
+ headers: ReqHeaders extends true ? Headers : Headers | undefined;
58
+ /**
59
+ * Set header
60
+ *
61
+ * If it's called outside of a request it will just be ignored.
62
+ */
92
63
  setHeader: (key: string, value: string) => void;
93
- getHeader: (key: string) => string | null;
94
- getCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;
95
- getSignedCookie: (key: string, secret: string, prefix?: CookiePrefixOptions) => Promise<string | false | null>;
96
- setCookie: (key: string, value: string, options?: CookieOptions) => string;
97
- setSignedCookie: (key: string, value: string, secret: string, options?: CookieOptions) => Promise<string>;
98
- redirect: (url: string) => {
99
- status: keyof typeof statusCodes | Status;
100
- body: ({
101
- message?: string;
102
- code?: string;
103
- cause?: unknown;
104
- } & Record<string, any>) | undefined;
105
- headers: HeadersInit;
106
- statusCode: number;
107
- name: string;
108
- message: string;
109
- stack?: string;
110
- cause?: unknown;
111
- } & {
112
- errorStack: string | undefined;
113
- };
114
- error: (status: keyof typeof statusCodes | Status, body?: {
115
- message?: string;
116
- code?: string;
117
- } | undefined, headers?: HeadersInit) => {
118
- status: keyof typeof statusCodes | Status;
119
- body: ({
120
- message?: string;
121
- code?: string;
122
- cause?: unknown;
123
- } & Record<string, any>) | undefined;
124
- headers: HeadersInit;
125
- statusCode: number;
126
- name: string;
127
- message: string;
128
- stack?: string;
129
- cause?: unknown;
130
- } & {
131
- errorStack: string | undefined;
132
- };
64
+ /**
65
+ * Set the response status code
66
+ */
133
67
  setStatus: (status: Status) => void;
134
- json: (json: Record<string, any>, routerResponse?: {
135
- status?: number;
136
- headers?: Record<string, string>;
137
- response?: Response;
138
- body?: Record<string, any>;
139
- } | Response) => Record<string, any>;
140
- responseHeaders: Headers;
141
- responseStatus: Status | undefined;
142
- asResponse?: boolean;
143
- returnHeaders?: boolean;
144
- returnStatus?: boolean;
145
- use?: Middleware[];
146
- } | {
147
- body: any;
148
- query: any;
149
- path: string;
150
- context: Record<string, any>;
151
- returned: any;
152
- headers: HeadersInit | undefined;
153
- request: Request | undefined;
154
- params: Record<string, any> | undefined;
155
- method: any;
156
- setHeader: (key: string, value: string) => void;
68
+ /**
69
+ * Get header
70
+ *
71
+ * If it's called outside of a request it will just return null
72
+ *
73
+ * @param key - The key of the header
74
+ */
157
75
  getHeader: (key: string) => string | null;
76
+ /**
77
+ * Get a cookie value from the request
78
+ *
79
+ * @param key - The key of the cookie
80
+ * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`
81
+ * @returns The value of the cookie
82
+ */
158
83
  getCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;
159
- getSignedCookie: (key: string, secret: string, prefix?: CookiePrefixOptions) => Promise<string | false | null>;
84
+ /**
85
+ * Get a signed cookie value from the request
86
+ *
87
+ * @param key - The key of the cookie
88
+ * @param secret - The secret of the signed cookie
89
+ * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`
90
+ * @returns The value of the cookie or null if the cookie is not found or false if the signature is invalid
91
+ */
92
+ getSignedCookie: (key: string, secret: string, prefix?: CookiePrefixOptions) => Promise<string | null | false>;
93
+ /**
94
+ * Set a cookie value in the response
95
+ *
96
+ * @param key - The key of the cookie
97
+ * @param value - The value to set
98
+ * @param options - The options of the cookie
99
+ * @returns The cookie string
100
+ */
160
101
  setCookie: (key: string, value: string, options?: CookieOptions) => string;
102
+ /**
103
+ * Set signed cookie
104
+ *
105
+ * @param key - The key of the cookie
106
+ * @param value - The value to set
107
+ * @param secret - The secret to sign the cookie with
108
+ * @param options - The options of the cookie
109
+ * @returns The cookie string
110
+ */
161
111
  setSignedCookie: (key: string, value: string, secret: string, options?: CookieOptions) => Promise<string>;
162
- redirect: (url: string) => {
163
- status: keyof typeof statusCodes | Status;
164
- body: ({
165
- message?: string;
166
- code?: string;
167
- cause?: unknown;
168
- } & Record<string, any>) | undefined;
169
- headers: HeadersInit;
170
- statusCode: number;
171
- name: string;
172
- message: string;
173
- stack?: string;
174
- cause?: unknown;
175
- } & {
176
- errorStack: string | undefined;
177
- };
178
- error: (status: keyof typeof statusCodes | Status, body?: {
179
- message?: string;
180
- code?: string;
181
- } | undefined, headers?: HeadersInit) => {
182
- status: keyof typeof statusCodes | Status;
183
- body: ({
184
- message?: string;
185
- code?: string;
186
- cause?: unknown;
187
- } & Record<string, any>) | undefined;
188
- headers: HeadersInit;
189
- statusCode: number;
190
- name: string;
191
- message: string;
192
- stack?: string;
193
- cause?: unknown;
194
- } & {
195
- errorStack: string | undefined;
196
- };
197
- setStatus: (status: Status) => void;
198
- json: (json: Record<string, any>, routerResponse?: {
112
+ /**
113
+ * JSON
114
+ *
115
+ * A helper function to create a JSON response with the correct headers
116
+ * and status code. If `asResponse` is set to true in the context then
117
+ * it will return a Response object instead of the JSON object.
118
+ *
119
+ * @param json - The JSON object to return
120
+ * @param routerResponse - The response object to return if `asResponse` is
121
+ * true in the context this will take precedence
122
+ */
123
+ json: <R extends Record<string, any> | null>(json: R, routerResponse?: {
199
124
  status?: number;
200
125
  headers?: Record<string, string>;
201
126
  response?: Response;
202
127
  body?: Record<string, any>;
203
- } | Response) => Record<string, any>;
204
- responseHeaders: Headers;
205
- responseStatus: Status | undefined;
206
- asResponse?: boolean;
207
- returnHeaders?: boolean;
208
- returnStatus?: boolean;
209
- use?: Middleware[];
210
- } | {
211
- body: any;
212
- query: any;
213
- path: string;
214
- context: Record<string, any>;
215
- returned: any;
216
- headers: HeadersInit | undefined;
217
- request: Request | undefined;
218
- params: Record<string, any> | undefined;
219
- method: any;
220
- setHeader: (key: string, value: string) => void;
221
- getHeader: (key: string) => string | null;
222
- getCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;
223
- getSignedCookie: (key: string, secret: string, prefix?: CookiePrefixOptions) => Promise<string | false | null>;
224
- setCookie: (key: string, value: string, options?: CookieOptions) => string;
225
- setSignedCookie: (key: string, value: string, secret: string, options?: CookieOptions) => Promise<string>;
226
- redirect: (url: string) => {
227
- status: keyof typeof statusCodes | Status;
228
- body: ({
229
- message?: string;
230
- code?: string;
231
- cause?: unknown;
232
- } & Record<string, any>) | undefined;
233
- headers: HeadersInit;
234
- statusCode: number;
235
- name: string;
236
- message: string;
237
- stack?: string;
238
- cause?: unknown;
239
- } & {
240
- errorStack: string | undefined;
241
- };
128
+ } | Response) => R;
129
+ /**
130
+ * Middleware context
131
+ */
132
+ context: 0 extends 1 & Use ? Prettify<Context> : Prettify<Context & InferUse<Use>>;
133
+ /**
134
+ * Redirect to a new URL
135
+ */
136
+ redirect: (url: string) => APIError;
137
+ /**
138
+ * Return error
139
+ */
242
140
  error: (status: keyof typeof statusCodes | Status, body?: {
243
141
  message?: string;
244
142
  code?: string;
245
- } | undefined, headers?: HeadersInit) => {
246
- status: keyof typeof statusCodes | Status;
247
- body: ({
248
- message?: string;
249
- code?: string;
250
- cause?: unknown;
251
- } & Record<string, any>) | undefined;
252
- headers: HeadersInit;
253
- statusCode: number;
254
- name: string;
255
- message: string;
256
- stack?: string;
257
- cause?: unknown;
258
- } & {
259
- errorStack: string | undefined;
260
- };
261
- setStatus: (status: Status) => void;
262
- json: (json: Record<string, any>, routerResponse?: {
263
- status?: number;
264
- headers?: Record<string, string>;
265
- response?: Response;
266
- body?: Record<string, any>;
267
- } | Response) => Record<string, any>;
268
- responseHeaders: Headers;
269
- responseStatus: Status | undefined;
270
- asResponse?: boolean;
271
- returnHeaders?: boolean;
272
- returnStatus?: boolean;
273
- use?: Middleware[];
274
- } | {
275
- body: any;
276
- query: any;
277
- path: string;
278
- context: Record<string, any>;
279
- returned: any;
280
- headers: HeadersInit | undefined;
281
- request: Request | undefined;
282
- params: Record<string, any> | undefined;
283
- method: any;
284
- setHeader: (key: string, value: string) => void;
285
- getHeader: (key: string) => string | null;
286
- getCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;
287
- getSignedCookie: (key: string, secret: string, prefix?: CookiePrefixOptions) => Promise<string | false | null>;
288
- setCookie: (key: string, value: string, options?: CookieOptions) => string;
289
- setSignedCookie: (key: string, value: string, secret: string, options?: CookieOptions) => Promise<string>;
290
- redirect: (url: string) => {
291
- status: keyof typeof statusCodes | Status;
292
- body: ({
293
- message?: string;
294
- code?: string;
295
- cause?: unknown;
296
- } & Record<string, any>) | undefined;
297
- headers: HeadersInit;
298
- statusCode: number;
299
- name: string;
300
- message: string;
301
- stack?: string;
302
- cause?: unknown;
303
- } & {
304
- errorStack: string | undefined;
305
- };
306
- error: (status: keyof typeof statusCodes | Status, body?: {
307
- message?: string;
308
- code?: string;
309
- } | undefined, headers?: HeadersInit) => {
310
- status: keyof typeof statusCodes | Status;
311
- body: ({
312
- message?: string;
313
- code?: string;
314
- cause?: unknown;
315
- } & Record<string, any>) | undefined;
316
- headers: HeadersInit;
317
- statusCode: number;
318
- name: string;
319
- message: string;
320
- stack?: string;
321
- cause?: unknown;
322
- } & {
323
- errorStack: string | undefined;
324
- };
325
- setStatus: (status: Status) => void;
326
- json: (json: Record<string, any>, routerResponse?: {
327
- status?: number;
328
- headers?: Record<string, string>;
329
- response?: Response;
330
- body?: Record<string, any>;
331
- } | Response) => Record<string, any>;
332
- responseHeaders: Headers;
333
- responseStatus: Status | undefined;
334
- asResponse?: boolean;
335
- returnHeaders?: boolean;
336
- returnStatus?: boolean;
337
- use?: Middleware[];
338
- }>;
143
+ } & Record<string, any>, headers?: HeadersInit) => APIError;
144
+ };
339
145
  //#endregion
340
- export { HTTPMethod, InferBody, InferBodyInput, InferHeaders, InferHeadersInput, InferInputMethod, InferMethod, InferMiddlewareBody, InferMiddlewareQuery, InferParam, InferParamInput, InferQuery, InferQueryInput, InferRequest, InferRequestInput, InferUse, InputContext, Method, createInternalContext };
146
+ export { EndpointContext };
341
147
  //# sourceMappingURL=context.d.mts.map
package/dist/context.mjs CHANGED
@@ -1,13 +1,18 @@
1
+ import { getCryptoKey, verifySignature } from "./crypto.mjs";
1
2
  import { APIError, ValidationError } from "./error.mjs";
2
3
  import { isRequest } from "./utils.mjs";
3
- import { runValidation } from "./validator.mjs";
4
- import { getCryptoKey, verifySignature } from "./crypto.mjs";
5
4
  import { getCookieKey, parseCookies, serializeCookie, serializeSignedCookie } from "./cookies.mjs";
5
+ import { runValidation } from "./validator.mjs";
6
6
 
7
7
  //#region src/context.ts
8
+ /**
9
+ * Creates the internal context for an endpoint or middleware invocation.
10
+ * This is the runtime function that does validation, cookie handling,
11
+ * middleware execution, etc.
12
+ */
8
13
  const createInternalContext = async (context, { options, path }) => {
9
14
  const headers = new Headers();
10
- let responseStatus = void 0;
15
+ let responseStatus;
11
16
  const { data, error } = await runValidation(options, context);
12
17
  if (error) throw new ValidationError(error.message, error.issues);
13
18
  const requestHeaders = "headers" in context ? context.headers instanceof Headers ? context.headers : new Headers(context.headers) : "request" in context && isRequest(context.request) ? context.request.headers : null;
@@ -19,7 +24,6 @@ const createInternalContext = async (context, { options, path }) => {
19
24
  query: data.query,
20
25
  path: context.path || path || "virtual:",
21
26
  context: "context" in context && context.context ? context.context : {},
22
- returned: void 0,
23
27
  headers: context?.headers,
24
28
  request: context?.request,
25
29
  params: "params" in context ? context.params : void 0,
@@ -76,10 +80,10 @@ const createInternalContext = async (context, { options, path }) => {
76
80
  _flag: "json"
77
81
  };
78
82
  },
79
- responseHeaders: headers,
80
83
  get responseStatus() {
81
84
  return responseStatus;
82
- }
85
+ },
86
+ responseHeaders: headers
83
87
  };
84
88
  for (const middleware of options.use || []) {
85
89
  const response = await middleware({
@@ -88,9 +92,6 @@ const createInternalContext = async (context, { options, path }) => {
88
92
  asResponse: false
89
93
  });
90
94
  if (response.response) Object.assign(internalContext.context, response.response);
91
- /**
92
- * Apply headers from the middleware to the endpoint headers
93
- */
94
95
  if (response.headers) response.headers.forEach((value, key) => {
95
96
  internalContext.responseHeaders.set(key, value);
96
97
  });
@@ -1 +1 @@
1
- {"version":3,"file":"context.mjs","names":[],"sources":["../src/context.ts"],"sourcesContent":["import type { EndpointOptions } from \"./endpoint\";\nimport {\n\ttype statusCodes,\n\tAPIError,\n\tValidationError,\n\ttype Status,\n} from \"./error\";\nimport type {\n\tInferParamPath,\n\tInferParamWildCard,\n\tIsEmptyObject,\n\tPrettify,\n\tUnionToIntersection,\n} from \"./helper\";\nimport type {\n\tMiddleware,\n\tMiddlewareContext,\n\tMiddlewareOptions,\n} from \"./middleware\";\nimport { runValidation } from \"./validator\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n\ttype CookieOptions,\n\ttype CookiePrefixOptions,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { isRequest } from \"./utils\";\n\nexport type HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\nexport type Method = HTTPMethod | \"*\";\n\nexport type InferBodyInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tBody = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer B;\n\t\t};\n\t}\n\t\t? B\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"body\"]>\n\t\t\t: undefined,\n> = undefined extends Body\n\t? {\n\t\t\tbody?: Body;\n\t\t}\n\t: {\n\t\t\tbody: Body;\n\t\t};\n\nexport type InferBody<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer Body;\n\t\t};\n\t}\n\t\t? Body\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"body\"]>\n\t\t\t: any;\n\nexport type InferQueryInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tQuery = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined,\n> = undefined extends Query\n\t? {\n\t\t\tquery?: Query;\n\t\t}\n\t: {\n\t\t\tquery: Query;\n\t\t};\n\nexport type InferQuery<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined;\n\nexport type InferMethod<Options extends EndpointOptions> =\n\tOptions[\"method\"] extends Array<Method>\n\t\t? Options[\"method\"][number]\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"];\n\nexport type InferInputMethod<\n\tOptions extends EndpointOptions,\n\tMethod = Options[\"method\"] extends Array<any>\n\t\t? Options[\"method\"][number] | undefined\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"] | undefined,\n> = undefined extends Method\n\t? {\n\t\t\tmethod?: Method;\n\t\t}\n\t: {\n\t\t\tmethod: Method;\n\t\t};\n\nexport type InferParam<Path extends string> = [Path] extends [never]\n\t? Record<string, any> | undefined\n\t: IsEmptyObject<InferParamPath<Path> & InferParamWildCard<Path>> extends true\n\t\t? Record<string, any> | undefined\n\t\t: Prettify<InferParamPath<Path> & InferParamWildCard<Path>>;\n\nexport type InferParamInput<Path extends string> = [Path] extends [never]\n\t? { params?: Record<string, any> }\n\t: IsEmptyObject<InferParamPath<Path> & InferParamWildCard<Path>> extends true\n\t\t? {\n\t\t\t\tparams?: Record<string, any>;\n\t\t\t}\n\t\t: {\n\t\t\t\tparams: Prettify<InferParamPath<Path> & InferParamWildCard<Path>>;\n\t\t\t};\n\nexport type InferRequest<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireRequest\"] extends true ? Request : Request | undefined;\n\nexport type InferRequestInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireRequest\"] extends true\n\t? {\n\t\t\trequest: Request;\n\t\t}\n\t: {\n\t\t\trequest?: Request;\n\t\t};\n\nexport type InferHeaders<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireHeaders\"] extends true ? Headers : Headers | undefined;\n\nexport type InferHeadersInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireHeaders\"] extends true\n\t? {\n\t\t\theaders: HeadersInit;\n\t\t}\n\t: {\n\t\t\theaders?: HeadersInit;\n\t\t};\n\nexport type InferUse<Opts extends EndpointOptions[\"use\"]> =\n\tOpts extends Middleware[]\n\t\t? UnionToIntersection<Awaited<ReturnType<Opts[number]>>>\n\t\t: {};\n\nexport type InferMiddlewareBody<Options extends MiddlewareOptions> =\n\tOptions[\"body\"] extends StandardSchemaV1<infer T> ? T : any;\n\nexport type InferMiddlewareQuery<Options extends MiddlewareOptions> =\n\tOptions[\"query\"] extends StandardSchemaV1<infer T>\n\t\t? T\n\t\t: Record<string, any> | undefined;\n\nexport type InputContext<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n> = InferBodyInput<Options> &\n\tInferInputMethod<Options> &\n\tInferQueryInput<Options> &\n\tInferParamInput<Path> &\n\tInferRequestInput<Options> &\n\tInferHeadersInput<Options> & {\n\t\tasResponse?: boolean;\n\t\treturnHeaders?: boolean;\n\t\treturnStatus?: boolean;\n\t\tuse?: Middleware[];\n\t\tpath?: string;\n\t\tcontext?: Record<string, any>;\n\t};\n\nexport const createInternalContext = async (\n\tcontext: InputContext<any, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: EndpointOptions;\n\t\tpath?: string;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined = undefined;\n\n\tconst { data, error } = await runValidation(options, context);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\tconst requestHeaders: Headers | null =\n\t\t\"headers\" in context\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\treturned: undefined as any,\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: (\n\t\t\tjson: Record<string, any>,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t) => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t};\n\t\t},\n\t\tresponseHeaders: headers,\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t};\n\t//if context was shimmed through the input we want to apply it\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\t/**\n\t\t * Apply headers from the middleware to the endpoint headers\n\t\t */\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\treturn internalContext;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"context.mjs","names":[],"sources":["../src/context.ts"],"sourcesContent":["import type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport {\n\tAPIError,\n\ttype Status,\n\ttype statusCodes,\n\tValidationError,\n} from \"./error\";\nimport type { Prettify } from \"./helper\";\nimport type { Middleware, MiddlewareContext } from \"./middleware\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport type {\n\tInferParam,\n\tInferUse,\n\tResolveBody,\n\tResolveMethod,\n\tResolveQuery,\n} from \"./types\";\nimport { isRequest } from \"./utils\";\nimport { runValidation } from \"./validator\";\n\nexport type EndpointContext<\n\tPath extends string,\n\tM,\n\tBodySchema extends object | undefined,\n\tQuerySchema extends object | undefined,\n\tUse extends Middleware[],\n\tReqHeaders extends boolean,\n\tReqRequest extends boolean,\n\tContext = {},\n\tMeta = undefined,\n> = {\n\t/**\n\t * Method\n\t *\n\t * The request method\n\t */\n\tmethod: ResolveMethod<M>;\n\t/**\n\t * Path\n\t *\n\t * The path of the endpoint\n\t */\n\tpath: Path;\n\t/**\n\t * Body\n\t *\n\t * The body object will be the parsed JSON from the request and validated\n\t * against the body schema if it exists.\n\t */\n\tbody: ResolveBody<BodySchema, Meta>;\n\t/**\n\t * Query\n\t *\n\t * The query object will be the parsed query string from the request\n\t * and validated against the query schema if it exists\n\t */\n\tquery: ResolveQuery<QuerySchema, Meta>;\n\t/**\n\t * Params\n\t *\n\t * If the path is `/user/:id` and the request is `/user/1` then the params will\n\t * be `{ id: \"1\" }` and if the path includes a wildcard like `/user/*` then the\n\t * params will be `{ _: \"1\" }` where `_` is the wildcard key. If the wildcard\n\t * is named like `/user/**:name` then the params will be `{ name: string }`\n\t */\n\tparams: InferParam<Path>;\n\t/**\n\t * Request object\n\t *\n\t * If `requireRequest` is set to true in the endpoint options this will be\n\t * required\n\t */\n\trequest: ReqRequest extends true ? Request : Request | undefined;\n\t/**\n\t * Headers\n\t *\n\t * If `requireHeaders` is set to true in the endpoint options this will be\n\t * required\n\t */\n\theaders: ReqHeaders extends true ? Headers : Headers | undefined;\n\t/**\n\t * Set header\n\t *\n\t * If it's called outside of a request it will just be ignored.\n\t */\n\tsetHeader: (key: string, value: string) => void;\n\t/**\n\t * Set the response status code\n\t */\n\tsetStatus: (status: Status) => void;\n\t/**\n\t * Get header\n\t *\n\t * If it's called outside of a request it will just return null\n\t *\n\t * @param key - The key of the header\n\t */\n\tgetHeader: (key: string) => string | null;\n\t/**\n\t * Get a cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie\n\t */\n\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;\n\t/**\n\t * Get a signed cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param secret - The secret of the signed cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie or null if the cookie is not found or false if the signature is invalid\n\t */\n\tgetSignedCookie: (\n\t\tkey: string,\n\t\tsecret: string,\n\t\tprefix?: CookiePrefixOptions,\n\t) => Promise<string | null | false>;\n\t/**\n\t * Set a cookie value in the response\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetCookie: (key: string, value: string, options?: CookieOptions) => string;\n\t/**\n\t * Set signed cookie\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param secret - The secret to sign the cookie with\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetSignedCookie: (\n\t\tkey: string,\n\t\tvalue: string,\n\t\tsecret: string,\n\t\toptions?: CookieOptions,\n\t) => Promise<string>;\n\t/**\n\t * JSON\n\t *\n\t * A helper function to create a JSON response with the correct headers\n\t * and status code. If `asResponse` is set to true in the context then\n\t * it will return a Response object instead of the JSON object.\n\t *\n\t * @param json - The JSON object to return\n\t * @param routerResponse - The response object to return if `asResponse` is\n\t * true in the context this will take precedence\n\t */\n\tjson: <R extends Record<string, any> | null>(\n\t\tjson: R,\n\t\trouterResponse?:\n\t\t\t| {\n\t\t\t\t\tstatus?: number;\n\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\tresponse?: Response;\n\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t }\n\t\t\t| Response,\n\t) => R;\n\t/**\n\t * Middleware context\n\t */\n\tcontext: 0 extends 1 & Use\n\t\t? Prettify<Context>\n\t\t: Prettify<Context & InferUse<Use>>;\n\t/**\n\t * Redirect to a new URL\n\t */\n\tredirect: (url: string) => APIError;\n\t/**\n\t * Return error\n\t */\n\terror: (\n\t\tstatus: keyof typeof statusCodes | Status,\n\t\tbody?: {\n\t\t\tmessage?: string;\n\t\t\tcode?: string;\n\t\t} & Record<string, any>,\n\t\theaders?: HeadersInit,\n\t) => APIError;\n};\n\n/**\n * Creates the internal context for an endpoint or middleware invocation.\n * This is the runtime function that does validation, cookie handling,\n * middleware execution, etc.\n */\nexport const createInternalContext = async (\n\tcontext: Record<string, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: {\n\t\t\tmethod?: string | string[];\n\t\t\tbody?: StandardSchemaV1;\n\t\t\tquery?: StandardSchemaV1;\n\t\t\trequireHeaders?: boolean;\n\t\t\trequireRequest?: boolean;\n\t\t\tuse?: Middleware[];\n\t\t\t[key: string]: any;\n\t\t};\n\t\tpath?: string;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined;\n\n\tconst { data, error } = await runValidation(options as any, context as any);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\n\tconst requestHeaders: Headers | null =\n\t\t\"headers\" in context\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: <R extends Record<string, any> | null>(\n\t\t\tjson: R,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t): R => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t} as any;\n\t\t},\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t\tresponseHeaders: headers,\n\t} satisfies MiddlewareContext<any>;\n\n\t// Execute middleware chain\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\n\treturn internalContext;\n};\n"],"mappings":"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"}
package/dist/cookies.cjs CHANGED
@@ -1,5 +1,5 @@
1
- const require_utils = require('./utils.cjs');
2
1
  const require_crypto = require('./crypto.cjs');
2
+ const require_utils = require('./utils.cjs');
3
3
 
4
4
  //#region src/cookies.ts
5
5
  const getCookieKey = (key, prefix) => {
@@ -86,18 +86,7 @@ type CookieOptions = {
86
86
  */
87
87
  prefix?: CookiePrefixOptions;
88
88
  };
89
- declare const getCookieKey: (key: string, prefix?: CookiePrefixOptions) => string | undefined;
90
- /**
91
- * Parse an HTTP Cookie header string and returning an object of all cookie
92
- * name-value pairs.
93
- *
94
- * Inspired by https://github.com/unjs/cookie-es/blob/main/src/cookie/parse.ts
95
- *
96
- * @param str the string representing a `Cookie` header value
97
- */
98
- declare function parseCookies(str: string): Map<string, string>;
99
- declare const serializeCookie: (key: string, value: string, opt?: CookieOptions) => string;
100
89
  declare const serializeSignedCookie: (key: string, value: string, secret: string, opt?: CookieOptions) => Promise<string>;
101
90
  //#endregion
102
- export { CookieOptions, CookiePrefixOptions, getCookieKey, parseCookies, serializeCookie, serializeSignedCookie };
91
+ export { CookieOptions, CookiePrefixOptions, serializeSignedCookie };
103
92
  //# sourceMappingURL=cookies.d.cts.map
@@ -86,18 +86,7 @@ type CookieOptions = {
86
86
  */
87
87
  prefix?: CookiePrefixOptions;
88
88
  };
89
- declare const getCookieKey: (key: string, prefix?: CookiePrefixOptions) => string | undefined;
90
- /**
91
- * Parse an HTTP Cookie header string and returning an object of all cookie
92
- * name-value pairs.
93
- *
94
- * Inspired by https://github.com/unjs/cookie-es/blob/main/src/cookie/parse.ts
95
- *
96
- * @param str the string representing a `Cookie` header value
97
- */
98
- declare function parseCookies(str: string): Map<string, string>;
99
- declare const serializeCookie: (key: string, value: string, opt?: CookieOptions) => string;
100
89
  declare const serializeSignedCookie: (key: string, value: string, secret: string, opt?: CookieOptions) => Promise<string>;
101
90
  //#endregion
102
- export { CookieOptions, CookiePrefixOptions, getCookieKey, parseCookies, serializeCookie, serializeSignedCookie };
91
+ export { CookieOptions, CookiePrefixOptions, serializeSignedCookie };
103
92
  //# sourceMappingURL=cookies.d.mts.map
package/dist/cookies.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { tryDecode } from "./utils.mjs";
2
1
  import { signCookieValue } from "./crypto.mjs";
2
+ import { tryDecode } from "./utils.mjs";
3
3
 
4
4
  //#region src/cookies.ts
5
5
  const getCookieKey = (key, prefix) => {