cabloy 5.1.155 → 5.1.156

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 (53) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/skills/cabloy-contract-loop/SKILL.md +1 -1
  3. package/.claude/skills/cabloy-spec-generation/SKILL.md +1 -1
  4. package/.claude/skills/cabloy-workflow/SKILL.md +3 -3
  5. package/CHANGELOG.md +13 -0
  6. package/CLAUDE.md +1 -1
  7. package/README.md +18 -18
  8. package/package.json +1 -1
  9. package/repo-docs/.vitepress/public/CNAME +1 -1
  10. package/repo-docs/ai/edition-consistency-checklist.md +7 -7
  11. package/repo-docs/backend/quickstart.md +1 -1
  12. package/repo-docs/blogs/ai-react-nextjs-enterprise-architecture-cabloy/index.md +8 -8
  13. package/repo-docs/blogs/cabloy-fullstack-resource-addressing/index.md +13 -13
  14. package/repo-docs/blogs/vue-object-oriented-zova-beginner-mental-model/index.md +6 -6
  15. package/repo-docs/editions/cabloy-start.md +10 -12
  16. package/repo-docs/editions/choosing-between-basic-and-start.md +6 -7
  17. package/repo-docs/editions/detection.md +1 -1
  18. package/repo-docs/editions/overview.md +26 -14
  19. package/repo-docs/frontend/foundation.md +1 -1
  20. package/repo-docs/frontend/introduction.md +1 -1
  21. package/repo-docs/frontend/scripts.md +2 -2
  22. package/repo-docs/fullstack/deploy-cloudflare-docker.md +1 -1
  23. package/repo-docs/fullstack/edition-collaboration-differences.md +2 -2
  24. package/repo-docs/fullstack/introduction.md +7 -3
  25. package/repo-docs/fullstack/openapi-to-sdk.md +1 -1
  26. package/repo-docs/fullstack/quickstart.md +4 -4
  27. package/repo-docs/fullstack/vona-zova-integration.md +1 -1
  28. package/repo-docs/index.md +1 -1
  29. package/repo-docs/reference/glossary.md +8 -5
  30. package/repo-docs/reference/introduction.md +1 -1
  31. package/repo-docs/reference/repo-scripts.md +12 -4
  32. package/vona/packages-vona/vona/package.json +1 -1
  33. package/vona/packages-vona/vona-shared/package.json +4 -4
  34. package/vona/pnpm-lock.yaml +8 -3
  35. package/vona/src/suite/a-home/modules/home-user/src/bean/meta.redlock.ts +2 -1
  36. package/vona/src/suite/a-home/modules/home-user/src/service/roleAdapter.ts +115 -6
  37. package/vona/src/suite/a-home/modules/home-user/test/role.test.ts +163 -2
  38. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/package.json +1 -1
  39. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/.metadata/index.ts +26 -0
  40. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/bean/eventListener.roleMembershipChanged.ts +25 -0
  41. package/vona/src/suite-vendor/a-cabloy/package.json +2 -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-permission/package.json +1 -1
  44. package/vona/src/suite-vendor/a-vona/modules/a-queue/package.json +1 -1
  45. package/vona/src/suite-vendor/a-vona/modules/a-queue/src/lib/beanQueueBase.ts +1 -1
  46. package/vona/src/suite-vendor/a-vona/modules/a-queue/src/service/queue.ts +2 -2
  47. package/vona/src/suite-vendor/a-vona/modules/a-user/package.json +1 -1
  48. package/vona/src/suite-vendor/a-vona/modules/a-user/src/.metadata/index.ts +15 -0
  49. package/vona/src/suite-vendor/a-vona/modules/a-user/src/bean/bean.role.ts +44 -3
  50. package/vona/src/suite-vendor/a-vona/modules/a-user/src/bean/event.roleMembershipChanged.ts +16 -0
  51. package/vona/src/suite-vendor/a-vona/modules/a-user/src/types/role.ts +12 -1
  52. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  53. package/zova/pnpm-lock.yaml +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-suite-a-cabloy",
3
- "version": "5.1.48",
3
+ "version": "5.1.49",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "",
6
6
  "author": "",
