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,849 @@
1
+ import { c as isConfigurationError, i as createInfrastructureError, l as isInfrastructureError, n as BetterAuthConfigurationError, s as isAuthFailure, t as AuthFailures, u as normalizeThrown } from "./auth-errors-CQjfgjaO.mjs";
2
+ import { Inject, Injectable, SetMetadata, UseGuards, UseInterceptors, applyDecorators, createParamDecorator } from "@nestjs/common";
3
+ import { Observable } from "rxjs";
4
+ import { AsyncLocalStorage } from "node:async_hooks";
5
+ import { IntrinsicException } from "@nestjs/common/exceptions/intrinsic.exception.js";
6
+ //#region src/auth-tokens.ts
7
+ /** Stable Nest injection tokens shared by every package copy and module format. */
8
+ function instanceToken(base, alias) {
9
+ return alias === void 0 || alias === "" || alias === "default" ? base : `${base}_${alias}`;
10
+ }
11
+ function getBetterAuthInstanceToken(alias) {
12
+ return instanceToken("NESTJS_SLIGHTLY_BETTER_AUTH_INSTANCE", alias);
13
+ }
14
+ function getBetterAuthOptionsToken(alias) {
15
+ return instanceToken("NESTJS_SLIGHTLY_BETTER_AUTH_OPTIONS", alias);
16
+ }
17
+ function getBetterAuthServiceToken(alias) {
18
+ return instanceToken("NESTJS_SLIGHTLY_BETTER_AUTH_SERVICE", alias);
19
+ }
20
+ function getBetterAuthHandleToken(alias) {
21
+ return instanceToken("NESTJS_SLIGHTLY_BETTER_AUTH_HANDLE", alias);
22
+ }
23
+ const INSTANCE_REGISTRY = Symbol.for("nestjs-slightly-better-auth:instance-registry");
24
+ const REQUEST_SCOPE = Symbol.for("nestjs-slightly-better-auth:request-scope");
25
+ const PRINCIPAL_READINGS = Symbol.for("nestjs-slightly-better-auth:principal-readings");
26
+ const ROUTE_PLANNER = Symbol.for("nestjs-slightly-better-auth:route-planner");
27
+ const TRANSPORT_REGISTRY = Symbol.for("nestjs-slightly-better-auth:transport-registry");
28
+ const POLICY_RESOLVER = Symbol.for("nestjs-slightly-better-auth:policy-resolver");
29
+ const MOUNT_COORDINATOR = Symbol.for("nestjs-slightly-better-auth:mount-coordinator");
30
+ const GUARD_CORE = Symbol.for("nestjs-slightly-better-auth:guard-core");
31
+ const SCOPE_CORE = Symbol.for("nestjs-slightly-better-auth:scope-core");
32
+ const PRINCIPAL_RESOLVER = Symbol.for("nestjs-slightly-better-auth:principal-resolver");
33
+ const POLICY_INVOKER = Symbol.for("nestjs-slightly-better-auth:policy-invoker");
34
+ const PLATFORMS = Symbol.for("nestjs-slightly-better-auth:platforms");
35
+ const TRANSPORTS = Symbol.for("nestjs-slightly-better-auth:transports");
36
+ const ACCESS_METADATA = Symbol.for("nestjs-slightly-better-auth:access");
37
+ const ACCEPT_PRINCIPALS_METADATA = Symbol.for("nestjs-slightly-better-auth:accept-principals");
38
+ const REQUIREMENTS_METADATA = Symbol.for("nestjs-slightly-better-auth:requirements");
39
+ const SKIP_DEFAULT_REQUIREMENTS_METADATA = Symbol.for("nestjs-slightly-better-auth:skip-default-requirements");
40
+ const FRESHNESS_METADATA = Symbol.for("nestjs-slightly-better-auth:freshness");
41
+ const AUTH_INSTANCE_METADATA = Symbol.for("nestjs-slightly-better-auth:auth-instance");
42
+ const PRINCIPAL_PARAMS_METADATA = Symbol.for("nestjs-slightly-better-auth:principal-params");
43
+ const INVOCATION_PARAMS_METADATA = Symbol.for("nestjs-slightly-better-auth:invocation-params");
44
+ const FORWARD_COOKIES_METADATA = Symbol.for("nestjs-slightly-better-auth:forward-cookies");
45
+ const SKIP_ORIGIN_CHECK_METADATA = Symbol.for("nestjs-slightly-better-auth:skip-origin-check");
46
+ const USE_BETTER_AUTH_METADATA = Symbol.for("nestjs-slightly-better-auth:use-better-auth");
47
+ const HOOK_METADATA = Symbol.for("nestjs-slightly-better-auth:hook");
48
+ const DB_HOOK_METADATA = Symbol.for("nestjs-slightly-better-auth:db-hook");
49
+ const AUTH_ENHANCER = Symbol.for("nestjs-slightly-better-auth:enhancer");
50
+ function getPrincipalSourcesToken(instance) {
51
+ return Symbol.for(`nestjs-slightly-better-auth:principal-sources:${instance}`);
52
+ }
53
+ function getExtensionToken(point, instance, index) {
54
+ return Symbol.for(`nestjs-slightly-better-auth:ext:${point}:${instance}:${index}`);
55
+ }
56
+ const READER_CONTEXT = Symbol.for("nestjs-slightly-better-auth:reader-context");
57
+ const INVOCATION_VALUES = Symbol.for("nestjs-slightly-better-auth:invocation");
58
+ //#endregion
59
+ //#region src/principal-resolver.ts
60
+ const definePrincipalSource = (source) => source;
61
+ const authenticated = (principal) => ({
62
+ outcome: "authenticated",
63
+ principal
64
+ });
65
+ const absent = () => ({ outcome: "absent" });
66
+ const rejected = (failure) => ({
67
+ outcome: "rejected",
68
+ failure
69
+ });
70
+ var MemoKeys = class {
71
+ owners = /* @__PURE__ */ new WeakMap();
72
+ key(owner, namespace, value) {
73
+ if (typeof value === "string") return JSON.stringify([
74
+ namespace,
75
+ "string",
76
+ value
77
+ ]);
78
+ let identities = this.owners.get(owner);
79
+ if (!identities) {
80
+ identities = {
81
+ objects: /* @__PURE__ */ new WeakMap(),
82
+ symbols: /* @__PURE__ */ new Map(),
83
+ next: 0
84
+ };
85
+ this.owners.set(owner, identities);
86
+ }
87
+ let id = typeof value === "symbol" ? identities.symbols.get(value) : identities.objects.get(value);
88
+ if (id === void 0) {
89
+ id = ++identities.next;
90
+ if (typeof value === "symbol") identities.symbols.set(value, id);
91
+ else identities.objects.set(value, id);
92
+ }
93
+ return JSON.stringify([
94
+ namespace,
95
+ typeof value,
96
+ id
97
+ ]);
98
+ }
99
+ };
100
+ function requestHeaders(call, entry) {
101
+ const headers = new Headers(call.headers());
102
+ for (const name of [...headers.keys()]) if (name.startsWith(":") || name.startsWith("x-nsba-ip-") || name === entry.bridge.clientIpHeader) headers.delete(name);
103
+ if (entry.bridge.clientIpHeader && call.clientIp) headers.set(entry.bridge.clientIpHeader, call.clientIp);
104
+ return headers;
105
+ }
106
+ function normalizeForRequest(error, where, site, entry, headers) {
107
+ try {
108
+ return normalizeThrown(error, where, site, [], entry.options.errors);
109
+ } catch (normalized) {
110
+ if (isConfigurationError(normalized) || isInfrastructureError(error) && normalized === error) throw normalized;
111
+ throw createInfrastructureError(error, {
112
+ headers,
113
+ credentialHeaders: entry.credentialHeaders,
114
+ exposeRawCause: entry.options.errors?.exposeRawCause
115
+ });
116
+ }
117
+ }
118
+ var ChainPrincipalResolver = class {
119
+ instances;
120
+ scope;
121
+ transports;
122
+ keys = new MemoKeys();
123
+ constructor(instances, scope, transports) {
124
+ this.instances = instances;
125
+ this.scope = scope;
126
+ this.transports = transports;
127
+ }
128
+ resolve(call, request) {
129
+ const entry = this.instances.get(request.auth.name);
130
+ const compute = async () => {
131
+ const headers = requestHeaders(call, entry);
132
+ const sources = request.reclassify ? entry.sources.filter((source) => source.id === request.reclassify.sourceId && source.sessionBacked) : entry.sources.filter((source) => source.kinds.some((kind) => request.accepts.has(kind)));
133
+ return request.auth.run({
134
+ cookies: call.cookies,
135
+ forward: "same-credential",
136
+ inbound: () => headers,
137
+ internal: true
138
+ }, async () => {
139
+ for (const source of sources) {
140
+ const input = {
141
+ headers,
142
+ cookies: call.cookies,
143
+ transport: this.transports.idOf(call),
144
+ request: call.request,
145
+ freshness: request.freshness,
146
+ auth: request.auth,
147
+ memo: (key, fn) => this.scope.memoPolicyIo(call.key, entry.name, this.keys.key(call.key, `source:${source.id}`, key), fn, entry.options.limits?.maxAuthorizationCallsPerRequest)
148
+ };
149
+ try {
150
+ if (source.appliesTo && !source.appliesTo(input)) continue;
151
+ const result = await source.resolve(input);
152
+ if (result.outcome === "authenticated" && (!source.kinds.includes(result.principal.kind) || result.principal.source !== source.id || Boolean(result.principal.delegation) !== Boolean(source.delegates))) throw new Error(`Principal source ${source.id} violated its declared principal contract`);
153
+ if (result.outcome !== "absent") return result;
154
+ } catch (error) {
155
+ const failure = normalizeForRequest(error, "source", source.id, entry, headers);
156
+ if (isAuthFailure(failure)) return rejected(failure);
157
+ throw error;
158
+ }
159
+ }
160
+ return absent();
161
+ });
162
+ };
163
+ return request.reclassify ? compute() : this.scope.memoPrincipal(call, {
164
+ instance: entry.name,
165
+ freshness: request.freshness,
166
+ sourceSet: request.sourceSet
167
+ }, compute);
168
+ }
169
+ };
170
+ //#endregion
171
+ //#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorateMetadata.js
172
+ function __decorateMetadata(k, v) {
173
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
174
+ }
175
+ //#endregion
176
+ //#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorateParam.js
177
+ function __decorateParam(paramIndex, decorator) {
178
+ return function(target, key) {
179
+ decorator(target, key, paramIndex);
180
+ };
181
+ }
182
+ //#endregion
183
+ //#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorate.js
184
+ function __decorate(decorators, target, key, desc) {
185
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
186
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
187
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
188
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
189
+ }
190
+ //#endregion
191
+ //#region src/auth-guard.ts
192
+ let BetterAuthGuard = class BetterAuthGuard {
193
+ core;
194
+ static [AUTH_ENHANCER] = "guard";
195
+ [AUTH_ENHANCER] = "guard";
196
+ constructor(core) {
197
+ this.core = core;
198
+ }
199
+ canActivate(context) {
200
+ return this.core.canActivate(context);
201
+ }
202
+ };
203
+ BetterAuthGuard = __decorate([
204
+ Injectable(),
205
+ __decorateParam(0, Inject(GUARD_CORE)),
206
+ __decorateMetadata("design:paramtypes", [typeof Pick === "undefined" ? Object : Pick])
207
+ ], BetterAuthGuard);
208
+ var GuardCore = class {
209
+ instances;
210
+ planner;
211
+ transports;
212
+ resolver;
213
+ evaluator;
214
+ scope;
215
+ readings;
216
+ constructor(instances, planner, transports, resolver, evaluator, scope, readings) {
217
+ this.instances = instances;
218
+ this.planner = planner;
219
+ this.transports = transports;
220
+ this.resolver = resolver;
221
+ this.evaluator = evaluator;
222
+ this.scope = scope;
223
+ this.readings = readings;
224
+ }
225
+ async canActivate(context) {
226
+ let transport;
227
+ let call;
228
+ let plan;
229
+ try {
230
+ plan = this.planner.forContext(context);
231
+ if (plan.access === "inherit") {
232
+ transport = this.transports.find(context);
233
+ const lineage = transport?.lineage?.(context);
234
+ if (lineage && !this.readings.enclosing(lineage, context.getArgs())) {
235
+ call = this.transports.describe(context, transport);
236
+ throw BetterAuthConfigurationError.atRequest("NO_ENCLOSING_DECISION", "An inherited invocation has no enclosing guard decision", { site: plan.site });
237
+ }
238
+ if (plan.originCheck !== "form") return true;
239
+ }
240
+ if (plan.access === "public" && plan.originCheck !== "form") {
241
+ const lineage = this.transports.find(context)?.lineage?.(context);
242
+ if (lineage && !plan.nested) this.readings.recordLineage(lineage, {
243
+ outcome: "no-identity",
244
+ instance: plan.instance
245
+ });
246
+ return true;
247
+ }
248
+ transport = this.transports.select(context);
249
+ call = this.transports.describe(context, transport);
250
+ const entry = this.instances.get(plan.instance);
251
+ if (plan.originCheck !== "off") {
252
+ const browser = call.browser;
253
+ if (browser) {
254
+ if (plan.originCheck === "form" || browser.enforce) {
255
+ const failure = await entry.origin.check(browser, plan.originCheck);
256
+ if (failure) throw failure;
257
+ } else await entry.origin.advisory(browser);
258
+ }
259
+ }
260
+ if (plan.access === "inherit") return true;
261
+ if (plan.access === "public") {
262
+ if (!plan.nested) this.readings.record(call, {
263
+ outcome: "no-identity",
264
+ instance: plan.instance
265
+ });
266
+ return true;
267
+ }
268
+ const result = await this.resolver.resolve(call, {
269
+ auth: entry.handle,
270
+ freshness: plan.freshness,
271
+ accepts: plan.accepts,
272
+ sourceSet: plan.sourceSet
273
+ });
274
+ this.readings.record(call, {
275
+ ...result,
276
+ instance: plan.instance
277
+ });
278
+ if (result.outcome === "rejected") throw result.failure;
279
+ if (result.outcome === "absent") {
280
+ if (plan.access === "optional") return true;
281
+ throw AuthFailures.unauthenticated();
282
+ }
283
+ if (!plan.accepts.has(result.principal.kind)) throw AuthFailures.forbidden("PRINCIPAL_NOT_SUPPORTED");
284
+ const decision = await this.evaluator.evaluate(plan, result.principal, call, entry, context, transport.id);
285
+ if (decision.effect === "deny") throw AuthFailures.rejected({
286
+ status: decision.status ?? 403,
287
+ reason: decision.reason,
288
+ message: decision.message,
289
+ challenge: decision.challenge
290
+ });
291
+ return true;
292
+ } catch (error) {
293
+ if (isAuthFailure(error) && transport) {
294
+ const mapping = plan && this.instances.get(plan.instance).options.errors?.map;
295
+ throw mapping ? mapping(error, context, transport.id) : transport.toException(error, context);
296
+ }
297
+ if ((isConfigurationError(error) || isInfrastructureError(error)) && transport) {
298
+ const repeated = call ? this.scope.surfaced(call.key, error, {
299
+ instance: plan?.instance ?? "default",
300
+ site: plan?.site ?? "guard",
301
+ lineage: call.lineage
302
+ }) : false;
303
+ throw transport.toInternalException?.(error, context, { repeated }) ?? error;
304
+ }
305
+ throw error;
306
+ }
307
+ }
308
+ };
309
+ //#endregion
310
+ //#region src/auth-scope-interceptor.ts
311
+ let BetterAuthScopeInterceptor = class BetterAuthScopeInterceptor {
312
+ core;
313
+ static [AUTH_ENHANCER] = "scope";
314
+ [AUTH_ENHANCER] = "scope";
315
+ constructor(core) {
316
+ this.core = core;
317
+ }
318
+ intercept(context, next) {
319
+ return this.core.intercept(context, next);
320
+ }
321
+ };
322
+ BetterAuthScopeInterceptor = __decorate([
323
+ Injectable(),
324
+ __decorateParam(0, Inject(SCOPE_CORE)),
325
+ __decorateMetadata("design:paramtypes", [typeof Pick === "undefined" ? Object : Pick])
326
+ ], BetterAuthScopeInterceptor);
327
+ var ScopeCore = class {
328
+ instances;
329
+ planner;
330
+ transports;
331
+ scope;
332
+ readings;
333
+ constructor(instances, planner, transports, scope, readings) {
334
+ this.instances = instances;
335
+ this.planner = planner;
336
+ this.transports = transports;
337
+ this.scope = scope;
338
+ this.readings = readings;
339
+ }
340
+ intercept(context, next) {
341
+ const plan = this.planner.forContext(context);
342
+ const entry = this.instances.get(plan.instance);
343
+ let described = false;
344
+ let call;
345
+ const getCall = () => {
346
+ if (!described) {
347
+ const transport = this.transports.find(context);
348
+ call = transport ? this.transports.describe(context, transport) : void 0;
349
+ described = true;
350
+ }
351
+ return call;
352
+ };
353
+ let reading;
354
+ const read = () => {
355
+ if (reading) return reading;
356
+ const lineage = this.transports.find(context)?.lineage?.(context);
357
+ reading = this.readings.read({
358
+ args: context.getArgs(),
359
+ plan,
360
+ lineage,
361
+ ...plan.access === "public" || plan.access === "inherit" ? {} : { call: getCall() }
362
+ });
363
+ return reading;
364
+ };
365
+ const instances = this.instances;
366
+ const state = {
367
+ view: {
368
+ get cookies() {
369
+ return getCall()?.cookies ?? null;
370
+ },
371
+ forward: plan.forwardDirectCalls ? "same-credential" : "none",
372
+ internal: false,
373
+ get inbound() {
374
+ return () => {
375
+ const call = getCall();
376
+ return call ? requestHeaders(call, entry) : new Headers();
377
+ };
378
+ },
379
+ get browserHeaders() {
380
+ const browser = getCall()?.browser;
381
+ return browser ? () => browser.headers() : void 0;
382
+ },
383
+ get checkCallerSession() {
384
+ if (plan.originCheck === "off") return;
385
+ const browser = getCall()?.browser;
386
+ return browser ? (path, instance) => instances.get(instance).origin.assertCallerSession(browser, path, instance) : void 0;
387
+ }
388
+ },
389
+ plan,
390
+ reading: read,
391
+ get call() {
392
+ return getCall();
393
+ }
394
+ };
395
+ const args = context.getArgs();
396
+ const bridge = {
397
+ args: [...args],
398
+ reading: read,
399
+ scope: this.scope,
400
+ readings: this.readings
401
+ };
402
+ for (const arg of [args, ...args]) if (arg && (typeof arg === "object" || typeof arg === "function") && Object.isExtensible(arg)) Object.defineProperty(arg, READER_CONTEXT, {
403
+ value: bridge,
404
+ configurable: true
405
+ });
406
+ return new Observable((subscriber) => this.scope.run(state, () => {
407
+ const subscription = next.handle().subscribe({
408
+ next: (value) => this.scope.run(state, () => subscriber.next(value)),
409
+ error: (error) => this.scope.run(state, () => subscriber.error(error)),
410
+ complete: () => this.scope.run(state, () => subscriber.complete())
411
+ });
412
+ return () => this.scope.run(state, () => subscription.unsubscribe());
413
+ }));
414
+ }
415
+ };
416
+ //#endregion
417
+ //#region src/request-scope.ts
418
+ const SURFACED = Symbol.for("nestjs-slightly-better-auth:surfaced");
419
+ function memoKey(instance, ...inputs) {
420
+ return JSON.stringify([instance, ...inputs]);
421
+ }
422
+ /** Shared by guards and readers that have only the transport's structural lineage. */
423
+ function surfacedRecord(key, lineage) {
424
+ const carrier = lineage?.carrier ?? key;
425
+ const partition = lineage ? lineage.position.split(":", 1)[0] : "";
426
+ let records = Reflect.get(carrier, SURFACED);
427
+ if (!records) {
428
+ records = /* @__PURE__ */ new Map();
429
+ Object.defineProperty(carrier, SURFACED, { value: records });
430
+ }
431
+ let record = records.get(partition);
432
+ if (!record) {
433
+ record = /* @__PURE__ */ new Set();
434
+ records.set(partition, record);
435
+ }
436
+ return record;
437
+ }
438
+ var RequestScope = class {
439
+ #storage = new AsyncLocalStorage();
440
+ #states = /* @__PURE__ */ new WeakMap();
441
+ #valueKeys = /* @__PURE__ */ new Map();
442
+ #errorIds = /* @__PURE__ */ new WeakMap();
443
+ #nextError = 0;
444
+ run(state, fn) {
445
+ return this.#storage.run(state, fn);
446
+ }
447
+ exit(fn) {
448
+ return this.#storage.exit(fn);
449
+ }
450
+ current() {
451
+ return this.#storage.getStore();
452
+ }
453
+ stateFor(key) {
454
+ let state = this.#states.get(key);
455
+ if (!state) {
456
+ state = {
457
+ principal: /* @__PURE__ */ new Map(),
458
+ policyIo: /* @__PURE__ */ new Map(),
459
+ decisions: /* @__PURE__ */ new Map(),
460
+ values: /* @__PURE__ */ new Map(),
461
+ authorizationCalls: /* @__PURE__ */ new Set(),
462
+ origins: /* @__PURE__ */ new Map(),
463
+ surfaced: /* @__PURE__ */ new Set(),
464
+ connections: /* @__PURE__ */ new Map()
465
+ };
466
+ this.#states.set(key, state);
467
+ }
468
+ return state;
469
+ }
470
+ memoPrincipal(call, input, compute) {
471
+ const key = memoKey(input.instance, input.freshness, input.sourceSet);
472
+ const state = this.stateFor(call.key);
473
+ const existing = state.principal.get(key);
474
+ if (existing) return existing;
475
+ const connection = call.connection && input.freshness !== "authoritative" && (call.principalTtlMs ?? 0) > 0 ? this.stateFor(call.connection).connections : void 0;
476
+ const cached = connection?.get(key);
477
+ const promise = Promise.resolve().then(async () => {
478
+ if (cached && cached.expiresAt > Date.now()) return cached.value;
479
+ connection?.delete(key);
480
+ try {
481
+ const value = await compute();
482
+ if (value.outcome !== "rejected") connection?.set(key, {
483
+ value,
484
+ expiresAt: Date.now() + (call.principalTtlMs ?? 0)
485
+ });
486
+ return value;
487
+ } catch (error) {
488
+ connection?.delete(key);
489
+ throw error;
490
+ }
491
+ });
492
+ state.principal.set(key, promise);
493
+ return promise;
494
+ }
495
+ memoPolicyIo(request, instance, concreteKey, compute, limit = 100) {
496
+ const state = this.stateFor(request);
497
+ const key = memoKey(instance, concreteKey);
498
+ const existing = state.policyIo.get(key);
499
+ if (existing) return existing;
500
+ if (limit !== false && [...state.authorizationCalls].filter((entry) => JSON.parse(entry)[0] === instance).length >= limit) return Promise.reject(AuthFailures.rejected({
501
+ status: 429,
502
+ reason: "TOO_MANY_AUTHORIZATION_CHECKS"
503
+ }));
504
+ state.authorizationCalls.add(key);
505
+ const promise = Promise.resolve().then(compute);
506
+ state.policyIo.set(key, promise);
507
+ return promise;
508
+ }
509
+ memoDecision(invocation, instance, concreteKey, compute) {
510
+ const decisions = this.stateFor(invocation).decisions;
511
+ const key = memoKey(instance, concreteKey);
512
+ let promise = decisions.get(key);
513
+ if (!promise) {
514
+ promise = Promise.resolve().then(compute);
515
+ decisions.set(key, promise);
516
+ }
517
+ return promise;
518
+ }
519
+ valueKey(instance, key) {
520
+ let keys = this.#valueKeys.get(instance);
521
+ if (!keys) {
522
+ keys = /* @__PURE__ */ new Map();
523
+ this.#valueKeys.set(instance, keys);
524
+ }
525
+ let namespaced = keys.get(key);
526
+ if (!namespaced) {
527
+ namespaced = Symbol(key.description);
528
+ keys.set(key, namespaced);
529
+ }
530
+ return namespaced;
531
+ }
532
+ surfaced(key, error, context) {
533
+ let id = this.#errorIds.get(error);
534
+ if (!id) {
535
+ id = ++this.#nextError;
536
+ this.#errorIds.set(error, id);
537
+ }
538
+ const reason = isConfigurationError(error) ? memoKey(context.instance, error.code, context.site) : `error:${id}`;
539
+ const carrier = surfacedRecord(key, context.lineage);
540
+ const state = key === context.lineage?.carrier ? carrier : this.stateFor(key).surfaced;
541
+ const repeated = state.has(reason) || carrier.has(reason);
542
+ state.add(reason);
543
+ carrier.add(reason);
544
+ return repeated;
545
+ }
546
+ };
547
+ //#endregion
548
+ //#region src/principal-readings.ts
549
+ const RESOLUTION = Symbol.for("nestjs-slightly-better-auth:resolution");
550
+ const TEST_STAMP = Symbol.for("nestjs-slightly-better-auth:test-stamp");
551
+ function object(value) {
552
+ return value !== null && (typeof value === "object" || typeof value === "function");
553
+ }
554
+ function records(target, create = false) {
555
+ let value = Reflect.get(target, RESOLUTION);
556
+ if (!value && create) {
557
+ value = {
558
+ own: /* @__PURE__ */ new Map(),
559
+ positions: /* @__PURE__ */ new Map()
560
+ };
561
+ Object.defineProperty(target, RESOLUTION, { value });
562
+ }
563
+ return value;
564
+ }
565
+ function matchingStamp(args) {
566
+ for (const target of [args, ...args]) {
567
+ if (!object(target)) continue;
568
+ const stamp = Reflect.get(target, TEST_STAMP);
569
+ if (stamp && stamp.elements.length === args.length && stamp.elements.every((value, index) => value === args[index])) return stamp;
570
+ }
571
+ }
572
+ function lineageFromArgs(args) {
573
+ const targets = [args, ...args.filter(object)];
574
+ for (const target of targets) {
575
+ const own = records(target)?.invocationLineage;
576
+ if (own) return own;
577
+ }
578
+ for (const target of targets) {
579
+ const carrier = records(target)?.lineage;
580
+ if (!carrier) continue;
581
+ for (const position of carrier.enclosing(args)) return {
582
+ ...carrier,
583
+ position
584
+ };
585
+ }
586
+ }
587
+ /** The intrinsic twin suppresses Nest's repeated log, while retaining the safe wire shape. */
588
+ var RepeatedReaderError = class extends IntrinsicException {
589
+ constructor(error) {
590
+ super(error.message);
591
+ Object.defineProperties(this, Object.getOwnPropertyDescriptors(error));
592
+ }
593
+ };
594
+ var PrincipalReadings = class {
595
+ scope;
596
+ constructor(scope) {
597
+ this.scope = scope;
598
+ }
599
+ record(call, reading) {
600
+ const record = records(call.invocation, true);
601
+ record.own.set(reading.instance, reading);
602
+ if (call.lineage) {
603
+ record.invocationLineage = call.lineage;
604
+ this.recordLineage(call.lineage, reading);
605
+ }
606
+ }
607
+ recordLineage(lineage, reading) {
608
+ const value = records(lineage.carrier, true);
609
+ value.positions.set(lineage.position, reading);
610
+ value.lineage = lineage;
611
+ }
612
+ enclosing(lineage, args) {
613
+ const positions = records(lineage.carrier)?.positions;
614
+ for (const position of lineage.enclosing(args)) {
615
+ const reading = positions?.get(position);
616
+ if (reading) return reading;
617
+ }
618
+ }
619
+ read(input) {
620
+ const { plan, args, call } = input;
621
+ const lineage = input.lineage ?? call?.lineage;
622
+ let resolvedInstance = plan?.instance;
623
+ try {
624
+ if (plan?.access === "public") return {
625
+ outcome: "no-identity",
626
+ instance: plan.instance
627
+ };
628
+ let reading;
629
+ let validation = lineage ?? lineageFromArgs(args);
630
+ if (plan?.access === "inherit") reading = lineage && this.enclosing(lineage, args);
631
+ else {
632
+ const targets = call ? [call.invocation] : [args, ...args.filter(object)];
633
+ for (const target of targets) {
634
+ const own = records(target)?.own;
635
+ reading = plan ? own?.get(plan.instance) : own?.size === 1 ? own.values().next().value : void 0;
636
+ if (reading) break;
637
+ }
638
+ if (!reading && !plan) for (const target of [args, ...args.filter(object)]) {
639
+ const candidate = records(target)?.lineage;
640
+ if (!candidate) continue;
641
+ reading = this.enclosing(candidate, args);
642
+ if (reading) {
643
+ validation = candidate;
644
+ break;
645
+ }
646
+ }
647
+ }
648
+ if (!reading) {
649
+ const stamp = matchingStamp(args);
650
+ const instance = plan?.instance ?? "default";
651
+ const result = stamp?.results.get(instance);
652
+ if (result) reading = {
653
+ ...result,
654
+ instance
655
+ };
656
+ }
657
+ if (!reading) throw BetterAuthConfigurationError.atRequest(input.beforeGuard && plan?.access !== "inherit" ? "PRINCIPAL_READ_BEFORE_GUARD" : "NO_AUTH_RESULT", "No authentication result: BetterAuthGuard did not run for this invocation", {
658
+ site: plan?.site ?? input.site,
659
+ hint: "Run BetterAuthGuard before reading a principal; test replacements must stampPrincipal()."
660
+ });
661
+ resolvedInstance = reading.instance;
662
+ if (reading.outcome === "authenticated") validation?.assertReadable?.(args);
663
+ return reading;
664
+ } catch (error) {
665
+ if (isConfigurationError(error)) throw this.deliver(error, input, resolvedInstance);
666
+ throw error;
667
+ }
668
+ }
669
+ current() {
670
+ const state = this.scope.current();
671
+ if (!state?.reading) throw BetterAuthConfigurationError.atRequest("NO_AUTH_SCOPE", "Principal readers require a handler scope");
672
+ return state.reading();
673
+ }
674
+ project(reading, spec, input) {
675
+ if (reading.outcome === "no-identity" || reading.outcome === "absent") return null;
676
+ if (reading.outcome === "rejected") throw reading.failure;
677
+ if (spec.kind && reading.principal.kind !== spec.kind) {
678
+ const error = BetterAuthConfigurationError.atRequest(spec.reason ?? "PRINCIPAL_KIND_REQUIRED", `This reader requires principal kind ${spec.kind}`, {
679
+ site: spec.site,
680
+ hint: "Use @CurrentPrincipal() or getPrincipal() and narrow p.kind."
681
+ });
682
+ throw this.deliver(error, input, reading.instance);
683
+ }
684
+ return spec.project(reading.principal);
685
+ }
686
+ deliver(error, input, instance) {
687
+ const state = this.scope.current();
688
+ const call = state?.call ?? input?.call;
689
+ const lineage = call?.lineage ?? input?.lineage ?? (input && lineageFromArgs(input.args));
690
+ const key = call?.key ?? lineage?.carrier ?? input?.args;
691
+ if (!key) return error;
692
+ return this.scope.surfaced(key, error, {
693
+ instance: instance ?? state?.plan?.instance ?? input?.plan?.instance ?? "default",
694
+ site: error.site ?? input?.site ?? input?.plan?.site ?? "principal reader",
695
+ lineage
696
+ }) ? new RepeatedReaderError(error) : error;
697
+ }
698
+ stamp(args, instance, result) {
699
+ const stamp = matchingStamp(args) ?? {
700
+ elements: [...args],
701
+ results: /* @__PURE__ */ new Map()
702
+ };
703
+ stamp.results.set(instance, result);
704
+ for (const target of [args, ...args]) if (object(target) && Object.isExtensible(target)) Object.defineProperty(target, TEST_STAMP, {
705
+ value: stamp,
706
+ configurable: true
707
+ });
708
+ }
709
+ };
710
+ //#endregion
711
+ //#region src/auth-decorators.ts
712
+ function append(target, key, value) {
713
+ Reflect.defineMetadata(key, Object.freeze([...Reflect.getOwnMetadata(key, target) ?? [], value]), target);
714
+ }
715
+ const Public = () => SetMetadata(ACCESS_METADATA, "public");
716
+ const OptionalAuth = () => SetMetadata(ACCESS_METADATA, "optional");
717
+ const RequireAuth = (options) => applyDecorators(SetMetadata(ACCESS_METADATA, "required"), SetMetadata(FRESHNESS_METADATA, options?.authoritative === true));
718
+ const UseAuthInstance = (name) => SetMetadata(AUTH_INSTANCE_METADATA, name);
719
+ const AcceptPrincipals = (...kinds) => SetMetadata(ACCEPT_PRINCIPALS_METADATA, Object.freeze([...kinds]));
720
+ const SkipDefaultRequirements = () => SetMetadata(SKIP_DEFAULT_REQUIREMENTS_METADATA, true);
721
+ const ForwardAuthCookies = (enabled = true) => SetMetadata(FORWARD_COOKIES_METADATA, enabled);
722
+ const SkipOriginCheck = () => SetMetadata(SKIP_ORIGIN_CHECK_METADATA, true);
723
+ const UseBetterAuth = () => applyDecorators(SetMetadata(USE_BETTER_AUTH_METADATA, true), UseGuards(BetterAuthGuard), UseInterceptors(BetterAuthScopeInterceptor));
724
+ function Require(...requirements) {
725
+ return (target, _key, descriptor) => {
726
+ for (const expression of requirements) append(descriptor?.value ?? target, REQUIREMENTS_METADATA, expression);
727
+ };
728
+ }
729
+ const anyOf = (...requirements) => ({ anyOf: requirements });
730
+ const allOf = (...requirements) => ({ allOf: requirements });
731
+ const requirement = (policy, params, options) => ({
732
+ policy,
733
+ params,
734
+ ...options
735
+ });
736
+ function readerContext(context) {
737
+ const args = context.getArgs();
738
+ for (const arg of [args, ...args]) {
739
+ if ((typeof arg !== "object" || arg === null) && typeof arg !== "function") continue;
740
+ const bridge = Reflect.get(arg, READER_CONTEXT);
741
+ if (bridge && bridge.args.length === args.length && bridge.args.every((value, index) => value === args[index]) && bridge.reading !== void 0 && bridge.scope.current()?.reading === bridge.reading) return bridge;
742
+ }
743
+ const scope = new RequestScope();
744
+ return {
745
+ args,
746
+ scope,
747
+ readings: new PrincipalReadings(scope)
748
+ };
749
+ }
750
+ function principalParam(spec) {
751
+ const decorator = createParamDecorator((_data, context) => {
752
+ const bridge = readerContext(context);
753
+ const input = {
754
+ args: context.getArgs(),
755
+ site: `${context.getClass().name}.${context.getHandler().name}`
756
+ };
757
+ const reading = bridge.reading !== void 0 && bridge.scope.current()?.reading === bridge.reading ? bridge.readings.current() : bridge.readings.read(input);
758
+ return bridge.readings.project(reading, {
759
+ ...spec,
760
+ site: input.site,
761
+ project: spec?.project ?? ((p) => p)
762
+ }, input);
763
+ })();
764
+ return (target, propertyKey, index) => {
765
+ if (propertyKey === void 0) throw new BetterAuthConfigurationError("PRINCIPAL_PARAM_TARGET", "Principal parameters require a handler method");
766
+ append(Reflect.get(target, propertyKey), PRINCIPAL_PARAMS_METADATA, {
767
+ index,
768
+ ...spec ? {
769
+ kind: spec.kind,
770
+ reason: spec.reason
771
+ } : {}
772
+ });
773
+ decorator(target, propertyKey, index);
774
+ };
775
+ }
776
+ const CurrentPrincipal = () => principalParam();
777
+ function definePrincipalParam(spec) {
778
+ return () => principalParam(spec);
779
+ }
780
+ function defineInvocationParam(slot, spec) {
781
+ return () => {
782
+ const decorator = createParamDecorator((_data, context) => {
783
+ const bridge = readerContext(context);
784
+ const state = bridge.scope.current();
785
+ const input = {
786
+ args: context.getArgs(),
787
+ site: `${context.getClass().name}.${context.getHandler().name}`
788
+ };
789
+ const reading = state?.reading ? bridge.readings.current() : bridge.readings.read(input);
790
+ const candidates = state?.call ? [state.call.invocation] : [input.args, ...input.args];
791
+ for (const candidate of candidates) {
792
+ if (!candidate || typeof candidate !== "object" && typeof candidate !== "function") continue;
793
+ const values = Reflect.get(candidate, INVOCATION_VALUES);
794
+ if (values?.get(reading.instance)?.has(slot)) return values.get(reading.instance).get(slot);
795
+ }
796
+ throw bridge.readings.deliver(BetterAuthConfigurationError.atRequest("NO_INVOCATION_VALUE", spec.missing, { site: input.site }), input, reading.instance);
797
+ })();
798
+ return (target, key, index) => {
799
+ if (key === void 0) throw new BetterAuthConfigurationError("INVOCATION_PARAM_TARGET", "Invocation parameters require a handler method");
800
+ append(Reflect.get(target, key), INVOCATION_PARAMS_METADATA, {
801
+ index,
802
+ slot,
803
+ missing: spec.missing
804
+ });
805
+ decorator(target, key, index);
806
+ };
807
+ };
808
+ }
809
+ function readHookMetadata(handler) {
810
+ return {
811
+ hooks: Reflect.getOwnMetadata(HOOK_METADATA, handler) ?? [],
812
+ databaseHooks: Reflect.getOwnMetadata(DB_HOOK_METADATA, handler) ?? []
813
+ };
814
+ }
815
+ function hook(phase, match, options) {
816
+ return (_target, method, descriptor) => {
817
+ const handler = descriptor.value;
818
+ const records = readHookMetadata(handler).hooks;
819
+ append(handler, HOOK_METADATA, Object.freeze({
820
+ phase,
821
+ match: Array.isArray(match) ? Object.freeze([...match]) : match,
822
+ options: Object.freeze({ ...options }),
823
+ method,
824
+ handler,
825
+ declarationOrder: records.length
826
+ }));
827
+ };
828
+ }
829
+ const BeforeAuth = (match, options) => hook("before", match, options);
830
+ const AfterAuth = (match, options) => hook("after", match, options);
831
+ function databaseHook(phase, target, options) {
832
+ return (_prototype, method, descriptor) => {
833
+ const handler = descriptor.value;
834
+ append(handler, DB_HOOK_METADATA, Object.freeze({
835
+ phase,
836
+ target,
837
+ options: Object.freeze({ ...options }),
838
+ method,
839
+ handler,
840
+ declarationOrder: readHookMetadata(handler).databaseHooks.length
841
+ }));
842
+ };
843
+ }
844
+ const BeforeDatabase = (target, options) => databaseHook("before", target, options);
845
+ const AfterDatabase = (target, options) => databaseHook("after", target, options);
846
+ //#endregion
847
+ export { POLICY_RESOLVER as $, __decorateParam as A, ACCEPT_PRINCIPALS_METADATA as B, RequestScope as C, BetterAuthGuard as D, ScopeCore as E, authenticated as F, FRESHNESS_METADATA as G, AUTH_ENHANCER as H, definePrincipalSource as I, INVOCATION_PARAMS_METADATA as J, GUARD_CORE as K, normalizeForRequest as L, ChainPrincipalResolver as M, MemoKeys as N, GuardCore as O, absent as P, POLICY_INVOKER as Q, rejected as R, PrincipalReadings as S, BetterAuthScopeInterceptor as T, AUTH_INSTANCE_METADATA as U, ACCESS_METADATA as V, FORWARD_COOKIES_METADATA as W, MOUNT_COORDINATOR as X, INVOCATION_VALUES as Y, PLATFORMS as Z, anyOf as _, getPrincipalSourcesToken as _t, BeforeDatabase as a, ROUTE_PLANNER as at, readHookMetadata as b, OptionalAuth as c, SKIP_ORIGIN_CHECK_METADATA as ct, RequireAuth as d, USE_BETTER_AUTH_METADATA as dt, PRINCIPAL_PARAMS_METADATA as et, SkipDefaultRequirements as f, getBetterAuthHandleToken as ft, allOf as g, getExtensionToken as gt, UseBetterAuth as h, getBetterAuthServiceToken as ht, BeforeAuth as i, REQUIREMENTS_METADATA as it, __decorateMetadata as j, __decorate as k, Public as l, TRANSPORTS as lt, UseAuthInstance as m, getBetterAuthOptionsToken as mt, AfterAuth as n, PRINCIPAL_RESOLVER as nt, CurrentPrincipal as o, SCOPE_CORE as ot, SkipOriginCheck as p, getBetterAuthInstanceToken as pt, INSTANCE_REGISTRY as q, AfterDatabase as r, REQUEST_SCOPE as rt, ForwardAuthCookies as s, SKIP_DEFAULT_REQUIREMENTS_METADATA as st, AcceptPrincipals as t, PRINCIPAL_READINGS as tt, Require as u, TRANSPORT_REGISTRY as ut, defineInvocationParam as v, memoKey as w, requirement as x, definePrincipalParam as y, requestHeaders as z };
848
+
849
+ //# sourceMappingURL=auth-decorators-DfAJbHar.mjs.map