cabloy 5.1.59 → 5.1.60

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 (102) hide show
  1. package/.claude/skills/cabloy-contract-loop/SKILL.md +16 -0
  2. package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +26 -0
  3. package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +144 -0
  4. package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +18 -0
  5. package/.claude/skills/cabloy-resource-field-update/SKILL.md +267 -0
  6. package/.claude/skills/cabloy-resource-field-update/evals/evals.json +53 -0
  7. package/.claude/skills/cabloy-resource-field-update/references/custom-renderer-demo-checklist.md +102 -0
  8. package/.claude/skills/cabloy-resource-field-update/references/field-update-decision-tree.md +120 -0
  9. package/.claude/skills/cabloy-resource-field-update/references/follow-up-checklist.md +80 -0
  10. package/.claude/skills/cabloy-resource-field-update/references/verification-checklist.md +97 -0
  11. package/.github/workflows/docs-pages.yml +2 -0
  12. package/.github/workflows/vona-cov-pg.yml +2 -0
  13. package/.github/workflows/vona-test-crud.yml +4 -2
  14. package/.github/workflows/vona-test-mysql.yml +2 -0
  15. package/.github/workflows/vona-test-pg.yml +2 -0
  16. package/.github/workflows/vona-test-sqlite3.yml +2 -0
  17. package/.github/workflows/vona-tsc.yml +2 -0
  18. package/.github/workflows/zova-ui.yml +2 -0
  19. package/.gitignore +0 -4
  20. package/CHANGELOG.md +30 -0
  21. package/CLAUDE.md +2 -0
  22. package/README.md +15 -0
  23. package/cabloy-docs/.vitepress/config.mjs +43 -0
  24. package/cabloy-docs/ai/class-placement-rule.md +2 -0
  25. package/cabloy-docs/ai/cli-to-skill-map.md +7 -0
  26. package/cabloy-docs/ai/future-skill-roadmap.md +17 -2
  27. package/cabloy-docs/backend/bean-scene-authoring.md +350 -0
  28. package/cabloy-docs/backend/cli.md +26 -1
  29. package/cabloy-docs/backend/foundation.md +28 -3
  30. package/cabloy-docs/backend/introduction.md +8 -0
  31. package/cabloy-docs/backend/service-guide.md +2 -0
  32. package/cabloy-docs/backend/websocket-call-flow.md +435 -0
  33. package/cabloy-docs/backend/websocket-guide.md +455 -0
  34. package/cabloy-docs/backend/websocket-protocol-guide.md +381 -0
  35. package/cabloy-docs/backend/websocket-usage-guide.md +356 -0
  36. package/cabloy-docs/frontend/bean-scene-authoring.md +372 -0
  37. package/cabloy-docs/frontend/behavior-guide.md +449 -0
  38. package/cabloy-docs/frontend/cli.md +12 -0
  39. package/cabloy-docs/frontend/introduction.md +5 -0
  40. package/cabloy-docs/frontend/ioc-and-beans.md +10 -9
  41. package/cabloy-docs/frontend/router-tabs-admin-web-comparison.md +206 -0
  42. package/cabloy-docs/frontend/router-tabs-introduction.md +106 -0
  43. package/cabloy-docs/frontend/router-tabs-mechanism.md +469 -0
  44. package/cabloy-docs/frontend/router-tabs-overview.md +227 -0
  45. package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +343 -0
  46. package/cabloy-docs/frontend/ssr-architecture-overview.md +211 -0
  47. package/cabloy-docs/frontend/ssr-build-deploy-guide.md +308 -0
  48. package/cabloy-docs/frontend/ssr-review-checklist.md +184 -0
  49. package/cabloy-docs/frontend/ssr-troubleshooting-guide.md +301 -0
  50. package/cabloy-docs/fullstack/framework-performance.md +3 -3
  51. package/cabloy-docs/fullstack/introduction.md +29 -0
  52. package/cabloy-docs/fullstack/quickstart.md +7 -1
  53. package/cabloy-docs/fullstack/tutorial-1-first-module.md +111 -0
  54. package/cabloy-docs/fullstack/tutorial-2-first-crud.md +122 -0
  55. package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +131 -0
  56. package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +119 -0
  57. package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +144 -0
  58. package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +168 -0
  59. package/cabloy-docs/fullstack/tutorials-overview.md +179 -0
  60. package/cabloy-docs/index.md +4 -3
  61. package/cabloy-docs/reference/bean-scene-boilerplates.md +73 -0
  62. package/cabloy-docs/reference/cli-reference.md +2 -0
  63. package/package.json +6 -2
  64. package/scripts/init.ts +18 -2
  65. package/vona/packages-cli/cabloy-cli/package.json +2 -2
  66. package/vona/packages-cli/cli/package.json +1 -1
  67. package/vona/packages-cli/cli-set-api/package.json +1 -1
  68. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.create.module.ts +4 -0
  69. package/vona/packages-vona/vona/package.json +1 -1
  70. package/vona/pnpm-lock.yaml +133 -1088
  71. package/vona/pnpm-workspace.yaml +0 -1
  72. package/vona/src/suite-vendor/a-vona/modules/a-core/assets/static/img/vona.svg +1 -1
  73. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
  74. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  75. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +1 -1
  76. package/vona/src/suite-vendor/a-vona/modules/a-upload/package.json +2 -2
  77. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  78. package/zova/package.original.json +1 -1
  79. package/zova/packages-cli/cli/package.json +3 -3
  80. package/zova/packages-cli/cli-set-front/cli/templates/init/icon/boilerplate/icons/default/zova.svg +1 -1
  81. package/zova/packages-cli/cli-set-front/package.json +3 -3
  82. package/zova/packages-cli/cli-set-front/src/lib/bean/cli.create.module.ts +4 -0
  83. package/zova/packages-cli/cli-set-front/src/lib/command/create.bean.ts +5 -1
  84. package/zova/packages-utils/zova-vite/package.json +2 -2
  85. package/zova/packages-zova/zova/package.json +2 -2
  86. package/zova/pnpm-lock.yaml +284 -1313
  87. package/zova/pnpm-workspace.yaml +0 -1
  88. package/zova/src/suite/a-home/modules/home-icon/icons/social/cabloy.svg +1 -1
  89. package/zova/src/suite/a-home/modules/home-icon/icons/social/vona.svg +1 -1
  90. package/zova/src/suite/a-home/modules/home-icon/icons/social/zova.svg +1 -1
  91. package/zova/src/suite/a-home/modules/home-icon/src/.metadata/icons/groups/social.svg +3 -3
  92. package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +9 -0
  93. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  94. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +66 -16
  95. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  96. package/zova/src/suite-vendor/a-zova/modules/a-routertabs/package.json +1 -1
  97. package/zova/src/suite-vendor/a-zova/modules/a-routertabs/src/model/tabs.ts +60 -18
  98. package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableActionRow/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
  99. package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableCell/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
  100. package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
  101. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  102. package/zova/src/suite-vendor/a-zova/package.json +4 -4