@@ -9,7 +9,7 @@
9
9
  "dependencies": {
10
10
  "vona-module-a-cabloy": "workspace:^",
11
11
  "vona-module-a-markdown": "^5.0.3",
12
- "vona-module-a-rbac": "^5.0.2",
12
+ "vona-module-a-rbac": "^5.0.3",
13
13
  "vona-module-a-socket": "workspace:^",
14
14
  "vona-module-a-ssr": "workspace:^",
15
15
  "vona-module-a-ssrhmr": "workspace:^"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-module-a-core",
3
- "version": "5.1.51",
3
+ "version": "5.1.52",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-module-a-permission",
3
- "version": "5.1.18",
3
+ "version": "5.1.19",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-module-a-queue",
3
- "version": "5.1.15",
3
+ "version": "5.1.16",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "",
6
6
  "keywords": [
@@ -11,7 +11,7 @@ export class BeanQueueBase<DATA = unknown, RESULT = unknown> extends BeanBase {
11
11
  );
12
12
  }
13
13
 
14
- push(data: DATA, options?: IQueuePushOptions) {
14
+ push(data: DATA, options?: IQueuePushOptions): Promise<void> {
15
15
  return this.$scope.queue.service.queue.push(
16
16
  this.$scope.queue.service.queue.prepareJobInfo(this.$onionName as any, data, options),
17
17
  );
@@ -24,9 +24,9 @@ export class ServiceQueue extends BeanBase {
24
24
  _queues: IQueueQueues = {};
25
25
  _queueCallbacks: IQueueCallbacks = {};
26
26
 
27
- push<DATA>(info: IQueueJobContext<DATA>) {
27
+ push<DATA>(info: IQueueJobContext<DATA>): Promise<void> {
28
28
  if (!info.options?.dbInfo) throw new Error('should specify the options.dbInfo');
29
- this._queuePush(info, false);
29
+ return this._queuePush(info, false);
30
30
  }
31
31
 
32
32
  // { locale, instanceName, module, queueName,queueNameSub,data }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-module-a-user",
3
- "version": "5.1.24",
3
+ "version": "5.1.25",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "",
6
6
  "keywords": [
@@ -174,6 +174,7 @@ export interface IModuleCacheRedis {
174
174
  export * from '../bean/event.activate.ts';
175
175
  export * from '../bean/event.createAnonymous.ts';
176
176
  export * from '../bean/event.register.ts';
177
+ export * from '../bean/event.roleMembershipChanged.ts';
177
178
  export * from '../bean/event.signin.ts';
178
179
  export * from '../bean/event.signout.ts';
179
180
 
@@ -214,6 +215,16 @@ declare module 'vona-module-a-user' {
214
215
  get $onionName(): 'a-user:register';
215
216
  }
216
217
 
218
+ export interface EventRoleMembershipChanged {
219
+ /** @internal */
220
+ get scope(): ScopeModuleAUser;
221
+ }
222
+
223
+ export interface EventRoleMembershipChanged {
224
+ get $beanFullName(): 'a-user.event.roleMembershipChanged';
225
+ get $onionName(): 'a-user:roleMembershipChanged';
226
+ }
227
+
217
228
  export interface EventSignin {
218
229
  /** @internal */
219
230
  get scope(): ScopeModuleAUser;
@@ -239,12 +250,14 @@ declare module 'vona-module-a-user' {
239
250
  import type { EventActivate } from '../bean/event.activate.ts';
240
251
  import type { EventCreateAnonymous } from '../bean/event.createAnonymous.ts';
241
252
  import type { EventRegister } from '../bean/event.register.ts';
253
+ import type { EventRoleMembershipChanged } from '../bean/event.roleMembershipChanged.ts';
242
254
  import type { EventSignin } from '../bean/event.signin.ts';
243
255
  import type { EventSignout } from '../bean/event.signout.ts';
244
256
  export interface IModuleEvent {
245
257
  'activate': EventActivate;
246
258
  'createAnonymous': EventCreateAnonymous;
247
259
  'register': EventRegister;
260
+ 'roleMembershipChanged': EventRoleMembershipChanged;
248
261
  'signin': EventSignin;
249
262
  'signout': EventSignout;
250
263
  }
@@ -253,6 +266,7 @@ export interface IModuleEvent {
253
266
  import type { TypeEventActivateData, TypeEventActivateResult } from '../bean/event.activate.ts';
254
267
  import type { TypeEventCreateAnonymousData, TypeEventCreateAnonymousResult } from '../bean/event.createAnonymous.ts';
255
268
  import type { TypeEventRegisterData, TypeEventRegisterResult } from '../bean/event.register.ts';
269
+ import type { TypeEventRoleMembershipChangedData, TypeEventRoleMembershipChangedResult } from '../bean/event.roleMembershipChanged.ts';
256
270
  import type { TypeEventSigninData, TypeEventSigninResult } from '../bean/event.signin.ts';
257
271
  import type { TypeEventSignoutData, TypeEventSignoutResult } from '../bean/event.signout.ts';
258
272
  import type { EventOn } from 'vona-module-a-event';
@@ -261,6 +275,7 @@ declare module 'vona-module-a-event' {
261
275
  'a-user:activate': EventOn<TypeEventActivateData, TypeEventActivateResult>;
262
276
  'a-user:createAnonymous': EventOn<TypeEventCreateAnonymousData, TypeEventCreateAnonymousResult>;
263
277
  'a-user:register': EventOn<TypeEventRegisterData, TypeEventRegisterResult>;
278
+ 'a-user:roleMembershipChanged': EventOn<TypeEventRoleMembershipChangedData, TypeEventRoleMembershipChangedResult>;
264
279
  'a-user:signin': EventOn<TypeEventSigninData, TypeEventSigninResult>;
265
280
  'a-user:signout': EventOn<TypeEventSignoutData, TypeEventSignoutResult>;
266
281
  }
@@ -2,8 +2,9 @@ import type { TableIdentity } from 'table-identity';
2
2
 
3
3
  import { BeanBase, beanFullNameFromOnionName } from 'vona';
4
4
  import { Bean } from 'vona-module-a-bean';
5
+ import { Core } from 'vona-module-a-core';
5
6
 
6
- import type { IRole, IRoleAdapter } from '../types/role.ts';
7
+ import type { IRole, IRoleAdapter, IRoleMembershipReplaceResult } from '../types/role.ts';
7
8
 
8
9
  @Bean()
9
10
  export class BeanRole extends BeanBase {
@@ -33,7 +34,47 @@ export class BeanRole extends BeanBase {
33
34
  return this.roleAdapter.findAllByUserId(userId);
34
35
  }
35
36
 
36
- addUserId(id: TableIdentity, userId: TableIdentity): Promise<TableIdentity> {
37
- return this.roleAdapter.addUserId(id, userId);
37
+ @Core.transaction()
38
+ async addUserId(id: TableIdentity, userId: TableIdentity): Promise<boolean> {
39
+ const changed = await this.roleAdapter.addUserId(id, userId);
40
+ if (changed) await this.emitMembershipChanged(userId, [id]);
41
+ return changed;
42
+ }
43
+
44
+ @Core.transaction()
45
+ async removeUserId(id: TableIdentity, userId: TableIdentity): Promise<boolean> {
46
+ const changed = await this.roleAdapter.removeUserId(id, userId);
47
+ if (changed) await this.emitMembershipChanged(userId, [id]);
48
+ return changed;
49
+ }
50
+
51
+ @Core.transaction()
52
+ async replaceUserRoleIds(
53
+ userId: TableIdentity,
54
+ roleIds: TableIdentity[],
55
+ options?: { preserveRoleIds?: TableIdentity[] },
56
+ ): Promise<IRoleMembershipReplaceResult> {
57
+ const result = await this.roleAdapter.replaceUserRoleIds(userId, roleIds, options);
58
+ const changedRoleIds = [...result.addedRoleIds, ...result.removedRoleIds];
59
+ if (changedRoleIds.length) await this.emitMembershipChanged(userId, changedRoleIds);
60
+ return result;
61
+ }
62
+
63
+ private async emitMembershipChanged(
64
+ userId: TableIdentity,
65
+ roleIds: TableIdentity[],
66
+ ): Promise<void> {
67
+ await this.scope.event.roleMembershipChanged.emit({
68
+ userIds: this.uniqueIds([userId]),
69
+ roleIds: this.uniqueIds(roleIds),
70
+ });
71
+ }
72
+
73
+ private uniqueIds(ids: TableIdentity[]): TableIdentity[] {
74
+ const values = new Map<string, TableIdentity>();
75
+ for (const id of ids) values.set(String(id), id);
76
+ return [...values.entries()]
77
+ .toSorted(([left], [right]) => left.localeCompare(right))
78
+ .map(([, id]) => id);
38
79
  }
39
80
  }
@@ -0,0 +1,16 @@
1
+ import type { TableIdentity } from 'table-identity';
2
+
3
+ import { BeanEventBase, Event } from 'vona-module-a-event';
4
+
5
+ export interface TypeEventRoleMembershipChangedData {
6
+ userIds: TableIdentity[];
7
+ roleIds: TableIdentity[];
8
+ }
9
+
10
+ export type TypeEventRoleMembershipChangedResult = void;
11
+
12
+ @Event()
13
+ export class EventRoleMembershipChanged extends BeanEventBase<
14
+ TypeEventRoleMembershipChangedData,
15
+ TypeEventRoleMembershipChangedResult
16
+ > {}
@@ -18,9 +18,20 @@ export interface IRole {
18
18
  builtin?: boolean;
19
19
  }
20
20
 
21
+ export interface IRoleMembershipReplaceResult {
22
+ addedRoleIds: TableIdentity[];
23
+ removedRoleIds: TableIdentity[];
24
+ }
25
+
21
26
  export interface IRoleAdapter {
22
27
  findOneByName(name: string): Promise<IRole | undefined>;
23
28
  findOne(role: Partial<IRole>): Promise<IRole | undefined>;
24
29
  findAllByUserId(userId: TableIdentity): Promise<IRole[] | undefined>;
25
- addUserId(id: TableIdentity, userId: TableIdentity): Promise<TableIdentity>;
30
+ addUserId(id: TableIdentity, userId: TableIdentity): Promise<boolean>;
31
+ removeUserId(id: TableIdentity, userId: TableIdentity): Promise<boolean>;
32
+ replaceUserRoleIds(
33
+ userId: TableIdentity,
34
+ roleIds: TableIdentity[],
35
+ options?: { preserveRoleIds?: TableIdentity[] },
36
+ ): Promise<IRoleMembershipReplaceResult>;
26
37
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-suite-a-vona",
3
- "version": "5.1.82",
3
+ "version": "5.1.83",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "",
6
6
  "author": "",
@@ -977,7 +977,7 @@ importers:
977
977
  specifier: ^5.0.1
978
978
  version: link:modules/a-rbac
979
979
  zova-module-rest-resource:
980
- specifier: ^5.1.48
980
+ specifier: ^5.1.49
981
981
  version: link:modules/rest-resource
982
982
 
983
983
  src/suite-vendor/a-cabloy/modules/a-rbac: