cabloy 5.1.72 → 5.1.74

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 (55) hide show
  1. package/.claude/skills/cabloy-backend-scaffold/SKILL.md +3 -1
  2. package/.claude/skills/cabloy-master-detail/SKILL.md +198 -0
  3. package/.claude/skills/cabloy-workflow/SKILL.md +3 -1
  4. package/.gitignore +0 -2
  5. package/CHANGELOG.md +38 -0
  6. package/cabloy-docs/.vitepress/config.mjs +5 -0
  7. package/cabloy-docs/backend/dto-guide.md +1 -1
  8. package/cabloy-docs/backend/dto-infer-generation.md +38 -0
  9. package/cabloy-docs/backend/master-detail-source-reading-map.md +260 -0
  10. package/cabloy-docs/backend/master-detail-workflow.md +174 -23
  11. package/cabloy-docs/backend/relations-guide.md +4 -0
  12. package/lint-staged.config.mjs +0 -1
  13. package/oxfmt.config.ts +0 -1
  14. package/oxlint.config.ts +0 -1
  15. package/package.json +2 -2
  16. package/scripts/init.ts +29 -2
  17. package/vona/oxfmt.config.ts +0 -1
  18. package/vona/oxlint.config.ts +0 -1
  19. package/vona/packages-cli/cabloy-cli/package.json +1 -1
  20. package/vona/packages-cli/cabloy-cli/src/lib/local.common.ts +3 -3
  21. package/vona/packages-cli/cli/package.json +1 -1
  22. package/vona/packages-cli/cli-set-api/package.json +1 -1
  23. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.build.ts +2 -0
  24. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.buildModule.ts +2 -0
  25. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.dev.ts +1 -0
  26. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.tools.deps.ts +10 -23
  27. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.tools.metadata.ts +1 -1
  28. package/vona/packages-vona/vona/package.json +1 -1
  29. package/vona/patches/zova-core@5.1.61.patch +57 -0
  30. package/vona/pnpm-lock.yaml +278 -332
  31. package/vona/pnpm-workspace.yaml +4 -0
  32. package/vona/src/suite/a-training/modules/training-record/src/dto/recordCreate.tsx +1 -1
  33. package/vona/src/suite/a-training/modules/training-record/src/dto/recordUpdate.tsx +1 -1
  34. package/vona/src/suite/a-training/modules/training-record/src/entity/record.tsx +2 -52
  35. package/vona/src/suite/a-training/modules/training-record/src/index.ts +1 -0
  36. package/vona/src/suite/a-training/modules/training-record/src/lib/index.ts +2 -0
  37. package/vona/src/suite/a-training/modules/training-record/src/lib/onEffectForAverageScore.tsx +29 -0
  38. package/vona/src/suite/a-training/modules/training-record/src/lib/onEffectForTrainingRecordSubjects.tsx +26 -0
  39. package/vona/src/suite/a-training/modules/training-student/src/dto/detailRecordBase.tsx +2 -1
  40. package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/package.json +1 -2
  41. package/vona/src/suite/cabloy-basic/modules/basic-siteweb/package.json +1 -2
  42. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
  43. package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +2 -2
  44. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  45. package/zova/env/.env.cabloyBasicAdmin +1 -1
  46. package/zova/env/.env.cabloyBasicWeb +1 -1
  47. package/zova/oxfmt.config.ts +0 -1
  48. package/zova/oxlint.config.ts +0 -1
  49. package/zova/packages-cli/cli/package.json +3 -3
  50. package/zova/packages-cli/cli-set-front/package.json +2 -2
  51. package/zova/packages-zova/zova/package.json +2 -2
  52. package/zova/pnpm-lock.yaml +47 -47
  53. package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.tabs.tsx +2 -2
  54. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  55. package/zova/src/suite-vendor/a-zova/package.json +2 -2
@@ -1,18 +1,43 @@
1
1
  # Master-Detail Workflow
2
2
 
