nestjs-slightly-better-auth 1.0.0

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 (77) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +57 -0
  3. package/dist/admin.cjs +88 -0
  4. package/dist/admin.cjs.map +1 -0
  5. package/dist/admin.d.cts +14 -0
  6. package/dist/admin.d.cts.map +1 -0
  7. package/dist/admin.d.mts +14 -0
  8. package/dist/admin.d.mts.map +1 -0
  9. package/dist/admin.mjs +85 -0
  10. package/dist/admin.mjs.map +1 -0
  11. package/dist/api-key.cjs +163 -0
  12. package/dist/api-key.cjs.map +1 -0
  13. package/dist/api-key.d.cts +42 -0
  14. package/dist/api-key.d.cts.map +1 -0
  15. package/dist/api-key.d.mts +42 -0
  16. package/dist/api-key.d.mts.map +1 -0
  17. package/dist/api-key.mjs +159 -0
  18. package/dist/api-key.mjs.map +1 -0
  19. package/dist/auth-contracts-BBA1C1gj.d.cts +1635 -0
  20. package/dist/auth-contracts-BBA1C1gj.d.cts.map +1 -0
  21. package/dist/auth-contracts-tqsfBZ8B.d.mts +1635 -0
  22. package/dist/auth-contracts-tqsfBZ8B.d.mts.map +1 -0
  23. package/dist/auth-decorators-CwW5JY4y.cjs +1274 -0
  24. package/dist/auth-decorators-CwW5JY4y.cjs.map +1 -0
  25. package/dist/auth-decorators-DfAJbHar.mjs +849 -0
  26. package/dist/auth-decorators-DfAJbHar.mjs.map +1 -0
  27. package/dist/auth-errors-CQjfgjaO.mjs +283 -0
  28. package/dist/auth-errors-CQjfgjaO.mjs.map +1 -0
  29. package/dist/auth-errors-CsERBNWI.cjs +348 -0
  30. package/dist/auth-errors-CsERBNWI.cjs.map +1 -0
  31. package/dist/express.cjs +247 -0
  32. package/dist/express.cjs.map +1 -0
  33. package/dist/express.d.cts +37 -0
  34. package/dist/express.d.cts.map +1 -0
  35. package/dist/express.d.mts +37 -0
  36. package/dist/express.d.mts.map +1 -0
  37. package/dist/express.mjs +245 -0
  38. package/dist/express.mjs.map +1 -0
  39. package/dist/fastify.cjs +215 -0
  40. package/dist/fastify.cjs.map +1 -0
  41. package/dist/fastify.d.cts +28 -0
  42. package/dist/fastify.d.cts.map +1 -0
  43. package/dist/fastify.d.mts +28 -0
  44. package/dist/fastify.d.mts.map +1 -0
  45. package/dist/fastify.mjs +213 -0
  46. package/dist/fastify.mjs.map +1 -0
  47. package/dist/index.cjs +2634 -0
  48. package/dist/index.cjs.map +1 -0
  49. package/dist/index.d.cts +2 -0
  50. package/dist/index.d.mts +2 -0
  51. package/dist/index.mjs +2556 -0
  52. package/dist/index.mjs.map +1 -0
  53. package/dist/organization.cjs +191 -0
  54. package/dist/organization.cjs.map +1 -0
  55. package/dist/organization.d.cts +40 -0
  56. package/dist/organization.d.cts.map +1 -0
  57. package/dist/organization.d.mts +40 -0
  58. package/dist/organization.d.mts.map +1 -0
  59. package/dist/organization.mjs +177 -0
  60. package/dist/organization.mjs.map +1 -0
  61. package/dist/platform.cjs +393 -0
  62. package/dist/platform.cjs.map +1 -0
  63. package/dist/platform.d.cts +43 -0
  64. package/dist/platform.d.cts.map +1 -0
  65. package/dist/platform.d.mts +43 -0
  66. package/dist/platform.d.mts.map +1 -0
  67. package/dist/platform.mjs +385 -0
  68. package/dist/platform.mjs.map +1 -0
  69. package/dist/plugin.cjs +312 -0
  70. package/dist/plugin.cjs.map +1 -0
  71. package/dist/plugin.d.cts +26 -0
  72. package/dist/plugin.d.cts.map +1 -0
  73. package/dist/plugin.d.mts +26 -0
  74. package/dist/plugin.d.mts.map +1 -0
  75. package/dist/plugin.mjs +310 -0
  76. package/dist/plugin.mjs.map +1 -0
  77. package/package.json +186 -0
