@sudobility/entity_service 1.0.1

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 (72) hide show
  1. package/CLAUDE.md +124 -0
  2. package/dist/helpers/EntityHelper.cjs +234 -0
  3. package/dist/helpers/EntityHelper.d.ts +60 -0
  4. package/dist/helpers/EntityHelper.d.ts.map +1 -0
  5. package/dist/helpers/EntityHelper.js +234 -0
  6. package/dist/helpers/EntityHelper.js.map +1 -0
  7. package/dist/helpers/EntityMemberHelper.cjs +215 -0
  8. package/dist/helpers/EntityMemberHelper.d.ts +45 -0
  9. package/dist/helpers/EntityMemberHelper.d.ts.map +1 -0
  10. package/dist/helpers/EntityMemberHelper.js +215 -0
  11. package/dist/helpers/EntityMemberHelper.js.map +1 -0
  12. package/dist/helpers/InvitationHelper.cjs +251 -0
  13. package/dist/helpers/InvitationHelper.d.ts +59 -0
  14. package/dist/helpers/InvitationHelper.d.ts.map +1 -0
  15. package/dist/helpers/InvitationHelper.js +251 -0
  16. package/dist/helpers/InvitationHelper.js.map +1 -0
  17. package/dist/helpers/PermissionHelper.cjs +197 -0
  18. package/dist/helpers/PermissionHelper.d.ts +86 -0
  19. package/dist/helpers/PermissionHelper.d.ts.map +1 -0
  20. package/dist/helpers/PermissionHelper.js +197 -0
  21. package/dist/helpers/PermissionHelper.js.map +1 -0
  22. package/dist/helpers/index.cjs +15 -0
  23. package/dist/helpers/index.d.ts +8 -0
  24. package/dist/helpers/index.d.ts.map +1 -0
  25. package/dist/helpers/index.js +15 -0
  26. package/dist/helpers/index.js.map +1 -0
  27. package/dist/index.cjs +76 -0
  28. package/dist/index.d.ts +36 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +76 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/middleware/hono.cjs +148 -0
  33. package/dist/middleware/hono.d.ts +102 -0
  34. package/dist/middleware/hono.d.ts.map +1 -0
  35. package/dist/middleware/hono.js +148 -0
  36. package/dist/middleware/hono.js.map +1 -0
  37. package/dist/middleware/index.cjs +12 -0
  38. package/dist/middleware/index.d.ts +5 -0
  39. package/dist/middleware/index.d.ts.map +1 -0
  40. package/dist/middleware/index.js +12 -0
  41. package/dist/middleware/index.js.map +1 -0
  42. package/dist/migrations/001_add_entities.cjs +269 -0
  43. package/dist/migrations/001_add_entities.d.ts +29 -0
  44. package/dist/migrations/001_add_entities.d.ts.map +1 -0
  45. package/dist/migrations/001_add_entities.js +269 -0
  46. package/dist/migrations/001_add_entities.js.map +1 -0
  47. package/dist/migrations/index.cjs +10 -0
  48. package/dist/migrations/index.d.ts +5 -0
  49. package/dist/migrations/index.d.ts.map +1 -0
  50. package/dist/migrations/index.js +10 -0
  51. package/dist/migrations/index.js.map +1 -0
  52. package/dist/schema/entities.cjs +304 -0
  53. package/dist/schema/entities.d.ts +1047 -0
  54. package/dist/schema/entities.d.ts.map +1 -0
  55. package/dist/schema/entities.js +304 -0
  56. package/dist/schema/entities.js.map +1 -0
  57. package/dist/types/index.cjs +14 -0
  58. package/dist/types/index.d.ts +71 -0
  59. package/dist/types/index.d.ts.map +1 -0
  60. package/dist/types/index.js +14 -0
  61. package/dist/types/index.js.map +1 -0
  62. package/dist/utils/index.cjs +21 -0
  63. package/dist/utils/index.d.ts +5 -0
  64. package/dist/utils/index.d.ts.map +1 -0
  65. package/dist/utils/index.js +21 -0
  66. package/dist/utils/index.js.map +1 -0
  67. package/dist/utils/slug-generator.cjs +92 -0
  68. package/dist/utils/slug-generator.d.ts +41 -0
  69. package/dist/utils/slug-generator.d.ts.map +1 -0
  70. package/dist/utils/slug-generator.js +92 -0
  71. package/dist/utils/slug-generator.js.map +1 -0
  72. package/package.json +78 -0
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Entity Member Helper Class
4
+ * @description Operations for managing entity members and their roles
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.EntityMemberHelper = void 0;
8
+ const drizzle_orm_1 = require("drizzle-orm");
9
+ const types_1 = require("../types");
10
+ /**
11
+ * Helper class for entity member operations.
12
+ */
13
+ class EntityMemberHelper {
14
+ constructor(config) {
15
+ this.config = config;
16
+ }
17
+ /**
18
+ * Get all members of an entity.
19
+ */
20
+ async getMembers(entityId, options) {
21
+ // Build conditions
22
+ const conditions = [(0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId)];
23
+ if (options?.role) {
24
+ conditions.push((0, drizzle_orm_1.eq)(this.config.membersTable.role, options.role));
25
+ }
26
+ let query = this.config.db
27
+ .select({
28
+ member: this.config.membersTable,
29
+ user: {
30
+ id: this.config.usersTable.uuid,
31
+ email: this.config.usersTable.email,
32
+ displayName: this.config.usersTable.display_name,
33
+ },
34
+ })
35
+ .from(this.config.membersTable)
36
+ .leftJoin(this.config.usersTable, (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, this.config.usersTable.uuid))
37
+ .where((0, drizzle_orm_1.and)(...conditions))
38
+ .$dynamic();
39
+ if (options?.limit) {
40
+ query = query.limit(options.limit);
41
+ }
42
+ if (options?.offset) {
43
+ query = query.offset(options.offset);
44
+ }
45
+ const results = await query;
46
+ return results.map(({ member, user }) => this.mapRecordToMember(member, user));
47
+ }
48
+ /**
49
+ * Get a specific member by user ID.
50
+ */
51
+ async getMember(entityId, userId) {
52
+ const results = await this.config.db
53
+ .select({
54
+ member: this.config.membersTable,
55
+ user: {
56
+ id: this.config.usersTable.uuid,
57
+ email: this.config.usersTable.email,
58
+ displayName: this.config.usersTable.display_name,
59
+ },
60
+ })
61
+ .from(this.config.membersTable)
62
+ .leftJoin(this.config.usersTable, (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, this.config.usersTable.uuid))
63
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)))
64
+ .limit(1);
65
+ if (results.length === 0) {
66
+ return null;
67
+ }
68
+ return this.mapRecordToMember(results[0].member, results[0].user);
69
+ }
70
+ /**
71
+ * Get user's role in an entity.
72
+ */
73
+ async getUserRole(entityId, userId) {
74
+ const results = await this.config.db
75
+ .select({ role: this.config.membersTable.role })
76
+ .from(this.config.membersTable)
77
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)))
78
+ .limit(1);
79
+ if (results.length === 0) {
80
+ return null;
81
+ }
82
+ return results[0].role;
83
+ }
84
+ /**
85
+ * Add a member to an entity.
86
+ */
87
+ async addMember(entityId, userId, role) {
88
+ const [member] = await this.config.db
89
+ .insert(this.config.membersTable)
90
+ .values({
91
+ entity_id: entityId,
92
+ user_id: userId,
93
+ role,
94
+ })
95
+ .returning();
96
+ // Fetch user info for response
97
+ const users = await this.config.db
98
+ .select({
99
+ id: this.config.usersTable.uuid,
100
+ email: this.config.usersTable.email,
101
+ displayName: this.config.usersTable.display_name,
102
+ })
103
+ .from(this.config.usersTable)
104
+ .where((0, drizzle_orm_1.eq)(this.config.usersTable.uuid, userId))
105
+ .limit(1);
106
+ return this.mapRecordToMember(member, users[0] ?? null);
107
+ }
108
+ /**
109
+ * Update a member's role.
110
+ */
111
+ async updateMemberRole(entityId, userId, role) {
112
+ // Check constraints for personal entities
113
+ const entity = await this.config.db
114
+ .select()
115
+ .from(this.config.entitiesTable)
116
+ .where((0, drizzle_orm_1.eq)(this.config.entitiesTable.id, entityId))
117
+ .limit(1);
118
+ if (entity.length > 0 && entity[0].entity_type === types_1.EntityType.PERSONAL) {
119
+ throw new Error('Cannot change roles in personal entities');
120
+ }
121
+ // Ensure at least one admin remains
122
+ if (role !== types_1.EntityRole.ADMIN) {
123
+ const admins = await this.config.db
124
+ .select()
125
+ .from(this.config.membersTable)
126
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.role, types_1.EntityRole.ADMIN)));
127
+ const isOnlyAdmin = admins.length === 1 && admins[0].user_id === userId;
128
+ if (isOnlyAdmin) {
129
+ throw new Error('Cannot demote the only admin');
130
+ }
131
+ }
132
+ const [updated] = await this.config.db
133
+ .update(this.config.membersTable)
134
+ .set({
135
+ role,
136
+ updated_at: new Date(),
137
+ })
138
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)))
139
+ .returning();
140
+ // Fetch user info for response
141
+ const users = await this.config.db
142
+ .select({
143
+ id: this.config.usersTable.uuid,
144
+ email: this.config.usersTable.email,
145
+ displayName: this.config.usersTable.display_name,
146
+ })
147
+ .from(this.config.usersTable)
148
+ .where((0, drizzle_orm_1.eq)(this.config.usersTable.uuid, userId))
149
+ .limit(1);
150
+ return this.mapRecordToMember(updated, users[0] ?? null);
151
+ }
152
+ /**
153
+ * Remove a member from an entity.
154
+ */
155
+ async removeMember(entityId, userId) {
156
+ // Check constraints for personal entities
157
+ const entity = await this.config.db
158
+ .select()
159
+ .from(this.config.entitiesTable)
160
+ .where((0, drizzle_orm_1.eq)(this.config.entitiesTable.id, entityId))
161
+ .limit(1);
162
+ if (entity.length > 0 && entity[0].entity_type === types_1.EntityType.PERSONAL) {
163
+ throw new Error('Cannot remove members from personal entities');
164
+ }
165
+ // Check if user is the owner
166
+ if (entity.length > 0 && entity[0].owner_user_id === userId) {
167
+ throw new Error('Cannot remove the entity owner');
168
+ }
169
+ // Ensure at least one admin remains
170
+ const member = await this.getMember(entityId, userId);
171
+ if (member?.role === types_1.EntityRole.ADMIN) {
172
+ const admins = await this.config.db
173
+ .select()
174
+ .from(this.config.membersTable)
175
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.role, types_1.EntityRole.ADMIN)));
176
+ if (admins.length === 1) {
177
+ throw new Error('Cannot remove the only admin');
178
+ }
179
+ }
180
+ await this.config.db
181
+ .delete(this.config.membersTable)
182
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)));
183
+ }
184
+ /**
185
+ * Check if a user is a member of an entity.
186
+ */
187
+ async isMember(entityId, userId) {
188
+ const role = await this.getUserRole(entityId, userId);
189
+ return role !== null;
190
+ }
191
+ /**
192
+ * Map database record to EntityMember type.
193
+ */
194
+ mapRecordToMember(record, user) {
195
+ const member = {
196
+ id: record.id,
197
+ entityId: record.entity_id,
198
+ userId: record.user_id,
199
+ role: record.role,
200
+ joinedAt: record.joined_at?.toISOString() ?? new Date().toISOString(),
201
+ createdAt: record.created_at?.toISOString() ?? new Date().toISOString(),
202
+ updatedAt: record.updated_at?.toISOString() ?? new Date().toISOString(),
203
+ };
204
+ if (user) {
205
+ member.user = {
206
+ id: user.id,
207
+ email: user.email,
208
+ displayName: user.displayName,
209
+ };
210
+ }
211
+ return member;
212
+ }
213
+ }
214
+ exports.EntityMemberHelper = EntityMemberHelper;
215
+ //# sourceMappingURL=EntityMemberHelper.js.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @fileoverview Entity Member Helper Class
3
+ * @description Operations for managing entity members and their roles
4
+ */
5
+ import { EntityRole, type EntityMember, type EntityHelperConfig, type ListMembersOptions } from '../types';
6
+ /**
7
+ * Helper class for entity member operations.
8
+ */
9
+ export declare class EntityMemberHelper {
10
+ private readonly config;
11
+ constructor(config: EntityHelperConfig);
12
+ /**
13
+ * Get all members of an entity.
14
+ */
15
+ getMembers(entityId: string, options?: ListMembersOptions): Promise<EntityMember[]>;
16
+ /**
17
+ * Get a specific member by user ID.
18
+ */
19
+ getMember(entityId: string, userId: string): Promise<EntityMember | null>;
20
+ /**
21
+ * Get user's role in an entity.
22
+ */
23
+ getUserRole(entityId: string, userId: string): Promise<EntityRole | null>;
24
+ /**
25
+ * Add a member to an entity.
26
+ */
27
+ addMember(entityId: string, userId: string, role: EntityRole): Promise<EntityMember>;
28
+ /**
29
+ * Update a member's role.
30
+ */
31
+ updateMemberRole(entityId: string, userId: string, role: EntityRole): Promise<EntityMember>;
32
+ /**
33
+ * Remove a member from an entity.
34
+ */
35
+ removeMember(entityId: string, userId: string): Promise<void>;
36
+ /**
37
+ * Check if a user is a member of an entity.
38
+ */
39
+ isMember(entityId: string, userId: string): Promise<boolean>;
40
+ /**
41
+ * Map database record to EntityMember type.
42
+ */
43
+ private mapRecordToMember;
44
+ }
45
+ //# sourceMappingURL=EntityMemberHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityMemberHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/EntityMemberHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,UAAU,EAEV,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAElB;;GAEG;AACH,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,kBAAkB;IAEvD;;OAEG;IACG,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,YAAY,EAAE,CAAC;IAuC1B;;OAEG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IA8B/B;;OAEG;IACG,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAmB7B;;OAEG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC;IAwBxB;;OAEG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC;IA2DxB;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CnE;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKlE;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAwB1B"}
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Entity Member Helper Class
4
+ * @description Operations for managing entity members and their roles
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.EntityMemberHelper = void 0;
8
+ const drizzle_orm_1 = require("drizzle-orm");
9
+ const types_1 = require("../types");
10
+ /**
11
+ * Helper class for entity member operations.
12
+ */
13
+ class EntityMemberHelper {
14
+ constructor(config) {
15
+ this.config = config;
16
+ }
17
+ /**
18
+ * Get all members of an entity.
19
+ */
20
+ async getMembers(entityId, options) {
21
+ // Build conditions
22
+ const conditions = [(0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId)];
23
+ if (options?.role) {
24
+ conditions.push((0, drizzle_orm_1.eq)(this.config.membersTable.role, options.role));
25
+ }
26
+ let query = this.config.db
27
+ .select({
28
+ member: this.config.membersTable,
29
+ user: {
30
+ id: this.config.usersTable.uuid,
31
+ email: this.config.usersTable.email,
32
+ displayName: this.config.usersTable.display_name,
33
+ },
34
+ })
35
+ .from(this.config.membersTable)
36
+ .leftJoin(this.config.usersTable, (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, this.config.usersTable.uuid))
37
+ .where((0, drizzle_orm_1.and)(...conditions))
38
+ .$dynamic();
39
+ if (options?.limit) {
40
+ query = query.limit(options.limit);
41
+ }
42
+ if (options?.offset) {
43
+ query = query.offset(options.offset);
44
+ }
45
+ const results = await query;
46
+ return results.map(({ member, user }) => this.mapRecordToMember(member, user));
47
+ }
48
+ /**
49
+ * Get a specific member by user ID.
50
+ */
51
+ async getMember(entityId, userId) {
52
+ const results = await this.config.db
53
+ .select({
54
+ member: this.config.membersTable,
55
+ user: {
56
+ id: this.config.usersTable.uuid,
57
+ email: this.config.usersTable.email,
58
+ displayName: this.config.usersTable.display_name,
59
+ },
60
+ })
61
+ .from(this.config.membersTable)
62
+ .leftJoin(this.config.usersTable, (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, this.config.usersTable.uuid))
63
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)))
64
+ .limit(1);
65
+ if (results.length === 0) {
66
+ return null;
67
+ }
68
+ return this.mapRecordToMember(results[0].member, results[0].user);
69
+ }
70
+ /**
71
+ * Get user's role in an entity.
72
+ */
73
+ async getUserRole(entityId, userId) {
74
+ const results = await this.config.db
75
+ .select({ role: this.config.membersTable.role })
76
+ .from(this.config.membersTable)
77
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)))
78
+ .limit(1);
79
+ if (results.length === 0) {
80
+ return null;
81
+ }
82
+ return results[0].role;
83
+ }
84
+ /**
85
+ * Add a member to an entity.
86
+ */
87
+ async addMember(entityId, userId, role) {
88
+ const [member] = await this.config.db
89
+ .insert(this.config.membersTable)
90
+ .values({
91
+ entity_id: entityId,
92
+ user_id: userId,
93
+ role,
94
+ })
95
+ .returning();
96
+ // Fetch user info for response
97
+ const users = await this.config.db
98
+ .select({
99
+ id: this.config.usersTable.uuid,
100
+ email: this.config.usersTable.email,
101
+ displayName: this.config.usersTable.display_name,
102
+ })
103
+ .from(this.config.usersTable)
104
+ .where((0, drizzle_orm_1.eq)(this.config.usersTable.uuid, userId))
105
+ .limit(1);
106
+ return this.mapRecordToMember(member, users[0] ?? null);
107
+ }
108
+ /**
109
+ * Update a member's role.
110
+ */
111
+ async updateMemberRole(entityId, userId, role) {
112
+ // Check constraints for personal entities
113
+ const entity = await this.config.db
114
+ .select()
115
+ .from(this.config.entitiesTable)
116
+ .where((0, drizzle_orm_1.eq)(this.config.entitiesTable.id, entityId))
117
+ .limit(1);
118
+ if (entity.length > 0 && entity[0].entity_type === types_1.EntityType.PERSONAL) {
119
+ throw new Error('Cannot change roles in personal entities');
120
+ }
121
+ // Ensure at least one admin remains
122
+ if (role !== types_1.EntityRole.ADMIN) {
123
+ const admins = await this.config.db
124
+ .select()
125
+ .from(this.config.membersTable)
126
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.role, types_1.EntityRole.ADMIN)));
127
+ const isOnlyAdmin = admins.length === 1 && admins[0].user_id === userId;
128
+ if (isOnlyAdmin) {
129
+ throw new Error('Cannot demote the only admin');
130
+ }
131
+ }
132
+ const [updated] = await this.config.db
133
+ .update(this.config.membersTable)
134
+ .set({
135
+ role,
136
+ updated_at: new Date(),
137
+ })
138
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)))
139
+ .returning();
140
+ // Fetch user info for response
141
+ const users = await this.config.db
142
+ .select({
143
+ id: this.config.usersTable.uuid,
144
+ email: this.config.usersTable.email,
145
+ displayName: this.config.usersTable.display_name,
146
+ })
147
+ .from(this.config.usersTable)
148
+ .where((0, drizzle_orm_1.eq)(this.config.usersTable.uuid, userId))
149
+ .limit(1);
150
+ return this.mapRecordToMember(updated, users[0] ?? null);
151
+ }
152
+ /**
153
+ * Remove a member from an entity.
154
+ */
155
+ async removeMember(entityId, userId) {
156
+ // Check constraints for personal entities
157
+ const entity = await this.config.db
158
+ .select()
159
+ .from(this.config.entitiesTable)
160
+ .where((0, drizzle_orm_1.eq)(this.config.entitiesTable.id, entityId))
161
+ .limit(1);
162
+ if (entity.length > 0 && entity[0].entity_type === types_1.EntityType.PERSONAL) {
163
+ throw new Error('Cannot remove members from personal entities');
164
+ }
165
+ // Check if user is the owner
166
+ if (entity.length > 0 && entity[0].owner_user_id === userId) {
167
+ throw new Error('Cannot remove the entity owner');
168
+ }
169
+ // Ensure at least one admin remains
170
+ const member = await this.getMember(entityId, userId);
171
+ if (member?.role === types_1.EntityRole.ADMIN) {
172
+ const admins = await this.config.db
173
+ .select()
174
+ .from(this.config.membersTable)
175
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.role, types_1.EntityRole.ADMIN)));
176
+ if (admins.length === 1) {
177
+ throw new Error('Cannot remove the only admin');
178
+ }
179
+ }
180
+ await this.config.db
181
+ .delete(this.config.membersTable)
182
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)));
183
+ }
184
+ /**
185
+ * Check if a user is a member of an entity.
186
+ */
187
+ async isMember(entityId, userId) {
188
+ const role = await this.getUserRole(entityId, userId);
189
+ return role !== null;
190
+ }
191
+ /**
192
+ * Map database record to EntityMember type.
193
+ */
194
+ mapRecordToMember(record, user) {
195
+ const member = {
196
+ id: record.id,
197
+ entityId: record.entity_id,
198
+ userId: record.user_id,
199
+ role: record.role,
200
+ joinedAt: record.joined_at?.toISOString() ?? new Date().toISOString(),
201
+ createdAt: record.created_at?.toISOString() ?? new Date().toISOString(),
202
+ updatedAt: record.updated_at?.toISOString() ?? new Date().toISOString(),
203
+ };
204
+ if (user) {
205
+ member.user = {
206
+ id: user.id,
207
+ email: user.email,
208
+ displayName: user.displayName,
209
+ };
210
+ }
211
+ return member;
212
+ }
213
+ }
214
+ exports.EntityMemberHelper = EntityMemberHelper;
215
+ //# sourceMappingURL=EntityMemberHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityMemberHelper.js","sourceRoot":"","sources":["../../src/helpers/EntityMemberHelper.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6CAAsC;AACtC,oCAMkB;AAElB;;GAEG;AACH,MAAa,kBAAkB;IAC7B,YAA6B,MAA0B;QAA1B,WAAM,GAAN,MAAM,CAAoB;IAAG,CAAC;IAE3D;;OAEG;IACH,KAAK,CAAC,UAAU,CACd,QAAgB,EAChB,OAA4B;QAE5B,mBAAmB;QACnB,MAAM,UAAU,GAAG,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;QACtE,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;YAClB,UAAU,CAAC,IAAI,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE;aACvB,MAAM,CAAC;YACN,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;YAChC,IAAI,EAAE;gBACJ,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI;gBAC/B,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK;gBACnC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY;aACjD;SACF,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;aAC9B,QAAQ,CACP,IAAI,CAAC,MAAM,CAAC,UAAU,EACtB,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAClE;aACA,KAAK,CAAC,IAAA,iBAAG,EAAC,GAAG,UAAU,CAAC,CAAC;aACzB,QAAQ,EAAE,CAAC;QAEd,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;YACnB,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;YACpB,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC;QAE5B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CACtC,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,CACrC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS,CACb,QAAgB,EAChB,MAAc;QAEd,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aACjC,MAAM,CAAC;YACN,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;YAChC,IAAI,EAAE;gBACJ,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI;gBAC/B,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK;gBACnC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY;aACjD;SACF,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;aAC9B,QAAQ,CACP,IAAI,CAAC,MAAM,CAAC,UAAU,EACtB,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAClE;aACA,KAAK,CACJ,IAAA,iBAAG,EACD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,EAChD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAC7C,CACF;aACA,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CACf,QAAgB,EAChB,MAAc;QAEd,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aACjC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;aAC/C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;aAC9B,KAAK,CACJ,IAAA,iBAAG,EACD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,EAChD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAC7C,CACF;aACA,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,IAAkB,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS,CACb,QAAgB,EAChB,MAAc,EACd,IAAgB;QAEhB,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aAClC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;aAChC,MAAM,CAAC;YACN,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,MAAM;YACf,IAAI;SACL,CAAC;aACD,SAAS,EAAE,CAAC;QAEf,+BAA+B;QAC/B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aAC/B,MAAM,CAAC;YACN,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI;YAC/B,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK;YACnC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY;SACjD,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;aAC5B,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;aAC9C,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,OAAO,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CACpB,QAAgB,EAChB,MAAc,EACd,IAAgB;QAEhB,0CAA0C;QAC1C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aAChC,MAAM,EAAE;aACR,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;aAC/B,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;aACjD,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,kBAAU,CAAC,QAAQ,EAAE,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,CAAC;QAED,oCAAoC;QACpC,IAAI,IAAI,KAAK,kBAAU,CAAC,KAAK,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;iBAChC,MAAM,EAAE;iBACR,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;iBAC9B,KAAK,CACJ,IAAA,iBAAG,EACD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,EAChD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,kBAAU,CAAC,KAAK,CAAC,CACpD,CACF,CAAC;YAEJ,MAAM,WAAW,GACf,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC;YACtD,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aACnC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;aAChC,GAAG,CAAC;YACH,IAAI;YACJ,UAAU,EAAE,IAAI,IAAI,EAAE;SACvB,CAAC;aACD,KAAK,CACJ,IAAA,iBAAG,EACD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,EAChD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAC7C,CACF;aACA,SAAS,EAAE,CAAC;QAEf,+BAA+B;QAC/B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aAC/B,MAAM,CAAC;YACN,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI;YAC/B,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK;YACnC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY;SACjD,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;aAC5B,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;aAC9C,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,MAAc;QACjD,0CAA0C;QAC1C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aAChC,MAAM,EAAE;aACR,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;aAC/B,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;aACjD,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,kBAAU,CAAC,QAAQ,EAAE,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QAED,6BAA6B;QAC7B,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,KAAK,MAAM,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpD,CAAC;QAED,oCAAoC;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACtD,IAAI,MAAM,EAAE,IAAI,KAAK,kBAAU,CAAC,KAAK,EAAE,CAAC;YACtC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;iBAChC,MAAM,EAAE;iBACR,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;iBAC9B,KAAK,CACJ,IAAA,iBAAG,EACD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,EAChD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,kBAAU,CAAC,KAAK,CAAC,CACpD,CACF,CAAC;YAEJ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAED,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aACjB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;aAChC,KAAK,CACJ,IAAA,iBAAG,EACD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,EAChD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAC7C,CACF,CAAC;IACN,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,QAAgB,EAAE,MAAc;QAC7C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACtD,OAAO,IAAI,KAAK,IAAI,CAAC;IACvB,CAAC;IAED;;OAEG;IACK,iBAAiB,CACvB,MAAW,EACX,IAA6E;QAE7E,MAAM,MAAM,GAAiB;YAC3B,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,QAAQ,EAAE,MAAM,CAAC,SAAS;YAC1B,MAAM,EAAE,MAAM,CAAC,OAAO;YACtB,IAAI,EAAE,MAAM,CAAC,IAAkB;YAC/B,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACrE,SAAS,EAAE,MAAM,CAAC,UAAU,EAAE,WAAW,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACvE,SAAS,EAAE,MAAM,CAAC,UAAU,EAAE,WAAW,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACxE,CAAC;QAEF,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,GAAG;gBACZ,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;aAC9B,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAjSD,gDAiSC"}