3
- This guide explains how to scaffold a backend master-detail aggregate in the Cabloy monorepo.
3
+ This guide explains how to scaffold and reason about backend detail aggregates in the Cabloy monorepo.
4
+
5
+ Use this page when the business shape is not “two unrelated CRUD resources,” but a parent resource that owns one or more nested detail collections.
6
+
7
+ > [!TIP]
8
+ > For the deep evidence trail behind this workflow, also read [Master-Detail Source Reading Map](/backend/master-detail-source-reading-map).
9
+
10
+ ## What this page covers
11
+
12
+ The current repo already demonstrates three related shapes:
13
+
14
+ 1. **master-detail** — one master resource owns a first-level detail collection
15
+ 2. **nested-detail** — a detail can itself own another detail collection
16
+ 3. **standalone-capable detail resource** — a detail can remain aggregate-owned only, or also keep its own standalone resource surface
17
+
18
+ The strongest current specimen is:
19
+
20
+ - `training-student` -> `training-record` -> `training-recordsubject`
21
+
22
+ A practical reading of that chain is:
23
+
24
+ - `student` is the master resource
25
+ - `record` is a first-level detail under `student`
26
+ - `subject` is a second-level detail under `record`
27
+ - `record` also demonstrates the case where a detail keeps its own standalone CRUD/resource surface
4
28
 
5
29
  ## Why this page matters
6
30
 
7
- Some business shapes are not best expressed as two unrelated CRUD resources.
31
+ Some business shapes are not best expressed as unrelated standalone resources.
8
32
 
9
- A common pattern is:
33
+ A common Cabloy pattern is:
10
34
 
11
35
  - one master resource owns the aggregate lifecycle
12
36
  - one detail resource is edited as a nested collection under the master
13
37
  - the detail may or may not also expose its own standalone resource surface
38
+ - the same structural rule can repeat recursively when a detail becomes the parent of another detail
14
39
 
15
- The `training-student` + `training-record` specimen in the current repo demonstrates this pattern.
40
+ The `training-student` + `training-record` specimen demonstrates the first-level pattern, and the `training-record` + `training-recordsubject` thread demonstrates the recursive second-level pattern.
16
41
 
17
42
  ## Use the generator first
18
43
 
@@ -34,6 +59,8 @@ A practical reading of the arguments is:
34
59
  - `--fk=studentId`: detail-side FK field
35
60
  - `--detailMode=...`: whether the detail keeps a standalone resource surface
36
61
 
62
+ The same structural rule applies recursively when a first-level detail later owns its own nested detail collection.
63
+
37
64
  ## Module naming rule
38
65
 
39
66
  For `--module` and `--detailModule`, use the canonical Vona module relative name such as `training-student` or `training-record`.
@@ -53,9 +80,10 @@ The generator is designed to create the aggregate-detail thread, including:
53
80
  1. master model relation wiring
54
81
  2. master service `include` lifecycle for create/view/update/delete
55
82
  3. master-side nested detail DTOs
56
- 4. built-in `basic-details` UI metadata for row/bulk actions
83
+ 4. built-in `basic-details` UI metadata for nested row/bulk interactions
57
84
  5. detail FK persistence field in the detail entity
58
85
  6. detail schema/index support for the FK
86
+ 7. metadata refresh for both the master module and the detail module
59
87
 
60
88
  This keeps the structural pattern consistent before domain-specific refinement starts.
61
89
 
@@ -73,7 +101,12 @@ In this mode, the detail module remains:
73
101
 
74
102
  - entity/model/meta-based
75
103
  - owned by the master aggregate
76
- - without a standalone controller/service resource surface
104
+ - without a standalone controller/service/DTO resource surface
105
+
106
+ A practical source-backed nuance is:
107
+
108
+ - if the detail resource was just scaffolded for aggregate usage, the standalone controller/service/DTO surface is removed
109
+ - if an existing detail module already has a standalone surface, the generator refuses to silently repurpose it as aggregate-only
77
110
 
78
111
  Choose this mode when the detail is primarily edited only through the master workflow.
79
112
 
@@ -88,7 +121,8 @@ Use:
88
121
  In this mode, the detail module:
89
122
 
90
123
  - still participates in the master aggregate
91
- - keeps or creates its own standalone controller/service resource surface
124
+ - keeps its own standalone controller/service/DTO resource surface
125
+ - can be addressed both through nested editing and through its own independent resource workflow
92
126
 
93
127
  Choose this mode when the detail also needs independent entry points, workflows, or resource-level access outside the master editing flow.
94
128
 
