@sudobility/entity_service 1.0.3 → 1.0.5
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/CLAUDE.md +103 -59
- package/dist/helpers/EntityHelper.cjs +29 -21
- package/dist/helpers/EntityHelper.d.ts +12 -4
- package/dist/helpers/EntityHelper.d.ts.map +1 -1
- package/dist/helpers/EntityHelper.js +29 -21
- package/dist/helpers/EntityHelper.js.map +1 -1
- package/dist/helpers/EntityMemberHelper.cjs +86 -47
- package/dist/helpers/EntityMemberHelper.d.ts +11 -3
- package/dist/helpers/EntityMemberHelper.d.ts.map +1 -1
- package/dist/helpers/EntityMemberHelper.js +86 -47
- package/dist/helpers/EntityMemberHelper.js.map +1 -1
- package/dist/helpers/InvitationHelper.cjs +15 -10
- package/dist/helpers/InvitationHelper.d.ts +6 -2
- package/dist/helpers/InvitationHelper.d.ts.map +1 -1
- package/dist/helpers/InvitationHelper.js +15 -10
- package/dist/helpers/InvitationHelper.js.map +1 -1
- package/dist/helpers/PermissionHelper.cjs +8 -12
- package/dist/helpers/PermissionHelper.d.ts +3 -0
- package/dist/helpers/PermissionHelper.d.ts.map +1 -1
- package/dist/helpers/PermissionHelper.js +8 -12
- package/dist/helpers/PermissionHelper.js.map +1 -1
- package/dist/middleware/hono.cjs +6 -6
- package/dist/middleware/hono.d.ts +3 -3
- package/dist/middleware/hono.js +6 -6
- package/dist/middleware/hono.js.map +1 -1
- package/dist/migrations/001_add_entities.cjs +41 -28
- package/dist/migrations/001_add_entities.d.ts.map +1 -1
- package/dist/migrations/001_add_entities.js +41 -28
- package/dist/migrations/001_add_entities.js.map +1 -1
- package/dist/schema/entities.cjs +30 -23
- package/dist/schema/entities.d.ts +61 -46
- package/dist/schema/entities.d.ts.map +1 -1
- package/dist/schema/entities.js +30 -23
- package/dist/schema/entities.js.map +1 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -3
package/CLAUDE.md
CHANGED
|
@@ -2,21 +2,81 @@
|
|
|
2
2
|
|
|
3
3
|
Shared backend library for multi-tenant entity/organization management.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**npm**: `@sudobility/entity_service` (public)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Entity management**: Personal workspaces and organizations
|
|
9
|
-
- **Member management**: Role-based access control (admin, manager, viewer)
|
|
10
|
-
- **Invitation system**: Email invitations with auto-accept on signup
|
|
11
|
-
- **Permission checking**: Granular permission checks
|
|
12
|
-
- **Hono middleware**: Entity context injection for routes
|
|
7
|
+
## Tech Stack
|
|
13
8
|
|
|
14
|
-
|
|
9
|
+
- **Language**: TypeScript (strict mode)
|
|
10
|
+
- **Runtime**: Bun
|
|
11
|
+
- **Build**: TypeScript compiler (dual ESM/CJS)
|
|
12
|
+
- **Test**: bun:test
|
|
13
|
+
- **Database**: PostgreSQL with Drizzle ORM
|
|
14
|
+
- **Framework**: Hono middleware
|
|
15
|
+
|
|
16
|
+
## Project Structure
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
src/
|
|
20
|
+
├── index.ts # Main exports
|
|
21
|
+
├── types/ # Type definitions
|
|
22
|
+
│ ├── entity.ts # Entity types
|
|
23
|
+
│ ├── member.ts # Member/role types
|
|
24
|
+
│ └── invitation.ts # Invitation types
|
|
25
|
+
├── helpers/ # Business logic
|
|
26
|
+
│ ├── EntityHelper.ts # Entity CRUD operations
|
|
27
|
+
│ ├── MemberHelper.ts # Member management
|
|
28
|
+
│ └── InvitationHelper.ts # Invitation handling
|
|
29
|
+
├── middleware/ # Hono middleware
|
|
30
|
+
│ └── entityContext.ts # Entity context injection
|
|
31
|
+
├── schema/ # Drizzle schema templates
|
|
32
|
+
│ ├── entities.ts
|
|
33
|
+
│ ├── entityMembers.ts
|
|
34
|
+
│ └── entityInvitations.ts
|
|
35
|
+
└── utils/ # Utilities
|
|
36
|
+
└── permissions.ts # Permission checks
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Commands
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bun run build # Build ESM + CJS
|
|
43
|
+
bun run verify # All checks + build (use before commit)
|
|
44
|
+
bun test # Run tests
|
|
45
|
+
bun run typecheck # TypeScript check
|
|
46
|
+
bun run lint # Run ESLint
|
|
47
|
+
bun run clean # Remove dist/
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Key Concepts
|
|
51
|
+
|
|
52
|
+
### Entities
|
|
53
|
+
- **Personal Entity**: Auto-created for each user (entitySlug = userId)
|
|
54
|
+
- **Organization**: Created by users, has members with roles
|
|
15
55
|
|
|
16
|
-
###
|
|
56
|
+
### Roles & Permissions
|
|
17
57
|
|
|
58
|
+
| Permission | Admin | Manager | Viewer |
|
|
59
|
+
|------------|-------|---------|--------|
|
|
60
|
+
| View entity | Yes | Yes | Yes |
|
|
61
|
+
| Edit entity | Yes | No | No |
|
|
62
|
+
| Delete entity | Yes | No | No |
|
|
63
|
+
| Manage members | Yes | No | No |
|
|
64
|
+
| Invite members | Yes | No | No |
|
|
65
|
+
| Manage projects | Yes | Yes | No |
|
|
66
|
+
| Create projects | Yes | Yes | No |
|
|
67
|
+
| View projects | Yes | Yes | Yes |
|
|
68
|
+
|
|
69
|
+
### Invitation Flow
|
|
70
|
+
1. Admin creates invitation with email + role
|
|
71
|
+
2. Invitation stored with entity reference
|
|
72
|
+
3. On user signup, pending invitations auto-accepted
|
|
73
|
+
4. User becomes member of invited entities
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
### Setup Helpers
|
|
18
78
|
```typescript
|
|
19
|
-
import { createEntityHelpers } from '@
|
|
79
|
+
import { createEntityHelpers } from '@sudobility/entity_service';
|
|
20
80
|
|
|
21
81
|
const helpers = createEntityHelpers({
|
|
22
82
|
db: drizzleDb,
|
|
@@ -28,7 +88,6 @@ const helpers = createEntityHelpers({
|
|
|
28
88
|
```
|
|
29
89
|
|
|
30
90
|
### Entity Operations
|
|
31
|
-
|
|
32
91
|
```typescript
|
|
33
92
|
// Get or create personal entity (on user login)
|
|
34
93
|
const personalEntity = await helpers.entity.getOrCreatePersonalEntity(userId, email);
|
|
@@ -43,36 +102,9 @@ const org = await helpers.entity.createOrganizationEntity(userId, {
|
|
|
43
102
|
const entities = await helpers.entity.getUserEntities(userId);
|
|
44
103
|
```
|
|
45
104
|
|
|
46
|
-
### Member Operations
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
// Add member
|
|
50
|
-
await helpers.members.addMember(entityId, userId, EntityRole.MANAGER);
|
|
51
|
-
|
|
52
|
-
// Update role
|
|
53
|
-
await helpers.members.updateMemberRole(entityId, userId, EntityRole.ADMIN);
|
|
54
|
-
|
|
55
|
-
// Remove member
|
|
56
|
-
await helpers.members.removeMember(entityId, userId);
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### Invitation Operations
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
// Create invitation
|
|
63
|
-
const invitation = await helpers.invitations.createInvitation(entityId, invitedBy, {
|
|
64
|
-
email: 'user@example.com',
|
|
65
|
-
role: EntityRole.VIEWER,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Process pending invitations for new user
|
|
69
|
-
await helpers.invitations.processNewUserInvitations(userId, email);
|
|
70
|
-
```
|
|
71
|
-
|
|
72
105
|
### Hono Middleware
|
|
73
|
-
|
|
74
106
|
```typescript
|
|
75
|
-
import { createEntityContextMiddleware } from '@
|
|
107
|
+
import { createEntityContextMiddleware } from '@sudobility/entity_service';
|
|
76
108
|
|
|
77
109
|
const entityContext = createEntityContextMiddleware(config, {
|
|
78
110
|
getUserId: (c) => c.get('userId'),
|
|
@@ -88,10 +120,10 @@ app.get('/api/v1/entities/:entitySlug/projects', (c) => {
|
|
|
88
120
|
|
|
89
121
|
## Database Schema
|
|
90
122
|
|
|
91
|
-
|
|
123
|
+
Factory functions for creating tables in any PostgreSQL schema:
|
|
92
124
|
|
|
93
125
|
```typescript
|
|
94
|
-
import { createEntitiesTable, createEntityMembersTable } from '@
|
|
126
|
+
import { createEntitiesTable, createEntityMembersTable } from '@sudobility/entity_service';
|
|
95
127
|
import { pgSchema } from 'drizzle-orm/pg-core';
|
|
96
128
|
|
|
97
129
|
const mySchema = pgSchema('my_app');
|
|
@@ -100,25 +132,37 @@ export const entities = createEntitiesTable(mySchema, 'my_app');
|
|
|
100
132
|
export const entityMembers = createEntityMembersTable(mySchema, 'my_app');
|
|
101
133
|
```
|
|
102
134
|
|
|
103
|
-
##
|
|
135
|
+
## Peer Dependencies
|
|
104
136
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
| Manage members | ✓ | ✗ | ✗ |
|
|
111
|
-
| Invite members | ✓ | ✗ | ✗ |
|
|
112
|
-
| Manage projects | ✓ | ✓ | ✗ |
|
|
113
|
-
| Create projects | ✓ | ✓ | ✗ |
|
|
114
|
-
| View projects | ✓ | ✓ | ✓ |
|
|
115
|
-
| Manage API keys | ✓ | ✓ | ✗ |
|
|
116
|
-
| View API keys | ✓ | ✓ | ✓ |
|
|
117
|
-
|
|
118
|
-
## Build
|
|
137
|
+
Required in consuming app:
|
|
138
|
+
- `drizzle-orm` - Database ORM
|
|
139
|
+
- `hono` - Web framework (for middleware)
|
|
140
|
+
|
|
141
|
+
## Publishing
|
|
119
142
|
|
|
120
143
|
```bash
|
|
121
|
-
bun run
|
|
122
|
-
|
|
123
|
-
|
|
144
|
+
bun run verify # All checks
|
|
145
|
+
npm publish # Publish to npm
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Architecture
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
entity_service (this package)
|
|
152
|
+
↑
|
|
153
|
+
shapeshyft_api (backend)
|
|
154
|
+
sudojo_api (backend)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Code Patterns
|
|
158
|
+
|
|
159
|
+
### Error Handling
|
|
160
|
+
- Invalid entity slug: Return 404
|
|
161
|
+
- Permission denied: Return 403
|
|
162
|
+
- Duplicate invitation: Return 409
|
|
163
|
+
|
|
164
|
+
### Type Imports
|
|
165
|
+
```typescript
|
|
166
|
+
import type { Entity, EntityMember, EntityRole } from '@sudobility/entity_service';
|
|
167
|
+
import { EntityRole, hasPermission } from '@sudobility/entity_service';
|
|
124
168
|
```
|
|
@@ -18,8 +18,10 @@ class EntityHelper {
|
|
|
18
18
|
/**
|
|
19
19
|
* Create a personal entity for a user.
|
|
20
20
|
* Called automatically when a user first logs in.
|
|
21
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
22
|
+
* @param email - Optional email for display name
|
|
21
23
|
*/
|
|
22
|
-
async createPersonalEntity(
|
|
24
|
+
async createPersonalEntity(firebaseUid, email) {
|
|
23
25
|
const slug = (0, utils_1.generateEntitySlug)();
|
|
24
26
|
const displayName = email?.split('@')[0] ?? 'Personal';
|
|
25
27
|
const [entity] = await this.config.db
|
|
@@ -28,37 +30,42 @@ class EntityHelper {
|
|
|
28
30
|
entity_slug: slug,
|
|
29
31
|
entity_type: types_1.EntityType.PERSONAL,
|
|
30
32
|
display_name: displayName,
|
|
31
|
-
owner_user_id: userId,
|
|
32
33
|
})
|
|
33
34
|
.returning();
|
|
34
|
-
// Add user as admin
|
|
35
|
+
// Add user as admin (personal entities use admin role, not owner)
|
|
35
36
|
await this.config.db.insert(this.config.membersTable).values({
|
|
36
37
|
entity_id: entity.id,
|
|
37
|
-
user_id:
|
|
38
|
+
user_id: firebaseUid,
|
|
38
39
|
role: types_1.EntityRole.ADMIN,
|
|
40
|
+
is_active: true,
|
|
39
41
|
});
|
|
40
42
|
return this.mapRecordToEntity(entity);
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
43
45
|
* Get or create a personal entity for a user.
|
|
44
46
|
* Ensures exactly one personal entity exists per user.
|
|
47
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
48
|
+
* @param email - Optional email for display name
|
|
45
49
|
*/
|
|
46
|
-
async getOrCreatePersonalEntity(
|
|
47
|
-
// Check for existing personal entity
|
|
50
|
+
async getOrCreatePersonalEntity(firebaseUid, email) {
|
|
51
|
+
// Check for existing personal entity where user is admin
|
|
48
52
|
const existing = await this.config.db
|
|
49
|
-
.select()
|
|
50
|
-
.from(this.config.
|
|
51
|
-
.
|
|
53
|
+
.select({ entity: this.config.entitiesTable })
|
|
54
|
+
.from(this.config.membersTable)
|
|
55
|
+
.innerJoin(this.config.entitiesTable, (0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, this.config.entitiesTable.id))
|
|
56
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.user_id, firebaseUid), (0, drizzle_orm_1.eq)(this.config.membersTable.role, types_1.EntityRole.ADMIN), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true), (0, drizzle_orm_1.eq)(this.config.entitiesTable.entity_type, types_1.EntityType.PERSONAL)))
|
|
52
57
|
.limit(1);
|
|
53
58
|
if (existing.length > 0) {
|
|
54
|
-
return this.mapRecordToEntity(existing[0]);
|
|
59
|
+
return this.mapRecordToEntity(existing[0].entity);
|
|
55
60
|
}
|
|
56
|
-
return this.createPersonalEntity(
|
|
61
|
+
return this.createPersonalEntity(firebaseUid, email);
|
|
57
62
|
}
|
|
58
63
|
/**
|
|
59
64
|
* Create an organization entity.
|
|
65
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
66
|
+
* @param request - Entity creation request
|
|
60
67
|
*/
|
|
61
|
-
async createOrganizationEntity(
|
|
68
|
+
async createOrganizationEntity(firebaseUid, request) {
|
|
62
69
|
// Determine slug
|
|
63
70
|
let slug;
|
|
64
71
|
if (request.entitySlug) {
|
|
@@ -81,14 +88,14 @@ class EntityHelper {
|
|
|
81
88
|
entity_type: types_1.EntityType.ORGANIZATION,
|
|
82
89
|
display_name: request.displayName,
|
|
83
90
|
description: request.description ?? null,
|
|
84
|
-
owner_user_id: userId,
|
|
85
91
|
})
|
|
86
92
|
.returning();
|
|
87
|
-
// Add creator as
|
|
93
|
+
// Add creator as owner
|
|
88
94
|
await this.config.db.insert(this.config.membersTable).values({
|
|
89
95
|
entity_id: entity.id,
|
|
90
|
-
user_id:
|
|
91
|
-
role: types_1.EntityRole.
|
|
96
|
+
user_id: firebaseUid,
|
|
97
|
+
role: types_1.EntityRole.OWNER,
|
|
98
|
+
is_active: true,
|
|
92
99
|
});
|
|
93
100
|
return this.mapRecordToEntity(entity);
|
|
94
101
|
}
|
|
@@ -123,8 +130,10 @@ class EntityHelper {
|
|
|
123
130
|
/**
|
|
124
131
|
* Get all entities a user is a member of.
|
|
125
132
|
* If the user has no entities, a personal entity is automatically created.
|
|
133
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
134
|
+
* @param email - Optional email for display name if creating personal entity
|
|
126
135
|
*/
|
|
127
|
-
async getUserEntities(
|
|
136
|
+
async getUserEntities(firebaseUid, email) {
|
|
128
137
|
const results = await this.config.db
|
|
129
138
|
.select({
|
|
130
139
|
entity: this.config.entitiesTable,
|
|
@@ -132,14 +141,14 @@ class EntityHelper {
|
|
|
132
141
|
})
|
|
133
142
|
.from(this.config.membersTable)
|
|
134
143
|
.innerJoin(this.config.entitiesTable, (0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, this.config.entitiesTable.id))
|
|
135
|
-
.where((0, drizzle_orm_1.eq)(this.config.membersTable.user_id,
|
|
144
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.user_id, firebaseUid), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true)));
|
|
136
145
|
// If user has no entities, create a personal entity for them
|
|
137
146
|
if (results.length === 0) {
|
|
138
|
-
const personalEntity = await this.createPersonalEntity(
|
|
147
|
+
const personalEntity = await this.createPersonalEntity(firebaseUid, email);
|
|
139
148
|
return [
|
|
140
149
|
{
|
|
141
150
|
...personalEntity,
|
|
142
|
-
userRole: types_1.EntityRole.
|
|
151
|
+
userRole: types_1.EntityRole.OWNER,
|
|
143
152
|
},
|
|
144
153
|
];
|
|
145
154
|
}
|
|
@@ -235,7 +244,6 @@ class EntityHelper {
|
|
|
235
244
|
displayName: record.display_name,
|
|
236
245
|
description: record.description,
|
|
237
246
|
avatarUrl: record.avatar_url,
|
|
238
|
-
ownerUserId: record.owner_user_id,
|
|
239
247
|
createdAt: record.created_at?.toISOString() ?? new Date().toISOString(),
|
|
240
248
|
updatedAt: record.updated_at?.toISOString() ?? new Date().toISOString(),
|
|
241
249
|
};
|
|
@@ -12,17 +12,23 @@ export declare class EntityHelper {
|
|
|
12
12
|
/**
|
|
13
13
|
* Create a personal entity for a user.
|
|
14
14
|
* Called automatically when a user first logs in.
|
|
15
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
16
|
+
* @param email - Optional email for display name
|
|
15
17
|
*/
|
|
16
|
-
createPersonalEntity(
|
|
18
|
+
createPersonalEntity(firebaseUid: string, email?: string): Promise<Entity>;
|
|
17
19
|
/**
|
|
18
20
|
* Get or create a personal entity for a user.
|
|
19
21
|
* Ensures exactly one personal entity exists per user.
|
|
22
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
23
|
+
* @param email - Optional email for display name
|
|
20
24
|
*/
|
|
21
|
-
getOrCreatePersonalEntity(
|
|
25
|
+
getOrCreatePersonalEntity(firebaseUid: string, email?: string): Promise<Entity>;
|
|
22
26
|
/**
|
|
23
27
|
* Create an organization entity.
|
|
28
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
29
|
+
* @param request - Entity creation request
|
|
24
30
|
*/
|
|
25
|
-
createOrganizationEntity(
|
|
31
|
+
createOrganizationEntity(firebaseUid: string, request: CreateEntityRequest): Promise<Entity>;
|
|
26
32
|
/**
|
|
27
33
|
* Get entity by ID.
|
|
28
34
|
*/
|
|
@@ -34,8 +40,10 @@ export declare class EntityHelper {
|
|
|
34
40
|
/**
|
|
35
41
|
* Get all entities a user is a member of.
|
|
36
42
|
* If the user has no entities, a personal entity is automatically created.
|
|
43
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
44
|
+
* @param email - Optional email for display name if creating personal entity
|
|
37
45
|
*/
|
|
38
|
-
getUserEntities(
|
|
46
|
+
getUserEntities(firebaseUid: string, email?: string): Promise<EntityWithRole[]>;
|
|
39
47
|
/**
|
|
40
48
|
* Update entity details.
|
|
41
49
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/EntityHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAGlB;;GAEG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,kBAAkB;IAEvD
|
|
1
|
+
{"version":3,"file":"EntityHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/EntityHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAGlB;;GAEG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,kBAAkB;IAEvD;;;;;OAKG;IACG,oBAAoB,CACxB,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;IAwBlB;;;;;OAKG;IACG,yBAAyB,CAC7B,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;IA0BlB;;;;OAIG;IACG,wBAAwB,CAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC;IAqClB;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAczD;;OAEG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAc3D;;;;;OAKG;IACG,eAAe,CACnB,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,EAAE,CAAC;IAmC5B;;OAEG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC;IAyClB;;;OAGG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAenD;;OAEG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUrD;;OAEG;YACW,kBAAkB;IAUhC;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAY1B"}
|
|
@@ -18,8 +18,10 @@ class EntityHelper {
|
|
|
18
18
|
/**
|
|
19
19
|
* Create a personal entity for a user.
|
|
20
20
|
* Called automatically when a user first logs in.
|
|
21
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
22
|
+
* @param email - Optional email for display name
|
|
21
23
|
*/
|
|
22
|
-
async createPersonalEntity(
|
|
24
|
+
async createPersonalEntity(firebaseUid, email) {
|
|
23
25
|
const slug = (0, utils_1.generateEntitySlug)();
|
|
24
26
|
const displayName = email?.split('@')[0] ?? 'Personal';
|
|
25
27
|
const [entity] = await this.config.db
|
|
@@ -28,37 +30,42 @@ class EntityHelper {
|
|
|
28
30
|
entity_slug: slug,
|
|
29
31
|
entity_type: types_1.EntityType.PERSONAL,
|
|
30
32
|
display_name: displayName,
|
|
31
|
-
owner_user_id: userId,
|
|
32
33
|
})
|
|
33
34
|
.returning();
|
|
34
|
-
// Add user as admin
|
|
35
|
+
// Add user as admin (personal entities use admin role, not owner)
|
|
35
36
|
await this.config.db.insert(this.config.membersTable).values({
|
|
36
37
|
entity_id: entity.id,
|
|
37
|
-
user_id:
|
|
38
|
+
user_id: firebaseUid,
|
|
38
39
|
role: types_1.EntityRole.ADMIN,
|
|
40
|
+
is_active: true,
|
|
39
41
|
});
|
|
40
42
|
return this.mapRecordToEntity(entity);
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
43
45
|
* Get or create a personal entity for a user.
|
|
44
46
|
* Ensures exactly one personal entity exists per user.
|
|
47
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
48
|
+
* @param email - Optional email for display name
|
|
45
49
|
*/
|
|
46
|
-
async getOrCreatePersonalEntity(
|
|
47
|
-
// Check for existing personal entity
|
|
50
|
+
async getOrCreatePersonalEntity(firebaseUid, email) {
|
|
51
|
+
// Check for existing personal entity where user is admin
|
|
48
52
|
const existing = await this.config.db
|
|
49
|
-
.select()
|
|
50
|
-
.from(this.config.
|
|
51
|
-
.
|
|
53
|
+
.select({ entity: this.config.entitiesTable })
|
|
54
|
+
.from(this.config.membersTable)
|
|
55
|
+
.innerJoin(this.config.entitiesTable, (0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, this.config.entitiesTable.id))
|
|
56
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.user_id, firebaseUid), (0, drizzle_orm_1.eq)(this.config.membersTable.role, types_1.EntityRole.ADMIN), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true), (0, drizzle_orm_1.eq)(this.config.entitiesTable.entity_type, types_1.EntityType.PERSONAL)))
|
|
52
57
|
.limit(1);
|
|
53
58
|
if (existing.length > 0) {
|
|
54
|
-
return this.mapRecordToEntity(existing[0]);
|
|
59
|
+
return this.mapRecordToEntity(existing[0].entity);
|
|
55
60
|
}
|
|
56
|
-
return this.createPersonalEntity(
|
|
61
|
+
return this.createPersonalEntity(firebaseUid, email);
|
|
57
62
|
}
|
|
58
63
|
/**
|
|
59
64
|
* Create an organization entity.
|
|
65
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
66
|
+
* @param request - Entity creation request
|
|
60
67
|
*/
|
|
61
|
-
async createOrganizationEntity(
|
|
68
|
+
async createOrganizationEntity(firebaseUid, request) {
|
|
62
69
|
// Determine slug
|
|
63
70
|
let slug;
|
|
64
71
|
if (request.entitySlug) {
|
|
@@ -81,14 +88,14 @@ class EntityHelper {
|
|
|
81
88
|
entity_type: types_1.EntityType.ORGANIZATION,
|
|
82
89
|
display_name: request.displayName,
|
|
83
90
|
description: request.description ?? null,
|
|
84
|
-
owner_user_id: userId,
|
|
85
91
|
})
|
|
86
92
|
.returning();
|
|
87
|
-
// Add creator as
|
|
93
|
+
// Add creator as owner
|
|
88
94
|
await this.config.db.insert(this.config.membersTable).values({
|
|
89
95
|
entity_id: entity.id,
|
|
90
|
-
user_id:
|
|
91
|
-
role: types_1.EntityRole.
|
|
96
|
+
user_id: firebaseUid,
|
|
97
|
+
role: types_1.EntityRole.OWNER,
|
|
98
|
+
is_active: true,
|
|
92
99
|
});
|
|
93
100
|
return this.mapRecordToEntity(entity);
|
|
94
101
|
}
|
|
@@ -123,8 +130,10 @@ class EntityHelper {
|
|
|
123
130
|
/**
|
|
124
131
|
* Get all entities a user is a member of.
|
|
125
132
|
* If the user has no entities, a personal entity is automatically created.
|
|
133
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
134
|
+
* @param email - Optional email for display name if creating personal entity
|
|
126
135
|
*/
|
|
127
|
-
async getUserEntities(
|
|
136
|
+
async getUserEntities(firebaseUid, email) {
|
|
128
137
|
const results = await this.config.db
|
|
129
138
|
.select({
|
|
130
139
|
entity: this.config.entitiesTable,
|
|
@@ -132,14 +141,14 @@ class EntityHelper {
|
|
|
132
141
|
})
|
|
133
142
|
.from(this.config.membersTable)
|
|
134
143
|
.innerJoin(this.config.entitiesTable, (0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, this.config.entitiesTable.id))
|
|
135
|
-
.where((0, drizzle_orm_1.eq)(this.config.membersTable.user_id,
|
|
144
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.user_id, firebaseUid), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true)));
|
|
136
145
|
// If user has no entities, create a personal entity for them
|
|
137
146
|
if (results.length === 0) {
|
|
138
|
-
const personalEntity = await this.createPersonalEntity(
|
|
147
|
+
const personalEntity = await this.createPersonalEntity(firebaseUid, email);
|
|
139
148
|
return [
|
|
140
149
|
{
|
|
141
150
|
...personalEntity,
|
|
142
|
-
userRole: types_1.EntityRole.
|
|
151
|
+
userRole: types_1.EntityRole.OWNER,
|
|
143
152
|
},
|
|
144
153
|
];
|
|
145
154
|
}
|
|
@@ -235,7 +244,6 @@ class EntityHelper {
|
|
|
235
244
|
displayName: record.display_name,
|
|
236
245
|
description: record.description,
|
|
237
246
|
avatarUrl: record.avatar_url,
|
|
238
|
-
ownerUserId: record.owner_user_id,
|
|
239
247
|
createdAt: record.created_at?.toISOString() ?? new Date().toISOString(),
|
|
240
248
|
updatedAt: record.updated_at?.toISOString() ?? new Date().toISOString(),
|
|
241
249
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityHelper.js","sourceRoot":"","sources":["../../src/helpers/EntityHelper.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6CAAsC;AACtC,oCAQkB;AAClB,oCAA2E;AAE3E;;GAEG;AACH,MAAa,YAAY;IACvB,YAA6B,MAA0B;QAA1B,WAAM,GAAN,MAAM,CAAoB;IAAG,CAAC;IAE3D
|
|
1
|
+
{"version":3,"file":"EntityHelper.js","sourceRoot":"","sources":["../../src/helpers/EntityHelper.ts"],"names":[],"mappings":"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"}
|