cabloy 5.1.59 → 5.1.61

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 (149) hide show
  1. package/.claude/hooks/contract-loop-gate.ts +296 -0
  2. package/.claude/settings.json +16 -0
  3. package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +1 -0
  4. package/.claude/skills/cabloy-contract-loop/SKILL.md +103 -14
  5. package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +126 -12
  6. package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +148 -0
  7. package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +49 -13
  8. package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +11 -0
  9. package/.claude/skills/cabloy-frontend-scaffold/references/follow-up-checklist.md +2 -0
  10. package/.claude/skills/cabloy-module-removal/SKILL.md +144 -0
  11. package/.claude/skills/cabloy-resource-field-update/SKILL.md +274 -0
  12. package/.claude/skills/cabloy-resource-field-update/evals/evals.json +53 -0
  13. package/.claude/skills/cabloy-resource-field-update/references/custom-renderer-demo-checklist.md +102 -0
  14. package/.claude/skills/cabloy-resource-field-update/references/field-update-decision-tree.md +120 -0
  15. package/.claude/skills/cabloy-resource-field-update/references/follow-up-checklist.md +80 -0
  16. package/.claude/skills/cabloy-resource-field-update/references/verification-checklist.md +97 -0
  17. package/.claude/skills/cabloy-zova-source-reading/SKILL.md +221 -0
  18. package/.claude/skills/cabloy-zova-source-reading/references/analysis-modes.md +91 -0
  19. package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +117 -0
  20. package/.github/workflows/docs-pages.yml +2 -0
  21. package/.github/workflows/vona-cov-pg.yml +2 -0
  22. package/.github/workflows/vona-test-crud.yml +4 -2
  23. package/.github/workflows/vona-test-mysql.yml +2 -0
  24. package/.github/workflows/vona-test-pg.yml +2 -0
  25. package/.github/workflows/vona-test-sqlite3.yml +2 -0
  26. package/.github/workflows/vona-tsc.yml +2 -0
  27. package/.github/workflows/zova-ui.yml +2 -0
  28. package/.gitignore +0 -4
  29. package/CHANGELOG.md +52 -0
  30. package/CLAUDE.md +12 -0
  31. package/README.md +15 -0
  32. package/cabloy-docs/.vitepress/config.mjs +89 -0
  33. package/cabloy-docs/ai/class-placement-rule.md +2 -0
  34. package/cabloy-docs/ai/cli-to-skill-map.md +14 -0
  35. package/cabloy-docs/ai/docs-skills-rules-mapping.md +14 -0
  36. package/cabloy-docs/ai/future-skill-roadmap.md +27 -9
  37. package/cabloy-docs/ai/introduction.md +1 -0
  38. package/cabloy-docs/ai/playbook-backend-module.md +6 -0
  39. package/cabloy-docs/ai/playbook-module-removal.md +164 -0
  40. package/cabloy-docs/ai/skills.md +11 -0
  41. package/cabloy-docs/backend/bean-scene-authoring.md +350 -0
  42. package/cabloy-docs/backend/cli.md +26 -1
  43. package/cabloy-docs/backend/dto-guide.md +6 -0
  44. package/cabloy-docs/backend/entity-guide.md +18 -0
  45. package/cabloy-docs/backend/foundation.md +28 -3
  46. package/cabloy-docs/backend/introduction.md +10 -0
  47. package/cabloy-docs/backend/serialization-guide.md +10 -0
  48. package/cabloy-docs/backend/service-guide.md +2 -0
  49. package/cabloy-docs/backend/status-guide.md +271 -0
  50. package/cabloy-docs/backend/websocket-call-flow.md +435 -0
  51. package/cabloy-docs/backend/websocket-guide.md +455 -0
  52. package/cabloy-docs/backend/websocket-protocol-guide.md +381 -0
  53. package/cabloy-docs/backend/websocket-usage-guide.md +356 -0
  54. package/cabloy-docs/frontend/api-guide.md +2 -0
  55. package/cabloy-docs/frontend/bean-scene-authoring.md +374 -0
  56. package/cabloy-docs/frontend/behavior-guide.md +449 -0
  57. package/cabloy-docs/frontend/cli.md +24 -0
  58. package/cabloy-docs/frontend/command-scene-authoring.md +495 -0
  59. package/cabloy-docs/frontend/design-principles.md +6 -0
  60. package/cabloy-docs/frontend/fetch-interceptor-guide.md +440 -0
  61. package/cabloy-docs/frontend/form-guide.md +795 -0
  62. package/cabloy-docs/frontend/foundation.md +29 -0
  63. package/cabloy-docs/frontend/introduction.md +17 -1
  64. package/cabloy-docs/frontend/ioc-and-beans.md +16 -9
  65. package/cabloy-docs/frontend/mock-guide.md +1 -0
  66. package/cabloy-docs/frontend/model-architecture.md +252 -39
  67. package/cabloy-docs/frontend/model-resource-best-practices.md +379 -0
  68. package/cabloy-docs/frontend/model-resource-cookbook.md +505 -0
  69. package/cabloy-docs/frontend/model-resource-owner-pattern.md +382 -0
  70. package/cabloy-docs/frontend/model-resource-usage-guide.md +318 -0
  71. package/cabloy-docs/frontend/model-state-guide.md +366 -13
  72. package/cabloy-docs/frontend/openapi-sdk-guide.md +5 -2
  73. package/cabloy-docs/frontend/page-guide.md +6 -0
  74. package/cabloy-docs/frontend/quickstart.md +4 -0
  75. package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +266 -0
  76. package/cabloy-docs/frontend/router-tabs-admin-web-comparison.md +206 -0
  77. package/cabloy-docs/frontend/router-tabs-introduction.md +106 -0
  78. package/cabloy-docs/frontend/router-tabs-mechanism.md +469 -0
  79. package/cabloy-docs/frontend/router-tabs-overview.md +227 -0
  80. package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +343 -0
  81. package/cabloy-docs/frontend/server-data.md +2 -0
  82. package/cabloy-docs/frontend/ssr-architecture-overview.md +211 -0
  83. package/cabloy-docs/frontend/ssr-build-deploy-guide.md +308 -0
  84. package/cabloy-docs/frontend/ssr-review-checklist.md +184 -0
  85. package/cabloy-docs/frontend/ssr-troubleshooting-guide.md +301 -0
  86. package/cabloy-docs/frontend/zova-form-source-reading-map.md +295 -0
  87. package/cabloy-docs/frontend/zova-form-under-the-hood.md +556 -0
  88. package/cabloy-docs/frontend/zova-reactivity-under-the-hood.md +320 -0
  89. package/cabloy-docs/frontend/zova-source-reading-map.md +327 -0
  90. package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +308 -0
  91. package/cabloy-docs/fullstack/contract-loop-playbook.md +350 -0
  92. package/cabloy-docs/fullstack/framework-performance.md +3 -3
  93. package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +44 -1
  94. package/cabloy-docs/fullstack/introduction.md +40 -0
  95. package/cabloy-docs/fullstack/openapi-to-sdk.md +19 -9
  96. package/cabloy-docs/fullstack/quickstart.md +7 -1
  97. package/cabloy-docs/fullstack/tutorial-1-first-module.md +111 -0
  98. package/cabloy-docs/fullstack/tutorial-2-first-crud.md +122 -0
  99. package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +131 -0
  100. package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +144 -0
  101. package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +146 -0
  102. package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +170 -0
  103. package/cabloy-docs/fullstack/tutorials-overview.md +192 -0
  104. package/cabloy-docs/index.md +4 -3
  105. package/cabloy-docs/reference/bean-scene-boilerplates.md +75 -0
  106. package/cabloy-docs/reference/cli-reference.md +2 -0
  107. package/package.json +7 -2
  108. package/scripts/initTestData.ts +25 -0
  109. package/scripts/upgrade.ts +17 -2
  110. package/vona/packages-cli/cabloy-cli/package.json +2 -2
  111. package/vona/packages-cli/cli/package.json +1 -1
  112. package/vona/packages-cli/cli-set-api/package.json +1 -1
  113. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.create.module.ts +4 -0
  114. package/vona/packages-vona/vona/package.json +1 -1
  115. package/vona/pnpm-lock.yaml +226 -1091
  116. package/vona/pnpm-workspace.yaml +0 -1
  117. package/vona/src/suite-vendor/a-vona/modules/a-core/assets/static/img/vona.svg +1 -1
  118. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
  119. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  120. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +1 -1
  121. package/vona/src/suite-vendor/a-vona/modules/a-upload/package.json +2 -2
  122. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  123. package/zova/package.original.json +1 -1
  124. package/zova/packages-cli/cli/package.json +3 -3
  125. package/zova/packages-cli/cli-set-front/cli/templates/init/icon/boilerplate/icons/default/zova.svg +1 -1
  126. package/zova/packages-cli/cli-set-front/cli/templates/openapi/config/boilerplate/module/openapi.config.ts +6 -1
  127. package/zova/packages-cli/cli-set-front/package.json +3 -3
  128. package/zova/packages-cli/cli-set-front/src/lib/bean/cli.create.module.ts +4 -0
  129. package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +34 -4
  130. package/zova/packages-cli/cli-set-front/src/lib/command/create.bean.ts +5 -1
  131. package/zova/packages-utils/zova-vite/package.json +2 -2
  132. package/zova/packages-zova/zova/package.json +2 -2
  133. package/zova/pnpm-lock.yaml +282 -1311
  134. package/zova/pnpm-workspace.yaml +0 -1
  135. package/zova/src/suite/a-home/modules/home-icon/icons/social/cabloy.svg +1 -1
  136. package/zova/src/suite/a-home/modules/home-icon/icons/social/vona.svg +1 -1
  137. package/zova/src/suite/a-home/modules/home-icon/icons/social/zova.svg +1 -1
  138. package/zova/src/suite/a-home/modules/home-icon/src/.metadata/icons/groups/social.svg +3 -3
  139. package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +9 -0
  140. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  141. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +66 -16
  142. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  143. package/zova/src/suite-vendor/a-zova/modules/a-routertabs/package.json +1 -1
  144. package/zova/src/suite-vendor/a-zova/modules/a-routertabs/src/model/tabs.ts +60 -18
  145. package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableActionRow/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
  146. package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableCell/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
  147. package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
  148. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  149. package/zova/src/suite-vendor/a-zova/package.json +4 -4
