@nestjs-kit/better-auth 0.0.0-stage → 2.1.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 (142) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +1078 -2
  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 +164 -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 +160 -0
  18. package/dist/api-key.mjs.map +1 -0
  19. package/dist/auth-contracts-Brh_Qko9.d.cts +1654 -0
  20. package/dist/auth-contracts-Brh_Qko9.d.cts.map +1 -0
  21. package/dist/auth-contracts-Cz7C4_Ch.d.mts +1654 -0
  22. package/dist/auth-contracts-Cz7C4_Ch.d.mts.map +1 -0
  23. package/dist/auth-decorators-B1mFnGJ6.mjs +284 -0
  24. package/dist/auth-decorators-B1mFnGJ6.mjs.map +1 -0
  25. package/dist/auth-decorators-Cu_nxWnF.cjs +421 -0
  26. package/dist/auth-decorators-Cu_nxWnF.cjs.map +1 -0
  27. package/dist/auth-errors-C3rbTV9p.mjs +301 -0
  28. package/dist/auth-errors-C3rbTV9p.mjs.map +1 -0
  29. package/dist/auth-errors-DmiKl0L_.cjs +378 -0
  30. package/dist/auth-errors-DmiKl0L_.cjs.map +1 -0
  31. package/dist/auth-guard-CLyhAEEj.cjs +136 -0
  32. package/dist/auth-guard-CLyhAEEj.cjs.map +1 -0
  33. package/dist/auth-guard-h9QB_l11.mjs +125 -0
  34. package/dist/auth-guard-h9QB_l11.mjs.map +1 -0
  35. package/dist/auth-module-BgcY2HpA.cjs +2809 -0
  36. package/dist/auth-module-BgcY2HpA.cjs.map +1 -0
  37. package/dist/auth-module-CtHx3gRU.mjs +2708 -0
  38. package/dist/auth-module-CtHx3gRU.mjs.map +1 -0
  39. package/dist/auth-scope-interceptor-BjxAL1-S.cjs +290 -0
  40. package/dist/auth-scope-interceptor-BjxAL1-S.cjs.map +1 -0
  41. package/dist/auth-scope-interceptor-DYPn3b8M.mjs +231 -0
  42. package/dist/auth-scope-interceptor-DYPn3b8M.mjs.map +1 -0
  43. package/dist/bridge-protocol-BDw8opAG.cjs +25 -0
  44. package/dist/bridge-protocol-BDw8opAG.cjs.map +1 -0
  45. package/dist/bridge-protocol-c66aEkr5.mjs +8 -0
  46. package/dist/bridge-protocol-c66aEkr5.mjs.map +1 -0
  47. package/dist/decorate-Cr4Q7bNE.cjs +319 -0
  48. package/dist/decorate-Cr4Q7bNE.cjs.map +1 -0
  49. package/dist/decorate-Dt0e9K6R.mjs +80 -0
  50. package/dist/decorate-Dt0e9K6R.mjs.map +1 -0
  51. package/dist/express.cjs +256 -0
  52. package/dist/express.cjs.map +1 -0
  53. package/dist/express.d.cts +37 -0
  54. package/dist/express.d.cts.map +1 -0
  55. package/dist/express.d.mts +37 -0
  56. package/dist/express.d.mts.map +1 -0
  57. package/dist/express.mjs +254 -0
  58. package/dist/express.mjs.map +1 -0
  59. package/dist/fastify.cjs +218 -0
  60. package/dist/fastify.cjs.map +1 -0
  61. package/dist/fastify.d.cts +28 -0
  62. package/dist/fastify.d.cts.map +1 -0
  63. package/dist/fastify.d.mts +28 -0
  64. package/dist/fastify.d.mts.map +1 -0
  65. package/dist/fastify.mjs +216 -0
  66. package/dist/fastify.mjs.map +1 -0
  67. package/dist/graphql.cjs +509 -0
  68. package/dist/graphql.cjs.map +1 -0
  69. package/dist/graphql.d.cts +38 -0
  70. package/dist/graphql.d.cts.map +1 -0
  71. package/dist/graphql.d.mts +38 -0
  72. package/dist/graphql.d.mts.map +1 -0
  73. package/dist/graphql.mjs +503 -0
  74. package/dist/graphql.mjs.map +1 -0
  75. package/dist/index.cjs +86 -0
  76. package/dist/index.d.cts +2 -0
  77. package/dist/index.d.mts +2 -0
  78. package/dist/index.mjs +8 -0
  79. package/dist/microservices.cjs +231 -0
  80. package/dist/microservices.cjs.map +1 -0
  81. package/dist/microservices.d.cts +39 -0
  82. package/dist/microservices.d.cts.map +1 -0
  83. package/dist/microservices.d.mts +39 -0
  84. package/dist/microservices.d.mts.map +1 -0
  85. package/dist/microservices.mjs +222 -0
  86. package/dist/microservices.mjs.map +1 -0
  87. package/dist/organization.cjs +191 -0
  88. package/dist/organization.cjs.map +1 -0
  89. package/dist/organization.d.cts +40 -0
  90. package/dist/organization.d.cts.map +1 -0
  91. package/dist/organization.d.mts +40 -0
  92. package/dist/organization.d.mts.map +1 -0
  93. package/dist/organization.mjs +177 -0
  94. package/dist/organization.mjs.map +1 -0
  95. package/dist/platform-CZl7TY8j.mjs +414 -0
  96. package/dist/platform-CZl7TY8j.mjs.map +1 -0
  97. package/dist/platform-YICqqYv6.cjs +473 -0
  98. package/dist/platform-YICqqYv6.cjs.map +1 -0
  99. package/dist/platform.cjs +10 -0
  100. package/dist/platform.d.cts +43 -0
  101. package/dist/platform.d.cts.map +1 -0
  102. package/dist/platform.d.mts +43 -0
  103. package/dist/platform.d.mts.map +1 -0
  104. package/dist/platform.mjs +1 -0
  105. package/dist/plugin.cjs +323 -0
  106. package/dist/plugin.cjs.map +1 -0
  107. package/dist/plugin.d.cts +24 -0
  108. package/dist/plugin.d.cts.map +1 -0
  109. package/dist/plugin.d.mts +24 -0
  110. package/dist/plugin.d.mts.map +1 -0
  111. package/dist/plugin.mjs +321 -0
  112. package/dist/plugin.mjs.map +1 -0
  113. package/dist/principal-readings-Chmt6rQV.cjs +208 -0
  114. package/dist/principal-readings-Chmt6rQV.cjs.map +1 -0
  115. package/dist/principal-readings-Ied2staw.mjs +191 -0
  116. package/dist/principal-readings-Ied2staw.mjs.map +1 -0
  117. package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
  118. package/dist/testing/conformance.cjs +6214 -0
  119. package/dist/testing/conformance.cjs.map +1 -0
  120. package/dist/testing/conformance.d.cts +528 -0
  121. package/dist/testing/conformance.d.cts.map +1 -0
  122. package/dist/testing/conformance.d.mts +528 -0
  123. package/dist/testing/conformance.d.mts.map +1 -0
  124. package/dist/testing/conformance.mjs +6204 -0
  125. package/dist/testing/conformance.mjs.map +1 -0
  126. package/dist/testing.cjs +221 -0
  127. package/dist/testing.cjs.map +1 -0
  128. package/dist/testing.d.cts +64 -0
  129. package/dist/testing.d.cts.map +1 -0
  130. package/dist/testing.d.mts +64 -0
  131. package/dist/testing.d.mts.map +1 -0
  132. package/dist/testing.mjs +214 -0
  133. package/dist/testing.mjs.map +1 -0
  134. package/dist/websockets.cjs +396 -0
  135. package/dist/websockets.cjs.map +1 -0
  136. package/dist/websockets.d.cts +67 -0
  137. package/dist/websockets.d.cts.map +1 -0
  138. package/dist/websockets.d.mts +67 -0
  139. package/dist/websockets.d.mts.map +1 -0
  140. package/dist/websockets.mjs +383 -0
  141. package/dist/websockets.mjs.map +1 -0
  142. package/package.json +327 -3
