cabloy 5.1.60 → 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 (76) 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 +89 -16
  5. package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +102 -14
  6. package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +4 -0
  7. package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +32 -14
  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 +7 -0
  12. package/.claude/skills/cabloy-zova-source-reading/SKILL.md +221 -0
  13. package/.claude/skills/cabloy-zova-source-reading/references/analysis-modes.md +91 -0
  14. package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +117 -0
  15. package/CHANGELOG.md +22 -0
  16. package/CLAUDE.md +10 -0
  17. package/cabloy-docs/.vitepress/config.mjs +50 -4
  18. package/cabloy-docs/ai/cli-to-skill-map.md +7 -0
  19. package/cabloy-docs/ai/docs-skills-rules-mapping.md +14 -0
  20. package/cabloy-docs/ai/future-skill-roadmap.md +10 -7
  21. package/cabloy-docs/ai/introduction.md +1 -0
  22. package/cabloy-docs/ai/playbook-backend-module.md +6 -0
  23. package/cabloy-docs/ai/playbook-module-removal.md +164 -0
  24. package/cabloy-docs/ai/skills.md +11 -0
  25. package/cabloy-docs/backend/dto-guide.md +6 -0
  26. package/cabloy-docs/backend/entity-guide.md +18 -0
  27. package/cabloy-docs/backend/introduction.md +2 -0
  28. package/cabloy-docs/backend/serialization-guide.md +10 -0
  29. package/cabloy-docs/backend/status-guide.md +271 -0
  30. package/cabloy-docs/frontend/api-guide.md +2 -0
  31. package/cabloy-docs/frontend/bean-scene-authoring.md +2 -0
  32. package/cabloy-docs/frontend/cli.md +12 -0
  33. package/cabloy-docs/frontend/command-scene-authoring.md +495 -0
  34. package/cabloy-docs/frontend/design-principles.md +6 -0
  35. package/cabloy-docs/frontend/fetch-interceptor-guide.md +440 -0
  36. package/cabloy-docs/frontend/form-guide.md +795 -0
  37. package/cabloy-docs/frontend/foundation.md +29 -0
  38. package/cabloy-docs/frontend/introduction.md +12 -1
  39. package/cabloy-docs/frontend/ioc-and-beans.md +6 -0
  40. package/cabloy-docs/frontend/mock-guide.md +1 -0
  41. package/cabloy-docs/frontend/model-architecture.md +252 -39
  42. package/cabloy-docs/frontend/model-resource-best-practices.md +379 -0
  43. package/cabloy-docs/frontend/model-resource-cookbook.md +505 -0
  44. package/cabloy-docs/frontend/model-resource-owner-pattern.md +382 -0
  45. package/cabloy-docs/frontend/model-resource-usage-guide.md +318 -0
  46. package/cabloy-docs/frontend/model-state-guide.md +366 -13
  47. package/cabloy-docs/frontend/openapi-sdk-guide.md +5 -2
  48. package/cabloy-docs/frontend/page-guide.md +6 -0
  49. package/cabloy-docs/frontend/quickstart.md +4 -0
  50. package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +266 -0
  51. package/cabloy-docs/frontend/server-data.md +2 -0
  52. package/cabloy-docs/frontend/zova-form-source-reading-map.md +295 -0
  53. package/cabloy-docs/frontend/zova-form-under-the-hood.md +556 -0
  54. package/cabloy-docs/frontend/zova-reactivity-under-the-hood.md +320 -0
  55. package/cabloy-docs/frontend/zova-source-reading-map.md +327 -0
  56. package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +308 -0
  57. package/cabloy-docs/fullstack/contract-loop-playbook.md +350 -0
  58. package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +44 -1
  59. package/cabloy-docs/fullstack/introduction.md +12 -1
  60. package/cabloy-docs/fullstack/openapi-to-sdk.md +19 -9
  61. package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +2 -2
  62. package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +30 -5
  63. package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +9 -7
  64. package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +2 -0
  65. package/cabloy-docs/fullstack/tutorials-overview.md +16 -3
  66. package/cabloy-docs/reference/bean-scene-boilerplates.md +2 -0
  67. package/package.json +2 -1
  68. package/scripts/init.ts +2 -18
  69. package/scripts/initTestData.ts +25 -0
  70. package/scripts/upgrade.ts +17 -2
  71. package/vona/pnpm-lock.yaml +94 -4
  72. package/zova/packages-cli/cli/package.json +2 -2
  73. package/zova/packages-cli/cli-set-front/cli/templates/openapi/config/boilerplate/module/openapi.config.ts +6 -1
  74. package/zova/packages-cli/cli-set-front/package.json +1 -1
  75. package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +34 -4
  76. package/zova/pnpm-lock.yaml +20 -20
