better-call 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +35 -0
  2. package/dist/_virtual/rolldown_runtime.cjs +29 -0
  3. package/dist/adapters/node/request.cjs +125 -0
  4. package/dist/adapters/node/request.cjs.map +1 -0
  5. package/dist/{node.d.ts → adapters/node/request.d.cts} +2 -6
  6. package/dist/adapters/node/request.d.mts +16 -0
  7. package/dist/{node.js → adapters/node/request.mjs} +2 -13
  8. package/dist/adapters/node/request.mjs.map +1 -0
  9. package/dist/client.cjs +8 -1
  10. package/dist/client.cjs.map +1 -1
  11. package/dist/client.d.cts +12 -13
  12. package/dist/client.d.mts +53 -0
  13. package/dist/client.mjs +14 -0
  14. package/dist/client.mjs.map +1 -0
  15. package/dist/context.cjs +102 -0
  16. package/dist/context.cjs.map +1 -0
  17. package/dist/context.d.cts +340 -0
  18. package/dist/context.d.mts +340 -0
  19. package/dist/context.mjs +102 -0
  20. package/dist/context.mjs.map +1 -0
  21. package/dist/cookies.cjs +87 -0
  22. package/dist/cookies.cjs.map +1 -0
  23. package/dist/cookies.d.cts +103 -0
  24. package/dist/cookies.d.mts +103 -0
  25. package/dist/cookies.mjs +84 -0
  26. package/dist/cookies.mjs.map +1 -0
  27. package/dist/crypto.cjs +39 -0
  28. package/dist/crypto.cjs.map +1 -0
  29. package/dist/crypto.mjs +36 -0
  30. package/dist/crypto.mjs.map +1 -0
  31. package/dist/endpoint.cjs +70 -0
  32. package/dist/endpoint.cjs.map +1 -0
  33. package/dist/endpoint.d.cts +428 -0
  34. package/dist/endpoint.d.mts +428 -0
  35. package/dist/endpoint.mjs +70 -0
  36. package/dist/endpoint.mjs.map +1 -0
  37. package/dist/error.cjs +141 -0
  38. package/dist/error.cjs.map +1 -0
  39. package/dist/error.d.cts +103 -0
  40. package/dist/error.d.mts +103 -0
  41. package/dist/error.mjs +135 -0
  42. package/dist/error.mjs.map +1 -0
  43. package/dist/helper.d.cts +12 -0
  44. package/dist/helper.d.mts +12 -0
  45. package/dist/index.cjs +26 -968
  46. package/dist/index.d.cts +11 -14
  47. package/dist/index.d.mts +11 -0
  48. package/dist/index.mjs +10 -0
  49. package/dist/middleware.cjs +39 -0
  50. package/dist/middleware.cjs.map +1 -0
  51. package/dist/middleware.d.cts +123 -0
  52. package/dist/middleware.d.mts +123 -0
  53. package/dist/middleware.mjs +39 -0
  54. package/dist/middleware.mjs.map +1 -0
  55. package/dist/node.cjs +4 -151
  56. package/dist/node.cjs.map +1 -1
  57. package/dist/node.d.cts +2 -13
  58. package/dist/node.d.mts +9 -0
  59. package/dist/node.mjs +15 -0
  60. package/dist/node.mjs.map +1 -0
  61. package/dist/openapi.cjs +191 -0
  62. package/dist/openapi.cjs.map +1 -0
  63. package/dist/openapi.d.cts +113 -0
  64. package/dist/openapi.d.mts +113 -0
  65. package/dist/openapi.mjs +189 -0
  66. package/dist/openapi.mjs.map +1 -0
  67. package/dist/router.cjs +117 -0
  68. package/dist/router.cjs.map +1 -0
  69. package/dist/router.d.cts +4 -1242
  70. package/dist/router.d.mts +97 -0
  71. package/dist/router.mjs +116 -0
  72. package/dist/router.mjs.map +1 -0
  73. package/dist/standard-schema.d.cts +59 -0
  74. package/dist/standard-schema.d.mts +59 -0
  75. package/dist/to-response.cjs +96 -0
  76. package/dist/to-response.cjs.map +1 -0
  77. package/dist/to-response.d.cts +12 -0
  78. package/dist/to-response.d.mts +12 -0
  79. package/dist/to-response.mjs +96 -0
  80. package/dist/to-response.mjs.map +1 -0
  81. package/dist/utils.cjs +77 -0
  82. package/dist/utils.cjs.map +1 -0
  83. package/dist/utils.mjs +74 -0
  84. package/dist/utils.mjs.map +1 -0
  85. package/dist/validator.cjs +58 -0
  86. package/dist/validator.cjs.map +1 -0
  87. package/dist/validator.mjs +57 -0
  88. package/dist/validator.mjs.map +1 -0
  89. package/package.json +23 -13
  90. package/dist/client.d.ts +0 -54
  91. package/dist/client.js +0 -13
  92. package/dist/client.js.map +0 -1
  93. package/dist/index.cjs.map +0 -1
  94. package/dist/index.d.ts +0 -14
  95. package/dist/index.js +0 -951
  96. package/dist/index.js.map +0 -1
  97. package/dist/node.js.map +0 -1
  98. package/dist/router.d.ts +0 -1335