@@ -0,0 +1,455 @@
1
+ # Web Socket Guide
2
+
3
+ This guide explains how Web Socket support works in Vona within the Cabloy monorepo.
4
+
5
+ Read this together with:
6
+
7
+ - [Web Socket Usage Guide](/backend/websocket-usage-guide)
8
+ - [Web Socket Protocol Guide](/backend/websocket-protocol-guide)
9
+ - [Web Socket Call Flow](/backend/websocket-call-flow)
10
+
11
+ Use the practical split:
12
+
13
+ - this page for the architecture overview
14
+ - [Web Socket Usage Guide](/backend/websocket-usage-guide) for server-side authoring patterns
15
+ - [Web Socket Protocol Guide](/backend/websocket-protocol-guide) for the client-visible wire format
16
+ - [Web Socket Call Flow](/backend/websocket-call-flow) for source tracing and debugging
17
+
18
+ ## Why Web Socket support matters
19
+
20
+ Vona provides a framework-native Web Socket runtime so backend modules can keep long-lived connections, push server-side events, and route request-like actions over a persistent channel.
21
+
22
+ That matters because some backend workflows are not well expressed as one HTTP request followed by one HTTP response. They need:
23
+
24
+ - server-initiated delivery
25
+ - namespace-scoped signaling
26
+ - connection-aware authentication and lifecycle control
27
+ - extension hooks that other modules can reuse without replacing the transport layer
28
+
29
+ ## The `a-socket` module role
30
+
31
+ The built-in Web Socket runtime lives in `a-socket`.
32
+
33
+ At the module level, `a-socket` contributes three onion families:
34
+
35
+ - `socketNamespace`
36
+ - `socketConnection`
37
+ - `socketPacket`
38
+
39
+ A practical split is:
40
+
41
+ - use **socket namespace** beans to define namespace-scoped send and broadcast APIs
42
+ - use **socket connection** onions to control connection-time lifecycle behavior
43
+ - use **socket packet** onions to process inbound Web Socket messages
44
+
45
+ The module also enables the monkey lifecycle capability so Web Socket startup and shutdown can attach to the backend runtime automatically.
46
+
47
+ ## Runtime entry and lifecycle
48
+
49
+ The runtime entry is straightforward:
50
+
51
+ - `src/monkey.ts` forwards `appReady()` and `appClose()` to `service.socket`
52
+ - `src/service/socket.ts` creates the `WebSocketServer` when the app server is ready
53
+ - on shutdown, the Web Socket server is closed and tracked clients are terminated
54
+
55
+ Representative shape:
56
+
57
+ ```typescript
58
+ export class Monkey extends BeanSimple implements IMonkeyAppReady, IMonkeyAppClose {
59
+ async appReady() {
60
+ await this.app.scope(__ThisModule__).service.socket.appReady();
61
+ }
62
+
63
+ async appClose() {
64
+ await this.app.scope(__ThisModule__).service.socket.appClose();
65
+ }
66
+ }
67
+ ```
68
+
69
+ This keeps the Web Socket transport aligned with ordinary backend startup instead of requiring a separate manual bootstrap path.
70
+
71
+ ## Connection entry flow
72
+
73
+ The main connection flow is implemented in `src/service/socket.ts`.
74
+
75
+ A practical reading order is:
76
+
77
+ 1. create `WebSocketServer` from `app.server`
78
+ 2. accept a `connection`
79
+ 3. parse request URL and query values
80
+ 4. create a request-scoped backend context
81
+ 5. assign Web Socket metadata such as `id` and `namespace`
82
+ 6. register the client in the socket registry
83
+ 7. execute the `socketConnection` onion chain with `enter`
84
+ 8. install `close`, `message`, and `error` handlers
85
+ 9. send the `sysReady` system event
86
+
87
+ The connection context carries useful protocol values from query parameters, including:
88
+
89
+ - passport code
90
+ - instance name
91
+ - locale
92
+ - timezone
93
+
94
+ Those keys come from the module config.
95
+
96
+ Representative config shape:
97
+
98
+ ```typescript
99
+ return {
100
+ eventPrefix: '_:',
101
+ globalPrefix: '/ws',
102
+ queryKey: {
103
+ passportCode: $protocolKey('x-vona-passport-code'),
104
+ instanceName: $protocolKey('x-vona-instance-name'),
105
+ locale: $protocolKey('x-vona-locale'),
106
+ tz: $protocolKey('x-vona-tz'),
107
+ },
108
+ timeout: {
109
+ ping: 20000,
110
+ },
111
+ };
112
+ ```
113
+
114
+ ## Namespace routing
115
+
116
+ `a-socket` derives the logical namespace from the request path.
117
+
118
+ The default global prefix is:
119
+
120
+ - `/ws`
121
+
122
+ A useful mental model is:
123
+
124
+ - `/ws` maps to the root namespace `/`
125
+ - `/ws/ssrhmr` maps to the namespace `/ssrhmr`
126
+
127
+ This happens through `ServiceSocket.getNamespace()`, which strips the global prefix from `ctx.path` and falls back to `/` when no additional path segment remains.
128
+
129
+ That means the URL path is not only a transport detail. It becomes the namespace identity used by namespace beans and namespace-scoped broadcasts.
130
+
131
+ ## Client registry and connection tracking
132
+
133
+ Connected clients are tracked by `src/bean/bean.socket.ts`.
134
+
135
+ The registry keeps two coordinated views:
136
+
137
+ - client id -> `WebSocket`
138
+ - namespace -> array of client ids
139
+
140
+ This supports:
141
+
142
+ - direct send by client id
143
+ - namespace broadcast
144
+ - cleanup on disconnect
145
+ - full termination on app shutdown or bean disposal
146
+
147
+ That registry is the bridge between transport-level sockets and higher-level namespace delivery.
148
+
149
+ ## Built-in connection onion chain
150
+
151
+ The connection pipeline is built from `socketConnection` onions. The built-in chain executes in this order:
152
+
153
+ 1. `alive`
154
+ 2. `app`
155
+ 3. `instance`
156
+ 4. `cors`
157
+ 5. `event`
158
+ 6. `passport`
159
+ 7. `ready`
160
+
161
+ Each stage has a focused responsibility.
162
+
163
+ ### `alive`
164
+
165
+ The `alive` stage sets up heartbeat tracking.
166
+
167
+ It:
168
+
169
+ - marks each new socket as alive
170
+ - listens for `pong`
171
+ - runs a periodic interval
172
+ - terminates stale sockets that stop responding
173
+
174
+ The interval uses the module `timeout.ping` config value.
175
+
176
+ ### `app`
177
+
178
+ The `app` stage checks runtime readiness.
179
+
180
+ For ordinary external access, it prevents new connections when:
181
+
182
+ - the app is already closing, or
183
+ - the instance service reports that the app is not ready yet
184
+
185
+ This keeps Web Socket traffic aligned with the same backend readiness expectations as other runtime entry paths.
186
+
187
+ ### `instance`
188
+
189
+ The `instance` stage initializes the effective instance before the connection proceeds.
190
+
191
+ This is important in multi-instance deployments because Web Socket work should resolve against the same backend instance model as the rest of the framework.
192
+
193
+ Read this together with [Multi-Instance and Instance Resolution](/backend/multi-instance-and-instance-resolution).
194
+
195
+ ### `cors`
196
+
197
+ The `cors` stage validates the request origin.
198
+
199
+ If origin checking fails, the socket is terminated immediately.
200
+
201
+ That means Web Socket origin validation is part of the built-in connection chain rather than a separate ad hoc check.
202
+
203
+ ### `event`
204
+
205
+ The `event` stage adds the transport send helper:
206
+
207
+ - `ws.sendEvent(...)`
208
+
209
+ This method:
210
+
211
+ - maps system event names to short wire codes when available
212
+ - prefixes event payloads with `'_:'`
213
+ - serializes the packet as JSON
214
+
215
+ Representative pattern:
216
+
217
+ ```typescript
218
+ ws.send(`${this.scope.config.eventPrefix}${JSON.stringify([eventNameInner, data])}`);
219
+ ```
220
+
221
+ This is the core server-to-client event encoding mechanism.
222
+
223
+ ### `passport`
224
+
225
+ The `passport` stage handles authentication.
226
+
227
+ A practical rule is:
228
+
229
+ - if a current passport already exists, use it
230
+ - otherwise read the access token from the configured passport-code query key
231
+ - if no authenticated passport is established, sign in anonymously
232
+
233
+ This gives Web Socket connections the same backend identity model as other Vona runtime flows, while still allowing anonymous connections when that is the intended capability.
234
+
235
+ ### `ready`
236
+
237
+ The `ready` stage is the terminal built-in stage in the default chain.
238
+
239
+ It does not add extra behavior by itself, but it completes the ordered dependency chain and marks the point after which the connection is considered ready for normal packet processing.
240
+
241
+ ## System ready signal
242
+
243
+ After the connection chain finishes successfully, `a-socket` sends the system event:
244
+
245
+ - `sysReady`
246
+
247
+ This tells the client that:
248
+
249
+ - the connection was accepted
250
+ - the server-side connection pipeline completed
251
+ - the socket can begin ordinary packet traffic
252
+
253
+ ## Packet processing flow
254
+
255
+ Inbound Web Socket messages move through the `socketPacket` onion chain.
256
+
257
+ The built-in packet order is:
258
+
259
+ 1. `event`
260
+ 2. `performAction`
261
+
262
+ ### `event`
263
+
264
+ The `event` packet stage normalizes raw inbound data.
265
+
266
+ If a string payload starts with the configured event prefix `'_:'`, the stage:
267
+
268
+ - removes the prefix
269
+ - parses the JSON payload
270
+ - reverse-maps short wire codes such as `_a`, `_b`, and `_c`
271
+ - returns a structured packet `[eventName, data]`
272
+
273
+ If the payload is not an event-formatted string, the stage forwards:
274
+
275
+ - `[undefined, data]`
276
+
277
+ That makes later packet handlers operate on a normalized packet shape instead of raw transport data.
278
+
279
+ ### `performAction`
280
+
281
+ The `performAction` stage implements the built-in request-like action channel.
282
+
283
+ It handles the system event:
284
+
285
+ - `sysPerformAction`
286
+
287
+ The payload contains compact request fields such as:
288
+
289
+ - request id
290
+ - method
291
+ - path
292
+ - query
293
+ - body
294
+ - headers
295
+
296
+ The stage forwards those values to:
297
+
298
+ - `this.$scope.executor.service.executor.performActionInner(...)`
299
+
300
+ If execution succeeds, the server sends:
301
+
302
+ - `sysPerformActionBack` with success code `0` and the result payload
303
+
304
+ If execution fails, the server sends:
305
+
306
+ - `sysPerformActionBack` with the backend error code and message
307
+
308
+ This gives Vona a built-in RPC-like path over Web Socket without replacing the ordinary backend action execution model.
309
+
310
+ ## System event protocol
311
+
312
+ The canonical built-in system event mapping is:
313
+
314
+ - `sysReady -> _a`
315
+ - `sysPerformAction -> _b`
316
+ - `sysPerformActionBack -> _c`
317
+
318
+ A useful interpretation is:
319
+
320
+ - the human-readable names are the framework event identities
321
+ - the short codes are the compact wire-level transport forms
322
+
323
+ Because the mapping lives in `types/socketEvent.ts`, that file is the source-truth contract for built-in Web Socket system events.
324
+
325
+ ## Sending and broadcasting messages
326
+
327
+ The delivery service is implemented in `src/service/socketEvent.ts`.
328
+
329
+ It provides two main patterns:
330
+
331
+ - `send(id, eventName, data, options)`
332
+ - `broadcast(namespace, eventName, data, options)`
333
+
334
+ ### Direct send
335
+
336
+ `send(...)` delivers to one known client id.
337
+
338
+ A practical flow is:
339
+
340
+ - send immediately on the current worker through `sendWorker(...)`
341
+ - emit the matching broadcast bean so other workers can perform the same delivery check if needed
342
+
343
+ ### Namespace broadcast
344
+
345
+ `broadcast(...)` delivers to all known clients in one namespace.
346
+
347
+ A practical flow is:
348
+
349
+ - send immediately to namespace members on the current worker through `broadcastWorker(...)`
350
+ - emit the matching broadcast bean so other workers can fan out to their local namespace members
351
+
352
+ This is why Web Socket delivery in Vona is closely related to distributed runtime primitives.
353
+
354
+ Read this together with:
355
+
356
+ - [Broadcast Guide](/backend/broadcast-guide)
357
+ - [Worker Guide](/backend/worker-guide)
358
+
359
+ ## Defining a socket namespace
360
+
361
+ The main extension pattern for application modules is a socket namespace bean.
362
+
363
+ The pattern has three parts:
364
+
365
+ 1. extend `ISocketNamespaceRecord`
366
+ 2. declare a bean with `@SocketNamespace(...)`
367
+ 3. inherit `BeanSocketNamespaceBase`
368
+
369
+ Representative shape:
370
+
371
+ ```typescript
372
+ declare module 'vona-module-a-socket' {
373
+ export interface ISocketNamespaceRecord {
374
+ '/ssrhmr': never;
375
+ }
376
+ }
377
+
378
+ @SocketNamespace({
379
+ namespace: '/ssrhmr',
380
+ })
381
+ export class SocketNamespaceSsrHmr extends BeanSocketNamespaceBase {}
382
+ ```
383
+
384
+ `BeanSocketNamespaceBase` gives namespace beans two useful helpers:
385
+
386
+ - `send(id, eventName, data, options)`
387
+ - `broadcast(eventName, data, options)`
388
+
389
+ That means downstream modules usually do not need to talk to the low-level socket registry directly.
390
+
391
+ ## Example: `a-ssrhmr`
392
+
393
+ The `a-ssrhmr` module is a concrete example of extending `a-socket`.
394
+
395
+ Its namespace bean declares:
396
+
397
+ - namespace: `/ssrhmr`
398
+ - event: `reload`
399
+
400
+ Representative shape:
401
+
402
+ ```typescript
403
+ @SocketNamespace<ISocketNamespaceOptionsSsrHmr>({
404
+ namespace: '/ssrhmr',
405
+ })
406
+ export class SocketNamespaceSsrHmr extends BeanSocketNamespaceBase<ISocketNamespaceOptionsSsrHmrEvents> {}
407
+ ```
408
+
409
+ Then a regular bean can trigger namespace broadcast through scope:
410
+
411
+ ```typescript
412
+ @Bean()
413
+ export class BeanSsrHmr extends BeanBase {
414
+ reload() {
415
+ this.scope.socketNamespace.ssrHmr.broadcast('reload');
416
+ }
417
+ }
418
+ ```
419
+
420
+ This example shows the intended layering:
421
+
422
+ - `a-socket` owns the transport runtime
423
+ - application or framework modules define namespace semantics
424
+ - ordinary beans trigger namespace delivery through scope
425
+
426
+ ## Relationship to other backend guides
427
+
428
+ Read this guide together with:
429
+
430
+ - [Web Socket Usage Guide](/backend/websocket-usage-guide)
431
+ - [Web Socket Protocol Guide](/backend/websocket-protocol-guide)
432
+ - [Web Socket Call Flow](/backend/websocket-call-flow)
433
+ - [Runtime and Flavors](/backend/runtime-and-flavors)
434
+ - [Config Guide](/backend/config-guide)
435
+ - [Broadcast Guide](/backend/broadcast-guide)
436
+ - [Worker Guide](/backend/worker-guide)
437
+ - [Event Guide](/backend/event-guide)
438
+
439
+ A practical distinction is:
440
+
441
+ - use **Event** when backend code needs framework-native in-process event composition
442
+ - use **Broadcast** when many workers should all receive the same signal
443
+ - use **Web Socket** when the backend needs long-lived client connections, server push, or packet-based request flow over a persistent transport
444
+
445
+ ## Implementation checks for Web Socket-related backend work
446
+
447
+ When extending or reviewing Web Socket behavior, ask:
448
+
449
+ 1. does the work belong in a namespace bean, a connection onion, or a packet onion?
450
+ 2. is the namespace path consistent with the `/ws/...` routing model?
451
+ 3. does the connection flow need identity, instance, or origin checks?
452
+ 4. should delivery be point-to-point or namespace-wide?
453
+ 5. is the behavior local to one worker, or should it propagate through broadcast?
454
+
455
+ That helps backend extensions stay aligned with the existing `a-socket` architecture instead of bypassing the framework transport model.