cabloy 5.1.98 → 5.1.100
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.
- package/.cabloy-version +1 -1
- package/.claude/hooks/contract-loop-gate.ts +151 -44
- package/CHANGELOG.md +28 -0
- package/CLAUDE.md +2 -0
- package/cabloy-docs/.vitepress/config.mjs +4 -0
- package/cabloy-docs/backend/controller-aop-guide.md +0 -1
- package/cabloy-docs/frontend/a-openapi-under-the-hood.md +1 -1
- package/cabloy-docs/frontend/generated-contract-consumption-entry-branch.md +1 -1
- package/cabloy-docs/frontend/generated-contract-consumption-list-branch.md +1 -1
- package/cabloy-docs/frontend/generated-contract-consumption-verify-playbook.md +1 -1
- package/cabloy-docs/frontend/model-resource-owner-pattern.md +1 -1
- package/cabloy-docs/frontend/model-state-guide.md +3 -1
- package/cabloy-docs/frontend/resource-entry-page-deep-dive.md +2 -2
- package/cabloy-docs/frontend/resource-list-page-deep-dive.md +1 -1
- package/cabloy-docs/frontend/rest-resource-source-reading-map.md +2 -2
- package/cabloy-docs/frontend/rest-resource-under-the-hood.md +4 -4
- package/cabloy-docs/frontend/use-state-data-best-practices.md +384 -0
- package/package.json +1 -1
- package/scripts/upgrade.ts +2 -0
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/packages-vona/vona-core/package.json +1 -1
- package/vona/packages-vona/vona-core/src/lib/bean/beanBase.ts +9 -9
- package/vona/packages-vona/vona-mock/package.json +1 -1
- package/vona/pnpm-lock.yaml +56 -56
- package/vona/pnpm-workspace.yaml +1 -1
- package/vona/src/suite/a-training/modules/training-record/src/bean/fileScene.dossierFile.ts +22 -0
- package/vona/src/suite/a-training/modules/training-record/src/bean/meta.version.ts +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordDossierFileView.ts +47 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordSelectResItem.tsx +13 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +13 -0
- package/vona/src/suite/a-training/modules/training-record/src/entity/record.tsx +16 -5
- package/vona/src/suite/a-training/modules/training-record/src/index.ts +2 -0
- package/vona/src/suite/a-training/modules/training-record/src/lib/index.ts +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/lib/resolveDossierFiles.ts +34 -0
- package/vona/src/suite/a-training/modules/training-record/test/record.test.ts +209 -123
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/detailRecordBase.tsx +18 -1
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +0 -2
- package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +1 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/package.json +5 -3
- package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/bean.fileUploadPolicy.ts +28 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/controller/file.ts +8 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadPolicyRequest.ts +15 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadPolicyResponse.ts +30 -0
- package/vona/src/suite-vendor/a-file/package.json +2 -2
- package/vona/src/suite-vendor/a-image/modules/a-image/package.json +1 -1
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.imageUploadPolicy.ts +27 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/controller/image.ts +8 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadPolicyRequest.ts +15 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadPolicyResponse.ts +27 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/package.json +1 -1
- package/vona/src/suite-vendor/a-image/modules/image-native/src/controller/image.ts +1 -1
- package/vona/src/suite-vendor/a-image/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/.metadata/index.ts +24 -9
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +87 -73
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permissionActionByRoles.ts +27 -0
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permissionUser.ts +20 -0
- package/vona/src/suite-vendor/a-vona/modules/a-startup/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-startup/src/service/startup.ts +4 -3
- package/vona/src/suite-vendor/a-vona/modules/a-upload/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-upload/src/bean/interceptor.upload.ts +5 -1
- package/vona/src/suite-vendor/a-vona/modules/a-user/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-user/src/.metadata/index.ts +0 -13
- package/vona/src/suite-vendor/a-vona/modules/a-user/src/lib/passport.ts +0 -7
- package/vona/src/suite-vendor/a-vona/modules/a-version/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-version/src/bean/meta.version.ts +2 -24
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/packages-utils/zova-jsx/package.json +2 -2
- package/zova/packages-zova/zova/package.json +3 -3
- package/zova/packages-zova/zova-core/package.json +1 -1
- package/zova/packages-zova/zova-core/src/bean/beanBase.ts +9 -13
- package/zova/pnpm-lock.yaml +24 -9
- package/zova/src/suite/a-demo/modules/demo-basic/src/page/toolOne/controller.tsx +2 -2
- package/zova/src/suite/a-demo/modules/demo-todo/src/page/todo/controller.tsx +2 -2
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx +2 -2
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx +2 -2
- package/zova/src/suite/a-home/modules/home-login/src/page/login/controller.tsx +2 -2
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockDetails/controller.tsx +5 -1
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockTable/controller.tsx +20 -15
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/service/detail.tsx +6 -1
- package/zova/src/suite/cabloy-basic/modules/basic-file/cli/openapi.config.ts +9 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/package.json +58 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/component/formFieldFile.ts +31 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/index.ts +222 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/locales.ts +7 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/this.ts +2 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/file.ts +121 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/baseURL.ts +5 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/index.ts +3 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/schemas.ts +306 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/types.ts +5718 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/apiSchema/file.ts +40 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/bean/tableCell.file.tsx +187 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/component/formFieldFile/controller.tsx +534 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/config/locale/en-us.ts +15 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/config/locale/zh-cn.ts +15 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/index.ts +4 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/lib/file.ts +74 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/lib/index.ts +1 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/model/file.ts +23 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/types/file.ts +12 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/types/index.ts +1 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/tsconfig.build.json +13 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/tsconfig.json +5 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/.metadata/index.ts +61 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/image.ts +38 -1
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/imageNativeImage.ts +31 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/schemas.ts +52 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/types.ts +614 -1
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/apiSchema/image.ts +10 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/apiSchema/imageNativeImage.ts +13 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/component/formFieldImage/controller.tsx +126 -53
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/model/image.ts +23 -0
- package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx +44 -4
- package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsx +17 -12
- package/zova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockPageEntry/controller.tsx +2 -2
- package/zova/src/suite/cabloy-basic/modules/basic-resource/src/component/formFieldResourcePicker/controller.tsx +2 -2
- package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/controller.tsx +7 -2
- package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/render.tsx +34 -33
- package/zova/src/suite/cabloy-basic/package.json +1 -0
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +5 -3
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/entry/controller.tsx +2 -2
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/resource/controller.tsx +2 -2
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-model/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-model/src/lib/utils.ts +17 -17
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +8 -3
- package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/package.json +4 -4
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permission.ts +0 -17
- package/vona/src/suite-vendor/a-vona/modules/a-user/src/bean/guard.userName.ts +0 -35
- /package/vona/patches/{zova-core@5.1.76.patch → zova-core@5.1.77.patch} +0 -0
package/.cabloy-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.1.
|
|
1
|
+
5.1.100
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync, statSync, writeFileSync
|
|
2
|
+
import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { spawnSync, type SpawnSyncReturns } from 'node:child_process';
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
@@ -21,6 +21,25 @@ interface SyncStateEntry {
|
|
|
21
21
|
timestamp: number;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
interface CommandPlan {
|
|
25
|
+
args: readonly string[];
|
|
26
|
+
display: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface EditionConfig {
|
|
30
|
+
id: 'basic' | 'start';
|
|
31
|
+
label: string;
|
|
32
|
+
reverseVonaContentMarkers: readonly string[];
|
|
33
|
+
reverseAutoSyncCommands: readonly CommandPlan[];
|
|
34
|
+
reverseWebBuildCommand: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type ReverseSyncOutcome =
|
|
38
|
+
| { kind: 'not-applicable'; message: string }
|
|
39
|
+
| { kind: 'skipped'; message: string }
|
|
40
|
+
| { kind: 'success'; message: string }
|
|
41
|
+
| { kind: 'failure'; message: string };
|
|
42
|
+
|
|
24
43
|
type SyncState = Record<string, SyncStateEntry>;
|
|
25
44
|
|
|
26
45
|
const SCRIPT_FILE = fileURLToPath(import.meta.url);
|
|
@@ -45,13 +64,10 @@ const FORWARD_PATH_MARKERS = ['/controller/', '/dto/', '/entity/'];
|
|
|
45
64
|
|
|
46
65
|
const FORWARD_CONTENT_MARKERS = ['@Web.', '@Api.field', '@Api.body', 'v.openapi(', '@Dto<'];
|
|
47
66
|
|
|
48
|
-
const
|
|
49
|
-
'zova-rest-cabloy-basic-admin',
|
|
67
|
+
const SHARED_REVERSE_VONA_CONTENT_MARKERS = [
|
|
50
68
|
'ZovaRender.',
|
|
51
69
|
'tableActionRow(',
|
|
52
70
|
'tableActionBulk(',
|
|
53
|
-
'ZovaRender.field(',
|
|
54
|
-
'ZovaRender.cell(',
|
|
55
71
|
];
|
|
56
72
|
|
|
57
73
|
const REVERSE_ZOVA_PATH_MARKERS = ['/src/bean/', '/src/component/', '/src/.metadata/'];
|
|
@@ -64,6 +80,35 @@ const REVERSE_ZOVA_CONTENT_MARKERS = [
|
|
|
64
80
|
'@Component<',
|
|
65
81
|
];
|
|
66
82
|
|
|
83
|
+
const REVERSE_AUTO_SYNC_COMMANDS: readonly CommandPlan[] = [
|
|
84
|
+
{ args: ['run', 'build:zova:admin'], display: 'npm run build:zova:admin' },
|
|
85
|
+
{ args: ['run', 'deps:vona'], display: 'npm run deps:vona' },
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
const EDITION_CONFIGS: Record<'basic' | 'start', EditionConfig> = {
|
|
89
|
+
basic: {
|
|
90
|
+
id: 'basic',
|
|
91
|
+
label: 'Cabloy Basic',
|
|
92
|
+
reverseVonaContentMarkers: ['zova-rest-cabloy-basic-admin'],
|
|
93
|
+
reverseAutoSyncCommands: REVERSE_AUTO_SYNC_COMMANDS,
|
|
94
|
+
reverseWebBuildCommand: 'npm run build:zova:web',
|
|
95
|
+
},
|
|
96
|
+
start: {
|
|
97
|
+
id: 'start',
|
|
98
|
+
label: 'Cabloy Start',
|
|
99
|
+
reverseVonaContentMarkers: ['zova-rest-cabloy-start-admin'],
|
|
100
|
+
reverseAutoSyncCommands: REVERSE_AUTO_SYNC_COMMANDS,
|
|
101
|
+
reverseWebBuildCommand: 'npm run build:zova:web',
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const ACTIVE_EDITION = resolveEdition();
|
|
106
|
+
const FALLBACK_REVERSE_VONA_CONTENT_MARKERS = [
|
|
107
|
+
...SHARED_REVERSE_VONA_CONTENT_MARKERS,
|
|
108
|
+
...EDITION_CONFIGS.basic.reverseVonaContentMarkers,
|
|
109
|
+
...EDITION_CONFIGS.start.reverseVonaContentMarkers,
|
|
110
|
+
];
|
|
111
|
+
|
|
67
112
|
function toPosixPath(value: string): string {
|
|
68
113
|
return value.split(path.sep).join('/');
|
|
69
114
|
}
|
|
@@ -78,6 +123,21 @@ function normalizePath(value?: string): string | null {
|
|
|
78
123
|
}
|
|
79
124
|
}
|
|
80
125
|
|
|
126
|
+
function resolveEdition(): EditionConfig | null {
|
|
127
|
+
if (existsSync(path.resolve(ROOT, '__CABLOY_BASIC__'))) {
|
|
128
|
+
return EDITION_CONFIGS.basic;
|
|
129
|
+
}
|
|
130
|
+
if (existsSync(path.resolve(ROOT, '__CABLOY_START__'))) {
|
|
131
|
+
return EDITION_CONFIGS.start;
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function getReverseVonaContentMarkers(edition: EditionConfig | null): readonly string[] {
|
|
137
|
+
if (!edition) return FALLBACK_REVERSE_VONA_CONTENT_MARKERS;
|
|
138
|
+
return [...SHARED_REVERSE_VONA_CONTENT_MARKERS, ...edition.reverseVonaContentMarkers];
|
|
139
|
+
}
|
|
140
|
+
|
|
81
141
|
function isCodeFile(filePath: string): boolean {
|
|
82
142
|
return TARGET_PATTERNS.some(([prefix, suffix]) => filePath.includes(prefix) && filePath.endsWith(suffix));
|
|
83
143
|
}
|
|
@@ -98,8 +158,12 @@ function detectForward(filePath: string, content: string): string | null {
|
|
|
98
158
|
return null;
|
|
99
159
|
}
|
|
100
160
|
|
|
101
|
-
function detectReverse(
|
|
102
|
-
|
|
161
|
+
function detectReverse(
|
|
162
|
+
filePath: string,
|
|
163
|
+
content: string,
|
|
164
|
+
reverseVonaContentMarkers: readonly string[],
|
|
165
|
+
): string | null {
|
|
166
|
+
if (filePath.includes('/vona/src/') && containsAny(content, reverseVonaContentMarkers)) {
|
|
103
167
|
return 'Vona code is consuming frontend metadata or render resources.';
|
|
104
168
|
}
|
|
105
169
|
if (
|
|
@@ -112,10 +176,10 @@ function detectReverse(filePath: string, content: string): string | null {
|
|
|
112
176
|
return null;
|
|
113
177
|
}
|
|
114
178
|
|
|
115
|
-
function analyze(filePath: string, content: string): AnalysisResult {
|
|
179
|
+
function analyze(filePath: string, content: string, edition: EditionConfig | null): AnalysisResult {
|
|
116
180
|
return {
|
|
117
181
|
forwardReason: detectForward(filePath, content),
|
|
118
|
-
reverseReason: detectReverse(filePath, content),
|
|
182
|
+
reverseReason: detectReverse(filePath, content, getReverseVonaContentMarkers(edition)),
|
|
119
183
|
};
|
|
120
184
|
}
|
|
121
185
|
|
|
@@ -180,9 +244,9 @@ function markAutoSync(filePath: string): void {
|
|
|
180
244
|
saveState(state);
|
|
181
245
|
}
|
|
182
246
|
|
|
183
|
-
function runNpm(args: string[]): SpawnSyncReturns<string> {
|
|
247
|
+
function runNpm(args: readonly string[]): SpawnSyncReturns<string> {
|
|
184
248
|
const command = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
185
|
-
return spawnSync(command, args, {
|
|
249
|
+
return spawnSync(command, [...args], {
|
|
186
250
|
cwd: ROOT,
|
|
187
251
|
encoding: 'utf8',
|
|
188
252
|
});
|
|
@@ -205,22 +269,79 @@ function summarizeProcess(result: SpawnSyncReturns<string>): string {
|
|
|
205
269
|
return `exit ${exitCode}: ${tail}`;
|
|
206
270
|
}
|
|
207
271
|
|
|
208
|
-
function autoSyncReverse(filePath: string):
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
272
|
+
function autoSyncReverse(filePath: string, edition: EditionConfig): ReverseSyncOutcome {
|
|
273
|
+
for (const command of edition.reverseAutoSyncCommands) {
|
|
274
|
+
const result = runNpm(command.args);
|
|
275
|
+
if (result.status !== 0) {
|
|
276
|
+
return {
|
|
277
|
+
kind: 'failure',
|
|
278
|
+
message: `Auto-sync failed during \`${command.display}\`: ${summarizeProcess(result)}`,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
markAutoSync(filePath);
|
|
284
|
+
const commands = edition.reverseAutoSyncCommands.map(command => `\`${command.display}\``).join(' and ');
|
|
285
|
+
return {
|
|
286
|
+
kind: 'success',
|
|
287
|
+
message: `Auto-sync ran ${commands} for this ${edition.label} reverse-chain edit.`,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function buildReverseGuidance(edition: EditionConfig | null): string {
|
|
292
|
+
if (!edition) {
|
|
293
|
+
return 'If backend tooling or backend metadata will consume this handoff, refresh generated metadata when applicable, resolve the active Cabloy edition marker before choosing the relevant Zova build and generated-output path, and then run `npm run deps:vona`.';
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const autoSyncCommands = edition.reverseAutoSyncCommands
|
|
297
|
+
.map(command => `\`${command.display}\``)
|
|
298
|
+
.join(', then ');
|
|
299
|
+
return `If backend tooling or backend metadata will consume this handoff, refresh generated metadata when applicable, run ${autoSyncCommands}, and also run \`${edition.reverseWebBuildCommand}\` when the Web flavor is affected in this ${edition.label} repo.`;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function resolveReverseSyncOutcome(
|
|
303
|
+
filePath: string,
|
|
304
|
+
result: AnalysisResult,
|
|
305
|
+
edition: EditionConfig | null,
|
|
306
|
+
): ReverseSyncOutcome {
|
|
307
|
+
if (!result.reverseReason) {
|
|
308
|
+
return {
|
|
309
|
+
kind: 'not-applicable',
|
|
310
|
+
message: '',
|
|
311
|
+
};
|
|
212
312
|
}
|
|
213
313
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
314
|
+
if (!isHighConfidenceReverseSource(filePath)) {
|
|
315
|
+
return {
|
|
316
|
+
kind: 'not-applicable',
|
|
317
|
+
message:
|
|
318
|
+
'Auto-sync did not run because this reverse-chain signal came from the consumer side rather than a high-confidence frontend source edit.',
|
|
319
|
+
};
|
|
217
320
|
}
|
|
218
321
|
|
|
219
|
-
|
|
220
|
-
|
|
322
|
+
if (shouldSkipAutoSync(filePath)) {
|
|
323
|
+
return {
|
|
324
|
+
kind: 'skipped',
|
|
325
|
+
message: 'Auto-sync skipped because the same reverse-source edit was already synced recently in this repo.',
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (!edition) {
|
|
330
|
+
return {
|
|
331
|
+
kind: 'not-applicable',
|
|
332
|
+
message:
|
|
333
|
+
'Auto-sync did not run because the active Cabloy edition marker could not be resolved for this repo.',
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return autoSyncReverse(filePath, edition);
|
|
221
338
|
}
|
|
222
339
|
|
|
223
|
-
function buildMessages(
|
|
340
|
+
function buildMessages(
|
|
341
|
+
result: AnalysisResult,
|
|
342
|
+
edition: EditionConfig | null,
|
|
343
|
+
reverseSyncOutcome: ReverseSyncOutcome,
|
|
344
|
+
): string {
|
|
224
345
|
const messages = ["Contract-loop gate: this change may affect Cabloy's bidirectional contract loop."];
|
|
225
346
|
|
|
226
347
|
if (result.forwardReason) {
|
|
@@ -233,30 +354,15 @@ function buildMessages(filePath: string, result: AnalysisResult): string {
|
|
|
233
354
|
}
|
|
234
355
|
|
|
235
356
|
if (result.reverseReason) {
|
|
236
|
-
messages.push(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
messages.push('Auto-sync skipped because the same reverse-source edit was already synced recently in this repo.');
|
|
242
|
-
} else {
|
|
243
|
-
const [ok, detail] = autoSyncReverse(filePath);
|
|
244
|
-
messages.push(detail);
|
|
245
|
-
if (!ok) {
|
|
246
|
-
messages.push(
|
|
247
|
-
'Please review the failure before continuing. If generated artifacts already contain the expected changes but consumers still behave stale, suspect local dependency drift before making more source edits.',
|
|
248
|
-
);
|
|
249
|
-
return messages.join(' ');
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
} else {
|
|
357
|
+
messages.push(`Reverse chain: ${result.reverseReason} ${buildReverseGuidance(edition)}`);
|
|
358
|
+
if (reverseSyncOutcome.message) {
|
|
359
|
+
messages.push(reverseSyncOutcome.message);
|
|
360
|
+
}
|
|
361
|
+
if (reverseSyncOutcome.kind === 'failure') {
|
|
253
362
|
messages.push(
|
|
254
|
-
'
|
|
363
|
+
'Please review the failure before continuing. If generated artifacts already contain the expected changes but consumers still behave stale, suspect local dependency drift before making more source edits.',
|
|
255
364
|
);
|
|
256
365
|
}
|
|
257
|
-
messages.push(
|
|
258
|
-
'For Cabloy Start, apply the same reverse-chain logic but resolve the Start-specific flavor names and generated-output paths from the active Start repo before executing edition-specific steps.',
|
|
259
|
-
);
|
|
260
366
|
}
|
|
261
367
|
|
|
262
368
|
return messages.join(' ');
|
|
@@ -277,10 +383,11 @@ function runClaudeHook(): number {
|
|
|
277
383
|
const content = readText(filePath);
|
|
278
384
|
if (content === null) return 0;
|
|
279
385
|
|
|
280
|
-
const result = analyze(filePath, content);
|
|
386
|
+
const result = analyze(filePath, content, ACTIVE_EDITION);
|
|
281
387
|
if (!hasSignal(result)) return 0;
|
|
282
388
|
|
|
283
|
-
const
|
|
389
|
+
const reverseSyncOutcome = resolveReverseSyncOutcome(filePath, result, ACTIVE_EDITION);
|
|
390
|
+
const message = buildMessages(result, ACTIVE_EDITION, reverseSyncOutcome);
|
|
284
391
|
console.log(
|
|
285
392
|
JSON.stringify({
|
|
286
393
|
hookSpecificOutput: {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.100
|
|
4
|
+
|
|
5
|
+
### Improvements
|
|
6
|
+
|
|
7
|
+
- Refresh the Zova lockfile after compensation rerun preparation.
|
|
8
|
+
- Refresh the Vona `zova-core` patch for v5.1.77.
|
|
9
|
+
|
|
10
|
+
## 5.1.99
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- Add dossier files to training records.
|
|
15
|
+
- Derive dossier file policy from the file scene.
|
|
16
|
+
|
|
17
|
+
### Improvements
|
|
18
|
+
|
|
19
|
+
- Rename and standardize `QueryAutoLoad` helpers.
|
|
20
|
+
- Use `QueryAutoLoad` for upload policy handling.
|
|
21
|
+
- Simplify the contract loop hook.
|
|
22
|
+
- Share Claude assets across editions.
|
|
23
|
+
- Split permission cache beans for clearer responsibility.
|
|
24
|
+
- Clarify permission action method names.
|
|
25
|
+
- Align default permission guard evaluation.
|
|
26
|
+
- Reuse derived upload policy state.
|
|
27
|
+
- Streamline upload policy queries.
|
|
28
|
+
- Derive image policy from the image scene.
|
|
29
|
+
- Generate the file SDK and move policy state into the model.
|
|
30
|
+
|
|
3
31
|
## 5.1.98
|
|
4
32
|
|
|
5
33
|
### Features
|
package/CLAUDE.md
CHANGED
|
@@ -53,6 +53,8 @@ Before inventing a custom implementation path:
|
|
|
53
53
|
- For frontend work, assume Cabloy Basic and Cabloy Start share a frontend engineering layer but may diverge in UI layer, frontend flavors, suite/module availability, SSR site baselines, project assets, and generated outputs.
|
|
54
54
|
- For Zova frontend analysis, do not default to generic Vue reinterpretation first. Read the code through Zova’s controller / bean / IoC architecture before mapping it to Vue concepts.
|
|
55
55
|
- For Zova source-reading or Vue-vs-Zova explanation tasks, start from the frontend reading guides and source-reading map in `cabloy-docs/frontend/` before doing framework-neutral reinterpretation.
|
|
56
|
+
- For frontend async state that affects rendering or interaction across consumers, prefer model-owned `$useStateData(...)` over controller-managed fetch/cache state.
|
|
57
|
+
- Default to establishing such query state during render. Use `disableSuspenseOnInit: true` only for relatively stable query-backed state when you want to skip the init-time `query.suspense()` kick; if strict readiness is needed later, wait explicitly at the interaction boundary.
|
|
56
58
|
- Keep repo-wide AI rules in `CLAUDE.md` short and durable; put branching Zova analysis workflows in `.claude/skills/`.
|
|
57
59
|
- For SSR theme-sensitive frontend work, detect the active edition marker and UI library before making assumptions. Cabloy Basic currently means DaisyUI + Tailwind CSS assumptions; Cabloy Start currently means Vuetify assumptions.
|
|
58
60
|
- In Web SSR without cookie-backed theme resolution, do not treat server reads of `$theme.dark`, `$theme.darkMode`, or `$token` as final browser truth. Keep theme-sensitive SSR branching hydration-tolerant or defer final theme-sensitive decisions to the client.
|
|
@@ -485,6 +485,10 @@ export default defineConfig({
|
|
|
485
485
|
text: 'Resource Models & CRUD',
|
|
486
486
|
items: [
|
|
487
487
|
{ text: 'Model State Guide', link: '/frontend/model-state-guide' },
|
|
488
|
+
{
|
|
489
|
+
text: '`$useStateData` Best Practices',
|
|
490
|
+
link: '/frontend/use-state-data-best-practices',
|
|
491
|
+
},
|
|
488
492
|
{
|
|
489
493
|
text: 'Model Resource Owner Pattern',
|
|
490
494
|
link: '/frontend/model-resource-owner-pattern',
|
|
@@ -131,7 +131,7 @@ The source confirms that:
|
|
|
131
131
|
|
|
132
132
|
- bootstrap data is loaded first
|
|
133
133
|
- permissions are then loaded through `getPermissions(resource)`
|
|
134
|
-
- on the server, permissions are
|
|
134
|
+
- on the server, permissions are ensured loaded as part of the bootstrap path
|
|
135
135
|
- on the client, permission queries are refetched when needed
|
|
136
136
|
|
|
137
137
|
That means bootstrap and permissions are part of the same lower-level OpenAPI/runtime ladder, not unrelated utilities.
|
|
@@ -121,7 +121,7 @@ Representative source facts:
|
|
|
121
121
|
|
|
122
122
|
- the page resolves `$$modelResource` from the route resource
|
|
123
123
|
- it derives `formMeta` from `formScene`
|
|
124
|
-
- it
|
|
124
|
+
- it ensures `this.$$modelResource.getFormApiSchemas(this.formMeta)?.sdk` is loaded
|
|
125
125
|
- it derives `formSchema` from `this.$$modelResource.getFormSchema(this.formMeta)`
|
|
126
126
|
|
|
127
127
|
This is the entry-shell boundary:
|
|
@@ -94,7 +94,7 @@ The clearest current list shell is:
|
|
|
94
94
|
Representative source facts:
|
|
95
95
|
|
|
96
96
|
- the page resolves `$$modelResource` from the route resource
|
|
97
|
-
- `__init__()`
|
|
97
|
+
- `__init__()` ensures `this.$$modelResource.apiSchemasSelect.sdk` is loaded
|
|
98
98
|
- render reads `schemaRow?.rest?.blocks`
|
|
99
99
|
|
|
100
100
|
This is the list-shell boundary:
|
|
@@ -117,7 +117,7 @@ Primary anchors:
|
|
|
117
117
|
What to prove:
|
|
118
118
|
|
|
119
119
|
- the list route shell resolves the expected `resource`
|
|
120
|
-
- `apiSchemasSelect.sdk` still
|
|
120
|
+
- `apiSchemasSelect.sdk` is still ensured loaded where expected
|
|
121
121
|
- `schemaRow`, `schemaFilter`, and list data flow are still exposed correctly
|
|
122
122
|
- `basic-page:blockPage` still becomes the deeper list runtime owner
|
|
123
123
|
|
|
@@ -162,7 +162,7 @@ protected async __init__(resource: string) {
|
|
|
162
162
|
And `_bootstrap()` uses:
|
|
163
163
|
|
|
164
164
|
```typescript
|
|
165
|
-
const queryBootstrap = await $
|
|
165
|
+
const queryBootstrap = await $QueryEnsureLoaded(() => this.$sdk.getBootstrap(this.resource));
|
|
166
166
|
```
|
|
167
167
|
|
|
168
168
|
Then it resolves:
|
|
@@ -10,6 +10,8 @@ If you specifically want the scalable resource-facade pattern, continue with [Mo
|
|
|
10
10
|
|
|
11
11
|
If you want the generic lower-level model runtime beneath these helper families, continue with [A-Model Under the Hood](/frontend/a-model-under-the-hood).
|
|
12
12
|
|
|
13
|
+
If your main question is how to design and review `$useStateData(...)` usage itself, continue with [`$useStateData` Best Practices](/frontend/use-state-data-best-practices).
|
|
14
|
+
|
|
13
15
|
If you want to understand how that owner pattern expands into the whole `rest-resource` module runtime, continue with [Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood), then [Rest Resource Source Reading Map](/frontend/rest-resource-source-reading-map).
|
|
14
16
|
|
|
15
17
|
If you want to apply that pattern in your own module with a more uniform two-usage model, continue with [Using `ModelResource` in Your Module](/frontend/model-resource-usage-guide).
|
|
@@ -346,7 +348,7 @@ A plain CRUD helper usually forwards requests.
|
|
|
346
348
|
|
|
347
349
|
It owns several resource-level concerns together:
|
|
348
350
|
|
|
349
|
-
- bootstrap of resource metadata through `$
|
|
351
|
+
- bootstrap of resource metadata through `$QueryEnsureLoaded(...)`
|
|
350
352
|
- resolution of the final `resourceApi`
|
|
351
353
|
- permissions lookup
|
|
352
354
|
- OpenAPI schema access for view/create/update/select
|
|
@@ -110,7 +110,7 @@ Its main jobs are:
|
|
|
110
110
|
- derive `formMeta`
|
|
111
111
|
- resolve `formProvider`
|
|
112
112
|
- resolve `formSchema`
|
|
113
|
-
-
|
|
113
|
+
- ensure form API schemas are loaded
|
|
114
114
|
- render `formSchema?.rest?.blocks`
|
|
115
115
|
|
|
116
116
|
This is the first key architectural boundary:
|
|
@@ -154,7 +154,7 @@ Its main jobs are:
|
|
|
154
154
|
- derive `formMeta` and `schemaScene`
|
|
155
155
|
- derive `formProvider`, `formSchema`, and `formData`
|
|
156
156
|
- prepare the shared JSX render context
|
|
157
|
-
-
|
|
157
|
+
- ensure view/query data is loaded
|
|
158
158
|
- own submit flow through `submitData(...)`
|
|
159
159
|
- update page meta through `setPageMeta(...)`
|
|
160
160
|
- expose `$$pageEntry` into the render context for downstream blocks
|
|
@@ -102,7 +102,7 @@ zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/resource/controlle
|
|
|
102
102
|
Its main jobs are:
|
|
103
103
|
|
|
104
104
|
- resolve the current selector-backed `ModelResource`
|
|
105
|
-
-
|
|
105
|
+
- ensure select API schemas are loaded
|
|
106
106
|
- read `schemaRow?.rest?.blocks`
|
|
107
107
|
- render those blocks through `ZovaJsx`
|
|
108
108
|
|
|
@@ -207,7 +207,7 @@ Read:
|
|
|
207
207
|
This controller does three main things:
|
|
208
208
|
|
|
209
209
|
1. resolves the selector-backed `ModelResource` instance from `this.$params.resource`
|
|
210
|
-
2.
|
|
210
|
+
2. ensures `apiSchemasSelect.sdk` is loaded
|
|
211
211
|
3. reads `schemaRow?.rest?.blocks` and renders those blocks through `ZovaJsx`
|
|
212
212
|
|
|
213
213
|
The key point is what it does **not** do.
|
|
@@ -239,7 +239,7 @@ It mainly owns:
|
|
|
239
239
|
- `formMeta` derivation
|
|
240
240
|
- `formProvider` lookup from `ModelResource`
|
|
241
241
|
- `formSchema` lookup from `ModelResource`
|
|
242
|
-
-
|
|
242
|
+
- ensuring the form API schemas are loaded
|
|
243
243
|
- block rendering from `formSchema?.rest?.blocks`
|
|
244
244
|
|
|
245
245
|
Again, the most important insight is what it does **not** fully own.
|
|
@@ -98,7 +98,7 @@ Route record
|
|
|
98
98
|
└─ page-controller shell
|
|
99
99
|
├─ resolves current resource / id / formScene
|
|
100
100
|
├─ resolves selector-backed ModelResource
|
|
101
|
-
├─
|
|
101
|
+
├─ ensures top-level API schema surface is loaded
|
|
102
102
|
└─ reads schemaRow.rest.blocks or formSchema.rest.blocks
|
|
103
103
|
│
|
|
104
104
|
▼
|
|
@@ -255,7 +255,7 @@ zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/resource/controlle
|
|
|
255
255
|
The main jobs of `ControllerPageResource` are:
|
|
256
256
|
|
|
257
257
|
1. resolve the selector-backed model from `this.$params.resource`
|
|
258
|
-
2.
|
|
258
|
+
2. ensure the select API schema is loaded through `this.$$modelResource.apiSchemasSelect.sdk`
|
|
259
259
|
3. read `this.schemaRow?.rest?.blocks`
|
|
260
260
|
4. render those blocks through `ZovaJsx`
|
|
261
261
|
|
|
@@ -291,7 +291,7 @@ The main jobs of `ControllerPageEntry` are:
|
|
|
291
291
|
- derive `formMeta`
|
|
292
292
|
- expose `formProvider` from the model
|
|
293
293
|
- expose `formSchema` from the model
|
|
294
|
-
-
|
|
294
|
+
- ensure the form API schemas are loaded
|
|
295
295
|
- read `formSchema?.rest?.blocks`
|
|
296
296
|
- render those blocks through `ZovaJsx`
|
|
297
297
|
|
|
@@ -366,7 +366,7 @@ That means one generic model class can serve many resources safely, because the
|
|
|
366
366
|
Inside initialization, `_bootstrap()` calls:
|
|
367
367
|
|
|
368
368
|
```typescript
|
|
369
|
-
$
|
|
369
|
+
$QueryEnsureLoaded(() => this.$sdk.getBootstrap(this.resource));
|
|
370
370
|
```
|
|
371
371
|
|
|
372
372
|
and then resolves:
|