better-call 0.2.10 → 0.2.13-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,291 +1,137 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
- var __commonJS = (cb, mod) => function __require() {
10
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
- };
12
- var __export = (target, all) => {
13
- for (var name in all)
14
- __defProp(target, name, { get: all[name], enumerable: true });
15
- };
16
- var __copyProps = (to, from, except, desc) => {
17
- if (from && typeof from === "object" || typeof from === "function") {
18
- for (let key of __getOwnPropNames(from))
19
- if (!__hasOwnProp.call(to, key) && key !== except)
20
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
- }
22
- return to;
23
- };
24
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
- // If the importer is in node compatibility mode or this is not an ESM
26
- // file that has been converted to a CommonJS file using a Babel-
27
- // compatible transform (i.e. "__esModule" has not been set), then set
28
- // "default" to the CommonJS "module.exports" for node compatibility.
29
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
- mod
31
- ));
32
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1
+ 'use strict';
2
+
3
+ const crypto = require('uncrypto');
4
+ const rou3 = require('rou3');
5
+
6
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
34
7
 
35
- // node_modules/set-cookie-parser/lib/set-cookie.js
36
- var require_set_cookie = __commonJS({
37
- "node_modules/set-cookie-parser/lib/set-cookie.js"(exports2, module2) {
38
- "use strict";
39
- var defaultParseOptions = {
40
- decodeValues: true,
41
- map: false,
42
- silent: false
8
+ const crypto__default = /*#__PURE__*/_interopDefaultCompat(crypto);
9
+
10
+ function createJSON({
11
+ asResponse,
12
+ response
13
+ }) {
14
+ return async function json(json, routerResponse) {
15
+ if (!asResponse) {
16
+ return json;
17
+ }
18
+ return {
19
+ body: json,
20
+ routerResponse,
21
+ _flag: "json"
43
22
  };
44
- function isNonEmptyString(str) {
45
- return typeof str === "string" && !!str.trim();
46
- }
47
- function parseString(setCookieValue, options) {
48
- var parts = setCookieValue.split(";").filter(isNonEmptyString);
49
- var nameValuePairStr = parts.shift();
50
- var parsed = parseNameValuePair(nameValuePairStr);
51
- var name = parsed.name;
52
- var value = parsed.value;
53
- options = options ? Object.assign({}, defaultParseOptions, options) : defaultParseOptions;
54
- try {
55
- value = options.decodeValues ? decodeURIComponent(value) : value;
56
- } catch (e) {
57
- console.error(
58
- "set-cookie-parser encountered an error while decoding a cookie with value '" + value + "'. Set options.decodeValues to false to disable this feature.",
59
- e
60
- );
61
- }
62
- var cookie = {
63
- name,
64
- value
23
+ };
24
+ }
25
+ function runValidation(options, context) {
26
+ let request = {
27
+ body: void 0,
28
+ query: void 0
29
+ };
30
+ if (options.body) {
31
+ const result = options.body.safeParse(context.body);
32
+ if (result.error) {
33
+ return {
34
+ data: null,
35
+ error: fromError(result.error)
65
36
  };
66
- parts.forEach(function(part) {
67
- var sides = part.split("=");
68
- var key = sides.shift().trimLeft().toLowerCase();
69
- var value2 = sides.join("=");
70
- if (key === "expires") {
71
- cookie.expires = new Date(value2);
72
- } else if (key === "max-age") {
73
- cookie.maxAge = parseInt(value2, 10);
74
- } else if (key === "secure") {
75
- cookie.secure = true;
76
- } else if (key === "httponly") {
77
- cookie.httpOnly = true;
78
- } else if (key === "samesite") {
79
- cookie.sameSite = value2;
80
- } else if (key === "partitioned") {
81
- cookie.partitioned = true;
82
- } else {
83
- cookie[key] = value2;
84
- }
85
- });
86
- return cookie;
87
- }
88
- function parseNameValuePair(nameValuePairStr) {
89
- var name = "";
90
- var value = "";
91
- var nameValueArr = nameValuePairStr.split("=");
92
- if (nameValueArr.length > 1) {
93
- name = nameValueArr.shift();
94
- value = nameValueArr.join("=");
95
- } else {
96
- value = nameValuePairStr;
97
- }
98
- return { name, value };
99
37
  }
100
- function parse2(input, options) {
101
- options = options ? Object.assign({}, defaultParseOptions, options) : defaultParseOptions;
102
- if (!input) {
103
- if (!options.map) {
104
- return [];
105
- } else {
106
- return {};
107
- }
108
- }
109
- if (input.headers) {
110
- if (typeof input.headers.getSetCookie === "function") {
111
- input = input.headers.getSetCookie();
112
- } else if (input.headers["set-cookie"]) {
113
- input = input.headers["set-cookie"];
114
- } else {
115
- var sch = input.headers[Object.keys(input.headers).find(function(key) {
116
- return key.toLowerCase() === "set-cookie";
117
- })];
118
- if (!sch && input.headers.cookie && !options.silent) {
119
- console.warn(
120
- "Warning: set-cookie-parser appears to have been called on a request object. It is designed to parse Set-Cookie headers from responses, not Cookie headers from requests. Set the option {silent: true} to suppress this warning."
121
- );
122
- }
123
- input = sch;
124
- }
125
- }
126
- if (!Array.isArray(input)) {
127
- input = [input];
128
- }
129
- options = options ? Object.assign({}, defaultParseOptions, options) : defaultParseOptions;
130
- if (!options.map) {
131
- return input.filter(isNonEmptyString).map(function(str) {
132
- return parseString(str, options);
133
- });
134
- } else {
135
- var cookies = {};
136
- return input.filter(isNonEmptyString).reduce(function(cookies2, str) {
137
- var cookie = parseString(str, options);
138
- cookies2[cookie.name] = cookie;
139
- return cookies2;
140
- }, cookies);
141
- }
38
+ request.body = result.data;
39
+ }
40
+ if (options.query) {
41
+ const result = options.query.safeParse(context.query);
42
+ if (result.error) {
43
+ return {
44
+ data: null,
45
+ error: fromError(result.error)
46
+ };
142
47
  }
143
- function splitCookiesString2(cookiesString) {
144
- if (Array.isArray(cookiesString)) {
145
- return cookiesString;
146
- }
147
- if (typeof cookiesString !== "string") {
148
- return [];
149
- }
150
- var cookiesStrings = [];
151
- var pos = 0;
152
- var start;
153
- var ch;
154
- var lastComma;
155
- var nextStart;
156
- var cookiesSeparatorFound;
157
- function skipWhitespace() {
158
- while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) {
159
- pos += 1;
160
- }
161
- return pos < cookiesString.length;
162
- }
163
- function notSpecialChar() {
164
- ch = cookiesString.charAt(pos);
165
- return ch !== "=" && ch !== ";" && ch !== ",";
166
- }
167
- while (pos < cookiesString.length) {
168
- start = pos;
169
- cookiesSeparatorFound = false;
170
- while (skipWhitespace()) {
171
- ch = cookiesString.charAt(pos);
172
- if (ch === ",") {
173
- lastComma = pos;
174
- pos += 1;
175
- skipWhitespace();
176
- nextStart = pos;
177
- while (pos < cookiesString.length && notSpecialChar()) {
178
- pos += 1;
179
- }
180
- if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") {
181
- cookiesSeparatorFound = true;
182
- pos = nextStart;
183
- cookiesStrings.push(cookiesString.substring(start, lastComma));
184
- start = pos;
185
- } else {
186
- pos = lastComma + 1;
187
- }
188
- } else {
189
- pos += 1;
190
- }
191
- }
192
- if (!cookiesSeparatorFound || pos >= cookiesString.length) {
193
- cookiesStrings.push(cookiesString.substring(start, cookiesString.length));
194
- }
195
- }
196
- return cookiesStrings;
48
+ request.query = result.data;
49
+ }
50
+ if (options.requireHeaders && !(context.headers instanceof Headers)) {
51
+ return {
52
+ data: null,
53
+ error: { message: "Validation Error: Headers are required" }
54
+ };
55
+ }
56
+ if (options.requireRequest && !context.request) {
57
+ return {
58
+ data: null,
59
+ error: { message: "Validation Error: Request is required" }
60
+ };
61
+ }
62
+ return {
63
+ data: request,
64
+ error: null
65
+ };
66
+ }
67
+ function fromError(error) {
68
+ const errorMessages = [];
69
+ for (const issue of error.issues) {
70
+ const path = issue.path.join(".");
71
+ const message = issue.message;
72
+ if (path) {
73
+ errorMessages.push(`${message} at "${path}"`);
74
+ } else {
75
+ errorMessages.push(message);
197
76
  }
198
- module2.exports = parse2;
199
- module2.exports.parse = parse2;
200
- module2.exports.parseString = parseString;
201
- module2.exports.splitCookiesString = splitCookiesString2;
202
77
  }
203
- });
204
-
205
- // src/index.ts
206
- var src_exports = {};
207
- __export(src_exports, {
208
- APIError: () => APIError,
209
- createEndpoint: () => createEndpoint,
210
- createEndpointCreator: () => createEndpointCreator,
211
- createMiddleware: () => createMiddleware,
212
- createMiddlewareCreator: () => createMiddlewareCreator,
213
- createRouter: () => createRouter,
214
- getBody: () => getBody,
215
- getCookie: () => getCookie,
216
- getRequest: () => getRequest,
217
- getSignedCookie: () => getSignedCookie,
218
- parse: () => parse,
219
- parseSigned: () => parseSigned,
220
- serialize: () => serialize,
221
- serializeSigned: () => serializeSigned,
222
- setCookie: () => setCookie,
223
- setResponse: () => setResponse,
224
- setSignedCookie: () => setSignedCookie,
225
- shouldSerialize: () => shouldSerialize,
226
- statusCode: () => statusCode,
227
- toNodeHandler: () => toNodeHandler
228
- });
229
- module.exports = __toCommonJS(src_exports);
78
+ return {
79
+ message: `Validation error: ${errorMessages.join(", ")}`
80
+ };
81
+ }
230
82
 
231
- // src/endpoint.ts
232
- var import_zod = require("zod");
83
+ function createSetHeader(headers) {
84
+ return (key, value) => {
85
+ headers.set(key, value);
86
+ };
87
+ }
88
+ function createGetHeader(headers) {
89
+ return (key) => {
90
+ return headers.get(key);
91
+ };
92
+ }
233
93
 
234
- // src/error.ts
235
- var APIError = class extends Error {
236
- constructor(status, body, headers) {
237
- super(`API Error: ${status} ${body?.message ?? ""}`, {
238
- cause: body
239
- });
240
- __publicField(this, "status");
241
- __publicField(this, "headers");
242
- __publicField(this, "body");
94
+ class APIError extends Error {
95
+ constructor(message, status = 500, code = "INTERNAL_SERVER_ERROR", headers = {}) {
96
+ super(message);
97
+ this.message = message;
243
98
  this.status = status;
244
- this.body = body ?? {};
99
+ this.code = code;
100
+ this.headers = headers;
101
+ this.name = "APIError";
102
+ this.message = message;
103
+ this.status = status;
104
+ this.code = code;
105
+ this.headers = headers;
245
106
  this.stack = "";
246
- this.headers = headers || new Headers();
247
- this.name = "BetterCallAPIError";
248
107
  }
249
- };
250
-
251
- // src/helper.ts
252
- var json = (body, option) => {
253
- return {
254
- response: {
255
- body: option?.body ?? body,
256
- status: option?.status ?? 200,
257
- statusText: option?.statusText ?? "OK",
258
- headers: option?.headers
259
- },
260
- body,
261
- _flag: "json"
262
- };
263
- };
108
+ }
264
109
 
265
- // src/cookie.ts
266
- var import_uncrypto = __toESM(require("uncrypto"), 1);
267
- var algorithm = { name: "HMAC", hash: "SHA-256" };
268
- var getCryptoKey = async (secret) => {
110
+ const algorithm = { name: "HMAC", hash: "SHA-256" };
111
+ const getCryptoKey = async (secret) => {
269
112
  const secretBuf = typeof secret === "string" ? new TextEncoder().encode(secret) : secret;
270
- return await import_uncrypto.default.subtle.importKey("raw", secretBuf, algorithm, false, ["sign", "verify"]);
113
+ return await crypto__default.subtle.importKey("raw", secretBuf, algorithm, false, [
114
+ "sign",
115
+ "verify"
116
+ ]);
271
117
  };
272
- var makeSignature = async (value, secret) => {
118
+ const makeSignature = async (value, secret) => {
273
119
  const key = await getCryptoKey(secret);
274
- const signature = await import_uncrypto.default.subtle.sign(
120
+ const signature = await crypto__default.subtle.sign(
275
121
  algorithm.name,
276
122
  key,
277
123
  new TextEncoder().encode(value)
278
124
  );
279
125
  return btoa(String.fromCharCode(...new Uint8Array(signature)));
280
126
  };
281
- var verifySignature = async (base64Signature, value, secret) => {
127
+ const verifySignature = async (base64Signature, value, secret) => {
282
128
  try {
283
129
  const signatureBinStr = atob(base64Signature);
284
130
  const signature = new Uint8Array(signatureBinStr.length);
285
131
  for (let i = 0, len = signatureBinStr.length; i < len; i++) {
286
132
  signature[i] = signatureBinStr.charCodeAt(i);
287
133
  }
288
- return await import_uncrypto.default.subtle.verify(
134
+ return await crypto__default.subtle.verify(
289
135
  algorithm,
290
136
  secret,
291
137
  signature,
@@ -295,9 +141,9 @@ var verifySignature = async (base64Signature, value, secret) => {
295
141
  return false;
296
142
  }
297
143
  };
298
- var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
299
- var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
300
- var parse = (cookie, name) => {
144
+ const validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
145
+ const validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
146
+ const parse = (cookie, name) => {
301
147
  const pairs = cookie.trim().split(";");
302
148
  return pairs.reduce((parsedCookie, pairStr) => {
303
149
  pairStr = pairStr.trim();
@@ -319,7 +165,7 @@ var parse = (cookie, name) => {
319
165
  return parsedCookie;
320
166
  }, {});
321
167
  };
322
- var parseSigned = async (cookie, secret, name) => {
168
+ const parseSigned = async (cookie, secret, name) => {
323
169
  const parsedCookie = {};
324
170
  const secretKey = await getCryptoKey(secret);
325
171
  for (const [key, value] of Object.entries(parse(cookie, name))) {
@@ -337,7 +183,7 @@ var parseSigned = async (cookie, secret, name) => {
337
183
  }
338
184
  return parsedCookie;
339
185
  };
340
- var _serialize = (name, value, opt = {}) => {
186
+ const _serialize = (name, value, opt = {}) => {
341
187
  let cookie = `${name}=${value}`;
342
188
  if (name.startsWith("__Secure-") && !opt.secure) {
343
189
  opt.secure = true;
@@ -392,19 +238,18 @@ var _serialize = (name, value, opt = {}) => {
392
238
  }
393
239
  return cookie;
394
240
  };
395
- var serialize = (name, value, opt) => {
241
+ const serialize = (name, value, opt) => {
396
242
  value = encodeURIComponent(value);
397
243
  return _serialize(name, value, opt);
398
244
  };
399
- var serializeSigned = async (name, value, secret, opt = {}) => {
245
+ const serializeSigned = async (name, value, secret, opt = {}) => {
400
246
  const signature = await makeSignature(value, secret);
401
247
  value = `${value}.${signature}`;
402
248
  value = encodeURIComponent(value);
403
249
  return _serialize(name, value, opt);
404
250
  };
405
251
 
406
- // src/cookie-utils.ts
407
- var getCookie = (cookie, key, prefix) => {
252
+ const getCookie = (cookie, key, prefix) => {
408
253
  if (!cookie) {
409
254
  return void 0;
410
255
  }
@@ -421,17 +266,23 @@ var getCookie = (cookie, key, prefix) => {
421
266
  const obj = parse(cookie, finalKey);
422
267
  return obj[finalKey];
423
268
  };
424
- var setCookie = (header, name, value, opt) => {
269
+ const setCookie = (header, name, value, opt) => {
425
270
  const existingCookies = header.get("Set-Cookie");
426
271
  if (existingCookies) {
427
272
  const cookies = existingCookies.split(", ");
428
- const updatedCookies = cookies.filter((cookie2) => !cookie2.startsWith(`${name}=`));
273
+ const updatedCookies = cookies.filter(
274
+ (cookie2) => !cookie2.startsWith(`${name}=`)
275
+ );
429
276
  header.delete("Set-Cookie");
430
277
  updatedCookies.forEach((cookie2) => header.append("Set-Cookie", cookie2));
431
278
  }
432
279
  let cookie;
433
280
  if (opt?.prefix === "secure") {
434
- cookie = serialize("__Secure-" + name, value, { path: "/", ...opt, secure: true });
281
+ cookie = serialize("__Secure-" + name, value, {
282
+ path: "/",
283
+ ...opt,
284
+ secure: true
285
+ });
435
286
  } else if (opt?.prefix === "host") {
436
287
  cookie = serialize("__Host-" + name, value, {
437
288
  ...opt,
@@ -444,7 +295,7 @@ var setCookie = (header, name, value, opt) => {
444
295
  }
445
296
  header.append("Set-Cookie", cookie);
446
297
  };
447
- var setSignedCookie = async (header, name, value, secret, opt) => {
298
+ const setSignedCookie = async (header, name, value, secret, opt) => {
448
299
  let cookie;
449
300
  if (opt?.prefix === "secure") {
450
301
  cookie = await serializeSigned("__Secure-" + name, value, secret, {
@@ -464,7 +315,7 @@ var setSignedCookie = async (header, name, value, secret, opt) => {
464
315
  }
465
316
  header.append("Set-Cookie", cookie);
466
317
  };
467
- var getSignedCookie = async (header, secret, key, prefix) => {
318
+ const getSignedCookie = async (header, secret, key, prefix) => {
468
319
  const cookie = header.get("cookie");
469
320
  if (!cookie) {
470
321
  return void 0;
@@ -481,162 +332,127 @@ var getSignedCookie = async (header, secret, key, prefix) => {
481
332
  return obj[finalKey];
482
333
  };
483
334
 
484
- // src/endpoint.ts
485
- function createEndpointCreator(opts) {
486
- return (path, options, handler) => {
487
- return createEndpoint(
488
- path,
335
+ const createResponse = (handlerResponse, response) => {
336
+ if (handlerResponse instanceof Response) {
337
+ response.headers.forEach((value, key) => {
338
+ handlerResponse.headers.set(key, value);
339
+ });
340
+ return handlerResponse;
341
+ } else if (handlerResponse?._flag === "json") {
342
+ const responseObj = new Response(
343
+ JSON.stringify(
344
+ handlerResponse.routerResponse?.body || handlerResponse.body
345
+ ),
489
346
  {
490
- ...options,
491
- use: [...options?.use || [], ...opts?.use || []]
492
- },
493
- handler
347
+ status: handlerResponse.routerResponse?.status || 200,
348
+ headers: handlerResponse.routerResponse?.headers
349
+ }
494
350
  );
495
- };
496
- }
497
- function createEndpoint(path, options, handler) {
498
- let responseHeader = new Headers();
499
- const handle = async (...ctx) => {
500
- let internalCtx = {
501
- setHeader(key, value) {
502
- responseHeader.set(key, value);
351
+ response.headers.forEach((value, key) => {
352
+ responseObj.headers.set(key, value);
353
+ });
354
+ return responseObj;
355
+ } else {
356
+ const responseObj = new Response(
357
+ handlerResponse ? JSON.stringify(handlerResponse) : void 0
358
+ );
359
+ response.headers.forEach((value, key) => {
360
+ responseObj.headers.set(key, value);
361
+ });
362
+ return responseObj;
363
+ }
364
+ };
365
+ const runMiddleware = async (options, context) => {
366
+ let finalContext = {};
367
+ for (const middleware of options.use || []) {
368
+ const result = await middleware(context);
369
+ if (result?.context && result._flag === "context") {
370
+ context = { ...context, ...result.context };
371
+ } else {
372
+ finalContext = { ...result, ...finalContext };
373
+ context.context = finalContext;
374
+ }
375
+ }
376
+ return finalContext;
377
+ };
378
+ const createEndpoint = (path, options, handler) => {
379
+ const internalHandler = async (...inputCtx) => {
380
+ let response = new Response();
381
+ const { asResponse, ...ctx } = inputCtx[0] || {};
382
+ const { data, error } = runValidation(options, ctx);
383
+ if (error) {
384
+ throw new APIError(error.message, 400);
385
+ }
386
+ const context = {
387
+ json: createJSON({
388
+ asResponse,
389
+ response
390
+ }),
391
+ body: "body" in data ? data.body : void 0,
392
+ path,
393
+ method: "method" in ctx ? ctx.method : void 0,
394
+ query: "query" in data ? data.query : void 0,
395
+ params: "params" in ctx ? ctx.params : void 0,
396
+ headers: "headers" in ctx ? ctx.headers : void 0,
397
+ request: "request" in ctx ? ctx.request : void 0,
398
+ setHeader: createSetHeader(response.headers),
399
+ getHeader: (key) => {
400
+ const requestHeaders = "headers" in ctx && ctx.headers instanceof Headers ? ctx.headers : "request" in ctx && ctx.request instanceof Request ? ctx.request.headers : null;
401
+ if (!requestHeaders)
402
+ return null;
403
+ return requestHeaders.get(key);
503
404
  },
504
- setCookie(key, value, options2) {
505
- setCookie(responseHeader, key, value, options2);
405
+ setCookie: (name, value, options2) => {
406
+ setCookie(response.headers, name, value, options2);
506
407
  },
507
408
  getCookie(key, prefix) {
508
- const header = ctx[0]?.headers;
509
- const cookieH = header?.get("cookie");
510
- const cookie = getCookie(cookieH || "", key, prefix);
511
- return cookie;
409
+ const headers = context.headers?.get("cookie");
410
+ if (!headers)
411
+ return void 0;
412
+ return getCookie(headers, key, prefix);
512
413
  },
513
- getSignedCookie(key, secret, prefix) {
514
- const header = ctx[0]?.headers;
515
- if (!header) {
516
- throw new TypeError("Headers are required");
517
- }
518
- const cookie = getSignedCookie(header, secret, key, prefix);
519
- return cookie;
414
+ setSignedCookie(key, value, secret, options2) {
415
+ return setSignedCookie(response.headers, key, value, secret, options2);
520
416
  },
521
- async setSignedCookie(key, value, secret, options2) {
522
- await setSignedCookie(responseHeader, key, value, secret, options2);
417
+ async getSignedCookie(key, secret, prefix) {
418
+ const headers = context.headers;
419
+ if (!headers)
420
+ return void 0;
421
+ return getSignedCookie(headers, secret, key, prefix);
523
422
  },
524
- redirect(url) {
525
- responseHeader.set("Location", url);
526
- return new APIError("FOUND");
423
+ redirect: (url) => {
424
+ const apiError = new APIError("Redirecting", 302, "FOUND", {
425
+ Location: url,
426
+ ...response.headers
427
+ });
428
+ return apiError;
527
429
  },
528
- json,
529
- context: ctx[0]?.context || {},
530
- _flag: ctx[0]?.asResponse ? "router" : ctx[0]?._flag,
531
- responseHeader,
532
- path,
533
- ...ctx[0] || {}
430
+ context: {}
534
431
  };
535
- if (options.use?.length) {
536
- let middlewareContexts = {};
537
- let middlewareBody = {};
538
- for (const middleware of options.use) {
539
- if (typeof middleware !== "function") {
540
- console.warn("Middleware is not a function", {
541
- middleware
542
- });
543
- continue;
544
- }
545
- const res = await middleware(internalCtx);
546
- if (res) {
547
- const body = res.options?.body ? res.options.body.parse(internalCtx.body) : void 0;
548
- middlewareContexts = {
549
- ...middlewareContexts,
550
- ...res
551
- };
552
- middlewareBody = {
553
- ...middlewareBody,
554
- ...body
555
- };
556
- }
557
- }
558
- internalCtx = {
559
- ...internalCtx,
560
- body: {
561
- ...middlewareBody,
562
- ...internalCtx.body
563
- },
564
- context: {
565
- ...internalCtx.context || {},
566
- ...middlewareContexts
432
+ const finalContext = await runMiddleware(options, context);
433
+ context.context = finalContext;
434
+ const handlerResponse = await handler(context).catch((e) => {
435
+ if (e instanceof APIError && asResponse) {
436
+ const headers = response.headers;
437
+ for (const [key, value] of Object.entries(e.headers)) {
438
+ headers.set(key, value);
567
439
  }
568
- };
569
- }
570
- try {
571
- const body = options.body ? options.body.parse(internalCtx.body) : internalCtx.body;
572
- internalCtx = {
573
- ...internalCtx,
574
- body: body ? {
575
- ...body,
576
- ...internalCtx.body
577
- } : internalCtx.body
578
- };
579
- internalCtx.query = options.query ? options.query.parse(internalCtx.query) : internalCtx.query;
580
- } catch (e) {
581
- if (e instanceof import_zod.ZodError) {
582
- throw new APIError("BAD_REQUEST", {
583
- message: e.message,
584
- details: e.errors
440
+ return new Response(null, {
441
+ status: e.status,
442
+ headers
585
443
  });
586
444
  }
587
445
  throw e;
588
- }
589
- if (options.requireHeaders && !internalCtx.headers) {
590
- throw new APIError("BAD_REQUEST", {
591
- message: "Headers are required"
592
- });
593
- }
594
- if (options.requireRequest && !internalCtx.request) {
595
- throw new APIError("BAD_REQUEST", {
596
- message: "Request is required"
597
- });
598
- }
599
- try {
600
- let res = await handler(internalCtx);
601
- let actualResponse = res;
602
- if (res && typeof res === "object" && "_flag" in res) {
603
- if (res._flag === "json" && internalCtx._flag === "router") {
604
- const h = res.response.headers;
605
- Object.keys(h || {}).forEach((key) => {
606
- responseHeader.set(key, h[key]);
607
- });
608
- responseHeader.set("Content-Type", "application/json");
609
- actualResponse = new Response(JSON.stringify(res.response.body), {
610
- status: res.response.status ?? 200,
611
- statusText: res.response.statusText,
612
- headers: responseHeader
613
- });
614
- } else {
615
- actualResponse = res.body;
616
- }
617
- }
618
- responseHeader = new Headers();
619
- return actualResponse;
620
- } catch (e) {
621
- if (e instanceof APIError) {
622
- e.headers = responseHeader;
623
- responseHeader = new Headers();
624
- throw e;
625
- }
626
- throw e;
627
- }
446
+ });
447
+ response = createResponse(handlerResponse, response);
448
+ const res = asResponse ? response : handlerResponse;
449
+ return res;
628
450
  };
629
- handle.path = path;
630
- handle.options = options;
631
- handle.method = options.method;
632
- handle.headers = responseHeader;
633
- return handle;
634
- }
635
-
636
- // src/router.ts
637
- var import_rou3 = require("rou3");
451
+ internalHandler.path = path;
452
+ internalHandler.options = options;
453
+ return internalHandler;
454
+ };
638
455
 
639
- // src/utils.ts
640
456
  async function getBody(request) {
641
457
  const contentType = request.headers.get("content-type") || "";
642
458
  if (!request.body) {
@@ -676,78 +492,22 @@ async function getBody(request) {
676
492
  }
677
493
  return await request.text();
678
494
  }
679
- function shouldSerialize(body) {
680
- return typeof body === "object" && body !== null && !(body instanceof Blob) && !(body instanceof FormData);
681
- }
682
- var statusCode = {
683
- OK: 200,
684
- CREATED: 201,
685
- ACCEPTED: 202,
686
- NO_CONTENT: 204,
687
- MULTIPLE_CHOICES: 300,
688
- MOVED_PERMANENTLY: 301,
689
- FOUND: 302,
690
- SEE_OTHER: 303,
691
- NOT_MODIFIED: 304,
692
- TEMPORARY_REDIRECT: 307,
693
- BAD_REQUEST: 400,
694
- UNAUTHORIZED: 401,
695
- PAYMENT_REQUIRED: 402,
696
- FORBIDDEN: 403,
697
- NOT_FOUND: 404,
698
- METHOD_NOT_ALLOWED: 405,
699
- NOT_ACCEPTABLE: 406,
700
- PROXY_AUTHENTICATION_REQUIRED: 407,
701
- REQUEST_TIMEOUT: 408,
702
- CONFLICT: 409,
703
- GONE: 410,
704
- LENGTH_REQUIRED: 411,
705
- PRECONDITION_FAILED: 412,
706
- PAYLOAD_TOO_LARGE: 413,
707
- URI_TOO_LONG: 414,
708
- UNSUPPORTED_MEDIA_TYPE: 415,
709
- RANGE_NOT_SATISFIABLE: 416,
710
- EXPECTATION_FAILED: 417,
711
- "I'M_A_TEAPOT": 418,
712
- MISDIRECTED_REQUEST: 421,
713
- UNPROCESSABLE_ENTITY: 422,
714
- LOCKED: 423,
715
- FAILED_DEPENDENCY: 424,
716
- TOO_EARLY: 425,
717
- UPGRADE_REQUIRED: 426,
718
- PRECONDITION_REQUIRED: 428,
719
- TOO_MANY_REQUESTS: 429,
720
- REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
721
- UNAVAILABLE_FOR_LEGAL_REASONS: 451,
722
- INTERNAL_SERVER_ERROR: 500,
723
- NOT_IMPLEMENTED: 501,
724
- BAD_GATEWAY: 502,
725
- SERVICE_UNAVAILABLE: 503,
726
- GATEWAY_TIMEOUT: 504,
727
- HTTP_VERSION_NOT_SUPPORTED: 505,
728
- VARIANT_ALSO_NEGOTIATES: 506,
729
- INSUFFICIENT_STORAGE: 507,
730
- LOOP_DETECTED: 508,
731
- NOT_EXTENDED: 510,
732
- NETWORK_AUTHENTICATION_REQUIRED: 511
733
- };
734
495
 
735
- // src/router.ts
736
- var createRouter = (endpoints, config) => {
496
+ const createRouter = (endpoints, config) => {
737
497
  const _endpoints = Object.values(endpoints);
738
- const router = (0, import_rou3.createRouter)();
498
+ const router = rou3.createRouter();
739
499
  for (const endpoint of _endpoints) {
740
500
  if (Array.isArray(endpoint.options?.method)) {
741
501
  for (const method of endpoint.options.method) {
742
- (0, import_rou3.addRoute)(router, method, endpoint.path, endpoint);
502
+ rou3.addRoute(router, method, endpoint.path, endpoint);
743
503
  }
744
504
  } else {
745
- (0, import_rou3.addRoute)(router, endpoint.options.method, endpoint.path, endpoint);
505
+ rou3.addRoute(router, endpoint.options.method, endpoint.path, endpoint);
746
506
  }
747
507
  }
748
- const middlewareRouter = (0, import_rou3.createRouter)();
508
+ const middlewareRouter = rou3.createRouter();
749
509
  for (const route of config?.routerMiddleware || []) {
750
- (0, import_rou3.addRoute)(middlewareRouter, "*", route.path, route.middleware);
510
+ rou3.addRoute(middlewareRouter, "*", route.path, route.middleware);
751
511
  }
752
512
  const handler = async (request) => {
753
513
  const url = new URL(request.url);
@@ -766,12 +526,12 @@ var createRouter = (endpoints, config) => {
766
526
  });
767
527
  }
768
528
  const method = request.method;
769
- const route = (0, import_rou3.findRoute)(router, method, path);
529
+ const route = rou3.findRoute(router, method, path);
770
530
  const handler2 = route?.data;
771
531
  const body = await getBody(request);
772
532
  const headers = request.headers;
773
533
  const query = Object.fromEntries(url.searchParams);
774
- const routerMiddleware = (0, import_rou3.findAllRoutes)(middlewareRouter, "*", path);
534
+ const routerMiddleware = rou3.findAllRoutes(middlewareRouter, "*", path);
775
535
  if (!handler2) {
776
536
  return new Response(null, {
777
537
  status: 404,
@@ -819,18 +579,17 @@ var createRouter = (endpoints, config) => {
819
579
  request,
820
580
  body,
821
581
  query,
822
- _flag: "router",
823
582
  context: {
824
583
  ...middlewareContext,
825
584
  ...config?.extraContext
826
- }
585
+ },
586
+ asResponse: true
827
587
  });
828
588
  if (handlerRes instanceof Response) {
829
589
  return handlerRes;
830
590
  }
831
- const resBody = shouldSerialize(handlerRes) ? JSON.stringify(handlerRes) : handlerRes;
832
- return new Response(resBody, {
833
- headers: handler2.headers
591
+ return new Response(handlerRes ? JSON.stringify(handlerRes) : void 0, {
592
+ status: 200
834
593
  });
835
594
  } catch (e) {
836
595
  if (config?.onError) {
@@ -840,12 +599,16 @@ var createRouter = (endpoints, config) => {
840
599
  }
841
600
  }
842
601
  if (e instanceof APIError) {
843
- headers.set("Content-Type", "application/json");
844
- return new Response(e.body ? JSON.stringify(e.body) : null, {
845
- status: statusCode[e.status],
846
- statusText: e.status,
847
- headers: e.headers
848
- });
602
+ return new Response(
603
+ e.message ? JSON.stringify({
604
+ message: e.message,
605
+ code: e.code
606
+ }) : null,
607
+ {
608
+ status: e.status,
609
+ headers: e.headers
610
+ }
611
+ );
849
612
  }
850
613
  if (config?.throwError) {
851
614
  throw e;
@@ -857,24 +620,11 @@ var createRouter = (endpoints, config) => {
857
620
  }
858
621
  };
859
622
  return {
860
- handler: async (request) => {
861
- const onReq = await config?.onRequest?.(request);
862
- if (onReq instanceof Response) {
863
- return onReq;
864
- }
865
- const req = onReq instanceof Request ? onReq : request;
866
- const res = await handler(req);
867
- const onRes = await config?.onResponse?.(res);
868
- if (onRes instanceof Response) {
869
- return onRes;
870
- }
871
- return res;
872
- },
623
+ handler,
873
624
  endpoints
874
625
  };
875
626
  };
876
627
 
877
- // src/middleware.ts
878
628
  function createMiddleware(optionsOrHandler, handler) {
879
629
  if (typeof optionsOrHandler === "function") {
880
630
  return createEndpoint(
@@ -898,202 +648,20 @@ function createMiddleware(optionsOrHandler, handler) {
898
648
  );
899
649
  return endpoint;
900
650
  }
901
- var createMiddlewareCreator = (opts) => {
902
- function fn(optionsOrHandler, handler) {
903
- if (typeof optionsOrHandler === "function") {
904
- return createEndpoint(
905
- "*",
906
- {
907
- method: "*"
908
- },
909
- optionsOrHandler
910
- );
911
- }
912
- if (!handler) {
913
- throw new Error("Middleware handler is required");
914
- }
915
- const endpoint = createEndpoint(
916
- "*",
917
- {
918
- ...optionsOrHandler,
919
- method: "*"
920
- },
921
- handler
922
- );
923
- return endpoint;
924
- }
925
- return fn;
926
- };
927
-
928
- // src/types.ts
929
- var import_zod2 = require("zod");
930
-
931
- // src/adapter/node.ts
932
- var import_node_http2 = require("http");
933
-
934
- // src/adapter/request.ts
935
- var import_node_http = require("http");
936
- var set_cookie_parser = __toESM(require_set_cookie(), 1);
937
- function get_raw_body(req, body_size_limit) {
938
- const h = req.headers;
939
- if (!h["content-type"]) return null;
940
- const content_length = Number(h["content-length"]);
941
- if (req.httpVersionMajor === 1 && isNaN(content_length) && h["transfer-encoding"] == null || content_length === 0) {
942
- return null;
943
- }
944
- let length = content_length;
945
- if (body_size_limit) {
946
- if (!length) {
947
- length = body_size_limit;
948
- } else if (length > body_size_limit) {
949
- throw Error(
950
- `Received content-length of ${length}, but only accept up to ${body_size_limit} bytes.`
951
- );
952
- }
953
- }
954
- if (req.destroyed) {
955
- const readable = new ReadableStream();
956
- readable.cancel();
957
- return readable;
958
- }
959
- let size = 0;
960
- let cancelled = false;
961
- return new ReadableStream({
962
- start(controller) {
963
- req.on("error", (error) => {
964
- cancelled = true;
965
- controller.error(error);
966
- });
967
- req.on("end", () => {
968
- if (cancelled) return;
969
- controller.close();
970
- });
971
- req.on("data", (chunk) => {
972
- if (cancelled) return;
973
- size += chunk.length;
974
- if (size > length) {
975
- cancelled = true;
976
- controller.error(
977
- new Error(
978
- `request body size exceeded ${content_length ? "'content-length'" : "BODY_SIZE_LIMIT"} of ${length}`
979
- )
980
- );
981
- return;
982
- }
983
- controller.enqueue(chunk);
984
- if (controller.desiredSize === null || controller.desiredSize <= 0) {
985
- req.pause();
986
- }
987
- });
988
- },
989
- pull() {
990
- req.resume();
991
- },
992
- cancel(reason) {
993
- cancelled = true;
994
- req.destroy(reason);
995
- }
996
- });
997
- }
998
- function getRequest({
999
- request,
1000
- base,
1001
- bodySizeLimit
1002
- }) {
1003
- return new Request(base + request.url, {
1004
- // @ts-expect-error
1005
- duplex: "half",
1006
- method: request.method,
1007
- body: get_raw_body(request, bodySizeLimit),
1008
- headers: request.headers
1009
- });
1010
- }
1011
- async function setResponse(res, response) {
1012
- for (const [key, value] of response.headers) {
1013
- try {
1014
- res.setHeader(
1015
- key,
1016
- key === "set-cookie" ? set_cookie_parser.splitCookiesString(response.headers.get(key)) : value
1017
- );
1018
- } catch (error) {
1019
- res.getHeaderNames().forEach((name) => res.removeHeader(name));
1020
- res.writeHead(500).end(String(error));
1021
- return;
1022
- }
1023
- }
1024
- res.writeHead(response.status);
1025
- if (!response.body) {
1026
- res.end();
1027
- return;
1028
- }
1029
- if (response.body.locked) {
1030
- res.end(
1031
- "Fatal error: Response body is locked. This can happen when the response was already read (for example through 'response.json()' or 'response.text()')."
1032
- );
1033
- return;
1034
- }
1035
- const reader = response.body.getReader();
1036
- if (res.destroyed) {
1037
- reader.cancel();
1038
- return;
1039
- }
1040
- const cancel = (error) => {
1041
- res.off("close", cancel);
1042
- res.off("error", cancel);
1043
- reader.cancel(error).catch(() => {
1044
- });
1045
- if (error) res.destroy(error);
1046
- };
1047
- res.on("close", cancel);
1048
- res.on("error", cancel);
1049
- next();
1050
- async function next() {
1051
- try {
1052
- for (; ; ) {
1053
- const { done, value } = await reader.read();
1054
- if (done) break;
1055
- if (!res.write(value)) {
1056
- res.once("drain", next);
1057
- return;
1058
- }
1059
- }
1060
- res.end();
1061
- } catch (error) {
1062
- cancel(error instanceof Error ? error : new Error(String(error)));
1063
- }
1064
- }
1065
- }
1066
651
 
1067
- // src/adapter/node.ts
1068
- function toNodeHandler(handler) {
1069
- return async (req, res) => {
1070
- const protocol = req.connection?.encrypted ? "https" : "http";
1071
- const base = `${protocol}://${req.headers[":authority"] || req.headers.host}`;
1072
- const response = await handler(getRequest({ base, request: req }));
1073
- setResponse(res, response);
1074
- };
1075
- }
1076
- // Annotate the CommonJS export names for ESM import in node:
1077
- 0 && (module.exports = {
1078
- APIError,
1079
- createEndpoint,
1080
- createEndpointCreator,
1081
- createMiddleware,
1082
- createMiddlewareCreator,
1083
- createRouter,
1084
- getBody,
1085
- getCookie,
1086
- getRequest,
1087
- getSignedCookie,
1088
- parse,
1089
- parseSigned,
1090
- serialize,
1091
- serializeSigned,
1092
- setCookie,
1093
- setResponse,
1094
- setSignedCookie,
1095
- shouldSerialize,
1096
- statusCode,
1097
- toNodeHandler
1098
- });
1099
- //# sourceMappingURL=index.cjs.map
652
+ exports.createEndpoint = createEndpoint;
653
+ exports.createGetHeader = createGetHeader;
654
+ exports.createJSON = createJSON;
655
+ exports.createMiddleware = createMiddleware;
656
+ exports.createRouter = createRouter;
657
+ exports.createSetHeader = createSetHeader;
658
+ exports.fromError = fromError;
659
+ exports.getCookie = getCookie;
660
+ exports.getSignedCookie = getSignedCookie;
661
+ exports.parse = parse;
662
+ exports.parseSigned = parseSigned;
663
+ exports.runValidation = runValidation;
664
+ exports.serialize = serialize;
665
+ exports.serializeSigned = serializeSigned;
666
+ exports.setCookie = setCookie;
667
+ exports.setSignedCookie = setSignedCookie;