package/dist/index.js DELETED
@@ -1,951 +0,0 @@
1
- import { getWebcryptoSubtle } from "@better-auth/utils";
2
- import { addRoute, createRouter as createRouter$1, findAllRoutes, findRoute } from "rou3";
3
- import { ZodObject, ZodOptional } from "zod";
4
-
5
- //#region src/error.ts
6
- function isErrorStackTraceLimitWritable() {
7
- const desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit");
8
- if (desc === void 0) return Object.isExtensible(Error);
9
- return Object.prototype.hasOwnProperty.call(desc, "writable") ? desc.writable : desc.set !== void 0;
10
- }
11
- /**
12
- * Hide internal stack frames from the error stack trace.
13
- */
14
- function hideInternalStackFrames(stack) {
15
- const lines = stack.split("\n at ");
16
- if (lines.length <= 1) return stack;
17
- lines.splice(1, 1);
18
- return lines.join("\n at ");
19
- }
20
- /**
21
- * Creates a custom error class that hides stack frames.
22
- */
23
- function makeErrorForHideStackFrame(Base, clazz) {
24
- class HideStackFramesError extends Base {
25
- #hiddenStack;
26
- constructor(...args) {
27
- if (isErrorStackTraceLimitWritable()) {
28
- const limit = Error.stackTraceLimit;
29
- Error.stackTraceLimit = 0;
30
- super(...args);
31
- Error.stackTraceLimit = limit;
32
- } else super(...args);
33
- const stack = (/* @__PURE__ */ new Error()).stack;
34
- if (stack) this.#hiddenStack = hideInternalStackFrames(stack.replace(/^Error/, this.name));
35
- }
36
- get errorStack() {
37
- return this.#hiddenStack;
38
- }
39
- }
40
- Object.defineProperty(HideStackFramesError.prototype, "constructor", {
41
- get() {
42
- return clazz;
43
- },
44
- enumerable: false,
45
- configurable: true
46
- });
47
- return HideStackFramesError;
48
- }
49
- const statusCodes = {
50
- OK: 200,
51
- CREATED: 201,
52
- ACCEPTED: 202,
53
- NO_CONTENT: 204,
54
- MULTIPLE_CHOICES: 300,
55
- MOVED_PERMANENTLY: 301,
56
- FOUND: 302,
57
- SEE_OTHER: 303,
58
- NOT_MODIFIED: 304,
59
- TEMPORARY_REDIRECT: 307,
60
- BAD_REQUEST: 400,
61
- UNAUTHORIZED: 401,
62
- PAYMENT_REQUIRED: 402,
63
- FORBIDDEN: 403,
64
- NOT_FOUND: 404,
65
- METHOD_NOT_ALLOWED: 405,
66
- NOT_ACCEPTABLE: 406,
67
- PROXY_AUTHENTICATION_REQUIRED: 407,
68
- REQUEST_TIMEOUT: 408,
69
- CONFLICT: 409,
70
- GONE: 410,
71
- LENGTH_REQUIRED: 411,
72
- PRECONDITION_FAILED: 412,
73
- PAYLOAD_TOO_LARGE: 413,
74
- URI_TOO_LONG: 414,
75
- UNSUPPORTED_MEDIA_TYPE: 415,
76
- RANGE_NOT_SATISFIABLE: 416,
77
- EXPECTATION_FAILED: 417,
78
- "I'M_A_TEAPOT": 418,
79
- MISDIRECTED_REQUEST: 421,
80
- UNPROCESSABLE_ENTITY: 422,
81
- LOCKED: 423,
82
- FAILED_DEPENDENCY: 424,
83
- TOO_EARLY: 425,
84
- UPGRADE_REQUIRED: 426,
85
- PRECONDITION_REQUIRED: 428,
86
- TOO_MANY_REQUESTS: 429,
87
- REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
88
- UNAVAILABLE_FOR_LEGAL_REASONS: 451,
89
- INTERNAL_SERVER_ERROR: 500,
90
- NOT_IMPLEMENTED: 501,
91
- BAD_GATEWAY: 502,
92
- SERVICE_UNAVAILABLE: 503,
93
- GATEWAY_TIMEOUT: 504,
94
- HTTP_VERSION_NOT_SUPPORTED: 505,
95
- VARIANT_ALSO_NEGOTIATES: 506,
96
- INSUFFICIENT_STORAGE: 507,
97
- LOOP_DETECTED: 508,
98
- NOT_EXTENDED: 510,
99
- NETWORK_AUTHENTICATION_REQUIRED: 511
100
- };
101
- var InternalAPIError = class extends Error {
102
- constructor(status = "INTERNAL_SERVER_ERROR", body = void 0, headers = {}, statusCode = typeof status === "number" ? status : statusCodes[status]) {
103
- super(body?.message, body?.cause ? { cause: body.cause } : void 0);
104
- this.status = status;
105
- this.body = body;
106
- this.headers = headers;
107
- this.statusCode = statusCode;
108
- this.name = "APIError";
109
- this.status = status;
110
- this.headers = headers;
111
- this.statusCode = statusCode;
112
- this.body = body ? {
113
- code: body?.message?.toUpperCase().replace(/ /g, "_").replace(/[^A-Z0-9_]/g, ""),
114
- ...body
115
- } : void 0;
116
- }
117
- };
118
- var ValidationError = class extends InternalAPIError {
119
- constructor(message, issues) {
120
- super(400, {
121
- message,
122
- code: "VALIDATION_ERROR"
123
- });
124
- this.message = message;
125
- this.issues = issues;
126
- this.issues = issues;
127
- }
128
- };
129
- var BetterCallError = class extends Error {
130
- constructor(message) {
131
- super(message);
132
- this.name = "BetterCallError";
133
- }
134
- };
135
- const APIError = makeErrorForHideStackFrame(InternalAPIError, Error);
136
-
137
- //#endregion
138
- //#region src/utils.ts
139
- const jsonContentTypeRegex = /^application\/([a-z0-9.+-]*\+)?json/i;
140
- async function getBody(request, allowedMediaTypes) {
141
- const contentType = request.headers.get("content-type") || "";
142
- const normalizedContentType = contentType.toLowerCase();
143
- if (!request.body) return;
144
- if (allowedMediaTypes && allowedMediaTypes.length > 0) {
145
- if (!allowedMediaTypes.some((allowed) => {
146
- const normalizedContentTypeBase = normalizedContentType.split(";")[0].trim();
147
- const normalizedAllowed = allowed.toLowerCase().trim();
148
- return normalizedContentTypeBase === normalizedAllowed || normalizedContentTypeBase.includes(normalizedAllowed);
149
- })) {
150
- if (!normalizedContentType) throw new APIError(415, {
151
- message: `Content-Type is required. Allowed types: ${allowedMediaTypes.join(", ")}`,
152
- code: "UNSUPPORTED_MEDIA_TYPE"
153
- });
154
- throw new APIError(415, {
155
- message: `Content-Type "${contentType}" is not allowed. Allowed types: ${allowedMediaTypes.join(", ")}`,
156
- code: "UNSUPPORTED_MEDIA_TYPE"
157
- });
158
- }
159
- }
160
- if (jsonContentTypeRegex.test(normalizedContentType)) return await request.json();
161
- if (normalizedContentType.includes("application/x-www-form-urlencoded")) {
162
- const formData = await request.formData();
163
- const result = {};
164
- formData.forEach((value, key) => {
165
- result[key] = value.toString();
166
- });
167
- return result;
168
- }
169
- if (normalizedContentType.includes("multipart/form-data")) {
170
- const formData = await request.formData();
171
- const result = {};
172
- formData.forEach((value, key) => {
173
- result[key] = value;
174
- });
175
- return result;
176
- }
177
- if (normalizedContentType.includes("text/plain")) return await request.text();
178
- if (normalizedContentType.includes("application/octet-stream")) return await request.arrayBuffer();
179
- if (normalizedContentType.includes("application/pdf") || normalizedContentType.includes("image/") || normalizedContentType.includes("video/")) return await request.blob();
180
- if (normalizedContentType.includes("application/stream") || request.body instanceof ReadableStream) return request.body;
181
- return await request.text();
182
- }
183
- function isAPIError(error) {
184
- return error instanceof APIError || error?.name === "APIError";
185
- }
186
- function tryDecode(str) {
187
- try {
188
- return str.includes("%") ? decodeURIComponent(str) : str;
189
- } catch {
190
- return str;
191
- }
192
- }
193
- async function tryCatch(promise) {
194
- try {
195
- return {
196
- data: await promise,
197
- error: null
198
- };
199
- } catch (error) {
200
- return {
201
- data: null,
202
- error
203
- };
204
- }
205
- }
206
-
207
- //#endregion
208
- //#region src/to-response.ts
209
- function isJSONSerializable(value) {
210
- if (value === void 0) return false;
211
- const t = typeof value;
212
- if (t === "string" || t === "number" || t === "boolean" || t === null) return true;
213
- if (t !== "object") return false;
214
- if (Array.isArray(value)) return true;
215
- if (value.buffer) return false;
216
- return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
217
- }
218
- function safeStringify(obj, replacer, space) {
219
- let id = 0;
220
- const seen = /* @__PURE__ */ new WeakMap();
221
- const safeReplacer = (key, value) => {
222
- if (typeof value === "bigint") return value.toString();
223
- if (typeof value === "object" && value !== null) {
224
- if (seen.has(value)) return `[Circular ref-${seen.get(value)}]`;
225
- seen.set(value, id++);
226
- }
227
- if (replacer) return replacer(key, value);
228
- return value;
229
- };
230
- return JSON.stringify(obj, safeReplacer, space);
231
- }
232
- function isJSONResponse(value) {
233
- if (!value || typeof value !== "object") return false;
234
- return "_flag" in value && value._flag === "json";
235
- }
236
- function toResponse(data, init) {
237
- if (data instanceof Response) {
238
- if (init?.headers instanceof Headers) init.headers.forEach((value, key) => {
239
- data.headers.set(key, value);
240
- });
241
- return data;
242
- }
243
- if (isJSONResponse(data)) {
244
- const body$1 = data.body;
245
- const routerResponse = data.routerResponse;
246
- if (routerResponse instanceof Response) return routerResponse;
247
- const headers$1 = new Headers();
248
- if (routerResponse?.headers) {
249
- const headers$2 = new Headers(routerResponse.headers);
250
- for (const [key, value] of headers$2.entries()) headers$2.set(key, value);
251
- }
252
- if (data.headers) for (const [key, value] of new Headers(data.headers).entries()) headers$1.set(key, value);
253
- if (init?.headers) for (const [key, value] of new Headers(init.headers).entries()) headers$1.set(key, value);
254
- headers$1.set("Content-Type", "application/json");
255
- return new Response(JSON.stringify(body$1), {
256
- ...routerResponse,
257
- headers: headers$1,
258
- status: data.status ?? init?.status ?? routerResponse?.status,
259
- statusText: init?.statusText ?? routerResponse?.statusText
260
- });
261
- }
262
- if (isAPIError(data)) return toResponse(data.body, {
263
- status: init?.status ?? data.statusCode,
264
- statusText: data.status.toString(),
265
- headers: init?.headers || data.headers
266
- });
267
- let body = data;
268
- let headers = new Headers(init?.headers);
269
- if (!data) {
270
- if (data === null) body = JSON.stringify(null);
271
- headers.set("content-type", "application/json");
272
- } else if (typeof data === "string") {
273
- body = data;
274
- headers.set("Content-Type", "text/plain");
275
- } else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
276
- body = data;
277
- headers.set("Content-Type", "application/octet-stream");
278
- } else if (data instanceof Blob) {
279
- body = data;
280
- headers.set("Content-Type", data.type || "application/octet-stream");
281
- } else if (data instanceof FormData) body = data;
282
- else if (data instanceof URLSearchParams) {
283
- body = data;
284
- headers.set("Content-Type", "application/x-www-form-urlencoded");
285
- } else if (data instanceof ReadableStream) {
286
- body = data;
287
- headers.set("Content-Type", "application/octet-stream");
288
- } else if (isJSONSerializable(data)) {
289
- body = safeStringify(data);
290
- headers.set("Content-Type", "application/json");
291
- }
292
- return new Response(body, {
293
- ...init,
294
- headers
295
- });
296
- }
297
-
298
- //#endregion
299
- //#region src/validator.ts
300
- /**
301
- * Runs validation on body and query
302
- * @returns error and data object
303
- */
304
- async function runValidation(options, context = {}) {
305
- let request = {
306
- body: context.body,
307
- query: context.query
308
- };
309
- if (options.body) {
310
- const result = await options.body["~standard"].validate(context.body);
311
- if (result.issues) return {
312
- data: null,
313
- error: fromError(result.issues, "body")
314
- };
315
- request.body = result.value;
316
- }
317
- if (options.query) {
318
- const result = await options.query["~standard"].validate(context.query);
319
- if (result.issues) return {
320
- data: null,
321
- error: fromError(result.issues, "query")
322
- };
323
- request.query = result.value;
324
- }
325
- if (options.requireHeaders && !context.headers) return {
326
- data: null,
327
- error: {
328
- message: "Headers is required",
329
- issues: []
330
- }
331
- };
332
- if (options.requireRequest && !context.request) return {
333
- data: null,
334
- error: {
335
- message: "Request is required",
336
- issues: []
337
- }
338
- };
339
- return {
340
- data: request,
341
- error: null
342
- };
343
- }
344
- function fromError(error, validating) {
345
- return {
346
- message: error.map((e) => {
347
- return `[${e.path?.length ? `${validating}.` + e.path.map((x) => typeof x === "object" ? x.key : x).join(".") : validating}] ${e.message}`;
348
- }).join("; "),
349
- issues: error
350
- };
351
- }
352
-
353
- //#endregion
354
- //#region src/crypto.ts
355
- const algorithm = {
356
- name: "HMAC",
357
- hash: "SHA-256"
358
- };
359
- const getCryptoKey = async (secret) => {
360
- const secretBuf = typeof secret === "string" ? new TextEncoder().encode(secret) : secret;
361
- return await getWebcryptoSubtle().importKey("raw", secretBuf, algorithm, false, ["sign", "verify"]);
362
- };
363
- const verifySignature = async (base64Signature, value, secret) => {
364
- try {
365
- const signatureBinStr = atob(base64Signature);
366
- const signature = new Uint8Array(signatureBinStr.length);
367
- for (let i = 0, len = signatureBinStr.length; i < len; i++) signature[i] = signatureBinStr.charCodeAt(i);
368
- return await getWebcryptoSubtle().verify(algorithm, secret, signature, new TextEncoder().encode(value));
369
- } catch (e) {
370
- return false;
371
- }
372
- };
373
- const makeSignature = async (value, secret) => {
374
- const key = await getCryptoKey(secret);
375
- const signature = await getWebcryptoSubtle().sign(algorithm.name, key, new TextEncoder().encode(value));
376
- return btoa(String.fromCharCode(...new Uint8Array(signature)));
377
- };
378
- const signCookieValue = async (value, secret) => {
379
- const signature = await makeSignature(value, secret);
380
- value = `${value}.${signature}`;
381
- value = encodeURIComponent(value);
382
- return value;
383
- };
384
-
385
- //#endregion
386
- //#region src/cookies.ts
387
- const getCookieKey = (key, prefix) => {
388
- let finalKey = key;
389
- if (prefix) if (prefix === "secure") finalKey = "__Secure-" + key;
390
- else if (prefix === "host") finalKey = "__Host-" + key;
391
- else return;
392
- return finalKey;
393
- };
394
- /**
395
- * Parse an HTTP Cookie header string and returning an object of all cookie
396
- * name-value pairs.
397
- *
398
- * Inspired by https://github.com/unjs/cookie-es/blob/main/src/cookie/parse.ts
399
- *
400
- * @param str the string representing a `Cookie` header value
401
- */
402
- function parseCookies(str) {
403
- if (typeof str !== "string") throw new TypeError("argument str must be a string");
404
- const cookies = /* @__PURE__ */ new Map();
405
- let index = 0;
406
- while (index < str.length) {
407
- const eqIdx = str.indexOf("=", index);
408
- if (eqIdx === -1) break;
409
- let endIdx = str.indexOf(";", index);
410
- if (endIdx === -1) endIdx = str.length;
411
- else if (endIdx < eqIdx) {
412
- index = str.lastIndexOf(";", eqIdx - 1) + 1;
413
- continue;
414
- }
415
- const key = str.slice(index, eqIdx).trim();
416
- if (!cookies.has(key)) {
417
- let val = str.slice(eqIdx + 1, endIdx).trim();
418
- if (val.codePointAt(0) === 34) val = val.slice(1, -1);
419
- cookies.set(key, tryDecode(val));
420
- }
421
- index = endIdx + 1;
422
- }
423
- return cookies;
424
- }
425
- const _serialize = (key, value, opt = {}) => {
426
- let cookie;
427
- if (opt?.prefix === "secure") cookie = `${`__Secure-${key}`}=${value}`;
428
- else if (opt?.prefix === "host") cookie = `${`__Host-${key}`}=${value}`;
429
- else cookie = `${key}=${value}`;
430
- if (key.startsWith("__Secure-") && !opt.secure) opt.secure = true;
431
- if (key.startsWith("__Host-")) {
432
- if (!opt.secure) opt.secure = true;
433
- if (opt.path !== "/") opt.path = "/";
434
- if (opt.domain) opt.domain = void 0;
435
- }
436
- if (opt && typeof opt.maxAge === "number" && opt.maxAge >= 0) {
437
- if (opt.maxAge > 3456e4) throw new Error("Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.");
438
- cookie += `; Max-Age=${Math.floor(opt.maxAge)}`;
439
- }
440
- if (opt.domain && opt.prefix !== "host") cookie += `; Domain=${opt.domain}`;
441
- if (opt.path) cookie += `; Path=${opt.path}`;
442
- if (opt.expires) {
443
- if (opt.expires.getTime() - Date.now() > 3456e7) throw new Error("Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.");
444
- cookie += `; Expires=${opt.expires.toUTCString()}`;
445
- }
446
- if (opt.httpOnly) cookie += "; HttpOnly";
447
- if (opt.secure) cookie += "; Secure";
448
- if (opt.sameSite) cookie += `; SameSite=${opt.sameSite.charAt(0).toUpperCase() + opt.sameSite.slice(1)}`;
449
- if (opt.partitioned) {
450
- if (!opt.secure) opt.secure = true;
451
- cookie += "; Partitioned";
452
- }
453
- return cookie;
454
- };
455
- const serializeCookie = (key, value, opt) => {
456
- value = encodeURIComponent(value);
457
- return _serialize(key, value, opt);
458
- };
459
- const serializeSignedCookie = async (key, value, secret, opt) => {
460
- value = await signCookieValue(value, secret);
461
- return _serialize(key, value, opt);
462
- };
463
-
464
- //#endregion
465
- //#region src/context.ts
466
- const createInternalContext = async (context, { options, path }) => {
467
- const headers = new Headers();
468
- let responseStatus = void 0;
469
- const { data, error } = await runValidation(options, context);
470
- if (error) throw new ValidationError(error.message, error.issues);
471
- const requestHeaders = "headers" in context ? context.headers instanceof Headers ? context.headers : new Headers(context.headers) : "request" in context && context.request instanceof Request ? context.request.headers : null;
472
- const requestCookies = requestHeaders?.get("cookie");
473
- const parsedCookies = requestCookies ? parseCookies(requestCookies) : void 0;
474
- const internalContext = {
475
- ...context,
476
- body: data.body,
477
- query: data.query,
478
- path: context.path || path || "virtual:",
479
- context: "context" in context && context.context ? context.context : {},
480
- returned: void 0,
481
- headers: context?.headers,
482
- request: context?.request,
483
- params: "params" in context ? context.params : void 0,
484
- method: context.method,
485
- setHeader: (key, value) => {
486
- headers.set(key, value);
487
- },
488
- getHeader: (key) => {
489
- if (!requestHeaders) return null;
490
- return requestHeaders.get(key);
491
- },
492
- getCookie: (key, prefix) => {
493
- const finalKey = getCookieKey(key, prefix);
494
- if (!finalKey) return null;
495
- return parsedCookies?.get(finalKey) || null;
496
- },
497
- getSignedCookie: async (key, secret, prefix) => {
498
- const finalKey = getCookieKey(key, prefix);
499
- if (!finalKey) return null;
500
- const value = parsedCookies?.get(finalKey);
501
- if (!value) return null;
502
- const signatureStartPos = value.lastIndexOf(".");
503
- if (signatureStartPos < 1) return null;
504
- const signedValue = value.substring(0, signatureStartPos);
505
- const signature = value.substring(signatureStartPos + 1);
506
- if (signature.length !== 44 || !signature.endsWith("=")) return null;
507
- return await verifySignature(signature, signedValue, await getCryptoKey(secret)) ? signedValue : false;
508
- },
509
- setCookie: (key, value, options$1) => {
510
- const cookie = serializeCookie(key, value, options$1);
511
- headers.append("set-cookie", cookie);
512
- return cookie;
513
- },
514
- setSignedCookie: async (key, value, secret, options$1) => {
515
- const cookie = await serializeSignedCookie(key, value, secret, options$1);
516
- headers.append("set-cookie", cookie);
517
- return cookie;
518
- },
519
- redirect: (url) => {
520
- headers.set("location", url);
521
- return new APIError("FOUND", void 0, headers);
522
- },
523
- error: (status, body, headers$1) => {
524
- return new APIError(status, body, headers$1);
525
- },
526
- setStatus: (status) => {
527
- responseStatus = status;
528
- },
529
- json: (json, routerResponse) => {
530
- if (!context.asResponse) return json;
531
- return {
532
- body: routerResponse?.body || json,
533
- routerResponse,
534
- _flag: "json"
535
- };
536
- },
537
- responseHeaders: headers,
538
- get responseStatus() {
539
- return responseStatus;
540
- }
541
- };
542
- for (const middleware of options.use || []) {
543
- const response = await middleware({
544
- ...internalContext,
545
- returnHeaders: true,
546
- asResponse: false
547
- });
548
- if (response.response) Object.assign(internalContext.context, response.response);
549
- /**
550
- * Apply headers from the middleware to the endpoint headers
551
- */
552
- if (response.headers) response.headers.forEach((value, key) => {
553
- internalContext.responseHeaders.set(key, value);
554
- });
555
- }
556
- return internalContext;
557
- };
558
-
559
- //#endregion
560
- //#region src/endpoint.ts
561
- function createEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
562
- const path = typeof pathOrOptions === "string" ? pathOrOptions : void 0;
563
- const options = typeof handlerOrOptions === "object" ? handlerOrOptions : pathOrOptions;
564
- const handler = typeof handlerOrOptions === "function" ? handlerOrOptions : handlerOrNever;
565
- if ((options.method === "GET" || options.method === "HEAD") && options.body) throw new BetterCallError("Body is not allowed with GET or HEAD methods");
566
- if (path && /\/{2,}/.test(path)) throw new BetterCallError("Path cannot contain consecutive slashes");
567
- const internalHandler = async (...inputCtx) => {
568
- const context = inputCtx[0] || {};
569
- const { data: internalContext, error: validationError } = await tryCatch(createInternalContext(context, {
570
- options,
571
- path
572
- }));
573
- if (validationError) {
574
- if (!(validationError instanceof ValidationError)) throw validationError;
575
- if (options.onValidationError) await options.onValidationError({
576
- message: validationError.message,
577
- issues: validationError.issues
578
- });
579
- throw new APIError(400, {
580
- message: validationError.message,
581
- code: "VALIDATION_ERROR"
582
- });
583
- }
584
- const response = await handler(internalContext).catch(async (e) => {
585
- if (isAPIError(e)) {
586
- const onAPIError = options.onAPIError;
587
- if (onAPIError) await onAPIError(e);
588
- if (context.asResponse) return e;
589
- }
590
- throw e;
591
- });
592
- const headers = internalContext.responseHeaders;
593
- const status = internalContext.responseStatus;
594
- return context.asResponse ? toResponse(response, {
595
- headers,
596
- status
597
- }) : context.returnHeaders ? context.returnStatus ? {
598
- headers,
599
- response,
600
- status
601
- } : {
602
- headers,
603
- response
604
- } : context.returnStatus ? {
605
- response,
606
- status
607
- } : response;
608
- };
609
- internalHandler.options = options;
610
- internalHandler.path = path;
611
- return internalHandler;
612
- }
613
- createEndpoint.create = (opts) => {
614
- return (path, options, handler) => {
615
- return createEndpoint(path, {
616
- ...options,
617
- use: [...options?.use || [], ...opts?.use || []]
618
- }, handler);
619
- };
620
- };
621
-
622
- //#endregion
623
- //#region src/middleware.ts
624
- function createMiddleware(optionsOrHandler, handler) {
625
- const internalHandler = async (inputCtx) => {
626
- const context = inputCtx;
627
- const _handler = typeof optionsOrHandler === "function" ? optionsOrHandler : handler;
628
- const internalContext = await createInternalContext(context, {
629
- options: typeof optionsOrHandler === "function" ? {} : optionsOrHandler,
630
- path: "/"
631
- });
632
- if (!_handler) throw new Error("handler must be defined");
633
- const response = await _handler(internalContext);
634
- const headers = internalContext.responseHeaders;
635
- return context.returnHeaders ? {
636
- headers,
637
- response
638
- } : response;
639
- };
640
- internalHandler.options = typeof optionsOrHandler === "function" ? {} : optionsOrHandler;
641
- return internalHandler;
642
- }
643
- createMiddleware.create = (opts) => {
644
- function fn(optionsOrHandler, handler) {
645
- if (typeof optionsOrHandler === "function") return createMiddleware({ use: opts?.use }, optionsOrHandler);
646
- if (!handler) throw new Error("Middleware handler is required");
647
- return createMiddleware({
648
- ...optionsOrHandler,
649
- method: "*",
650
- use: [...opts?.use || [], ...optionsOrHandler.use || []]
651
- }, handler);
652
- }
653
- return fn;
654
- };
655
-
656
- //#endregion
657
- //#region src/openapi.ts
658
- const paths = {};
659
- function getTypeFromZodType(zodType) {
660
- switch (zodType.constructor.name) {
661
- case "ZodString": return "string";
662
- case "ZodNumber": return "number";
663
- case "ZodBoolean": return "boolean";
664
- case "ZodObject": return "object";
665
- case "ZodArray": return "array";
666
- default: return "string";
667
- }
668
- }
669
- function getParameters(options) {
670
- const parameters = [];
671
- if (options.metadata?.openapi?.parameters) {
672
- parameters.push(...options.metadata.openapi.parameters);
673
- return parameters;
674
- }
675
- if (options.query instanceof ZodObject) Object.entries(options.query.shape).forEach(([key, value]) => {
676
- if (value instanceof ZodObject) parameters.push({
677
- name: key,
678
- in: "query",
679
- schema: {
680
- type: getTypeFromZodType(value),
681
- ..."minLength" in value && value.minLength ? { minLength: value.minLength } : {},
682
- description: value.description
683
- }
684
- });
685
- });
686
- return parameters;
687
- }
688
- function getRequestBody(options) {
689
- if (options.metadata?.openapi?.requestBody) return options.metadata.openapi.requestBody;
690
- if (!options.body) return void 0;
691
- if (options.body instanceof ZodObject || options.body instanceof ZodOptional) {
692
- const shape = options.body.shape;
693
- if (!shape) return void 0;
694
- const properties = {};
695
- const required = [];
696
- Object.entries(shape).forEach(([key, value]) => {
697
- if (value instanceof ZodObject) {
698
- properties[key] = {
699
- type: getTypeFromZodType(value),
700
- description: value.description
701
- };
702
- if (!(value instanceof ZodOptional)) required.push(key);
703
- }
704
- });
705
- return {
706
- required: options.body instanceof ZodOptional ? false : options.body ? true : false,
707
- content: { "application/json": { schema: {
708
- type: "object",
709
- properties,
710
- required
711
- } } }
712
- };
713
- }
714
- }
715
- function getResponse(responses) {
716
- return {
717
- "400": {
718
- content: { "application/json": { schema: {
719
- type: "object",
720
- properties: { message: { type: "string" } },
721
- required: ["message"]
722
- } } },
723
- description: "Bad Request. Usually due to missing parameters, or invalid parameters."
724
- },
725
- "401": {
726
- content: { "application/json": { schema: {
727
- type: "object",
728
- properties: { message: { type: "string" } },
729
- required: ["message"]
730
- } } },
731
- description: "Unauthorized. Due to missing or invalid authentication."
732
- },
733
- "403": {
734
- content: { "application/json": { schema: {
735
- type: "object",
736
- properties: { message: { type: "string" } }
737
- } } },
738
- description: "Forbidden. You do not have permission to access this resource or to perform this action."
739
- },
740
- "404": {
741
- content: { "application/json": { schema: {
742
- type: "object",
743
- properties: { message: { type: "string" } }
744
- } } },
745
- description: "Not Found. The requested resource was not found."
746
- },
747
- "429": {
748
- content: { "application/json": { schema: {
749
- type: "object",
750
- properties: { message: { type: "string" } }
751
- } } },
752
- description: "Too Many Requests. You have exceeded the rate limit. Try again later."
753
- },
754
- "500": {
755
- content: { "application/json": { schema: {
756
- type: "object",
757
- properties: { message: { type: "string" } }
758
- } } },
759
- description: "Internal Server Error. This is a problem with the server that you cannot fix."
760
- },
761
- ...responses
762
- };
763
- }
764
- async function generator(endpoints, config) {
765
- const components = { schemas: {} };
766
- Object.entries(endpoints).forEach(([_, value]) => {
767
- const options = value.options;
768
- if (!value.path || options.metadata?.SERVER_ONLY) return;
769
- if (options.method === "GET") paths[value.path] = { get: {
770
- tags: ["Default", ...options.metadata?.openapi?.tags || []],
771
- description: options.metadata?.openapi?.description,
772
- operationId: options.metadata?.openapi?.operationId,
773
- security: [{ bearerAuth: [] }],
774
- parameters: getParameters(options),
775
- responses: getResponse(options.metadata?.openapi?.responses)
776
- } };
777
- if (options.method === "POST") {
778
- const body = getRequestBody(options);
779
- paths[value.path] = { post: {
780
- tags: ["Default", ...options.metadata?.openapi?.tags || []],
781
- description: options.metadata?.openapi?.description,
782
- operationId: options.metadata?.openapi?.operationId,
783
- security: [{ bearerAuth: [] }],
784
- parameters: getParameters(options),
785
- ...body ? { requestBody: body } : { requestBody: { content: { "application/json": { schema: {
786
- type: "object",
787
- properties: {}
788
- } } } } },
789
- responses: getResponse(options.metadata?.openapi?.responses)
790
- } };
791
- }
792
- });
793
- return {
794
- openapi: "3.1.1",
795
- info: {
796
- title: "Better Auth",
797
- description: "API Reference for your Better Auth Instance",
798
- version: "1.1.0"
799
- },
800
- components,
801
- security: [{ apiKeyCookie: [] }],
802
- servers: [{ url: config?.url }],
803
- tags: [{
804
- name: "Default",
805
- description: "Default endpoints that are included with Better Auth by default. These endpoints are not part of any plugin."
806
- }],
807
- paths
808
- };
809
- }
810
- const getHTML = (apiReference, config) => `<!doctype html>
811
- <html>
812
- <head>
813
- <title>Scalar API Reference</title>
814
- <meta charset="utf-8" />
815
- <meta
816
- name="viewport"
817
- content="width=device-width, initial-scale=1" />
818
- </head>
819
- <body>
820
- <script
821
- id="api-reference"
822
- type="application/json">
823
- ${JSON.stringify(apiReference)}
824
- <\/script>
825
- <script>
826
- var configuration = {
827
- favicon: ${config?.logo ? `data:image/svg+xml;utf8,${encodeURIComponent(config.logo)}` : void 0} ,
828
- theme: ${config?.theme || "saturn"},
829
- metaData: {
830
- title: ${config?.title || "Open API Reference"},
831
- description: ${config?.description || "Better Call Open API"},
832
- }
833
- }
834
- document.getElementById('api-reference').dataset.configuration =
835
- JSON.stringify(configuration)
836
- <\/script>
837
- <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"><\/script>
838
- </body>
839
- </html>`;
840
-
841
- //#endregion
842
- //#region src/router.ts
843
- const createRouter = (endpoints, config) => {
844
- if (!config?.openapi?.disabled) {
845
- const openapi = {
846
- path: "/api/reference",
847
- ...config?.openapi
848
- };
849
- endpoints["openapi"] = createEndpoint(openapi.path, { method: "GET" }, async (c) => {
850
- const schema = await generator(endpoints);
851
- return new Response(getHTML(schema, openapi.scalar), { headers: { "Content-Type": "text/html" } });
852
- });
853
- }
854
- const router = createRouter$1();
855
- const middlewareRouter = createRouter$1();
856
- for (const endpoint of Object.values(endpoints)) {
857
- if (!endpoint.options || !endpoint.path) continue;
858
- if (endpoint.options?.metadata?.SERVER_ONLY) continue;
859
- const methods = Array.isArray(endpoint.options?.method) ? endpoint.options.method : [endpoint.options?.method];
860
- for (const method of methods) addRoute(router, method, endpoint.path, endpoint);
861
- }
862
- if (config?.routerMiddleware?.length) for (const { path, middleware } of config.routerMiddleware) addRoute(middlewareRouter, "*", path, middleware);
863
- const processRequest = async (request) => {
864
- const url = new URL(request.url);
865
- const pathname = url.pathname;
866
- const path = config?.basePath && config.basePath !== "/" ? pathname.split(config.basePath).reduce((acc, curr, index) => {
867
- if (index !== 0) if (index > 1) acc.push(`${config.basePath}${curr}`);
868
- else acc.push(curr);
869
- return acc;
870
- }, []).join("") : url.pathname;
871
- if (!path?.length) return new Response(null, {
872
- status: 404,
873
- statusText: "Not Found"
874
- });
875
- if (/\/{2,}/.test(path)) return new Response(null, {
876
- status: 404,
877
- statusText: "Not Found"
878
- });
879
- const route = findRoute(router, request.method, path);
880
- if (path.endsWith("/") !== route?.data?.path?.endsWith("/") && !config?.skipTrailingSlashes) return new Response(null, {
881
- status: 404,
882
- statusText: "Not Found"
883
- });
884
- if (!route?.data) return new Response(null, {
885
- status: 404,
886
- statusText: "Not Found"
887
- });
888
- const query = {};
889
- url.searchParams.forEach((value, key) => {
890
- if (key in query) if (Array.isArray(query[key])) query[key].push(value);
891
- else query[key] = [query[key], value];
892
- else query[key] = value;
893
- });
894
- const handler = route.data;
895
- try {
896
- const allowedMediaTypes = handler.options.metadata?.allowedMediaTypes || config?.allowedMediaTypes;
897
- const context = {
898
- path,
899
- method: request.method,
900
- headers: request.headers,
901
- params: route.params ? JSON.parse(JSON.stringify(route.params)) : {},
902
- request,
903
- body: handler.options.disableBody ? void 0 : await getBody(handler.options.cloneRequest ? request.clone() : request, allowedMediaTypes),
904
- query,
905
- _flag: "router",
906
- asResponse: true,
907
- context: config?.routerContext
908
- };
909
- const middlewareRoutes = findAllRoutes(middlewareRouter, "*", path);
910
- if (middlewareRoutes?.length) for (const { data: middleware, params } of middlewareRoutes) {
911
- const res = await middleware({
912
- ...context,
913
- params,
914
- asResponse: false
915
- });
916
- if (res instanceof Response) return res;
917
- }
918
- return await handler(context);
919
- } catch (error) {
920
- if (config?.onError) try {
921
- const errorResponse = await config.onError(error);
922
- if (errorResponse instanceof Response) return toResponse(errorResponse);
923
- } catch (error$1) {
924
- if (isAPIError(error$1)) return toResponse(error$1);
925
- throw error$1;
926
- }
927
- if (config?.throwError) throw error;
928
- if (isAPIError(error)) return toResponse(error);
929
- console.error(`# SERVER_ERROR: `, error);
930
- return new Response(null, {
931
- status: 500,
932
- statusText: "Internal Server Error"
933
- });
934
- }
935
- };
936
- return {
937
- handler: async (request) => {
938
- const onReq = await config?.onRequest?.(request);
939
- if (onReq instanceof Response) return onReq;
940
- const res = await processRequest(onReq instanceof Request ? onReq : request);
941
- const onRes = await config?.onResponse?.(res);
942
- if (onRes instanceof Response) return onRes;
943
- return res;
944
- },
945
- endpoints
946
- };
947
- };
948
-
949
- //#endregion
950
- export { APIError, BetterCallError, ValidationError, createEndpoint, createInternalContext, createMiddleware, createRouter, generator, getCookieKey, getHTML, hideInternalStackFrames, makeErrorForHideStackFrame, parseCookies, serializeCookie, serializeSignedCookie, statusCodes, toResponse };
951
- //# sourceMappingURL=index.js.map