alepha 0.20.3 → 0.20.4

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 (217) hide show
  1. package/dist/api/audits/index.d.ts.map +1 -1
  2. package/dist/api/files/index.d.ts.map +1 -1
  3. package/dist/api/jobs/index.d.ts +14 -14
  4. package/dist/api/jobs/index.d.ts.map +1 -1
  5. package/dist/api/keys/index.d.ts +4 -4
  6. package/dist/api/organizations/index.d.ts.map +1 -1
  7. package/dist/api/parameters/index.d.ts +8 -3
  8. package/dist/api/parameters/index.d.ts.map +1 -1
  9. package/dist/api/parameters/index.js +20 -4
  10. package/dist/api/parameters/index.js.map +1 -1
  11. package/dist/api/payments/index.d.ts.map +1 -1
  12. package/dist/api/users/index.browser.js +6 -0
  13. package/dist/api/users/index.browser.js.map +1 -1
  14. package/dist/api/users/index.d.ts +5037 -139
  15. package/dist/api/users/index.d.ts.map +1 -1
  16. package/dist/api/users/index.js +58 -10
  17. package/dist/api/users/index.js.map +1 -1
  18. package/dist/bucket/index.d.ts +77 -107
  19. package/dist/bucket/index.d.ts.map +1 -1
  20. package/dist/bucket/index.js +148 -4
  21. package/dist/bucket/index.js.map +1 -1
  22. package/dist/bucket/index.workerd.js +7 -1
  23. package/dist/bucket/index.workerd.js.map +1 -1
  24. package/dist/cache/core/index.d.ts +26 -0
  25. package/dist/cache/core/index.d.ts.map +1 -1
  26. package/dist/cache/core/index.js +11 -1
  27. package/dist/cache/core/index.js.map +1 -1
  28. package/dist/cache/core/index.workerd.js +11 -1
  29. package/dist/cache/core/index.workerd.js.map +1 -1
  30. package/dist/cli/config/index.d.ts +7 -5
  31. package/dist/cli/config/index.d.ts.map +1 -1
  32. package/dist/cli/config/index.js +2 -3
  33. package/dist/cli/config/index.js.map +1 -1
  34. package/dist/cli/core/index.d.ts +420 -13
  35. package/dist/cli/core/index.d.ts.map +1 -1
  36. package/dist/cli/core/index.js +22 -511
  37. package/dist/cli/core/index.js.map +1 -1
  38. package/dist/cli/devtools/index.d.ts +4 -8
  39. package/dist/cli/devtools/index.d.ts.map +1 -1
  40. package/dist/cli/devtools/index.js +13 -15
  41. package/dist/cli/devtools/index.js.map +1 -1
  42. package/dist/cli/platform/index.d.ts +10 -13
  43. package/dist/cli/platform/index.d.ts.map +1 -1
  44. package/dist/cli/platform/index.js +18 -15
  45. package/dist/cli/platform/index.js.map +1 -1
  46. package/dist/cli/vendor/index.d.ts +10 -13
  47. package/dist/cli/vendor/index.d.ts.map +1 -1
  48. package/dist/cli/vendor/index.js +16 -13
  49. package/dist/cli/vendor/index.js.map +1 -1
  50. package/dist/core/index.browser.js +27 -3
  51. package/dist/core/index.browser.js.map +1 -1
  52. package/dist/core/index.d.ts +6 -3
  53. package/dist/core/index.d.ts.map +1 -1
  54. package/dist/core/index.js +27 -3
  55. package/dist/core/index.js.map +1 -1
  56. package/dist/core/index.native.js +27 -3
  57. package/dist/core/index.native.js.map +1 -1
  58. package/dist/core/index.workerd.js +27 -3
  59. package/dist/core/index.workerd.js.map +1 -1
  60. package/dist/datetime/index.d.ts +69 -10
  61. package/dist/datetime/index.d.ts.map +1 -1
  62. package/dist/datetime/index.js +135 -13
  63. package/dist/datetime/index.js.map +1 -1
  64. package/dist/email/smtp/index.js +10636 -2
  65. package/dist/email/smtp/index.js.map +1 -1
  66. package/dist/fake/index.d.ts +8085 -4
  67. package/dist/fake/index.d.ts.map +1 -1
  68. package/dist/fake/index.js +33554 -3
  69. package/dist/fake/index.js.map +1 -1
  70. package/dist/lock/core/index.d.ts +30 -2
  71. package/dist/lock/core/index.d.ts.map +1 -1
  72. package/dist/lock/core/index.js +35 -12
  73. package/dist/lock/core/index.js.map +1 -1
  74. package/dist/mcp/index.d.ts +238 -31
  75. package/dist/mcp/index.d.ts.map +1 -1
  76. package/dist/mcp/index.js +198 -71
  77. package/dist/mcp/index.js.map +1 -1
  78. package/dist/orm/core/index.browser.js +1 -1
  79. package/dist/orm/core/index.browser.js.map +1 -1
  80. package/dist/orm/core/index.bun.js +4 -3
  81. package/dist/orm/core/index.bun.js.map +1 -1
  82. package/dist/orm/core/index.d.ts +4877 -9
  83. package/dist/orm/core/index.d.ts.map +1 -1
  84. package/dist/orm/core/index.js +4 -3
  85. package/dist/orm/core/index.js.map +1 -1
  86. package/dist/orm/postgres/index.d.ts +608 -1
  87. package/dist/orm/postgres/index.d.ts.map +1 -1
  88. package/dist/react/core/index.d.ts +102 -1
  89. package/dist/react/core/index.d.ts.map +1 -1
  90. package/dist/react/core/index.js +65 -1
  91. package/dist/react/core/index.js.map +1 -1
  92. package/dist/react/form/index.d.ts +6 -0
  93. package/dist/react/form/index.d.ts.map +1 -1
  94. package/dist/react/form/index.js +7 -7
  95. package/dist/react/form/index.js.map +1 -1
  96. package/dist/react/i18n/index.d.ts +7 -1
  97. package/dist/react/i18n/index.d.ts.map +1 -1
  98. package/dist/react/i18n/index.js +6 -0
  99. package/dist/react/i18n/index.js.map +1 -1
  100. package/dist/react/router/index.browser.js +20 -2
  101. package/dist/react/router/index.browser.js.map +1 -1
  102. package/dist/react/router/index.d.ts +36 -4
  103. package/dist/react/router/index.d.ts.map +1 -1
  104. package/dist/react/router/index.js +20 -2
  105. package/dist/react/router/index.js.map +1 -1
  106. package/dist/react/testing/chunk-6Ep1yQYe.js +16 -0
  107. package/dist/react/testing/index.d.ts +411 -1
  108. package/dist/react/testing/index.d.ts.map +1 -1
  109. package/dist/react/testing/index.js +12293 -13
  110. package/dist/react/testing/index.js.map +1 -1
  111. package/dist/react/ui/index.d.ts +195 -1
  112. package/dist/react/ui/index.d.ts.map +1 -1
  113. package/dist/react/ui/index.js +61 -1
  114. package/dist/react/ui/index.js.map +1 -1
  115. package/dist/scheduler/index.d.ts +84 -3
  116. package/dist/scheduler/index.d.ts.map +1 -1
  117. package/dist/scheduler/index.js +390 -1
  118. package/dist/scheduler/index.js.map +1 -1
  119. package/dist/scheduler/index.workerd.js +390 -1
  120. package/dist/scheduler/index.workerd.js.map +1 -1
  121. package/dist/security/index.d.ts +325 -2
  122. package/dist/security/index.d.ts.map +1 -1
  123. package/dist/security/index.js +1361 -2
  124. package/dist/security/index.js.map +1 -1
  125. package/dist/server/auth/index.d.ts +1054 -1
  126. package/dist/server/auth/index.d.ts.map +1 -1
  127. package/dist/server/auth/index.js +1223 -1
  128. package/dist/server/auth/index.js.map +1 -1
  129. package/dist/server/core/index.browser.js +10 -3
  130. package/dist/server/core/index.browser.js.map +1 -1
  131. package/dist/server/core/index.d.ts.map +1 -1
  132. package/dist/server/core/index.js +28 -5
  133. package/dist/server/core/index.js.map +1 -1
  134. package/dist/server/metrics/index.d.ts +514 -1
  135. package/dist/server/metrics/index.d.ts.map +1 -1
  136. package/dist/server/metrics/index.js +4374 -4
  137. package/dist/server/metrics/index.js.map +1 -1
  138. package/dist/server/swagger/index.d.ts.map +1 -1
  139. package/dist/server/swagger/index.js +3 -4
  140. package/dist/server/swagger/index.js.map +1 -1
  141. package/dist/websocket/index.browser.js +11 -5
  142. package/dist/websocket/index.browser.js.map +1 -1
  143. package/dist/websocket/index.d.ts +3 -1
  144. package/dist/websocket/index.d.ts.map +1 -1
  145. package/dist/websocket/index.js +21 -6
  146. package/dist/websocket/index.js.map +1 -1
  147. package/package.json +671 -263
  148. package/src/api/parameters/services/ParameterProvider.ts +21 -4
  149. package/src/api/users/__tests__/SessionService.spec.ts +99 -0
  150. package/src/api/users/__tests__/UserJobs.spec.ts +67 -0
  151. package/src/api/users/atoms/realmAuthSettingsAtom.ts +15 -0
  152. package/src/api/users/entities/sessions.ts +6 -0
  153. package/src/api/users/jobs/UserJobs.ts +44 -17
  154. package/src/api/users/providers/RealmProvider.ts +4 -0
  155. package/src/api/users/services/SessionService.ts +27 -0
  156. package/src/bucket/__tests__/NodeS3BucketProvider.spec.ts +74 -0
  157. package/src/bucket/index.ts +19 -2
  158. package/src/bucket/primitives/$bucket.ts +9 -1
  159. package/src/bucket/providers/CloudflareR2Provider.ts +2 -137
  160. package/src/bucket/providers/NodeS3BucketProvider.ts +218 -0
  161. package/src/cache/core/index.ts +29 -0
  162. package/src/cache/core/primitives/$cache.ts +14 -1
  163. package/src/cli/config/defineConfig.ts +13 -15
  164. package/src/cli/core/__tests__/init.spec.ts +6 -7
  165. package/src/cli/core/services/ProjectScaffolder.ts +18 -14
  166. package/src/cli/core/tasks/BuildCloudflareTask.ts +5 -0
  167. package/src/cli/core/templates/agentMd.ts +2 -10
  168. package/src/cli/core/templates/saasAdminLayoutTsx.ts +3 -3
  169. package/src/cli/devtools/index.ts +12 -26
  170. package/src/cli/platform/index.ts +15 -24
  171. package/src/cli/vendor/atoms/vendorOptions.ts +1 -1
  172. package/src/cli/vendor/index.ts +14 -23
  173. package/src/core/Alepha.ts +11 -1
  174. package/src/core/helpers/ref.ts +18 -0
  175. package/src/core/index.shared.ts +1 -0
  176. package/src/core/providers/SchemaValidator.ts +9 -1
  177. package/src/core/providers/TypeProvider.ts +1 -2
  178. package/src/datetime/REFACTORING.md +118 -0
  179. package/src/datetime/providers/DateTimeProvider.ts +203 -24
  180. package/src/lock/core/index.ts +31 -0
  181. package/src/lock/core/primitives/$lock.ts +14 -1
  182. package/src/mcp/__tests__/jsonrpc.spec.ts +1 -1
  183. package/src/mcp/helpers/jsonrpc.ts +26 -1
  184. package/src/mcp/index.ts +10 -5
  185. package/src/mcp/interfaces/McpTypes.ts +83 -6
  186. package/src/mcp/primitives/$prompt.ts +18 -1
  187. package/src/mcp/primitives/$resource.ts +18 -1
  188. package/src/mcp/primitives/$tool.ts +83 -7
  189. package/src/mcp/providers/McpServerProvider.ts +74 -16
  190. package/src/mcp/transports/StreamableHttpMcpTransport.ts +226 -0
  191. package/src/orm/REFACTORING.md +330 -0
  192. package/src/orm/core/primitives/$transactional.ts +11 -0
  193. package/src/orm/core/schemas/updateSchema.ts +1 -1
  194. package/src/orm/core/services/PgRelationManager.ts +4 -2
  195. package/src/react/core/__tests__/useQuery.browser.spec.tsx +86 -0
  196. package/src/react/core/hooks/useQuery.ts +153 -0
  197. package/src/react/core/index.ts +1 -0
  198. package/src/react/form/services/FormModel.ts +15 -6
  199. package/src/react/form/services/parseField.ts +8 -0
  200. package/src/react/i18n/providers/I18nProvider.ts +8 -2
  201. package/src/react/router/__tests__/$page.spec.tsx +0 -16
  202. package/src/react/router/__tests__/ssr.spec.tsx +339 -0
  203. package/src/react/router/primitives/$page.ts +28 -4
  204. package/src/react/router/providers/ReactPageProvider.ts +27 -9
  205. package/src/react/ui/atoms/uiThemeListAtom.ts +36 -0
  206. package/src/react/ui/index.ts +6 -0
  207. package/src/react/ui/services/SchemaControl.ts +209 -0
  208. package/src/security/primitives/$issuer.ts +6 -3
  209. package/src/server/core/__tests__/ServerRouterProvider-serializationError.spec.ts +75 -0
  210. package/src/server/core/__tests__/ServerRouterProvider-validationError.spec.ts +306 -0
  211. package/src/server/core/errors/ValidationError.ts +13 -1
  212. package/src/server/core/primitives/$action.ts +16 -5
  213. package/src/server/core/providers/ServerRouterProvider.ts +26 -4
  214. package/src/server/swagger/providers/ServerSwaggerProvider.ts +5 -7
  215. package/src/websocket/providers/NodeWebSocketServerProvider.ts +10 -4
  216. package/src/websocket/services/WebSocketClient.ts +11 -5
  217. package/src/mcp/transports/SseMcpTransport.ts +0 -182
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/server/swagger/primitives/$swagger.ts","../../../src/server/swagger/providers/ServerSwaggerProvider.ts","../../../src/server/swagger/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/server/swagger/primitives/$swagger.ts","../../../src/server/swagger/providers/ServerSwaggerProvider.ts","../../../src/server/swagger/index.ts"],"mappings":"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"}
@@ -126,8 +126,7 @@ var ServerSwaggerProvider = class {
126
126
  operation.responses["401"] = { description: "Unauthorized" };
127
127
  hasSecurity = true;
128
128
  }
129
- const g = t.raw;
130
- if (g.IsObject(route.options.schema.body) || g.IsArray(route.options.schema.body)) if (g.IsObject(route.options.schema.body) && this.isBodyMultipart(route.options.schema.body)) operation.requestBody = {
129
+ if (t.schema.isObject(route.options.schema.body) || t.schema.isArray(route.options.schema.body)) if (t.schema.isObject(route.options.schema.body) && this.isBodyMultipart(route.options.schema.body)) operation.requestBody = {
131
130
  required: true,
132
131
  content: { "multipart/form-data": { schema: schema(route.options.schema.body) } }
133
132
  };
@@ -135,7 +134,7 @@ var ServerSwaggerProvider = class {
135
134
  required: true,
136
135
  content: { "application/json": { schema: schema(route.options.schema.body) } }
137
136
  };
138
- if (g.IsObject(route.options.schema.query)) {
137
+ if (t.schema.isObject(route.options.schema.query)) {
139
138
  operation.parameters ??= [];
140
139
  const requiredKeys = route.options.schema.query.required ?? [];
141
140
  for (const [key, value] of Object.entries(route.options.schema.query.properties)) {
@@ -150,7 +149,7 @@ var ServerSwaggerProvider = class {
150
149
  operation.parameters.push(param);
151
150
  }
152
151
  }
153
- if (g.IsObject(route.options.schema.params)) {
152
+ if (t.schema.isObject(route.options.schema.params)) {
154
153
  operation.parameters ??= [];
155
154
  for (const [key, value] of Object.entries(route.options.schema.params.properties)) {
156
155
  const description = "description" in value && typeof value.description === "string" ? value.description : void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/server/swagger/primitives/$swagger.ts","../../../src/server/swagger/providers/ServerSwaggerProvider.ts","../../../src/server/swagger/index.ts"],"sourcesContent":["import { createPrimitive, KIND, Primitive } from \"alepha\";\n\n/**\n * Creates an OpenAPI/Swagger documentation primitive with interactive UI.\n *\n * Automatically generates API documentation from your $action primitives and serves\n * an interactive Swagger UI for testing endpoints. Supports customization, tag filtering,\n * and OAuth configuration.\n *\n * @example\n * ```ts\n * class App {\n * docs = $swagger({\n * prefix: \"/api-docs\",\n * info: {\n * title: \"My API\",\n * version: \"1.0.0\",\n * description: \"REST API documentation\"\n * },\n * excludeTags: [\"internal\"],\n * ui: { root: \"/swagger\" }\n * });\n * }\n * ```\n */\nexport const $swagger = (\n options: SwaggerPrimitiveOptions = {},\n): SwaggerPrimitive => {\n return createPrimitive(SwaggerPrimitive, options);\n};\n\nexport interface SwaggerPrimitiveOptions {\n info?: OpenApiDocument[\"info\"];\n\n /**\n * @default: \"/docs\"\n */\n prefix?: string;\n\n /**\n * If true, docs will be disabled.\n */\n disabled?: boolean;\n\n /**\n * Tags to exclude from the documentation.\n */\n excludeTags?: string[];\n\n /**\n * Server URLs for the API.\n * If not provided, the server hostname is used automatically.\n */\n servers?: OpenApiServer[];\n\n /**\n * Enable Swagger UI.\n *\n * @default true\n */\n ui?: boolean | SwaggerUiOptions;\n\n /**\n * Function to rewrite the OpenAPI document before serving it.\n */\n rewrite?: (doc: OpenApiDocument) => void;\n}\n\nexport interface OpenApiServer {\n url: string;\n description?: string;\n}\n\nexport interface SwaggerUiOptions {\n root?: string;\n\n /**\n * If true, the authorization data is persisted in browser localStorage.\n *\n * @default true\n */\n persistAuthorization?: boolean;\n\n initOAuth?: {\n /**\n * Default clientId.\n */\n clientId?: string;\n\n /**\n * realm query parameter (for oauth1) added to authorizationUrl and tokenUrl.\n */\n realm?: string;\n\n /**\n * application name, displayed in authorization popup.\n */\n appName?: string;\n\n /**\n * scope separator for passing scopes, encoded before calling, default\n * value is a space (encoded value %20).\n *\n * @default ' '\n */\n scopeSeparator?: string;\n\n /**\n * string array or scope separator (i.e. space) separated string of\n * initially selected oauth scopes\n *\n * @default []\n */\n scopes?: string | string[];\n\n /**\n * Additional query parameters added to authorizationUrl and tokenUrl.\n * MUST be an object\n */\n additionalQueryStringParams?: { [key: string]: any };\n\n /**\n * Only activated for the accessCode flow. During the authorization_code\n * request to the tokenUrl, pass the Client Password using the HTTP Basic\n * Authentication scheme (Authorization header with Basic\n * base64encode(client_id + client_secret)).\n *\n * @default false\n */\n useBasicAuthenticationWithAccessCodeGrant?: boolean;\n\n /**\n * Only applies to Authorization Code flows. Proof Key for Code Exchange\n * brings enhanced security for OAuth public clients.\n *\n * @default false\n */\n usePkceWithAuthorizationCodeGrant?: boolean;\n };\n}\n\nexport class SwaggerPrimitive extends Primitive<SwaggerPrimitiveOptions> {}\n\n$swagger[KIND] = SwaggerPrimitive;\n\nexport interface OpenApiDocument {\n openapi: string;\n info: {\n title: string;\n version: string;\n description?: string;\n };\n servers?: OpenApiServer[];\n paths: Record<string, any>;\n components?: {\n schemas?: Record<string, any>;\n securitySchemes?: Record<string, any>;\n };\n}\n\nexport interface OpenApiOperation {\n tags?: string[];\n summary?: string;\n description?: string;\n operationId?: string;\n deprecated?: boolean;\n parameters?: Array<{\n name: string;\n in: \"query\" | \"header\" | \"path\" | \"cookie\";\n description?: string;\n required?: boolean;\n schema: any;\n }>;\n requestBody?: {\n description?: string;\n content: Record<\n string,\n {\n schema: any;\n }\n >;\n required?: boolean;\n };\n responses: Record<\n string,\n {\n description: string;\n content?: Record<\n string,\n {\n schema: any;\n }\n >;\n }\n >;\n security?: Array<Record<string, any[]>>;\n}\n","import { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n $atom,\n $hook,\n $inject,\n $state,\n Alepha,\n isTypeFile,\n type Static,\n type TObject,\n type TSchema,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport {\n $action,\n type ActionPrimitive,\n type RequestConfigSchema,\n ServerProvider,\n ServerRouterProvider,\n} from \"alepha/server\";\nimport { ServerStaticProvider } from \"alepha/server/static\";\nimport { FileSystemProvider } from \"alepha/system\";\nimport {\n $swagger,\n type OpenApiDocument,\n type OpenApiOperation,\n type SwaggerPrimitiveOptions,\n} from \"../primitives/$swagger.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Swagger provider configuration atom\n */\nexport const swaggerOptions = $atom({\n name: \"alepha.server.swagger.options\",\n schema: t.object({\n excludeKeys: t.optional(\n t.array(t.string(), {\n description: \"Keys to exclude from swagger schema\",\n }),\n ),\n }),\n default: {\n excludeKeys: [],\n },\n});\n\nexport type ServerSwaggerProviderOptions = Static<typeof swaggerOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [swaggerOptions.key]: ServerSwaggerProviderOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class ServerSwaggerProvider {\n protected readonly serverStaticProvider = $inject(ServerStaticProvider);\n protected readonly serverRouterProvider = $inject(ServerRouterProvider);\n protected readonly serverProvider = $inject(ServerProvider);\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly options = $state(swaggerOptions);\n protected readonly fs = $inject(FileSystemProvider);\n\n public json?: OpenApiDocument;\n\n protected readonly configure = $hook({\n on: \"configure\",\n priority: \"last\", // wait for all configurations, sometimes some actions are registered late!\n handler: async (alepha) => {\n const options = alepha.primitives($swagger)?.[0]?.options;\n if (!options) {\n return;\n }\n\n this.json = await this.setupSwaggerPlugin(options);\n },\n });\n\n public generateSwaggerDoc(options: SwaggerPrimitiveOptions): OpenApiDocument {\n const json = this.configureOpenApi(\n this.alepha.primitives($action),\n options,\n );\n\n if (options.rewrite) {\n options.rewrite(json);\n }\n\n return json;\n }\n\n protected async setupSwaggerPlugin(\n options: SwaggerPrimitiveOptions,\n ): Promise<OpenApiDocument | undefined> {\n if (options.disabled) {\n return;\n }\n\n const json = this.generateSwaggerDoc(options);\n\n const prefix = options.prefix ?? \"/docs\";\n\n this.configureSwaggerApi(prefix, json);\n\n if (options.ui !== false) {\n await this.configureSwaggerUi(prefix, options);\n } else {\n this.log.info(`Swagger API available at ${prefix}/json`);\n }\n\n return json;\n }\n\n protected configureOpenApi(\n actions: ActionPrimitive<RequestConfigSchema>[],\n doc: SwaggerPrimitiveOptions,\n ): OpenApiDocument {\n const openApi: OpenApiDocument = {\n openapi: \"3.0.0\",\n info: doc.info ?? {\n title: \"API Documentation\",\n version: \"1.0.0\",\n },\n servers: doc.servers ?? [{ url: this.serverProvider.hostname }],\n paths: {},\n components: {},\n };\n\n let hasSecurity = false;\n const excludeTags = doc.excludeTags ?? [];\n const schemas: Record<string, any> = {};\n\n const schema = (source: TSchema) => {\n if (\"title\" in source && typeof source.title === \"string\") {\n schemas[source.title] = copy(source);\n return { $ref: `#/components/schemas/${source.title}` };\n }\n return copy(source);\n };\n\n const copy = (obj: any) => {\n const newValue = JSON.parse(JSON.stringify(obj));\n this.removePrivateFields(newValue, [\n ...(this.options.excludeKeys || []),\n \"~options\",\n ]);\n return newValue;\n };\n\n for (const route of actions) {\n if (!route.options.schema) {\n continue;\n }\n\n const response = this.getResponseSchema(route);\n if (!response) {\n continue;\n }\n\n if (excludeTags.includes(route.group)) {\n continue;\n }\n\n if (route.options.hide) {\n continue;\n }\n\n const operation: OpenApiOperation = {\n operationId: route.name,\n summary: route.options.summary,\n description: route.options.description,\n deprecated: route.options.deprecated || undefined,\n tags: [route.group.replaceAll(\":\", \" / \")],\n responses: {\n [response.status]: {\n description: this.getStatusDescription(response.status),\n content: response.type\n ? {\n [response.type]: {\n schema: schema(response.schema),\n },\n }\n : undefined,\n },\n },\n };\n\n const isSecured = route.middlewares.some((m) => m?.name === \"$secure\");\n\n if (isSecured) {\n operation.security = [{ bearerAuth: [] }];\n operation.responses[\"401\"] = {\n description: \"Unauthorized\",\n };\n hasSecurity = true;\n }\n\n const g = t.raw;\n\n if (\n g.IsObject(route.options.schema.body) ||\n g.IsArray(route.options.schema.body)\n ) {\n if (\n g.IsObject(route.options.schema.body) &&\n this.isBodyMultipart(route.options.schema.body)\n ) {\n operation.requestBody = {\n required: true,\n content: {\n \"multipart/form-data\": {\n schema: schema(route.options.schema.body),\n },\n },\n };\n } else {\n operation.requestBody = {\n required: true,\n content: {\n \"application/json\": {\n schema: schema(route.options.schema.body),\n },\n },\n };\n }\n }\n\n if (g.IsObject(route.options.schema.query)) {\n operation.parameters ??= [];\n const requiredKeys: string[] =\n route.options.schema.query.required ?? [];\n for (const [key, value] of Object.entries(\n route.options.schema.query.properties,\n )) {\n const param: any = {\n name: key,\n in: \"query\",\n required: requiredKeys.includes(key),\n schema: schema(value),\n };\n const example = this.extractExample(value);\n if (example !== undefined) param.example = example;\n operation.parameters.push(param);\n }\n }\n\n if (g.IsObject(route.options.schema.params)) {\n operation.parameters ??= [];\n for (const [key, value] of Object.entries(\n route.options.schema.params.properties,\n )) {\n const description =\n \"description\" in value && typeof value.description === \"string\"\n ? value.description\n : undefined;\n const ref = schema(value);\n ref.description = undefined;\n const param: any = {\n name: key,\n in: \"path\",\n required: true,\n description,\n schema: ref,\n };\n const example = this.extractExample(value);\n if (example !== undefined) param.example = example;\n operation.parameters.push(param);\n }\n }\n\n const hasValidation =\n operation.requestBody || operation.parameters?.length;\n if (hasValidation) {\n operation.responses[\"400\"] = {\n description: \"Bad Request\",\n };\n }\n\n const url = route.prefix + this.replacePathParams(route.path);\n\n openApi.paths[url] = {\n ...openApi.paths[url],\n [route.method.toLowerCase()]: operation,\n };\n }\n\n if (hasSecurity && openApi.components) {\n openApi.components.securitySchemes = {\n bearerAuth: {\n type: \"http\",\n scheme: \"bearer\",\n bearerFormat: \"JWT\",\n description:\n \"Enter a JWT token or API key. Both are accepted as Bearer tokens.\",\n },\n };\n }\n\n if (openApi.components) openApi.components.schemas = schemas;\n\n return JSON.parse(JSON.stringify(openApi));\n }\n\n public isBodyMultipart(schema: TObject): boolean {\n for (const key in schema.properties) {\n if (isTypeFile(schema.properties[key])) {\n return true;\n }\n }\n return false;\n }\n\n public replacePathParams(url: string): string {\n return url.replace(/:\\w+/g, (match) => {\n const paramName = match.slice(1);\n return `{${paramName}}`;\n });\n }\n\n public getResponseSchema(route: ActionPrimitive<RequestConfigSchema>):\n | {\n type?: string;\n schema?: any;\n status: number;\n }\n | undefined {\n const schema: any = route.options.schema?.response;\n if (!schema) {\n return {\n status: 204,\n };\n }\n\n if (t.schema.isObject(schema) || t.schema.isArray(schema)) {\n return {\n schema,\n status: 200,\n type: \"application/json\",\n };\n }\n\n if (t.schema.isString(schema)) {\n return {\n schema,\n status: 200,\n type: \"text/plain\",\n };\n }\n\n if (\n t.schema.isNumber(schema) ||\n t.schema.isInteger(schema) ||\n t.schema.isBoolean(schema)\n ) {\n return {\n schema,\n status: 200,\n type: \"application/json\",\n };\n }\n\n if (isTypeFile(schema)) {\n return {\n schema,\n status: 200,\n type: \"application/octet-stream\",\n };\n }\n\n // Status-code-keyed map: e.g. { 201: t.object({...}) }\n const status = Object.keys(schema)[0];\n if (status && !Number.isNaN(Number(status))) {\n const inner = schema[status];\n return {\n schema: inner,\n status: Number(status),\n type: this.getContentType(inner),\n };\n }\n }\n\n protected extractExample(schema: any): any {\n if (\"examples\" in schema && Array.isArray(schema.examples)) {\n return schema.examples[0];\n }\n if (\"default\" in schema) {\n return schema.default;\n }\n return undefined;\n }\n\n protected getStatusDescription(status: number): string {\n switch (status) {\n case 200:\n return \"OK\";\n case 201:\n return \"Created\";\n case 204:\n return \"No Content\";\n case 400:\n return \"Bad Request\";\n case 401:\n return \"Unauthorized\";\n case 403:\n return \"Forbidden\";\n case 404:\n return \"Not Found\";\n case 500:\n return \"Internal Server Error\";\n default:\n return \"\";\n }\n }\n\n protected getContentType(schema: any): string | undefined {\n if (!schema) return undefined;\n if (t.schema.isObject(schema) || t.schema.isArray(schema)) {\n return \"application/json\";\n }\n if (t.schema.isString(schema)) return \"text/plain\";\n if (\n t.schema.isNumber(schema) ||\n t.schema.isInteger(schema) ||\n t.schema.isBoolean(schema)\n ) {\n return \"application/json\";\n }\n if (isTypeFile(schema)) return \"application/octet-stream\";\n return \"application/json\";\n }\n\n protected configureSwaggerApi(prefix: string, json: OpenApiDocument): void {\n this.serverRouterProvider.createRoute({\n method: \"GET\",\n path: `${prefix}/json`,\n schema: {\n response: t.json(),\n },\n handler: () => json,\n });\n }\n\n protected async configureSwaggerUi(\n prefix: string,\n options: SwaggerPrimitiveOptions,\n ): Promise<void> {\n const ui = typeof options.ui === \"object\" ? options.ui : {};\n const persistAuth = ui.persistAuthorization !== false;\n const initializer = `\nwindow.onload = function() {\n\twindow.ui = SwaggerUIBundle({\n\t\turl: \"${prefix}/json\",\n\t\tdom_id: '#swagger-ui',\n\t\tdeepLinking: true,\n\t\tpersistAuthorization: ${persistAuth},\n\t\tpresets: [\n\t\t\tSwaggerUIBundle.presets.apis,\n\t\t\tSwaggerUIStandalonePreset\n\t\t],\n\t\tplugins: [\n\t\t\tSwaggerUIBundle.plugins.DownloadUrl\n\t\t],\n\t\tlayout: \"BaseLayout\"\n\t});\n\n document.body.style.backgroundColor = \"#f2f2f2\";\n\n\tconst options = ${JSON.stringify(ui)};\n\n\tif (options.initOAuth) {\n\t\tui.initOAuth(options.initOAuth);\n\t}\n};\n\t\t`.trim();\n\n if (!this.alepha.isServerless()) {\n const dirname = fileURLToPath(import.meta.url);\n\n const root = await this.getAssetPath(\n ui.root,\n // TODO: this is shitty, take time to get the correct path\n join(dirname, \"../../assets/swagger-ui\"),\n join(dirname, \"../../../assets/swagger-ui\"),\n join(dirname, \"../../../../assets/swagger-ui\"),\n join(dirname, \"../../../../../assets/swagger-ui\"),\n );\n\n if (!root) {\n this.log.warn(`Failed to locate Swagger UI assets for path ${prefix}`);\n return;\n }\n\n await this.serverStaticProvider.createStaticServer({\n path: prefix,\n root,\n });\n }\n\n this.serverRouterProvider.createRoute({\n method: \"GET\",\n path: `${prefix}/swagger-initializer.js`,\n handler: ({ reply }) => {\n reply.headers[\"content-type\"] = \"application/javascript; charset=utf-8\";\n return initializer;\n },\n });\n\n this.log.info(\"SwaggerUI OK\", {\n url: `${this.serverProvider.hostname}${prefix}`,\n });\n }\n\n protected async getAssetPath(\n ...paths: (string | undefined)[]\n ): Promise<string | undefined> {\n for (const path of paths) {\n if (!path) continue;\n const exists = await this.fs.exists(path);\n if (exists) {\n return path;\n }\n }\n }\n\n public removePrivateFields<T extends Record<string, any>>(\n obj: T,\n excludeList: string[],\n ): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n\n const visited = new WeakSet();\n\n const traverse = (o: any): void => {\n if (visited.has(o)) return;\n visited.add(o);\n\n if (Array.isArray(o)) {\n for (let i = 0; i < o.length; i++) {\n const item = o[i];\n if (item !== null && typeof item === \"object\") {\n traverse(item);\n }\n }\n } else {\n for (const excludeKey of excludeList) {\n if (excludeKey in o) {\n delete o[excludeKey];\n }\n }\n for (const key in o) {\n const item = o[key];\n if (item !== null && typeof item === \"object\") {\n traverse(item);\n }\n }\n }\n };\n\n traverse(obj);\n return obj;\n }\n}\n","import \"alepha/security\";\nimport { $module } from \"alepha\";\nimport { AlephaServer, type RequestConfigSchema } from \"alepha/server\";\nimport { AlephaServerEtag } from \"alepha/server/etag\";\nimport { AlephaServerStatic } from \"alepha/server/static\";\nimport { $swagger } from \"./primitives/$swagger.ts\";\nimport { ServerSwaggerProvider } from \"./providers/ServerSwaggerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$swagger.ts\";\nexport * from \"./providers/ServerSwaggerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha/server\" {\n interface ActionPrimitiveOptions<TConfig extends RequestConfigSchema> {\n /**\n * Short description of the route.\n */\n summary?: string;\n\n /**\n * Don't include this action in the Swagger documentation.\n */\n hide?: boolean;\n\n /**\n * Mark this action as deprecated in the documentation.\n */\n deprecated?: boolean;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Automatic API documentation generation.\n *\n * **Features:**\n * - Swagger/OpenAPI configuration\n * - Routes: `GET /swagger/ui`, `GET /swagger.json`\n *\n * @module alepha.server.swagger\n */\nexport const AlephaServerSwagger = $module({\n name: \"alepha.server.swagger\",\n primitives: [$swagger],\n services: [ServerSwaggerProvider],\n register: (alepha) => {\n alepha.with(AlephaServer);\n alepha.with(AlephaServerEtag);\n alepha.with(AlephaServerStatic);\n alepha.with(ServerSwaggerProvider);\n alepha.store.push(\"alepha.build.assets\", \"alepha\");\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/server/swagger/primitives/$swagger.ts","../../../src/server/swagger/providers/ServerSwaggerProvider.ts","../../../src/server/swagger/index.ts"],"sourcesContent":["import { createPrimitive, KIND, Primitive } from \"alepha\";\n\n/**\n * Creates an OpenAPI/Swagger documentation primitive with interactive UI.\n *\n * Automatically generates API documentation from your $action primitives and serves\n * an interactive Swagger UI for testing endpoints. Supports customization, tag filtering,\n * and OAuth configuration.\n *\n * @example\n * ```ts\n * class App {\n * docs = $swagger({\n * prefix: \"/api-docs\",\n * info: {\n * title: \"My API\",\n * version: \"1.0.0\",\n * description: \"REST API documentation\"\n * },\n * excludeTags: [\"internal\"],\n * ui: { root: \"/swagger\" }\n * });\n * }\n * ```\n */\nexport const $swagger = (\n options: SwaggerPrimitiveOptions = {},\n): SwaggerPrimitive => {\n return createPrimitive(SwaggerPrimitive, options);\n};\n\nexport interface SwaggerPrimitiveOptions {\n info?: OpenApiDocument[\"info\"];\n\n /**\n * @default: \"/docs\"\n */\n prefix?: string;\n\n /**\n * If true, docs will be disabled.\n */\n disabled?: boolean;\n\n /**\n * Tags to exclude from the documentation.\n */\n excludeTags?: string[];\n\n /**\n * Server URLs for the API.\n * If not provided, the server hostname is used automatically.\n */\n servers?: OpenApiServer[];\n\n /**\n * Enable Swagger UI.\n *\n * @default true\n */\n ui?: boolean | SwaggerUiOptions;\n\n /**\n * Function to rewrite the OpenAPI document before serving it.\n */\n rewrite?: (doc: OpenApiDocument) => void;\n}\n\nexport interface OpenApiServer {\n url: string;\n description?: string;\n}\n\nexport interface SwaggerUiOptions {\n root?: string;\n\n /**\n * If true, the authorization data is persisted in browser localStorage.\n *\n * @default true\n */\n persistAuthorization?: boolean;\n\n initOAuth?: {\n /**\n * Default clientId.\n */\n clientId?: string;\n\n /**\n * realm query parameter (for oauth1) added to authorizationUrl and tokenUrl.\n */\n realm?: string;\n\n /**\n * application name, displayed in authorization popup.\n */\n appName?: string;\n\n /**\n * scope separator for passing scopes, encoded before calling, default\n * value is a space (encoded value %20).\n *\n * @default ' '\n */\n scopeSeparator?: string;\n\n /**\n * string array or scope separator (i.e. space) separated string of\n * initially selected oauth scopes\n *\n * @default []\n */\n scopes?: string | string[];\n\n /**\n * Additional query parameters added to authorizationUrl and tokenUrl.\n * MUST be an object\n */\n additionalQueryStringParams?: { [key: string]: any };\n\n /**\n * Only activated for the accessCode flow. During the authorization_code\n * request to the tokenUrl, pass the Client Password using the HTTP Basic\n * Authentication scheme (Authorization header with Basic\n * base64encode(client_id + client_secret)).\n *\n * @default false\n */\n useBasicAuthenticationWithAccessCodeGrant?: boolean;\n\n /**\n * Only applies to Authorization Code flows. Proof Key for Code Exchange\n * brings enhanced security for OAuth public clients.\n *\n * @default false\n */\n usePkceWithAuthorizationCodeGrant?: boolean;\n };\n}\n\nexport class SwaggerPrimitive extends Primitive<SwaggerPrimitiveOptions> {}\n\n$swagger[KIND] = SwaggerPrimitive;\n\nexport interface OpenApiDocument {\n openapi: string;\n info: {\n title: string;\n version: string;\n description?: string;\n };\n servers?: OpenApiServer[];\n paths: Record<string, any>;\n components?: {\n schemas?: Record<string, any>;\n securitySchemes?: Record<string, any>;\n };\n}\n\nexport interface OpenApiOperation {\n tags?: string[];\n summary?: string;\n description?: string;\n operationId?: string;\n deprecated?: boolean;\n parameters?: Array<{\n name: string;\n in: \"query\" | \"header\" | \"path\" | \"cookie\";\n description?: string;\n required?: boolean;\n schema: any;\n }>;\n requestBody?: {\n description?: string;\n content: Record<\n string,\n {\n schema: any;\n }\n >;\n required?: boolean;\n };\n responses: Record<\n string,\n {\n description: string;\n content?: Record<\n string,\n {\n schema: any;\n }\n >;\n }\n >;\n security?: Array<Record<string, any[]>>;\n}\n","import { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n $atom,\n $hook,\n $inject,\n $state,\n Alepha,\n isTypeFile,\n type Static,\n type TObject,\n type TSchema,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport {\n $action,\n type ActionPrimitive,\n type RequestConfigSchema,\n ServerProvider,\n ServerRouterProvider,\n} from \"alepha/server\";\nimport { ServerStaticProvider } from \"alepha/server/static\";\nimport { FileSystemProvider } from \"alepha/system\";\nimport {\n $swagger,\n type OpenApiDocument,\n type OpenApiOperation,\n type SwaggerPrimitiveOptions,\n} from \"../primitives/$swagger.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Swagger provider configuration atom\n */\nexport const swaggerOptions = $atom({\n name: \"alepha.server.swagger.options\",\n schema: t.object({\n excludeKeys: t.optional(\n t.array(t.string(), {\n description: \"Keys to exclude from swagger schema\",\n }),\n ),\n }),\n default: {\n excludeKeys: [],\n },\n});\n\nexport type ServerSwaggerProviderOptions = Static<typeof swaggerOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [swaggerOptions.key]: ServerSwaggerProviderOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class ServerSwaggerProvider {\n protected readonly serverStaticProvider = $inject(ServerStaticProvider);\n protected readonly serverRouterProvider = $inject(ServerRouterProvider);\n protected readonly serverProvider = $inject(ServerProvider);\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly options = $state(swaggerOptions);\n protected readonly fs = $inject(FileSystemProvider);\n\n public json?: OpenApiDocument;\n\n protected readonly configure = $hook({\n on: \"configure\",\n priority: \"last\", // wait for all configurations, sometimes some actions are registered late!\n handler: async (alepha) => {\n const options = alepha.primitives($swagger)?.[0]?.options;\n if (!options) {\n return;\n }\n\n this.json = await this.setupSwaggerPlugin(options);\n },\n });\n\n public generateSwaggerDoc(options: SwaggerPrimitiveOptions): OpenApiDocument {\n const json = this.configureOpenApi(\n this.alepha.primitives($action),\n options,\n );\n\n if (options.rewrite) {\n options.rewrite(json);\n }\n\n return json;\n }\n\n protected async setupSwaggerPlugin(\n options: SwaggerPrimitiveOptions,\n ): Promise<OpenApiDocument | undefined> {\n if (options.disabled) {\n return;\n }\n\n const json = this.generateSwaggerDoc(options);\n\n const prefix = options.prefix ?? \"/docs\";\n\n this.configureSwaggerApi(prefix, json);\n\n if (options.ui !== false) {\n await this.configureSwaggerUi(prefix, options);\n } else {\n this.log.info(`Swagger API available at ${prefix}/json`);\n }\n\n return json;\n }\n\n protected configureOpenApi(\n actions: ActionPrimitive<RequestConfigSchema>[],\n doc: SwaggerPrimitiveOptions,\n ): OpenApiDocument {\n const openApi: OpenApiDocument = {\n openapi: \"3.0.0\",\n info: doc.info ?? {\n title: \"API Documentation\",\n version: \"1.0.0\",\n },\n servers: doc.servers ?? [{ url: this.serverProvider.hostname }],\n paths: {},\n components: {},\n };\n\n let hasSecurity = false;\n const excludeTags = doc.excludeTags ?? [];\n const schemas: Record<string, any> = {};\n\n const schema = (source: TSchema) => {\n if (\"title\" in source && typeof source.title === \"string\") {\n schemas[source.title] = copy(source);\n return { $ref: `#/components/schemas/${source.title}` };\n }\n return copy(source);\n };\n\n const copy = (obj: any) => {\n const newValue = JSON.parse(JSON.stringify(obj));\n this.removePrivateFields(newValue, [\n ...(this.options.excludeKeys || []),\n \"~options\",\n ]);\n return newValue;\n };\n\n for (const route of actions) {\n if (!route.options.schema) {\n continue;\n }\n\n const response = this.getResponseSchema(route);\n if (!response) {\n continue;\n }\n\n if (excludeTags.includes(route.group)) {\n continue;\n }\n\n if (route.options.hide) {\n continue;\n }\n\n const operation: OpenApiOperation = {\n operationId: route.name,\n summary: route.options.summary,\n description: route.options.description,\n deprecated: route.options.deprecated || undefined,\n tags: [route.group.replaceAll(\":\", \" / \")],\n responses: {\n [response.status]: {\n description: this.getStatusDescription(response.status),\n content: response.type\n ? {\n [response.type]: {\n schema: schema(response.schema),\n },\n }\n : undefined,\n },\n },\n };\n\n const isSecured = route.middlewares.some((m) => m?.name === \"$secure\");\n\n if (isSecured) {\n operation.security = [{ bearerAuth: [] }];\n operation.responses[\"401\"] = {\n description: \"Unauthorized\",\n };\n hasSecurity = true;\n }\n\n if (\n t.schema.isObject(route.options.schema.body) ||\n t.schema.isArray(route.options.schema.body)\n ) {\n if (\n t.schema.isObject(route.options.schema.body) &&\n this.isBodyMultipart(route.options.schema.body)\n ) {\n operation.requestBody = {\n required: true,\n content: {\n \"multipart/form-data\": {\n schema: schema(route.options.schema.body),\n },\n },\n };\n } else {\n operation.requestBody = {\n required: true,\n content: {\n \"application/json\": {\n schema: schema(route.options.schema.body),\n },\n },\n };\n }\n }\n\n if (t.schema.isObject(route.options.schema.query)) {\n operation.parameters ??= [];\n const requiredKeys: string[] =\n route.options.schema.query.required ?? [];\n for (const [key, value] of Object.entries(\n route.options.schema.query.properties,\n )) {\n const param: any = {\n name: key,\n in: \"query\",\n required: requiredKeys.includes(key),\n schema: schema(value),\n };\n const example = this.extractExample(value);\n if (example !== undefined) param.example = example;\n operation.parameters.push(param);\n }\n }\n\n if (t.schema.isObject(route.options.schema.params)) {\n operation.parameters ??= [];\n for (const [key, value] of Object.entries(\n route.options.schema.params.properties,\n )) {\n const description =\n \"description\" in value && typeof value.description === \"string\"\n ? value.description\n : undefined;\n const ref = schema(value);\n ref.description = undefined;\n const param: any = {\n name: key,\n in: \"path\",\n required: true,\n description,\n schema: ref,\n };\n const example = this.extractExample(value);\n if (example !== undefined) param.example = example;\n operation.parameters.push(param);\n }\n }\n\n const hasValidation =\n operation.requestBody || operation.parameters?.length;\n if (hasValidation) {\n operation.responses[\"400\"] = {\n description: \"Bad Request\",\n };\n }\n\n const url = route.prefix + this.replacePathParams(route.path);\n\n openApi.paths[url] = {\n ...openApi.paths[url],\n [route.method.toLowerCase()]: operation,\n };\n }\n\n if (hasSecurity && openApi.components) {\n openApi.components.securitySchemes = {\n bearerAuth: {\n type: \"http\",\n scheme: \"bearer\",\n bearerFormat: \"JWT\",\n description:\n \"Enter a JWT token or API key. Both are accepted as Bearer tokens.\",\n },\n };\n }\n\n if (openApi.components) openApi.components.schemas = schemas;\n\n return JSON.parse(JSON.stringify(openApi));\n }\n\n public isBodyMultipart(schema: TObject): boolean {\n for (const key in schema.properties) {\n if (isTypeFile(schema.properties[key])) {\n return true;\n }\n }\n return false;\n }\n\n public replacePathParams(url: string): string {\n return url.replace(/:\\w+/g, (match) => {\n const paramName = match.slice(1);\n return `{${paramName}}`;\n });\n }\n\n public getResponseSchema(route: ActionPrimitive<RequestConfigSchema>):\n | {\n type?: string;\n schema?: any;\n status: number;\n }\n | undefined {\n const schema: any = route.options.schema?.response;\n if (!schema) {\n return {\n status: 204,\n };\n }\n\n if (t.schema.isObject(schema) || t.schema.isArray(schema)) {\n return {\n schema,\n status: 200,\n type: \"application/json\",\n };\n }\n\n if (t.schema.isString(schema)) {\n return {\n schema,\n status: 200,\n type: \"text/plain\",\n };\n }\n\n if (\n t.schema.isNumber(schema) ||\n t.schema.isInteger(schema) ||\n t.schema.isBoolean(schema)\n ) {\n return {\n schema,\n status: 200,\n type: \"application/json\",\n };\n }\n\n if (isTypeFile(schema)) {\n return {\n schema,\n status: 200,\n type: \"application/octet-stream\",\n };\n }\n\n // Status-code-keyed map: e.g. { 201: t.object({...}) }\n const status = Object.keys(schema)[0];\n if (status && !Number.isNaN(Number(status))) {\n const inner = schema[status];\n return {\n schema: inner,\n status: Number(status),\n type: this.getContentType(inner),\n };\n }\n }\n\n protected extractExample(schema: any): any {\n if (\"examples\" in schema && Array.isArray(schema.examples)) {\n return schema.examples[0];\n }\n if (\"default\" in schema) {\n return schema.default;\n }\n return undefined;\n }\n\n protected getStatusDescription(status: number): string {\n switch (status) {\n case 200:\n return \"OK\";\n case 201:\n return \"Created\";\n case 204:\n return \"No Content\";\n case 400:\n return \"Bad Request\";\n case 401:\n return \"Unauthorized\";\n case 403:\n return \"Forbidden\";\n case 404:\n return \"Not Found\";\n case 500:\n return \"Internal Server Error\";\n default:\n return \"\";\n }\n }\n\n protected getContentType(schema: any): string | undefined {\n if (!schema) return undefined;\n if (t.schema.isObject(schema) || t.schema.isArray(schema)) {\n return \"application/json\";\n }\n if (t.schema.isString(schema)) return \"text/plain\";\n if (\n t.schema.isNumber(schema) ||\n t.schema.isInteger(schema) ||\n t.schema.isBoolean(schema)\n ) {\n return \"application/json\";\n }\n if (isTypeFile(schema)) return \"application/octet-stream\";\n return \"application/json\";\n }\n\n protected configureSwaggerApi(prefix: string, json: OpenApiDocument): void {\n this.serverRouterProvider.createRoute({\n method: \"GET\",\n path: `${prefix}/json`,\n schema: {\n response: t.json(),\n },\n handler: () => json,\n });\n }\n\n protected async configureSwaggerUi(\n prefix: string,\n options: SwaggerPrimitiveOptions,\n ): Promise<void> {\n const ui = typeof options.ui === \"object\" ? options.ui : {};\n const persistAuth = ui.persistAuthorization !== false;\n const initializer = `\nwindow.onload = function() {\n\twindow.ui = SwaggerUIBundle({\n\t\turl: \"${prefix}/json\",\n\t\tdom_id: '#swagger-ui',\n\t\tdeepLinking: true,\n\t\tpersistAuthorization: ${persistAuth},\n\t\tpresets: [\n\t\t\tSwaggerUIBundle.presets.apis,\n\t\t\tSwaggerUIStandalonePreset\n\t\t],\n\t\tplugins: [\n\t\t\tSwaggerUIBundle.plugins.DownloadUrl\n\t\t],\n\t\tlayout: \"BaseLayout\"\n\t});\n\n document.body.style.backgroundColor = \"#f2f2f2\";\n\n\tconst options = ${JSON.stringify(ui)};\n\n\tif (options.initOAuth) {\n\t\tui.initOAuth(options.initOAuth);\n\t}\n};\n\t\t`.trim();\n\n if (!this.alepha.isServerless()) {\n const dirname = fileURLToPath(import.meta.url);\n\n const root = await this.getAssetPath(\n ui.root,\n // TODO: this is shitty, take time to get the correct path\n join(dirname, \"../../assets/swagger-ui\"),\n join(dirname, \"../../../assets/swagger-ui\"),\n join(dirname, \"../../../../assets/swagger-ui\"),\n join(dirname, \"../../../../../assets/swagger-ui\"),\n );\n\n if (!root) {\n this.log.warn(`Failed to locate Swagger UI assets for path ${prefix}`);\n return;\n }\n\n await this.serverStaticProvider.createStaticServer({\n path: prefix,\n root,\n });\n }\n\n this.serverRouterProvider.createRoute({\n method: \"GET\",\n path: `${prefix}/swagger-initializer.js`,\n handler: ({ reply }) => {\n reply.headers[\"content-type\"] = \"application/javascript; charset=utf-8\";\n return initializer;\n },\n });\n\n this.log.info(\"SwaggerUI OK\", {\n url: `${this.serverProvider.hostname}${prefix}`,\n });\n }\n\n protected async getAssetPath(\n ...paths: (string | undefined)[]\n ): Promise<string | undefined> {\n for (const path of paths) {\n if (!path) continue;\n const exists = await this.fs.exists(path);\n if (exists) {\n return path;\n }\n }\n }\n\n public removePrivateFields<T extends Record<string, any>>(\n obj: T,\n excludeList: string[],\n ): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n\n const visited = new WeakSet();\n\n const traverse = (o: any): void => {\n if (visited.has(o)) return;\n visited.add(o);\n\n if (Array.isArray(o)) {\n for (let i = 0; i < o.length; i++) {\n const item = o[i];\n if (item !== null && typeof item === \"object\") {\n traverse(item);\n }\n }\n } else {\n for (const excludeKey of excludeList) {\n if (excludeKey in o) {\n delete o[excludeKey];\n }\n }\n for (const key in o) {\n const item = o[key];\n if (item !== null && typeof item === \"object\") {\n traverse(item);\n }\n }\n }\n };\n\n traverse(obj);\n return obj;\n }\n}\n","import \"alepha/security\";\nimport { $module } from \"alepha\";\nimport { AlephaServer, type RequestConfigSchema } from \"alepha/server\";\nimport { AlephaServerEtag } from \"alepha/server/etag\";\nimport { AlephaServerStatic } from \"alepha/server/static\";\nimport { $swagger } from \"./primitives/$swagger.ts\";\nimport { ServerSwaggerProvider } from \"./providers/ServerSwaggerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$swagger.ts\";\nexport * from \"./providers/ServerSwaggerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha/server\" {\n interface ActionPrimitiveOptions<TConfig extends RequestConfigSchema> {\n /**\n * Short description of the route.\n */\n summary?: string;\n\n /**\n * Don't include this action in the Swagger documentation.\n */\n hide?: boolean;\n\n /**\n * Mark this action as deprecated in the documentation.\n */\n deprecated?: boolean;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Automatic API documentation generation.\n *\n * **Features:**\n * - Swagger/OpenAPI configuration\n * - Routes: `GET /swagger/ui`, `GET /swagger.json`\n *\n * @module alepha.server.swagger\n */\nexport const AlephaServerSwagger = $module({\n name: \"alepha.server.swagger\",\n primitives: [$swagger],\n services: [ServerSwaggerProvider],\n register: (alepha) => {\n alepha.with(AlephaServer);\n alepha.with(AlephaServerEtag);\n alepha.with(AlephaServerStatic);\n alepha.with(ServerSwaggerProvider);\n alepha.store.push(\"alepha.build.assets\", \"alepha\");\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,YACX,UAAmC,EAAE,KAChB;AACrB,QAAO,gBAAgB,kBAAkB,QAAQ;;AAiHnD,IAAa,mBAAb,cAAsC,UAAmC;AAEzE,SAAS,QAAQ;;;;;;AC3GjB,MAAa,iBAAiB,MAAM;CAClC,MAAM;CACN,QAAQ,EAAE,OAAO,EACf,aAAa,EAAE,SACb,EAAE,MAAM,EAAE,QAAQ,EAAE,EAClB,aAAa,uCACd,CAAC,CACH,EACF,CAAC;CACF,SAAS,EACP,aAAa,EAAE,EAChB;CACF,CAAC;AAYF,IAAa,wBAAb,MAAmC;CACjC,uBAA0C,QAAQ,qBAAqB;CACvE,uBAA0C,QAAQ,qBAAqB;CACvE,iBAAoC,QAAQ,eAAe;CAC3D,SAA4B,QAAQ,OAAO;CAC3C,MAAyB,SAAS;CAClC,UAA6B,OAAO,eAAe;CACnD,KAAwB,QAAQ,mBAAmB;CAEnD;CAEA,YAA+B,MAAM;EACnC,IAAI;EACJ,UAAU;EACV,SAAS,OAAO,WAAW;GACzB,MAAM,UAAU,OAAO,WAAW,SAAS,GAAG,IAAI;AAClD,OAAI,CAAC,QACH;AAGF,QAAK,OAAO,MAAM,KAAK,mBAAmB,QAAQ;;EAErD,CAAC;CAEF,mBAA0B,SAAmD;EAC3E,MAAM,OAAO,KAAK,iBAChB,KAAK,OAAO,WAAW,QAAQ,EAC/B,QACD;AAED,MAAI,QAAQ,QACV,SAAQ,QAAQ,KAAK;AAGvB,SAAO;;CAGT,MAAgB,mBACd,SACsC;AACtC,MAAI,QAAQ,SACV;EAGF,MAAM,OAAO,KAAK,mBAAmB,QAAQ;EAE7C,MAAM,SAAS,QAAQ,UAAU;AAEjC,OAAK,oBAAoB,QAAQ,KAAK;AAEtC,MAAI,QAAQ,OAAO,MACjB,OAAM,KAAK,mBAAmB,QAAQ,QAAQ;MAE9C,MAAK,IAAI,KAAK,4BAA4B,OAAO,OAAO;AAG1D,SAAO;;CAGT,iBACE,SACA,KACiB;EACjB,MAAM,UAA2B;GAC/B,SAAS;GACT,MAAM,IAAI,QAAQ;IAChB,OAAO;IACP,SAAS;IACV;GACD,SAAS,IAAI,WAAW,CAAC,EAAE,KAAK,KAAK,eAAe,UAAU,CAAC;GAC/D,OAAO,EAAE;GACT,YAAY,EAAE;GACf;EAED,IAAI,cAAc;EAClB,MAAM,cAAc,IAAI,eAAe,EAAE;EACzC,MAAM,UAA+B,EAAE;EAEvC,MAAM,UAAU,WAAoB;AAClC,OAAI,WAAW,UAAU,OAAO,OAAO,UAAU,UAAU;AACzD,YAAQ,OAAO,SAAS,KAAK,OAAO;AACpC,WAAO,EAAE,MAAM,wBAAwB,OAAO,SAAS;;AAEzD,UAAO,KAAK,OAAO;;EAGrB,MAAM,QAAQ,QAAa;GACzB,MAAM,WAAW,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC;AAChD,QAAK,oBAAoB,UAAU,CACjC,GAAI,KAAK,QAAQ,eAAe,EAAE,EAClC,WACD,CAAC;AACF,UAAO;;AAGT,OAAK,MAAM,SAAS,SAAS;AAC3B,OAAI,CAAC,MAAM,QAAQ,OACjB;GAGF,MAAM,WAAW,KAAK,kBAAkB,MAAM;AAC9C,OAAI,CAAC,SACH;AAGF,OAAI,YAAY,SAAS,MAAM,MAAM,CACnC;AAGF,OAAI,MAAM,QAAQ,KAChB;GAGF,MAAM,YAA8B;IAClC,aAAa,MAAM;IACnB,SAAS,MAAM,QAAQ;IACvB,aAAa,MAAM,QAAQ;IAC3B,YAAY,MAAM,QAAQ,cAAc,KAAA;IACxC,MAAM,CAAC,MAAM,MAAM,WAAW,KAAK,MAAM,CAAC;IAC1C,WAAW,GACR,SAAS,SAAS;KACjB,aAAa,KAAK,qBAAqB,SAAS,OAAO;KACvD,SAAS,SAAS,OACd,GACG,SAAS,OAAO,EACf,QAAQ,OAAO,SAAS,OAAO,EAChC,EACF,GACD,KAAA;KACL,EACF;IACF;AAID,OAFkB,MAAM,YAAY,MAAM,MAAM,GAAG,SAAS,UAE/C,EAAE;AACb,cAAU,WAAW,CAAC,EAAE,YAAY,EAAE,EAAE,CAAC;AACzC,cAAU,UAAU,SAAS,EAC3B,aAAa,gBACd;AACD,kBAAc;;AAGhB,OACE,EAAE,OAAO,SAAS,MAAM,QAAQ,OAAO,KAAK,IAC5C,EAAE,OAAO,QAAQ,MAAM,QAAQ,OAAO,KAAK,CAE3C,KACE,EAAE,OAAO,SAAS,MAAM,QAAQ,OAAO,KAAK,IAC5C,KAAK,gBAAgB,MAAM,QAAQ,OAAO,KAAK,CAE/C,WAAU,cAAc;IACtB,UAAU;IACV,SAAS,EACP,uBAAuB,EACrB,QAAQ,OAAO,MAAM,QAAQ,OAAO,KAAK,EAC1C,EACF;IACF;OAED,WAAU,cAAc;IACtB,UAAU;IACV,SAAS,EACP,oBAAoB,EAClB,QAAQ,OAAO,MAAM,QAAQ,OAAO,KAAK,EAC1C,EACF;IACF;AAIL,OAAI,EAAE,OAAO,SAAS,MAAM,QAAQ,OAAO,MAAM,EAAE;AACjD,cAAU,eAAe,EAAE;IAC3B,MAAM,eACJ,MAAM,QAAQ,OAAO,MAAM,YAAY,EAAE;AAC3C,SAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAChC,MAAM,QAAQ,OAAO,MAAM,WAC5B,EAAE;KACD,MAAM,QAAa;MACjB,MAAM;MACN,IAAI;MACJ,UAAU,aAAa,SAAS,IAAI;MACpC,QAAQ,OAAO,MAAM;MACtB;KACD,MAAM,UAAU,KAAK,eAAe,MAAM;AAC1C,SAAI,YAAY,KAAA,EAAW,OAAM,UAAU;AAC3C,eAAU,WAAW,KAAK,MAAM;;;AAIpC,OAAI,EAAE,OAAO,SAAS,MAAM,QAAQ,OAAO,OAAO,EAAE;AAClD,cAAU,eAAe,EAAE;AAC3B,SAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAChC,MAAM,QAAQ,OAAO,OAAO,WAC7B,EAAE;KACD,MAAM,cACJ,iBAAiB,SAAS,OAAO,MAAM,gBAAgB,WACnD,MAAM,cACN,KAAA;KACN,MAAM,MAAM,OAAO,MAAM;AACzB,SAAI,cAAc,KAAA;KAClB,MAAM,QAAa;MACjB,MAAM;MACN,IAAI;MACJ,UAAU;MACV;MACA,QAAQ;MACT;KACD,MAAM,UAAU,KAAK,eAAe,MAAM;AAC1C,SAAI,YAAY,KAAA,EAAW,OAAM,UAAU;AAC3C,eAAU,WAAW,KAAK,MAAM;;;AAMpC,OADE,UAAU,eAAe,UAAU,YAAY,OAE/C,WAAU,UAAU,SAAS,EAC3B,aAAa,eACd;GAGH,MAAM,MAAM,MAAM,SAAS,KAAK,kBAAkB,MAAM,KAAK;AAE7D,WAAQ,MAAM,OAAO;IACnB,GAAG,QAAQ,MAAM;KAChB,MAAM,OAAO,aAAa,GAAG;IAC/B;;AAGH,MAAI,eAAe,QAAQ,WACzB,SAAQ,WAAW,kBAAkB,EACnC,YAAY;GACV,MAAM;GACN,QAAQ;GACR,cAAc;GACd,aACE;GACH,EACF;AAGH,MAAI,QAAQ,WAAY,SAAQ,WAAW,UAAU;AAErD,SAAO,KAAK,MAAM,KAAK,UAAU,QAAQ,CAAC;;CAG5C,gBAAuB,QAA0B;AAC/C,OAAK,MAAM,OAAO,OAAO,WACvB,KAAI,WAAW,OAAO,WAAW,KAAK,CACpC,QAAO;AAGX,SAAO;;CAGT,kBAAyB,KAAqB;AAC5C,SAAO,IAAI,QAAQ,UAAU,UAAU;AAErC,UAAO,IADW,MAAM,MAAM,EACV,CAAC;IACrB;;CAGJ,kBAAyB,OAMX;EACZ,MAAM,SAAc,MAAM,QAAQ,QAAQ;AAC1C,MAAI,CAAC,OACH,QAAO,EACL,QAAQ,KACT;AAGH,MAAI,EAAE,OAAO,SAAS,OAAO,IAAI,EAAE,OAAO,QAAQ,OAAO,CACvD,QAAO;GACL;GACA,QAAQ;GACR,MAAM;GACP;AAGH,MAAI,EAAE,OAAO,SAAS,OAAO,CAC3B,QAAO;GACL;GACA,QAAQ;GACR,MAAM;GACP;AAGH,MACE,EAAE,OAAO,SAAS,OAAO,IACzB,EAAE,OAAO,UAAU,OAAO,IAC1B,EAAE,OAAO,UAAU,OAAO,CAE1B,QAAO;GACL;GACA,QAAQ;GACR,MAAM;GACP;AAGH,MAAI,WAAW,OAAO,CACpB,QAAO;GACL;GACA,QAAQ;GACR,MAAM;GACP;EAIH,MAAM,SAAS,OAAO,KAAK,OAAO,CAAC;AACnC,MAAI,UAAU,CAAC,OAAO,MAAM,OAAO,OAAO,CAAC,EAAE;GAC3C,MAAM,QAAQ,OAAO;AACrB,UAAO;IACL,QAAQ;IACR,QAAQ,OAAO,OAAO;IACtB,MAAM,KAAK,eAAe,MAAM;IACjC;;;CAIL,eAAyB,QAAkB;AACzC,MAAI,cAAc,UAAU,MAAM,QAAQ,OAAO,SAAS,CACxD,QAAO,OAAO,SAAS;AAEzB,MAAI,aAAa,OACf,QAAO,OAAO;;CAKlB,qBAA+B,QAAwB;AACrD,UAAQ,QAAR;GACE,KAAK,IACH,QAAO;GACT,KAAK,IACH,QAAO;GACT,KAAK,IACH,QAAO;GACT,KAAK,IACH,QAAO;GACT,KAAK,IACH,QAAO;GACT,KAAK,IACH,QAAO;GACT,KAAK,IACH,QAAO;GACT,KAAK,IACH,QAAO;GACT,QACE,QAAO;;;CAIb,eAAyB,QAAiC;AACxD,MAAI,CAAC,OAAQ,QAAO,KAAA;AACpB,MAAI,EAAE,OAAO,SAAS,OAAO,IAAI,EAAE,OAAO,QAAQ,OAAO,CACvD,QAAO;AAET,MAAI,EAAE,OAAO,SAAS,OAAO,CAAE,QAAO;AACtC,MACE,EAAE,OAAO,SAAS,OAAO,IACzB,EAAE,OAAO,UAAU,OAAO,IAC1B,EAAE,OAAO,UAAU,OAAO,CAE1B,QAAO;AAET,MAAI,WAAW,OAAO,CAAE,QAAO;AAC/B,SAAO;;CAGT,oBAA8B,QAAgB,MAA6B;AACzE,OAAK,qBAAqB,YAAY;GACpC,QAAQ;GACR,MAAM,GAAG,OAAO;GAChB,QAAQ,EACN,UAAU,EAAE,MAAM,EACnB;GACD,eAAe;GAChB,CAAC;;CAGJ,MAAgB,mBACd,QACA,SACe;EACf,MAAM,KAAK,OAAO,QAAQ,OAAO,WAAW,QAAQ,KAAK,EAAE;EAE3D,MAAM,cAAc;;;UAGd,OAAO;;;0BAJO,GAAG,yBAAyB,MAOd;;;;;;;;;;;;;mBAanB,KAAK,UAAU,GAAG,CAAC;;;;;;IAMlC,MAAM;AAEN,MAAI,CAAC,KAAK,OAAO,cAAc,EAAE;GAC/B,MAAM,UAAU,cAAc,OAAO,KAAK,IAAI;GAE9C,MAAM,OAAO,MAAM,KAAK,aACtB,GAAG,MAEH,KAAK,SAAS,0BAA0B,EACxC,KAAK,SAAS,6BAA6B,EAC3C,KAAK,SAAS,gCAAgC,EAC9C,KAAK,SAAS,mCAAmC,CAClD;AAED,OAAI,CAAC,MAAM;AACT,SAAK,IAAI,KAAK,+CAA+C,SAAS;AACtE;;AAGF,SAAM,KAAK,qBAAqB,mBAAmB;IACjD,MAAM;IACN;IACD,CAAC;;AAGJ,OAAK,qBAAqB,YAAY;GACpC,QAAQ;GACR,MAAM,GAAG,OAAO;GAChB,UAAU,EAAE,YAAY;AACtB,UAAM,QAAQ,kBAAkB;AAChC,WAAO;;GAEV,CAAC;AAEF,OAAK,IAAI,KAAK,gBAAgB,EAC5B,KAAK,GAAG,KAAK,eAAe,WAAW,UACxC,CAAC;;CAGJ,MAAgB,aACd,GAAG,OAC0B;AAC7B,OAAK,MAAM,QAAQ,OAAO;AACxB,OAAI,CAAC,KAAM;AAEX,OAAI,MADiB,KAAK,GAAG,OAAO,KAAK,CAEvC,QAAO;;;CAKb,oBACE,KACA,aACG;AACH,MAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU,QAAO;EAEpD,MAAM,0BAAU,IAAI,SAAS;EAE7B,MAAM,YAAY,MAAiB;AACjC,OAAI,QAAQ,IAAI,EAAE,CAAE;AACpB,WAAQ,IAAI,EAAE;AAEd,OAAI,MAAM,QAAQ,EAAE,CAClB,MAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;IACjC,MAAM,OAAO,EAAE;AACf,QAAI,SAAS,QAAQ,OAAO,SAAS,SACnC,UAAS,KAAK;;QAGb;AACL,SAAK,MAAM,cAAc,YACvB,KAAI,cAAc,EAChB,QAAO,EAAE;AAGb,SAAK,MAAM,OAAO,GAAG;KACnB,MAAM,OAAO,EAAE;AACf,SAAI,SAAS,QAAQ,OAAO,SAAS,SACnC,UAAS,KAAK;;;;AAMtB,WAAS,IAAI;AACb,SAAO;;;;;;;;;;;;;;ACtgBX,MAAa,sBAAsB,QAAQ;CACzC,MAAM;CACN,YAAY,CAAC,SAAS;CACtB,UAAU,CAAC,sBAAsB;CACjC,WAAW,WAAW;AACpB,SAAO,KAAK,aAAa;AACzB,SAAO,KAAK,iBAAiB;AAC7B,SAAO,KAAK,mBAAmB;AAC/B,SAAO,KAAK,sBAAsB;AAClC,SAAO,MAAM,KAAK,uBAAuB,SAAS;;CAErD,CAAC"}
@@ -1,4 +1,4 @@
1
- import { $env, $inject, $module, Alepha, AlephaError, KIND, Primitive, Value, createPrimitive, t } from "alepha";
1
+ import { $env, $inject, $module, Alepha, AlephaError, KIND, Primitive, SchemaValidator, createPrimitive, t } from "alepha";
2
2
  import { $topic, AlephaTopic } from "alepha/topic";
3
3
  import { $logger } from "alepha/logger";
4
4
  //#region ../../src/websocket/primitives/$channel.ts
@@ -186,6 +186,7 @@ const envSchema = t.object({
186
186
  */
187
187
  var WebSocketChannelConnection = class WebSocketChannelConnection {
188
188
  alepha = $inject(Alepha);
189
+ schemaValidator = $inject(SchemaValidator);
189
190
  log = $logger();
190
191
  ws;
191
192
  reconnectAttempts = 0;
@@ -376,10 +377,15 @@ var WebSocketChannelConnection = class WebSocketChannelConnection {
376
377
  message
377
378
  });
378
379
  const outSchema = this.channel.options.schema.out;
379
- if (!Value.Check(outSchema, message)) {
380
- const errors = Array.from(Value.Errors(outSchema, message));
381
- this.log.warn("Message validation failed", { errors });
382
- throw new AlephaError(`Message validation failed: ${errors.map((e) => e.message).join(", ")}`);
380
+ try {
381
+ this.schemaValidator.validate(outSchema, message, {
382
+ trim: false,
383
+ nullToUndefined: false,
384
+ deleteUndefined: false
385
+ });
386
+ } catch (err) {
387
+ this.log.warn("Message validation failed", { error: err });
388
+ throw new AlephaError(`Message validation failed: ${err.message}`);
383
389
  }
384
390
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
385
391
  if (this.messageQueue.length >= WebSocketChannelConnection.MAX_QUEUE_SIZE) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.js","names":[],"sources":["../../src/websocket/primitives/$channel.ts","../../src/websocket/providers/WebSocketServerProvider.ts","../../src/websocket/primitives/$websocket.ts","../../src/websocket/services/WebSocketClient.ts","../../src/websocket/errors/WebSocketError.ts","../../src/websocket/interfaces/WebSocketInterfaces.ts","../../src/websocket/services/RoomManager.ts","../../src/websocket/services/WebSocketTopicService.ts","../../src/websocket/index.browser.ts"],"sourcesContent":["import {\n createPrimitive,\n KIND,\n Primitive,\n type TObject,\n type TString,\n type TUnion,\n} from \"alepha\";\n\nexport type TWSObject = TObject | TUnion;\n\n/**\n * Channel primitive options\n */\nexport interface ChannelPrimitiveOptions<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n /**\n * WebSocket endpoint path (e.g., \"/ws/chat\")\n */\n path: string;\n\n /**\n * Optional description for documentation\n */\n description?: string;\n\n /**\n * Message schemas for bidirectional communication\n */\n schema: {\n /**\n * Optional room ID schema validation\n * Default: t.text() (any string)\n * Can be enforced at application level: t.uuid(), t.regex(/^[a-f0-9\\-]{36}$/)\n */\n roomId?: TString;\n\n /**\n * Messages from server to client\n * This is what clients will receive\n */\n in: TClient;\n\n /**\n * Messages from client to server\n * This is what the server will receive\n */\n out: TServer;\n };\n}\n\n/**\n * Defines a WebSocket channel with specified client and server message schemas.\n *\n * Channels must be defined as class properties to be registered in the Alepha context.\n * They define the \"vocabulary\" for communication - the schema for messages flowing\n * in both directions (server→client and client→server).\n *\n * @example Server-side with $websocket\n * ```typescript\n * class ChatController {\n * // Channel must be defined inside a class\n * chatChannel = $channel({\n * path: \"/ws/chat\",\n * description: \"Real-time chat channel\",\n * schema: {\n * // Server → Client messages\n * in: t.union([\n * t.object({\n * type: t.const(\"append\"),\n * content: t.text(),\n * username: t.text()\n * }),\n * t.object({\n * type: t.const(\"system\"),\n * message: t.text()\n * })\n * ]),\n * // Client → Server messages\n * out: t.object({\n * content: t.text()\n * })\n * }\n * });\n *\n * chat = $websocket({\n * channel: this.chatChannel,\n * handler: async ({ message, reply }) => {\n * await reply({\n * message: { type: \"append\", content: message.content, username: \"user\" }\n * });\n * }\n * });\n * }\n * ```\n *\n * @example Browser-side with useRoom\n * ```typescript\n * // Define channel in a class for browser context\n * class ChatClient {\n * chatChannel = $channel({\n * path: \"/ws/chat\",\n * schema: { in: inSchema, out: outSchema }\n * });\n * }\n *\n * // Use in React component\n * function Chat() {\n * const client = useInject(ChatClient);\n * const chat = useRoom({ roomId: \"lobby\", channel: client.chatChannel, handler: ... }, []);\n * }\n * ```\n */\nexport const $channel = <TClient extends TWSObject, TServer extends TWSObject>(\n options: ChannelPrimitiveOptions<TClient, TServer>,\n): ChannelPrimitive<TClient, TServer> => {\n return createPrimitive(ChannelPrimitive<TClient, TServer>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class ChannelPrimitive<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> extends Primitive<ChannelPrimitiveOptions<TClient, TServer>> {\n // Channels are just schema definitions - no initialization logic needed\n}\n\n$channel[KIND] = ChannelPrimitive;\n","import type {\n EmitOptions,\n WebSocketConnection,\n WebSocketPrimitiveOptions,\n} from \"../interfaces/WebSocketInterfaces.ts\";\nimport type { TWSObject } from \"../primitives/$channel.ts\";\n\n/**\n * Abstract WebSocket server provider\n *\n * This class provides the base interface that must be implemented by\n * platform-specific providers (Node.js, Browser, etc.)\n */\nexport abstract class WebSocketServerProvider {\n /**\n * Register a WebSocket endpoint with its channel configuration\n */\n abstract registerEndpoint<\n TClient extends TWSObject,\n TServer extends TWSObject,\n >(config: WebSocketPrimitiveOptions<TClient, TServer>): void;\n\n /**\n * Emit a message to clients based on targeting criteria\n *\n * This method distributes messages across all server instances via pub/sub.\n */\n abstract emit<TClient extends TWSObject>(\n channelPath: string,\n options: EmitOptions<TClient>,\n ): Promise<void>;\n\n /**\n * Get all active connections (local to this server instance)\n */\n abstract getConnections(): WebSocketConnection[];\n\n /**\n * Get connections in a specific room (local to this server instance)\n */\n abstract getRoomConnections(roomId: string): WebSocketConnection[];\n\n /**\n * Get connections for a specific user (local to this server instance)\n */\n abstract getUserConnections(userId: string): WebSocketConnection[];\n\n /**\n * Close a specific connection\n */\n abstract closeConnection(\n connectionId: string,\n code?: number,\n reason?: string,\n ): Promise<void>;\n}\n","import { $inject, createPrimitive, KIND, Primitive } from \"alepha\";\nimport type {\n EmitOptions,\n WebSocketPrimitiveOptions,\n} from \"../interfaces/WebSocketInterfaces.ts\";\nimport { WebSocketServerProvider } from \"../providers/WebSocketServerProvider.ts\";\nimport type { TWSObject } from \"./$channel.ts\";\n\n/**\n * Defines a WebSocket server endpoint for a specific channel.\n *\n * Server-side only. Creates a WebSocket endpoint that:\n * - Accepts connections from clients\n * - Validates incoming messages against the channel schema\n * - Provides room-based messaging\n * - Integrates with alepha/security for authentication (optional)\n * - Supports horizontal scaling via alepha/topic\n *\n * @example\n * ```typescript\n * class ChatController {\n * chat = $websocket({\n * channel: chatChannel,\n * handler: async ({ connectionId, userId, roomId, message, reply }) => {\n * // Broadcast to all in room except sender\n * await reply({\n * message: {\n * type: \"append\",\n * username: userId,\n * content: message.content\n * },\n * exceptSelf: true\n * });\n * }\n * });\n *\n * async broadcastAnnouncement(roomId: string, text: string) {\n * await this.chat.emit({\n * roomId,\n * message: {\n * type: \"append\",\n * username: \"System\",\n * content: text\n * }\n * });\n * }\n * }\n * ```\n */\nexport const $websocket = <\n TClient extends TWSObject,\n TServer extends TWSObject,\n>(\n options: WebSocketPrimitiveOptions<TClient, TServer>,\n): WebSocketPrimitive<TClient, TServer> => {\n return createPrimitive(WebSocketPrimitive<TClient, TServer>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class WebSocketPrimitive<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> extends Primitive<WebSocketPrimitiveOptions<TClient, TServer>> {\n protected readonly webSocketServerProvider = $inject(WebSocketServerProvider);\n\n protected onInit() {\n this.webSocketServerProvider.registerEndpoint(this.options);\n }\n\n /**\n * Emit message to clients\n *\n * Send messages from the server to connected clients based on targeting criteria.\n * Messages are distributed across all server instances via pub/sub.\n *\n * @example\n * ```typescript\n * // Send to specific room\n * await websocket.emit({\n * roomId: \"room-123\",\n * message: { type: \"update\", data: {...} }\n * });\n *\n * // Send to specific user (all their connections)\n * await websocket.emit({\n * userId: \"user-456\",\n * message: { type: \"notification\", text: \"Hello!\" }\n * });\n *\n * // Send to multiple rooms, except certain users\n * await websocket.emit({\n * roomIds: [\"room-1\", \"room-2\"],\n * exceptUserIds: [\"user-123\"],\n * message: { type: \"broadcast\", content: \"System announcement\" }\n * });\n * ```\n */\n public async emit(options: EmitOptions<TClient>): Promise<void> {\n await this.webSocketServerProvider.emit(\n this.options.channel.options.path,\n options,\n );\n }\n}\n\n$websocket[KIND] = WebSocketPrimitive;\n","import {\n $env,\n $inject,\n Alepha,\n AlephaError,\n type Static,\n t,\n Value,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { ChannelPrimitive, TWSObject } from \"../primitives/$channel.ts\";\n\nconst envSchema = t.object({\n WEBSOCKET_URL: t.text({\n default: \"\",\n description:\n \"WebSocket server URL (e.g., ws://localhost:3001). Leave empty to auto-detect.\",\n }),\n WEBSOCKET_RECONNECT_INTERVAL: t.integer({\n default: 3000,\n description: \"Reconnection interval in milliseconds\",\n }),\n WEBSOCKET_MAX_RECONNECT_ATTEMPTS: t.integer({\n default: 10,\n description:\n \"Maximum number of reconnection attempts. Set to -1 for infinite.\",\n }),\n});\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Room subscription\n */\ninterface RoomSubscription<TClient extends TWSObject> {\n roomId: string;\n handler: (message: Static<TClient>) => void;\n}\n\n/**\n * WebSocket channel connection\n *\n * Manages a single WebSocket connection to a channel with multiple room subscriptions.\n * One connection can handle multiple rooms on the same channel.\n */\nexport class WebSocketChannelConnection<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected ws?: WebSocket;\n protected reconnectAttempts = 0;\n protected reconnectTimer?: number;\n protected static readonly MAX_QUEUE_SIZE = 1000;\n protected messageQueue: Array<{ roomId: string; message: Static<TServer> }> =\n [];\n\n // Room subscriptions: Map<roomId, handler>\n protected subscriptions = new Map<\n string,\n (message: Static<TClient>) => void\n >();\n\n // Connection state\n public isConnected = false;\n public isConnecting = false;\n public isError = false;\n public error?: Error;\n protected connectPromise?: Promise<void>;\n\n // Connection callbacks\n protected onConnectCallbacks = new Set<() => void>();\n protected onDisconnectCallbacks = new Set<() => void>();\n protected onErrorCallbacks = new Set<(error: Error) => void>();\n\n constructor(\n protected readonly channel: ChannelPrimitive<TClient, TServer>,\n protected readonly options: {\n url?: string;\n autoReconnect?: boolean;\n reconnectInterval?: number;\n maxReconnectAttempts?: number;\n },\n protected readonly env: Static<typeof envSchema>,\n ) {}\n\n /**\n * Build WebSocket URL\n */\n protected buildUrl(): string {\n this.log.trace(\"Building WebSocket URL\", {\n hasCustomUrl: !!this.options.url,\n channelPath: this.channel.options.path,\n });\n\n if (this.options.url) {\n this.log.debug(\"Using custom WebSocket URL\", { url: this.options.url });\n return this.options.url;\n }\n\n // Auto-detect URL from current location (browser only)\n if (typeof window !== \"undefined\") {\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const host = window.location.host;\n const path = this.channel.options.path;\n // Send all room IDs as query params\n const roomIds = Array.from(this.subscriptions.keys());\n const roomParam =\n roomIds.length > 0 ? `?roomIds=${roomIds.join(\",\")}` : \"\";\n const url = `${protocol}//${host}${path}${roomParam}`;\n this.log.debug(\"Auto-detected WebSocket URL\", { url, roomIds });\n return url;\n }\n\n // Fallback to env URL\n const url = `${this.env.WEBSOCKET_URL}${this.channel.options.path}`;\n this.log.debug(\"Using env WebSocket URL\", { url });\n return url;\n }\n\n /**\n * Subscribe to a room on this channel\n */\n public subscribe(\n roomId: string,\n handler: (message: Static<TClient>) => void,\n callbacks?: {\n onConnect?: () => void;\n onDisconnect?: () => void;\n onError?: (error: Error) => void;\n },\n ): () => void {\n this.log.debug(\"Subscribing to room\", {\n roomId,\n channelPath: this.channel.options.path,\n existingSubscriptions: this.subscriptions.size,\n });\n\n // Add subscription\n this.subscriptions.set(roomId, handler);\n\n // Add callbacks\n if (callbacks?.onConnect) this.onConnectCallbacks.add(callbacks.onConnect);\n if (callbacks?.onDisconnect)\n this.onDisconnectCallbacks.add(callbacks.onDisconnect);\n if (callbacks?.onError) this.onErrorCallbacks.add(callbacks.onError);\n\n // Connect or reconnect to include the new room in the URL\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n this.log.trace(\"No active connection, initiating connect\");\n this.connect().catch((error) => {\n this.log.error(\"Failed to connect:\", error);\n });\n } else {\n this.log.trace(\"Reconnecting to include new room subscription\", {\n roomId,\n });\n this.reconnect();\n }\n\n // Return unsubscribe function\n return () => {\n this.log.debug(\"Unsubscribing from room\", { roomId });\n this.subscriptions.delete(roomId);\n if (callbacks?.onConnect)\n this.onConnectCallbacks.delete(callbacks.onConnect);\n if (callbacks?.onDisconnect)\n this.onDisconnectCallbacks.delete(callbacks.onDisconnect);\n if (callbacks?.onError) this.onErrorCallbacks.delete(callbacks.onError);\n\n // Disconnect if no more subscriptions\n if (this.subscriptions.size === 0) {\n this.log.debug(\"No more subscriptions, disconnecting\");\n this.disconnect();\n }\n };\n }\n\n /**\n * Connect to WebSocket server\n */\n protected async connect(): Promise<void> {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.log.trace(\"Already connected, skipping connect\");\n return;\n }\n\n if (this.connectPromise) {\n this.log.trace(\"Connection already in progress, reusing promise\");\n return this.connectPromise;\n }\n\n this.isConnecting = true;\n this.isError = false;\n this.error = undefined;\n\n const url = this.buildUrl();\n this.log.info(\"Connecting to WebSocket server\", { url });\n\n this.connectPromise = new Promise<void>((resolve, reject) => {\n try {\n const ws = new WebSocket(url);\n this.ws = ws;\n\n ws.onopen = () => {\n this.isConnected = true;\n this.isConnecting = false;\n this.isError = false;\n this.error = undefined;\n this.reconnectAttempts = 0;\n\n this.log.info(\"WebSocket connected\", {\n channelPath: this.channel.options.path,\n rooms: Array.from(this.subscriptions.keys()),\n });\n\n // Flush queued messages\n if (this.messageQueue.length > 0) {\n this.log.debug(\"Flushing queued messages\", {\n count: this.messageQueue.length,\n });\n }\n while (this.messageQueue.length > 0) {\n const msg = this.messageQueue.shift();\n if (msg) {\n this.log.trace(\"Sending queued message\", { roomId: msg.roomId });\n ws.send(\n JSON.stringify({\n roomId: msg.roomId,\n message: msg.message,\n }),\n );\n }\n }\n\n // Call all connect callbacks\n for (const callback of this.onConnectCallbacks) {\n callback();\n }\n\n resolve();\n };\n\n ws.onmessage = (event) => {\n this.log.trace(\"Message received\", {\n dataLength: event.data?.length,\n });\n this.handleMessage(event.data);\n };\n\n ws.onclose = (event) => {\n this.isConnected = false;\n this.isConnecting = false;\n this.ws = undefined;\n\n this.log.info(\"WebSocket disconnected\", {\n code: event.code,\n reason: event.reason,\n wasClean: event.wasClean,\n });\n\n // Call all disconnect callbacks\n for (const callback of this.onDisconnectCallbacks) {\n callback();\n }\n\n // Attempt reconnection\n if (this.options.autoReconnect !== false) {\n this.scheduleReconnect();\n }\n };\n\n ws.onerror = () => {\n const err = new Error(\"WebSocket connection error\");\n this.isError = true;\n this.error = err;\n this.isConnecting = false;\n\n this.log.error(\"WebSocket error\", { url });\n\n // Call all error callbacks\n for (const callback of this.onErrorCallbacks) {\n callback(err);\n }\n\n reject(err);\n };\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error(\"Connection failed\");\n this.isError = true;\n this.error = error;\n this.isConnecting = false;\n\n this.log.error(\"Failed to create WebSocket\", { error: error.message });\n\n // Call all error callbacks\n for (const callback of this.onErrorCallbacks) {\n callback(error);\n }\n\n reject(error);\n }\n }).finally(() => {\n this.connectPromise = undefined;\n });\n\n return this.connectPromise;\n }\n\n /**\n * Handle incoming message\n */\n protected handleMessage(data: string): void {\n try {\n const parsed = JSON.parse(data);\n this.log.trace(\"Parsed incoming message\", { parsed });\n\n // Validate incoming message against schema\n const inSchema = this.channel.options.schema.in;\n this.alepha.codec.validate(inSchema, parsed);\n\n this.log.debug(\"Dispatching message to handlers\", {\n handlerCount: this.subscriptions.size,\n });\n\n // Extract roomId from message if present (server should send it back)\n // For now, broadcast to all subscribed rooms\n // TODO: Server should include roomId in response\n for (const handler of this.subscriptions.values()) {\n handler(parsed as Static<TClient>);\n }\n } catch (err) {\n this.log.error(\"Error handling message:\", err);\n }\n }\n\n /**\n * Send message to a specific room\n */\n public async send(roomId: string, message: Static<TServer>): Promise<void> {\n this.log.trace(\"Sending message\", { roomId, message });\n\n // Validate outgoing message against schema\n const outSchema = this.channel.options.schema.out;\n if (!Value.Check(outSchema, message)) {\n const errors = Array.from(Value.Errors(outSchema, message));\n this.log.warn(\"Message validation failed\", { errors });\n throw new AlephaError(\n `Message validation failed: ${errors.map((e) => e.message).join(\", \")}`,\n );\n }\n\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n if (\n this.messageQueue.length >= WebSocketChannelConnection.MAX_QUEUE_SIZE\n ) {\n this.log.warn(\"Message queue full, dropping oldest message\", {\n roomId,\n queueSize: this.messageQueue.length,\n });\n this.messageQueue.shift();\n }\n this.log.debug(\"Connection not ready, queuing message\", {\n roomId,\n queueSize: this.messageQueue.length + 1,\n });\n this.messageQueue.push({ roomId, message });\n return;\n }\n\n this.log.debug(\"Sending message to server\", { roomId });\n this.ws.send(\n JSON.stringify({\n roomId,\n message,\n }),\n );\n }\n\n /**\n * Schedule reconnection\n */\n protected scheduleReconnect(): void {\n // Clear any pending reconnect timer\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n const maxAttempts =\n this.options.maxReconnectAttempts ??\n this.env.WEBSOCKET_MAX_RECONNECT_ATTEMPTS ??\n 10;\n const reconnectInterval =\n this.options.reconnectInterval ??\n this.env.WEBSOCKET_RECONNECT_INTERVAL ??\n 3000;\n\n if (maxAttempts !== -1 && this.reconnectAttempts >= maxAttempts) {\n this.log.warn(\"Max reconnection attempts reached\", {\n attempts: this.reconnectAttempts,\n maxAttempts,\n });\n return;\n }\n\n this.reconnectAttempts++;\n\n this.log.debug(\"Scheduling reconnection\", {\n attempt: this.reconnectAttempts,\n maxAttempts,\n intervalMs: reconnectInterval,\n });\n\n this.reconnectTimer = window.setTimeout(() => {\n this.log.info(\"Reconnecting...\", {\n attempt: this.reconnectAttempts,\n maxAttempts,\n });\n this.connect().catch((error) => {\n this.log.error(\"Reconnection failed:\", error);\n });\n }, reconnectInterval);\n }\n\n /**\n * Disconnect from server\n */\n public disconnect(): void {\n this.log.debug(\"Disconnecting\", {\n hasTimer: !!this.reconnectTimer,\n hasConnection: !!this.ws,\n });\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n if (this.ws) {\n this.ws.close();\n this.ws = undefined;\n }\n\n this.isConnected = false;\n this.isConnecting = false;\n this.connectPromise = undefined;\n\n this.log.info(\"Disconnected\");\n }\n\n /**\n * Reconnect manually\n */\n public reconnect(): void {\n this.log.info(\"Manual reconnect requested\");\n this.disconnect();\n this.connect().catch((error) => {\n this.log.error(\"Manual reconnection failed:\", error);\n });\n }\n\n /**\n * Check if subscribed to a room\n */\n public hasRoom(roomId: string): boolean {\n return this.subscriptions.has(roomId);\n }\n\n /**\n * Get all subscribed rooms\n */\n public getRooms(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n}\n\n/**\n * WebSocket Client Service\n *\n * Manages WebSocket connections from the client side (browser).\n * One connection per channel, multiple rooms per connection.\n */\nexport class WebSocketClient {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly env = $env(envSchema);\n\n // Map<channelPath, connection>\n protected connections = new Map<\n string,\n WebSocketChannelConnection<any, any>\n >();\n\n /**\n * Subscribe to a room on a channel\n */\n public subscribe<TClient extends TWSObject, TServer extends TWSObject>(\n roomId: string,\n channel: ChannelPrimitive<TClient, TServer>,\n handler: (message: Static<TClient>) => void,\n options: {\n url?: string;\n autoReconnect?: boolean;\n reconnectInterval?: number;\n maxReconnectAttempts?: number;\n onConnect?: () => void;\n onDisconnect?: () => void;\n onError?: (error: Error) => void;\n } = {},\n ): () => void {\n const channelPath = channel.options.path;\n\n this.log.debug(\"WebSocketClient.subscribe\", {\n roomId,\n channelPath,\n existingConnections: this.connections.size,\n });\n\n // Get or create connection for this channel\n let connection = this.connections.get(\n channelPath,\n ) as WebSocketChannelConnection<TClient, TServer>;\n\n if (!connection) {\n this.log.debug(\"Creating new connection for channel\", { channelPath });\n connection = this.alepha.inject(WebSocketChannelConnection, {\n lifetime: \"transient\",\n args: [\n channel,\n {\n url: options.url,\n autoReconnect: options.autoReconnect,\n reconnectInterval: options.reconnectInterval,\n maxReconnectAttempts: options.maxReconnectAttempts,\n },\n this.env,\n ],\n }) as WebSocketChannelConnection<any, any>;\n\n this.connections.set(channelPath, connection);\n } else {\n this.log.trace(\"Reusing existing connection for channel\", {\n channelPath,\n });\n }\n\n // Subscribe to the room on this connection\n const unsubscribe = connection.subscribe(roomId, handler, {\n onConnect: options.onConnect,\n onDisconnect: options.onDisconnect,\n onError: options.onError,\n });\n\n // Return unsubscribe function\n return () => {\n this.log.debug(\"WebSocketClient.unsubscribe\", { roomId, channelPath });\n unsubscribe();\n\n // Clean up connection if no more rooms\n if (connection.getRooms().length === 0) {\n this.log.debug(\"Removing connection for channel (no more rooms)\", {\n channelPath,\n });\n this.connections.delete(channelPath);\n }\n };\n }\n\n /**\n * Send message to a room on a channel\n */\n public async send<TClient extends TWSObject, TServer extends TWSObject>(\n roomId: string,\n channel: ChannelPrimitive<TClient, TServer>,\n message: Static<TServer>,\n ): Promise<void> {\n const channelPath = channel.options.path;\n\n this.log.trace(\"WebSocketClient.send\", { roomId, channelPath });\n\n const connection = this.connections.get(\n channelPath,\n ) as WebSocketChannelConnection<TClient, TServer>;\n\n if (!connection) {\n this.log.warn(\"Attempted to send on unsubscribed channel\", {\n channelPath,\n });\n throw new AlephaError(\n `Not subscribed to channel ${channelPath}. Subscribe first before sending messages.`,\n );\n }\n\n await connection.send(roomId, message);\n }\n\n /**\n * Get connection for a channel\n */\n public getConnection<TClient extends TWSObject, TServer extends TWSObject>(\n channel: ChannelPrimitive<TClient, TServer>,\n ): WebSocketChannelConnection<TClient, TServer> | undefined {\n const channelPath = channel.options.path;\n const connection = this.connections.get(channelPath) as\n | WebSocketChannelConnection<TClient, TServer>\n | undefined;\n\n this.log.trace(\"WebSocketClient.getConnection\", {\n channelPath,\n found: !!connection,\n });\n\n return connection;\n }\n\n /**\n * Disconnect all connections\n */\n public disconnectAll(): void {\n this.log.info(\"Disconnecting all connections\", {\n count: this.connections.size,\n });\n\n for (const connection of this.connections.values()) {\n connection.disconnect();\n }\n this.connections.clear();\n\n this.log.debug(\"All connections disconnected\");\n }\n}\n","import { AlephaError } from \"alepha\";\n\n/**\n * Base WebSocket error class\n */\nexport class WebSocketError extends AlephaError {\n constructor(\n message: string,\n public readonly code?: number,\n ) {\n super(message);\n this.name = \"WebSocketError\";\n }\n}\n\n/**\n * Error thrown when WebSocket connection fails\n */\nexport class WebSocketConnectionError extends WebSocketError {\n constructor(message: string, code?: number) {\n super(message, code);\n this.name = \"WebSocketConnectionError\";\n }\n}\n\n/**\n * Error thrown when WebSocket message validation fails\n */\nexport class WebSocketValidationError extends WebSocketError {\n constructor(message: string) {\n super(message);\n this.name = \"WebSocketValidationError\";\n }\n}\n","import type { Static } from \"alepha\";\nimport type { ChannelPrimitive, TWSObject } from \"../primitives/$channel.ts\";\n\n/**\n * WebSocket connection interface\n */\nexport interface WebSocketConnection {\n /**\n * Unique connection ID\n */\n id: string;\n\n /**\n * User ID (if authenticated and security module is used)\n */\n userId?: string;\n\n /**\n * Channel path this connection belongs to\n */\n channelPath: string;\n\n /**\n * Room IDs that this connection is currently in\n */\n roomIds: string[];\n\n /**\n * Send a message to this connection\n */\n send(message: any): Promise<void>;\n\n /**\n * Close this connection\n */\n close(code?: number, reason?: string): Promise<void>;\n\n /**\n * Connection metadata (custom data)\n */\n metadata?: Record<string, any>;\n\n /**\n * Connection state\n */\n readyState: WebSocketState;\n}\n\n/**\n * WebSocket state enum\n */\nexport enum WebSocketState {\n CONNECTING = 0,\n OPEN = 1,\n CLOSING = 2,\n CLOSED = 3,\n}\n\n/**\n * WebSocket endpoint configuration (server-side)\n */\nexport interface WebSocketPrimitiveOptions<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n /**\n * Channel definition with schema and path\n */\n channel: ChannelPrimitive<TClient, TServer>;\n\n /**\n * Handler for incoming messages from clients\n */\n handler: WebSocketHandler<TClient, TServer>;\n\n /**\n * Optional connection handler (called when a client connects)\n */\n onConnect?: (params: {\n /**\n * Unique connection ID of the client\n */\n connectionId: string;\n\n /**\n * User ID of the connected client (if authenticated and security module is used)\n */\n userId?: string;\n\n /**\n * Room IDs that the client is connecting to\n */\n roomIds: string[];\n }) => Promise<void> | void;\n\n /**\n * Optional disconnection handler (called when a client disconnects)\n */\n onDisconnect?: (params: {\n /**\n * Unique connection ID of the client\n */\n connectionId: string;\n\n /**\n * User ID of the connected client (if authenticated and security module is used)\n */\n userId?: string;\n\n /**\n * Room IDs that the client was connected to\n */\n roomIds: string[];\n }) => Promise<void> | void;\n\n /**\n * Change WebSocket server provider (for custom implementations)\n */\n provider?: any;\n\n /**\n * Whether to enforce security (authentication, authorization) on this WebSocket endpoint\n * Requires alepha/security integration\n */\n secure?: boolean;\n\n /**\n * Limit number of connections per user (if authenticated)\n */\n maxConnectionsPerUser?: number;\n}\n\n/**\n * WebSocket message handler\n */\nexport type WebSocketHandler<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> = (\n context: WebSocketHandlerContext<TClient, TServer>,\n) => Promise<void> | void;\n\n/**\n * WebSocket handler context\n */\nexport interface WebSocketHandlerContext<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n /**\n * Unique connection ID of the client\n */\n connectionId: string;\n\n /**\n * User ID of the connected client (if authenticated and security module is used)\n */\n userId?: string;\n\n /**\n * Room ID that the client sent the message from\n */\n roomId: string;\n\n /**\n * The parsed and validated message from the client\n */\n message: Static<TServer>;\n\n /**\n * Reply function tailored to current context (connectionId, roomId)\n */\n reply: (options: {\n /**\n * Message to send\n */\n message: Static<TClient>;\n\n /**\n * Optional: specify room ID to send to (defaults to sender's room ID)\n */\n roomId?: string;\n\n /**\n * Optional: exclude the sender connection from receiving the message\n * Will populate exceptConnectionIds with sender connection ID behind the scenes\n */\n exceptSelf?: boolean;\n\n /**\n * Optional: exclude specific connection IDs from receiving the message\n */\n exceptConnectionIds?: string[];\n\n /**\n * Optional: exclude specific user IDs from receiving the message\n * Requires alepha/security integration\n */\n exceptUserIds?: string[];\n }) => Promise<void>;\n}\n\n/**\n * Emit options for sending messages from the server\n */\nexport interface EmitOptions<TClient extends TWSObject> {\n /**\n * Message to send to clients\n */\n message: Static<TClient>;\n\n /**\n * Room ID to send the message to\n */\n roomId?: string;\n\n /**\n * Room IDs to send the message to\n */\n roomIds?: string[];\n\n /**\n * User ID to send the message to (if authenticated)\n */\n userId?: string;\n\n /**\n * User IDs to send the message to (if authenticated)\n */\n userIds?: string[];\n\n /**\n * Connection ID to send the message to\n */\n connectionId?: string;\n\n /**\n * Connection IDs to send the message to\n */\n connectionIds?: string[];\n\n /**\n * Optional: exclude specific connection IDs from receiving the message\n */\n exceptConnectionIds?: string[];\n\n /**\n * Optional: exclude specific user IDs from receiving the message\n * Requires alepha/security integration\n */\n exceptUserIds?: string[];\n}\n","import { $logger } from \"alepha/logger\";\n\n/**\n * Manages WebSocket room memberships\n *\n * Rooms are logical groupings of connections. A connection can be in multiple rooms,\n * and messages can be targeted to specific rooms.\n */\nexport class RoomManager {\n protected readonly log = $logger();\n\n /**\n * Maps roomId → Set<connectionId>\n */\n protected readonly rooms = new Map<string, Set<string>>();\n\n /**\n * Maps connectionId → Set<roomId>\n * Inverse index for fast lookup of connection's rooms\n */\n protected readonly connectionRooms = new Map<string, Set<string>>();\n\n /**\n * Join a connection to one or more rooms\n */\n public joinRooms(connectionId: string, roomIds: string[]): void {\n for (const roomId of roomIds) {\n this.joinRoom(connectionId, roomId);\n }\n }\n\n /**\n * Join a connection to a room\n */\n public joinRoom(connectionId: string, roomId: string): void {\n // Add to room\n let room = this.rooms.get(roomId);\n if (!room) {\n room = new Set();\n this.rooms.set(roomId, room);\n }\n room.add(connectionId);\n\n // Update inverse index\n let connRooms = this.connectionRooms.get(connectionId);\n if (!connRooms) {\n connRooms = new Set();\n this.connectionRooms.set(connectionId, connRooms);\n }\n connRooms.add(roomId);\n\n this.log.debug(`Connection ${connectionId} joined room ${roomId}`);\n }\n\n /**\n * Leave a connection from a room\n */\n public leaveRoom(connectionId: string, roomId: string): void {\n // Remove from room\n const room = this.rooms.get(roomId);\n if (room) {\n room.delete(connectionId);\n if (room.size === 0) {\n this.rooms.delete(roomId);\n }\n }\n\n // Update inverse index\n const connRooms = this.connectionRooms.get(connectionId);\n if (connRooms) {\n connRooms.delete(roomId);\n if (connRooms.size === 0) {\n this.connectionRooms.delete(connectionId);\n }\n }\n\n this.log.debug(`Connection ${connectionId} left room ${roomId}`);\n }\n\n /**\n * Remove a connection from all rooms\n */\n public leaveAllRooms(connectionId: string): void {\n const connRooms = this.connectionRooms.get(connectionId);\n if (!connRooms) {\n return;\n }\n\n for (const roomId of connRooms) {\n const room = this.rooms.get(roomId);\n if (room) {\n room.delete(connectionId);\n if (room.size === 0) {\n this.rooms.delete(roomId);\n }\n }\n }\n\n this.connectionRooms.delete(connectionId);\n this.log.debug(`Connection ${connectionId} left all rooms`);\n }\n\n /**\n * Get all connection IDs in a room\n */\n public getRoomConnections(roomId: string): string[] {\n const room = this.rooms.get(roomId);\n return room ? Array.from(room) : [];\n }\n\n /**\n * Get all room IDs for a connection\n */\n public getConnectionRooms(connectionId: string): string[] {\n const connRooms = this.connectionRooms.get(connectionId);\n return connRooms ? Array.from(connRooms) : [];\n }\n\n /**\n * Check if a connection is in a room\n */\n public isInRoom(connectionId: string, roomId: string): boolean {\n const connRooms = this.connectionRooms.get(connectionId);\n return connRooms ? connRooms.has(roomId) : false;\n }\n\n /**\n * Get all active rooms\n */\n public getAllRooms(): string[] {\n return Array.from(this.rooms.keys());\n }\n\n /**\n * Get total number of connections across all rooms\n */\n public getTotalConnections(): number {\n return this.connectionRooms.size;\n }\n\n /**\n * Get room statistics\n */\n public getStats(): {\n totalRooms: number;\n totalConnections: number;\n roomSizes: Map<string, number>;\n } {\n const roomSizes = new Map<string, number>();\n for (const [roomId, connections] of this.rooms) {\n roomSizes.set(roomId, connections.size);\n }\n\n return {\n totalRooms: this.rooms.size,\n totalConnections: this.connectionRooms.size,\n roomSizes,\n };\n }\n}\n","import { type Static, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $topic } from \"alepha/topic\";\n\n/**\n * WebSocket message distribution event\n */\nconst webSocketMessageSchema = {\n payload: t.object({\n /**\n * Channel path (e.g., \"/ws/chat\")\n */\n channelPath: t.text(),\n\n /**\n * Target room ID(s)\n */\n roomIds: t.optional(t.array(t.text())),\n\n /**\n * Target user ID(s)\n */\n userIds: t.optional(t.array(t.text())),\n\n /**\n * Target connection ID(s)\n */\n connectionIds: t.optional(t.array(t.text())),\n\n /**\n * Exclude connection ID(s) from receiving the message\n */\n exceptConnectionIds: t.optional(t.array(t.text())),\n\n /**\n * Exclude user ID(s) from receiving the message\n */\n exceptUserIds: t.optional(t.array(t.text())),\n\n /**\n * The message payload to send\n */\n message: t.any(),\n }),\n};\n\n/**\n * WebSocket Topic Service\n *\n * Manages pub/sub messaging for WebSocket connections across multiple server instances.\n * Uses alepha/topic for cross-instance message distribution, enabling horizontal scaling.\n *\n * When a WebSocket message needs to be sent:\n * 1. Server instance A publishes to the topic\n * 2. All server instances (A, B, C, etc.) receive the message\n * 3. Each instance sends to its local connections that match the criteria\n *\n * This enables:\n * - Multiple server instances handling WebSocket connections\n * - Redis-backed message distribution (with alepha/topic/redis)\n * - Horizontal scaling without losing messages\n */\nexport class WebSocketTopicService {\n protected readonly log = $logger();\n\n /**\n * Handler function to be called when a message is received from the topic\n * This is set by the WebSocket provider during initialization\n */\n public messageHandler?: (\n event: Static<(typeof webSocketMessageSchema)[\"payload\"]>,\n ) => Promise<void>;\n\n /**\n * Topic for distributing WebSocket messages across server instances\n */\n public readonly topic = $topic({\n name: \"websocket:broadcast\",\n description:\n \"Distributes WebSocket messages across server instances for horizontal scaling\",\n schema: webSocketMessageSchema,\n handler: async (message) => {\n if (this.messageHandler) {\n await this.messageHandler(message.payload);\n }\n },\n });\n\n /**\n * Publish a message to be distributed across all server instances\n */\n public async publish(\n event: Static<(typeof webSocketMessageSchema)[\"payload\"]>,\n ): Promise<void> {\n await this.topic.publish(event);\n }\n\n /**\n * Set the handler for incoming messages\n */\n public setMessageHandler(\n handler: (\n event: Static<(typeof webSocketMessageSchema)[\"payload\"]>,\n ) => Promise<void>,\n ): void {\n this.messageHandler = handler;\n }\n}\n","import { $module, type Alepha } from \"alepha\";\nimport { AlephaTopic } from \"alepha/topic\";\nimport { $channel } from \"./primitives/$channel.ts\";\nimport { $websocket } from \"./primitives/$websocket.ts\";\nimport { WebSocketClient } from \"./services/WebSocketClient.ts\";\n\n/**\n * alepha/websocket (Browser)\n *\n * Browser-side WebSocket client module. Provides WebSocketClient service\n * for managing WebSocket connections from the browser.\n *\n * For React applications, use alepha/react/websocket with the useRoom hook.\n */\nexport * from \"./index.shared.ts\";\n\nexport const AlephaWebSocket = $module({\n name: \"alepha.websocket\",\n primitives: [$channel, $websocket],\n services: [WebSocketClient],\n register: (alepha: Alepha) => {\n alepha.with(AlephaTopic);\n alepha.with(WebSocketClient);\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.browser.js","names":[],"sources":["../../src/websocket/primitives/$channel.ts","../../src/websocket/providers/WebSocketServerProvider.ts","../../src/websocket/primitives/$websocket.ts","../../src/websocket/services/WebSocketClient.ts","../../src/websocket/errors/WebSocketError.ts","../../src/websocket/interfaces/WebSocketInterfaces.ts","../../src/websocket/services/RoomManager.ts","../../src/websocket/services/WebSocketTopicService.ts","../../src/websocket/index.browser.ts"],"sourcesContent":["import {\n createPrimitive,\n KIND,\n Primitive,\n type TObject,\n type TString,\n type TUnion,\n} from \"alepha\";\n\nexport type TWSObject = TObject | TUnion;\n\n/**\n * Channel primitive options\n */\nexport interface ChannelPrimitiveOptions<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n /**\n * WebSocket endpoint path (e.g., \"/ws/chat\")\n */\n path: string;\n\n /**\n * Optional description for documentation\n */\n description?: string;\n\n /**\n * Message schemas for bidirectional communication\n */\n schema: {\n /**\n * Optional room ID schema validation\n * Default: t.text() (any string)\n * Can be enforced at application level: t.uuid(), t.regex(/^[a-f0-9\\-]{36}$/)\n */\n roomId?: TString;\n\n /**\n * Messages from server to client\n * This is what clients will receive\n */\n in: TClient;\n\n /**\n * Messages from client to server\n * This is what the server will receive\n */\n out: TServer;\n };\n}\n\n/**\n * Defines a WebSocket channel with specified client and server message schemas.\n *\n * Channels must be defined as class properties to be registered in the Alepha context.\n * They define the \"vocabulary\" for communication - the schema for messages flowing\n * in both directions (server→client and client→server).\n *\n * @example Server-side with $websocket\n * ```typescript\n * class ChatController {\n * // Channel must be defined inside a class\n * chatChannel = $channel({\n * path: \"/ws/chat\",\n * description: \"Real-time chat channel\",\n * schema: {\n * // Server → Client messages\n * in: t.union([\n * t.object({\n * type: t.const(\"append\"),\n * content: t.text(),\n * username: t.text()\n * }),\n * t.object({\n * type: t.const(\"system\"),\n * message: t.text()\n * })\n * ]),\n * // Client → Server messages\n * out: t.object({\n * content: t.text()\n * })\n * }\n * });\n *\n * chat = $websocket({\n * channel: this.chatChannel,\n * handler: async ({ message, reply }) => {\n * await reply({\n * message: { type: \"append\", content: message.content, username: \"user\" }\n * });\n * }\n * });\n * }\n * ```\n *\n * @example Browser-side with useRoom\n * ```typescript\n * // Define channel in a class for browser context\n * class ChatClient {\n * chatChannel = $channel({\n * path: \"/ws/chat\",\n * schema: { in: inSchema, out: outSchema }\n * });\n * }\n *\n * // Use in React component\n * function Chat() {\n * const client = useInject(ChatClient);\n * const chat = useRoom({ roomId: \"lobby\", channel: client.chatChannel, handler: ... }, []);\n * }\n * ```\n */\nexport const $channel = <TClient extends TWSObject, TServer extends TWSObject>(\n options: ChannelPrimitiveOptions<TClient, TServer>,\n): ChannelPrimitive<TClient, TServer> => {\n return createPrimitive(ChannelPrimitive<TClient, TServer>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class ChannelPrimitive<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> extends Primitive<ChannelPrimitiveOptions<TClient, TServer>> {\n // Channels are just schema definitions - no initialization logic needed\n}\n\n$channel[KIND] = ChannelPrimitive;\n","import type {\n EmitOptions,\n WebSocketConnection,\n WebSocketPrimitiveOptions,\n} from \"../interfaces/WebSocketInterfaces.ts\";\nimport type { TWSObject } from \"../primitives/$channel.ts\";\n\n/**\n * Abstract WebSocket server provider\n *\n * This class provides the base interface that must be implemented by\n * platform-specific providers (Node.js, Browser, etc.)\n */\nexport abstract class WebSocketServerProvider {\n /**\n * Register a WebSocket endpoint with its channel configuration\n */\n abstract registerEndpoint<\n TClient extends TWSObject,\n TServer extends TWSObject,\n >(config: WebSocketPrimitiveOptions<TClient, TServer>): void;\n\n /**\n * Emit a message to clients based on targeting criteria\n *\n * This method distributes messages across all server instances via pub/sub.\n */\n abstract emit<TClient extends TWSObject>(\n channelPath: string,\n options: EmitOptions<TClient>,\n ): Promise<void>;\n\n /**\n * Get all active connections (local to this server instance)\n */\n abstract getConnections(): WebSocketConnection[];\n\n /**\n * Get connections in a specific room (local to this server instance)\n */\n abstract getRoomConnections(roomId: string): WebSocketConnection[];\n\n /**\n * Get connections for a specific user (local to this server instance)\n */\n abstract getUserConnections(userId: string): WebSocketConnection[];\n\n /**\n * Close a specific connection\n */\n abstract closeConnection(\n connectionId: string,\n code?: number,\n reason?: string,\n ): Promise<void>;\n}\n","import { $inject, createPrimitive, KIND, Primitive } from \"alepha\";\nimport type {\n EmitOptions,\n WebSocketPrimitiveOptions,\n} from \"../interfaces/WebSocketInterfaces.ts\";\nimport { WebSocketServerProvider } from \"../providers/WebSocketServerProvider.ts\";\nimport type { TWSObject } from \"./$channel.ts\";\n\n/**\n * Defines a WebSocket server endpoint for a specific channel.\n *\n * Server-side only. Creates a WebSocket endpoint that:\n * - Accepts connections from clients\n * - Validates incoming messages against the channel schema\n * - Provides room-based messaging\n * - Integrates with alepha/security for authentication (optional)\n * - Supports horizontal scaling via alepha/topic\n *\n * @example\n * ```typescript\n * class ChatController {\n * chat = $websocket({\n * channel: chatChannel,\n * handler: async ({ connectionId, userId, roomId, message, reply }) => {\n * // Broadcast to all in room except sender\n * await reply({\n * message: {\n * type: \"append\",\n * username: userId,\n * content: message.content\n * },\n * exceptSelf: true\n * });\n * }\n * });\n *\n * async broadcastAnnouncement(roomId: string, text: string) {\n * await this.chat.emit({\n * roomId,\n * message: {\n * type: \"append\",\n * username: \"System\",\n * content: text\n * }\n * });\n * }\n * }\n * ```\n */\nexport const $websocket = <\n TClient extends TWSObject,\n TServer extends TWSObject,\n>(\n options: WebSocketPrimitiveOptions<TClient, TServer>,\n): WebSocketPrimitive<TClient, TServer> => {\n return createPrimitive(WebSocketPrimitive<TClient, TServer>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class WebSocketPrimitive<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> extends Primitive<WebSocketPrimitiveOptions<TClient, TServer>> {\n protected readonly webSocketServerProvider = $inject(WebSocketServerProvider);\n\n protected onInit() {\n this.webSocketServerProvider.registerEndpoint(this.options);\n }\n\n /**\n * Emit message to clients\n *\n * Send messages from the server to connected clients based on targeting criteria.\n * Messages are distributed across all server instances via pub/sub.\n *\n * @example\n * ```typescript\n * // Send to specific room\n * await websocket.emit({\n * roomId: \"room-123\",\n * message: { type: \"update\", data: {...} }\n * });\n *\n * // Send to specific user (all their connections)\n * await websocket.emit({\n * userId: \"user-456\",\n * message: { type: \"notification\", text: \"Hello!\" }\n * });\n *\n * // Send to multiple rooms, except certain users\n * await websocket.emit({\n * roomIds: [\"room-1\", \"room-2\"],\n * exceptUserIds: [\"user-123\"],\n * message: { type: \"broadcast\", content: \"System announcement\" }\n * });\n * ```\n */\n public async emit(options: EmitOptions<TClient>): Promise<void> {\n await this.webSocketServerProvider.emit(\n this.options.channel.options.path,\n options,\n );\n }\n}\n\n$websocket[KIND] = WebSocketPrimitive;\n","import {\n $env,\n $inject,\n Alepha,\n AlephaError,\n SchemaValidator,\n type Static,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { ChannelPrimitive, TWSObject } from \"../primitives/$channel.ts\";\n\nconst envSchema = t.object({\n WEBSOCKET_URL: t.text({\n default: \"\",\n description:\n \"WebSocket server URL (e.g., ws://localhost:3001). Leave empty to auto-detect.\",\n }),\n WEBSOCKET_RECONNECT_INTERVAL: t.integer({\n default: 3000,\n description: \"Reconnection interval in milliseconds\",\n }),\n WEBSOCKET_MAX_RECONNECT_ATTEMPTS: t.integer({\n default: 10,\n description:\n \"Maximum number of reconnection attempts. Set to -1 for infinite.\",\n }),\n});\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Room subscription\n */\ninterface RoomSubscription<TClient extends TWSObject> {\n roomId: string;\n handler: (message: Static<TClient>) => void;\n}\n\n/**\n * WebSocket channel connection\n *\n * Manages a single WebSocket connection to a channel with multiple room subscriptions.\n * One connection can handle multiple rooms on the same channel.\n */\nexport class WebSocketChannelConnection<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n protected readonly alepha = $inject(Alepha);\n protected readonly schemaValidator = $inject(SchemaValidator);\n protected readonly log = $logger();\n protected ws?: WebSocket;\n protected reconnectAttempts = 0;\n protected reconnectTimer?: number;\n protected static readonly MAX_QUEUE_SIZE = 1000;\n protected messageQueue: Array<{ roomId: string; message: Static<TServer> }> =\n [];\n\n // Room subscriptions: Map<roomId, handler>\n protected subscriptions = new Map<\n string,\n (message: Static<TClient>) => void\n >();\n\n // Connection state\n public isConnected = false;\n public isConnecting = false;\n public isError = false;\n public error?: Error;\n protected connectPromise?: Promise<void>;\n\n // Connection callbacks\n protected onConnectCallbacks = new Set<() => void>();\n protected onDisconnectCallbacks = new Set<() => void>();\n protected onErrorCallbacks = new Set<(error: Error) => void>();\n\n constructor(\n protected readonly channel: ChannelPrimitive<TClient, TServer>,\n protected readonly options: {\n url?: string;\n autoReconnect?: boolean;\n reconnectInterval?: number;\n maxReconnectAttempts?: number;\n },\n protected readonly env: Static<typeof envSchema>,\n ) {}\n\n /**\n * Build WebSocket URL\n */\n protected buildUrl(): string {\n this.log.trace(\"Building WebSocket URL\", {\n hasCustomUrl: !!this.options.url,\n channelPath: this.channel.options.path,\n });\n\n if (this.options.url) {\n this.log.debug(\"Using custom WebSocket URL\", { url: this.options.url });\n return this.options.url;\n }\n\n // Auto-detect URL from current location (browser only)\n if (typeof window !== \"undefined\") {\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const host = window.location.host;\n const path = this.channel.options.path;\n // Send all room IDs as query params\n const roomIds = Array.from(this.subscriptions.keys());\n const roomParam =\n roomIds.length > 0 ? `?roomIds=${roomIds.join(\",\")}` : \"\";\n const url = `${protocol}//${host}${path}${roomParam}`;\n this.log.debug(\"Auto-detected WebSocket URL\", { url, roomIds });\n return url;\n }\n\n // Fallback to env URL\n const url = `${this.env.WEBSOCKET_URL}${this.channel.options.path}`;\n this.log.debug(\"Using env WebSocket URL\", { url });\n return url;\n }\n\n /**\n * Subscribe to a room on this channel\n */\n public subscribe(\n roomId: string,\n handler: (message: Static<TClient>) => void,\n callbacks?: {\n onConnect?: () => void;\n onDisconnect?: () => void;\n onError?: (error: Error) => void;\n },\n ): () => void {\n this.log.debug(\"Subscribing to room\", {\n roomId,\n channelPath: this.channel.options.path,\n existingSubscriptions: this.subscriptions.size,\n });\n\n // Add subscription\n this.subscriptions.set(roomId, handler);\n\n // Add callbacks\n if (callbacks?.onConnect) this.onConnectCallbacks.add(callbacks.onConnect);\n if (callbacks?.onDisconnect)\n this.onDisconnectCallbacks.add(callbacks.onDisconnect);\n if (callbacks?.onError) this.onErrorCallbacks.add(callbacks.onError);\n\n // Connect or reconnect to include the new room in the URL\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n this.log.trace(\"No active connection, initiating connect\");\n this.connect().catch((error) => {\n this.log.error(\"Failed to connect:\", error);\n });\n } else {\n this.log.trace(\"Reconnecting to include new room subscription\", {\n roomId,\n });\n this.reconnect();\n }\n\n // Return unsubscribe function\n return () => {\n this.log.debug(\"Unsubscribing from room\", { roomId });\n this.subscriptions.delete(roomId);\n if (callbacks?.onConnect)\n this.onConnectCallbacks.delete(callbacks.onConnect);\n if (callbacks?.onDisconnect)\n this.onDisconnectCallbacks.delete(callbacks.onDisconnect);\n if (callbacks?.onError) this.onErrorCallbacks.delete(callbacks.onError);\n\n // Disconnect if no more subscriptions\n if (this.subscriptions.size === 0) {\n this.log.debug(\"No more subscriptions, disconnecting\");\n this.disconnect();\n }\n };\n }\n\n /**\n * Connect to WebSocket server\n */\n protected async connect(): Promise<void> {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.log.trace(\"Already connected, skipping connect\");\n return;\n }\n\n if (this.connectPromise) {\n this.log.trace(\"Connection already in progress, reusing promise\");\n return this.connectPromise;\n }\n\n this.isConnecting = true;\n this.isError = false;\n this.error = undefined;\n\n const url = this.buildUrl();\n this.log.info(\"Connecting to WebSocket server\", { url });\n\n this.connectPromise = new Promise<void>((resolve, reject) => {\n try {\n const ws = new WebSocket(url);\n this.ws = ws;\n\n ws.onopen = () => {\n this.isConnected = true;\n this.isConnecting = false;\n this.isError = false;\n this.error = undefined;\n this.reconnectAttempts = 0;\n\n this.log.info(\"WebSocket connected\", {\n channelPath: this.channel.options.path,\n rooms: Array.from(this.subscriptions.keys()),\n });\n\n // Flush queued messages\n if (this.messageQueue.length > 0) {\n this.log.debug(\"Flushing queued messages\", {\n count: this.messageQueue.length,\n });\n }\n while (this.messageQueue.length > 0) {\n const msg = this.messageQueue.shift();\n if (msg) {\n this.log.trace(\"Sending queued message\", { roomId: msg.roomId });\n ws.send(\n JSON.stringify({\n roomId: msg.roomId,\n message: msg.message,\n }),\n );\n }\n }\n\n // Call all connect callbacks\n for (const callback of this.onConnectCallbacks) {\n callback();\n }\n\n resolve();\n };\n\n ws.onmessage = (event) => {\n this.log.trace(\"Message received\", {\n dataLength: event.data?.length,\n });\n this.handleMessage(event.data);\n };\n\n ws.onclose = (event) => {\n this.isConnected = false;\n this.isConnecting = false;\n this.ws = undefined;\n\n this.log.info(\"WebSocket disconnected\", {\n code: event.code,\n reason: event.reason,\n wasClean: event.wasClean,\n });\n\n // Call all disconnect callbacks\n for (const callback of this.onDisconnectCallbacks) {\n callback();\n }\n\n // Attempt reconnection\n if (this.options.autoReconnect !== false) {\n this.scheduleReconnect();\n }\n };\n\n ws.onerror = () => {\n const err = new Error(\"WebSocket connection error\");\n this.isError = true;\n this.error = err;\n this.isConnecting = false;\n\n this.log.error(\"WebSocket error\", { url });\n\n // Call all error callbacks\n for (const callback of this.onErrorCallbacks) {\n callback(err);\n }\n\n reject(err);\n };\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error(\"Connection failed\");\n this.isError = true;\n this.error = error;\n this.isConnecting = false;\n\n this.log.error(\"Failed to create WebSocket\", { error: error.message });\n\n // Call all error callbacks\n for (const callback of this.onErrorCallbacks) {\n callback(error);\n }\n\n reject(error);\n }\n }).finally(() => {\n this.connectPromise = undefined;\n });\n\n return this.connectPromise;\n }\n\n /**\n * Handle incoming message\n */\n protected handleMessage(data: string): void {\n try {\n const parsed = JSON.parse(data);\n this.log.trace(\"Parsed incoming message\", { parsed });\n\n // Validate incoming message against schema\n const inSchema = this.channel.options.schema.in;\n this.alepha.codec.validate(inSchema, parsed);\n\n this.log.debug(\"Dispatching message to handlers\", {\n handlerCount: this.subscriptions.size,\n });\n\n // Extract roomId from message if present (server should send it back)\n // For now, broadcast to all subscribed rooms\n // TODO: Server should include roomId in response\n for (const handler of this.subscriptions.values()) {\n handler(parsed as Static<TClient>);\n }\n } catch (err) {\n this.log.error(\"Error handling message:\", err);\n }\n }\n\n /**\n * Send message to a specific room\n */\n public async send(roomId: string, message: Static<TServer>): Promise<void> {\n this.log.trace(\"Sending message\", { roomId, message });\n\n // Validate outgoing message against schema\n const outSchema = this.channel.options.schema.out;\n try {\n this.schemaValidator.validate(outSchema, message, {\n trim: false,\n nullToUndefined: false,\n deleteUndefined: false,\n });\n } catch (err) {\n this.log.warn(\"Message validation failed\", { error: err });\n throw new AlephaError(\n `Message validation failed: ${(err as Error).message}`,\n );\n }\n\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n if (\n this.messageQueue.length >= WebSocketChannelConnection.MAX_QUEUE_SIZE\n ) {\n this.log.warn(\"Message queue full, dropping oldest message\", {\n roomId,\n queueSize: this.messageQueue.length,\n });\n this.messageQueue.shift();\n }\n this.log.debug(\"Connection not ready, queuing message\", {\n roomId,\n queueSize: this.messageQueue.length + 1,\n });\n this.messageQueue.push({ roomId, message });\n return;\n }\n\n this.log.debug(\"Sending message to server\", { roomId });\n this.ws.send(\n JSON.stringify({\n roomId,\n message,\n }),\n );\n }\n\n /**\n * Schedule reconnection\n */\n protected scheduleReconnect(): void {\n // Clear any pending reconnect timer\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n const maxAttempts =\n this.options.maxReconnectAttempts ??\n this.env.WEBSOCKET_MAX_RECONNECT_ATTEMPTS ??\n 10;\n const reconnectInterval =\n this.options.reconnectInterval ??\n this.env.WEBSOCKET_RECONNECT_INTERVAL ??\n 3000;\n\n if (maxAttempts !== -1 && this.reconnectAttempts >= maxAttempts) {\n this.log.warn(\"Max reconnection attempts reached\", {\n attempts: this.reconnectAttempts,\n maxAttempts,\n });\n return;\n }\n\n this.reconnectAttempts++;\n\n this.log.debug(\"Scheduling reconnection\", {\n attempt: this.reconnectAttempts,\n maxAttempts,\n intervalMs: reconnectInterval,\n });\n\n this.reconnectTimer = window.setTimeout(() => {\n this.log.info(\"Reconnecting...\", {\n attempt: this.reconnectAttempts,\n maxAttempts,\n });\n this.connect().catch((error) => {\n this.log.error(\"Reconnection failed:\", error);\n });\n }, reconnectInterval);\n }\n\n /**\n * Disconnect from server\n */\n public disconnect(): void {\n this.log.debug(\"Disconnecting\", {\n hasTimer: !!this.reconnectTimer,\n hasConnection: !!this.ws,\n });\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n if (this.ws) {\n this.ws.close();\n this.ws = undefined;\n }\n\n this.isConnected = false;\n this.isConnecting = false;\n this.connectPromise = undefined;\n\n this.log.info(\"Disconnected\");\n }\n\n /**\n * Reconnect manually\n */\n public reconnect(): void {\n this.log.info(\"Manual reconnect requested\");\n this.disconnect();\n this.connect().catch((error) => {\n this.log.error(\"Manual reconnection failed:\", error);\n });\n }\n\n /**\n * Check if subscribed to a room\n */\n public hasRoom(roomId: string): boolean {\n return this.subscriptions.has(roomId);\n }\n\n /**\n * Get all subscribed rooms\n */\n public getRooms(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n}\n\n/**\n * WebSocket Client Service\n *\n * Manages WebSocket connections from the client side (browser).\n * One connection per channel, multiple rooms per connection.\n */\nexport class WebSocketClient {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly env = $env(envSchema);\n\n // Map<channelPath, connection>\n protected connections = new Map<\n string,\n WebSocketChannelConnection<any, any>\n >();\n\n /**\n * Subscribe to a room on a channel\n */\n public subscribe<TClient extends TWSObject, TServer extends TWSObject>(\n roomId: string,\n channel: ChannelPrimitive<TClient, TServer>,\n handler: (message: Static<TClient>) => void,\n options: {\n url?: string;\n autoReconnect?: boolean;\n reconnectInterval?: number;\n maxReconnectAttempts?: number;\n onConnect?: () => void;\n onDisconnect?: () => void;\n onError?: (error: Error) => void;\n } = {},\n ): () => void {\n const channelPath = channel.options.path;\n\n this.log.debug(\"WebSocketClient.subscribe\", {\n roomId,\n channelPath,\n existingConnections: this.connections.size,\n });\n\n // Get or create connection for this channel\n let connection = this.connections.get(\n channelPath,\n ) as WebSocketChannelConnection<TClient, TServer>;\n\n if (!connection) {\n this.log.debug(\"Creating new connection for channel\", { channelPath });\n connection = this.alepha.inject(WebSocketChannelConnection, {\n lifetime: \"transient\",\n args: [\n channel,\n {\n url: options.url,\n autoReconnect: options.autoReconnect,\n reconnectInterval: options.reconnectInterval,\n maxReconnectAttempts: options.maxReconnectAttempts,\n },\n this.env,\n ],\n }) as WebSocketChannelConnection<any, any>;\n\n this.connections.set(channelPath, connection);\n } else {\n this.log.trace(\"Reusing existing connection for channel\", {\n channelPath,\n });\n }\n\n // Subscribe to the room on this connection\n const unsubscribe = connection.subscribe(roomId, handler, {\n onConnect: options.onConnect,\n onDisconnect: options.onDisconnect,\n onError: options.onError,\n });\n\n // Return unsubscribe function\n return () => {\n this.log.debug(\"WebSocketClient.unsubscribe\", { roomId, channelPath });\n unsubscribe();\n\n // Clean up connection if no more rooms\n if (connection.getRooms().length === 0) {\n this.log.debug(\"Removing connection for channel (no more rooms)\", {\n channelPath,\n });\n this.connections.delete(channelPath);\n }\n };\n }\n\n /**\n * Send message to a room on a channel\n */\n public async send<TClient extends TWSObject, TServer extends TWSObject>(\n roomId: string,\n channel: ChannelPrimitive<TClient, TServer>,\n message: Static<TServer>,\n ): Promise<void> {\n const channelPath = channel.options.path;\n\n this.log.trace(\"WebSocketClient.send\", { roomId, channelPath });\n\n const connection = this.connections.get(\n channelPath,\n ) as WebSocketChannelConnection<TClient, TServer>;\n\n if (!connection) {\n this.log.warn(\"Attempted to send on unsubscribed channel\", {\n channelPath,\n });\n throw new AlephaError(\n `Not subscribed to channel ${channelPath}. Subscribe first before sending messages.`,\n );\n }\n\n await connection.send(roomId, message);\n }\n\n /**\n * Get connection for a channel\n */\n public getConnection<TClient extends TWSObject, TServer extends TWSObject>(\n channel: ChannelPrimitive<TClient, TServer>,\n ): WebSocketChannelConnection<TClient, TServer> | undefined {\n const channelPath = channel.options.path;\n const connection = this.connections.get(channelPath) as\n | WebSocketChannelConnection<TClient, TServer>\n | undefined;\n\n this.log.trace(\"WebSocketClient.getConnection\", {\n channelPath,\n found: !!connection,\n });\n\n return connection;\n }\n\n /**\n * Disconnect all connections\n */\n public disconnectAll(): void {\n this.log.info(\"Disconnecting all connections\", {\n count: this.connections.size,\n });\n\n for (const connection of this.connections.values()) {\n connection.disconnect();\n }\n this.connections.clear();\n\n this.log.debug(\"All connections disconnected\");\n }\n}\n","import { AlephaError } from \"alepha\";\n\n/**\n * Base WebSocket error class\n */\nexport class WebSocketError extends AlephaError {\n constructor(\n message: string,\n public readonly code?: number,\n ) {\n super(message);\n this.name = \"WebSocketError\";\n }\n}\n\n/**\n * Error thrown when WebSocket connection fails\n */\nexport class WebSocketConnectionError extends WebSocketError {\n constructor(message: string, code?: number) {\n super(message, code);\n this.name = \"WebSocketConnectionError\";\n }\n}\n\n/**\n * Error thrown when WebSocket message validation fails\n */\nexport class WebSocketValidationError extends WebSocketError {\n constructor(message: string) {\n super(message);\n this.name = \"WebSocketValidationError\";\n }\n}\n","import type { Static } from \"alepha\";\nimport type { ChannelPrimitive, TWSObject } from \"../primitives/$channel.ts\";\n\n/**\n * WebSocket connection interface\n */\nexport interface WebSocketConnection {\n /**\n * Unique connection ID\n */\n id: string;\n\n /**\n * User ID (if authenticated and security module is used)\n */\n userId?: string;\n\n /**\n * Channel path this connection belongs to\n */\n channelPath: string;\n\n /**\n * Room IDs that this connection is currently in\n */\n roomIds: string[];\n\n /**\n * Send a message to this connection\n */\n send(message: any): Promise<void>;\n\n /**\n * Close this connection\n */\n close(code?: number, reason?: string): Promise<void>;\n\n /**\n * Connection metadata (custom data)\n */\n metadata?: Record<string, any>;\n\n /**\n * Connection state\n */\n readyState: WebSocketState;\n}\n\n/**\n * WebSocket state enum\n */\nexport enum WebSocketState {\n CONNECTING = 0,\n OPEN = 1,\n CLOSING = 2,\n CLOSED = 3,\n}\n\n/**\n * WebSocket endpoint configuration (server-side)\n */\nexport interface WebSocketPrimitiveOptions<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n /**\n * Channel definition with schema and path\n */\n channel: ChannelPrimitive<TClient, TServer>;\n\n /**\n * Handler for incoming messages from clients\n */\n handler: WebSocketHandler<TClient, TServer>;\n\n /**\n * Optional connection handler (called when a client connects)\n */\n onConnect?: (params: {\n /**\n * Unique connection ID of the client\n */\n connectionId: string;\n\n /**\n * User ID of the connected client (if authenticated and security module is used)\n */\n userId?: string;\n\n /**\n * Room IDs that the client is connecting to\n */\n roomIds: string[];\n }) => Promise<void> | void;\n\n /**\n * Optional disconnection handler (called when a client disconnects)\n */\n onDisconnect?: (params: {\n /**\n * Unique connection ID of the client\n */\n connectionId: string;\n\n /**\n * User ID of the connected client (if authenticated and security module is used)\n */\n userId?: string;\n\n /**\n * Room IDs that the client was connected to\n */\n roomIds: string[];\n }) => Promise<void> | void;\n\n /**\n * Change WebSocket server provider (for custom implementations)\n */\n provider?: any;\n\n /**\n * Whether to enforce security (authentication, authorization) on this WebSocket endpoint\n * Requires alepha/security integration\n */\n secure?: boolean;\n\n /**\n * Limit number of connections per user (if authenticated)\n */\n maxConnectionsPerUser?: number;\n}\n\n/**\n * WebSocket message handler\n */\nexport type WebSocketHandler<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> = (\n context: WebSocketHandlerContext<TClient, TServer>,\n) => Promise<void> | void;\n\n/**\n * WebSocket handler context\n */\nexport interface WebSocketHandlerContext<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n /**\n * Unique connection ID of the client\n */\n connectionId: string;\n\n /**\n * User ID of the connected client (if authenticated and security module is used)\n */\n userId?: string;\n\n /**\n * Room ID that the client sent the message from\n */\n roomId: string;\n\n /**\n * The parsed and validated message from the client\n */\n message: Static<TServer>;\n\n /**\n * Reply function tailored to current context (connectionId, roomId)\n */\n reply: (options: {\n /**\n * Message to send\n */\n message: Static<TClient>;\n\n /**\n * Optional: specify room ID to send to (defaults to sender's room ID)\n */\n roomId?: string;\n\n /**\n * Optional: exclude the sender connection from receiving the message\n * Will populate exceptConnectionIds with sender connection ID behind the scenes\n */\n exceptSelf?: boolean;\n\n /**\n * Optional: exclude specific connection IDs from receiving the message\n */\n exceptConnectionIds?: string[];\n\n /**\n * Optional: exclude specific user IDs from receiving the message\n * Requires alepha/security integration\n */\n exceptUserIds?: string[];\n }) => Promise<void>;\n}\n\n/**\n * Emit options for sending messages from the server\n */\nexport interface EmitOptions<TClient extends TWSObject> {\n /**\n * Message to send to clients\n */\n message: Static<TClient>;\n\n /**\n * Room ID to send the message to\n */\n roomId?: string;\n\n /**\n * Room IDs to send the message to\n */\n roomIds?: string[];\n\n /**\n * User ID to send the message to (if authenticated)\n */\n userId?: string;\n\n /**\n * User IDs to send the message to (if authenticated)\n */\n userIds?: string[];\n\n /**\n * Connection ID to send the message to\n */\n connectionId?: string;\n\n /**\n * Connection IDs to send the message to\n */\n connectionIds?: string[];\n\n /**\n * Optional: exclude specific connection IDs from receiving the message\n */\n exceptConnectionIds?: string[];\n\n /**\n * Optional: exclude specific user IDs from receiving the message\n * Requires alepha/security integration\n */\n exceptUserIds?: string[];\n}\n","import { $logger } from \"alepha/logger\";\n\n/**\n * Manages WebSocket room memberships\n *\n * Rooms are logical groupings of connections. A connection can be in multiple rooms,\n * and messages can be targeted to specific rooms.\n */\nexport class RoomManager {\n protected readonly log = $logger();\n\n /**\n * Maps roomId → Set<connectionId>\n */\n protected readonly rooms = new Map<string, Set<string>>();\n\n /**\n * Maps connectionId → Set<roomId>\n * Inverse index for fast lookup of connection's rooms\n */\n protected readonly connectionRooms = new Map<string, Set<string>>();\n\n /**\n * Join a connection to one or more rooms\n */\n public joinRooms(connectionId: string, roomIds: string[]): void {\n for (const roomId of roomIds) {\n this.joinRoom(connectionId, roomId);\n }\n }\n\n /**\n * Join a connection to a room\n */\n public joinRoom(connectionId: string, roomId: string): void {\n // Add to room\n let room = this.rooms.get(roomId);\n if (!room) {\n room = new Set();\n this.rooms.set(roomId, room);\n }\n room.add(connectionId);\n\n // Update inverse index\n let connRooms = this.connectionRooms.get(connectionId);\n if (!connRooms) {\n connRooms = new Set();\n this.connectionRooms.set(connectionId, connRooms);\n }\n connRooms.add(roomId);\n\n this.log.debug(`Connection ${connectionId} joined room ${roomId}`);\n }\n\n /**\n * Leave a connection from a room\n */\n public leaveRoom(connectionId: string, roomId: string): void {\n // Remove from room\n const room = this.rooms.get(roomId);\n if (room) {\n room.delete(connectionId);\n if (room.size === 0) {\n this.rooms.delete(roomId);\n }\n }\n\n // Update inverse index\n const connRooms = this.connectionRooms.get(connectionId);\n if (connRooms) {\n connRooms.delete(roomId);\n if (connRooms.size === 0) {\n this.connectionRooms.delete(connectionId);\n }\n }\n\n this.log.debug(`Connection ${connectionId} left room ${roomId}`);\n }\n\n /**\n * Remove a connection from all rooms\n */\n public leaveAllRooms(connectionId: string): void {\n const connRooms = this.connectionRooms.get(connectionId);\n if (!connRooms) {\n return;\n }\n\n for (const roomId of connRooms) {\n const room = this.rooms.get(roomId);\n if (room) {\n room.delete(connectionId);\n if (room.size === 0) {\n this.rooms.delete(roomId);\n }\n }\n }\n\n this.connectionRooms.delete(connectionId);\n this.log.debug(`Connection ${connectionId} left all rooms`);\n }\n\n /**\n * Get all connection IDs in a room\n */\n public getRoomConnections(roomId: string): string[] {\n const room = this.rooms.get(roomId);\n return room ? Array.from(room) : [];\n }\n\n /**\n * Get all room IDs for a connection\n */\n public getConnectionRooms(connectionId: string): string[] {\n const connRooms = this.connectionRooms.get(connectionId);\n return connRooms ? Array.from(connRooms) : [];\n }\n\n /**\n * Check if a connection is in a room\n */\n public isInRoom(connectionId: string, roomId: string): boolean {\n const connRooms = this.connectionRooms.get(connectionId);\n return connRooms ? connRooms.has(roomId) : false;\n }\n\n /**\n * Get all active rooms\n */\n public getAllRooms(): string[] {\n return Array.from(this.rooms.keys());\n }\n\n /**\n * Get total number of connections across all rooms\n */\n public getTotalConnections(): number {\n return this.connectionRooms.size;\n }\n\n /**\n * Get room statistics\n */\n public getStats(): {\n totalRooms: number;\n totalConnections: number;\n roomSizes: Map<string, number>;\n } {\n const roomSizes = new Map<string, number>();\n for (const [roomId, connections] of this.rooms) {\n roomSizes.set(roomId, connections.size);\n }\n\n return {\n totalRooms: this.rooms.size,\n totalConnections: this.connectionRooms.size,\n roomSizes,\n };\n }\n}\n","import { type Static, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $topic } from \"alepha/topic\";\n\n/**\n * WebSocket message distribution event\n */\nconst webSocketMessageSchema = {\n payload: t.object({\n /**\n * Channel path (e.g., \"/ws/chat\")\n */\n channelPath: t.text(),\n\n /**\n * Target room ID(s)\n */\n roomIds: t.optional(t.array(t.text())),\n\n /**\n * Target user ID(s)\n */\n userIds: t.optional(t.array(t.text())),\n\n /**\n * Target connection ID(s)\n */\n connectionIds: t.optional(t.array(t.text())),\n\n /**\n * Exclude connection ID(s) from receiving the message\n */\n exceptConnectionIds: t.optional(t.array(t.text())),\n\n /**\n * Exclude user ID(s) from receiving the message\n */\n exceptUserIds: t.optional(t.array(t.text())),\n\n /**\n * The message payload to send\n */\n message: t.any(),\n }),\n};\n\n/**\n * WebSocket Topic Service\n *\n * Manages pub/sub messaging for WebSocket connections across multiple server instances.\n * Uses alepha/topic for cross-instance message distribution, enabling horizontal scaling.\n *\n * When a WebSocket message needs to be sent:\n * 1. Server instance A publishes to the topic\n * 2. All server instances (A, B, C, etc.) receive the message\n * 3. Each instance sends to its local connections that match the criteria\n *\n * This enables:\n * - Multiple server instances handling WebSocket connections\n * - Redis-backed message distribution (with alepha/topic/redis)\n * - Horizontal scaling without losing messages\n */\nexport class WebSocketTopicService {\n protected readonly log = $logger();\n\n /**\n * Handler function to be called when a message is received from the topic\n * This is set by the WebSocket provider during initialization\n */\n public messageHandler?: (\n event: Static<(typeof webSocketMessageSchema)[\"payload\"]>,\n ) => Promise<void>;\n\n /**\n * Topic for distributing WebSocket messages across server instances\n */\n public readonly topic = $topic({\n name: \"websocket:broadcast\",\n description:\n \"Distributes WebSocket messages across server instances for horizontal scaling\",\n schema: webSocketMessageSchema,\n handler: async (message) => {\n if (this.messageHandler) {\n await this.messageHandler(message.payload);\n }\n },\n });\n\n /**\n * Publish a message to be distributed across all server instances\n */\n public async publish(\n event: Static<(typeof webSocketMessageSchema)[\"payload\"]>,\n ): Promise<void> {\n await this.topic.publish(event);\n }\n\n /**\n * Set the handler for incoming messages\n */\n public setMessageHandler(\n handler: (\n event: Static<(typeof webSocketMessageSchema)[\"payload\"]>,\n ) => Promise<void>,\n ): void {\n this.messageHandler = handler;\n }\n}\n","import { $module, type Alepha } from \"alepha\";\nimport { AlephaTopic } from \"alepha/topic\";\nimport { $channel } from \"./primitives/$channel.ts\";\nimport { $websocket } from \"./primitives/$websocket.ts\";\nimport { WebSocketClient } from \"./services/WebSocketClient.ts\";\n\n/**\n * alepha/websocket (Browser)\n *\n * Browser-side WebSocket client module. Provides WebSocketClient service\n * for managing WebSocket connections from the browser.\n *\n * For React applications, use alepha/react/websocket with the useRoom hook.\n */\nexport * from \"./index.shared.ts\";\n\nexport const AlephaWebSocket = $module({\n name: \"alepha.websocket\",\n primitives: [$channel, $websocket],\n services: [WebSocketClient],\n register: (alepha: Alepha) => {\n alepha.with(AlephaTopic);\n alepha.with(WebSocketClient);\n },\n});\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import * as _$alepha from "alepha";
2
- import { Alepha, AlephaError, KIND, Primitive, Static, TObject, TString, TUnion } from "alepha";
2
+ import { Alepha, AlephaError, KIND, Primitive, SchemaValidator, Static, TObject, TString, TUnion } from "alepha";
3
3
  import * as _$alepha_topic0 from "alepha/topic";
4
4
  import * as _$alepha_logger0 from "alepha/logger";
5
5
  import { WebSocket as WebSocket$1, WebSocketServer } from "ws";
@@ -537,6 +537,7 @@ declare class WebSocketChannelConnection<TClient extends TWSObject, TServer exte
537
537
  };
538
538
  protected readonly env: Static<typeof envSchema>;
539
539
  protected readonly alepha: Alepha;
540
+ protected readonly schemaValidator: SchemaValidator;
540
541
  protected readonly log: _$alepha_logger0.Logger;
541
542
  protected ws?: WebSocket;
542
543
  protected reconnectAttempts: number;
@@ -809,6 +810,7 @@ declare class NodeWebSocketConnection implements WebSocketConnection {
809
810
  protected readonly provider: NodeWebSocketServerProvider;
810
811
  protected readonly endpoint: WebSocketPrimitiveOptions<any, any>;
811
812
  protected readonly log: _$alepha_logger0.Logger;
813
+ protected readonly schemaValidator: SchemaValidator;
812
814
  metadata?: Record<string, any>;
813
815
  constructor(id: string, userId: string | undefined, roomIds: string[], ws: WebSocket$1, provider: NodeWebSocketServerProvider, endpoint: WebSocketPrimitiveOptions<any, any>);
814
816
  get channelPath(): string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/websocket/errors/WebSocketError.ts","../../src/websocket/primitives/$channel.ts","../../src/websocket/interfaces/WebSocketInterfaces.ts","../../src/websocket/providers/WebSocketServerProvider.ts","../../src/websocket/primitives/$websocket.ts","../../src/websocket/services/RoomManager.ts","../../src/websocket/services/WebSocketClient.ts","../../src/websocket/services/WebSocketTopicService.ts","../../src/websocket/providers/NodeWebSocketServerProvider.ts","../../src/websocket/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/websocket/errors/WebSocketError.ts","../../src/websocket/primitives/$channel.ts","../../src/websocket/interfaces/WebSocketInterfaces.ts","../../src/websocket/providers/WebSocketServerProvider.ts","../../src/websocket/primitives/$websocket.ts","../../src/websocket/services/RoomManager.ts","../../src/websocket/services/WebSocketClient.ts","../../src/websocket/services/WebSocketTopicService.ts","../../src/websocket/providers/NodeWebSocketServerProvider.ts","../../src/websocket/index.ts"],"mappings":"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"}