@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 @@
1
+ {"version":3,"file":"testing.mjs","names":[],"sources":["../src/testing.ts"],"sourcesContent":["import type {\n CanActivate,\n ExecutionContext,\n INestApplication,\n} from \"@nestjs/common\";\nimport type { TestingModuleBuilder } from \"@nestjs/testing\";\nimport { isObservable, lastValueFrom } from \"rxjs\";\nimport type {\n AuthorizationDecision,\n PolicyInvoker,\n PrincipalRequest,\n PrincipalResolver,\n PrincipalResult,\n PrincipalSource,\n TransportCall,\n} from \"./auth-contracts.js\";\nimport { BetterAuthConfigurationError } from \"./auth-errors.js\";\nimport { ScopeCore } from \"./auth-scope-interceptor.js\";\nimport {\n GUARD_CORE,\n INSTANCE_REGISTRY,\n POLICY_INVOKER,\n PRINCIPAL_RESOLVER,\n REQUEST_SCOPE,\n ROUTE_PLANNER,\n SCOPE_CORE,\n TRANSPORT_REGISTRY,\n} from \"./auth-tokens.js\";\nimport type { AuthLike, AuthPrincipal } from \"./auth-types.js\";\nimport { BRIDGE_HANDLE, type BridgeHandle } from \"./bridge-protocol.js\";\nimport type { InstanceRegistry } from \"./instance-registry.js\";\nimport {\n PrincipalReadings,\n stampedReading,\n stampResult,\n type ReadingInput,\n} from \"./principal-readings.js\";\nimport {\n absent,\n authenticated,\n ChainPrincipalResolver,\n} from \"./principal-resolver.js\";\nimport type { RequestScope } from \"./request-scope.js\";\nimport type { RoutePlanner } from \"./route-planner.js\";\nimport type { TransportRegistry } from \"./transport-registry.js\";\n\nconst TEST_APP = Symbol.for(\"@nestjs-kit/better-auth:test-app\");\nconst TEST_APP_CLOSE = Symbol.for(\"@nestjs-kit/better-auth:test-app-close\");\nconst TEST_OVERRIDES = Symbol.for(\"@nestjs-kit/better-auth:test-overrides\");\nconst PLUGIN_ID = \"@nestjs-kit/better-auth\";\nconst TEST_PRINCIPAL_SOURCE = \"@nestjs-kit/better-auth:test-principal\";\n\ntype FixedPrincipal =\n | AuthPrincipal\n | null\n | ((call: TransportCall) => AuthPrincipal | null);\ntype Decide = (\n policyId: string,\n params: unknown,\n principal: AuthPrincipal,\n) =>\n | AuthorizationDecision\n | undefined\n | Promise<AuthorizationDecision | undefined>;\n\ninterface TestOverrides {\n readonly principals: Map<string, FixedPrincipal>;\n readonly deciders: Decide[];\n}\n\n/**\n * TestingModuleBuilder keys overrides by token, so repeated helper calls share one provider and its configuration.\n * The configuration lives on the builder under a global symbol, so the ESM and CommonJS copies of this entry compose.\n */\nfunction overridesOf(builder: TestingModuleBuilder): TestOverrides {\n let overrides = Reflect.get(builder, TEST_OVERRIDES) as\n | TestOverrides\n | undefined;\n if (!overrides) {\n overrides = { principals: new Map(), deciders: [] };\n Object.defineProperty(builder, TEST_OVERRIDES, { value: overrides });\n }\n return overrides;\n}\n\n/** Make app.close() run Nest's shutdown once, whoever calls it: initTestApp, a registered hook or the test. */\nfunction closeOnce(app: INestApplication): () => Promise<void> {\n const existing = Reflect.get(app, TEST_APP_CLOSE) as\n | (() => Promise<void>)\n | undefined;\n if (existing) {\n return existing;\n }\n const close = app.close.bind(app);\n let pending: Promise<void> | undefined;\n const once = () => {\n pending ??= close();\n return pending;\n };\n Object.defineProperty(app, TEST_APP_CLOSE, { value: once });\n app.close = once;\n return once;\n}\n\nasync function bridgeOf(auth: AuthLike): Promise<BridgeHandle | undefined> {\n const context = (await auth.$context) as {\n getPlugin?(id: string): unknown;\n };\n const plugin = context.getPlugin?.(PLUGIN_ID);\n return plugin && typeof plugin === \"object\"\n ? (Reflect.get(plugin, BRIDGE_HANDLE) as BridgeHandle | undefined)\n : undefined;\n}\n\nfunction registryOf(app: INestApplication): InstanceRegistry | undefined {\n try {\n return app.get<InstanceRegistry>(INSTANCE_REGISTRY, { strict: false });\n } catch {\n return undefined;\n }\n}\n\n/**\n * init() plus Fastify ready() when the adapter exposes it. Before init, closes the previous application that\n * initTestApp initialized for the same Better Auth instance and that is still bound to it: an instance binds\n * exclusively to one application (B06). A failed init() leaves its binding for the next application, which takes it\n * over with W_INSTANCE_TAKEN_OVER. app.close() becomes idempotent, and `closeWith` receives it: a per-test cleanup such as\n * Vitest's onTestFinished or node:test's t.after, or a list that a suite-level afterEach drains (Jest registers no hooks\n * while a test runs). Without `closeWith`, close the last application yourself. On Express, compile one TestingModule per application: a\n * second application of one container fails init() with APP_ADAPTER_CHANGED.\n */\nexport async function initTestApp<T extends INestApplication>(\n app: T,\n options: { closeWith?: (close: () => Promise<void>) => void } = {},\n): Promise<T> {\n const close = closeOnce(app);\n const bridges: BridgeHandle[] = [];\n for (const registration of registryOf(app)?.registrations() ?? []) {\n const bridge = registration.instance\n ? await bridgeOf(registration.instance)\n : undefined;\n if (!bridge) {\n continue;\n }\n const previous = Reflect.get(bridge, TEST_APP) as\n | INestApplication\n | undefined;\n if (previous && previous !== app && bridge.state === \"bound\") {\n // initTestApp made previous.close() idempotent, so a registered close of the same app does nothing later.\n await previous.close();\n }\n Object.defineProperty(bridge, TEST_APP, {\n value: undefined,\n configurable: true,\n writable: true,\n });\n bridges.push(bridge);\n }\n await app.init();\n const server = (\n app.getHttpAdapter?.() as { getInstance?(): unknown } | undefined\n )?.getInstance?.() as { ready?: () => unknown } | undefined;\n if (typeof server?.ready === \"function\") {\n await server.ready();\n }\n for (const bridge of bridges) {\n Object.defineProperty(bridge, TEST_APP, {\n value: app,\n configurable: true,\n writable: true,\n });\n }\n options.closeWith?.(close);\n return app;\n}\n\n/** Real session headers for `userId` through Better Auth's testUtils() plugin, which the instance must include. */\nexport async function authHeadersFor(\n auth: AuthLike,\n userId: string,\n): Promise<Headers> {\n const context = (await auth.$context) as {\n test?: { getAuthHeaders?(options: { userId: string }): Promise<Headers> };\n };\n if (typeof context.test?.getAuthHeaders !== \"function\") {\n throw new BetterAuthConfigurationError(\n \"TEST_UTILS_MISSING\",\n \"authHeadersFor requires Better Auth's testUtils() plugin on the instance.\",\n \"Add testUtils() from better-auth/plugins to the test instance.\",\n );\n }\n return context.test.getAuthHeaders({ userId });\n}\n\n/**\n * Replace principal resolution for one instance (default: 'default') without Better Auth I/O. Acceptance, the\n * origin check and policies still run. A policy's re-classification read of a generic 401 answers absent,\n * because the request carries no session; other instances keep the real resolver.\n */\nexport function overridePrincipal(\n builder: TestingModuleBuilder,\n principal: FixedPrincipal,\n options: { instance?: string } = {},\n): TestingModuleBuilder {\n const configured = overridesOf(builder).principals;\n configured.set(options.instance || \"default\", principal);\n builder.overrideProvider(PRINCIPAL_RESOLVER).useFactory({\n inject: [INSTANCE_REGISTRY, REQUEST_SCOPE, TRANSPORT_REGISTRY],\n factory: (\n instances: InstanceRegistry,\n scope: RequestScope,\n transports: TransportRegistry,\n ): PrincipalResolver => {\n const real = new ChainPrincipalResolver(instances, scope, transports);\n return {\n resolve(call, request): Promise<PrincipalResult> {\n if (!configured.has(request.auth.name)) {\n return real.resolve(call, request);\n }\n if (request.reclassify) {\n return Promise.resolve(absent());\n }\n const fixed = configured.get(request.auth.name);\n const value = typeof fixed === \"function\" ? fixed(call) : fixed;\n return Promise.resolve(value ? authenticated(value) : absent());\n },\n };\n },\n });\n return builder;\n}\n\n/**\n * Replace the policy invoker: `decide` answers per requirement, and undefined runs the real policy. Acceptance,\n * the delegation gate, the origin check and the decision memo still run. Later calls are consulted after earlier ones.\n */\nexport function overrideDecisions(\n builder: TestingModuleBuilder,\n decide: Decide,\n): TestingModuleBuilder {\n const configured = overridesOf(builder).deciders;\n configured.push(decide);\n const invoker: PolicyInvoker = {\n async invoke(policy, params, context) {\n for (const decider of configured) {\n const decision = await decider(policy.id, params, context.principal);\n if (decision !== undefined) {\n return decision;\n }\n }\n return policy.evaluate(params, context);\n },\n };\n builder.overrideProvider(POLICY_INVOKER).useValue(invoker);\n return builder;\n}\n\n/** A principal source that answers a fixed principal (or null for absent), for test module composition. */\nexport function testPrincipal(\n principal: AuthPrincipal | ((req: PrincipalRequest) => AuthPrincipal | null),\n options: {\n kinds?: readonly string[];\n acceptance?: \"default\" | \"explicit\";\n delegates?: boolean;\n } = {},\n): PrincipalSource {\n const fixed = typeof principal === \"function\" ? undefined : principal;\n const id = fixed?.source ?? TEST_PRINCIPAL_SOURCE;\n const kinds = options.kinds ?? (fixed ? [fixed.kind] : [\"session\"]);\n return {\n id,\n kinds: kinds as PrincipalSource[\"kinds\"],\n acceptance: options.acceptance ?? \"default\",\n delegates: options.delegates ?? Boolean(fixed?.delegation),\n async resolve(request) {\n const value =\n typeof principal === \"function\" ? principal(request) : principal;\n return value\n ? authenticated({ ...value, source: id } as AuthPrincipal)\n : absent();\n },\n };\n}\n\n/**\n * Publish a principal for this invocation from a hand-written guard. The stamp lives on ctx.getArgs() and its\n * object elements. Readers accept it from the same args array (WS, RPC and GraphQL share it between guards and\n * interceptors) or from another array with the same elements when at least two elements are objects (an HTTP request\n * and its response); a lone shared element such as a socket never identifies an invocation. Pass `instance` for\n * handlers of a named instance.\n */\nexport function stampPrincipal(\n context: ExecutionContext,\n principal: AuthPrincipal | null,\n options: { instance?: string } = {},\n): void {\n stampResult(\n context.getArgs(),\n options.instance || \"default\",\n principal ? authenticated(principal) : absent(),\n );\n}\n\nclass StampFirstReadings extends PrincipalReadings {\n override read(input: ReadingInput) {\n const stamped =\n input.plan && input.plan.access !== \"public\"\n ? stampedReading(input.args, input.plan.instance)\n : undefined;\n return stamped ?? super.read(input);\n }\n}\n\nfunction planInstance(planner: RoutePlanner, context: ExecutionContext) {\n try {\n return planner.forContext(context).instance;\n } catch {\n return \"default\";\n }\n}\n\n/**\n * Replace the guard and scope bodies everywhere with one override each of GUARD_CORE and SCOPE_CORE: the APP_GUARD\n * alias and every @UseBetterAuth()/@UseGuards(BetterAuthGuard) site delegate to the same collaborator, which\n * overrideProvider(BetterAuthGuard) plus overrideGuard(BetterAuthGuard) cannot achieve. With `{ principal }` the\n * stand-in stamps the principal (for the handler's instance) and allows; with a CanActivate, that guard runs as the\n * whole guard body and may call stampPrincipal(); an object with a canActivate method is always treated as a guard,\n * even when it also has a `principal` property. The stand-in interceptor opens the same transport-described scope\n * as the real one, reading the test stamp first, so readers and BetterAuthService perform no Better Auth I/O.\n */\nexport function overrideAuthGuard(\n builder: TestingModuleBuilder,\n impl:\n | CanActivate\n | {\n principal:\n | AuthPrincipal\n | null\n | ((ctx: ExecutionContext) => AuthPrincipal | null);\n },\n): TestingModuleBuilder {\n builder.overrideProvider(GUARD_CORE).useFactory({\n inject: [ROUTE_PLANNER],\n factory: (planner: RoutePlanner) => ({\n async canActivate(context: ExecutionContext): Promise<boolean> {\n // A CanActivate may hold its own `principal` field; its canActivate always runs.\n if (typeof (impl as Partial<CanActivate>).canActivate === \"function\") {\n const result = (impl as CanActivate).canActivate(context);\n return isObservable(result) ? lastValueFrom(result) : result;\n }\n const { principal } = impl as {\n principal:\n | AuthPrincipal\n | null\n | ((ctx: ExecutionContext) => AuthPrincipal | null);\n };\n const value =\n typeof principal === \"function\" ? principal(context) : principal;\n stampResult(\n context.getArgs(),\n planInstance(planner, context),\n value ? authenticated(value) : absent(),\n );\n return true;\n },\n }),\n });\n builder.overrideProvider(SCOPE_CORE).useFactory({\n inject: [\n INSTANCE_REGISTRY,\n ROUTE_PLANNER,\n TRANSPORT_REGISTRY,\n REQUEST_SCOPE,\n ],\n factory: (\n instances: InstanceRegistry,\n planner: RoutePlanner,\n transports: TransportRegistry,\n scope: RequestScope,\n ) =>\n new ScopeCore(\n instances,\n planner,\n transports,\n scope,\n new StampFirstReadings(scope),\n ),\n });\n return builder;\n}\n"],"mappings":";;;;;;;AA8CA,MAAM,WAAW,OAAO,IAAI,kCAAkC;AAC9D,MAAM,iBAAiB,OAAO,IAAI,wCAAwC;AAC1E,MAAM,iBAAiB,OAAO,IAAI,wCAAwC;AAC1E,MAAM,YAAY;AAClB,MAAM,wBAAwB;;;;;AAwB9B,SAAS,YAAY,SAA8C;CACjE,IAAI,YAAY,QAAQ,IAAI,SAAS,cAAc;CAGnD,IAAI,CAAC,WAAW;EACd,YAAY;GAAE,4BAAY,IAAI,IAAI;GAAG,UAAU,CAAC;EAAE;EAClD,OAAO,eAAe,SAAS,gBAAgB,EAAE,OAAO,UAAU,CAAC;CACrE;CACA,OAAO;AACT;;AAGA,SAAS,UAAU,KAA4C;CAC7D,MAAM,WAAW,QAAQ,IAAI,KAAK,cAAc;CAGhD,IAAI,UACF,OAAO;CAET,MAAM,QAAQ,IAAI,MAAM,KAAK,GAAG;CAChC,IAAI;CACJ,MAAM,aAAa;EACjB,YAAY,MAAM;EAClB,OAAO;CACT;CACA,OAAO,eAAe,KAAK,gBAAgB,EAAE,OAAO,KAAK,CAAC;CAC1D,IAAI,QAAQ;CACZ,OAAO;AACT;AAEA,eAAe,SAAS,MAAmD;CAIzE,MAAM,UAAS,MAHQ,KAAK,SAAA,CAGL,YAAY,SAAS;CAC5C,OAAO,UAAU,OAAO,WAAW,WAC9B,QAAQ,IAAI,QAAQ,aAAa,IAClC,KAAA;AACN;AAEA,SAAS,WAAW,KAAqD;CACvE,IAAI;EACF,OAAO,IAAI,IAAsB,mBAAmB,EAAE,QAAQ,MAAM,CAAC;CACvE,QAAQ;EACN;CACF;AACF;;;;;;;;;;AAWA,eAAsB,YACpB,KACA,UAAgE,CAAC,GACrD;CACZ,MAAM,QAAQ,UAAU,GAAG;CAC3B,MAAM,UAA0B,CAAC;CACjC,KAAK,MAAM,gBAAgB,WAAW,GAAG,CAAC,EAAE,cAAc,KAAK,CAAC,GAAG;EACjE,MAAM,SAAS,aAAa,WACxB,MAAM,SAAS,aAAa,QAAQ,IACpC,KAAA;EACJ,IAAI,CAAC,QACH;EAEF,MAAM,WAAW,QAAQ,IAAI,QAAQ,QAAQ;EAG7C,IAAI,YAAY,aAAa,OAAO,OAAO,UAAU,SAEnD,MAAM,SAAS,MAAM;EAEvB,OAAO,eAAe,QAAQ,UAAU;GACtC,OAAO,KAAA;GACP,cAAc;GACd,UAAU;EACZ,CAAC;EACD,QAAQ,KAAK,MAAM;CACrB;CACA,MAAM,IAAI,KAAK;CACf,MAAM,UACJ,IAAI,iBAAiB,EAAA,EACpB,cAAc;CACjB,IAAI,OAAO,QAAQ,UAAU,YAC3B,MAAM,OAAO,MAAM;CAErB,KAAK,MAAM,UAAU,SACnB,OAAO,eAAe,QAAQ,UAAU;EACtC,OAAO;EACP,cAAc;EACd,UAAU;CACZ,CAAC;CAEH,QAAQ,YAAY,KAAK;CACzB,OAAO;AACT;;AAGA,eAAsB,eACpB,MACA,QACkB;CAClB,MAAM,UAAW,MAAM,KAAK;CAG5B,IAAI,OAAO,QAAQ,MAAM,mBAAmB,YAC1C,MAAM,IAAI,6BACR,sBACA,6EACA,gEACF;CAEF,OAAO,QAAQ,KAAK,eAAe,EAAE,OAAO,CAAC;AAC/C;;;;;;AAOA,SAAgB,kBACd,SACA,WACA,UAAiC,CAAC,GACZ;CACtB,MAAM,aAAa,YAAY,OAAO,CAAC,CAAC;CACxC,WAAW,IAAI,QAAQ,YAAY,WAAW,SAAS;CACvD,QAAQ,iBAAiB,kBAAkB,CAAC,CAAC,WAAW;EACtD,QAAQ;GAAC;GAAmB;GAAe;EAAkB;EAC7D,UACE,WACA,OACA,eACsB;GACtB,MAAM,OAAO,IAAI,uBAAuB,WAAW,OAAO,UAAU;GACpE,OAAO,EACL,QAAQ,MAAM,SAAmC;IAC/C,IAAI,CAAC,WAAW,IAAI,QAAQ,KAAK,IAAI,GACnC,OAAO,KAAK,QAAQ,MAAM,OAAO;IAEnC,IAAI,QAAQ,YACV,OAAO,QAAQ,QAAQ,OAAO,CAAC;IAEjC,MAAM,QAAQ,WAAW,IAAI,QAAQ,KAAK,IAAI;IAC9C,MAAM,QAAQ,OAAO,UAAU,aAAa,MAAM,IAAI,IAAI;IAC1D,OAAO,QAAQ,QAAQ,QAAQ,cAAc,KAAK,IAAI,OAAO,CAAC;GAChE,EACF;EACF;CACF,CAAC;CACD,OAAO;AACT;;;;;AAMA,SAAgB,kBACd,SACA,QACsB;CACtB,MAAM,aAAa,YAAY,OAAO,CAAC,CAAC;CACxC,WAAW,KAAK,MAAM;CAYtB,QAAQ,iBAAiB,cAAc,CAAC,CAAC,SAAS,EAVhD,MAAM,OAAO,QAAQ,QAAQ,SAAS;EACpC,KAAK,MAAM,WAAW,YAAY;GAChC,MAAM,WAAW,MAAM,QAAQ,OAAO,IAAI,QAAQ,QAAQ,SAAS;GACnE,IAAI,aAAa,KAAA,GACf,OAAO;EAEX;EACA,OAAO,OAAO,SAAS,QAAQ,OAAO;CACxC,EAEsD,CAAC;CACzD,OAAO;AACT;;AAGA,SAAgB,cACd,WACA,UAII,CAAC,GACY;CACjB,MAAM,QAAQ,OAAO,cAAc,aAAa,KAAA,IAAY;CAC5D,MAAM,KAAK,OAAO,UAAU;CAE5B,OAAO;EACL;EACA,OAHY,QAAQ,UAAU,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS;EAI/D,YAAY,QAAQ,cAAc;EAClC,WAAW,QAAQ,aAAa,QAAQ,OAAO,UAAU;EACzD,MAAM,QAAQ,SAAS;GACrB,MAAM,QACJ,OAAO,cAAc,aAAa,UAAU,OAAO,IAAI;GACzD,OAAO,QACH,cAAc;IAAE,GAAG;IAAO,QAAQ;GAAG,CAAkB,IACvD,OAAO;EACb;CACF;AACF;;;;;;;;AASA,SAAgB,eACd,SACA,WACA,UAAiC,CAAC,GAC5B;CACN,YACE,QAAQ,QAAQ,GAChB,QAAQ,YAAY,WACpB,YAAY,cAAc,SAAS,IAAI,OAAO,CAChD;AACF;AAEA,IAAM,qBAAN,cAAiC,kBAAkB;CACjD,KAAc,OAAqB;EAKjC,QAHE,MAAM,QAAQ,MAAM,KAAK,WAAW,WAChC,eAAe,MAAM,MAAM,MAAM,KAAK,QAAQ,IAC9C,KAAA,MACY,MAAM,KAAK,KAAK;CACpC;AACF;AAEA,SAAS,aAAa,SAAuB,SAA2B;CACtE,IAAI;EACF,OAAO,QAAQ,WAAW,OAAO,CAAC,CAAC;CACrC,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;AAWA,SAAgB,kBACd,SACA,MAQsB;CACtB,QAAQ,iBAAiB,UAAU,CAAC,CAAC,WAAW;EAC9C,QAAQ,CAAC,aAAa;EACtB,UAAU,aAA2B,EACnC,MAAM,YAAY,SAA6C;GAE7D,IAAI,OAAQ,KAA8B,gBAAgB,YAAY;IACpE,MAAM,SAAU,KAAqB,YAAY,OAAO;IACxD,OAAO,aAAa,MAAM,IAAI,cAAc,MAAM,IAAI;GACxD;GACA,MAAM,EAAE,cAAc;GAMtB,MAAM,QACJ,OAAO,cAAc,aAAa,UAAU,OAAO,IAAI;GACzD,YACE,QAAQ,QAAQ,GAChB,aAAa,SAAS,OAAO,GAC7B,QAAQ,cAAc,KAAK,IAAI,OAAO,CACxC;GACA,OAAO;EACT,EACF;CACF,CAAC;CACD,QAAQ,iBAAiB,UAAU,CAAC,CAAC,WAAW;EAC9C,QAAQ;GACN;GACA;GACA;GACA;EACF;EACA,UACE,WACA,SACA,YACA,UAEA,IAAI,UACF,WACA,SACA,YACA,OACA,IAAI,mBAAmB,KAAK,CAC9B;CACJ,CAAC;CACD,OAAO;AACT"}
@@ -0,0 +1,396 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_auth_errors = require("./auth-errors-DmiKl0L_.cjs");
3
+ const require_decorate = require("./decorate-Cr4Q7bNE.cjs");
4
+ const require_bridge_protocol = require("./bridge-protocol-BDw8opAG.cjs");
5
+ const require_platform = require("./platform-YICqqYv6.cjs");
6
+ let _nestjs_common = require("@nestjs/common");
7
+ let _nestjs_core = require("@nestjs/core");
8
+ let _nestjs_websockets = require("@nestjs/websockets");
9
+ //#region src/ws-connection-auth.ts
10
+ function wsCloseCodeFor(failure) {
11
+ return failure.status === 401 ? 4401 : failure.status === 403 ? 4403 : 4429;
12
+ }
13
+ const STACK_FRAME = /^\s+at .+:\d+:\d+\)?$/;
14
+ /**
15
+ * Describes an unexpected connection-authentication error for the server log. Package
16
+ * errors carry fixed messages and already-redacted causes. Application and runtime error
17
+ * messages can quote client credentials (native Headers errors do), so only their name
18
+ * and stack frames are kept.
19
+ */
20
+ function connectionErrorLog(error) {
21
+ const text = (value) => typeof value === "string" ? value : void 0;
22
+ let summary;
23
+ if (require_auth_errors.isConfigurationError(error)) summary = `${error.code}: ${error.detail}`;
24
+ else if (require_auth_errors.isInfrastructureError(error)) {
25
+ const cause = require_auth_errors.readErrorProperty(error, "cause");
26
+ summary = `${error.message} (${text(require_auth_errors.readErrorProperty(cause, "name")) ?? "Error"}: ${text(require_auth_errors.readErrorProperty(cause, "message")) ?? ""})`;
27
+ } else {
28
+ const name = text(require_auth_errors.readErrorProperty(error, "name"));
29
+ summary = `${name !== void 0 && /^[\w$.]{1,64}$/.test(name) ? name : typeof error} (message withheld)`;
30
+ }
31
+ const frames = (text(require_auth_errors.readErrorProperty(error, "stack")) ?? "").split(/\r?\n/).filter((line) => STACK_FRAME.test(line));
32
+ return {
33
+ message: `WebSocket connection authentication failed: ${summary}`,
34
+ stack: frames.length > 0 ? [summary, ...frames].join("\n") : void 0
35
+ };
36
+ }
37
+ /**
38
+ * The `ws` execution context of a connection before any gateway handler runs. Nest exports no
39
+ * public factory for execution contexts, so this implements the public `ExecutionContext`
40
+ * interface with the values Nest's internal host reports for the arguments `[client, undefined]`.
41
+ */
42
+ var ConnectionExecutionContext = class {
43
+ #args;
44
+ constructor(client) {
45
+ this.#args = [client, void 0];
46
+ }
47
+ getType() {
48
+ return "ws";
49
+ }
50
+ /** No handler runs yet, so there is no class; Nest's host reports `null` as well. */
51
+ getClass() {
52
+ return null;
53
+ }
54
+ /** No handler runs yet; Nest's host reports `null` as well. */
55
+ getHandler() {
56
+ return null;
57
+ }
58
+ getArgs() {
59
+ return this.#args;
60
+ }
61
+ getArgByIndex(index) {
62
+ return this.#args[index];
63
+ }
64
+ switchToHttp() {
65
+ return {
66
+ getRequest: () => this.getArgByIndex(0),
67
+ getResponse: () => this.getArgByIndex(1),
68
+ getNext: () => this.getArgByIndex(2)
69
+ };
70
+ }
71
+ switchToRpc() {
72
+ return {
73
+ getData: () => this.getArgByIndex(0),
74
+ getContext: () => this.getArgByIndex(1)
75
+ };
76
+ }
77
+ switchToWs() {
78
+ return {
79
+ getClient: () => this.getArgByIndex(0),
80
+ getData: () => this.getArgByIndex(1),
81
+ getPattern: () => this.getArgByIndex(this.#args.length - 1)
82
+ };
83
+ }
84
+ };
85
+ let WsConnectionAuth = class WsConnectionAuth {
86
+ instances;
87
+ resolver;
88
+ transports;
89
+ logger = new _nestjs_common.Logger("BetterAuth");
90
+ constructor(instances, resolver, transports) {
91
+ this.instances = instances;
92
+ this.resolver = resolver;
93
+ this.transports = transports;
94
+ }
95
+ async authenticate(client, options = {}) {
96
+ if (typeof client !== "object" || client === null) throw require_auth_errors.BetterAuthConfigurationError.atRequest("INVALID_WS_CLIENT", "Connection authentication requires a WebSocket client.");
97
+ const context = new ConnectionExecutionContext(client);
98
+ const transport = this.transports.select(context);
99
+ const call = this.transports.describe(context, transport);
100
+ const entry = this.instances.get(options.instance ?? "default");
101
+ const browser = call.browser;
102
+ if (browser && entry.options.originCheck?.mode !== "off") {
103
+ const failure = await entry.handle.checkOrigin(browser, "cookie");
104
+ if (failure) return {
105
+ outcome: "rejected",
106
+ failure
107
+ };
108
+ }
109
+ const accepts = new Set(entry.sources.filter((source) => source.acceptance === "default").flatMap((source) => [...source.kinds]));
110
+ try {
111
+ return await this.resolver.resolve(call, {
112
+ auth: entry.handle,
113
+ accepts,
114
+ sourceSet: JSON.stringify(entry.sources.flatMap((source, index) => source.kinds.some((kind) => accepts.has(kind)) ? [index] : [])),
115
+ freshness: entry.options.session !== false && entry.options.session?.freshness === "authoritative" ? "authoritative" : "default"
116
+ });
117
+ } catch (error) {
118
+ if (require_auth_errors.isAuthFailure(error)) return {
119
+ outcome: "rejected",
120
+ failure: error
121
+ };
122
+ throw error;
123
+ }
124
+ }
125
+ socketIoMiddleware(options = {}) {
126
+ return (socket, next) => {
127
+ this.authenticate(socket, options).then((result) => {
128
+ const failure = result.outcome === "rejected" ? result.failure : result.outcome === "absent" && options.required ? require_auth_errors.AuthFailures.unauthenticated() : void 0;
129
+ if (!failure) {
130
+ next();
131
+ return;
132
+ }
133
+ next(Object.assign(new Error(failure.message), { data: {
134
+ status: "error",
135
+ statusCode: failure.status,
136
+ code: failure.code,
137
+ ...failure.reason ? { reason: failure.reason } : {},
138
+ message: failure.message
139
+ } }));
140
+ }, (error) => {
141
+ const log = connectionErrorLog(error);
142
+ this.logger.error(log.message, log.stack);
143
+ next(Object.assign(/* @__PURE__ */ new Error("Internal server error"), { data: {
144
+ status: "error",
145
+ statusCode: 500,
146
+ message: "Internal server error"
147
+ } }));
148
+ });
149
+ };
150
+ }
151
+ };
152
+ WsConnectionAuth = require_decorate.__decorate([
153
+ require_decorate.__decorateParam(0, (0, _nestjs_common.Inject)(require_decorate.INSTANCE_REGISTRY)),
154
+ require_decorate.__decorateParam(1, (0, _nestjs_common.Inject)(require_decorate.PRINCIPAL_RESOLVER)),
155
+ require_decorate.__decorateParam(2, (0, _nestjs_common.Inject)(require_decorate.TRANSPORT_REGISTRY)),
156
+ require_decorate.__decorateMetadata("design:paramtypes", [
157
+ Object,
158
+ Object,
159
+ Object
160
+ ])
161
+ ], WsConnectionAuth);
162
+ //#endregion
163
+ //#region src/socket-io-transport.ts
164
+ /** Convert only mapped headers here: native Headers errors can quote the credential. */
165
+ function mappedCredentialHeaders(input) {
166
+ const headers = new Headers();
167
+ if (input === void 0) return headers;
168
+ const malformed = () => require_auth_errors.AuthFailures.rejected({
169
+ status: 401,
170
+ reason: "MALFORMED_CREDENTIALS"
171
+ });
172
+ if (input === null || typeof input !== "object") throw malformed();
173
+ const iterable = input[Symbol.iterator];
174
+ if (iterable !== void 0 && typeof iterable !== "function") throw malformed();
175
+ const entries = typeof iterable === "function" ? input : Object.entries(input);
176
+ for (const entry of entries) {
177
+ if (!Array.isArray(entry) || entry.length !== 2) throw malformed();
178
+ const [name, value] = entry;
179
+ if (typeof name !== "string" || typeof value !== "string" || /[\r\n\0]/.test(value)) throw malformed();
180
+ try {
181
+ headers.append(name, value);
182
+ } catch {
183
+ throw malformed();
184
+ }
185
+ }
186
+ return headers;
187
+ }
188
+ function isSocketIo(client) {
189
+ return typeof client === "object" && client !== null && "handshake" in client;
190
+ }
191
+ function wsException(failure) {
192
+ return new _nestjs_websockets.WsException({
193
+ status: "error",
194
+ statusCode: failure.status,
195
+ code: failure.code,
196
+ ...failure.reason ? { reason: failure.reason } : {},
197
+ message: failure.message
198
+ });
199
+ }
200
+ function validateGateways(context, coverage) {
201
+ class Probe {
202
+ message() {}
203
+ }
204
+ (0, _nestjs_websockets.WebSocketGateway)()(Probe);
205
+ (0, _nestjs_websockets.SubscribeMessage)("probe")(Probe.prototype, "message", Object.getOwnPropertyDescriptor(Probe.prototype, "message"));
206
+ if (Reflect.getMetadata("websockets:is_gateway", Probe) !== true || Reflect.getMetadata("websockets:message_mapping", Probe.prototype.message) !== true) throw new require_auth_errors.BetterAuthConfigurationError("NEST_METADATA_KEY_CHANGED", "Nest WebSocket gateway/message metadata failed its canary.");
207
+ const scanner = new _nestjs_core.MetadataScanner();
208
+ for (const wrapper of context.discovery.getProviders()) {
209
+ const target = wrapper.metatype;
210
+ if (!target?.prototype || wrapper.isAlias || !Reflect.getMetadata("websockets:is_gateway", target)) continue;
211
+ for (const method of scanner.getAllMethodNames(target.prototype)) if (Reflect.getMetadata("websockets:message_mapping", target.prototype[method])) context.claim(target, method, "explicit", {
212
+ everyHandler: true,
213
+ code: "GATEWAY_UNGUARDED",
214
+ coverage: coverage ?? "error",
215
+ 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.`
216
+ });
217
+ }
218
+ }
219
+ function quotaAdvice(context, ttl) {
220
+ return ttl === 0 && context.sources.some((source) => source.effects?.consumesQuota) ? [{
221
+ level: "warn",
222
+ code: "W_QUOTA_PER_MESSAGE",
223
+ message: "Quota-consuming WebSocket principals verify on every message.",
224
+ hint: "Consider connection-time authentication and principalTtlMs; a positive TTL delays revocation on non-authoritative handlers."
225
+ }] : [];
226
+ }
227
+ function transportDefinition(transport) {
228
+ return {
229
+ [require_bridge_protocol.EXTENSION_DEFINITION]: true,
230
+ use: { useFactory: () => transport },
231
+ providers: [WsConnectionAuth, {
232
+ provide: require_decorate.WS_CONNECTION_AUTH,
233
+ useExisting: WsConnectionAuth
234
+ }],
235
+ exports: [WsConnectionAuth, require_decorate.WS_CONNECTION_AUTH]
236
+ };
237
+ }
238
+ function principalTtl(value = 0) {
239
+ if (!Number.isFinite(value) || value < 0) throw new require_auth_errors.BetterAuthConfigurationError("INVALID_WS_TTL", "principalTtlMs must be a finite non-negative number.");
240
+ return value;
241
+ }
242
+ function socketIoTransport(options = {}) {
243
+ const ttl = principalTtl(options.principalTtlMs);
244
+ return transportDefinition({
245
+ id: "socket.io",
246
+ handles: (context) => context.getType() === "ws" && isSocketIo(context.switchToWs().getClient()),
247
+ describe(context) {
248
+ const client = context.switchToWs().getClient();
249
+ const original = () => require_platform.toWebHeaders(client.handshake.headers);
250
+ return {
251
+ key: context.getArgs(),
252
+ invocation: context.getArgs(),
253
+ connection: client,
254
+ principalTtlMs: ttl,
255
+ headers: () => {
256
+ const headers = original();
257
+ let mapped;
258
+ if (options.credentials) mapped = options.credentials(client);
259
+ else if (!headers.has("authorization")) {
260
+ const token = client.handshake.auth?.token;
261
+ if (token !== void 0) {
262
+ if (typeof token !== "string") throw require_auth_errors.AuthFailures.rejected({
263
+ status: 401,
264
+ reason: "MALFORMED_CREDENTIALS"
265
+ });
266
+ mapped = { authorization: `Bearer ${token}` };
267
+ }
268
+ }
269
+ mappedCredentialHeaders(mapped).forEach((value, name) => {
270
+ headers.set(name, value);
271
+ });
272
+ return headers;
273
+ },
274
+ get clientIp() {
275
+ return client.handshake.address ?? null;
276
+ },
277
+ cookies: null,
278
+ get request() {
279
+ return {
280
+ method: "GET",
281
+ url: require_platform.upgradeRequestUrl(client.handshake)
282
+ };
283
+ },
284
+ param: (name) => context.switchToWs().getData()?.[name],
285
+ get browser() {
286
+ return {
287
+ enforce: true,
288
+ key: client,
289
+ headers: original,
290
+ url: require_platform.upgradeRequestUrl(client.handshake)
291
+ };
292
+ }
293
+ };
294
+ },
295
+ toException: wsException,
296
+ validate: (context) => validateGateways(context, options.gatewayCoverage),
297
+ advise: (context) => quotaAdvice(context, ttl)
298
+ });
299
+ }
300
+ //#endregion
301
+ //#region src/ws-transport.ts
302
+ function recordUpgradeRequest(client, request) {
303
+ Object.defineProperty(client, require_bridge_protocol.UPGRADE_REQUEST, {
304
+ value: Object.freeze({
305
+ headers: require_platform.toWebHeaders(request.headers),
306
+ url: request.url,
307
+ remoteAddress: request.socket?.remoteAddress,
308
+ encrypted: request.socket?.encrypted
309
+ }),
310
+ configurable: true
311
+ });
312
+ }
313
+ function withUpgradeRequest(Base) {
314
+ return class extends Base {
315
+ bindClientConnect(server, callback) {
316
+ return super.bindClientConnect(server, (client, request, ...rest) => {
317
+ recordUpgradeRequest(client, request);
318
+ callback(client, request, ...rest);
319
+ });
320
+ }
321
+ };
322
+ }
323
+ function wsTransport(options = {}) {
324
+ const ttl = principalTtl(options.principalTtlMs);
325
+ return transportDefinition({
326
+ id: "ws",
327
+ handles: (context) => context.getType() === "ws" && !isSocketIo(context.switchToWs().getClient()),
328
+ describe(context) {
329
+ const client = context.switchToWs().getClient();
330
+ const upgrade = () => {
331
+ const request = client[require_bridge_protocol.UPGRADE_REQUEST];
332
+ if (!request) throw require_auth_errors.BetterAuthConfigurationError.atRequest("WS_UPGRADE_REQUEST_MISSING", "WebSocket authentication requires its upgrade request.", { hint: "app.useWebSocketAdapter(new (withUpgradeRequest(WsAdapter))(app));" });
333
+ return request;
334
+ };
335
+ const url = () => {
336
+ const request = upgrade();
337
+ return require_platform.upgradeRequestUrl({
338
+ headers: request.headers,
339
+ url: request.url,
340
+ secure: request.encrypted
341
+ });
342
+ };
343
+ return {
344
+ key: context.getArgs(),
345
+ invocation: context.getArgs(),
346
+ connection: client,
347
+ principalTtlMs: ttl,
348
+ headers: () => {
349
+ const headers = new Headers(upgrade().headers);
350
+ mappedCredentialHeaders(options.credentials?.(client)).forEach((value, name) => {
351
+ headers.set(name, value);
352
+ });
353
+ return headers;
354
+ },
355
+ get clientIp() {
356
+ return upgrade().remoteAddress ?? null;
357
+ },
358
+ cookies: null,
359
+ get request() {
360
+ return {
361
+ method: "GET",
362
+ url: url()
363
+ };
364
+ },
365
+ param: (name) => context.switchToWs().getData()?.[name],
366
+ get browser() {
367
+ return {
368
+ enforce: true,
369
+ key: client,
370
+ headers: () => new Headers(upgrade().headers),
371
+ url: url()
372
+ };
373
+ }
374
+ };
375
+ },
376
+ toException: wsException,
377
+ validate: (context) => validateGateways(context, options.gatewayCoverage),
378
+ advise: (context) => quotaAdvice(context, ttl)
379
+ });
380
+ }
381
+ //#endregion
382
+ exports.UPGRADE_REQUEST = require_bridge_protocol.UPGRADE_REQUEST;
383
+ exports.WS_CONNECTION_AUTH = require_decorate.WS_CONNECTION_AUTH;
384
+ Object.defineProperty(exports, "WsConnectionAuth", {
385
+ enumerable: true,
386
+ get: function() {
387
+ return WsConnectionAuth;
388
+ }
389
+ });
390
+ exports.recordUpgradeRequest = recordUpgradeRequest;
391
+ exports.socketIoTransport = socketIoTransport;
392
+ exports.withUpgradeRequest = withUpgradeRequest;
393
+ exports.wsCloseCodeFor = wsCloseCodeFor;
394
+ exports.wsTransport = wsTransport;
395
+
396
+ //# sourceMappingURL=websockets.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websockets.cjs","names":["isConfigurationError","isInfrastructureError","readErrorProperty","Logger","BetterAuthConfigurationError","isAuthFailure","AuthFailures","Inject","INSTANCE_REGISTRY","PRINCIPAL_RESOLVER","TRANSPORT_REGISTRY","AuthFailures","WsException","BetterAuthConfigurationError","MetadataScanner","EXTENSION_DEFINITION","WS_CONNECTION_AUTH","toWebHeaders","upgradeRequestUrl","UPGRADE_REQUEST","toWebHeaders","BetterAuthConfigurationError","upgradeRequestUrl"],"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":"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"}
@@ -0,0 +1,67 @@
1
+ import { Bn as WS_CONNECTION_AUTH, F as ExtensionDefinition, Mn as InstanceLookup, Pn as UPGRADE_REQUEST, c as AuthTransport, jn as TransportRegistry, nt as PrincipalResolver, qn as AuthFailure, rt as PrincipalResult } from "./auth-contracts-Brh_Qko9.cjs";
2
+ import { IncomingHttpHeaders } from "node:http";
3
+ import { ExecutionContext, Type } from "@nestjs/common";
4
+ import "@nestjs/websockets";
5
+ //#region src/socket-io-transport.d.ts
6
+ interface WsTransportOptions<C> {
7
+ /** Replaces principal credentials without changing the browser handshake used for origin checks. */
8
+ credentials?: (client: C) => HeadersInit | undefined;
9
+ /** Defaults to zero. Positive values delay revocation for non-authoritative messages. */
10
+ principalTtlMs?: number;
11
+ /** Every message handler requires explicit guard and scope coverage on every Nest major. */
12
+ gatewayCoverage?: "error" | "warn" | "off";
13
+ }
14
+ interface SocketIoClientLike {
15
+ readonly handshake: {
16
+ readonly headers: IncomingHttpHeaders;
17
+ readonly auth?: Record<string, unknown>;
18
+ readonly address?: string;
19
+ readonly url?: string;
20
+ readonly secure?: boolean;
21
+ };
22
+ }
23
+ export declare function socketIoTransport(options?: WsTransportOptions<SocketIoClientLike>): ExtensionDefinition<AuthTransport>;
24
+ //#endregion
25
+ //#region src/ws-transport.d.ts
26
+ interface WsClientLike {
27
+ readonly [UPGRADE_REQUEST]?: {
28
+ readonly headers: Headers;
29
+ readonly url?: string;
30
+ readonly remoteAddress?: string;
31
+ readonly encrypted?: boolean;
32
+ };
33
+ }
34
+ interface WsAdapterLike {
35
+ bindClientConnect(server: unknown, callback: (...args: any[]) => void): unknown;
36
+ }
37
+ export declare function recordUpgradeRequest(client: object, request: {
38
+ headers: IncomingHttpHeaders;
39
+ url?: string;
40
+ socket?: {
41
+ remoteAddress?: string;
42
+ encrypted?: boolean;
43
+ };
44
+ }): void;
45
+ export declare function withUpgradeRequest<T extends new (...args: any[]) => WsAdapterLike>(Base: T): T;
46
+ export declare function wsTransport(options?: WsTransportOptions<WsClientLike>): ExtensionDefinition<AuthTransport>;
47
+ //#endregion
48
+ //#region src/ws-connection-auth.d.ts
49
+ export declare function wsCloseCodeFor(failure: AuthFailure): 4401 | 4403 | 4429;
50
+ /** Connection authentication delegates to the same origin and principal kernel as messages. */
51
+ export declare class WsConnectionAuth {
52
+ private readonly instances;
53
+ private readonly resolver;
54
+ private readonly transports;
55
+ private readonly logger;
56
+ constructor(instances: InstanceLookup, resolver: PrincipalResolver, transports: TransportRegistry);
57
+ authenticate(client: unknown, options?: {
58
+ instance?: string;
59
+ }): Promise<PrincipalResult>;
60
+ socketIoMiddleware(options?: {
61
+ required?: boolean;
62
+ instance?: string;
63
+ }): (socket: unknown, next: (error?: Error) => void) => void;
64
+ }
65
+ //#endregion
66
+ export { type SocketIoClientLike, UPGRADE_REQUEST, WS_CONNECTION_AUTH, type WsAdapterLike, type WsClientLike, type WsTransportOptions };
67
+ //# sourceMappingURL=websockets.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websockets.d.cts","names":[],"sources":["../src/socket-io-transport.ts","../src/ws-transport.ts","../src/ws-connection-auth.ts"],"mappings":";;;;;UAyBiB,mBAAmB;;EAElC,eAAe,QAAQ,MAAM;;EAE7B;;EAEA;;UAEe;WACN;aACE,SAAS;aACT,OAAO;aACP;aACA;aACA;;;wBAqJG,kBACd,UAAS,mBAAmB,sBAC3B,oBAAoB;;;UC7KN;YACL;aACC,SAAS;aACT;aACA;aACA;;;UAGI;EACf,kBACE,iBACA,cAAc;;wBAGF,qBACd,gBACA;EACE,SAAS;EACT;EACA;IAAW;IAAwB;;;wBAavB,mBACd,kBACK,gBACA,eACL,MAAM,IAAI;wBAaI,YACd,UAAS,mBAAmB,gBAC3B,oBAAoB;;;wBC1CP,eAAe,SAAS;;qBAgG3B;mBAImC;mBACC;mBACA;mBAL9B;EAEjB,YAC8C,WAAW,gBACV,UAAU,mBACV,YAAY;EAGrD,aACJ,iBACA;IAAW;MACV,QAAQ;EA8CX,mBACE;IAAW;IAAoB;OAC7B,iBAAiB,OAAO,QAAQ"}
@@ -0,0 +1,67 @@
1
+ import { Bn as WS_CONNECTION_AUTH, F as ExtensionDefinition, Mn as InstanceLookup, Pn as UPGRADE_REQUEST, c as AuthTransport, jn as TransportRegistry, nt as PrincipalResolver, qn as AuthFailure, rt as PrincipalResult } from "./auth-contracts-Cz7C4_Ch.mjs";
2
+ import { ExecutionContext, Type } from "@nestjs/common";
3
+ import { IncomingHttpHeaders } from "node:http";
4
+ import { WsException } from "@nestjs/websockets";
5
+ //#region src/socket-io-transport.d.ts
6
+ interface WsTransportOptions<C> {
7
+ /** Replaces principal credentials without changing the browser handshake used for origin checks. */
8
+ credentials?: (client: C) => HeadersInit | undefined;
9
+ /** Defaults to zero. Positive values delay revocation for non-authoritative messages. */
10
+ principalTtlMs?: number;
11
+ /** Every message handler requires explicit guard and scope coverage on every Nest major. */
12
+ gatewayCoverage?: "error" | "warn" | "off";
13
+ }
14
+ interface SocketIoClientLike {
15
+ readonly handshake: {
16
+ readonly headers: IncomingHttpHeaders;
17
+ readonly auth?: Record<string, unknown>;
18
+ readonly address?: string;
19
+ readonly url?: string;
20
+ readonly secure?: boolean;
21
+ };
22
+ }
23
+ export declare function socketIoTransport(options?: WsTransportOptions<SocketIoClientLike>): ExtensionDefinition<AuthTransport>;
24
+ //#endregion
25
+ //#region src/ws-transport.d.ts
26
+ interface WsClientLike {
27
+ readonly [UPGRADE_REQUEST]?: {
28
+ readonly headers: Headers;
29
+ readonly url?: string;
30
+ readonly remoteAddress?: string;
31
+ readonly encrypted?: boolean;
32
+ };
33
+ }
34
+ interface WsAdapterLike {
35
+ bindClientConnect(server: unknown, callback: (...args: any[]) => void): unknown;
36
+ }
37
+ export declare function recordUpgradeRequest(client: object, request: {
38
+ headers: IncomingHttpHeaders;
39
+ url?: string;
40
+ socket?: {
41
+ remoteAddress?: string;
42
+ encrypted?: boolean;
43
+ };
44
+ }): void;
45
+ export declare function withUpgradeRequest<T extends new (...args: any[]) => WsAdapterLike>(Base: T): T;
46
+ export declare function wsTransport(options?: WsTransportOptions<WsClientLike>): ExtensionDefinition<AuthTransport>;
47
+ //#endregion
48
+ //#region src/ws-connection-auth.d.ts
49
+ export declare function wsCloseCodeFor(failure: AuthFailure): 4401 | 4403 | 4429;
50
+ /** Connection authentication delegates to the same origin and principal kernel as messages. */
51
+ export declare class WsConnectionAuth {
52
+ private readonly instances;
53
+ private readonly resolver;
54
+ private readonly transports;
55
+ private readonly logger;
56
+ constructor(instances: InstanceLookup, resolver: PrincipalResolver, transports: TransportRegistry);
57
+ authenticate(client: unknown, options?: {
58
+ instance?: string;
59
+ }): Promise<PrincipalResult>;
60
+ socketIoMiddleware(options?: {
61
+ required?: boolean;
62
+ instance?: string;
63
+ }): (socket: unknown, next: (error?: Error) => void) => void;
64
+ }
65
+ //#endregion
66
+ export { type SocketIoClientLike, UPGRADE_REQUEST, WS_CONNECTION_AUTH, type WsAdapterLike, type WsClientLike, type WsTransportOptions };
67
+ //# sourceMappingURL=websockets.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websockets.d.mts","names":[],"sources":["../src/socket-io-transport.ts","../src/ws-transport.ts","../src/ws-connection-auth.ts"],"mappings":";;;;;UAyBiB,mBAAmB;;EAElC,eAAe,QAAQ,MAAM;;EAE7B;;EAEA;;UAEe;WACN;aACE,SAAS;aACT,OAAO;aACP;aACA;aACA;;;wBAqJG,kBACd,UAAS,mBAAmB,sBAC3B,oBAAoB;;;UC7KN;YACL;aACC,SAAS;aACT;aACA;aACA;;;UAGI;EACf,kBACE,iBACA,cAAc;;wBAGF,qBACd,gBACA;EACE,SAAS;EACT;EACA;IAAW;IAAwB;;;wBAavB,mBACd,kBACK,gBACA,eACL,MAAM,IAAI;wBAaI,YACd,UAAS,mBAAmB,gBAC3B,oBAAoB;;;wBC1CP,eAAe,SAAS;;qBAgG3B;mBAImC;mBACC;mBACA;mBAL9B;EAEjB,YAC8C,WAAW,gBACV,UAAU,mBACV,YAAY;EAGrD,aACJ,iBACA;IAAW;MACV,QAAQ;EA8CX,mBACE;IAAW;IAAoB;OAC7B,iBAAiB,OAAO,QAAQ"}