@@ -0,0 +1,435 @@
1
+ # Web Socket Call Flow
2
+
3
+ This guide is a source-oriented execution trace for the built-in `a-socket` module.
4
+
5
+ Read this together with:
6
+
7
+ - [Web Socket Guide](/backend/websocket-guide)
8
+ - [Web Socket Usage Guide](/backend/websocket-usage-guide)
9
+ - [Web Socket Protocol Guide](/backend/websocket-protocol-guide)
10
+
11
+ Use the practical split:
12
+
13
+ - [Web Socket Guide](/backend/websocket-guide) for architecture
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
+ - this page for source tracing and debugging
17
+
18
+ ## Why this call-flow view matters
19
+
20
+ The main Web Socket guide explains the architecture and extension model.
21
+
22
+ This page answers a different question:
23
+
24
+ - what methods actually run, and in what order, when a socket starts, receives a packet, sends a message, or closes?
25
+
26
+ That matters when you are:
27
+
28
+ - debugging connection lifecycle behavior
29
+ - deciding whether an extension belongs in `socketNamespace`, `socketConnection`, or `socketPacket`
30
+ - tracing authentication, origin checks, instance initialization, or packet execution from source
31
+ - verifying how local delivery and cross-worker broadcast fit together
32
+
33
+ ## Key source files
34
+
35
+ Use these files as the primary trace surface:
36
+
37
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/monkey.ts`
38
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/service/socket.ts`
39
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/service/socketEvent.ts`
40
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/bean/bean.socket.ts`
41
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/bean/socketConnection.*.ts`
42
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/bean/socketPacket.*.ts`
43
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/types/socketEvent.ts`
44
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/lib/const.ts`
45
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/bean/hmr.socketConnection.ts`
46
+ - `vona/src/suite-vendor/a-cabloy/modules/a-socket/src/bean/hmr.socketPacket.ts`
47
+
48
+ ## Startup call flow
49
+
50
+ At backend startup, the call path is:
51
+
52
+ 1. `Monkey.appReady()`
53
+ 2. `ServiceSocket.appReady()`
54
+ 3. create `WebSocketServer`
55
+ 4. register the `connection` listener
56
+
57
+ Representative shape:
58
+
59
+ ```typescript
60
+ async appReady() {
61
+ if (!this.app.server) return;
62
+ this.app.wss = new WebSocketServer({ server: this.app.server });
63
+ this.app.wss.on('connection', (ws, req) => {
64
+ this._onConnection(ws, req);
65
+ });
66
+ }
67
+ ```
68
+
69
+ A practical interpretation is:
70
+
71
+ - monkey lifecycle integration connects `a-socket` to ordinary backend startup
72
+ - `a-socket` does not create a separate standalone server
73
+ - the Web Socket server is attached to the existing backend HTTP server
74
+
75
+ ## Connection setup call flow
76
+
77
+ When a client connects, the main path is:
78
+
79
+ 1. `WebSocketServer` emits `connection`
80
+ 2. `ServiceSocket._onConnection(ws, req)` starts
81
+ 3. reject immediately if the app is already closing
82
+ 4. parse the request URL
83
+ 5. read query values for instance, locale, and timezone
84
+ 6. create a request-scoped backend context through `app.bean.executor.newCtx(...)`
85
+ 7. define `ctx.ws`
86
+ 8. derive `ws.namespace`
87
+ 9. assign `ws.id`
88
+ 10. add the client to `bean.socket`
89
+ 11. execute the connection onion chain with `{ method: 'enter', ws }`
90
+ 12. install `onclose`, `onmessage`, and `onerror`
91
+ 13. send `sysReady`
92
+
93
+ ## Connection setup as a source trace
94
+
95
+ A compact trace looks like this:
96
+
97
+ ```text
98
+ Monkey.appReady()
99
+ -> ServiceSocket.appReady()
100
+ -> new WebSocketServer({ server: app.server })
101
+ -> wss.on('connection', (ws, req) => _onConnection(ws, req))
102
+
103
+ connection
104
+ -> ServiceSocket._onConnection(ws, req)
105
+ -> URL.parse(req.url, ...)
106
+ -> app.bean.executor.newCtx(...)
107
+ -> define ctx.ws getter
108
+ -> ws.namespace = getNamespace()
109
+ -> ws.id = uuidv4()
110
+ -> bean.socket.addClient(ws)
111
+ -> _getComposeSocketConnections(ws.namespace)({ method: 'enter', ws })
112
+ -> install ws.onclose / ws.onmessage / ws.onerror
113
+ -> ws.sendEvent('sysReady')
114
+ ```
115
+
116
+ This is the first source path to read when a connection is accepted but later behavior is not what you expect.
117
+
118
+ ## Namespace resolution call flow
119
+
120
+ Namespace identity is derived inside `ServiceSocket.getNamespace()`.
121
+
122
+ The flow is:
123
+
124
+ 1. read `this.ctx.path`
125
+ 2. remove the configured global prefix
126
+ 3. if the remaining path is empty, use `/`
127
+ 4. cast the result to a namespace key
128
+
129
+ A useful interpretation is:
130
+
131
+ - transport path and logical namespace are intentionally coupled
132
+ - namespace selection happens before packet handling
133
+ - namespace-specific socket behavior is therefore determined at connection time
134
+
135
+ Representative mapping:
136
+
137
+ - `/ws` -> `/`
138
+ - `/ws/ssrhmr` -> `/ssrhmr`
139
+
140
+ ## Connection onion composition flow
141
+
142
+ The connection chain is not hardcoded as a manual list in `service/socket.ts`.
143
+
144
+ Instead, the flow is:
145
+
146
+ 1. `ServiceSocket._getComposeSocketConnections(namespace)`
147
+ 2. fetch the namespace cache from `getCacheSocketConnections(app)`
148
+ 3. if the namespace is not cached:
149
+ - ask `this.bean.onion.socketConnection.getOnionsEnabledWrapped(...)` for enabled onion slices
150
+ - wrap each slice through `_wrapOnionConnection(...)`
151
+ - compose the wrapped handlers through `compose(...)`
152
+ 4. execute the composed chain
153
+
154
+ Representative shape:
155
+
156
+ ```typescript
157
+ const connections = this.bean.onion.socketConnection.getOnionsEnabledWrapped(item => {
158
+ return this._wrapOnionConnection(item);
159
+ });
160
+ cacheSocketConnections[namespace] = compose(connections);
161
+ ```
162
+
163
+ This matters because the runtime chain is framework-driven:
164
+
165
+ - enabled onion metadata determines what participates
166
+ - wrappers resolve the real bean instance from the container
167
+ - the composed result is cached per namespace
168
+
169
+ ## Built-in connection onion execution order
170
+
171
+ The default built-in connection path is:
172
+
173
+ ```text
174
+ alive -> app -> instance -> cors -> event -> passport -> ready
175
+ ```
176
+
177
+ The runtime enters each bean through:
178
+
179
+ - `beanInstance.enter(ws, options, next)` on connection setup
180
+ - `beanInstance.exit(ws, options, next)` on connection teardown
181
+
182
+ A practical responsibility map is:
183
+
184
+ - `alive` -> heartbeat and stale-socket detection
185
+ - `app` -> app-ready and closing checks
186
+ - `instance` -> instance initialization
187
+ - `cors` -> origin validation
188
+ - `event` -> attach `ws.sendEvent(...)`
189
+ - `passport` -> token or anonymous sign-in
190
+ - `ready` -> terminal ordered stage
191
+
192
+ ## Packet composition flow
193
+
194
+ Inbound messages follow the same overall pattern as connection onions.
195
+
196
+ The runtime path is:
197
+
198
+ 1. `ws.onmessage`
199
+ 2. `ServiceSocket._getComposeSocketPackets(ws.namespace)`
200
+ 3. fetch the namespace cache from `getCacheSocketPackets(app)`
201
+ 4. if missing, load enabled packet onions, wrap them, and compose them
202
+ 5. execute the composed chain with `{ data: event.data, ws }`
203
+
204
+ The packet wrapper calls:
205
+
206
+ - `beanInstance.execute(data.data, data.ws, options, _patchPacketNext(...))`
207
+
208
+ That patching step lets packet handlers pass a transformed packet onward while the composed chain keeps the socket attached.
209
+
210
+ ## Built-in packet execution order
211
+
212
+ The default built-in packet path is:
213
+
214
+ ```text
215
+ event -> performAction
216
+ ```
217
+
218
+ ### Step 1: event decoding
219
+
220
+ `SocketPacketEvent.execute(...)` checks whether the payload is an event-formatted string.
221
+
222
+ If so, it:
223
+
224
+ 1. strips the configured prefix `'_:'`
225
+ 2. parses JSON
226
+ 3. reverse-maps short codes such as `_a`, `_b`, `_c`
227
+ 4. forwards `[eventName, data]`
228
+
229
+ Otherwise it forwards:
230
+
231
+ - `[undefined, rawData]`
232
+
233
+ This is the source transition from raw transport data into normalized packet data.
234
+
235
+ ### Step 2: perform-action handling
236
+
237
+ `SocketPacketPerformAction.execute(...)` checks whether the normalized event name is:
238
+
239
+ - `sysPerformAction`
240
+
241
+ If not, it calls `next()`.
242
+
243
+ If yes, it:
244
+
245
+ 1. extracts compact request fields from the packet
246
+ 2. calls `this.$scope.executor.service.executor.performActionInner(...)`
247
+ 3. sends `sysPerformActionBack` on success or failure
248
+
249
+ A compact trace looks like this:
250
+
251
+ ```text
252
+ ws.onmessage
253
+ -> composed socketPacket chain
254
+ -> SocketPacketEvent.execute(raw)
255
+ -> normalized packet [eventName, data]
256
+ -> SocketPacketPerformAction.execute(packet)
257
+ -> performActionInner(method, path, { query, body, headers })
258
+ -> ws.sendEvent('sysPerformActionBack', resultOrError)
259
+ ```
260
+
261
+ ## Outbound send call flow
262
+
263
+ The simplest server-to-client path is direct send by client id.
264
+
265
+ The runtime path is:
266
+
267
+ 1. some backend code calls `scope.socket.service.socketEvent.send(...)`
268
+ 2. `ServiceSocketEvent.send(...)` calls `sendWorker(...)` locally
269
+ 3. `sendWorker(...)` looks up the socket in `bean.socket.clients`
270
+ 4. `ws.sendEvent(...)` serializes and sends the packet
271
+ 5. `ServiceSocketEvent.send(...)` also emits the `send` broadcast bean for cross-worker propagation
272
+
273
+ A compact trace looks like this:
274
+
275
+ ```text
276
+ caller
277
+ -> ServiceSocketEvent.send(id, eventName, data, options)
278
+ -> sendWorker(id, ...)
279
+ -> bean.socket.clients[id]?.sendEvent(...)
280
+ -> ws.send('_:' + JSON.stringify([eventNameInner, data]))
281
+ -> scope.broadcast.send.emit(...)
282
+ ```
283
+
284
+ This is why even a targeted send is not only a local socket write. It also has a distributed propagation path.
285
+
286
+ ## Outbound broadcast call flow
287
+
288
+ Namespace broadcast follows the same two-level model.
289
+
290
+ The runtime path is:
291
+
292
+ 1. some backend code calls `broadcast(namespace, eventName, data, options)`
293
+ 2. `ServiceSocketEvent.broadcast(...)` calls `broadcastWorker(...)` locally
294
+ 3. `broadcastWorker(...)` reads client ids from `bean.socket.clientsNamespace[namespace]`
295
+ 4. each local client sends through `ws.sendEvent(...)`
296
+ 5. `ServiceSocketEvent.broadcast(...)` emits the `broadcast` bean for other workers
297
+
298
+ A compact trace looks like this:
299
+
300
+ ```text
301
+ caller
302
+ -> ServiceSocketEvent.broadcast(namespace, eventName, data, options)
303
+ -> broadcastWorker(namespace, ...)
304
+ -> ids = bean.socket.clientsNamespace[namespace]
305
+ -> for each id: bean.socket.clients[id]?.sendEvent(...)
306
+ -> scope.broadcast.broadcast.emit(...)
307
+ ```
308
+
309
+ A practical interpretation is:
310
+
311
+ - local clients receive the event immediately
312
+ - other workers replay the same delivery logic for their local namespace members
313
+ - `a-socket` reuses the distributed broadcast layer instead of inventing a separate cross-worker socket bus
314
+
315
+ ## Namespace-bean call flow
316
+
317
+ Most application code should not call low-level socket registries directly.
318
+
319
+ The usual path is a namespace bean extending `BeanSocketNamespaceBase`.
320
+
321
+ That path is:
322
+
323
+ 1. define a namespace bean with `@SocketNamespace(...)`
324
+ 2. call `send(...)` or `broadcast(...)` on that bean
325
+ 3. `BeanSocketNamespaceBase` forwards to `ServiceSocketEvent`
326
+ 4. `ServiceSocketEvent` performs local delivery and broadcast propagation
327
+
328
+ Representative trace:
329
+
330
+ ```text
331
+ BeanSsrHmr.reload()
332
+ -> this.scope.socketNamespace.ssrHmr.broadcast('reload')
333
+ -> BeanSocketNamespaceBase.broadcast(...)
334
+ -> this.$scope.socket.service.socketEvent.broadcast(namespace, ...)
335
+ -> local namespace delivery
336
+ -> broadcast fan-out to other workers
337
+ ```
338
+
339
+ This is the normal extension path for feature modules.
340
+
341
+ ## Disconnect call flow
342
+
343
+ When a connection closes, the runtime path is:
344
+
345
+ 1. `ws.onclose`
346
+ 2. run the connection onion chain again with `{ method: 'exit', ws }`
347
+ 3. remove the client from the registry in `bean.socket.removeClient(ws)`
348
+ 4. resolve the connection promise
349
+
350
+ Representative trace:
351
+
352
+ ```text
353
+ ws.onclose
354
+ -> _getComposeSocketConnections(ws.namespace)({ method: 'exit', ws })
355
+ -> bean.socket.removeClient(ws)
356
+ -> resolve()
357
+ ```
358
+
359
+ This matters because cleanup is not only a transport event. It also reuses the onion lifecycle so custom connection beans can attach exit-time behavior.
360
+
361
+ ## Shutdown call flow
362
+
363
+ At backend shutdown, the path is:
364
+
365
+ 1. `Monkey.appClose()`
366
+ 2. `ServiceSocket.appClose()`
367
+ 3. `app.wss.close()`
368
+ 4. `bean.socket.close()`
369
+ 5. terminate all tracked clients
370
+
371
+ A compact trace looks like this:
372
+
373
+ ```text
374
+ Monkey.appClose()
375
+ -> ServiceSocket.appClose()
376
+ -> app.wss.close()
377
+ -> bean.socket.close()
378
+ -> for each client: terminate()
379
+ ```
380
+
381
+ This keeps runtime shutdown and socket cleanup aligned.
382
+
383
+ ## HMR and cache invalidation flow
384
+
385
+ `a-socket` caches composed connection and packet chains in `app.meta` through:
386
+
387
+ - `SymbolCacheSocketConnections`
388
+ - `SymbolCacheSocketPackets`
389
+
390
+ The related flow is:
391
+
392
+ 1. first connection or packet execution composes and caches the chain
393
+ 2. later traffic reuses the cached composed function
394
+ 3. HMR reload triggers `HmrSocketConnection.reload(...)` or `HmrSocketPacket.reload(...)`
395
+ 4. those HMR beans clear the corresponding cache from `app.meta`
396
+ 5. the next execution rebuilds the composed chain from current metadata
397
+
398
+ A compact trace looks like this:
399
+
400
+ ```text
401
+ first use
402
+ -> _getComposeSocketConnections(namespace)
403
+ -> getCacheSocketConnections(app)
404
+ -> compose(...) and cache
405
+
406
+ HMR reload
407
+ -> HmrSocketConnection.reload(...)
408
+ -> clearAllCacheSocketConnections(app)
409
+
410
+ next use
411
+ -> rebuild composed chain
412
+ ```
413
+
414
+ This is the important source path when onion changes appear stale during development.
415
+
416
+ ## When to trace which path
417
+
418
+ Use these call paths depending on the problem you are investigating:
419
+
420
+ - startup problem -> `monkey.ts` and `ServiceSocket.appReady()`
421
+ - connection rejected too early -> `_onConnection(...)` plus `app`, `instance`, `cors`, and `passport`
422
+ - client never receives ready -> `event` connection onion plus `sysReady`
423
+ - inbound action fails -> `socketPacket.event.ts`, `socketPacket.performAction.ts`, and `performActionInner(...)`
424
+ - targeted delivery fails -> `ServiceSocketEvent.send(...)` and `bean.socket.clients`
425
+ - namespace broadcast fails -> `ServiceSocketEvent.broadcast(...)` and `clientsNamespace`
426
+ - development reload seems stale -> `lib/const.ts` and the HMR beans
427
+
428
+ ## Related guides
429
+
430
+ If you need the broader context next, read:
431
+
432
+ - [Web Socket Guide](/backend/websocket-guide) for the architecture and extension model
433
+ - [Web Socket Usage Guide](/backend/websocket-usage-guide) for server-side authoring patterns
434
+ - [Web Socket Protocol Guide](/backend/websocket-protocol-guide) for the client-visible wire format
435
+ - [Broadcast Guide](/backend/broadcast-guide) and [Worker Guide](/backend/worker-guide) for cross-worker delivery context