@@ -106,44 +140,161 @@ Use standalone mode when:
106
140
  - external workflows need to query or mutate detail items directly
107
141
  - the detail has user-facing or integration-facing behavior beyond nested editing
108
142
 
109
- ## Specimen mapping
143
+ ## Nested-detail pattern
144
+
145
+ Nested-detail is not a separate special case. It is the same structural idea applied one level lower.
146
+
147
+ The specimen chain is:
148
+
149
+ - `student`
150
+ - `trainingRecords`
151
+ - `trainingRecordSubjects`
152
+
153
+ A practical rule is:
154
+
155
+ - the master owns first-level detail editing
156
+ - a first-level detail can itself own second-level detail editing
157
+ - each level repeats the same relation + DTO + include wiring pattern with the immediate parent as the owner
158
+
159
+ That means `record` is both:
160
+
161
+ - a detail under `student`
162
+ - a parent of `trainingRecordSubjects`
163
+
164
+ ## DTO naming and placement rules
165
+
166
+ The current source shows a consistent naming and placement rule for nested detail DTOs.
167
+
168
+ | Concern | Rule | Example | Boundary |
169
+ | ------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
170
+ | Nested detail DTO naming | Prefix nested detail DTO names with `detail` for immediate recognizability | `detailRecordMutate`, `detailRecordView` | This rule is for nested detail DTOs, not every DTO in the child module |
171
+ | First-level placement | Place first-level detail DTOs beside the parent DTOs that consume them | `training-student/src/dto/studentCreate.tsx` beside `detailRecord*.tsx` | Do not move these DTOs into the child module just because the child also has its own resource |
172
+ | Second-level placement | Place second-level detail DTOs beside the DTOs of their immediate parent | `training-record/src/dto/recordCreate.tsx` beside `detailRecordSubject*.tsx` | Repeat the same rule recursively for deeper levels |
173
+ | Standalone child boundary | A detail resource that keeps its own standalone surface still uses its normal standalone DTO names there | `recordCreate`, `recordUpdate`, `recordView` in `training-record` | Standalone CRUD naming does not replace the nested `detail*` DTO convention |
174
+
175
+ ## DTO naming rule
176
+
177
+ Use the `detail` prefix for nested detail DTOs so the role is explicit in both source and generated contract surfaces.
178
+
179
+ Representative first-level examples:
180
+
181
+ - `detailRecordBase`
182
+ - `detailRecordMutate`
183
+ - `detailRecordResItem`
184
+ - `detailRecordView`
110
185
 
111
- The current specimen maps like this:
186
+ Representative second-level examples:
187
+
188
+ - `detailRecordSubjectBase`
189
+ - `detailRecordSubjectMutate`
190
+ - `detailRecordSubjectResItem`
191
+ - `detailRecordSubjectView`
192
+
193
+ This makes nested detail artifacts easy to distinguish from ordinary standalone CRUD DTOs.
194
+
195
+ ## DTO placement rule
196
+
197
+ Place nested detail DTOs next to the parent DTOs that consume them.
198
+
199
+ That means:
200
+
201
+ - the `student*` DTOs and `detailRecord*` DTOs live together in `training-student/src/dto/`
202
+ - the `record*` DTOs and `detailRecordSubject*` DTOs live together in `training-record/src/dto/`
203
+
204
+ A practical recursive rule is:
205
+
206
+ - first-level detail DTOs belong with the master DTOs
207
+ - second-level detail DTOs belong with the first-level parent DTOs
208
+ - repeat the same rule for deeper levels if the aggregate continues to nest
209
+
210
+ This placement makes the ownership path obvious at the point where nested editing is actually authored.
211
+
212
+ ## `dtoClass` in master-detail DTO wiring
213
+
214
+ The nested DTO thread is not only about naming. The current scaffolded pattern also uses `dtoClass` so the parent DTO keeps aggregate relation wiring while the nested detail DTO class defines the reusable field surface.
215
+
216
+ Representative pattern:
217
+
218
+ - parent DTOs include nested details through `include: { relationName: { dtoClass: DtoDetail... } }`
219
+ - detail DTO families such as `detailRecordBase`, `detailRecordMutate`, and `detailRecordView` define which detail fields are exposed for each scene
220
+ - nested details can repeat the same `dtoClass` pattern recursively one level lower
221
+
222
+ That is why master-detail DTOs do not need to inline long relation column lists everywhere. They can reuse named detail DTO classes instead.
223
+
224
+ For a broader explanation of `dtoClass` as a DTO inference option, also read [DTO Infer and Generation](/backend/dto-infer-generation).
225
+
226
+ ## Specimen walkthrough
227
+
228
+ The current specimen maps like this.
229
+
230
+ ### First-level master-detail: `student -> record`
112
231
 
