better-call 0.2.13-beta.8 → 0.2.14-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,187 +1,124 @@
1
- 'use strict';
2
-
3
- const crypto = require('uncrypto');
4
- const zodToOpenapi = require('@asteasolutions/zod-to-openapi');
5
- const zod = require('zod');
6
- const rou3 = require('rou3');
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 __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
31
 
8
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
32
+ // src/index.ts
33
+ var src_exports = {};
34
+ __export(src_exports, {
35
+ APIError: () => APIError,
36
+ createEndpoint: () => createEndpoint,
37
+ createEndpointCreator: () => createEndpointCreator,
38
+ createMiddleware: () => createMiddleware,
39
+ createMiddlewareCreator: () => createMiddlewareCreator,
40
+ createRouter: () => createRouter,
41
+ getBody: () => getBody,
42
+ getCookie: () => getCookie,
43
+ getRequest: () => getRequest,
44
+ getSignedCookie: () => getSignedCookie,
45
+ parse: () => parse,
46
+ parseSigned: () => parseSigned,
47
+ serialize: () => serialize,
48
+ serializeSigned: () => serializeSigned,
49
+ setCookie: () => setCookie,
50
+ setResponse: () => setResponse,
51
+ setSignedCookie: () => setSignedCookie,
52
+ shouldSerialize: () => shouldSerialize,
53
+ statusCode: () => statusCode,
54
+ toNodeHandler: () => toNodeHandler
55
+ });
56
+ module.exports = __toCommonJS(src_exports);
9
57
 
10
- const crypto__default = /*#__PURE__*/_interopDefaultCompat(crypto);
58
+ // src/endpoint.ts
59
+ var import_zod = require("zod");
11
60
 