@@ -0,0 +1,348 @@
1
+ let better_auth_api = require("better-auth/api");
2
+ //#region src/error-redactor.ts
3
+ /** Reading an arbitrary thrown value must not invoke another escaping fault. */
4
+ function readErrorProperty(value, key) {
5
+ if ((typeof value !== "object" || value === null) && typeof value !== "function") return;
6
+ try {
7
+ return Reflect.get(value, key);
8
+ } catch {
9
+ return;
10
+ }
11
+ }
12
+ var ErrorRedactor = class {
13
+ #secrets;
14
+ constructor(options = {}) {
15
+ const values = /* @__PURE__ */ new Set();
16
+ const add = (value) => {
17
+ if (!value) return;
18
+ values.add(value);
19
+ let decoded = value;
20
+ try {
21
+ decoded = decodeURIComponent(value);
22
+ values.add(decoded);
23
+ } catch {}
24
+ for (const form of [value, decoded]) {
25
+ const separator = form.lastIndexOf(".");
26
+ if (separator >= 16) values.add(form.slice(0, separator));
27
+ }
28
+ };
29
+ for (const value of options.secrets ?? []) add(value);
30
+ const headers = options.headers;
31
+ for (const cookie of (headers?.get("cookie") ?? "").split(";")) {
32
+ const separator = cookie.indexOf("=");
33
+ if (separator >= 0) {
34
+ const value = cookie.slice(separator + 1).trim();
35
+ add(value);
36
+ if (value.startsWith("\"") && value.endsWith("\"")) add(value.slice(1, -1));
37
+ }
38
+ }
39
+ const authorization = headers?.get("authorization");
40
+ if (authorization) {
41
+ add(authorization);
42
+ const credential = /^\S+\s+(.+)$/.exec(authorization)?.[1];
43
+ if (credential) add(credential);
44
+ }
45
+ for (const name of options.credentialHeaders ?? []) {
46
+ const value = headers?.get(name);
47
+ if (value) add(value);
48
+ }
49
+ this.#secrets = [...values].sort((left, right) => right.length - left.length);
50
+ }
51
+ redact(cause) {
52
+ return this.redactCause(cause, 0, /* @__PURE__ */ new Set());
53
+ }
54
+ replaceSecrets(value) {
55
+ for (const secret of this.#secrets) value = value.split(secret).join("[REDACTED]");
56
+ return value;
57
+ }
58
+ diagnostic(value) {
59
+ return this.replaceSecrets(value).split(/[\r\n]/, 1)[0].slice(0, 300);
60
+ }
61
+ redactCause(cause, depth, seen) {
62
+ const message = readErrorProperty(cause, "message");
63
+ const error = new Error(this.diagnostic(typeof message === "string" ? message : typeof cause === "string" ? cause : "Unknown authentication infrastructure failure"));
64
+ const name = readErrorProperty(cause, "name");
65
+ error.name = typeof name === "string" ? this.diagnostic(name) : "Error";
66
+ for (const key of [
67
+ "code",
68
+ "errno",
69
+ "syscall"
70
+ ]) {
71
+ const value = readErrorProperty(cause, key);
72
+ if (typeof value === "string" || typeof value === "number" && Number.isFinite(value)) Object.defineProperty(error, key, {
73
+ value: typeof value === "string" ? this.diagnostic(value) : value,
74
+ enumerable: true
75
+ });
76
+ }
77
+ const stack = readErrorProperty(cause, "stack");
78
+ const frames = typeof stack === "string" ? stack.split(/\r?\n/).filter((line) => /^\s+at .+:\d+:\d+\)?$/.test(line)).map((line) => this.replaceSecrets(line)) : [];
79
+ error.stack = [`${error.name}: ${error.message}`, ...frames].join("\n");
80
+ seen.add(cause);
81
+ const nested = readErrorProperty(cause, "cause");
82
+ if (nested !== void 0 && depth < 3 && !seen.has(nested)) Object.defineProperty(error, "cause", {
83
+ value: this.redactCause(nested, depth + 1, seen),
84
+ enumerable: false
85
+ });
86
+ return error;
87
+ }
88
+ };
89
+ //#endregion
90
+ //#region src/auth-errors.ts
91
+ const FAILURE_BRAND = Symbol.for("nestjs-slightly-better-auth:auth-failure");
92
+ const INFRASTRUCTURE_BRAND = Symbol.for("nestjs-slightly-better-auth:infrastructure-error");
93
+ const CONFIGURATION_BRAND = Symbol.for("nestjs-slightly-better-auth:configuration-error");
94
+ const RAW_CAUSE = Symbol.for("nestjs-slightly-better-auth:raw-cause");
95
+ const SDK_HEADERS = Symbol.for("better-call:api-error-headers");
96
+ function branded(value, brand) {
97
+ Object.defineProperty(value, brand, { value: true });
98
+ return value;
99
+ }
100
+ function isAuthFailure(value) {
101
+ return readErrorProperty(value, FAILURE_BRAND) === true;
102
+ }
103
+ function isInfrastructureError(value) {
104
+ return readErrorProperty(value, INFRASTRUCTURE_BRAND) === true;
105
+ }
106
+ function isConfigurationError(value) {
107
+ return readErrorProperty(value, CONFIGURATION_BRAND) === true;
108
+ }
109
+ function sdkStatus(error) {
110
+ try {
111
+ if (!(0, better_auth_api.isAPIError)(error)) return;
112
+ const status = readErrorProperty(error, "statusCode");
113
+ return typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599 ? status : void 0;
114
+ } catch {
115
+ return;
116
+ }
117
+ }
118
+ function sdkReason(error) {
119
+ const reason = readErrorProperty(readErrorProperty(error, "body"), "code");
120
+ return typeof reason === "string" ? reason : void 0;
121
+ }
122
+ /** Internal: preserve cookie lines for the exchange's separately governed cleanup. */
123
+ function getAPIErrorHeaders(error) {
124
+ const result = new Headers();
125
+ for (const value of [readErrorProperty(error, SDK_HEADERS), readErrorProperty(error, "headers")]) {
126
+ if (value === void 0 || value === null) continue;
127
+ try {
128
+ const headers = new Headers(value);
129
+ for (const [name, value] of headers) if (name !== "set-cookie") result.set(name, value);
130
+ for (const cookie of headers.getSetCookie()) result.append("set-cookie", cookie);
131
+ } catch {}
132
+ }
133
+ return result;
134
+ }
135
+ function rejection(input) {
136
+ const codes = {
137
+ 401: "UNAUTHENTICATED",
138
+ 403: "FORBIDDEN",
139
+ 429: "RATE_LIMITED"
140
+ };
141
+ const messages = {
142
+ 401: "Unauthorized",
143
+ 403: "Forbidden",
144
+ 429: "Too Many Requests"
145
+ };
146
+ const headers = new Headers();
147
+ const retry = input.retryAfterSeconds;
148
+ if (retry !== void 0 && Number.isFinite(retry) && retry >= 0) headers.set("retry-after", String(Math.ceil(retry)));
149
+ return branded({
150
+ status: input.status,
151
+ code: codes[input.status],
152
+ reason: input.reason,
153
+ message: input.message ?? messages[input.status],
154
+ challenge: input.challenge,
155
+ ...headers.has("retry-after") ? { headers } : {}
156
+ }, FAILURE_BRAND);
157
+ }
158
+ const AuthFailures = {
159
+ unauthenticated(message) {
160
+ return rejection({
161
+ status: 401,
162
+ message
163
+ });
164
+ },
165
+ rejected: rejection,
166
+ forbidden(reason, message) {
167
+ return rejection({
168
+ status: 403,
169
+ reason,
170
+ message
171
+ });
172
+ },
173
+ fromAPIError(error) {
174
+ const status = sdkStatus(error);
175
+ if (status !== 401 && status !== 403 && status !== 429) return null;
176
+ const originalHeaders = getAPIErrorHeaders(error);
177
+ const delay = readErrorProperty(readErrorProperty(readErrorProperty(error, "body"), "details"), "tryAgainIn");
178
+ const failure = rejection({
179
+ status,
180
+ reason: sdkReason(error),
181
+ challenge: originalHeaders.get("www-authenticate") ?? void 0,
182
+ retryAfterSeconds: status === 429 && typeof delay === "number" ? delay / 1e3 : void 0
183
+ });
184
+ const retryAfter = originalHeaders.get("retry-after");
185
+ if (retryAfter !== null) {
186
+ const headers = new Headers(failure.headers);
187
+ headers.set("retry-after", retryAfter);
188
+ return branded({
189
+ ...failure,
190
+ headers
191
+ }, FAILURE_BRAND);
192
+ }
193
+ return failure;
194
+ }
195
+ };
196
+ var BetterAuthConfigurationError = class BetterAuthConfigurationError extends Error {
197
+ code;
198
+ detail;
199
+ site;
200
+ hint;
201
+ phase;
202
+ extensions = {
203
+ code: "INTERNAL_SERVER_ERROR",
204
+ reason: "AUTH_MISCONFIGURED",
205
+ statusCode: 500
206
+ };
207
+ issues;
208
+ constructor(code, detail, hint) {
209
+ super(detail);
210
+ this.name = "BetterAuthConfigurationError";
211
+ this.code = code;
212
+ this.detail = detail;
213
+ this.hint = hint;
214
+ this.phase = "boot";
215
+ branded(this, CONFIGURATION_BRAND);
216
+ }
217
+ static atRequest(code, detail, options) {
218
+ const error = new BetterAuthConfigurationError(code, "Authentication is misconfigured", options?.hint);
219
+ Object.defineProperties(error, {
220
+ detail: {
221
+ value: detail,
222
+ enumerable: true
223
+ },
224
+ site: {
225
+ value: options?.site,
226
+ enumerable: true
227
+ },
228
+ phase: {
229
+ value: "request",
230
+ enumerable: true
231
+ }
232
+ });
233
+ return error;
234
+ }
235
+ };
236
+ var BetterAuthInfrastructureError = class extends Error {
237
+ cause;
238
+ extensions = {
239
+ code: "INTERNAL_SERVER_ERROR",
240
+ reason: "AUTH_UNAVAILABLE",
241
+ statusCode: 500
242
+ };
243
+ constructor(cause, options) {
244
+ super("Authentication service unavailable");
245
+ this.name = "BetterAuthInfrastructureError";
246
+ this.cause = new ErrorRedactor(options).redact(cause);
247
+ branded(this, INFRASTRUCTURE_BRAND);
248
+ }
249
+ };
250
+ /** Internal factory for an instance's explicit diagnostic opt-in, never global state. */
251
+ function createInfrastructureError(cause, options) {
252
+ const error = new BetterAuthInfrastructureError(cause, options);
253
+ if (options?.exposeRawCause === true) Object.defineProperty(error, RAW_CAUSE, {
254
+ value: cause,
255
+ enumerable: false
256
+ });
257
+ return error;
258
+ }
259
+ function getRawCause(error) {
260
+ return readErrorProperty(error, RAW_CAUSE);
261
+ }
262
+ /** Internal safety net. Evaluation performs the authoritative session-loss recheck. */
263
+ function normalizeThrown(error, where, site, secrets, options) {
264
+ if (isAuthFailure(error)) return error;
265
+ if (isInfrastructureError(error) || isConfigurationError(error)) throw error;
266
+ const status = sdkStatus(error);
267
+ const reason = sdkReason(error);
268
+ if (status === 429) return AuthFailures.fromAPIError(error);
269
+ if (status === 401 && where === "policy" && (reason === void 0 || reason === "UNAUTHORIZED")) return {
270
+ sessionLoss: error,
271
+ reason
272
+ };
273
+ if (status === 401 || status === 403) return where === "source" ? AuthFailures.fromAPIError(error) : AuthFailures.forbidden(reason ?? "FORBIDDEN");
274
+ if (status !== void 0 && status < 500) throw BetterAuthConfigurationError.atRequest("BETTER_AUTH_REJECTED_CALL", `better-auth rejected the library's call (${status} ${reason})`, { site });
275
+ throw createInfrastructureError(error, {
276
+ secrets,
277
+ exposeRawCause: options?.exposeRawCause
278
+ });
279
+ }
280
+ //#endregion
281
+ Object.defineProperty(exports, "AuthFailures", {
282
+ enumerable: true,
283
+ get: function() {
284
+ return AuthFailures;
285
+ }
286
+ });
287
+ Object.defineProperty(exports, "BetterAuthConfigurationError", {
288
+ enumerable: true,
289
+ get: function() {
290
+ return BetterAuthConfigurationError;
291
+ }
292
+ });
293
+ Object.defineProperty(exports, "BetterAuthInfrastructureError", {
294
+ enumerable: true,
295
+ get: function() {
296
+ return BetterAuthInfrastructureError;
297
+ }
298
+ });
299
+ Object.defineProperty(exports, "ErrorRedactor", {
300
+ enumerable: true,
301
+ get: function() {
302
+ return ErrorRedactor;
303
+ }
304
+ });
305
+ Object.defineProperty(exports, "createInfrastructureError", {
306
+ enumerable: true,
307
+ get: function() {
308
+ return createInfrastructureError;
309
+ }
310
+ });
311
+ Object.defineProperty(exports, "getAPIErrorHeaders", {
312
+ enumerable: true,
313
+ get: function() {
314
+ return getAPIErrorHeaders;
315
+ }
316
+ });
317
+ Object.defineProperty(exports, "getRawCause", {
318
+ enumerable: true,
319
+ get: function() {
320
+ return getRawCause;
321
+ }
322
+ });
323
+ Object.defineProperty(exports, "isAuthFailure", {
324
+ enumerable: true,
325
+ get: function() {
326
+ return isAuthFailure;
327
+ }
328
+ });
329
+ Object.defineProperty(exports, "isConfigurationError", {
330
+ enumerable: true,
331
+ get: function() {
332
+ return isConfigurationError;
333
+ }
334
+ });
335
+ Object.defineProperty(exports, "isInfrastructureError", {
336
+ enumerable: true,
337
+ get: function() {
338
+ return isInfrastructureError;
339
+ }
340
+ });
341
+ Object.defineProperty(exports, "normalizeThrown", {
342
+ enumerable: true,
343
+ get: function() {
344
+ return normalizeThrown;
345
+ }
346
+ });
347
+
348
+ //# sourceMappingURL=auth-errors-CsERBNWI.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-errors-CsERBNWI.cjs","names":["isAPIError"],"sources":["../src/error-redactor.ts","../src/auth-errors.ts"],"sourcesContent":["/** Inputs come from the active request's owner; the redactor retains no scope. */\nexport interface ErrorRedactorOptions {\n secrets?: readonly string[];\n headers?: Headers;\n credentialHeaders?: readonly string[];\n}\n\n/** Reading an arbitrary thrown value must not invoke another escaping fault. */\nexport function readErrorProperty(value: unknown, key: PropertyKey): unknown {\n if (\n (typeof value !== \"object\" || value === null) &&\n typeof value !== \"function\"\n ) {\n return undefined;\n }\n try {\n return Reflect.get(value, key);\n } catch {\n return undefined;\n }\n}\n\nexport class ErrorRedactor {\n readonly #secrets: readonly string[];\n\n constructor(options: ErrorRedactorOptions = {}) {\n const values = new Set<string>();\n const add = (value: string) => {\n if (!value) {\n return;\n }\n values.add(value);\n let decoded = value;\n try {\n decoded = decodeURIComponent(value);\n values.add(decoded);\n } catch {\n // Invalid escaping must not prevent redaction of the raw credential.\n }\n for (const form of [value, decoded]) {\n const separator = form.lastIndexOf(\".\");\n if (separator >= 16) {\n values.add(form.slice(0, separator));\n }\n }\n };\n for (const value of options.secrets ?? []) {\n add(value);\n }\n const headers = options.headers;\n for (const cookie of (headers?.get(\"cookie\") ?? \"\").split(\";\")) {\n const separator = cookie.indexOf(\"=\");\n if (separator >= 0) {\n const value = cookie.slice(separator + 1).trim();\n add(value);\n if (value.startsWith('\"') && value.endsWith('\"')) {\n add(value.slice(1, -1));\n }\n }\n }\n const authorization = headers?.get(\"authorization\");\n if (authorization) {\n add(authorization);\n const credential = /^\\S+\\s+(.+)$/.exec(authorization)?.[1];\n if (credential) {\n add(credential);\n }\n }\n for (const name of options.credentialHeaders ?? []) {\n const value = headers?.get(name);\n if (value) {\n add(value);\n }\n }\n this.#secrets = [...values].sort(\n (left, right) => right.length - left.length,\n );\n }\n\n redact(cause: unknown): Error {\n return this.redactCause(cause, 0, new Set());\n }\n\n private replaceSecrets(value: string): string {\n for (const secret of this.#secrets) {\n value = value.split(secret).join(\"[REDACTED]\");\n }\n return value;\n }\n\n private diagnostic(value: string): string {\n return this.replaceSecrets(value)\n .split(/[\\r\\n]/, 1)[0]\n .slice(0, 300);\n }\n\n private redactCause(\n cause: unknown,\n depth: number,\n seen: Set<unknown>,\n ): Error {\n const message = readErrorProperty(cause, \"message\");\n const error = new Error(\n this.diagnostic(\n typeof message === \"string\"\n ? message\n : typeof cause === \"string\"\n ? cause\n : \"Unknown authentication infrastructure failure\",\n ),\n );\n const name = readErrorProperty(cause, \"name\");\n error.name = typeof name === \"string\" ? this.diagnostic(name) : \"Error\";\n for (const key of [\"code\", \"errno\", \"syscall\"] as const) {\n const value = readErrorProperty(cause, key);\n if (\n typeof value === \"string\" ||\n (typeof value === \"number\" && Number.isFinite(value))\n ) {\n Object.defineProperty(error, key, {\n value: typeof value === \"string\" ? this.diagnostic(value) : value,\n enumerable: true,\n });\n }\n }\n const stack = readErrorProperty(cause, \"stack\");\n const frames =\n typeof stack === \"string\"\n ? stack\n .split(/\\r?\\n/)\n .filter((line) => /^\\s+at .+:\\d+:\\d+\\)?$/.test(line))\n .map((line) => this.replaceSecrets(line))\n : [];\n error.stack = [`${error.name}: ${error.message}`, ...frames].join(\"\\n\");\n seen.add(cause);\n const nested = readErrorProperty(cause, \"cause\");\n if (nested !== undefined && depth < 3 && !seen.has(nested)) {\n Object.defineProperty(error, \"cause\", {\n value: this.redactCause(nested, depth + 1, seen),\n enumerable: false,\n });\n }\n return error;\n }\n}\n","import type { ExecutionContext } from \"@nestjs/common\";\nimport { isAPIError } from \"better-auth/api\";\nimport {\n ErrorRedactor,\n type ErrorRedactorOptions,\n readErrorProperty,\n} from \"./error-redactor.js\";\n\nconst FAILURE_BRAND = Symbol.for(\"nestjs-slightly-better-auth:auth-failure\");\nconst INFRASTRUCTURE_BRAND = Symbol.for(\n \"nestjs-slightly-better-auth:infrastructure-error\",\n);\nconst CONFIGURATION_BRAND = Symbol.for(\n \"nestjs-slightly-better-auth:configuration-error\",\n);\nconst RAW_CAUSE = Symbol.for(\"nestjs-slightly-better-auth:raw-cause\");\nconst SDK_HEADERS = Symbol.for(\"better-call:api-error-headers\");\n\nexport type AuthErrorCode = \"UNAUTHENTICATED\" | \"FORBIDDEN\" | \"RATE_LIMITED\";\n\n/** A transport-neutral denial. Only transports make it throwable. */\nexport interface AuthFailure {\n readonly status: 401 | 403 | 429;\n readonly code: AuthErrorCode;\n readonly reason?: string;\n readonly message: string;\n readonly challenge?: string;\n readonly headers?: Headers;\n}\n\nexport interface AuthErrorBody {\n statusCode: 401 | 403 | 429;\n error: string;\n code: AuthErrorCode;\n reason?: string;\n message: string;\n}\n\nexport interface AuthGraphqlExtensions {\n code: AuthErrorCode | \"INTERNAL_SERVER_ERROR\";\n reason?: string;\n statusCode: number;\n}\n\nexport interface AuthTransportErrorPayload {\n status: \"error\";\n statusCode: number;\n code: AuthErrorCode;\n reason?: string;\n message: string;\n}\n\nexport interface ErrorMappingOptions {\n map?: (\n failure: AuthFailure,\n context: ExecutionContext,\n transport: string,\n ) => unknown;\n exposeRawCause?: boolean;\n}\n\nfunction branded<T extends object>(value: T, brand: symbol): T {\n Object.defineProperty(value, brand, { value: true });\n return value;\n}\n\nexport function isAuthFailure(value: unknown): value is AuthFailure {\n return readErrorProperty(value, FAILURE_BRAND) === true;\n}\n\nexport function isInfrastructureError(\n value: unknown,\n): value is BetterAuthInfrastructureError {\n return readErrorProperty(value, INFRASTRUCTURE_BRAND) === true;\n}\n\nexport function isConfigurationError(\n value: unknown,\n): value is BetterAuthConfigurationError {\n return readErrorProperty(value, CONFIGURATION_BRAND) === true;\n}\n\nfunction sdkStatus(error: unknown): number | undefined {\n try {\n if (!isAPIError(error)) {\n return undefined;\n }\n const status = readErrorProperty(error, \"statusCode\");\n return typeof status === \"number\" &&\n Number.isInteger(status) &&\n status >= 100 &&\n status <= 599\n ? status\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction sdkReason(error: unknown): string | undefined {\n const reason = readErrorProperty(readErrorProperty(error, \"body\"), \"code\");\n return typeof reason === \"string\" ? reason : undefined;\n}\n\n/** Internal: preserve cookie lines for the exchange's separately governed cleanup. */\nexport function getAPIErrorHeaders(error: unknown): Headers {\n const result = new Headers();\n for (const value of [\n readErrorProperty(error, SDK_HEADERS),\n readErrorProperty(error, \"headers\"),\n ]) {\n if (value === undefined || value === null) {\n continue;\n }\n try {\n const headers = new Headers(value as HeadersInit);\n for (const [name, value] of headers) {\n if (name !== \"set-cookie\") {\n result.set(name, value);\n }\n }\n for (const cookie of headers.getSetCookie()) {\n result.append(\"set-cookie\", cookie);\n }\n } catch {\n // A malformed optional header collection must not mask the original fault.\n }\n }\n return result;\n}\n\nfunction rejection(input: {\n status: 401 | 403 | 429;\n reason?: string;\n message?: string;\n challenge?: string;\n retryAfterSeconds?: number;\n}): AuthFailure {\n const codes = {\n 401: \"UNAUTHENTICATED\",\n 403: \"FORBIDDEN\",\n 429: \"RATE_LIMITED\",\n } as const;\n const messages = {\n 401: \"Unauthorized\",\n 403: \"Forbidden\",\n 429: \"Too Many Requests\",\n } as const;\n const headers = new Headers();\n const retry = input.retryAfterSeconds;\n if (retry !== undefined && Number.isFinite(retry) && retry >= 0) {\n headers.set(\"retry-after\", String(Math.ceil(retry)));\n }\n return branded(\n {\n status: input.status,\n code: codes[input.status],\n reason: input.reason,\n message: input.message ?? messages[input.status],\n challenge: input.challenge,\n ...(headers.has(\"retry-after\") ? { headers } : {}),\n },\n FAILURE_BRAND,\n );\n}\n\nexport const AuthFailures = {\n unauthenticated(message?: string): AuthFailure {\n return rejection({ status: 401, message });\n },\n rejected: rejection,\n forbidden(reason: string, message?: string): AuthFailure {\n return rejection({ status: 403, reason, message });\n },\n fromAPIError(error: unknown): AuthFailure | null {\n const status = sdkStatus(error);\n if (status !== 401 && status !== 403 && status !== 429) {\n return null;\n }\n const originalHeaders = getAPIErrorHeaders(error);\n const details = readErrorProperty(\n readErrorProperty(error, \"body\"),\n \"details\",\n );\n const delay = readErrorProperty(details, \"tryAgainIn\");\n const failure = rejection({\n status,\n reason: sdkReason(error),\n challenge: originalHeaders.get(\"www-authenticate\") ?? undefined,\n retryAfterSeconds:\n status === 429 && typeof delay === \"number\" ? delay / 1000 : undefined,\n });\n const retryAfter = originalHeaders.get(\"retry-after\");\n if (retryAfter !== null) {\n const headers = new Headers(failure.headers);\n headers.set(\"retry-after\", retryAfter);\n return branded({ ...failure, headers }, FAILURE_BRAND);\n }\n return failure;\n },\n};\n\nexport class BetterAuthConfigurationError extends Error {\n readonly code: string;\n readonly detail: string;\n readonly site?: string;\n readonly hint?: string;\n readonly phase: \"boot\" | \"request\";\n readonly extensions = {\n code: \"INTERNAL_SERVER_ERROR\",\n reason: \"AUTH_MISCONFIGURED\",\n statusCode: 500,\n } as const;\n readonly issues?: readonly BetterAuthConfigurationError[];\n\n constructor(code: string, detail: string, hint?: string) {\n super(detail);\n this.name = \"BetterAuthConfigurationError\";\n this.code = code;\n this.detail = detail;\n this.hint = hint;\n this.phase = \"boot\";\n branded(this, CONFIGURATION_BRAND);\n }\n\n static atRequest(\n code: string,\n detail: string,\n options?: { site?: string; hint?: string },\n ): BetterAuthConfigurationError {\n const error = new BetterAuthConfigurationError(\n code,\n \"Authentication is misconfigured\",\n options?.hint,\n );\n Object.defineProperties(error, {\n detail: { value: detail, enumerable: true },\n site: { value: options?.site, enumerable: true },\n phase: { value: \"request\", enumerable: true },\n });\n return error;\n }\n}\n\nexport class BetterAuthInfrastructureError extends Error {\n readonly cause: Error;\n readonly extensions = {\n code: \"INTERNAL_SERVER_ERROR\",\n reason: \"AUTH_UNAVAILABLE\",\n statusCode: 500,\n } as const;\n\n constructor(cause: unknown, options?: { secrets?: readonly string[] }) {\n super(\"Authentication service unavailable\");\n this.name = \"BetterAuthInfrastructureError\";\n this.cause = new ErrorRedactor(options).redact(cause);\n branded(this, INFRASTRUCTURE_BRAND);\n }\n}\n\n/** Internal factory for an instance's explicit diagnostic opt-in, never global state. */\nexport function createInfrastructureError(\n cause: unknown,\n options?: ErrorRedactorOptions & { exposeRawCause?: boolean },\n): BetterAuthInfrastructureError {\n // Preserve request-owned redaction inputs without widening the public constructor.\n const error = new BetterAuthInfrastructureError(cause, options);\n if (options?.exposeRawCause === true) {\n Object.defineProperty(error, RAW_CAUSE, {\n value: cause,\n enumerable: false,\n });\n }\n return error;\n}\n\nexport function getRawCause(error: BetterAuthInfrastructureError): unknown {\n return readErrorProperty(error, RAW_CAUSE);\n}\n\n/** Internal: evaluation must distinguish session loss from a failed session read. */\nexport interface SessionLossCandidate {\n readonly sessionLoss: unknown;\n readonly reason?: string;\n}\n\n/** Internal safety net. Evaluation performs the authoritative session-loss recheck. */\nexport function normalizeThrown(\n error: unknown,\n where: \"source\" | \"policy\",\n site: string,\n secrets: readonly string[],\n options?: { exposeRawCause?: boolean },\n): AuthFailure | SessionLossCandidate {\n if (isAuthFailure(error)) {\n return error;\n }\n if (isInfrastructureError(error) || isConfigurationError(error)) {\n throw error;\n }\n const status = sdkStatus(error);\n const reason = sdkReason(error);\n if (status === 429) {\n return AuthFailures.fromAPIError(error)!;\n }\n if (\n status === 401 &&\n where === \"policy\" &&\n (reason === undefined || reason === \"UNAUTHORIZED\")\n ) {\n return { sessionLoss: error, reason };\n }\n if (status === 401 || status === 403) {\n return where === \"source\"\n ? AuthFailures.fromAPIError(error)!\n : AuthFailures.forbidden(reason ?? \"FORBIDDEN\");\n }\n if (status !== undefined && status < 500) {\n throw BetterAuthConfigurationError.atRequest(\n \"BETTER_AUTH_REJECTED_CALL\",\n `better-auth rejected the library's call (${status} ${reason})`,\n { site },\n );\n }\n throw createInfrastructureError(error, {\n secrets,\n exposeRawCause: options?.exposeRawCause,\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,247 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_auth_errors = require("./auth-errors-CsERBNWI.cjs");
3
+ const require_platform = require("./platform.cjs");
4
+ let path_to_regexp = require("path-to-regexp");
5
+ //#region src/express-platform.ts
6
+ const RAW_BODY = Symbol.for("nestjs-slightly-better-auth:raw-body");
7
+ function application(adapter) {
8
+ return adapter.getInstance();
9
+ }
10
+ function routerOptions(app) {
11
+ const router = app?.router;
12
+ if (typeof router !== "object" && typeof router !== "function" || router === null) throw new require_auth_errors.BetterAuthConfigurationError("UNSUPPORTED_EXPRESS_ROUTER", "The Express application does not expose its initialized router.", "Use Express 5.2.x with @nestjs/platform-express 12.x, or move controller routes outside the auth mount.");
13
+ const options = router;
14
+ if (typeof options.caseSensitive !== "boolean" || typeof options.strict !== "boolean") throw new require_auth_errors.BetterAuthConfigurationError("UNSUPPORTED_EXPRESS_ROUTER", "The initialized Express router does not expose compatible routing options.", "Use Express 5.2.x with @nestjs/platform-express 12.x, or move controller routes outside the auth mount.");
15
+ return {
16
+ caseSensitive: options.caseSensitive,
17
+ strict: options.strict
18
+ };
19
+ }
20
+ function routeMayOverlapMount(path, basePath) {
21
+ const tokens = (0, path_to_regexp.parse)(path).tokens;
22
+ let literalPrefix = "";
23
+ let dynamic = false;
24
+ for (const token of tokens) {
25
+ if (token.type !== "text") {
26
+ dynamic = true;
27
+ break;
28
+ }
29
+ literalPrefix += token.value;
30
+ }
31
+ const route = literalPrefix.toLowerCase();
32
+ const base = basePath.toLowerCase().replace(/(?<!\/)\/+$/, "") || "/";
33
+ if (base === "/") return route.startsWith("/");
34
+ if (!dynamic) {
35
+ const exact = route.replace(/(?<!\/)\/+$/, "") || "/";
36
+ return exact === base || exact.startsWith(`${base}/`);
37
+ }
38
+ if (base.startsWith(route)) return true;
39
+ return route === base || route.startsWith(`${base}/`);
40
+ }
41
+ function rawTarget(req) {
42
+ return req.originalUrl ?? req.url ?? "/";
43
+ }
44
+ function rawPath(req) {
45
+ const target = rawTarget(req);
46
+ const query = target.indexOf("?");
47
+ return query === -1 ? target : target.slice(0, query);
48
+ }
49
+ function declaredLength(headers, limit) {
50
+ const value = headers["content-length"];
51
+ const first = Array.isArray(value) ? value[0] : value;
52
+ if (typeof first !== "string" || !/^\d+$/.test(first)) return;
53
+ const parsed = Number(first);
54
+ return Number.isSafeInteger(parsed) ? parsed : limit + 1;
55
+ }
56
+ function requestUrl(req) {
57
+ const socket = req.socket;
58
+ return `${req.protocol ?? (socket.encrypted ? "https" : "http")}://${req.host ?? ""}${rawTarget(req)}`;
59
+ }
60
+ function isExpressRequest(value) {
61
+ if (typeof value !== "object" || value === null) return false;
62
+ const req = value;
63
+ return typeof req.method === "string" && typeof req.headers === "object" && typeof req.res === "object" && req.res !== null && (req.res.req === void 0 || req.res.req === value);
64
+ }
65
+ function nativeResponse(value) {
66
+ if (typeof value !== "object" || value === null) return null;
67
+ const response = value;
68
+ return typeof response.setHeader === "function" && typeof response.getHeader === "function" ? value : null;
69
+ }
70
+ function proxyTrustOf(value) {
71
+ if (value === false || value === void 0) return {
72
+ mode: "none",
73
+ detail: "trust proxy = false"
74
+ };
75
+ if (value === true) return {
76
+ mode: "all",
77
+ detail: "trust proxy = true"
78
+ };
79
+ return {
80
+ mode: "partial",
81
+ detail: `trust proxy = ${typeof value === "function" ? "<function>" : Array.isArray(value) ? JSON.stringify(value) : String(value)}`
82
+ };
83
+ }
84
+ function abortOnDisconnect(req, res) {
85
+ const controller = new AbortController();
86
+ const abort = () => controller.abort();
87
+ req.once("aborted", abort);
88
+ res.once("close", abort);
89
+ if (req.aborted || res.destroyed) abort();
90
+ return {
91
+ signal: controller.signal,
92
+ dispose: () => {
93
+ req.removeListener("aborted", abort);
94
+ res.removeListener("close", abort);
95
+ }
96
+ };
97
+ }
98
+ /** Express-specific two-phase HTTP integration. */
99
+ var ExpressPlatform = class {
100
+ options;
101
+ id = "express";
102
+ #warnedConsumedBody = false;
103
+ #applicationRoutes = [];
104
+ #application;
105
+ constructor(options = {}) {
106
+ this.options = options;
107
+ }
108
+ requests = {
109
+ isRequest: (value) => isExpressRequest(value),
110
+ isLive: (value) => isExpressRequest(value) && value.res?.writableEnded === false,
111
+ key: (value) => value,
112
+ headers: (value) => require_platform.toWebHeaders(value.headers),
113
+ request: (value) => {
114
+ const req = value;
115
+ return {
116
+ method: req.method ?? "GET",
117
+ url: requestUrl(req)
118
+ };
119
+ },
120
+ clientIp: (value) => this.clientIp(value),
121
+ param: (value, name) => {
122
+ const parameter = value.params?.[name];
123
+ return typeof parameter === "string" ? parameter : void 0;
124
+ },
125
+ cookieSink: (request, response) => {
126
+ const req = request;
127
+ const res = nativeResponse(response) ?? nativeResponse(req.res);
128
+ return res === null ? null : { append: (cookies) => require_platform.appendSetCookie(res, cookies) };
129
+ }
130
+ };
131
+ supports(adapter) {
132
+ return adapter.getType?.() === "express";
133
+ }
134
+ prepare(ctx) {
135
+ const app = application(ctx.adapter);
136
+ this.#application = app;
137
+ app.use((req, _res, next) => {
138
+ const binding = ctx.route(rawPath(req));
139
+ const method = (req.method ?? "GET").toUpperCase();
140
+ if (!binding || this.isApplicationRoute(method, rawPath(req)) || method === "GET" || method === "HEAD" || method === "OPTIONS" || !require_platform.mayHaveBody(method, req.headers)) {
141
+ next();
142
+ return;
143
+ }
144
+ const continueRequest = require_platform.bindAsyncContext(next);
145
+ if (req.readableEnded || req.readable === false) {
146
+ const recovered = require_platform.recoverConsumedBody(req);
147
+ req[RAW_BODY] = {
148
+ ok: true,
149
+ bytes: recovered ?? /* @__PURE__ */ new Uint8Array()
150
+ };
151
+ if (!this.#warnedConsumedBody) {
152
+ this.#warnedConsumedBody = true;
153
+ ctx.logger.warn("W_BODY_ALREADY_CONSUMED: an Express body parser ran before the auth capture; raw-signature webhooks may receive re-serialized bytes.");
154
+ }
155
+ continueRequest();
156
+ return;
157
+ }
158
+ require_platform.readBoundedBody(req, {
159
+ limit: binding.bodyLimit,
160
+ declaredLength: declaredLength(req.headers, binding.bodyLimit),
161
+ drainOnOverflow: true,
162
+ drainCap: Math.min(Number.MAX_SAFE_INTEGER, binding.bodyLimit * 8)
163
+ }).then((captured) => {
164
+ req[RAW_BODY] = captured;
165
+ continueRequest();
166
+ }, (error) => continueRequest(error));
167
+ });
168
+ }
169
+ applicationRoutes(routes, bindings) {
170
+ const bodyRoutes = routes.flatMap((route) => {
171
+ if ([
172
+ "GET",
173
+ "HEAD",
174
+ "OPTIONS"
175
+ ].includes(route.method)) return [];
176
+ const paths = route.paths.filter((path) => bindings.some((binding) => routeMayOverlapMount(path, binding.basePath)));
177
+ return paths.length ? [{
178
+ ...route,
179
+ paths
180
+ }] : [];
181
+ });
182
+ const conditional = bodyRoutes.find((route) => route.conditions.length > 0);
183
+ if (conditional) throw new require_auth_errors.BetterAuthConfigurationError("CONDITIONAL_ROUTE_SHADOW", `${conditional.source} at '${conditional.paths.join(", ")}' uses ${conditional.conditions.join(" and ")} routing under an auth mount.`, "Move the controller route outside the auth mount or make its host and version routing unconditional.");
184
+ if (bodyRoutes.length === 0) {
185
+ this.#applicationRoutes = [];
186
+ return;
187
+ }
188
+ const { caseSensitive, strict } = routerOptions(this.#application);
189
+ this.#applicationRoutes = Object.freeze(bodyRoutes.flatMap((route) => route.paths.map((path) => ({
190
+ method: route.method,
191
+ regexp: (0, path_to_regexp.pathToRegexp)(path, {
192
+ end: true,
193
+ sensitive: caseSensitive,
194
+ trailing: !strict
195
+ }).regexp
196
+ }))));
197
+ }
198
+ mount(ctx) {
199
+ application(ctx.adapter).use((req, res, next) => {
200
+ if (!ctx.binding.matches(rawPath(req))) {
201
+ next();
202
+ return;
203
+ }
204
+ const disconnect = abortOnDisconnect(req, res);
205
+ this.dispatch(ctx.binding, req, res, disconnect.signal).then(() => disconnect.dispose(), (error) => {
206
+ disconnect.dispose();
207
+ if (!disconnect.signal.aborted) next(error);
208
+ });
209
+ });
210
+ }
211
+ proxyTrust(adapter) {
212
+ return proxyTrustOf(application(adapter).get("trust proxy"));
213
+ }
214
+ clientIp(req) {
215
+ if (this.options.clientIp) return this.options.clientIp(req);
216
+ return req.ip ?? null;
217
+ }
218
+ isApplicationRoute(method, pathname) {
219
+ return this.#applicationRoutes.some((route) => (route.method === "ALL" || route.method === method) && route.regexp.test(pathname));
220
+ }
221
+ async dispatch(binding, req, res, signal) {
222
+ const captured = req[RAW_BODY];
223
+ if (captured && !captured.ok && captured.reason === "aborted" || signal.aborted) return;
224
+ const response = captured && !captured.ok && captured.reason === "too-large" ? binding.payloadTooLarge() : await binding.handle({
225
+ method: req.method ?? "GET",
226
+ url: requestUrl(req),
227
+ headers: require_platform.toWebHeaders(req.headers),
228
+ body: captured?.ok ? captured.bytes : null,
229
+ clientIp: this.clientIp(req),
230
+ platformRequest: req,
231
+ signal
232
+ });
233
+ if (signal.aborted) {
234
+ await response.body?.cancel().catch(() => void 0);
235
+ return;
236
+ }
237
+ await require_platform.writeWebResponse(res, response, { head: req.method?.toUpperCase() === "HEAD" });
238
+ }
239
+ };
240
+ function expressPlatform(options) {
241
+ return new ExpressPlatform(options);
242
+ }
243
+ //#endregion
244
+ exports.ExpressPlatform = ExpressPlatform;
245
+ exports.expressPlatform = expressPlatform;
246
+
247
+ //# sourceMappingURL=express.cjs.map