113
232
  - master relation: `vona/src/suite/a-training/modules/training-student/src/model/student.ts`
114
233
  - master service include lifecycle: `vona/src/suite/a-training/modules/training-student/src/service/student.ts`
115
- - master nested DTOs: `vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx`, `studentUpdate.tsx`, `studentView.tsx`
116
- - detail row/bulk metadata: `vona/src/suite/a-training/modules/training-student/src/dto/detailRecordResItem.tsx`
234
+ - master nested DTO wiring: `vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx`, `studentUpdate.tsx`, `studentView.tsx`
235
+ - first-level detail DTOs: `vona/src/suite/a-training/modules/training-student/src/dto/detailRecordBase.tsx`, `detailRecordMutate.tsx`, `detailRecordResItem.tsx`, `detailRecordView.tsx`
117
236
  - detail FK field: `vona/src/suite/a-training/modules/training-record/src/entity/record.tsx`
237
+ - contract exposure: `vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts`
238
+
239
+ ### Second-level nested-detail: `record -> subject`
240
+
241
+ - detail-as-parent relation: `vona/src/suite/a-training/modules/training-record/src/model/record.ts`
242
+ - detail-as-parent include lifecycle: `vona/src/suite/a-training/modules/training-record/src/service/record.ts`
243
+ - second-level nested DTO wiring: `vona/src/suite/a-training/modules/training-record/src/dto/recordCreate.tsx`, `recordUpdate.tsx`, `recordView.tsx`
244
+ - second-level detail DTOs: `vona/src/suite/a-training/modules/training-record/src/dto/detailRecordSubjectBase.tsx`, `detailRecordSubjectMutate.tsx`, `detailRecordSubjectResItem.tsx`, `detailRecordSubjectView.tsx`
245
+ - contract exposure: `vona/src/suite/a-training/modules/training-record/src/.metadata/index.ts`
246
+
247
+ ### Detail resource that also keeps a standalone resource surface
118
248
 
119
- This is the reference shape the generator aims to standardize.
249
+ The `training-record` module demonstrates the dual-role case.
250
+
251
+ It is simultaneously:
252
+
253
+ - a nested detail under `student`
254
+ - a standalone resource with its own ordinary CRUD DTOs such as `recordCreate`, `recordUpdate`, and `recordView`
255
+
256
+ That is the practical boundary to remember:
257
+
258
+ - nested detail DTOs use `detail*` names in the parent module
259
+ - the child resource can still keep its own ordinary standalone DTO names in its own standalone resource surface
120
260
 
121
261
  ## Recommended workflow
122
262
 
123
263
  1. run `:tools:masterDetail`
124
264
  2. inspect the generated relation, DTO, and service thread
125
- 3. refine entity fields and validation rules for the domain
126
- 4. refine detail columns/actions when the default `basic-details` behavior is not enough
127
- 5. refresh and verify metadata/build outputs
265
+ 3. confirm whether the detail should remain aggregate-only or also stay standalone
266
+ 4. if the detail later becomes a parent of another detail, repeat the same pattern one level lower
267
+ 5. refine entity fields and validation rules for the domain
268
+ 6. refine detail columns/actions when the default `basic-details` behavior is not enough
269
+ 7. refresh and verify metadata/build outputs
128
270
 
129
- ## Relationship to CRUD workflow
271
+ ## Relationship to other docs
130
272
 
131
273
  Use [CRUD Workflow](/backend/crud-workflow) when the target is primarily a standalone resource.
132
274
 