12
- function runValidation(options, context) {
13
- let request = {
14
- body: void 0,
15
- query: void 0
16
- };
17
- if (options.body) {
18
- const result = options.body.safeParse(context.body);
19
- if (result.error) {
20
- return {
21
- data: null,
22
- error: fromError(result.error)
23
- };
24
- }
25
- request.body = result.data;
26
- }
27
- if (options.query) {
28
- const result = options.query.safeParse(context.query);
29
- if (result.error) {
30
- return {
31
- data: null,
32
- error: fromError(result.error)
33
- };
34
- }
35
- request.query = result.data;
36
- }
37
- if (options.requireHeaders && !(context.headers instanceof Headers)) {
38
- return {
39
- data: null,
40
- error: { message: "Validation Error: Headers are required" }
41
- };
42
- }
43
- if (options.requireRequest && !context.request) {
44
- return {
45
- data: null,
46
- error: { message: "Validation Error: Request is required" }
47
- };
48
- }
49
- return {
50
- data: request,
51
- error: null
52
- };
53
- }
54
- function fromError(error) {
55
- const errorMessages = [];
56
- for (const issue of error.issues) {
57
- const path = issue.path.join(".");
58
- const message = issue.message;
59
- if (path) {
60
- errorMessages.push(`${message} at "${path}"`);
61
- } else {
62
- errorMessages.push(message);
61
+ // src/error.ts
62
+ var APIError = class extends Error {
63
+ constructor(status, body, headers) {
64
+ super(`API Error: ${status} ${body?.message ?? ""}`, {
65
+ cause: body
66
+ });
67
+ __publicField(this, "status");
68
+ __publicField(this, "headers");
69
+ __publicField(this, "body");
70
+ this.status = status;
71
+ this.body = body ?? {};
72
+ this.stack = "";
73
+ this.headers = headers ?? new Headers();
74
+ if (!this.headers.has("Content-Type")) {
75
+ this.headers.set("Content-Type", "application/json");
63
76
  }
77
+ this.name = "BetterCallAPIError";
64
78
  }
65
- return {
66
- message: `Validation error: ${errorMessages.join(", ")}`
67
- };
68
- }
79
+ };
69
80
 
70
- function createSetHeader(headers) {
71
- return (key, value) => {
72
- headers.set(key, value);
73
- };
74
- }
75
- function createGetHeader(headers) {
76
- return (key) => {
77
- return headers.get(key);
81
+ // src/helper.ts
82
+ var json = (body, option) => {
83
+ return {
84
+ response: {
85
+ body: option?.body ?? body,
86
+ status: option?.status ?? 200,
87
+ statusText: option?.statusText ?? "OK",
88
+ headers: option?.headers
89
+ },
90
+ body,
91
+ _flag: "json"
78
92
  };
79
- }
80
-
81
- const _statusCode = {
82
- OK: 200,
83
- CREATED: 201,
84
- ACCEPTED: 202,
85
- NO_CONTENT: 204,
86
- MULTIPLE_CHOICES: 300,
87
- MOVED_PERMANENTLY: 301,
88
- FOUND: 302,
89
- SEE_OTHER: 303,
90
- NOT_MODIFIED: 304,
91
- TEMPORARY_REDIRECT: 307,
92
- BAD_REQUEST: 400,
93
- UNAUTHORIZED: 401,
94
- PAYMENT_REQUIRED: 402,
95
- FORBIDDEN: 403,
96
- NOT_FOUND: 404,
97
- METHOD_NOT_ALLOWED: 405,
98
- NOT_ACCEPTABLE: 406,
99
- PROXY_AUTHENTICATION_REQUIRED: 407,
100
- REQUEST_TIMEOUT: 408,
101
- CONFLICT: 409,
102
- GONE: 410,
103
- LENGTH_REQUIRED: 411,
104
- PRECONDITION_FAILED: 412,
105
- PAYLOAD_TOO_LARGE: 413,
106
- URI_TOO_LONG: 414,
107
- UNSUPPORTED_MEDIA_TYPE: 415,
108
- RANGE_NOT_SATISFIABLE: 416,
109
- EXPECTATION_FAILED: 417,
110
- "I'M_A_TEAPOT": 418,
111
- MISDIRECTED_REQUEST: 421,
112
- UNPROCESSABLE_ENTITY: 422,
113
- LOCKED: 423,
114
- FAILED_DEPENDENCY: 424,
115
- TOO_EARLY: 425,
116
- UPGRADE_REQUIRED: 426,
117
- PRECONDITION_REQUIRED: 428,
118
- TOO_MANY_REQUESTS: 429,
119
- REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
120
- UNAVAILABLE_FOR_LEGAL_REASONS: 451,
121
- INTERNAL_SERVER_ERROR: 500,
122
- NOT_IMPLEMENTED: 501,
123
- BAD_GATEWAY: 502,
124
- SERVICE_UNAVAILABLE: 503,
125
- GATEWAY_TIMEOUT: 504,
126
- HTTP_VERSION_NOT_SUPPORTED: 505,
127
- VARIANT_ALSO_NEGOTIATES: 506,
128
- INSUFFICIENT_STORAGE: 507,
129
- LOOP_DETECTED: 508,
130
- NOT_EXTENDED: 510,
131
- NETWORK_AUTHENTICATION_REQUIRED: 511
132
93
  };
133
- class APIError extends Error {
134
- constructor(status = "INTERNAL_SERVER_ERROR", body = void 0, headers = {}, statusCode = _statusCode[status]) {
135
- super(body?.message || status);
136
- this.status = status;
137
- this.body = body;
138
- this.headers = headers;
139
- this.statusCode = statusCode;
140
- this.name = "APIError";
141
- this.status = status;
142
- this.headers = headers;
143
- this.statusCode = statusCode;
144
- this.stack = "";
145
- }
146
- }
147
94
 
148
- const algorithm = { name: "HMAC", hash: "SHA-256" };
149
- const getCryptoKey = async (secret) => {
95
+ // src/cookie.ts
96
+ var import_uncrypto = require("uncrypto");
97
+ var algorithm = { name: "HMAC", hash: "SHA-256" };
98
+ var getCryptoKey = async (secret) => {
150
99
  const secretBuf = typeof secret === "string" ? new TextEncoder().encode(secret) : secret;
151
- return await crypto__default.subtle.importKey("raw", secretBuf, algorithm, false, [
152
- "sign",
153
- "verify"
154
- ]);
100
+ return await import_uncrypto.subtle.importKey("raw", secretBuf, algorithm, false, ["sign", "verify"]);
155
101
  };
156
- const makeSignature = async (value, secret) => {
102
+ var makeSignature = async (value, secret) => {
157
103
  const key = await getCryptoKey(secret);
158
- const signature = await crypto__default.subtle.sign(
159
- algorithm.name,
160
- key,
161
- new TextEncoder().encode(value)
162
- );
104
+ const signature = await import_uncrypto.subtle.sign(algorithm.name, key, new TextEncoder().encode(value));
163
105
  return btoa(String.fromCharCode(...new Uint8Array(signature)));
164
106
  };
165
- const verifySignature = async (base64Signature, value, secret) => {
107
+ var verifySignature = async (base64Signature, value, secret) => {
166
108
  try {
167
109
  const signatureBinStr = atob(base64Signature);
168
110
  const signature = new Uint8Array(signatureBinStr.length);
169
111
  for (let i = 0, len = signatureBinStr.length; i < len; i++) {
170
112
  signature[i] = signatureBinStr.charCodeAt(i);
171
113
  }
172
- return await crypto__default.subtle.verify(
173
- algorithm,
174
- secret,
175
- signature,
176
- new TextEncoder().encode(value)
177
- );
114
+ return await import_uncrypto.subtle.verify(algorithm, secret, signature, new TextEncoder().encode(value));
178
115
  } catch (e) {
179
116
  return false;
180
117
  }
181
118
  };
182
- const validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
183
- const validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
184
- const parse = (cookie, name) => {
119
+ var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
120
+ var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
121
+ var parse = (cookie, name) => {
185
122
  const pairs = cookie.trim().split(";");
186
123
  return pairs.reduce((parsedCookie, pairStr) => {
187
124
  pairStr = pairStr.trim();
@@ -203,7 +140,7 @@ const parse = (cookie, name) => {
203
140
  return parsedCookie;
204
141
  }, {});
205
142
  };
206
- const parseSigned = async (cookie, secret, name) => {
143
+ var parseSigned = async (cookie, secret, name) => {
207
144
  const parsedCookie = {};
208
145
  const secretKey = await getCryptoKey(secret);
209
146
  for (const [key, value] of Object.entries(parse(cookie, name))) {
@@ -221,7 +158,7 @@ const parseSigned = async (cookie, secret, name) => {
221
158
  }
222
159
  return parsedCookie;
223
160
  };
224
- const _serialize = (name, value, opt = {}) => {
161
+ var _serialize = (name, value, opt = {}) => {
225
162
  let cookie = `${name}=${value}`;
226
163
  if (name.startsWith("__Secure-") && !opt.secure) {
227
164
  opt.secure = true;
@@ -276,18 +213,19 @@ const _serialize = (name, value, opt = {}) => {
276
213
  }
277
214
  return cookie;
278
215
  };
279
- const serialize = (name, value, opt) => {
216
+ var serialize = (name, value, opt) => {
280
217
  value = encodeURIComponent(value);
281
218
  return _serialize(name, value, opt);
282
219
  };
283
- const serializeSigned = async (name, value, secret, opt = {}) => {
220
+ var serializeSigned = async (name, value, secret, opt = {}) => {
284
221
  const signature = await makeSignature(value, secret);
285
222
  value = `${value}.${signature}`;
286
223
  value = encodeURIComponent(value);
287
224
  return _serialize(name, value, opt);
288
225
  };
289
226
 
290
- const getCookie = (cookie, key, prefix) => {
227
+ // src/cookie-utils.ts
228
+ var getCookie = (cookie, key, prefix) => {
291
229
  if (!cookie) {
292
230
  return void 0;
293
231
  }
@@ -304,23 +242,17 @@ const getCookie = (cookie, key, prefix) => {
304
242
  const obj = parse(cookie, finalKey);
305
243
  return obj[finalKey];
306
244
  };
307
- const setCookie = (header, name, value, opt) => {
245
+ var setCookie = (header, name, value, opt) => {
308
246
  const existingCookies = header.get("Set-Cookie");
309
247
  if (existingCookies) {
310
248
  const cookies = existingCookies.split(", ");
311
- const updatedCookies = cookies.filter(
312
- (cookie2) => !cookie2.startsWith(`${name}=`)
313
- );
249
+ const updatedCookies = cookies.filter((cookie2) => !cookie2.startsWith(`${name}=`));
314
250
  header.delete("Set-Cookie");
315
251
  updatedCookies.forEach((cookie2) => header.append("Set-Cookie", cookie2));
316
252
  }
317
253
  let cookie;
318
254
  if (opt?.prefix === "secure") {
319
- cookie = serialize("__Secure-" + name, value, {
320
- path: "/",
321
- ...opt,
322
- secure: true
323
- });
255
+ cookie = serialize("__Secure-" + name, value, { path: "/", ...opt, secure: true });
324
256
  } else if (opt?.prefix === "host") {
325
257
  cookie = serialize("__Host-" + name, value, {
326
258
  ...opt,
@@ -333,7 +265,7 @@ const setCookie = (header, name, value, opt) => {
333
265
  }
334
266
  header.append("Set-Cookie", cookie);
335
267
  };
336
- const setSignedCookie = async (header, name, value, secret, opt) => {
268
+ var setSignedCookie = async (header, name, value, secret, opt) => {
337
269
  let cookie;
338
270
  if (opt?.prefix === "secure") {
339
271
  cookie = await serializeSigned("__Secure-" + name, value, secret, {
@@ -353,7 +285,7 @@ const setSignedCookie = async (header, name, value, secret, opt) => {
353
285
  }
354
286
  header.append("Set-Cookie", cookie);
355
287
  };
356
- const getSignedCookie = async (header, secret, key, prefix) => {
288
+ var getSignedCookie = async (header, secret, key, prefix) => {
357
289
  const cookie = header.get("cookie");
358
290
  if (!cookie) {
359
291
  return void 0;
@@ -370,204 +302,163 @@ const getSignedCookie = async (header, secret, key, prefix) => {
370
302
  return obj[finalKey];
371
303
  };
372
304
 
373
- function paramToZod(path) {
374
- const parts = path.split("/");
375
- const params = parts.filter((part) => part.startsWith(":"));
376
- const zod$1 = zod.z.object({});
377
- for (const param of params) {
378
- zod$1.merge(zod.z.object({ [param.slice(1)]: zod.z.string() }));
379
- }
380
- return zod$1;
381
- }
382
-
383
- zodToOpenapi.extendZodWithOpenApi(zod.z);
384
- const createResponse = (handlerResponse, response) => {
385
- if (handlerResponse instanceof Response) {
386
- response.headers.forEach((value, key) => {
387
- handlerResponse.headers.set(key, value);
388
- });
389
- return handlerResponse;
390
- } else if (handlerResponse?._flag === "json") {
391
- const responseObj = new Response(
392
- JSON.stringify(
393
- handlerResponse.routerResponse?.body || handlerResponse.body
394
- ),
305
+ // src/endpoint.ts
306
+ function createEndpointCreator(opts) {
307
+ return (path, options, handler) => {
308
+ return createEndpoint(
309
+ path,
395
310
  {
396
- status: handlerResponse.routerResponse?.status || 200,
397
- headers: handlerResponse.routerResponse?.headers
398
- }
399
- );
400
- response.headers.forEach((value, key) => {
401
- responseObj.headers.set(key, value);
402
- });
403
- return responseObj;
404
- } else {
405
- const responseObj = new Response(
406
- handlerResponse ? JSON.stringify(handlerResponse) : void 0
407
- );
408
- response.headers.forEach((value, key) => {
409
- responseObj.headers.set(key, value);
410
- });
411
- return responseObj;
412
- }
413
- };
414
- const runMiddleware = async (options, context) => {
415
- let finalContext = {};
416
- for (const middleware of options.use || []) {
417
- const result = await middleware(context);
418
- if (result?.context && result._flag === "context") {
419
- context = { ...context, ...result.context };
420
- } else {
421
- finalContext = { ...result, ...finalContext };
422
- context.context = finalContext;
423
- }
424
- }
425
- return finalContext;
426
- };
427
- const createEndpoint = (path, options, handler) => {
428
- const internalHandler = async (...inputCtx) => {
429
- let response = new Response();
430
- const { asResponse, ...ctx } = inputCtx[0] || {};
431
- const { data, error } = runValidation(options, ctx);
432
- if (error) {
433
- throw new APIError("BAD_REQUEST", {
434
- message: error.message
435
- });
436
- }
437
- const context = {
438
- json: (json, routerResponse) => {
439
- if (!asResponse) {
440
- return json;
441
- }
442
- return {
443
- body: json,
444
- routerResponse,
445
- _flag: "json"
446
- };
311
+ ...options,
312
+ use: [...options?.use || [], ...opts?.use || []]
447
313
  },
448
- body: "body" in data ? data.body : void 0,
449
- path,
450
- method: "method" in ctx ? ctx.method : void 0,
451
- query: "query" in data ? data.query : void 0,
452
- params: "params" in ctx ? ctx.params : void 0,
453
- headers: "headers" in ctx ? ctx.headers : void 0,
454
- request: "request" in ctx ? ctx.request : void 0,
455
- setHeader: createSetHeader(response.headers),
456
- getHeader: (key) => {
457
- const requestHeaders = "headers" in ctx && ctx.headers instanceof Headers ? ctx.headers : "request" in ctx && ctx.request instanceof Request ? ctx.request.headers : null;
458
- if (!requestHeaders)
459
- return null;
460
- return requestHeaders.get(key);
314
+ handler
315
+ );
316
+ };
317
+ }
318
+ function createEndpoint(path, options, handler) {
319
+ let responseHeader = new Headers();
320
+ const handle = async (...ctx) => {
321
+ let internalCtx = {
322
+ setHeader(key, value) {
323
+ responseHeader.set(key, value);
461
324
  },
462
- setCookie: (name, value, options2) => {
463
- setCookie(response.headers, name, value, options2);
325
+ setCookie(key, value, options2) {
326
+ setCookie(responseHeader, key, value, options2);
464
327
  },
465
328
  getCookie(key, prefix) {
466
- const headers = context.headers?.get("cookie");
467
- if (!headers)
468
- return void 0;
469
- return getCookie(headers, key, prefix);
329
+ const header = ctx[0]?.headers;
330
+ const cookieH = header?.get("cookie");
331
+ const cookie = getCookie(cookieH || "", key, prefix);
332
+ return cookie;
470
333
  },
471
- setSignedCookie(key, value, secret, options2) {
472
- return setSignedCookie(response.headers, key, value, secret, options2);
334
+ getSignedCookie(key, secret, prefix) {
335
+ const header = ctx[0]?.headers;
336
+ if (!header) {
337
+ throw new TypeError("Headers are required");
338
+ }
339
+ const cookie = getSignedCookie(header, secret, key, prefix);
340
+ return cookie;
473
341
  },
474
- async getSignedCookie(key, secret, prefix) {
475
- const headers = context.headers;
476
- if (!headers)
477
- return void 0;
478
- return getSignedCookie(headers, secret, key, prefix);
342
+ async setSignedCookie(key, value, secret, options2) {
343
+ await setSignedCookie(responseHeader, key, value, secret, options2);
479
344
  },
480
- redirect: (url) => {
481
- const apiError = new APIError("FOUND", void 0, {
482
- Location: url,
483
- ...response.headers
484
- });
485
- return apiError;
345
+ redirect(url) {
346
+ responseHeader.set("Location", url);
347
+ return new APIError("FOUND");
486
348
  },
487
- context: {}
349
+ json,
350
+ context: ctx[0]?.context || {},
351
+ _flag: ctx[0]?.asResponse ? "router" : ctx[0]?._flag,
352
+ responseHeader,
353
+ path,
354
+ ...ctx[0] || {}
488
355
  };
489
- const finalContext = await runMiddleware(options, context);
490
- context.context = finalContext;
491
- const handlerResponse = await handler(context).catch((e) => {
492
- if (e instanceof APIError && asResponse) {
493
- const headers = response.headers;
494
- for (const [key, value] of Object.entries(e.headers)) {
495
- headers.set(key, value);
356
+ if (options.use?.length) {
357
+ let middlewareContexts = {};
358
+ let middlewareBody = {};
359
+ for (const middleware of options.use) {
360
+ if (typeof middleware !== "function") {
361
+ console.warn("Middleware is not a function", {
362
+ middleware
363
+ });
364
+ continue;
365
+ }
366
+ const res = await middleware(internalCtx);
367
+ if (res) {
368
+ const body = res.options?.body ? res.options.body.parse(internalCtx.body) : void 0;
369
+ middlewareContexts = {
370
+ ...middlewareContexts,
371
+ ...res
372
+ };
373
+ middlewareBody = {
374
+ ...middlewareBody,
375
+ ...body
376
+ };
496
377
  }
497
- return new Response(null, {
498
- status: e.statusCode,
499
- headers
500
- });
501
378
  }
502
- throw e;
503
- });
504
- response = createResponse(handlerResponse, response);
505
- const res = asResponse ? response : handlerResponse;
506
- return res;
507
- };
508
- internalHandler.path = path;
509
- internalHandler.options = options;
510
- const registry = new zodToOpenapi.OpenAPIRegistry();
511
- registry.registerPath({
512
- path,
513
- method: Array.isArray(options.method) ? options.method[0].toLowerCase() : options.method.toLowerCase(),
514
- request: {
515
- ...options.body ? {
379
+ internalCtx = {
380
+ ...internalCtx,
516
381
  body: {
517
- content: {
518
- "application/json": {
519
- schema: options.body
520
- }
521
- }
522
- }
523
- } : {},
524
- ...options.query ? {
525
- query: options.query
526
- } : {},
527
- params: paramToZod(path)
528
- },
529
- responses: {
530
- 200: {
531
- description: "Successful response",
532
- content: {
533
- "application/json": {
534
- schema: zod.z.record(zod.z.unknown())
535
- }
382
+ ...middlewareBody,
383
+ ...internalCtx.body
384
+ },
385
+ context: {
386
+ ...internalCtx.context || {},
387
+ ...middlewareContexts
536
388
  }
537
- },
538
- 400: {
539
- description: "Bad request",
540
- content: {
541
- "application/json": {
542
- schema: zod.z.object({
543
- message: zod.z.string()
544
- })
545
- }
389
+ };
390
+ }
391
+ try {
392
+ const body = options.body ? options.body.parse(internalCtx.body) : internalCtx.body;
393
+ internalCtx = {
394
+ ...internalCtx,
395
+ body: body ? {
396
+ ...body,
397
+ ...internalCtx.body
398
+ } : internalCtx.body
399
+ };
400
+ internalCtx.query = options.query ? options.query.parse(internalCtx.query) : internalCtx.query;
401
+ } catch (e) {
402
+ if (e instanceof import_zod.ZodError) {
403
+ throw new APIError("BAD_REQUEST", {
404
+ message: e.message,
405
+ details: e.errors
406
+ });
407
+ }
408
+ throw e;
409
+ }
410
+ if (options.requireHeaders && !internalCtx.headers) {
411
+ throw new APIError("BAD_REQUEST", {
412
+ message: "Headers are required"
413
+ });
414
+ }
415
+ if (options.requireRequest && !internalCtx.request) {
416
+ throw new APIError("BAD_REQUEST", {
417
+ message: "Request is required"
418
+ });
419
+ }
420
+ try {
421
+ let res = await handler(internalCtx);
422
+ let actualResponse = res;
423
+ if (res && typeof res === "object" && "_flag" in res) {
424
+ if (res._flag === "json" && internalCtx._flag === "router") {
425
+ const h = res.response.headers;
426
+ Object.keys(h || {}).forEach((key) => {
427
+ responseHeader.set(key, h[key]);
428
+ });
429
+ responseHeader.set("Content-Type", "application/json");
430
+ actualResponse = new Response(JSON.stringify(res.response.body), {
431
+ status: res.response.status ?? 200,
432
+ statusText: res.response.statusText,
433
+ headers: responseHeader
434
+ });
435
+ } else {
436
+ actualResponse = res.body;
546
437
  }
547
- },
548
- ...options.openAPI?.responses
438
+ }
439
+ responseHeader = new Headers();
440
+ return actualResponse;
441
+ } catch (e) {
442
+ if (e instanceof APIError) {
443
+ responseHeader.set("Content-Type", "application/json");
444
+ e.headers = responseHeader;
445
+ responseHeader = new Headers();
446
+ throw e;
447
+ }
448
+ throw e;
549
449
  }
550
- });
551
- internalHandler.openAPI = {
552
- definitions: registry.definitions
553
- };
554
- return internalHandler;
555
- };
556
- function createEndpointCreator(opts) {
557
- return (path, options, handler) => {
558
- const res = createEndpoint(
559
- path,
560
- {
561
- ...options,
562
- use: [...options?.use || [], ...opts?.use || []]
563
- },
564
- handler
565
- );
566
- return res;
567
450
  };
451
+ handle.path = path;
452
+ handle.options = options;
453
+ handle.method = options.method;
454
+ handle.headers = responseHeader;
455
+ return handle;
568
456
  }
569
- createEndpoint.creator = createEndpointCreator;
570
457
 
458
+ // src/router.ts
459
+ var import_rou3 = require("rou3");
460
+
461
+ // src/utils.ts
571
462
  async function getBody(request) {
572
463
  const contentType = request.headers.get("content-type") || "";
573
464
  if (!request.body) {
@@ -607,22 +498,79 @@ async function getBody(request) {
607
498
  }
608
499
  return await request.text();
609
500
  }
501
+ function shouldSerialize(body) {
502
+ return typeof body === "object" && body !== null && !(body instanceof Blob) && !(body instanceof FormData);
503
+ }
504
+ var statusCode = {
505
+ OK: 200,
506
+ CREATED: 201,
507
+ ACCEPTED: 202,
508
+ NO_CONTENT: 204,
509
+ MULTIPLE_CHOICES: 300,
510
+ MOVED_PERMANENTLY: 301,
511
+ FOUND: 302,
512
+ SEE_OTHER: 303,
513
+ NOT_MODIFIED: 304,
514
+ TEMPORARY_REDIRECT: 307,
515
+ BAD_REQUEST: 400,
516
+ UNAUTHORIZED: 401,
517
+ PAYMENT_REQUIRED: 402,
518
+ FORBIDDEN: 403,
519
+ NOT_FOUND: 404,
520
+ METHOD_NOT_ALLOWED: 405,
521
+ NOT_ACCEPTABLE: 406,
522
+ PROXY_AUTHENTICATION_REQUIRED: 407,
523
+ REQUEST_TIMEOUT: 408,
524
+ CONFLICT: 409,
525
+ GONE: 410,
526
+ LENGTH_REQUIRED: 411,
527
+ PRECONDITION_FAILED: 412,
528
+ PAYLOAD_TOO_LARGE: 413,
529
+ URI_TOO_LONG: 414,
530
+ UNSUPPORTED_MEDIA_TYPE: 415,
531
+ RANGE_NOT_SATISFIABLE: 416,
532
+ EXPECTATION_FAILED: 417,
533
+ "I'M_A_TEAPOT": 418,
534
+ MISDIRECTED_REQUEST: 421,
535
+ UNPROCESSABLE_ENTITY: 422,
536
+ LOCKED: 423,
537
+ FAILED_DEPENDENCY: 424,
538
+ TOO_EARLY: 425,
539
+ UPGRADE_REQUIRED: 426,
540
+ PRECONDITION_REQUIRED: 428,
541
+ TOO_MANY_REQUESTS: 429,
542
+ REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
543
+ UNAVAILABLE_FOR_LEGAL_REASONS: 451,
544
+ INTERNAL_SERVER_ERROR: 500,
545
+ NOT_IMPLEMENTED: 501,
546
+ BAD_GATEWAY: 502,
547
+ SERVICE_UNAVAILABLE: 503,
548
+ GATEWAY_TIMEOUT: 504,
549
+ HTTP_VERSION_NOT_SUPPORTED: 505,
550
+ VARIANT_ALSO_NEGOTIATES: 506,
551
+ INSUFFICIENT_STORAGE: 507,
552
+ LOOP_DETECTED: 508,
553
+ NOT_EXTENDED: 510,
554
+ NETWORK_AUTHENTICATION_REQUIRED: 511
555
+ };
610
556
 
611
- const createRouter = (endpoints, config) => {
557
+ // src/router.ts
558
+ var createRouter = (endpoints, config) => {
612
559
  const _endpoints = Object.values(endpoints);
613
- const router = rou3.createRouter();
560
+ const router = (0, import_rou3.createRouter)();
614
561
  for (const endpoint of _endpoints) {
562
+ if (endpoint.options.metadata?.SERVER_ONLY) continue;
615
563
  if (Array.isArray(endpoint.options?.method)) {
616
564
  for (const method of endpoint.options.method) {
617
- rou3.addRoute(router, method, endpoint.path, endpoint);
565
+ (0, import_rou3.addRoute)(router, method, endpoint.path, endpoint);
618
566
  }
619
567
  } else {
620
- rou3.addRoute(router, endpoint.options.method, endpoint.path, endpoint);
568
+ (0, import_rou3.addRoute)(router, endpoint.options.method, endpoint.path, endpoint);
621
569
  }
622
570
  }
623
- const middlewareRouter = rou3.createRouter();
571
+ const middlewareRouter = (0, import_rou3.createRouter)();
624
572
  for (const route of config?.routerMiddleware || []) {
625
- rou3.addRoute(middlewareRouter, "*", route.path, route.middleware);
573
+ (0, import_rou3.addRoute)(middlewareRouter, "*", route.path, route.middleware);
626
574
  }
627
575
  const handler = async (request) => {
628
576
  const url = new URL(request.url);
@@ -641,12 +589,12 @@ const createRouter = (endpoints, config) => {
641
589
  });
642
590
  }
643
591
  const method = request.method;
644
- const route = rou3.findRoute(router, method, path);
592
+ const route = (0, import_rou3.findRoute)(router, method, path);
645
593
  const handler2 = route?.data;
646
594
  const body = await getBody(request);
647
595
  const headers = request.headers;
648
596
  const query = Object.fromEntries(url.searchParams);
649
- const routerMiddleware = rou3.findAllRoutes(middlewareRouter, "*", path);
597
+ const routerMiddleware = (0, import_rou3.findAllRoutes)(middlewareRouter, "*", path);
650
598
  if (!handler2) {
651
599
  return new Response(null, {
652
600
  status: 404,
@@ -694,17 +642,18 @@ const createRouter = (endpoints, config) => {
694
642
  request,
695
643
  body,
696
644
  query,
645
+ _flag: "router",
697
646
  context: {
698
647
  ...middlewareContext,
699
648
  ...config?.extraContext
700
- },
701
- asResponse: true
649
+ }
702
650
  });
703
651
  if (handlerRes instanceof Response) {
704
652
  return handlerRes;
705
653
  }
706
- return new Response(handlerRes ? JSON.stringify(handlerRes) : void 0, {
707
- status: 200
654
+ const resBody = shouldSerialize(handlerRes) ? JSON.stringify(handlerRes) : handlerRes;
655
+ return new Response(resBody, {
656
+ headers: handler2.headers
708
657
  });
709
658
  } catch (e) {
710
659
  if (config?.onError) {
@@ -715,7 +664,8 @@ const createRouter = (endpoints, config) => {
715
664
  }
716
665
  if (e instanceof APIError) {
717
666
  return new Response(e.body ? JSON.stringify(e.body) : null, {
718
- status: e.statusCode,
667
+ status: statusCode[e.status],
668
+ statusText: e.status,
719
669
  headers: e.headers
720
670
  });
721
671
  }
@@ -729,11 +679,24 @@ const createRouter = (endpoints, config) => {
729
679
  }
730
680
  };
731
681
  return {
732
- handler,
682
+ handler: async (request) => {
683
+ const onReq = await config?.onRequest?.(request);
684
+ if (onReq instanceof Response) {
685
+ return onReq;
686
+ }
687
+ const req = onReq instanceof Request ? onReq : request;
688
+ const res = await handler(req);
689
+ const onRes = await config?.onResponse?.(res);
690
+ if (onRes instanceof Response) {
691
+ return onRes;
692
+ }
693
+ return res;
694
+ },
733
695
  endpoints
734
696
  };
735
697
  };
736
698
 
699
+ // src/middleware.ts
737
700
  function createMiddleware(optionsOrHandler, handler) {
738
701
  if (typeof optionsOrHandler === "function") {
739
702
  return createEndpoint(
@@ -757,34 +720,202 @@ function createMiddleware(optionsOrHandler, handler) {
757
720
  );
758
721
  return endpoint;
759
722
  }
760
- function createMiddlewareCreator(opts) {
761
- return (handler) => {
762
- const res = createMiddleware(
723
+ var createMiddlewareCreator = (opts) => {
724
+ function fn(optionsOrHandler, handler) {
725
+ if (typeof optionsOrHandler === "function") {
726
+ return createEndpoint(
727
+ "*",
728
+ {
729
+ method: "*"
730
+ },
731
+ optionsOrHandler
732
+ );
733
+ }
734
+ if (!handler) {
735
+ throw new Error("Middleware handler is required");
736
+ }
737
+ const endpoint = createEndpoint(
738
+ "*",
763
739
  {
764
- method: "*",
765
- use: opts.use
740
+ ...optionsOrHandler,
741
+ method: "*"
766
742
  },
767
743
  handler
768
744
  );
769
- return res;
745
+ return endpoint;
746
+ }
747
+ return fn;
748
+ };
749
+
750
+ // src/types.ts
751
+ var import_zod2 = require("zod");
752
+
753
+ // src/adapter/node.ts
754
+ var import_node_http2 = require("http");
755
+
756
+ // src/adapter/request.ts
757
+ var import_node_http = require("http");
758
+ var set_cookie_parser = __toESM(require("set-cookie-parser"), 1);
759
+ function get_raw_body(req, body_size_limit) {
760
+ const h = req.headers;
761
+ if (!h["content-type"]) return null;
762
+ const content_length = Number(h["content-length"]);
763
+ if (req.httpVersionMajor === 1 && isNaN(content_length) && h["transfer-encoding"] == null || content_length === 0) {
764
+ return null;
765
+ }
766
+ let length = content_length;
767
+ if (body_size_limit) {
768
+ if (!length) {
769
+ length = body_size_limit;
770
+ } else if (length > body_size_limit) {
771
+ throw Error(
772
+ `Received content-length of ${length}, but only accept up to ${body_size_limit} bytes.`
773
+ );
774
+ }
775
+ }
776
+ if (req.destroyed) {
777
+ const readable = new ReadableStream();
778
+ readable.cancel();
779
+ return readable;
780
+ }
781
+ let size = 0;
782
+ let cancelled = false;
783
+ return new ReadableStream({
784
+ start(controller) {
785
+ req.on("error", (error) => {
786
+ cancelled = true;
787
+ controller.error(error);
788
+ });
789
+ req.on("end", () => {
790
+ if (cancelled) return;
791
+ controller.close();
792
+ });
793
+ req.on("data", (chunk) => {
794
+ if (cancelled) return;
795
+ size += chunk.length;
796
+ if (size > length) {
797
+ cancelled = true;
798
+ controller.error(
799
+ new Error(
800
+ `request body size exceeded ${content_length ? "'content-length'" : "BODY_SIZE_LIMIT"} of ${length}`
801
+ )
802
+ );
803
+ return;
804
+ }
805
+ controller.enqueue(chunk);
806
+ if (controller.desiredSize === null || controller.desiredSize <= 0) {
807
+ req.pause();
808
+ }
809
+ });
810
+ },
811
+ pull() {
812
+ req.resume();
813
+ },
814
+ cancel(reason) {
815
+ cancelled = true;
816
+ req.destroy(reason);
817
+ }
818
+ });
819
+ }
820
+ function getRequest({
821
+ request,
822
+ base,
823
+ bodySizeLimit
824
+ }) {
825
+ return new Request(base + request.url, {
826
+ // @ts-expect-error
827
+ duplex: "half",
828
+ method: request.method,
829
+ body: get_raw_body(request, bodySizeLimit),
830
+ headers: request.headers
831
+ });
832
+ }
833
+ async function setResponse(res, response) {
834
+ for (const [key, value] of response.headers) {
835
+ try {
836
+ res.setHeader(
837
+ key,
838
+ key === "set-cookie" ? set_cookie_parser.splitCookiesString(response.headers.get(key)) : value
839
+ );
840
+ } catch (error) {
841
+ res.getHeaderNames().forEach((name) => res.removeHeader(name));
842
+ res.writeHead(500).end(String(error));
843
+ return;
844
+ }
845
+ }
846
+ res.writeHead(response.status);
847
+ if (!response.body) {
848
+ res.end();
849
+ return;
850
+ }
851
+ if (response.body.locked) {
852
+ res.end(
853
+ "Fatal error: Response body is locked. This can happen when the response was already read (for example through 'response.json()' or 'response.text()')."
854
+ );
855
+ return;
856
+ }
857
+ const reader = response.body.getReader();
858
+ if (res.destroyed) {
859
+ reader.cancel();
860
+ return;
861
+ }
862
+ const cancel = (error) => {
863
+ res.off("close", cancel);
864
+ res.off("error", cancel);
865
+ reader.cancel(error).catch(() => {
866
+ });
867
+ if (error) res.destroy(error);
770
868
  };
869
+ res.on("close", cancel);
870
+ res.on("error", cancel);
871
+ next();
872
+ async function next() {
873
+ try {
874
+ for (; ; ) {
875
+ const { done, value } = await reader.read();
876
+ if (done) break;
877
+ if (!res.write(value)) {
878
+ res.once("drain", next);
879
+ return;
880
+ }
881
+ }
882
+ res.end();
883
+ } catch (error) {
884
+ cancel(error instanceof Error ? error : new Error(String(error)));
885
+ }
886
+ }
771
887
  }
772
- createMiddleware.creator = createMiddlewareCreator;
773
888
 
774
- exports.APIError = APIError;
775
- exports._statusCode = _statusCode;
776
- exports.createEndpoint = createEndpoint;
777
- exports.createGetHeader = createGetHeader;
778
- exports.createMiddleware = createMiddleware;
779
- exports.createRouter = createRouter;
780
- exports.createSetHeader = createSetHeader;
781
- exports.fromError = fromError;
782
- exports.getCookie = getCookie;
783
- exports.getSignedCookie = getSignedCookie;
784
- exports.parse = parse;
785
- exports.parseSigned = parseSigned;
786
- exports.runValidation = runValidation;
787
- exports.serialize = serialize;
788
- exports.serializeSigned = serializeSigned;
789
- exports.setCookie = setCookie;
790
- exports.setSignedCookie = setSignedCookie;
889
+ // src/adapter/node.ts
890
+ function toNodeHandler(handler) {
891
+ return async (req, res) => {
892
+ const protocol = req.connection?.encrypted ? "https" : "http";
893
+ const base = `${protocol}://${req.headers[":authority"] || req.headers.host}`;
894
+ const response = await handler(getRequest({ base, request: req }));
895
+ setResponse(res, response);
896
+ };
897
+ }
898
+ // Annotate the CommonJS export names for ESM import in node:
899
+ 0 && (module.exports = {
900
+ APIError,
901
+ createEndpoint,
902
+ createEndpointCreator,
903
+ createMiddleware,
904
+ createMiddlewareCreator,
905
+ createRouter,
906
+ getBody,
907
+ getCookie,
908
+ getRequest,
909
+ getSignedCookie,
910
+ parse,
911
+ parseSigned,
912
+ serialize,
913
+ serializeSigned,
914
+ setCookie,
915
+ setResponse,
916
+ setSignedCookie,
917
+ shouldSerialize,
918
+ statusCode,
919
+ toNodeHandler
920
+ });
921
+ //# sourceMappingURL=index.cjs.map