@@ -0,0 +1,440 @@
1
+ # Fetch Interceptor Guide
2
+
3
+ This guide explains how Zova fetch interceptors work in the Cabloy monorepo.
4
+
5
+ ## Why this page exists
6
+
7
+ When you first see `a-interceptor`, it is easy to read it as a thin Axios convenience layer.
8
+
9
+ That reading is incomplete.
10
+
11
+ In Zova, fetch interceptors are a built-in **onion scene** around `$fetch`. They are authored as beans, loaded through module metadata, ordered through dependency rules, and executed through a composed request/response pipeline.
12
+
13
+ So this page does two narrower things:
14
+
15
+ 1. explain the interceptor subsystem in Zova-native terms
16
+ 2. show the shortest source path from the public surface to the runtime flow
17
+
18
+ ## The shortest accurate mental model
19
+
20
+ A Zova fetch interceptor is:
21
+
22
+ - a bean-scene interceptor declared with `@Interceptor()`
23
+ - attached to the `$fetch` transport layer
24
+ - loaded as an onion item through module metadata
25
+ - ordered through dependency rules rather than an ad hoc list
26
+ - able to participate in request, request-error, response, and response-error flow
27
+
28
+ A practical one-line model is:
29
+
30
+ > Zova fetch interceptors are transport-layer middleware beans for `$fetch`, implemented on top of the generic onion-composition system.
31
+
32
+ That is more accurate than calling them only "Axios interceptors," because Axios is the host transport, but the lifecycle, loading, ordering, and execution model come from Zova.
33
+
34
+ ## Where interceptors fit in the frontend data stack
35
+
36
+ Use fetch interceptors when the concern belongs to the transport layer itself, for example:
37
+
38
+ - attaching locale or timezone headers
39
+ - attaching or refreshing JWT auth tokens
40
+ - normalizing a backend response envelope such as `{ code, message, data }`
41
+ - falling back to a local mock server for selected failures
42
+ - short-circuiting to SSR `performAction` on the server
43
+
44
+ Do **not** reach for a fetch interceptor first when the concern is mainly business-oriented or state-oriented.
45
+
46
+ A practical layering rule is:
47
+
48
+ - use `$fetch` + interceptors for transport concerns
49
+ - use `$api` for business-oriented frontend services
50
+ - use `Model` for state ownership, caching, and shared remote state
51
+ - use OpenAPI SDK or schema-driven layers when backend contract metadata should shape the frontend surface more directly
52
+
53
+ Read these together when you need the broader layering context:
54
+
55
+ - [Server Data](/frontend/server-data)
56
+ - [API Guide](/frontend/api-guide)
57
+ - [Model Architecture](/frontend/model-architecture)
58
+ - [OpenAPI SDK Guide](/frontend/openapi-sdk-guide)
59
+
60
+ ## The public authoring surface
61
+
62
+ The public decorator is implemented in:
63
+
64
+ - `zova/src/suite-vendor/a-zova/modules/a-fetch/src/lib/interceptor.ts`
65
+
66
+ Representative source shape:
67
+
68
+ ```typescript
69
+ export function Interceptor<T extends IDecoratorInterceptorOptions>(options?: T): ClassDecorator {
70
+ return createBeanDecorator('interceptor', 'new', true, options);
71
+ }
72
+ ```
73
+
74
+ This tells us two important things:
75
+
76
+ 1. an interceptor is a bean scene named `interceptor`
77
+ 2. the interceptor bean is authored as a fresh-instance bean scene
78
+
79
+ The typed transport hooks are defined in:
80
+
81
+ - `zova/src/suite-vendor/a-zova/modules/a-fetch/src/types/interceptor.ts`
82
+
83
+ The main hook surfaces are:
84
+
85
+ - `onRequest(...)`
86
+ - `onRequestError(...)`
87
+ - `onResponse(...)`
88
+ - `onResponseError(...)`
89
+
90
+ That same file also shows that interceptor options inherit generic onion features such as:
91
+
92
+ - `enable`
93
+ - `match`
94
+ - `ignore`
95
+ - `dependencies`
96
+ - `dependents`
97
+
98
+ So the public authoring contract is intentionally small, while the execution model is inherited from the broader onion system.
99
+
100
+ ## Where the built-in interceptors live
101
+
102
+ The built-in interceptor module is:
103
+
104
+ - `zova/src/suite-vendor/a-zova/modules/a-interceptor`
105
+
106
+ Its public metadata surface is exported from:
107
+
108
+ - `zova/src/suite-vendor/a-zova/modules/a-interceptor/src/.metadata/index.ts`
109
+
110
+ That metadata file confirms the built-in interceptor set:
111
+
112
+ - `a-interceptor:mock`
113
+ - `a-interceptor:headers`
114
+ - `a-interceptor:jwt`
115
+ - `a-interceptor:performAction`
116
+ - `a-interceptor:body`
117
+
118
+ It also augments `IInterceptorRecord`, which is how these named interceptors become part of the typed Zova fetch surface.
119
+
120
+ ## Runtime flow
121
+
122
+ The runtime path is easiest to understand from `$fetch` inward.
123
+
124
+ A compact runtime sketch is:
125
+
126
+ ```text
127
+ caller
128
+ -> $fetch
129
+ -> BeanFetch
130
+ -> ServiceComposer
131
+ -> load onion slices
132
+ -> create interceptor beans
133
+ -> compose 4 pipelines
134
+ -> request
135
+ -> request error
136
+ -> response
137
+ -> response error
138
+ -> mock
139
+ -> headers
140
+ -> jwt
141
+ -> performAction
142
+ -> body
143
+ -> final data or error shape returned to caller
144
+ ```
145
+
146
+ This sketch is intentionally simplified. The concrete order and participation of each interceptor still depend on the current onion metadata, dependency rules, and enable/match filtering.
147
+
148
+ A slightly more detailed request/response sketch is:
149
+
150
+ ```text
151
+ request path
152
+ caller
153
+ -> $fetch.request(...)
154
+ -> BeanFetch Axios instance
155
+ -> ServiceComposer.executeRequest(config)
156
+ -> mock? (enabled only when its request hook exists and matches)
157
+ -> headers (locale / timezone / optional protocol header)
158
+ -> jwt (token lookup / attach / maybe refresh)
159
+ -> performAction (server-side SSR short-circuit when matched)
160
+ -> body? (usually no request hook)
161
+ -> network request or SSR action result
162
+
163
+ response success path
164
+ network / SSR result
165
+ -> ServiceComposer.executeResponse(response)
166
+ -> mock? (usually no success-response hook)
167
+ -> headers? (usually no success-response hook)
168
+ -> jwt? (usually no success-response hook)
169
+ -> performAction? (usually no success-response hook)
170
+ -> body (unwrap { code, message, data } or pass through)
171
+ -> caller receives final data / response
172
+
173
+ response error path
174
+ transport error / response error
175
+ -> ServiceComposer.executeResponseError(error)
176
+ -> mock (may retry against local fake server)
177
+ -> headers? (usually no response-error hook)
178
+ -> jwt? (usually no response-error hook)
179
+ -> performAction? (usually no response-error hook)
180
+ -> body (normalize error.code / error.message)
181
+ -> caller receives final error
182
+ ```
183
+
184
+ This second sketch is still a reading aid rather than a promise that every interceptor participates in every phase. The actual phase participation comes from the concrete hook methods implemented by each interceptor bean.
185
+
186
+ ### 1. `$fetch` is the transport entrypoint
187
+
188
+ `$fetch` is wired in:
189
+
190
+ - `zova/src/suite-vendor/a-zova/modules/a-fetch/src/bean/bean.fetch.ts`
191
+
192
+ This bean:
193
+
194
+ - creates the Axios instance
195
+ - merges the effective Axios config
196
+ - creates `ServiceComposer`
197
+ - installs request and response interceptors on the Axios instance
198
+
199
+ So `$fetch` owns the transport instance, and the interceptor scene is attached there.
200
+
201
+ ### 2. `ServiceComposer` builds the interceptor pipeline
202
+
203
+ The composition logic lives in:
204
+
205
+ - `zova/src/suite-vendor/a-zova/modules/a-fetch/src/service/composer.ts`
206
+
207
+ `ServiceComposer` does four main jobs:
208
+
209
+ 1. load onion slices either from package metadata or from explicit `onionItems`
210
+ 2. instantiate each interceptor bean
211
+ 3. compose four pipelines:
212
+ - request
213
+ - request error
214
+ - response
215
+ - response error
216
+ 4. merge static onion options with per-request dynamic overrides from `config.interceptors[...]`
217
+
218
+ This is one of the most important source files in the whole flow, because it shows that the built-in interceptors are not hardcoded into Axios directly. They are first loaded as onion slices, then executed through the generic composer.
219
+
220
+ ### 3. The generic onion engine handles loading, ordering, and filtering
221
+
222
+ The underlying onion runtime lives in:
223
+
224
+ - `zova/src/suite-vendor/a-zova/modules/a-bean/src/service/onion_.ts`
225
+
226
+ This file shows that onion scenes are generic framework infrastructure. For the interceptor scene, it is responsible for:
227
+
228
+ - reading onion metadata from loaded modules
229
+ - building the full item list
230
+ - reordering items through dependency rules
231
+ - filtering items through `enable` / `match` / `ignore`
232
+ - composing the final chain
233
+
234
+ This is why the interceptor subsystem is best understood as a Zova onion scene first, not as a standalone helper layer.
235
+
236
+ ## The built-in interceptor chain
237
+
238
+ The dependency configuration is declared in:
239
+
240
+ - `zova/src/suite-vendor/a-zova/modules/a-interceptor/package.json`
241
+
242
+ The current built-in chain is:
243
+
244
+ 1. `a-interceptor:mock`
245
+ 2. `a-interceptor:headers`
246
+ 3. `a-interceptor:jwt`
247
+ 4. `a-interceptor:performAction`
248
+ 5. `a-interceptor:body`
249
+
250
+ The package does not encode that order as a simple list. Instead, it encodes dependency rules:
251
+
252
+ - `headers` depends on `mock`
253
+ - `jwt` depends on `headers`
254
+ - `performAction` depends on `jwt`
255
+ - `body` depends on `performAction`
256
+
257
+ That distinction matters because the order is part of the onion dependency model.
258
+
259
+ A source-aligned hook matrix for the current built-ins is:
260
+
261
+ | Interceptor | onRequest | onRequestError | onResponse | onResponseError |
262
+ | --- | --- | --- | --- | --- |
263
+ | `mock` | - | - | - | yes |
264
+ | `headers` | yes | - | - | - |
265
+ | `jwt` | yes | - | - | - |
266
+ | `performAction` | yes | - | - | - |
267
+ | `body` | - | - | yes | yes |
268
+
269
+ This table is only a reading shortcut. The authoritative source is still the concrete bean implementation under `a-interceptor/src/bean/`.
270
+
271
+ ### `mock`
272
+
273
+ Source:
274
+
275
+ - `zova/src/suite-vendor/a-zova/modules/a-interceptor/src/bean/interceptor.mock.ts`
276
+
277
+ Role:
278
+
279
+ - participates in `onResponseError(...)`
280
+ - checks whether mock support is enabled
281
+ - reroutes selected failures such as network failures or 404s to a local fake server
282
+ - preserves API prefix behavior when rebuilding the fallback base URL
283
+
284
+ This makes mock support a transport-layer fallback rather than a page-local workaround.
285
+
286
+ ### `headers`
287
+
288
+ Source:
289
+
290
+ - `zova/src/suite-vendor/a-zova/modules/a-interceptor/src/bean/interceptor.headers.ts`
291
+
292
+ Role:
293
+
294
+ - participates in `onRequest(...)`
295
+ - adds locale header when missing
296
+ - adds timezone header when missing
297
+ - optionally adds the OpenAPI schema protocol header
298
+
299
+ This keeps common request metadata close to `$fetch`, where every request can benefit from it consistently.
300
+
301
+ ### `jwt`
302
+
303
+ Source:
304
+
305
+ - `zova/src/suite-vendor/a-zova/modules/a-interceptor/src/bean/interceptor.jwt.ts`
306
+
307
+ Role:
308
+
309
+ - participates in `onRequest(...)`
310
+ - resolves a JWT adapter bean
311
+ - reads the current token state
312
+ - injects `Authorization: Bearer ...` when available
313
+ - refreshes expired tokens through a deduplicated promise
314
+ - throws 401 in strict-auth cases when a usable token is unavailable
315
+
316
+ This is also where SSR-aware token behavior appears, such as server-side auth-token header signaling.
317
+
318
+ ### `performAction`
319
+
320
+ Source:
321
+
322
+ - `zova/src/suite-vendor/a-zova/modules/a-interceptor/src/bean/interceptor.performAction.ts`
323
+
324
+ Role:
325
+
326
+ - participates in `onRequest(...)`
327
+ - only runs on the server
328
+ - checks whether the current base URL should be handled by SSR `performAction`
329
+ - transforms the fetch call into SSR action input
330
+ - throws the SSR result or SSR error to short-circuit the normal network path
331
+
332
+ This is a strong example of why the interceptor layer must be understood in Zova runtime terms, not only in browser-request terms.
333
+
334
+ ### `body`
335
+
336
+ Source:
337
+
338
+ - `zova/src/suite-vendor/a-zova/modules/a-interceptor/src/bean/interceptor.body.ts`
339
+
340
+ Role:
341
+
342
+ - participates in both `onResponse(...)` and `onResponseError(...)`
343
+ - passes through non-JSON responses
344
+ - unwraps the common JSON envelope shape
345
+ - throws when `code !== 0`
346
+ - maps response errors back onto `error.code` and `error.message`
347
+
348
+ This is the interceptor that turns a lower-level transport response into the simpler data shape many callers expect from `$fetch`.
349
+
350
+ ## Per-request overrides
351
+
352
+ One of the most useful implementation details appears in:
353
+
354
+ - `zova/src/suite-vendor/a-zova/modules/a-fetch/src/service/composer.ts`
355
+
356
+ `ServiceComposer` merges:
357
+
358
+ - the interceptor's static onion options
359
+ - any request-local overrides from `config.interceptors[item.name]`
360
+
361
+ That means a single request can selectively adjust interceptor behavior without changing the module-level registration.
362
+
363
+ In practice, this is where request-scoped `enable`, matching rules, or interceptor-specific options can be adjusted dynamically.
364
+
365
+ ## SSR and mock caveats
366
+
367
+ Two built-in interceptors deserve extra attention when you are tracing runtime behavior.
368
+
369
+ ### SSR caveat
370
+
371
+ `performAction` is server-only.
372
+
373
+ If SSR resolves a matching `performAction` handler, the request can be short-circuited before the normal network call completes. So a server-side `$fetch` path may be executing through SSR action infrastructure rather than through a browser-style remote call.
374
+
375
+ ### Mock caveat
376
+
377
+ `mock` works as a fallback path for selected failures when mock support is enabled.
378
+
379
+ That means mock behavior is not only a matter of authoring `.fake.ts` routes. The transport layer itself can decide to retry against the local fake server under the current runtime conditions.
380
+
381
+ Read this page together with [Mock Guide](/frontend/mock-guide) if you are debugging why a failed request unexpectedly resolves from mock infrastructure.
382
+
383
+ ## Stable contract versus implementation detail
384
+
385
+ The most stable parts of the subsystem are:
386
+
387
+ - `@Interceptor()` as the public authoring decorator
388
+ - the four hook categories
389
+ - the onion-style option model
390
+ - `$fetch` as the transport host
391
+
392
+ More implementation-sensitive details include:
393
+
394
+ - the exact built-in chain order
395
+ - the current response-envelope assumptions in `body`
396
+ - the exact SSR short-circuit shape in `performAction`
397
+ - mock fallback rules and error-code matching
398
+
399
+ When writing framework-facing application code, depend on the stable contract first and treat the implementation details as source-reading guidance.
400
+
401
+ ## Source reading path
402
+
403
+ If you want the shortest practical reading order, use this sequence:
404
+
405
+ 1. `zova/src/suite-vendor/a-zova/modules/a-interceptor/src/.metadata/index.ts`
406
+ - confirms the public interceptor set and type registration
407
+ 2. `zova/src/suite-vendor/a-zova/modules/a-fetch/src/types/interceptor.ts`
408
+ - shows the public hook and option contracts
409
+ 3. `zova/src/suite-vendor/a-zova/modules/a-fetch/src/lib/interceptor.ts`
410
+ - shows how the decorator becomes a bean scene
411
+ 4. `zova/src/suite-vendor/a-zova/modules/a-fetch/src/bean/bean.fetch.ts`
412
+ - shows where `$fetch` creates and attaches the runtime
413
+ 5. `zova/src/suite-vendor/a-zova/modules/a-fetch/src/service/composer.ts`
414
+ - shows loading, instantiation, composition, and per-request override merge
415
+ 6. `zova/src/suite-vendor/a-zova/modules/a-bean/src/service/onion_.ts`
416
+ - shows the generic onion engine
417
+ 7. the concrete built-in beans under `a-interceptor/src/bean/`
418
+ - show the behavior of `mock`, `headers`, `jwt`, `performAction`, and `body`
419
+
420
+ ## Read together with
421
+
422
+ These guides provide the best neighboring context:
423
+
424
+ - [Server Data](/frontend/server-data)
425
+ - [API Guide](/frontend/api-guide)
426
+ - [Mock Guide](/frontend/mock-guide)
427
+ - [IoC and Beans](/frontend/ioc-and-beans)
428
+ - [Behavior Guide](/frontend/behavior-guide)
429
+ - [Zova Source Reading Map](/frontend/zova-source-reading-map)
430
+
431
+ ## Verification checklist for source readers
432
+
433
+ When you use this page to reason about current behavior, verify:
434
+
435
+ 1. the interceptor order still matches `a-interceptor/package.json`
436
+ 2. the hook contracts in `a-fetch/src/types/interceptor.ts` still match the described flow
437
+ 3. `ServiceComposer` still merges `config.interceptors[...]` into the final onion options
438
+ 4. the built-in bean roles still match their current source files
439
+
440
+ That keeps the explanation tied to current source rather than to stale assumptions.