133
- Use this page when the target is a master resource with a nested detail collection.
275
+ Use [Relations Guide](/backend/relations-guide) when the question is about general ORM relation semantics such as `hasMany`, `belongsTo`, `include`, or `with`.
276
+
277
+ Use [Master-Detail Source Reading Map](/backend/master-detail-source-reading-map) when the question becomes “which source files prove the current master-detail and nested-detail behavior?”
278
+
279
+ Use [Contract Loop Playbook](/fullstack/contract-loop-playbook) when the next question crosses the backend/frontend contract boundary.
134
280
 
135
- The two workflows are complementary:
281
+ The workflows are complementary:
136
282
 
137
283
  - CRUD scaffolds standalone backend threads
138
284
  - master-detail scaffolds aggregate ownership plus nested detail editing
285
+ - the source-reading map traces the current evidence trail behind both
139
286
 
140
287
  ## Verification checklist
141
288
 
142
- After generation:
289
+ After generation or documentation changes:
143
290
 
144
- 1. confirm the master model contains the `hasMany` relation
291
+ 1. confirm the master model contains the expected `hasMany` relation
145
292
  2. confirm master service create/view/update/delete includes the detail relation
146
293
  3. confirm master create/update/view DTOs include nested detail DTO wiring
147
- 4. confirm the detail entity contains the FK field
148
- 5. confirm detail schema/index output includes the FK support
149
- 6. if standalone mode was chosen, confirm the detail module still exposes its standalone resource surface
294
+ 4. confirm the nested detail DTO names follow the `detail*` rule
295
+ 5. confirm the nested detail DTOs are placed beside the parent DTOs that consume them
296
+ 6. for second-level nested detail, confirm the same naming and placement rule repeats with the immediate parent
297
+ 7. confirm the detail entity contains the FK field
298
+ 8. confirm detail schema/index output includes the FK support
299
+ 9. confirm the module `.metadata/index.ts` exports the expected nested detail DTOs
300
+ 10. if standalone mode was chosen, confirm the detail module still exposes its standalone resource surface
@@ -106,6 +106,10 @@ await this.scope.model.order.update(
106
106
 
107
107
  This is one of the strongest reasons Cabloy can express CRUD-oriented business flows compactly.
108
108
 
109
+ If the next question becomes specifically about aggregate-owned detail resources, nested-detail recursion, or nested detail DTO naming/placement, continue with [Master-Detail Workflow](/backend/master-detail-workflow).
110
+
111
+ If the next question becomes how a relation-aware DTO should keep a reusable named field surface instead of only inline relation columns, continue with [DTO Infer and Generation](/backend/dto-infer-generation), especially the `dtoClass` guidance.
112
+
109
113
  ## `belongsToMany`
110
114
 
111
115
  `belongsToMany` models `n:n` relations through an intermediate model.
@@ -36,7 +36,6 @@ const OXFMT_IGNORE_PATTERNS = [
36
36
  '**/src-capacitor',
37
37
  '**/src-cordova',
38
38
  // vona-specific
39
- '**/zovaRest',
40
39
  'vona/packages-cli/cli-set-api/cli/templates',
41
40
  // zova-specific
42
41
  'zova/packages-cli/cli-set-front/cli/templates',
package/oxfmt.config.ts CHANGED
@@ -38,7 +38,6 @@ export default defineConfig(
38
38
  '**/src-capacitor',
39
39
  '**/src-cordova',
40
40
  // vona-specific
41
- '**/zovaRest',
42
41
  'vona/packages-cli/cli-set-api/cli/templates',
43
42
  // zova-specific
44
43
  'zova/packages-cli/cli-set-front/cli/templates',
package/oxlint.config.ts CHANGED
@@ -59,7 +59,6 @@ export default defineConfig(
59
59
  '**/src-cordova',
60
60
  '**/package.json',
61
61
  // vona-specific
62
- '**/zovaRest',
63
62
  'vona/packages-cli/cli-set-api/cli/templates',
64
63
  // zova-specific
65
64
  'zova/packages-cli/cli-set-front/cli/templates',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cabloy",
3
- "version": "5.1.72",
3
+ "version": "5.1.74",
4
4
  "gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
5
5
  "description": "A Node.js fullstack framework",
6
6
  "keywords": [
@@ -82,5 +82,5 @@
82
82
  "engines": {
83
83
  "node": ">=24.4.0"
84
84
  },
85
- "packageManager": "pnpm@11.9.0"
85
+ "packageManager": "pnpm@11.5.2"
86
86
  }
package/scripts/init.ts CHANGED
@@ -115,6 +115,32 @@ function writeVersionMarker(): void {
115
115
  console.log(`[init] Marked Cabloy version: ${version}`);
116
116
  }
117
117
 
118
+ function seedVonaZovaRestWorkspaceDependencies(pkgPath: string): void {
119
+ // `package.original.json` intentionally keeps Vona close to a minimal bootstrap state.
120
+ // During `npm run init`, seed the generated `.zova-rest/*` workspace dependencies back into
121
+ // `vona/package.json` before the first install so pnpm sees the `zova -> zova-core`
122
+ // dependency chain and applies the workspace patch instead of reporting it as unused.
123
+ const zovaRestWorkspaceDir = resolve(VONA_DIR, '.zova-rest');
124
+ if (!existsSync(zovaRestWorkspaceDir)) return;
125
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as {
126
+ dependencies?: Record<string, string>;
127
+ };
128
+ pkg.dependencies ??= {};
129
+ let changed = false;
130
+ for (const entry of readdirSync(zovaRestWorkspaceDir, { withFileTypes: true })) {
131
+ if (!entry.isDirectory()) continue;
132
+ const depName = `zova-rest-${entry.name}`;
133
+ const depValue = 'workspace:^';
134
+ if (pkg.dependencies[depName] === depValue) continue;
135
+ pkg.dependencies[depName] = depValue;
136
+ changed = true;
137
+ }
138
+ if (!changed) return;
139
+ writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
140
+ // eslint-disable-next-line
141
+ console.log('[init] Seeded Vona .zova-rest dependencies');
142
+ }
143
+
118
144
  // --- Step 0: Set APP_NAME in .env files ---
119
145
 
120
146
  function setAppName(): void {
@@ -215,6 +241,7 @@ function initVona(): void {
215
241
  const pkgPath = resolve(VONA_DIR, 'package.json');
216
242
  // if (!existsSync(pkgPath)) {
217
243
  copyFileSync(resolve(VONA_DIR, 'package.original.json'), pkgPath);
244
+ seedVonaZovaRestWorkspaceDependencies(pkgPath);
218
245
  pnpmInstall(VONA_DIR);
219
246
  // }
220
247
  exec('npm run vona :tools:deps');
@@ -286,10 +313,10 @@ setAppName();
286
313
  generateEnvProdLocal();
287
314
  generateEnvProdDockerLocal();
288
315
  cleanupWorkspaceYaml();
289
- initVona();
290
316
  initZova();
291
- initCabloyDocs();
292
317
  buildSsrCabloyBasicStartBatch();
318
+ initVona();
319
+ initCabloyDocs();
293
320
  writeVersionMarker();
294
321
  // eslint-disable-next-line
295
322
  console.log('[init] Done!');
@@ -14,7 +14,6 @@ export default defineConfig(
14
14
  '.assets',
15
15
  'coverage',
16
16
  'docker-compose',
17
- 'zovaRest',
18
17
  'assets',
19
18
  '.app',
20
19
  '.claude',
@@ -48,7 +48,6 @@ export default defineConfig(
48
48
  'coverage',
49
49
  'docker-compose',
50
50
  'package.json',
51
- 'zovaRest',
52
51
  'assets',
53
52
  'packages-cli/cli-set-api/cli/templates',
54
53
  ],
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cabloy/cli",
3
- "version": "3.1.26",
3
+ "version": "3.1.27",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "@cabloy/cli",
6
6
  "keywords": [
@@ -153,7 +153,7 @@ export class LocalCommon {
153
153
  }
154
154
  _handleDeps('dependencies', deps);
155
155
  _handleDeps('devDependencies', depsDev);
156
- // zovaRest
156
+ // zova rest workspace
157
157
  await this._generatePackageJson_pkgFromZovaRest(projectPath, pkgOriginal.dependencies);
158
158
  // save
159
159
  if (
@@ -176,7 +176,7 @@ export class LocalCommon {
176
176
  const bundles = await globby('*', { cwd: targetDir, onlyDirectories: true });
177
177
  for (const bundle of bundles) {
178
178
  const name = `zova-rest-${bundle}`;
179
- devDependencies[name] = `file:./.zova-rest/${bundle}`;
179
+ devDependencies[name] = 'workspace:^';
180
180
  }
181
181
  }
182
182
 
@@ -203,7 +203,7 @@ export class LocalCommon {
203
203
  const isZovaRest = key.includes('zova-rest-');
204
204
  const isModule = key.includes('vona-module-') || key.includes('zova-module-');
205
205
  const isModuleWorkspace = isModule && version.startsWith('workspace:');
206
- if (isZovaRest && version.includes('file:')) continue;
206
+ if (isZovaRest) continue;
207
207
  if (isModuleWorkspace) continue;
208
208
  // if (deps[key] && !isModule) continue;
209
209
  if (isModule) continue;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-cli",
3
- "version": "1.1.123",
3
+ "version": "1.1.125",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "vona cli",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-cli-set-api",
3
- "version": "1.1.121",
3
+ "version": "1.1.123",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "vona cli-set-api",
6
6
  "keywords": [
@@ -56,6 +56,8 @@ const __dialectDriversAll = [
56
56
  'pg',
57
57
  'mysql2',
58
58
  'better-sqlite3',
59
+ 'mariadb/callback',
60
+ 'mariadb',
59
61
  'mysql',
60
62
  'oracledb',
61
63
  'pg-native',
@@ -56,6 +56,8 @@ export class CliBinBuildModule extends BeanCliBase {
56
56
  const aliasEntries: aliasImport.Alias[] = [];
57
57
  for (const name of [
58
58
  'better-sqlite3',
59
+ 'mariadb/callback',
60
+ 'mariadb',
59
61
  'mysql',
60
62
  'oracledb',
61
63
  'pg-native',
@@ -51,6 +51,7 @@ export class CliBinDev extends BeanCliBase {
51
51
  cwd: projectPath,
52
52
  exec: 'node',
53
53
  execArgs: [getImportEsm()],
54
+ ext: 'ts,tsx,json',
54
55
  // execArgs: ['--experimental-transform-types', getImportEsm(), '--trace-deprecation'],
55
56
  // signal: 'SIGHUP',
56
57
  watch: ['packages-utils', 'packages-vona', './src'],
@@ -20,7 +20,7 @@ export class CliToolsDeps extends BeanCliBase {
20
20
  }
21
21
 
22
22
  async _generate(projectPath: string) {
23
- // generate zovaRest
23
+ // verify zova rest workspace
24
24
  const needPnpmInstall = await this._generateZovaRest(projectPath);
25
25
  // generate package.json
26
26
  const pnpmInstalled = await this.common._generatePackageJson(projectPath);
@@ -55,29 +55,16 @@ export class CliToolsDeps extends BeanCliBase {
55
55
  }
56
56
 
57
57
  async _generateZovaRest(projectPath: string) {
58
- let needPnpmInstall = false;
59
58
  const targetDir = path.join(projectPath, '.zova-rest');
60
- for (const module of this.modulesMeta.modulesArray) {
61
- const moduleZovaRest = path.join(module.root, 'zovaRest');
62
- if (!fse.existsSync(moduleZovaRest)) continue;
63
- const bundles = await globby('*', { cwd: moduleZovaRest, onlyDirectories: true });
64
- for (const bundle of bundles) {
65
- const moduleZovaRestSrc = path.join(moduleZovaRest, bundle);
66
- const moduleZovaRestDest = path.join(targetDir, bundle);
67
- let needCopy = true;
68
- if (fse.existsSync(moduleZovaRestDest)) {
69
- const statDest = await fse.stat(path.join(moduleZovaRestDest, 'package.json'));
70
- const statSrc = await fse.stat(path.join(moduleZovaRestSrc, 'package.json'));
71
- // diff: 5s
72
- if (statDest.mtimeMs + 5000 >= statSrc.mtimeMs) {
73
- needCopy = false;
74
- }
75
- }
76
- if (!needCopy) continue;
77
- await fse.copy(moduleZovaRestSrc, moduleZovaRestDest, { preserveTimestamps: true });
78
- needPnpmInstall = true;
79
- }
59
+ if (!fse.existsSync(targetDir)) {
60
+ throw new Error(
61
+ 'Zova REST workspace .zova-rest not found. Please run `npm run build:zova:admin` or `npm run build:zova:web` first.',
62
+ );
80
63
  }
81
- return needPnpmInstall;
64
+ const bundles = await globby('*', { cwd: targetDir, onlyDirectories: true });
65
+ if (bundles.length > 0) return false;
66
+ throw new Error(
67
+ 'No Zova REST bundles found in .zova-rest. Please run `npm run build:zova:admin` or `npm run build:zova:web` first.',
68
+ );
82
69
  }
83
70
  }
@@ -286,7 +286,7 @@ export { ScopeModule${relativeNameCapitalize} as ScopeModule } from './index.ts'
286
286
  return pkg;
287
287
  }
288
288
  // cli
289
- for (const name of ['cli', 'zovaRest']) {
289
+ for (const name of ['cli']) {
290
290
  const pathCheck = path.join(modulePath, name);
291
291
  if (!(await fse.pathExists(pathCheck))) continue;
292
292
  pkg = await _loadPkg();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona",
3
- "version": "5.1.60",
3
+ "version": "5.1.61",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "Vona is an intuitive, elegant and powerful Node.js framework for rapidly developing enterprise applications of any size",
6
6
  "keywords": [
@@ -0,0 +1,57 @@
1
+ diff --git a/dist/bean/resource/error/errorGlobal.d.ts b/dist/bean/resource/error/errorGlobal.d.ts
2
+ index 73cebe18f3e260c295bdf42a3d1ab9e86fa2de87..cb0ff5c3b541f646105198ee23ac0fc3d805023e 100644
3
+ --- a/dist/bean/resource/error/errorGlobal.d.ts
4
+ +++ b/dist/bean/resource/error/errorGlobal.d.ts
5
+ @@ -1,9 +1 @@
6
+ -import type { TypeScopesErrorCodes } from '../../type.ts';
7
+ -declare global {
8
+ - export interface Error {
9
+ - code?: TypeScopesErrorCodes | number | undefined;
10
+ - status?: number | string | undefined;
11
+ - }
12
+ -}
13
+ export {};
14
+ -//# sourceMappingURL=errorGlobal.d.ts.map
15
+
16
+ diff --git a/dist/types/interface/module.d.ts b/dist/types/interface/module.d.ts
17
+ index 838e299407218b7bfac469d42a12d6ab59820380..e8b61cc231e39ee3a270ee513ab43ff5a13fc290 100644
18
+ --- a/dist/types/interface/module.d.ts
19
+ +++ b/dist/types/interface/module.d.ts
20
+ @@ -23,12 +23,6 @@ export interface IModuleResource {
21
+ components: TypeModuleResourceComponents;
22
+ }
23
+ export declare const SymbolInstalled: unique symbol;
24
+ -declare module '@cabloy/module-info' {
25
+ - interface IModule {
26
+ - resource: IModuleResource;
27
+ - info: IModuleInfo;
28
+ - }
29
+ -}
30
+ export interface IModuleApp {
31
+ }
32
+ //# sourceMappingURL=module.d.ts.map
33
+
34
+ diff --git a/dist/types/utils/env.d.ts b/dist/types/utils/env.d.ts
35
+ index 708c0a584dfec65b8c7ad2d049156f900de49928..a8caacb276794e3ac70591b974f14d6eee3ac302 100644
36
+ --- a/dist/types/utils/env.d.ts
37
+ +++ b/dist/types/utils/env.d.ts
38
+ @@ -34,19 +34,4 @@ export interface ZovaConfigEnv {
39
+ MOCK_BUILD: string | undefined;
40
+ MOCK_BUILD_PORT: string | undefined;
41
+ }
42
+ -declare global {
43
+ - namespace NodeJS {
44
+ - interface ProcessEnv {
45
+ - NODE_ENV: ZovaMetaMode;
46
+ - META_FLAVOR: ZovaMetaFlavor;
47
+ - META_MODE: ZovaMetaMode;
48
+ - META_APP_MODE: ZovaMetaAppMode;
49
+ - SSR: boolean;
50
+ - DEV: boolean;
51
+ - PROD: boolean;
52
+ - CLIENT: boolean;
53
+ - SERVER: boolean;
54
+ - }
55
+ - }
56
+ -}
57
+ //# sourceMappingURL=env.d.ts.map