cabloy 5.1.179 → 5.1.181

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 (61) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/scheduled_tasks.lock +1 -1
  3. package/CHANGELOG.md +25 -0
  4. package/package.json +1 -1
  5. package/repo-docs/.vitepress/config.mjs +1 -0
  6. package/repo-docs/backend/controller-aop-guide.md +1 -1
  7. package/repo-docs/backend/demonstration-mode-guide.md +130 -0
  8. package/repo-docs/frontend/page-meta-guide.md +91 -13
  9. package/repo-docs/frontend/router-view-hosts-guide.md +37 -0
  10. package/repo-docs/fullstack/framework-performance.md +3 -3
  11. package/vona/packages-cli/cli/package.json +1 -1
  12. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/controller/{{resourceName}}.ts_ +7 -7
  13. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/test/{{resourceName}}.test.ts_ +93 -39
  14. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/snippets/3-en-us.ts +1 -1
  15. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/snippets/4-zh-cn.ts +1 -1
  16. package/vona/packages-cli/cli-set-api/package.json +1 -1
  17. package/vona/packages-vona/vona/package.json +1 -1
  18. package/vona/pnpm-lock.yaml +1965 -2204
  19. package/vona/pnpm-workspace.yaml +1 -1
  20. package/vona/src/suite/a-demo/modules/demo-demonstration/package.json +55 -0
  21. package/vona/src/suite/a-demo/modules/demo-demonstration/src/.metadata/index.ts +68 -0
  22. package/vona/src/suite/a-demo/modules/demo-demonstration/src/.metadata/locales.ts +18 -0
  23. package/vona/src/suite/a-demo/modules/demo-demonstration/src/.metadata/this.ts +2 -0
  24. package/vona/src/suite/a-demo/modules/demo-demonstration/src/bean/guard.demonstration.ts +68 -0
  25. package/vona/src/suite/a-demo/modules/demo-demonstration/src/config/errors.ts +6 -0
  26. package/vona/src/suite/a-demo/modules/demo-demonstration/src/config/locale/en-us.ts +3 -0
  27. package/vona/src/suite/a-demo/modules/demo-demonstration/src/config/locale/zh-cn.ts +3 -0
  28. package/vona/src/suite/a-demo/modules/demo-demonstration/src/index.ts +3 -0
  29. package/vona/src/suite/a-demo/modules/demo-demonstration/src/types/index.ts +8 -0
  30. package/vona/src/suite/a-demo/modules/demo-demonstration/test/guardDemonstration.test.ts +121 -0
  31. package/vona/src/suite/a-demo/modules/demo-demonstration/tsconfig.build.json +11 -0
  32. package/vona/src/suite/a-demo/modules/demo-demonstration/tsconfig.json +7 -0
  33. package/vona/src/suite/a-demo/package.json +2 -1
  34. package/vona/src/suite/a-demo/tsconfig.json +3 -0
  35. package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +9 -0
  36. package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +9 -0
  37. package/vona/src/suite/a-training/modules/training-student/src/controller/student.ts +19 -17
  38. package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +47 -27
  39. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/package.json +1 -1
  40. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/bean/bean.rbacScope.ts +13 -7
  41. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/test/rbacScopeCurrent.test.ts +28 -0
  42. package/vona/src/suite-vendor/a-cabloy/package.json +2 -2
  43. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  44. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  45. package/zova/packages-utils/zova-jsx/package.json +2 -2
  46. package/zova/packages-zova/zova/package.json +3 -3
  47. package/zova/packages-zova/zova-core/package.json +1 -1
  48. package/zova/packages-zova/zova-core/src/bean/type.ts +1 -0
  49. package/zova/packages-zova/zova-core/src/composables/useController.ts +1 -1
  50. package/zova/pnpm-lock.yaml +7 -7
  51. package/zova/src/suite/a-home/modules/home-indexadmin/src/page/dashboard/controller.tsx +26 -7
  52. package/zova/src/suite-vendor/a-zova/modules/a-router/package.json +1 -1
  53. package/zova/src/suite-vendor/a-zova/modules/a-router/src/lib/const.ts +1 -0
  54. package/zova/src/suite-vendor/a-zova/modules/a-router/src/monkey.ts +39 -2
  55. package/zova/src/suite-vendor/a-zova/modules/a-router/src/types/index.ts +1 -0
  56. package/zova/src/suite-vendor/a-zova/modules/a-router/src/types/pageHost.ts +9 -0
  57. package/zova/src/suite-vendor/a-zova/modules/a-router/src/types/router.ts +2 -0
  58. package/zova/src/suite-vendor/a-zova/modules/a-router/test/lib/pageHost.test.ts +53 -0
  59. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  60. package/zova/src/suite-vendor/a-zova/package.json +3 -3
  61. /package/vona/patches/{zova-core@5.1.91.patch → zova-core@5.1.92.patch} +0 -0
@@ -1,12 +1,74 @@
1
1
  import type { Dto<%=argv.resourceNameCapitalize%>Create, Dto<%=argv.resourceNameCapitalize%>SelectRes, Dto<%=argv.resourceNameCapitalize%>Update, Entity<%=argv.resourceNameCapitalize%> } from 'vona-module-<%=argv.moduleInfo.relativeName%>';
2
+
2
3
  import assert from 'node:assert';
3
4
  import { describe, it } from 'node:test';
5
+ import { appMetadata } from 'vona';
4
6
  import { app } from 'vona-mock';
7
+ import { SymbolOpenApiOptions } from 'vona-module-a-openapiutils';
8
+
9
+ describe('<%=argv.resourceName%>.test.ts', { concurrency: false }, () => {
10
+ it('action:<%=argv.resourceName%>:openapiMetadata', async () => {
11
+ await app.bean.executor.mockCtx(async () => {
12
+ const controllerBeanFullName = '<%=argv.moduleInfo.relativeName%>.controller.<%=argv.resourceName%>';
13
+ const controller = app.bean.onion.controller
14
+ .getOnionsEnabledCached()
15
+ .find(item => item.beanOptions.beanFullName === controllerBeanFullName)
16
+ ?.beanOptions.beanClass;
17
+ if (!controller) throw new Error(`${controllerBeanFullName} not found`);
18
+
19
+ const controllerMetadata = appMetadata.getMetadata<any>(
20
+ SymbolOpenApiOptions,
21
+ controller,
22
+ );
23
+ assert.equal(
24
+ controllerMetadata?.summary?.toString(),
25
+ '<%=argv.moduleInfo.relativeName%>::<%=argv.resourceNameCapitalize%>Controller',
26
+ );
27
+
28
+ const expectedSummaries = {
29
+ create: ['post', '<%=argv.moduleActionPathRaw%>', 'Create <%=argv.resourceNameCapitalize%>'],
30
+ select: ['get', '<%=argv.moduleActionPathRaw%>', 'Query <%=argv.resourceNameCapitalize%> List'],
31
+ view: ['get', '<%=argv.moduleActionPathRaw%>/{id}', 'View <%=argv.resourceNameCapitalize%>'],
32
+ update: ['patch', '<%=argv.moduleActionPathRaw%>/{id}', 'Update <%=argv.resourceNameCapitalize%>'],
33
+ delete: ['delete', '<%=argv.moduleActionPathRaw%>/{id}', 'Delete <%=argv.resourceNameCapitalize%>'],
34
+ deleteBulk: ['post', '<%=argv.moduleActionPathRaw%>/bulk/delete', 'Bulk Delete <%=argv.resourceNameCapitalize%>'],
35
+ } as const;
36
+ for (const [action, [method, path, summary]] of Object.entries(expectedSummaries)) {
37
+ const apiJson = await app.bean.openapi.generateJsonOfControllerAction(
38
+ controller,
39
+ action,
40
+ 'V31',
41
+ );
42
+ const operation = (apiJson.paths as any)?.[path]?.[method];
43
+ assert.ok(operation, `${action} operation is missing`);
44
+ assert.equal(operation.summary?.toJSON(), summary);
45
+ }
46
+ });
47
+ });
48
+
49
+ it('action:<%=argv.resourceName%>:rbacCatalog', async () => {
50
+ await app.bean.executor.mockCtx(async () => {
51
+ const controllerBeanFullName = '<%=argv.moduleInfo.relativeName%>.controller.<%=argv.resourceName%>';
52
+ const catalog = app.bean.rbacCatalog.getCatalog();
53
+ const expectedInherits = {
54
+ create: undefined,
55
+ select: undefined,
56
+ view: undefined,
57
+ update: undefined,
58
+ delete: undefined,
59
+ deleteBulk: `${controllerBeanFullName}#delete`,
60
+ } as const;
61
+ for (const [action, actionInheritKey] of Object.entries(expectedInherits)) {
62
+ const descriptor = catalog.get(`${controllerBeanFullName}#${action}`);
63
+ assert.ok(descriptor, `${action} RBAC action is missing`);
64
+ assert.equal(descriptor.actionInheritKey, actionInheritKey);
65
+ assert.equal(descriptor.options.dataScope, undefined);
66
+ }
67
+ });
68
+ });
5
69
 
6
- describe('<%=argv.resourceName%>.test.ts', () => {
7
70
  it('action:<%=argv.resourceName%>', async () => {
8
71
  await app.bean.executor.mockCtx(async () => {
9
- // data
10
72
  const data: Dto<%=argv.resourceNameCapitalize%>Create = {
11
73
  name: '__Tom__',
12
74
  description: 'This is a test',
@@ -15,48 +77,40 @@ describe('<%=argv.resourceName%>.test.ts', () => {
15
77
  name: '__TomNew__',
16
78
  description: 'This is a test',
17
79
  };
18
- // role-less authenticated users cannot access generated admin actions
80
+ let <%=argv.resourceName%>Id: Entity<%=argv.resourceNameCapitalize%>['id'] | undefined;
81
+ // sign in as an unrestricted test identity
19
82
  await app.bean.passport.signinMock();
20
83
  try {
21
- app.bean.passport.current!.roles = [];
22
- const actions = ['create', 'select', 'view', 'update', 'delete'];
23
- const permissions = await Promise.all(
24
- actions.map(action =>
25
- app.bean.permission.retrievePermissionAction(
26
- '<%=argv.moduleInfo.relativeName%>:<%=argv.resourceName%>',
27
- action,
28
- ),
29
- ),
30
- );
31
- assert.deepEqual(permissions, actions.map(() => false));
84
+ // create
85
+ <%=argv.resourceName%>Id = await app.bean.executor.performAction('post', '<%=argv.moduleActionPathRaw%>', { body: data });
86
+ assert.equal(!!<%=argv.resourceName%>Id, true);
87
+ // findMany
88
+ const selectRes: Dto<%=argv.resourceNameCapitalize%>SelectRes = await app.bean.executor.performAction('get', '<%=argv.moduleActionPathRaw%>');
89
+ assert.equal(selectRes.list.findIndex(item => item.name === data.name) > -1, true);
90
+ // update
91
+ const updateRes = await app.bean.executor.performAction('patch', '<%=argv.moduleActionPathRaw%>/:id', {
92
+ params: { id: <%=argv.resourceName%>Id },
93
+ body: dataUpdate,
94
+ });
95
+ assert.equal(updateRes, null);
96
+ // findOne
97
+ let <%=argv.resourceName%>: Entity<%=argv.resourceNameCapitalize%> = await app.bean.executor.performAction('get', '<%=argv.moduleActionPathRaw%>/:id', { params: { id: <%=argv.resourceName%>Id } });
98
+ assert.equal(<%=argv.resourceName%>.name, dataUpdate.name);
99
+ // delete
100
+ const deleteRes = await app.bean.executor.performAction('delete', '<%=argv.moduleActionPathRaw%>/:id', { params: { id: <%=argv.resourceName%>.id } });
101
+ assert.equal(deleteRes, null);
102
+ // findOne
103
+ <%=argv.resourceName%> = await app.bean.executor.performAction('get', '<%=argv.moduleActionPathRaw%>/:id', { params: { id: <%=argv.resourceName%>.id } });
104
+ assert.equal(<%=argv.resourceName%>, undefined);
32
105
  } finally {
106
+ if (<%=argv.resourceName%>Id) {
107
+ await app.scope('<%=argv.moduleInfo.relativeName%>').model.<%=argv.resourceName%>.deleteById(
108
+ <%=argv.resourceName%>Id,
109
+ { disableDeleted: true },
110
+ );
111
+ }
33
112
  await app.bean.passport.signout();
34
113
  }
35
- // login as system admin
36
- await app.bean.passport.signinMock();
37
- // create
38
- const <%=argv.resourceName%>Id = await app.bean.executor.performAction('post', '<%=argv.moduleActionPathRaw%>', { body: data });
39
- assert.equal(!!<%=argv.resourceName%>Id, true);
40
- // findMany
41
- const selectRes: Dto<%=argv.resourceNameCapitalize%>SelectRes = await app.bean.executor.performAction('get', '<%=argv.moduleActionPathRaw%>');
42
- assert.equal(selectRes.list.findIndex(item => item.name === data.name) > -1, true);
43
- // update
44
- const updateRes = await app.bean.executor.performAction('patch', '<%=argv.moduleActionPathRaw%>/:id', {
45
- params: { id: <%=argv.resourceName%>Id },
46
- body: dataUpdate,
47
- });
48
- assert.equal(updateRes, null);
49
- // findOne
50
- let <%=argv.resourceName%>: Entity<%=argv.resourceNameCapitalize%> = await app.bean.executor.performAction('get', '<%=argv.moduleActionPathRaw%>/:id', { params: { id: <%=argv.resourceName%>Id } });
51
- assert.equal(<%=argv.resourceName%>.name, dataUpdate.name);
52
- // delete
53
- const deleteRes = await app.bean.executor.performAction('delete', '<%=argv.moduleActionPathRaw%>/:id', { params: { id: <%=argv.resourceName%>.id } });
54
- assert.equal(deleteRes, null);
55
- // findOne
56
- <%=argv.resourceName%> = await app.bean.executor.performAction('get', '<%=argv.moduleActionPathRaw%>/:id', { params: { id: <%=argv.resourceName%>.id } });
57
- assert.equal(<%=argv.resourceName%>, undefined);
58
- // logout
59
- await app.bean.passport.signout();
60
114
  });
61
115
  });
62
116
  });
@@ -9,7 +9,6 @@ const __resources = {
9
9
  Name: 'Name',
10
10
  Description: 'Description',
11
11
  Operations: 'Operations',
12
- BulkDelete: 'Bulk Delete',
13
12
  };
14
13
 
15
14
  declare module '@cabloy/cli' {
@@ -40,6 +39,7 @@ export default metadataCustomSnippet({
40
39
  [`${resource}View`]: `View ${resource}`,
41
40
  [`${resource}Update`]: `Update ${resource}`,
42
41
  [`${resource}Delete`]: `Delete ${resource}`,
42
+ [`${resource}DeleteBulk`]: `Bulk Delete ${resource}`,
43
43
  };
44
44
  return locale_transform({ ast, argv, resources });
45
45
  },
@@ -7,7 +7,6 @@ const __resources = {
7
7
  Name: '名称',
8
8
  Description: '描述',
9
9
  Operations: '操作',
10
- BulkDelete: '批量删除',
11
10
  };
12
11
 
13
12
  export default metadataCustomSnippet({
@@ -23,6 +22,7 @@ export default metadataCustomSnippet({
23
22
  [`${resource}View`]: `查看${resource}`,
24
23
  [`${resource}Update`]: `更新${resource}`,
25
24
  [`${resource}Delete`]: `删除${resource}`,
25
+ [`${resource}DeleteBulk`]: `批量删除${resource}`,
26
26
  };
27
27
  return locale_transform({ ast, argv, resources });
28
28
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-cli-set-api",
3
- "version": "1.1.149",
3
+ "version": "1.1.150",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "vona cli-set-api",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona",
3
- "version": "5.1.94",
3
+ "version": "5.1.95",
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": [