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