@nestjs-kit/better-auth 0.0.0-stage → 2.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 (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,383 @@
1
+ import { c as isConfigurationError, l as isInfrastructureError, n as BetterAuthConfigurationError, p as readErrorProperty, s as isAuthFailure, t as AuthFailures } from "./auth-errors-C3rbTV9p.mjs";
2
+ import { C as PRINCIPAL_RESOLVER, M as TRANSPORT_REGISTRY, P as WS_CONNECTION_AUTH, m as INSTANCE_REGISTRY, n as __decorateParam, r as __decorateMetadata, t as __decorate } from "./decorate-Dt0e9K6R.mjs";
3
+ import { n as EXTENSION_DEFINITION, r as UPGRADE_REQUEST } from "./bridge-protocol-c66aEkr5.mjs";
4
+ import { o as toWebHeaders, s as upgradeRequestUrl } from "./platform-CZl7TY8j.mjs";
5
+ import { Inject, Logger } from "@nestjs/common";
6
+ import { MetadataScanner } from "@nestjs/core";
7
+ import { SubscribeMessage, WebSocketGateway, WsException } from "@nestjs/websockets";
8
+ //#region src/ws-connection-auth.ts
9
+ function wsCloseCodeFor(failure) {
10
+ return failure.status === 401 ? 4401 : failure.status === 403 ? 4403 : 4429;
11
+ }
12
+ const STACK_FRAME = /^\s+at .+:\d+:\d+\)?$/;
13
+ /**
14
+ * Describes an unexpected connection-authentication error for the server log. Package
15
+ * errors carry fixed messages and already-redacted causes. Application and runtime error
16
+ * messages can quote client credentials (native Headers errors do), so only their name
17
+ * and stack frames are kept.
18
+ */
19
+ function connectionErrorLog(error) {
20
+ const text = (value) => typeof value === "string" ? value : void 0;
21
+ let summary;
22
+ if (isConfigurationError(error)) summary = `${error.code}: ${error.detail}`;
23
+ else if (isInfrastructureError(error)) {
24
+ const cause = readErrorProperty(error, "cause");
25
+ summary = `${error.message} (${text(readErrorProperty(cause, "name")) ?? "Error"}: ${text(readErrorProperty(cause, "message")) ?? ""})`;
26
+ } else {
27
+ const name = text(readErrorProperty(error, "name"));
28
+ summary = `${name !== void 0 && /^[\w$.]{1,64}$/.test(name) ? name : typeof error} (message withheld)`;
29
+ }
30
+ const frames = (text(readErrorProperty(error, "stack")) ?? "").split(/\r?\n/).filter((line) => STACK_FRAME.test(line));
31
+ return {
32
+ message: `WebSocket connection authentication failed: ${summary}`,
33
+ stack: frames.length > 0 ? [summary, ...frames].join("\n") : void 0
34
+ };
35
+ }
36
+ /**
37
+ * The `ws` execution context of a connection before any gateway handler runs. Nest exports no
38
+ * public factory for execution contexts, so this implements the public `ExecutionContext`
39
+ * interface with the values Nest's internal host reports for the arguments `[client, undefined]`.
40
+ */
41
+ var ConnectionExecutionContext = class {
42
+ #args;
43
+ constructor(client) {
44
+ this.#args = [client, void 0];
45
+ }
46
+ getType() {
47
+ return "ws";
48
+ }
49
+ /** No handler runs yet, so there is no class; Nest's host reports `null` as well. */
50
+ getClass() {
51
+ return null;
52
+ }
53
+ /** No handler runs yet; Nest's host reports `null` as well. */
54
+ getHandler() {
55
+ return null;
56
+ }
57
+ getArgs() {
58
+ return this.#args;
59
+ }
60
+ getArgByIndex(index) {
61
+ return this.#args[index];
62
+ }
63
+ switchToHttp() {
64
+ return {
65
+ getRequest: () => this.getArgByIndex(0),
66
+ getResponse: () => this.getArgByIndex(1),
67
+ getNext: () => this.getArgByIndex(2)
68
+ };
69
+ }
70
+ switchToRpc() {
71
+ return {
72
+ getData: () => this.getArgByIndex(0),
73
+ getContext: () => this.getArgByIndex(1)
74
+ };
75
+ }
76
+ switchToWs() {
77
+ return {
78
+ getClient: () => this.getArgByIndex(0),
79
+ getData: () => this.getArgByIndex(1),
80
+ getPattern: () => this.getArgByIndex(this.#args.length - 1)
81
+ };
82
+ }
83
+ };
84
+ let WsConnectionAuth = class WsConnectionAuth {
85
+ instances;
86
+ resolver;
87
+ transports;
88
+ logger = new Logger("BetterAuth");
89
+ constructor(instances, resolver, transports) {
90
+ this.instances = instances;
91
+ this.resolver = resolver;
92
+ this.transports = transports;
93
+ }
94
+ async authenticate(client, options = {}) {
95
+ if (typeof client !== "object" || client === null) throw BetterAuthConfigurationError.atRequest("INVALID_WS_CLIENT", "Connection authentication requires a WebSocket client.");
96
+ const context = new ConnectionExecutionContext(client);
97
+ const transport = this.transports.select(context);
98
+ const call = this.transports.describe(context, transport);
99
+ const entry = this.instances.get(options.instance ?? "default");
100
+ const browser = call.browser;
101
+ if (browser && entry.options.originCheck?.mode !== "off") {
102
+ const failure = await entry.handle.checkOrigin(browser, "cookie");
103
+ if (failure) return {
104
+ outcome: "rejected",
105
+ failure
106
+ };
107
+ }
108
+ const accepts = new Set(entry.sources.filter((source) => source.acceptance === "default").flatMap((source) => [...source.kinds]));
109
+ try {
110
+ return await this.resolver.resolve(call, {
111
+ auth: entry.handle,
112
+ accepts,
113
+ sourceSet: JSON.stringify(entry.sources.flatMap((source, index) => source.kinds.some((kind) => accepts.has(kind)) ? [index] : [])),
114
+ freshness: entry.options.session !== false && entry.options.session?.freshness === "authoritative" ? "authoritative" : "default"
115
+ });
116
+ } catch (error) {
117
+ if (isAuthFailure(error)) return {
118
+ outcome: "rejected",
119
+ failure: error
120
+ };
121
+ throw error;
122
+ }
123
+ }
124
+ socketIoMiddleware(options = {}) {
125
+ return (socket, next) => {
126
+ this.authenticate(socket, options).then((result) => {
127
+ const failure = result.outcome === "rejected" ? result.failure : result.outcome === "absent" && options.required ? AuthFailures.unauthenticated() : void 0;
128
+ if (!failure) {
129
+ next();
130
+ return;
131
+ }
132
+ next(Object.assign(new Error(failure.message), { data: {
133
+ status: "error",
134
+ statusCode: failure.status,
135
+ code: failure.code,
136
+ ...failure.reason ? { reason: failure.reason } : {},
137
+ message: failure.message
138
+ } }));
139
+ }, (error) => {
140
+ const log = connectionErrorLog(error);
141
+ this.logger.error(log.message, log.stack);
142
+ next(Object.assign(/* @__PURE__ */ new Error("Internal server error"), { data: {
143
+ status: "error",
144
+ statusCode: 500,
145
+ message: "Internal server error"
146
+ } }));
147
+ });
148
+ };
149
+ }
150
+ };
151
+ WsConnectionAuth = __decorate([
152
+ __decorateParam(0, Inject(INSTANCE_REGISTRY)),
153
+ __decorateParam(1, Inject(PRINCIPAL_RESOLVER)),
154
+ __decorateParam(2, Inject(TRANSPORT_REGISTRY)),
155
+ __decorateMetadata("design:paramtypes", [
156
+ Object,
157
+ Object,
158
+ Object
159
+ ])
160
+ ], WsConnectionAuth);
161
+ //#endregion
162
+ //#region src/socket-io-transport.ts
163
+ /** Convert only mapped headers here: native Headers errors can quote the credential. */
164
+ function mappedCredentialHeaders(input) {
165
+ const headers = new Headers();
166
+ if (input === void 0) return headers;
167
+ const malformed = () => AuthFailures.rejected({
168
+ status: 401,
169
+ reason: "MALFORMED_CREDENTIALS"
170
+ });
171
+ if (input === null || typeof input !== "object") throw malformed();
172
+ const iterable = input[Symbol.iterator];
173
+ if (iterable !== void 0 && typeof iterable !== "function") throw malformed();
174
+ const entries = typeof iterable === "function" ? input : Object.entries(input);
175
+ for (const entry of entries) {
176
+ if (!Array.isArray(entry) || entry.length !== 2) throw malformed();
177
+ const [name, value] = entry;
178
+ if (typeof name !== "string" || typeof value !== "string" || /[\r\n\0]/.test(value)) throw malformed();
179
+ try {
180
+ headers.append(name, value);
181
+ } catch {
182
+ throw malformed();
183
+ }
184
+ }
185
+ return headers;
186
+ }
187
+ function isSocketIo(client) {
188
+ return typeof client === "object" && client !== null && "handshake" in client;
189
+ }
190
+ function wsException(failure) {
191
+ return new WsException({
192
+ status: "error",
193
+ statusCode: failure.status,
194
+ code: failure.code,
195
+ ...failure.reason ? { reason: failure.reason } : {},
196
+ message: failure.message
197
+ });
198
+ }
199
+ function validateGateways(context, coverage) {
200
+ class Probe {
201
+ message() {}
202
+ }
203
+ WebSocketGateway()(Probe);
204
+ SubscribeMessage("probe")(Probe.prototype, "message", Object.getOwnPropertyDescriptor(Probe.prototype, "message"));
205
+ if (Reflect.getMetadata("websockets:is_gateway", Probe) !== true || Reflect.getMetadata("websockets:message_mapping", Probe.prototype.message) !== true) throw new BetterAuthConfigurationError("NEST_METADATA_KEY_CHANGED", "Nest WebSocket gateway/message metadata failed its canary.");
206
+ const scanner = new MetadataScanner();
207
+ for (const wrapper of context.discovery.getProviders()) {
208
+ const target = wrapper.metatype;
209
+ if (!target?.prototype || wrapper.isAlias || !Reflect.getMetadata("websockets:is_gateway", target)) continue;
210
+ for (const method of scanner.getAllMethodNames(target.prototype)) if (Reflect.getMetadata("websockets:message_mapping", target.prototype[method])) context.claim(target, method, "explicit", {
211
+ everyHandler: true,
212
+ code: "GATEWAY_UNGUARDED",
213
+ coverage: coverage ?? "error",
214
+ hint: `Add @UseBetterAuth() to ${target.name} (or @Public() to opt out). Global guards and interceptors do not reach gateways on NestJS 11, and this check does not depend on the version.`
215
+ });
216
+ }
217
+ }
218
+ function quotaAdvice(context, ttl) {
219
+ return ttl === 0 && context.sources.some((source) => source.effects?.consumesQuota) ? [{
220
+ level: "warn",
221
+ code: "W_QUOTA_PER_MESSAGE",
222
+ message: "Quota-consuming WebSocket principals verify on every message.",
223
+ hint: "Consider connection-time authentication and principalTtlMs; a positive TTL delays revocation on non-authoritative handlers."
224
+ }] : [];
225
+ }
226
+ function transportDefinition(transport) {
227
+ return {
228
+ [EXTENSION_DEFINITION]: true,
229
+ use: { useFactory: () => transport },
230
+ providers: [WsConnectionAuth, {
231
+ provide: WS_CONNECTION_AUTH,
232
+ useExisting: WsConnectionAuth
233
+ }],
234
+ exports: [WsConnectionAuth, WS_CONNECTION_AUTH]
235
+ };
236
+ }
237
+ function principalTtl(value = 0) {
238
+ if (!Number.isFinite(value) || value < 0) throw new BetterAuthConfigurationError("INVALID_WS_TTL", "principalTtlMs must be a finite non-negative number.");
239
+ return value;
240
+ }
241
+ function socketIoTransport(options = {}) {
242
+ const ttl = principalTtl(options.principalTtlMs);
243
+ return transportDefinition({
244
+ id: "socket.io",
245
+ handles: (context) => context.getType() === "ws" && isSocketIo(context.switchToWs().getClient()),
246
+ describe(context) {
247
+ const client = context.switchToWs().getClient();
248
+ const original = () => toWebHeaders(client.handshake.headers);
249
+ return {
250
+ key: context.getArgs(),
251
+ invocation: context.getArgs(),
252
+ connection: client,
253
+ principalTtlMs: ttl,
254
+ headers: () => {
255
+ const headers = original();
256
+ let mapped;
257
+ if (options.credentials) mapped = options.credentials(client);
258
+ else if (!headers.has("authorization")) {
259
+ const token = client.handshake.auth?.token;
260
+ if (token !== void 0) {
261
+ if (typeof token !== "string") throw AuthFailures.rejected({
262
+ status: 401,
263
+ reason: "MALFORMED_CREDENTIALS"
264
+ });
265
+ mapped = { authorization: `Bearer ${token}` };
266
+ }
267
+ }
268
+ mappedCredentialHeaders(mapped).forEach((value, name) => {
269
+ headers.set(name, value);
270
+ });
271
+ return headers;
272
+ },
273
+ get clientIp() {
274
+ return client.handshake.address ?? null;
275
+ },
276
+ cookies: null,
277
+ get request() {
278
+ return {
279
+ method: "GET",
280
+ url: upgradeRequestUrl(client.handshake)
281
+ };
282
+ },
283
+ param: (name) => context.switchToWs().getData()?.[name],
284
+ get browser() {
285
+ return {
286
+ enforce: true,
287
+ key: client,
288
+ headers: original,
289
+ url: upgradeRequestUrl(client.handshake)
290
+ };
291
+ }
292
+ };
293
+ },
294
+ toException: wsException,
295
+ validate: (context) => validateGateways(context, options.gatewayCoverage),
296
+ advise: (context) => quotaAdvice(context, ttl)
297
+ });
298
+ }
299
+ //#endregion
300
+ //#region src/ws-transport.ts
301
+ function recordUpgradeRequest(client, request) {
302
+ Object.defineProperty(client, UPGRADE_REQUEST, {
303
+ value: Object.freeze({
304
+ headers: toWebHeaders(request.headers),
305
+ url: request.url,
306
+ remoteAddress: request.socket?.remoteAddress,
307
+ encrypted: request.socket?.encrypted
308
+ }),
309
+ configurable: true
310
+ });
311
+ }
312
+ function withUpgradeRequest(Base) {
313
+ return class extends Base {
314
+ bindClientConnect(server, callback) {
315
+ return super.bindClientConnect(server, (client, request, ...rest) => {
316
+ recordUpgradeRequest(client, request);
317
+ callback(client, request, ...rest);
318
+ });
319
+ }
320
+ };
321
+ }
322
+ function wsTransport(options = {}) {
323
+ const ttl = principalTtl(options.principalTtlMs);
324
+ return transportDefinition({
325
+ id: "ws",
326
+ handles: (context) => context.getType() === "ws" && !isSocketIo(context.switchToWs().getClient()),
327
+ describe(context) {
328
+ const client = context.switchToWs().getClient();
329
+ const upgrade = () => {
330
+ const request = client[UPGRADE_REQUEST];
331
+ if (!request) throw BetterAuthConfigurationError.atRequest("WS_UPGRADE_REQUEST_MISSING", "WebSocket authentication requires its upgrade request.", { hint: "app.useWebSocketAdapter(new (withUpgradeRequest(WsAdapter))(app));" });
332
+ return request;
333
+ };
334
+ const url = () => {
335
+ const request = upgrade();
336
+ return upgradeRequestUrl({
337
+ headers: request.headers,
338
+ url: request.url,
339
+ secure: request.encrypted
340
+ });
341
+ };
342
+ return {
343
+ key: context.getArgs(),
344
+ invocation: context.getArgs(),
345
+ connection: client,
346
+ principalTtlMs: ttl,
347
+ headers: () => {
348
+ const headers = new Headers(upgrade().headers);
349
+ mappedCredentialHeaders(options.credentials?.(client)).forEach((value, name) => {
350
+ headers.set(name, value);
351
+ });
352
+ return headers;
353
+ },
354
+ get clientIp() {
355
+ return upgrade().remoteAddress ?? null;
356
+ },
357
+ cookies: null,
358
+ get request() {
359
+ return {
360
+ method: "GET",
361
+ url: url()
362
+ };
363
+ },
364
+ param: (name) => context.switchToWs().getData()?.[name],
365
+ get browser() {
366
+ return {
367
+ enforce: true,
368
+ key: client,
369
+ headers: () => new Headers(upgrade().headers),
370
+ url: url()
371
+ };
372
+ }
373
+ };
374
+ },
375
+ toException: wsException,
376
+ validate: (context) => validateGateways(context, options.gatewayCoverage),
377
+ advise: (context) => quotaAdvice(context, ttl)
378
+ });
379
+ }
380
+ //#endregion
381
+ export { UPGRADE_REQUEST, WS_CONNECTION_AUTH, WsConnectionAuth, recordUpgradeRequest, socketIoTransport, withUpgradeRequest, wsCloseCodeFor, wsTransport };
382
+
383
+ //# sourceMappingURL=websockets.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websockets.mjs","names":[],"sources":["../src/ws-connection-auth.ts","../src/socket-io-transport.ts","../src/ws-transport.ts"],"sourcesContent":["import {\n type ContextType,\n type ExecutionContext,\n Inject,\n Logger,\n type Type,\n} from \"@nestjs/common\";\nimport type { PrincipalResolver, PrincipalResult } from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n isAuthFailure,\n isConfigurationError,\n isInfrastructureError,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport {\n INSTANCE_REGISTRY,\n PRINCIPAL_RESOLVER,\n TRANSPORT_REGISTRY,\n} from \"./auth-tokens.js\";\nimport { readErrorProperty } from \"./error-redactor.js\";\nimport type { InstanceLookup } from \"./instance-registry.js\";\nimport type { TransportRegistry } from \"./transport-registry.js\";\n\nexport { WS_CONNECTION_AUTH } from \"./auth-tokens.js\";\nexport function wsCloseCodeFor(failure: AuthFailure): 4401 | 4403 | 4429 {\n return failure.status === 401 ? 4401 : failure.status === 403 ? 4403 : 4429;\n}\n\nconst STACK_FRAME = /^\\s+at .+:\\d+:\\d+\\)?$/;\n\n/**\n * Describes an unexpected connection-authentication error for the server log. Package\n * errors carry fixed messages and already-redacted causes. Application and runtime error\n * messages can quote client credentials (native Headers errors do), so only their name\n * and stack frames are kept.\n */\nexport function connectionErrorLog(error: unknown): {\n message: string;\n stack?: string;\n} {\n const text = (value: unknown) =>\n typeof value === \"string\" ? value : undefined;\n let summary: string;\n if (isConfigurationError(error)) {\n summary = `${error.code}: ${error.detail}`;\n } else if (isInfrastructureError(error)) {\n const cause = readErrorProperty(error, \"cause\");\n summary = `${error.message} (${text(readErrorProperty(cause, \"name\")) ?? \"Error\"}: ${text(readErrorProperty(cause, \"message\")) ?? \"\"})`;\n } else {\n const name = text(readErrorProperty(error, \"name\"));\n summary = `${name !== undefined && /^[\\w$.]{1,64}$/.test(name) ? name : typeof error} (message withheld)`;\n }\n const frames = (text(readErrorProperty(error, \"stack\")) ?? \"\")\n .split(/\\r?\\n/)\n .filter((line) => STACK_FRAME.test(line));\n return {\n message: `WebSocket connection authentication failed: ${summary}`,\n stack: frames.length > 0 ? [summary, ...frames].join(\"\\n\") : undefined,\n };\n}\n\n/**\n * The `ws` execution context of a connection before any gateway handler runs. Nest exports no\n * public factory for execution contexts, so this implements the public `ExecutionContext`\n * interface with the values Nest's internal host reports for the arguments `[client, undefined]`.\n */\nexport class ConnectionExecutionContext implements ExecutionContext {\n readonly #args: unknown[];\n\n constructor(client: object) {\n this.#args = [client, undefined];\n }\n\n getType<TContext extends string = ContextType>(): TContext {\n return \"ws\" as TContext;\n }\n\n /** No handler runs yet, so there is no class; Nest's host reports `null` as well. */\n getClass<T>(): Type<T> {\n return null as unknown as Type<T>;\n }\n\n /** No handler runs yet; Nest's host reports `null` as well. */\n getHandler(): ReturnType<ExecutionContext[\"getHandler\"]> {\n return null as unknown as ReturnType<ExecutionContext[\"getHandler\"]>;\n }\n\n getArgs<T extends unknown[] = unknown[]>(): T {\n return this.#args as T;\n }\n\n getArgByIndex<T>(index: number): T {\n return this.#args[index] as T;\n }\n\n switchToHttp(): ReturnType<ExecutionContext[\"switchToHttp\"]> {\n return {\n getRequest: <T>() => this.getArgByIndex<T>(0),\n getResponse: <T>() => this.getArgByIndex<T>(1),\n getNext: <T>() => this.getArgByIndex<T>(2),\n };\n }\n\n switchToRpc(): ReturnType<ExecutionContext[\"switchToRpc\"]> {\n return {\n getData: <T>() => this.getArgByIndex<T>(0),\n getContext: <T>() => this.getArgByIndex<T>(1),\n };\n }\n\n switchToWs(): ReturnType<ExecutionContext[\"switchToWs\"]> {\n return {\n getClient: <T>() => this.getArgByIndex<T>(0),\n getData: <T>() => this.getArgByIndex<T>(1),\n getPattern: () => this.getArgByIndex<string>(this.#args.length - 1),\n };\n }\n}\n\n/** Connection authentication delegates to the same origin and principal kernel as messages. */\nexport class WsConnectionAuth {\n private readonly logger = new Logger(\"BetterAuth\");\n\n constructor(\n @Inject(INSTANCE_REGISTRY) private readonly instances: InstanceLookup,\n @Inject(PRINCIPAL_RESOLVER) private readonly resolver: PrincipalResolver,\n @Inject(TRANSPORT_REGISTRY) private readonly transports: TransportRegistry,\n ) {}\n\n async authenticate(\n client: unknown,\n options: { instance?: string } = {},\n ): Promise<PrincipalResult> {\n if (typeof client !== \"object\" || client === null) {\n throw BetterAuthConfigurationError.atRequest(\n \"INVALID_WS_CLIENT\",\n \"Connection authentication requires a WebSocket client.\",\n );\n }\n const context = new ConnectionExecutionContext(client);\n const transport = this.transports.select(context);\n const call = this.transports.describe(context, transport);\n const entry = this.instances.get(options.instance ?? \"default\");\n const browser = call.browser;\n if (browser && entry.options.originCheck?.mode !== \"off\") {\n const failure = await entry.handle.checkOrigin(browser, \"cookie\");\n if (failure) {\n return { outcome: \"rejected\", failure };\n }\n }\n const accepts = new Set(\n entry.sources\n .filter((source) => source.acceptance === \"default\")\n .flatMap((source) => [...source.kinds]),\n );\n try {\n return await this.resolver.resolve(call, {\n auth: entry.handle,\n accepts,\n sourceSet: JSON.stringify(\n entry.sources.flatMap((source, index) =>\n source.kinds.some((kind) => accepts.has(kind)) ? [index] : [],\n ),\n ),\n freshness:\n entry.options.session !== false &&\n entry.options.session?.freshness === \"authoritative\"\n ? \"authoritative\"\n : \"default\",\n });\n } catch (error) {\n if (isAuthFailure(error)) {\n return { outcome: \"rejected\", failure: error };\n }\n throw error;\n }\n }\n\n socketIoMiddleware(\n options: { required?: boolean; instance?: string } = {},\n ): (socket: unknown, next: (error?: Error) => void) => void {\n return (socket, next) => {\n void this.authenticate(socket, options).then(\n (result) => {\n const failure =\n result.outcome === \"rejected\"\n ? result.failure\n : result.outcome === \"absent\" && options.required\n ? AuthFailures.unauthenticated()\n : undefined;\n if (!failure) {\n next();\n return;\n }\n next(\n Object.assign(new Error(failure.message), {\n data: {\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n },\n }),\n );\n },\n (error: unknown) => {\n const log = connectionErrorLog(error);\n this.logger.error(log.message, log.stack);\n next(\n Object.assign(new Error(\"Internal server error\"), {\n data: {\n status: \"error\",\n statusCode: 500,\n message: \"Internal server error\",\n },\n }),\n );\n },\n );\n };\n }\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { ExecutionContext } from \"@nestjs/common\";\nimport { MetadataScanner } from \"@nestjs/core\";\nimport {\n SubscribeMessage,\n WebSocketGateway,\n WsException,\n} from \"@nestjs/websockets\";\nimport {\n type AuthTransport,\n type BootAdvice,\n type BootAdviceContext,\n type ExtensionDefinition,\n type TransportCall,\n type TransportValidationContext,\n} from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport { EXTENSION_DEFINITION } from \"./bridge-protocol.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport { WsConnectionAuth, WS_CONNECTION_AUTH } from \"./ws-connection-auth.js\";\n\nexport interface WsTransportOptions<C> {\n /** Replaces principal credentials without changing the browser handshake used for origin checks. */\n credentials?: (client: C) => HeadersInit | undefined;\n /** Defaults to zero. Positive values delay revocation for non-authoritative messages. */\n principalTtlMs?: number;\n /** Every message handler requires explicit guard and scope coverage on every Nest major. */\n gatewayCoverage?: \"error\" | \"warn\" | \"off\";\n}\nexport interface SocketIoClientLike {\n readonly handshake: {\n readonly headers: IncomingHttpHeaders;\n readonly auth?: Record<string, unknown>;\n readonly address?: string;\n readonly url?: string;\n readonly secure?: boolean;\n };\n}\n/** Convert only mapped headers here: native Headers errors can quote the credential. */\nexport function mappedCredentialHeaders(\n input: HeadersInit | undefined,\n): Headers {\n const headers = new Headers();\n if (input === undefined) {\n return headers;\n }\n const malformed = () =>\n AuthFailures.rejected({ status: 401, reason: \"MALFORMED_CREDENTIALS\" });\n if (input === null || typeof input !== \"object\") {\n throw malformed();\n }\n // Read caller-provided getters/iterators outside the conversion catch so their\n // programming errors remain errors, as do errors thrown by the mapper itself.\n const iterable = (input as { [Symbol.iterator]?: unknown })[Symbol.iterator];\n if (iterable !== undefined && typeof iterable !== \"function\") {\n throw malformed();\n }\n const entries: Iterable<unknown> =\n typeof iterable === \"function\"\n ? (input as Iterable<unknown>)\n : Object.entries(input);\n for (const entry of entries) {\n if (!Array.isArray(entry) || entry.length !== 2) {\n throw malformed();\n }\n const [name, value] = entry;\n if (\n typeof name !== \"string\" ||\n typeof value !== \"string\" ||\n /[\\r\\n\\0]/.test(value)\n ) {\n throw malformed();\n }\n try {\n headers.append(name, value);\n } catch {\n throw malformed();\n }\n }\n return headers;\n}\nexport function isSocketIo(client: unknown): client is SocketIoClientLike {\n return typeof client === \"object\" && client !== null && \"handshake\" in client;\n}\nexport function wsException(failure: AuthFailure): WsException {\n return new WsException({\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n });\n}\nexport function validateGateways(\n context: TransportValidationContext,\n coverage: WsTransportOptions<unknown>[\"gatewayCoverage\"],\n): void {\n class Probe {\n message(): void {}\n }\n WebSocketGateway()(Probe);\n SubscribeMessage(\"probe\")(\n Probe.prototype,\n \"message\",\n Object.getOwnPropertyDescriptor(Probe.prototype, \"message\")!,\n );\n if (\n Reflect.getMetadata(\"websockets:is_gateway\", Probe) !== true ||\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n Probe.prototype.message,\n ) !== true\n ) {\n throw new BetterAuthConfigurationError(\n \"NEST_METADATA_KEY_CHANGED\",\n \"Nest WebSocket gateway/message metadata failed its canary.\",\n );\n }\n const scanner = new MetadataScanner();\n for (const wrapper of context.discovery.getProviders()) {\n const target = wrapper.metatype;\n if (\n !target?.prototype ||\n wrapper.isAlias ||\n !Reflect.getMetadata(\"websockets:is_gateway\", target)\n ) {\n continue;\n }\n for (const method of scanner.getAllMethodNames(target.prototype)) {\n if (\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n target.prototype[method],\n )\n ) {\n context.claim(target, method, \"explicit\", {\n everyHandler: true,\n code: \"GATEWAY_UNGUARDED\",\n coverage: coverage ?? \"error\",\n hint: `Add @UseBetterAuth() to ${target.name} (or @Public() to opt out). Global guards and interceptors do not reach gateways on NestJS 11, and this check does not depend on the version.`,\n });\n }\n }\n }\n}\nexport function quotaAdvice(\n context: BootAdviceContext,\n ttl: number,\n): readonly BootAdvice[] {\n return ttl === 0 &&\n context.sources.some((source) => source.effects?.consumesQuota)\n ? [\n {\n level: \"warn\",\n code: \"W_QUOTA_PER_MESSAGE\",\n message:\n \"Quota-consuming WebSocket principals verify on every message.\",\n hint: \"Consider connection-time authentication and principalTtlMs; a positive TTL delays revocation on non-authoritative handlers.\",\n },\n ]\n : [];\n}\nexport function transportDefinition(\n transport: AuthTransport,\n): ExtensionDefinition<AuthTransport> {\n return {\n [EXTENSION_DEFINITION]: true,\n use: { useFactory: () => transport },\n providers: [\n WsConnectionAuth,\n { provide: WS_CONNECTION_AUTH, useExisting: WsConnectionAuth },\n ],\n exports: [WsConnectionAuth, WS_CONNECTION_AUTH],\n };\n}\nexport function principalTtl(value = 0): number {\n if (!Number.isFinite(value) || value < 0) {\n throw new BetterAuthConfigurationError(\n \"INVALID_WS_TTL\",\n \"principalTtlMs must be a finite non-negative number.\",\n );\n }\n return value;\n}\nexport function socketIoTransport(\n options: WsTransportOptions<SocketIoClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"socket.io\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n isSocketIo(context.switchToWs().getClient()),\n describe(context: ExecutionContext): TransportCall {\n const client = context.switchToWs().getClient<SocketIoClientLike>();\n const original = () => toWebHeaders(client.handshake.headers);\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = original();\n let mapped: HeadersInit | undefined;\n if (options.credentials) {\n mapped = options.credentials(client);\n } else if (!headers.has(\"authorization\")) {\n const token = client.handshake.auth?.token;\n if (token !== undefined) {\n if (typeof token !== \"string\") {\n throw AuthFailures.rejected({\n status: 401,\n reason: \"MALFORMED_CREDENTIALS\",\n });\n }\n mapped = { authorization: `Bearer ${token}` };\n }\n }\n mappedCredentialHeaders(mapped).forEach((value, name) => {\n headers.set(name, value);\n });\n return headers;\n },\n get clientIp() {\n return client.handshake.address ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: upgradeRequestUrl(client.handshake) };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: original,\n url: upgradeRequestUrl(client.handshake),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { AuthTransport, ExtensionDefinition } from \"./auth-contracts.js\";\nimport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nimport { BetterAuthConfigurationError } from \"./auth-errors.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport {\n isSocketIo,\n mappedCredentialHeaders,\n principalTtl,\n quotaAdvice,\n transportDefinition,\n validateGateways,\n wsException,\n type WsTransportOptions,\n} from \"./socket-io-transport.js\";\n\nexport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nexport interface WsClientLike {\n readonly [UPGRADE_REQUEST]?: {\n readonly headers: Headers;\n readonly url?: string;\n readonly remoteAddress?: string;\n readonly encrypted?: boolean;\n };\n}\nexport interface WsAdapterLike {\n bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown;\n}\nexport function recordUpgradeRequest(\n client: object,\n request: {\n headers: IncomingHttpHeaders;\n url?: string;\n socket?: { remoteAddress?: string; encrypted?: boolean };\n },\n): void {\n Object.defineProperty(client, UPGRADE_REQUEST, {\n value: Object.freeze({\n headers: toWebHeaders(request.headers),\n url: request.url,\n remoteAddress: request.socket?.remoteAddress,\n encrypted: request.socket?.encrypted,\n }),\n configurable: true,\n });\n}\nexport function withUpgradeRequest<\n T extends new (\n ...args: any[]\n ) => WsAdapterLike,\n>(Base: T): T {\n return class extends Base {\n override bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown {\n return super.bindClientConnect(server, (client, request, ...rest) => {\n recordUpgradeRequest(client, request);\n callback(client, request, ...rest);\n });\n }\n };\n}\nexport function wsTransport(\n options: WsTransportOptions<WsClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"ws\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n !isSocketIo(context.switchToWs().getClient()),\n describe(context) {\n const client = context.switchToWs().getClient<WsClientLike>();\n const upgrade = () => {\n const request = client[UPGRADE_REQUEST];\n if (!request) {\n throw BetterAuthConfigurationError.atRequest(\n \"WS_UPGRADE_REQUEST_MISSING\",\n \"WebSocket authentication requires its upgrade request.\",\n {\n hint: \"app.useWebSocketAdapter(new (withUpgradeRequest(WsAdapter))(app));\",\n },\n );\n }\n return request;\n };\n const url = () => {\n const request = upgrade();\n return upgradeRequestUrl({\n headers: request.headers,\n url: request.url,\n secure: request.encrypted,\n });\n };\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = new Headers(upgrade().headers);\n mappedCredentialHeaders(options.credentials?.(client)).forEach(\n (value, name) => {\n headers.set(name, value);\n },\n );\n return headers;\n },\n get clientIp() {\n return upgrade().remoteAddress ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: url() };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: () => new Headers(upgrade().headers),\n url: url(),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n"],"mappings":";;;;;;;;AA0BA,SAAgB,eAAe,SAA0C;CACvE,OAAO,QAAQ,WAAW,MAAM,OAAO,QAAQ,WAAW,MAAM,OAAO;AACzE;AAEA,MAAM,cAAc;;;;;;;AAQpB,SAAgB,mBAAmB,OAGjC;CACA,MAAM,QAAQ,UACZ,OAAO,UAAU,WAAW,QAAQ,KAAA;CACtC,IAAI;CACJ,IAAI,qBAAqB,KAAK,GAC5B,UAAU,GAAG,MAAM,KAAK,IAAI,MAAM;MAC7B,IAAI,sBAAsB,KAAK,GAAG;EACvC,MAAM,QAAQ,kBAAkB,OAAO,OAAO;EAC9C,UAAU,GAAG,MAAM,QAAQ,IAAI,KAAK,kBAAkB,OAAO,MAAM,CAAC,KAAK,QAAQ,IAAI,KAAK,kBAAkB,OAAO,SAAS,CAAC,KAAK,GAAG;CACvI,OAAO;EACL,MAAM,OAAO,KAAK,kBAAkB,OAAO,MAAM,CAAC;EAClD,UAAU,GAAG,SAAS,KAAA,KAAa,iBAAiB,KAAK,IAAI,IAAI,OAAO,OAAO,MAAM;CACvF;CACA,MAAM,UAAU,KAAK,kBAAkB,OAAO,OAAO,CAAC,KAAK,GAAA,CACxD,MAAM,OAAO,CAAC,CACd,QAAQ,SAAS,YAAY,KAAK,IAAI,CAAC;CAC1C,OAAO;EACL,SAAS,+CAA+C;EACxD,OAAO,OAAO,SAAS,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,KAAK,IAAI,IAAI,KAAA;CAC/D;AACF;;;;;;AAOA,IAAa,6BAAb,MAAoE;CAClE;CAEA,YAAY,QAAgB;EAC1B,KAAK,QAAQ,CAAC,QAAQ,KAAA,CAAS;CACjC;CAEA,UAA2D;EACzD,OAAO;CACT;;CAGA,WAAuB;EACrB,OAAO;CACT;;CAGA,aAAyD;EACvD,OAAO;CACT;CAEA,UAA8C;EAC5C,OAAO,KAAK;CACd;CAEA,cAAiB,OAAkB;EACjC,OAAO,KAAK,MAAM;CACpB;CAEA,eAA6D;EAC3D,OAAO;GACL,kBAAqB,KAAK,cAAiB,CAAC;GAC5C,mBAAsB,KAAK,cAAiB,CAAC;GAC7C,eAAkB,KAAK,cAAiB,CAAC;EAC3C;CACF;CAEA,cAA2D;EACzD,OAAO;GACL,eAAkB,KAAK,cAAiB,CAAC;GACzC,kBAAqB,KAAK,cAAiB,CAAC;EAC9C;CACF;CAEA,aAAyD;EACvD,OAAO;GACL,iBAAoB,KAAK,cAAiB,CAAC;GAC3C,eAAkB,KAAK,cAAiB,CAAC;GACzC,kBAAkB,KAAK,cAAsB,KAAK,MAAM,SAAS,CAAC;EACpE;CACF;AACF;AAGO,IAAM,mBAAN,MAAM,iBAAiB;CAIkB;CACC;CACA;CAL/C,SAA0B,IAAI,OAAO,YAAY;CAEjD,YACE,WACA,UACA,YACA;EAH4C,KAAA,YAAA;EACC,KAAA,WAAA;EACA,KAAA,aAAA;CAC5C;CAEH,MAAM,aACJ,QACA,UAAiC,CAAC,GACR;EAC1B,IAAI,OAAO,WAAW,YAAY,WAAW,MAC3C,MAAM,6BAA6B,UACjC,qBACA,wDACF;EAEF,MAAM,UAAU,IAAI,2BAA2B,MAAM;EACrD,MAAM,YAAY,KAAK,WAAW,OAAO,OAAO;EAChD,MAAM,OAAO,KAAK,WAAW,SAAS,SAAS,SAAS;EACxD,MAAM,QAAQ,KAAK,UAAU,IAAI,QAAQ,YAAY,SAAS;EAC9D,MAAM,UAAU,KAAK;EACrB,IAAI,WAAW,MAAM,QAAQ,aAAa,SAAS,OAAO;GACxD,MAAM,UAAU,MAAM,MAAM,OAAO,YAAY,SAAS,QAAQ;GAChE,IAAI,SACF,OAAO;IAAE,SAAS;IAAY;GAAQ;EAE1C;EACA,MAAM,UAAU,IAAI,IAClB,MAAM,QACH,QAAQ,WAAW,OAAO,eAAe,SAAS,CAAC,CACnD,SAAS,WAAW,CAAC,GAAG,OAAO,KAAK,CAAC,CAC1C;EACA,IAAI;GACF,OAAO,MAAM,KAAK,SAAS,QAAQ,MAAM;IACvC,MAAM,MAAM;IACZ;IACA,WAAW,KAAK,UACd,MAAM,QAAQ,SAAS,QAAQ,UAC7B,OAAO,MAAM,MAAM,SAAS,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAC9D,CACF;IACA,WACE,MAAM,QAAQ,YAAY,SAC1B,MAAM,QAAQ,SAAS,cAAc,kBACjC,kBACA;GACR,CAAC;EACH,SAAS,OAAO;GACd,IAAI,cAAc,KAAK,GACrB,OAAO;IAAE,SAAS;IAAY,SAAS;GAAM;GAE/C,MAAM;EACR;CACF;CAEA,mBACE,UAAqD,CAAC,GACI;EAC1D,QAAQ,QAAQ,SAAS;GACvB,KAAU,aAAa,QAAQ,OAAO,CAAC,CAAC,MACrC,WAAW;IACV,MAAM,UACJ,OAAO,YAAY,aACf,OAAO,UACP,OAAO,YAAY,YAAY,QAAQ,WACrC,aAAa,gBAAgB,IAC7B,KAAA;IACR,IAAI,CAAC,SAAS;KACZ,KAAK;KACL;IACF;IACA,KACE,OAAO,OAAO,IAAI,MAAM,QAAQ,OAAO,GAAG,EACxC,MAAM;KACJ,QAAQ;KACR,YAAY,QAAQ;KACpB,MAAM,QAAQ;KACd,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;KACnD,SAAS,QAAQ;IACnB,EACF,CAAC,CACH;GACF,IACC,UAAmB;IAClB,MAAM,MAAM,mBAAmB,KAAK;IACpC,KAAK,OAAO,MAAM,IAAI,SAAS,IAAI,KAAK;IACxC,KACE,OAAO,uBAAO,IAAI,MAAM,uBAAuB,GAAG,EAChD,MAAM;KACJ,QAAQ;KACR,YAAY;KACZ,SAAS;IACX,EACF,CAAC,CACH;GACF,CACF;EACF;CACF;AACF;;CAlGK,gBAAA,GAAA,OAAO,iBAAiB,CAAA;CACxB,gBAAA,GAAA,OAAO,kBAAkB,CAAA;CACzB,gBAAA,GAAA,OAAO,kBAAkB,CAAA;;;;;;;;;;ACrF9B,SAAgB,wBACd,OACS;CACT,MAAM,UAAU,IAAI,QAAQ;CAC5B,IAAI,UAAU,KAAA,GACZ,OAAO;CAET,MAAM,kBACJ,aAAa,SAAS;EAAE,QAAQ;EAAK,QAAQ;CAAwB,CAAC;CACxE,IAAI,UAAU,QAAQ,OAAO,UAAU,UACrC,MAAM,UAAU;CAIlB,MAAM,WAAY,MAA0C,OAAO;CACnE,IAAI,aAAa,KAAA,KAAa,OAAO,aAAa,YAChD,MAAM,UAAU;CAElB,MAAM,UACJ,OAAO,aAAa,aACf,QACD,OAAO,QAAQ,KAAK;CAC1B,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,GAC5C,MAAM,UAAU;EAElB,MAAM,CAAC,MAAM,SAAS;EACtB,IACE,OAAO,SAAS,YAChB,OAAO,UAAU,YACjB,WAAW,KAAK,KAAK,GAErB,MAAM,UAAU;EAElB,IAAI;GACF,QAAQ,OAAO,MAAM,KAAK;EAC5B,QAAQ;GACN,MAAM,UAAU;EAClB;CACF;CACA,OAAO;AACT;AACA,SAAgB,WAAW,QAA+C;CACxE,OAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,eAAe;AACzE;AACA,SAAgB,YAAY,SAAmC;CAC7D,OAAO,IAAI,YAAY;EACrB,QAAQ;EACR,YAAY,QAAQ;EACpB,MAAM,QAAQ;EACd,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;EACnD,SAAS,QAAQ;CACnB,CAAC;AACH;AACA,SAAgB,iBACd,SACA,UACM;CACN,MAAM,MAAM;EACV,UAAgB,CAAC;CACnB;CACA,iBAAiB,CAAC,CAAC,KAAK;CACxB,iBAAiB,OAAO,CAAC,CACvB,MAAM,WACN,WACA,OAAO,yBAAyB,MAAM,WAAW,SAAS,CAC5D;CACA,IACE,QAAQ,YAAY,yBAAyB,KAAK,MAAM,QACxD,QAAQ,YACN,8BACA,MAAM,UAAU,OAClB,MAAM,MAEN,MAAM,IAAI,6BACR,6BACA,4DACF;CAEF,MAAM,UAAU,IAAI,gBAAgB;CACpC,KAAK,MAAM,WAAW,QAAQ,UAAU,aAAa,GAAG;EACtD,MAAM,SAAS,QAAQ;EACvB,IACE,CAAC,QAAQ,aACT,QAAQ,WACR,CAAC,QAAQ,YAAY,yBAAyB,MAAM,GAEpD;EAEF,KAAK,MAAM,UAAU,QAAQ,kBAAkB,OAAO,SAAS,GAC7D,IACE,QAAQ,YACN,8BACA,OAAO,UAAU,OACnB,GAEA,QAAQ,MAAM,QAAQ,QAAQ,YAAY;GACxC,cAAc;GACd,MAAM;GACN,UAAU,YAAY;GACtB,MAAM,2BAA2B,OAAO,KAAK;EAC/C,CAAC;CAGP;AACF;AACA,SAAgB,YACd,SACA,KACuB;CACvB,OAAO,QAAQ,KACb,QAAQ,QAAQ,MAAM,WAAW,OAAO,SAAS,aAAa,IAC5D,CACE;EACE,OAAO;EACP,MAAM;EACN,SACE;EACF,MAAM;CACR,CACF,IACA,CAAC;AACP;AACA,SAAgB,oBACd,WACoC;CACpC,OAAO;GACJ,uBAAuB;EACxB,KAAK,EAAE,kBAAkB,UAAU;EACnC,WAAW,CACT,kBACA;GAAE,SAAS;GAAoB,aAAa;EAAiB,CAC/D;EACA,SAAS,CAAC,kBAAkB,kBAAkB;CAChD;AACF;AACA,SAAgB,aAAa,QAAQ,GAAW;CAC9C,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GACrC,MAAM,IAAI,6BACR,kBACA,sDACF;CAEF,OAAO;AACT;AACA,SAAgB,kBACd,UAAkD,CAAC,GACf;CACpC,MAAM,MAAM,aAAa,QAAQ,cAAc;CAC/C,OAAO,oBAAoB;EACzB,IAAI;EACJ,UAAU,YACR,QAAQ,QAAQ,MAAM,QACtB,WAAW,QAAQ,WAAW,CAAC,CAAC,UAAU,CAAC;EAC7C,SAAS,SAA0C;GACjD,MAAM,SAAS,QAAQ,WAAW,CAAC,CAAC,UAA8B;GAClE,MAAM,iBAAiB,aAAa,OAAO,UAAU,OAAO;GAC5D,OAAO;IACL,KAAK,QAAQ,QAAQ;IACrB,YAAY,QAAQ,QAAQ;IAC5B,YAAY;IACZ,gBAAgB;IAChB,eAAe;KACb,MAAM,UAAU,SAAS;KACzB,IAAI;KACJ,IAAI,QAAQ,aACV,SAAS,QAAQ,YAAY,MAAM;UAC9B,IAAI,CAAC,QAAQ,IAAI,eAAe,GAAG;MACxC,MAAM,QAAQ,OAAO,UAAU,MAAM;MACrC,IAAI,UAAU,KAAA,GAAW;OACvB,IAAI,OAAO,UAAU,UACnB,MAAM,aAAa,SAAS;QAC1B,QAAQ;QACR,QAAQ;OACV,CAAC;OAEH,SAAS,EAAE,eAAe,UAAU,QAAQ;MAC9C;KACF;KACA,wBAAwB,MAAM,CAAC,CAAC,SAAS,OAAO,SAAS;MACvD,QAAQ,IAAI,MAAM,KAAK;KACzB,CAAC;KACD,OAAO;IACT;IACA,IAAI,WAAW;KACb,OAAO,OAAO,UAAU,WAAW;IACrC;IACA,SAAS;IACT,IAAI,UAAU;KACZ,OAAO;MAAE,QAAQ;MAAO,KAAK,kBAAkB,OAAO,SAAS;KAAE;IACnE;IACA,QAAQ,SAAS,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG;IAClD,IAAI,UAAU;KACZ,OAAO;MACL,SAAS;MACT,KAAK;MACL,SAAS;MACT,KAAK,kBAAkB,OAAO,SAAS;KACzC;IACF;GACF;EACF;EACA,aAAa;EACb,WAAW,YAAY,iBAAiB,SAAS,QAAQ,eAAe;EACxE,SAAS,YAAY,YAAY,SAAS,GAAG;CAC/C,CAAC;AACH;;;AC1NA,SAAgB,qBACd,QACA,SAKM;CACN,OAAO,eAAe,QAAQ,iBAAiB;EAC7C,OAAO,OAAO,OAAO;GACnB,SAAS,aAAa,QAAQ,OAAO;GACrC,KAAK,QAAQ;GACb,eAAe,QAAQ,QAAQ;GAC/B,WAAW,QAAQ,QAAQ;EAC7B,CAAC;EACD,cAAc;CAChB,CAAC;AACH;AACA,SAAgB,mBAId,MAAY;CACZ,OAAO,cAAc,KAAK;EACxB,kBACE,QACA,UACS;GACT,OAAO,MAAM,kBAAkB,SAAS,QAAQ,SAAS,GAAG,SAAS;IACnE,qBAAqB,QAAQ,OAAO;IACpC,SAAS,QAAQ,SAAS,GAAG,IAAI;GACnC,CAAC;EACH;CACF;AACF;AACA,SAAgB,YACd,UAA4C,CAAC,GACT;CACpC,MAAM,MAAM,aAAa,QAAQ,cAAc;CAC/C,OAAO,oBAAoB;EACzB,IAAI;EACJ,UAAU,YACR,QAAQ,QAAQ,MAAM,QACtB,CAAC,WAAW,QAAQ,WAAW,CAAC,CAAC,UAAU,CAAC;EAC9C,SAAS,SAAS;GAChB,MAAM,SAAS,QAAQ,WAAW,CAAC,CAAC,UAAwB;GAC5D,MAAM,gBAAgB;IACpB,MAAM,UAAU,OAAO;IACvB,IAAI,CAAC,SACH,MAAM,6BAA6B,UACjC,8BACA,0DACA,EACE,MAAM,qEACR,CACF;IAEF,OAAO;GACT;GACA,MAAM,YAAY;IAChB,MAAM,UAAU,QAAQ;IACxB,OAAO,kBAAkB;KACvB,SAAS,QAAQ;KACjB,KAAK,QAAQ;KACb,QAAQ,QAAQ;IAClB,CAAC;GACH;GACA,OAAO;IACL,KAAK,QAAQ,QAAQ;IACrB,YAAY,QAAQ,QAAQ;IAC5B,YAAY;IACZ,gBAAgB;IAChB,eAAe;KACb,MAAM,UAAU,IAAI,QAAQ,QAAQ,CAAC,CAAC,OAAO;KAC7C,wBAAwB,QAAQ,cAAc,MAAM,CAAC,CAAC,CAAC,SACpD,OAAO,SAAS;MACf,QAAQ,IAAI,MAAM,KAAK;KACzB,CACF;KACA,OAAO;IACT;IACA,IAAI,WAAW;KACb,OAAO,QAAQ,CAAC,CAAC,iBAAiB;IACpC;IACA,SAAS;IACT,IAAI,UAAU;KACZ,OAAO;MAAE,QAAQ;MAAO,KAAK,IAAI;KAAE;IACrC;IACA,QAAQ,SAAS,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG;IAClD,IAAI,UAAU;KACZ,OAAO;MACL,SAAS;MACT,KAAK;MACL,eAAe,IAAI,QAAQ,QAAQ,CAAC,CAAC,OAAO;MAC5C,KAAK,IAAI;KACX;IACF;GACF;EACF;EACA,aAAa;EACb,WAAW,YAAY,iBAAiB,SAAS,QAAQ,eAAe;EACxE,SAAS,YAAY,YAAY,SAAS,GAAG;CAC/C,CAAC;AACH"}