@@ -0,0 +1,43 @@
1
+ import { IncomingHttpHeaders, IncomingMessage, ServerResponse } from "node:http";
2
+ //#region src/platform.d.ts
3
+ /** Convert Node headers to Web headers without exposing HTTP/2 metadata. */
4
+ export declare function toWebHeaders(raw: IncomingHttpHeaders | Record<string | symbol, unknown>): Headers;
5
+ /** Determine whether Node request framing permits a request body. */
6
+ export declare function mayHaveBody(method: string, headers: IncomingHttpHeaders): boolean;
7
+ /** Read a Node or Web body stream without retaining bytes past the limit. */
8
+ export declare function readBoundedBody(stream: NodeJS.ReadableStream | ReadableStream<Uint8Array>, options: {
9
+ limit: number;
10
+ declaredLength?: number;
11
+ drainOnOverflow?: boolean;
12
+ drainCap?: number;
13
+ }): Promise<{
14
+ ok: true;
15
+ bytes: Uint8Array;
16
+ } | {
17
+ ok: false;
18
+ reason: "too-large" | "aborted";
19
+ }>;
20
+ /** Append response cookies without replacing values already set by the host. */
21
+ export declare function appendSetCookie(res: ServerResponse, values: readonly string[]): boolean;
22
+ /** Write a Web response while retaining host headers and Node backpressure. */
23
+ export declare function writeWebResponse(res: ServerResponse, response: Response, options?: {
24
+ head?: boolean;
25
+ }): Promise<void>;
26
+ /** Capture the active async resource for a later stream continuation. */
27
+ export declare function bindAsyncContext<F extends (...args: any[]) => any>(fn: F): F;
28
+ /** Recover bytes after an earlier host parser consumed the request stream. */
29
+ export declare function recoverConsumedBody(req: IncomingMessage & {
30
+ body?: unknown;
31
+ rawBody?: Buffer;
32
+ }): Uint8Array | null;
33
+ /** Build an upgrade URL from socket TLS state, Host, and the raw target. */
34
+ export declare function upgradeRequestUrl(request: {
35
+ headers: IncomingHttpHeaders | Headers;
36
+ url?: string;
37
+ secure?: boolean;
38
+ socket?: {
39
+ encrypted?: boolean;
40
+ };
41
+ }): string;
42
+ //#endregion
43
+ //# sourceMappingURL=platform.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.mts","names":[],"sources":["../src/platform.ts"],"mappings":";;;wBA2BgB,aACd,KAAK,sBAAsB,mCAC1B;;wBAmBa,YACd,gBACA,SAAS;;wBAuMK,gBACd,QAAQ,OAAO,iBAAiB,eAAe,aAC/C;EACE;EACA;EACA;EACA;IAED;EACG;EAAU,OAAO;;EACjB;EAAW;;;wBAiBD,gBACd,KAAK,gBACL;;wBAoGoB,iBACpB,KAAK,gBACL,UAAU,UACV;EAAY;IACX;;wBAoFa,iBAAiB,cAAc,qBAAqB,IAAI,IAAI;;wBAmC5D,oBACd,KAAK;EAAoB;EAAgB,UAAU;IAClD;;wBAyCa,kBAAkB;EAChC,SAAS,sBAAsB;EAC/B;EACA;EACA;IAAW"}
@@ -0,0 +1 @@
1
+ export { t as appendSetCookie, n as bindAsyncContext, r as mayHaveBody, i as readBoundedBody, a as recoverConsumedBody, o as toWebHeaders, s as upgradeRequestUrl, c as writeWebResponse } from "./platform-CZl7TY8j.mjs";
@@ -0,0 +1,323 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let better_auth_api = require("better-auth/api");
3
+ let better_auth_cookies = require("better-auth/cookies");
4
+ let defu = require("defu");
5
+ //#region src/bridge-protocol.ts
6
+ const BRIDGE_HANDLE = Symbol.for("@nestjs-kit/better-auth:bridge");
7
+ //#endregion
8
+ //#region src/database-hook-dispatcher.ts
9
+ /**
10
+ * Construct all dispatchers once; bindings supply only the late-bound methods.
11
+ *
12
+ * The dispatchers take the SDK's own parameter types, so they satisfy `databaseHooks` whatever
13
+ * instance the program registers. Bound hooks declare `DatabaseHookData`, which adds the
14
+ * registered instance's plugin and additional fields (for example admin()'s `banned`) to the
15
+ * same rows; the dispatcher states that narrowing once when it forwards a payload.
16
+ */
17
+ function createDatabaseDispatchers(getBinding, countUnbound) {
18
+ function operation(target) {
19
+ const before = async (...[data, ctx]) => {
20
+ const binding = getBinding();
21
+ if (!binding) {
22
+ countUnbound();
23
+ return;
24
+ }
25
+ const hooks = binding.database[target].before;
26
+ let accumulated = {};
27
+ let changed = false;
28
+ for (const hook of hooks) {
29
+ const result = await hook(target.endsWith(".create") ? {
30
+ ...data,
31
+ ...accumulated
32
+ } : data, ctx);
33
+ if (result === false) return false;
34
+ if (!target.endsWith(".delete") && result && typeof result === "object" && "data" in result) {
35
+ accumulated = {
36
+ ...accumulated,
37
+ ...result.data
38
+ };
39
+ changed = true;
40
+ }
41
+ }
42
+ return changed ? { data: accumulated } : void 0;
43
+ };
44
+ const after = async (...[data, ctx]) => {
45
+ const binding = getBinding();
46
+ if (!binding) {
47
+ countUnbound();
48
+ return;
49
+ }
50
+ for (const hook of binding.database[target].after) await hook(data, ctx);
51
+ };
52
+ return {
53
+ before,
54
+ after
55
+ };
56
+ }
57
+ return {
58
+ user: {
59
+ create: operation("user.create"),
60
+ update: operation("user.update"),
61
+ delete: operation("user.delete")
62
+ },
63
+ session: {
64
+ create: operation("session.create"),
65
+ update: operation("session.update"),
66
+ delete: operation("session.delete")
67
+ },
68
+ account: {
69
+ create: operation("account.create"),
70
+ update: operation("account.update"),
71
+ delete: operation("account.delete")
72
+ },
73
+ verification: {
74
+ create: operation("verification.create"),
75
+ update: operation("verification.update"),
76
+ delete: operation("verification.delete")
77
+ }
78
+ };
79
+ }
80
+ //#endregion
81
+ //#region src/hook-dispatcher.ts
82
+ const API_ERROR_HEADERS = Symbol.for("better-call:api-error-headers");
83
+ const mergeContext = (0, defu.createDefu)((object, key, value) => {
84
+ if (Array.isArray(object[key]) && Array.isArray(value)) {
85
+ object[key] = value;
86
+ return true;
87
+ }
88
+ });
89
+ function mergeHeaders(target, source) {
90
+ source?.forEach((value, key) => {
91
+ if (key === "set-cookie") target.append(key, value);
92
+ else target.set(key, value);
93
+ });
94
+ }
95
+ function errorHeaders(error) {
96
+ const attached = error[API_ERROR_HEADERS];
97
+ if (!attached && !error.headers) return;
98
+ const headers = new Headers(attached);
99
+ if (error.headers && error.headers !== attached) mergeHeaders(headers, new Headers(error.headers));
100
+ return headers;
101
+ }
102
+ /** Run each method through the SDK middleware so its cookie/header state is isolated. */
103
+ async function runBefore(binding, ctx, scope) {
104
+ let accumulated = {};
105
+ for (const hook of binding.before) {
106
+ let matched;
107
+ try {
108
+ matched = hook.matches(ctx, scope);
109
+ } catch (error) {
110
+ ctx.context.logger.error("An error occurred during Nest hook matcher execution:", error);
111
+ throw new better_auth_api.APIError("INTERNAL_SERVER_ERROR", { message: "An error occurred during hook matcher execution. Check the logs for more details." });
112
+ }
113
+ if (!matched) continue;
114
+ let result;
115
+ try {
116
+ result = await (0, better_auth_api.createAuthMiddleware)(hook.run)({
117
+ ...ctx,
118
+ returnHeaders: true
119
+ });
120
+ } catch (error) {
121
+ if ((0, better_auth_api.isAPIError)(error)) ctx.responseHeaders = error[API_ERROR_HEADERS] ?? new Headers();
122
+ throw error;
123
+ }
124
+ ctx.context.responseHeaders ??= new Headers();
125
+ mergeHeaders(ctx.context.responseHeaders, result.headers);
126
+ const value = result.response;
127
+ if (value && typeof value === "object") {
128
+ if ("context" in value && typeof value.context === "object") {
129
+ const { headers, ...rest } = value.context;
130
+ if (headers instanceof Headers) {
131
+ const requestHeaders = accumulated.headers instanceof Headers ? accumulated.headers : new Headers();
132
+ headers.forEach((header, key) => {
133
+ requestHeaders.set(key, header);
134
+ });
135
+ accumulated.headers = requestHeaders;
136
+ }
137
+ accumulated = mergeContext(rest, accumulated);
138
+ } else return value;
139
+ }
140
+ }
141
+ return Object.keys(accumulated).length ? { context: accumulated } : void 0;
142
+ }
143
+ async function runAfter(binding, ctx, scope, relayMatcherError) {
144
+ for (const hook of binding.after) {
145
+ let matched;
146
+ try {
147
+ matched = hook.matches(ctx, scope);
148
+ } catch (error) {
149
+ if (!relayMatcherError) throw error;
150
+ relayMatcherError(error);
151
+ return;
152
+ }
153
+ if (!matched) continue;
154
+ let result;
155
+ try {
156
+ result = await (0, better_auth_api.createAuthMiddleware)(hook.run)({
157
+ ...ctx,
158
+ returnHeaders: true
159
+ });
160
+ } catch (error) {
161
+ if (!(0, better_auth_api.isAPIError)(error)) throw error;
162
+ result = {
163
+ response: error,
164
+ headers: errorHeaders(error)
165
+ };
166
+ }
167
+ if (result.headers) {
168
+ ctx.context.responseHeaders ??= new Headers();
169
+ mergeHeaders(ctx.context.responseHeaders, result.headers);
170
+ }
171
+ if (result.response !== void 0) ctx.context.returned = result.response;
172
+ }
173
+ return ctx.context.returned;
174
+ }
175
+ //#endregion
176
+ //#region src/plugin.ts
177
+ const NESTJS_PLUGIN_ID = "@nestjs-kit/better-auth";
178
+ const isRouter = (ctx) => "_flag" in ctx && ctx._flag === "router";
179
+ const separator = "\0";
180
+ function sessionToken(headers, ctx) {
181
+ return (0, better_auth_cookies.parseCookies)(headers?.get("cookie") ?? "").get(ctx.context.authCookies.sessionToken.name) ?? "";
182
+ }
183
+ function credential(headers, ctx, extra) {
184
+ return [
185
+ sessionToken(headers, ctx),
186
+ headers?.get("authorization") ?? "",
187
+ ...extra.map((name) => headers?.get(name) ?? "")
188
+ ].join(separator);
189
+ }
190
+ function sameCredential(ctx, scope, extra) {
191
+ const call = credential(ctx.headers, ctx, extra);
192
+ return call === separator.repeat(extra.length + 1) || call === credential(scope.inbound?.(), ctx, extra);
193
+ }
194
+ /** Pure construction-time Better Auth plugin; the Nest kernel binds through a global symbol. */
195
+ function nestjs(options = {}) {
196
+ let binding = null;
197
+ let registration;
198
+ let unboundDispatches = 0;
199
+ const endpointResults = /* @__PURE__ */ new WeakSet();
200
+ const afterMatcherErrors = /* @__PURE__ */ new WeakMap();
201
+ const scope = () => binding?.current();
202
+ const clientIpHeader = options.clientIpHeader === false ? null : options.clientIpHeader ?? `x-nestjs-kit-better-auth-ip-${globalThis.crypto.randomUUID().replaceAll("-", "")}`;
203
+ const handle = {
204
+ protocol: 4,
205
+ clientIpHeader,
206
+ get state() {
207
+ return binding === null ? "unbound" : binding.state === "closed" ? "closed" : "bound";
208
+ },
209
+ get unboundDispatches() {
210
+ return unboundDispatches;
211
+ },
212
+ bind(next) {
213
+ if (binding && binding.instance !== next.instance) throw new Error(`PLUGIN_SHARED_BETWEEN_INSTANCES: '${binding.instance}' and '${next.instance}'`);
214
+ if (binding?.owner === next.owner && registration) return registration;
215
+ if (binding?.state === "bootstrapped") throw new Error(`INSTANCE_ALREADY_BOUND: bound to ${binding.owner.description}`);
216
+ let tookOverFrom;
217
+ if (binding?.state === "initialized") {
218
+ tookOverFrom = binding.owner.description;
219
+ binding.state = "displaced";
220
+ }
221
+ binding = next;
222
+ unboundDispatches = 0;
223
+ registration = {
224
+ tookOverFrom,
225
+ close: () => {
226
+ next.state = "closed";
227
+ }
228
+ };
229
+ return registration;
230
+ },
231
+ producedByEndpoint(value) {
232
+ return typeof value === "object" && value !== null && endpointResults.has(value);
233
+ }
234
+ };
235
+ return {
236
+ id: NESTJS_PLUGIN_ID,
237
+ [BRIDGE_HANDLE]: handle,
238
+ init: () => ({ options: {
239
+ databaseHooks: createDatabaseDispatchers(() => binding, () => {
240
+ unboundDispatches++;
241
+ }),
242
+ ...clientIpHeader ? { advanced: { ipAddress: { ipAddressHeaders: [clientIpHeader] } } } : {}
243
+ } }),
244
+ hooks: {
245
+ before: [
246
+ {
247
+ matcher: (ctx) => {
248
+ if (!binding) {
249
+ unboundDispatches++;
250
+ return false;
251
+ }
252
+ return !isRouter(ctx) && scope()?.cookies === null;
253
+ },
254
+ handler: (0, better_auth_api.createAuthMiddleware)(async () => {
255
+ await (0, better_auth_api.setShouldSkipSessionRefresh)(true);
256
+ })
257
+ },
258
+ {
259
+ matcher: (ctx) => {
260
+ if (!binding || isRouter(ctx)) return false;
261
+ const current = scope();
262
+ if (!current || current.internal) return false;
263
+ const check = current.checkCallerSession;
264
+ current.inbound?.();
265
+ const browser = current.browserHeaders?.();
266
+ const token = sessionToken(ctx.headers, ctx);
267
+ return !!check && token !== "" && token === sessionToken(browser, ctx);
268
+ },
269
+ handler: (0, better_auth_api.createAuthMiddleware)(async (ctx) => {
270
+ scope()?.checkCallerSession?.(ctx.path, binding.instance);
271
+ })
272
+ },
273
+ {
274
+ matcher: () => binding !== null && binding.before.length > 0,
275
+ handler: (0, better_auth_api.createAuthMiddleware)((ctx) => runBefore(binding, ctx, scope()))
276
+ }
277
+ ],
278
+ after: [
279
+ {
280
+ matcher: () => binding !== null && binding.after.length > 0,
281
+ handler: (0, better_auth_api.createAuthMiddleware)((ctx) => runAfter(binding, ctx, scope(), (error) => {
282
+ afterMatcherErrors.set(ctx.context, error);
283
+ }))
284
+ },
285
+ {
286
+ matcher: (ctx) => {
287
+ if (afterMatcherErrors.has(ctx.context)) {
288
+ const error = afterMatcherErrors.get(ctx.context);
289
+ afterMatcherErrors.delete(ctx.context);
290
+ throw error;
291
+ }
292
+ return binding !== null && !isRouter(ctx);
293
+ },
294
+ handler: (0, better_auth_api.createAuthMiddleware)(async (ctx) => {
295
+ const value = ctx.context.returned;
296
+ if (typeof value === "object" && value !== null) endpointResults.add(value);
297
+ })
298
+ },
299
+ {
300
+ matcher: (ctx) => {
301
+ if (isRouter(ctx)) return false;
302
+ const current = scope();
303
+ return !!current?.cookies && current.forward !== "none";
304
+ },
305
+ handler: (0, better_auth_api.createAuthMiddleware)(async (ctx) => {
306
+ const current = scope();
307
+ if (current.forward === "same-credential" && !sameCredential(ctx, current, binding.credentialHeaders)) {
308
+ binding.onDropped(ctx.path);
309
+ return;
310
+ }
311
+ const cookies = ctx.context.responseHeaders?.getSetCookie() ?? [];
312
+ if (cookies.length) current.cookies.append(cookies);
313
+ })
314
+ }
315
+ ]
316
+ }
317
+ };
318
+ }
319
+ //#endregion
320
+ exports.NESTJS_PLUGIN_ID = NESTJS_PLUGIN_ID;
321
+ exports.nestjs = nestjs;
322
+
323
+ //# sourceMappingURL=plugin.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs","names":["createDefu","APIError","createAuthMiddleware","isAPIError","parseCookies","createAuthMiddleware","setShouldSkipSessionRefresh"],"sources":["../src/bridge-protocol.ts","../src/database-hook-dispatcher.ts","../src/hook-dispatcher.ts","../src/plugin.ts"],"sourcesContent":["import type { HookEndpointContext } from \"better-auth\";\nimport type { CookieSink, DatabaseHookTarget } from \"./auth-contracts.js\";\nimport type { DatabaseHookMethod } from \"./auth-types.js\";\n\nexport const BRIDGE_HANDLE = Symbol.for(\"@nestjs-kit/better-auth:bridge\");\nexport const EXTENSION_DEFINITION = Symbol.for(\n \"@nestjs-kit/better-auth:extension\",\n);\nexport const UPGRADE_REQUEST = Symbol.for(\n \"@nestjs-kit/better-auth:upgrade-request\",\n);\n\nexport interface BridgeHandle {\n readonly protocol: 4; // checked by core (B04); v5: binding state and instance, the caller-session check\n readonly clientIpHeader: string | null; // single source of truth for the header name (§6.8)\n /** 'unbound' until the first bind(); 'bound' while an application's hooks are registered; 'closed' after its shutdown, hooks still registered. */\n readonly state: \"unbound\" | \"bound\" | \"closed\";\n /** Endpoint dispatches and database-hook dispatches (writes) seen before the first binding, reset by every bind() (B26). */\n readonly unboundDispatches: number;\n /**\n * Registers the application's hooks and returns close(), which the kernel calls in onApplicationShutdown: a closed binding keeps\n * dispatching until another application binds (§10.6). A second bind() from the same owner for the same instance is a no-op that\n * returns the existing registration (NestMicroservice.init() runs lifecycle hooks twice); from the same owner for another instance it\n * throws PLUGIN_SHARED_BETWEEN_INSTANCES (B03). Throws INSTANCE_ALREADY_BOUND if another bootstrapped application is bound; takes over\n * a never-bootstrapped one (reported, B06) and a closed one (silently). A never-bootstrapped binding it takes over becomes\n * 'displaced': an application whose init() was still running when another bound fails in onApplicationBootstrap (B06).\n */\n bind(binding: BridgeBinding): { close(): void; tookOverFrom?: string };\n /** true when an endpoint returned `value` (an object) in a non-router dispatch observed while bound; false for before-hook short-circuits (LEAD-V37). */\n producedByEndpoint(value: unknown): boolean;\n}\nexport interface BridgeBinding {\n /** The application: compared by identity for the same-owner no-op; `description` goes into the B06 message. */\n readonly owner: { readonly description: string };\n /** The instance this plugin object serves; one plugin object serves one instance (B03). */\n readonly instance: string;\n /**\n * 'initialized' at bind; the kernel sets 'bootstrapped' in onApplicationBootstrap; close() sets 'closed'; bind() of another\n * application sets 'displaced' on an 'initialized' binding it takes over.\n */\n state: \"initialized\" | \"bootstrapped\" | \"closed\" | \"displaced\";\n /** View of the kernel's RequestScope; the plugin never owns an AsyncLocalStorage. [C] */\n current(): ScopeView | undefined;\n /** Credential header names declared by the instance's principal sources (credential matching, §7.5). */\n readonly credentialHeaders: readonly string[];\n readonly before: readonly CompiledHook[]; // sorted by order, then discovery order\n readonly after: readonly CompiledHook[];\n readonly database: Readonly<{\n [E in DatabaseHookTarget]: {\n readonly before: readonly DatabaseHookMethod<E, \"before\">[];\n readonly after: readonly DatabaseHookMethod<E, \"after\">[];\n };\n }>;\n /** Debug log when the bridge drops a direct call's cookies because its credential is foreign. */\n onDropped(path: string): void;\n}\nexport interface ScopeView {\n /** Cookie-capable forwarding handlers have already passed the enforcing form check on every method/operation (§7.10). */\n readonly cookies: CookieSink | null;\n readonly forward: \"none\" | \"same-credential\" | \"any\";\n readonly inbound: (() => Headers) | undefined;\n readonly internal: boolean;\n /**\n * Present in EVERY handler scope whose transport exposes a browser leg, unless the plan's origin check is 'off' — enforcing or not,\n * so safe methods and GraphQL queries are covered too (§7.5). Returns when this leg has a passing origin verdict for `instance`, or\n * the single kernel disable predicate (§7.10 item 4) holds; a guard run without a passing verdict is insufficient. Otherwise throws the kernel's\n * BetterAuthConfigurationError PUBLIC_HANDLER_USED_CALLER_SESSION.\n */\n readonly checkCallerSession?: (path: string, instance: string) => void;\n /** The browser leg's OWN headers (TransportCall.browser.headers()), before any transport credential mapping replaced them; undefined\n * when the transport exposes no browser leg. Entry 2 recognizes an ambiently carried session cookie with it. */\n readonly browserHeaders: (() => Headers) | undefined;\n}\nexport interface CompiledHook {\n /**\n * Evaluate the user predicate once and let it throw. The dispatcher logs and\n * converts before-hook matcher failures to APIError 500; after-hook matcher\n * failures cross the next fixed SDK matcher boundary unchanged, so the SDK\n * cannot recover them as handler APIErrors. Never swallow a failure as a\n * non-match or evaluate the predicate again in run().\n */\n matches(ctx: HookEndpointContext, scope: ScopeView | undefined): boolean;\n run(ctx: HookEndpointContext): Promise<unknown>;\n}\n","import type { BetterAuthOptions } from \"better-auth\";\nimport type { DatabaseHookTarget } from \"./auth-contracts.js\";\nimport type {\n DatabaseHookData,\n DatabaseHookResult,\n DbHookFn,\n} from \"./auth-types.js\";\nimport type { BridgeBinding } from \"./bridge-protocol.js\";\n\n/**\n * Construct all dispatchers once; bindings supply only the late-bound methods.\n *\n * The dispatchers take the SDK's own parameter types, so they satisfy `databaseHooks` whatever\n * instance the program registers. Bound hooks declare `DatabaseHookData`, which adds the\n * registered instance's plugin and additional fields (for example admin()'s `banned`) to the\n * same rows; the dispatcher states that narrowing once when it forwards a payload.\n */\nexport function createDatabaseDispatchers(\n getBinding: () => BridgeBinding | null,\n countUnbound: () => void,\n): NonNullable<BetterAuthOptions[\"databaseHooks\"]> {\n function operation<E extends DatabaseHookTarget>(target: E) {\n const before = async (\n ...[data, ctx]: Parameters<DbHookFn<E, \"before\">>\n ): Promise<DatabaseHookResult<E, \"before\">> => {\n const binding = getBinding();\n if (!binding) {\n countUnbound();\n return undefined as DatabaseHookResult<E, \"before\">;\n }\n const hooks = binding.database[target].before;\n let accumulated: Record<string, unknown> = {};\n let changed = false;\n for (const hook of hooks) {\n const result = await hook(\n (target.endsWith(\".create\")\n ? { ...data, ...accumulated }\n : data) as DatabaseHookData<E, \"before\">,\n ctx,\n );\n if (result === false) {\n return false as DatabaseHookResult<E, \"before\">;\n }\n if (\n !target.endsWith(\".delete\") &&\n result &&\n typeof result === \"object\" &&\n \"data\" in result\n ) {\n accumulated = { ...accumulated, ...result.data };\n changed = true;\n }\n }\n // A generic target cannot express the runtime delete narrowing. Delete\n // never reaches this branch; the public binding keeps its void/false type.\n return (\n changed ? { data: accumulated } : undefined\n ) as DatabaseHookResult<E, \"before\">;\n };\n const after = async (\n ...[data, ctx]: Parameters<DbHookFn<E, \"after\">>\n ): Promise<void> => {\n const binding = getBinding();\n if (!binding) {\n countUnbound();\n return;\n }\n for (const hook of binding.database[target].after) {\n await hook(data as DatabaseHookData<E, \"after\">, ctx);\n }\n };\n return { before, after };\n }\n return {\n user: {\n create: operation(\"user.create\"),\n update: operation(\"user.update\"),\n delete: operation(\"user.delete\"),\n },\n session: {\n create: operation(\"session.create\"),\n update: operation(\"session.update\"),\n delete: operation(\"session.delete\"),\n },\n account: {\n create: operation(\"account.create\"),\n update: operation(\"account.update\"),\n delete: operation(\"account.delete\"),\n },\n verification: {\n create: operation(\"verification.create\"),\n update: operation(\"verification.update\"),\n delete: operation(\"verification.delete\"),\n },\n };\n}\n","import type { HookEndpointContext } from \"better-auth\";\nimport { APIError, createAuthMiddleware, isAPIError } from \"better-auth/api\";\nimport { createDefu } from \"defu\";\nimport type { BridgeBinding, ScopeView } from \"./bridge-protocol.js\";\n\nconst API_ERROR_HEADERS = Symbol.for(\"better-call:api-error-headers\");\nconst mergeContext = createDefu((object, key, value) => {\n if (Array.isArray(object[key]) && Array.isArray(value)) {\n object[key] = value;\n return true;\n }\n});\n\nfunction mergeHeaders(\n target: Headers,\n source: Headers | null | undefined,\n): void {\n source?.forEach((value, key) => {\n if (key === \"set-cookie\") {\n target.append(key, value);\n } else {\n target.set(key, value);\n }\n });\n}\n\nfunction errorHeaders(error: APIError): Headers | undefined {\n const attached = (error as unknown as Record<symbol, Headers | undefined>)[\n API_ERROR_HEADERS\n ];\n if (!attached && !error.headers) {\n return undefined;\n }\n const headers = new Headers(attached);\n if (error.headers && error.headers !== attached) {\n mergeHeaders(headers, new Headers(error.headers));\n }\n return headers;\n}\n\n/** Run each method through the SDK middleware so its cookie/header state is isolated. */\nexport async function runBefore(\n binding: BridgeBinding,\n ctx: HookEndpointContext,\n scope: ScopeView | undefined,\n): Promise<unknown> {\n let accumulated: Record<string, unknown> = {};\n for (const hook of binding.before) {\n let matched: boolean;\n try {\n matched = hook.matches(ctx, scope);\n } catch (error) {\n ctx.context.logger.error(\n \"An error occurred during Nest hook matcher execution:\",\n error,\n );\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message:\n \"An error occurred during hook matcher execution. Check the logs for more details.\",\n });\n }\n if (!matched) {\n continue;\n }\n let result: { response: unknown; headers: Headers };\n try {\n result = (await createAuthMiddleware(hook.run)({\n ...ctx,\n returnHeaders: true,\n })) as { response: unknown; headers: Headers };\n } catch (error) {\n if (isAPIError(error)) {\n // The enclosing SDK middleware reattaches its own header object. Keep\n // the throwing method's headers, including non-enumerable cookie state.\n ctx.responseHeaders =\n (error as unknown as Record<symbol, Headers | undefined>)[\n API_ERROR_HEADERS\n ] ?? new Headers();\n }\n throw error;\n }\n ctx.context.responseHeaders ??= new Headers();\n mergeHeaders(ctx.context.responseHeaders, result.headers);\n const value = result.response;\n if (value && typeof value === \"object\") {\n if (\"context\" in value && typeof value.context === \"object\") {\n const { headers, ...rest } = value.context as Record<string, unknown>;\n if (headers instanceof Headers) {\n const requestHeaders =\n accumulated.headers instanceof Headers\n ? accumulated.headers\n : new Headers();\n headers.forEach((header, key) => {\n requestHeaders.set(key, header);\n });\n accumulated.headers = requestHeaders;\n }\n accumulated = mergeContext(rest, accumulated);\n } else {\n return value;\n }\n }\n }\n return Object.keys(accumulated).length ? { context: accumulated } : undefined;\n}\n\nexport async function runAfter(\n binding: BridgeBinding,\n ctx: HookEndpointContext,\n scope: ScopeView | undefined,\n relayMatcherError?: (error: unknown) => void,\n): Promise<unknown> {\n for (const hook of binding.after) {\n let matched: boolean;\n try {\n matched = hook.matches(ctx, scope);\n } catch (error) {\n if (!relayMatcherError) {\n throw error;\n }\n // A surrounding SDK handler catches APIErrors as recoverable results.\n // Stop here and rethrow from the next fixed SDK matcher instead.\n relayMatcherError(error);\n return undefined;\n }\n if (!matched) {\n continue;\n }\n let result: { response: unknown; headers?: Headers | null };\n try {\n result = (await createAuthMiddleware(hook.run)({\n ...ctx,\n returnHeaders: true,\n })) as { response: unknown; headers: Headers };\n } catch (error) {\n if (!isAPIError(error)) {\n throw error;\n }\n result = { response: error, headers: errorHeaders(error) };\n }\n if (result.headers) {\n ctx.context.responseHeaders ??= new Headers();\n mergeHeaders(ctx.context.responseHeaders, result.headers);\n }\n if (result.response !== undefined) {\n ctx.context.returned = result.response;\n }\n }\n return ctx.context.returned;\n}\n","import type { BetterAuthPlugin, HookEndpointContext } from \"better-auth\";\nimport {\n createAuthMiddleware,\n setShouldSkipSessionRefresh,\n} from \"better-auth/api\";\nimport { parseCookies } from \"better-auth/cookies\";\nimport type { NestjsPluginOptions } from \"./auth-contracts.js\";\nimport {\n BRIDGE_HANDLE,\n type BridgeBinding,\n type BridgeHandle,\n type ScopeView,\n} from \"./bridge-protocol.js\";\nimport { createDatabaseDispatchers } from \"./database-hook-dispatcher.js\";\nimport { runAfter, runBefore } from \"./hook-dispatcher.js\";\n\nexport type { NestjsPluginOptions } from \"./auth-contracts.js\";\nexport const NESTJS_PLUGIN_ID = \"@nestjs-kit/better-auth\";\n\nconst isRouter = (ctx: object): boolean =>\n \"_flag\" in ctx && ctx._flag === \"router\";\nconst separator = \"\\u0000\";\n\nfunction sessionToken(\n headers: Headers | undefined,\n ctx: HookEndpointContext,\n): string {\n return (\n parseCookies(headers?.get(\"cookie\") ?? \"\").get(\n ctx.context.authCookies.sessionToken.name,\n ) ?? \"\"\n );\n}\n\nfunction credential(\n headers: Headers | undefined,\n ctx: HookEndpointContext,\n extra: readonly string[],\n): string {\n return [\n sessionToken(headers, ctx),\n headers?.get(\"authorization\") ?? \"\",\n ...extra.map((name) => headers?.get(name) ?? \"\"),\n ].join(separator);\n}\n\nfunction sameCredential(\n ctx: HookEndpointContext,\n scope: ScopeView,\n extra: readonly string[],\n): boolean {\n const call = credential(ctx.headers, ctx, extra);\n return (\n call === separator.repeat(extra.length + 1) ||\n call === credential(scope.inbound?.(), ctx, extra)\n );\n}\n\n/** Pure construction-time Better Auth plugin; the Nest kernel binds through a global symbol. */\nexport function nestjs(\n options: NestjsPluginOptions = {},\n): BetterAuthPlugin & { id: typeof NESTJS_PLUGIN_ID } {\n let binding: BridgeBinding | null = null;\n let registration: ReturnType<BridgeHandle[\"bind\"]> | undefined;\n let unboundDispatches = 0;\n const endpointResults = new WeakSet<object>();\n const afterMatcherErrors = new WeakMap<object, unknown>();\n const scope = () => binding?.current();\n const clientIpHeader =\n options.clientIpHeader === false\n ? null\n : (options.clientIpHeader ??\n `x-nestjs-kit-better-auth-ip-${globalThis.crypto.randomUUID().replaceAll(\"-\", \"\")}`);\n const handle: BridgeHandle = {\n protocol: 4,\n clientIpHeader,\n get state() {\n return binding === null\n ? \"unbound\"\n : binding.state === \"closed\"\n ? \"closed\"\n : \"bound\";\n },\n get unboundDispatches() {\n return unboundDispatches;\n },\n bind(next) {\n if (binding && binding.instance !== next.instance) {\n throw new Error(\n `PLUGIN_SHARED_BETWEEN_INSTANCES: '${binding.instance}' and '${next.instance}'`,\n );\n }\n if (binding?.owner === next.owner && registration) {\n return registration;\n }\n if (binding?.state === \"bootstrapped\") {\n throw new Error(\n `INSTANCE_ALREADY_BOUND: bound to ${binding.owner.description}`,\n );\n }\n let tookOverFrom: string | undefined;\n if (binding?.state === \"initialized\") {\n tookOverFrom = binding.owner.description;\n // Its application may still be initializing: its bootstrap must fail rather than run without hooks.\n binding.state = \"displaced\";\n }\n binding = next;\n unboundDispatches = 0;\n registration = {\n tookOverFrom,\n close: () => {\n next.state = \"closed\";\n },\n };\n return registration;\n },\n producedByEndpoint(value) {\n return (\n typeof value === \"object\" &&\n value !== null &&\n endpointResults.has(value)\n );\n },\n };\n const plugin = {\n id: NESTJS_PLUGIN_ID,\n [BRIDGE_HANDLE]: handle,\n init: () => ({\n options: {\n databaseHooks: createDatabaseDispatchers(\n () => binding,\n () => {\n unboundDispatches++;\n },\n ),\n ...(clientIpHeader\n ? { advanced: { ipAddress: { ipAddressHeaders: [clientIpHeader] } } }\n : {}),\n },\n }),\n hooks: {\n before: [\n {\n matcher: (ctx) => {\n if (!binding) {\n unboundDispatches++;\n return false;\n }\n return !isRouter(ctx) && scope()?.cookies === null;\n },\n handler: createAuthMiddleware(async () => {\n await setShouldSkipSessionRefresh(true);\n }),\n },\n {\n matcher: (ctx) => {\n if (!binding || isRouter(ctx)) {\n return false;\n }\n const current = scope();\n if (!current || current.internal) {\n return false;\n }\n // Access capabilities before testing credentials: extraction errors\n // must fail even a credential-free direct endpoint call.\n const check = current.checkCallerSession;\n current.inbound?.();\n const browser = current.browserHeaders?.();\n const token = sessionToken(ctx.headers, ctx);\n // Only the browser leg's own cookie is ambient. A session cookie that a\n // transport mapped in-band (graphql-ws connectionParams, socket\n // credentials) cannot ride a cross-site request.\n return (\n !!check && token !== \"\" && token === sessionToken(browser, ctx)\n );\n },\n handler: createAuthMiddleware(async (ctx) => {\n scope()?.checkCallerSession?.(ctx.path, binding!.instance);\n }),\n },\n {\n matcher: () => binding !== null && binding.before.length > 0,\n handler: createAuthMiddleware((ctx) =>\n runBefore(binding!, ctx, scope()),\n ),\n },\n ],\n after: [\n {\n matcher: () => binding !== null && binding.after.length > 0,\n handler: createAuthMiddleware((ctx) =>\n runAfter(binding!, ctx, scope(), (error) => {\n afterMatcherErrors.set(ctx.context, error);\n }),\n ),\n },\n {\n matcher: (ctx) => {\n // Each endpoint dispatch owns this shared context, including nested\n // calls. Rethrow outside the SDK's recoverable handler-error catch.\n if (afterMatcherErrors.has(ctx.context)) {\n const error = afterMatcherErrors.get(ctx.context);\n afterMatcherErrors.delete(ctx.context);\n throw error;\n }\n return binding !== null && !isRouter(ctx);\n },\n handler: createAuthMiddleware(async (ctx) => {\n const value = ctx.context.returned;\n if (typeof value === \"object\" && value !== null) {\n endpointResults.add(value);\n }\n }),\n },\n {\n matcher: (ctx) => {\n if (isRouter(ctx)) {\n return false;\n }\n const current = scope();\n return !!current?.cookies && current.forward !== \"none\";\n },\n handler: createAuthMiddleware(async (ctx) => {\n const current = scope()!;\n if (\n current.forward === \"same-credential\" &&\n !sameCredential(ctx, current, binding!.credentialHeaders)\n ) {\n binding!.onDropped(ctx.path);\n return;\n }\n const cookies = ctx.context.responseHeaders?.getSetCookie() ?? [];\n if (cookies.length) {\n current.cookies!.append(cookies);\n }\n }),\n },\n ],\n },\n } satisfies BetterAuthPlugin & { [BRIDGE_HANDLE]: BridgeHandle };\n return plugin;\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { BetterAuthPlugin } from "better-auth";
2
+ import "@nestjs/common";
3
+ import "@nestjs/core";
4
+ import "rxjs";
5
+ //#region src/auth-contracts.d.ts
6
+ interface NestjsPluginOptions {
7
+ /**
8
+ * Header better-auth reads the client IP from, contributed to advanced.ipAddress.ipAddressHeaders as a default
9
+ * (user values win and come first). Default: a random name per plugin instance (per nestjs() call), `x-nestjs-kit-better-auth-ip-<32 hex chars>`, generated with
10
+ * globalThis.crypto.randomUUID(); it never leaves the process and clients cannot guess it. A string pins a fixed name
11
+ * (for a trusted sidecar that calls auth.handler itself); false contributes nothing (configure advanced.ipAddress yourself).
12
+ */
13
+ clientIpHeader?: string | false;
14
+ }
15
+ //#endregion
16
+ //#region src/plugin.d.ts
17
+ export declare const NESTJS_PLUGIN_ID = "@nestjs-kit/better-auth";
18
+ /** Pure construction-time Better Auth plugin; the Nest kernel binds through a global symbol. */
19
+ export declare function nestjs(options?: NestjsPluginOptions): BetterAuthPlugin & {
20
+ id: typeof NESTJS_PLUGIN_ID;
21
+ };
22
+ //#endregion
23
+ export type { NestjsPluginOptions };
24
+ //# sourceMappingURL=plugin.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.cts","names":[],"sources":["../src/auth-contracts.ts","../src/plugin.ts"],"mappings":";;;;;UAuXiB;;;;;;;EAOf;;;;qBC7WW;;wBA0CG,OACd,UAAS,sBACR;EAAqB,WAAW"}
@@ -0,0 +1,24 @@
1
+ import { BetterAuthPlugin } from "better-auth";
2
+ import "@nestjs/common";
3
+ import "@nestjs/core";
4
+ import "rxjs";
5
+ //#region src/auth-contracts.d.ts
6
+ interface NestjsPluginOptions {
7
+ /**
8
+ * Header better-auth reads the client IP from, contributed to advanced.ipAddress.ipAddressHeaders as a default
9
+ * (user values win and come first). Default: a random name per plugin instance (per nestjs() call), `x-nestjs-kit-better-auth-ip-<32 hex chars>`, generated with
10
+ * globalThis.crypto.randomUUID(); it never leaves the process and clients cannot guess it. A string pins a fixed name
11
+ * (for a trusted sidecar that calls auth.handler itself); false contributes nothing (configure advanced.ipAddress yourself).
12
+ */
13
+ clientIpHeader?: string | false;
14
+ }
15
+ //#endregion
16
+ //#region src/plugin.d.ts
17
+ export declare const NESTJS_PLUGIN_ID = "@nestjs-kit/better-auth";
18
+ /** Pure construction-time Better Auth plugin; the Nest kernel binds through a global symbol. */
19
+ export declare function nestjs(options?: NestjsPluginOptions): BetterAuthPlugin & {
20
+ id: typeof NESTJS_PLUGIN_ID;
21
+ };
22
+ //#endregion
23
+ export type { NestjsPluginOptions };
24
+ //# sourceMappingURL=plugin.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.mts","names":[],"sources":["../src/auth-contracts.ts","../src/plugin.ts"],"mappings":";;;;;UAuXiB;;;;;;;EAOf;;;;qBC7WW;;wBA0CG,OACd,UAAS,sBACR;EAAqB,WAAW"}