@elevasis/core 0.11.1 → 0.12.0
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/dist/index.d.ts +2 -2
- package/dist/index.js +10 -11
- package/dist/organization-model/index.d.ts +2 -2
- package/dist/organization-model/index.js +10 -11
- package/dist/test-utils/index.d.ts +10 -3
- package/dist/test-utils/index.js +6 -6
- package/package.json +1 -1
- package/src/__tests__/template-core-compatibility.test.ts +6 -15
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +27 -270
- package/src/auth/multi-tenancy/credentials/server/encryption.ts +83 -39
- package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +47 -0
- package/src/auth/multi-tenancy/index.ts +3 -0
- package/src/auth/multi-tenancy/invitations/api-schemas.ts +104 -107
- package/src/auth/multi-tenancy/memberships/api-schemas.ts +6 -5
- package/src/auth/multi-tenancy/memberships/membership.ts +130 -138
- package/src/auth/multi-tenancy/role-management/api-schemas.ts +78 -0
- package/src/auth/multi-tenancy/role-management/index.ts +16 -0
- package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +299 -293
- package/src/execution/engine/tools/integration/service.test.ts +214 -0
- package/src/execution/engine/tools/integration/service.ts +169 -161
- package/src/integrations/credentials/__tests__/api-schemas.test.ts +420 -496
- package/src/integrations/credentials/api-schemas.ts +127 -143
- package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +327 -318
- package/src/integrations/webhook-endpoints/api-schemas.ts +103 -102
- package/src/integrations/webhook-endpoints/types.ts +58 -51
- package/src/operations/activities/api-schemas.ts +80 -79
- package/src/operations/activities/types.ts +64 -63
- package/src/organization-model/contracts.ts +1 -1
- package/src/organization-model/defaults.ts +6 -6
- package/src/organization-model/domains/navigation.ts +38 -37
- package/src/organization-model/foundation.ts +2 -3
- package/src/organization-model/published.ts +3 -3
- package/src/platform/constants/versions.ts +1 -1
- package/src/reference/_generated/contracts.md +27 -270
- package/src/scaffold-registry/__tests__/index.test.ts +72 -7
- package/src/scaffold-registry/index.ts +159 -26
- package/src/server.ts +281 -272
- package/src/supabase/database.types.ts +7 -3
|
@@ -1,107 +1,104 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Invitations Domain - Zod Validation Schemas
|
|
3
|
-
*
|
|
4
|
-
* Validation schemas for invitation management endpoints.
|
|
5
|
-
* Includes request bodies, query params, and path params.
|
|
6
|
-
*
|
|
7
|
-
* Security:
|
|
8
|
-
* - All schemas use .strict() to prevent mass assignment attacks
|
|
9
|
-
* - Email validation prevents header injection
|
|
10
|
-
* - Role enum validation prevents privilege escalation
|
|
11
|
-
* - organizationId from JWT (not accepted in body for protected routes)
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { z } from 'zod'
|
|
15
|
-
import { EmailSchema } from '../../../platform/utils/validation'
|
|
16
|
-
import { MembershipRoleSchema } from '../memberships/api-schemas'
|
|
17
|
-
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// Path Parameters
|
|
20
|
-
// ============================================================================
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Validate invitation ID in URL path
|
|
24
|
-
* Used by: GET/DELETE /invitations/:id
|
|
25
|
-
*/
|
|
26
|
-
export const InvitationIdParamSchema = z
|
|
27
|
-
.object({
|
|
28
|
-
id: z.string().min(1) // WorkOS invitation IDs
|
|
29
|
-
})
|
|
30
|
-
.strict()
|
|
31
|
-
|
|
32
|
-
// ============================================================================
|
|
33
|
-
// Request Bodies
|
|
34
|
-
// ============================================================================
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Send new invitation
|
|
38
|
-
* POST /invitations
|
|
39
|
-
*
|
|
40
|
-
* Security:
|
|
41
|
-
* - Email format validated (prevents header injection)
|
|
42
|
-
* -
|
|
43
|
-
* - expiresInDays bounded (1-90 days)
|
|
44
|
-
* - organizationId NOT in body (from JWT via requireOrganization middleware)
|
|
45
|
-
*/
|
|
46
|
-
export const SendInvitationSchema = z
|
|
47
|
-
.object({
|
|
48
|
-
email: EmailSchema,
|
|
49
|
-
organizationId: z.string().optional(), // For WorkOS API - but typically from JWT
|
|
50
|
-
roleSlug: MembershipRoleSchema.default('member'),
|
|
51
|
-
expiresInDays: z.number().int().min(1).max(90).default(7)
|
|
52
|
-
})
|
|
53
|
-
.strict()
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Accept invitation by token
|
|
57
|
-
* POST /invitations/accept
|
|
58
|
-
*
|
|
59
|
-
* Security:
|
|
60
|
-
* - Token validated (non-empty string)
|
|
61
|
-
*/
|
|
62
|
-
export const AcceptInvitationSchema = z
|
|
63
|
-
.object({
|
|
64
|
-
invitation_token: z.string().min(1, 'Invitation token is required')
|
|
65
|
-
})
|
|
66
|
-
.strict()
|
|
67
|
-
|
|
68
|
-
// ============================================================================
|
|
69
|
-
// Query Parameters
|
|
70
|
-
// ============================================================================
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* List invitations with filters
|
|
74
|
-
* GET /invitations
|
|
75
|
-
*
|
|
76
|
-
* Filters:
|
|
77
|
-
* - organizationId: Filter by organization
|
|
78
|
-
* - email: Filter by email
|
|
79
|
-
*
|
|
80
|
-
* Security:
|
|
81
|
-
* - Requires organizationId or userId filter
|
|
82
|
-
* - Email validated
|
|
83
|
-
*/
|
|
84
|
-
export const ListInvitationsQuerySchema = z
|
|
85
|
-
.object({
|
|
86
|
-
organizationId: z.string().optional(),
|
|
87
|
-
userId: z.string().optional(),
|
|
88
|
-
email: EmailSchema.optional(),
|
|
89
|
-
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
90
|
-
before: z.string().optional(), // WorkOS pagination cursor
|
|
91
|
-
after: z.string().optional()
|
|
92
|
-
})
|
|
93
|
-
.strict()
|
|
94
|
-
.refine(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
export type
|
|
105
|
-
export type AcceptInvitationInput = z.infer<typeof AcceptInvitationSchema>
|
|
106
|
-
export type ListInvitationsQuery = z.infer<typeof ListInvitationsQuerySchema>
|
|
107
|
-
export type InvitationIdParam = z.infer<typeof InvitationIdParamSchema>
|
|
1
|
+
/**
|
|
2
|
+
* Invitations Domain - Zod Validation Schemas
|
|
3
|
+
*
|
|
4
|
+
* Validation schemas for invitation management endpoints.
|
|
5
|
+
* Includes request bodies, query params, and path params.
|
|
6
|
+
*
|
|
7
|
+
* Security:
|
|
8
|
+
* - All schemas use .strict() to prevent mass assignment attacks
|
|
9
|
+
* - Email validation prevents header injection
|
|
10
|
+
* - Role enum validation prevents privilege escalation
|
|
11
|
+
* - organizationId from JWT (not accepted in body for protected routes)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { z } from 'zod'
|
|
15
|
+
import { EmailSchema } from '../../../platform/utils/validation'
|
|
16
|
+
import { MembershipRoleSchema } from '../memberships/api-schemas'
|
|
17
|
+
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Path Parameters
|
|
20
|
+
// ============================================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validate invitation ID in URL path
|
|
24
|
+
* Used by: GET/DELETE /invitations/:id
|
|
25
|
+
*/
|
|
26
|
+
export const InvitationIdParamSchema = z
|
|
27
|
+
.object({
|
|
28
|
+
id: z.string().min(1) // WorkOS invitation IDs
|
|
29
|
+
})
|
|
30
|
+
.strict()
|
|
31
|
+
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// Request Bodies
|
|
34
|
+
// ============================================================================
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Send new invitation
|
|
38
|
+
* POST /invitations
|
|
39
|
+
*
|
|
40
|
+
* Security:
|
|
41
|
+
* - Email format validated (prevents header injection)
|
|
42
|
+
* - roleSlug validated as non-empty slug; service layer checks against org_rol_definitions
|
|
43
|
+
* - expiresInDays bounded (1-90 days)
|
|
44
|
+
* - organizationId NOT in body (from JWT via requireOrganization middleware)
|
|
45
|
+
*/
|
|
46
|
+
export const SendInvitationSchema = z
|
|
47
|
+
.object({
|
|
48
|
+
email: EmailSchema,
|
|
49
|
+
organizationId: z.string().optional(), // For WorkOS API - but typically from JWT
|
|
50
|
+
roleSlug: MembershipRoleSchema.default('member'),
|
|
51
|
+
expiresInDays: z.number().int().min(1).max(90).default(7)
|
|
52
|
+
})
|
|
53
|
+
.strict()
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Accept invitation by token
|
|
57
|
+
* POST /invitations/accept
|
|
58
|
+
*
|
|
59
|
+
* Security:
|
|
60
|
+
* - Token validated (non-empty string)
|
|
61
|
+
*/
|
|
62
|
+
export const AcceptInvitationSchema = z
|
|
63
|
+
.object({
|
|
64
|
+
invitation_token: z.string().min(1, 'Invitation token is required')
|
|
65
|
+
})
|
|
66
|
+
.strict()
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// Query Parameters
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* List invitations with filters
|
|
74
|
+
* GET /invitations
|
|
75
|
+
*
|
|
76
|
+
* Filters:
|
|
77
|
+
* - organizationId: Filter by organization
|
|
78
|
+
* - email: Filter by email
|
|
79
|
+
*
|
|
80
|
+
* Security:
|
|
81
|
+
* - Requires organizationId or userId filter
|
|
82
|
+
* - Email validated
|
|
83
|
+
*/
|
|
84
|
+
export const ListInvitationsQuerySchema = z
|
|
85
|
+
.object({
|
|
86
|
+
organizationId: z.string().optional(),
|
|
87
|
+
userId: z.string().optional(),
|
|
88
|
+
email: EmailSchema.optional(),
|
|
89
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
90
|
+
before: z.string().optional(), // WorkOS pagination cursor
|
|
91
|
+
after: z.string().optional() // WorkOS pagination cursor
|
|
92
|
+
})
|
|
93
|
+
.strict()
|
|
94
|
+
.refine((data) => data.organizationId || data.userId, { message: 'Either organizationId or userId must be provided' })
|
|
95
|
+
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// TypeScript Type Exports
|
|
98
|
+
// ============================================================================
|
|
99
|
+
|
|
100
|
+
// Export inferred types for use in route handlers
|
|
101
|
+
export type SendInvitationInput = z.infer<typeof SendInvitationSchema>
|
|
102
|
+
export type AcceptInvitationInput = z.infer<typeof AcceptInvitationSchema>
|
|
103
|
+
export type ListInvitationsQuery = z.infer<typeof ListInvitationsQuerySchema>
|
|
104
|
+
export type InvitationIdParam = z.infer<typeof InvitationIdParamSchema>
|
|
@@ -19,11 +19,12 @@ import { z } from 'zod'
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Membership role validation
|
|
22
|
-
*
|
|
22
|
+
* Accepts any non-empty role slug (max 64 chars).
|
|
23
23
|
*
|
|
24
|
-
*
|
|
24
|
+
* Roles are now DB-driven via `org_rol_definitions`. Runtime validation
|
|
25
|
+
* against valid slugs happens at the service layer, not here.
|
|
25
26
|
*/
|
|
26
|
-
export const MembershipRoleSchema = z.
|
|
27
|
+
export const MembershipRoleSchema = z.string().min(1).max(64)
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Membership status validation
|
|
@@ -73,7 +74,7 @@ export const MyOrgPermissionsResponseSchema = z.object({
|
|
|
73
74
|
* Security:
|
|
74
75
|
* - userId must be valid (string format for WorkOS)
|
|
75
76
|
* - organizationId must be valid (string format for WorkOS)
|
|
76
|
-
* - roleSlug
|
|
77
|
+
* - roleSlug validated as non-empty slug; service layer checks against org_rol_definitions
|
|
77
78
|
* - Strict mode prevents injection
|
|
78
79
|
*/
|
|
79
80
|
export const CreateMembershipSchema = z
|
|
@@ -90,7 +91,7 @@ export const CreateMembershipSchema = z
|
|
|
90
91
|
*
|
|
91
92
|
* Security:
|
|
92
93
|
* - Only roleSlug can be updated
|
|
93
|
-
* -
|
|
94
|
+
* - Service layer validates slug against org_rol_definitions
|
|
94
95
|
*/
|
|
95
96
|
export const UpdateMembershipSchema = z
|
|
96
97
|
.object({
|
|
@@ -1,138 +1,130 @@
|
|
|
1
|
-
import type { MembershipFeatureConfig } from '../types'
|
|
2
|
-
import { type MembershipStatus } from './api-schemas.js'
|
|
3
|
-
|
|
4
|
-
export type { MembershipStatus }
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Organization Membership types based on WorkOS API
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
export interface OrganizationMembership {
|
|
11
|
-
object: 'organization_membership'
|
|
12
|
-
id: string
|
|
13
|
-
userId: string
|
|
14
|
-
organizationId: string
|
|
15
|
-
role: {
|
|
16
|
-
slug: string
|
|
17
|
-
}
|
|
18
|
-
status: 'active' | 'inactive'
|
|
19
|
-
createdAt: string
|
|
20
|
-
updatedAt: string
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Request interfaces for membership operations
|
|
25
|
-
*/
|
|
26
|
-
export interface CreateMembershipRequest {
|
|
27
|
-
userId: string
|
|
28
|
-
organizationId: string
|
|
29
|
-
roleSlug?: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface UpdateMembershipRequest {
|
|
33
|
-
roleSlug: string
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface ListMembershipsParams {
|
|
37
|
-
userId?: string
|
|
38
|
-
organizationId?: string
|
|
39
|
-
statuses?: MembershipStatus[]
|
|
40
|
-
limit?: number
|
|
41
|
-
before?: string
|
|
42
|
-
after?: string
|
|
43
|
-
order?: 'asc' | 'desc'
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Response interfaces
|
|
48
|
-
*/
|
|
49
|
-
export interface ListMembershipsResponse {
|
|
50
|
-
data: OrganizationMembership[]
|
|
51
|
-
listMetadata?: {
|
|
52
|
-
before?: string | null
|
|
53
|
-
after?: string | null
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Extended membership with user and organization details for UI
|
|
59
|
-
*/
|
|
60
|
-
export interface MembershipWithDetails extends OrganizationMembership {
|
|
61
|
-
user?: {
|
|
62
|
-
id: string
|
|
63
|
-
email: string
|
|
64
|
-
firstName?: string
|
|
65
|
-
lastName?: string
|
|
66
|
-
profilePictureUrl?: string
|
|
67
|
-
}
|
|
68
|
-
organization?: {
|
|
69
|
-
id: string
|
|
70
|
-
name: string
|
|
71
|
-
workos_org_id: string
|
|
72
|
-
primaryDomain?: string
|
|
73
|
-
is_test?: boolean
|
|
74
|
-
status?: string
|
|
75
|
-
metadata?: Record<string, unknown>
|
|
76
|
-
config?: Record<string, unknown>
|
|
77
|
-
}
|
|
78
|
-
config?: MembershipFeatureConfig
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* UI-specific membership table row data
|
|
83
|
-
*/
|
|
84
|
-
export interface MembershipTableRow {
|
|
85
|
-
id: string
|
|
86
|
-
userId: string
|
|
87
|
-
organizationId: string
|
|
88
|
-
userEmail: string
|
|
89
|
-
userFullName: string
|
|
90
|
-
organizationName: string
|
|
91
|
-
role: string
|
|
92
|
-
status: MembershipStatus
|
|
93
|
-
statusBadge: 'active' | 'inactive'
|
|
94
|
-
joinedAt: Date
|
|
95
|
-
updatedAt: Date
|
|
96
|
-
canEdit: boolean
|
|
97
|
-
canRemove: boolean
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Transform membership to table row format
|
|
102
|
-
*/
|
|
103
|
-
export function transformMembershipToTableRow(membership: MembershipWithDetails): MembershipTableRow {
|
|
104
|
-
return {
|
|
105
|
-
id: membership.id,
|
|
106
|
-
userId: membership.userId,
|
|
107
|
-
organizationId: membership.organizationId,
|
|
108
|
-
userEmail: membership.user?.email || 'Unknown',
|
|
109
|
-
userFullName:
|
|
110
|
-
membership.user?.firstName && membership.user?.lastName
|
|
111
|
-
? `${membership.user.firstName} ${membership.user.lastName}`
|
|
112
|
-
: membership.user?.email || 'Unknown User',
|
|
113
|
-
organizationName: membership.organization?.name || 'Unknown Organization',
|
|
114
|
-
role: membership.role.slug,
|
|
115
|
-
status: membership.status,
|
|
116
|
-
statusBadge: membership.status,
|
|
117
|
-
joinedAt: new Date(membership.createdAt),
|
|
118
|
-
updatedAt: new Date(membership.updatedAt),
|
|
119
|
-
canEdit: membership.status === 'active',
|
|
120
|
-
canRemove: true
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Membership status color mapping for UI
|
|
126
|
-
*/
|
|
127
|
-
export const MEMBERSHIP_STATUS_COLORS = {
|
|
128
|
-
active: 'green',
|
|
129
|
-
inactive: 'gray'
|
|
130
|
-
} as const
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Membership role options (can be extended)
|
|
134
|
-
*/
|
|
135
|
-
export const DEFAULT_MEMBERSHIP_ROLES = [
|
|
136
|
-
{ value: 'admin', label: 'Admin' },
|
|
137
|
-
{ value: 'member', label: 'Member' }
|
|
138
|
-
] as const
|
|
1
|
+
import type { MembershipFeatureConfig } from '../types'
|
|
2
|
+
import { type MembershipStatus } from './api-schemas.js'
|
|
3
|
+
|
|
4
|
+
export type { MembershipStatus }
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Organization Membership types based on WorkOS API
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface OrganizationMembership {
|
|
11
|
+
object: 'organization_membership'
|
|
12
|
+
id: string
|
|
13
|
+
userId: string
|
|
14
|
+
organizationId: string
|
|
15
|
+
role: {
|
|
16
|
+
slug: string
|
|
17
|
+
}
|
|
18
|
+
status: 'active' | 'inactive'
|
|
19
|
+
createdAt: string
|
|
20
|
+
updatedAt: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Request interfaces for membership operations
|
|
25
|
+
*/
|
|
26
|
+
export interface CreateMembershipRequest {
|
|
27
|
+
userId: string
|
|
28
|
+
organizationId: string
|
|
29
|
+
roleSlug?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface UpdateMembershipRequest {
|
|
33
|
+
roleSlug: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ListMembershipsParams {
|
|
37
|
+
userId?: string
|
|
38
|
+
organizationId?: string
|
|
39
|
+
statuses?: MembershipStatus[]
|
|
40
|
+
limit?: number
|
|
41
|
+
before?: string
|
|
42
|
+
after?: string
|
|
43
|
+
order?: 'asc' | 'desc'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Response interfaces
|
|
48
|
+
*/
|
|
49
|
+
export interface ListMembershipsResponse {
|
|
50
|
+
data: OrganizationMembership[]
|
|
51
|
+
listMetadata?: {
|
|
52
|
+
before?: string | null
|
|
53
|
+
after?: string | null
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Extended membership with user and organization details for UI
|
|
59
|
+
*/
|
|
60
|
+
export interface MembershipWithDetails extends OrganizationMembership {
|
|
61
|
+
user?: {
|
|
62
|
+
id: string
|
|
63
|
+
email: string
|
|
64
|
+
firstName?: string
|
|
65
|
+
lastName?: string
|
|
66
|
+
profilePictureUrl?: string
|
|
67
|
+
}
|
|
68
|
+
organization?: {
|
|
69
|
+
id: string
|
|
70
|
+
name: string
|
|
71
|
+
workos_org_id: string
|
|
72
|
+
primaryDomain?: string
|
|
73
|
+
is_test?: boolean
|
|
74
|
+
status?: string
|
|
75
|
+
metadata?: Record<string, unknown>
|
|
76
|
+
config?: Record<string, unknown>
|
|
77
|
+
}
|
|
78
|
+
config?: MembershipFeatureConfig
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* UI-specific membership table row data
|
|
83
|
+
*/
|
|
84
|
+
export interface MembershipTableRow {
|
|
85
|
+
id: string
|
|
86
|
+
userId: string
|
|
87
|
+
organizationId: string
|
|
88
|
+
userEmail: string
|
|
89
|
+
userFullName: string
|
|
90
|
+
organizationName: string
|
|
91
|
+
role: string
|
|
92
|
+
status: MembershipStatus
|
|
93
|
+
statusBadge: 'active' | 'inactive'
|
|
94
|
+
joinedAt: Date
|
|
95
|
+
updatedAt: Date
|
|
96
|
+
canEdit: boolean
|
|
97
|
+
canRemove: boolean
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Transform membership to table row format
|
|
102
|
+
*/
|
|
103
|
+
export function transformMembershipToTableRow(membership: MembershipWithDetails): MembershipTableRow {
|
|
104
|
+
return {
|
|
105
|
+
id: membership.id,
|
|
106
|
+
userId: membership.userId,
|
|
107
|
+
organizationId: membership.organizationId,
|
|
108
|
+
userEmail: membership.user?.email || 'Unknown',
|
|
109
|
+
userFullName:
|
|
110
|
+
membership.user?.firstName && membership.user?.lastName
|
|
111
|
+
? `${membership.user.firstName} ${membership.user.lastName}`
|
|
112
|
+
: membership.user?.email || 'Unknown User',
|
|
113
|
+
organizationName: membership.organization?.name || 'Unknown Organization',
|
|
114
|
+
role: membership.role.slug,
|
|
115
|
+
status: membership.status,
|
|
116
|
+
statusBadge: membership.status,
|
|
117
|
+
joinedAt: new Date(membership.createdAt),
|
|
118
|
+
updatedAt: new Date(membership.updatedAt),
|
|
119
|
+
canEdit: membership.status === 'active',
|
|
120
|
+
canRemove: true
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Membership status color mapping for UI
|
|
126
|
+
*/
|
|
127
|
+
export const MEMBERSHIP_STATUS_COLORS = {
|
|
128
|
+
active: 'green',
|
|
129
|
+
inactive: 'gray'
|
|
130
|
+
} as const
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
const PermissionKeySchema = z.string().min(1).max(100)
|
|
4
|
+
|
|
5
|
+
export const OrgRoleParamsSchema = z
|
|
6
|
+
.object({
|
|
7
|
+
orgId: z.string().uuid(),
|
|
8
|
+
roleId: z.string().uuid()
|
|
9
|
+
})
|
|
10
|
+
.strict()
|
|
11
|
+
|
|
12
|
+
export const OrgRolesParamsSchema = z
|
|
13
|
+
.object({
|
|
14
|
+
orgId: z.string().uuid()
|
|
15
|
+
})
|
|
16
|
+
.strict()
|
|
17
|
+
|
|
18
|
+
export const MembershipRoleParamsSchema = z
|
|
19
|
+
.object({
|
|
20
|
+
membershipId: z.string().min(1),
|
|
21
|
+
roleId: z.string().uuid()
|
|
22
|
+
})
|
|
23
|
+
.strict()
|
|
24
|
+
|
|
25
|
+
export const MembershipParamsSchema = z
|
|
26
|
+
.object({
|
|
27
|
+
membershipId: z.string().min(1)
|
|
28
|
+
})
|
|
29
|
+
.strict()
|
|
30
|
+
|
|
31
|
+
export const CreateOrgRoleRequestSchema = z
|
|
32
|
+
.object({
|
|
33
|
+
name: z.string().min(1).max(100).trim(),
|
|
34
|
+
slug: z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1)
|
|
37
|
+
.max(100)
|
|
38
|
+
.regex(/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/, 'Role slug must be lowercase letters, numbers, dashes, or underscores'),
|
|
39
|
+
description: z.string().max(500).trim().optional(),
|
|
40
|
+
permissionKeys: z.array(PermissionKeySchema).default([])
|
|
41
|
+
})
|
|
42
|
+
.strict()
|
|
43
|
+
|
|
44
|
+
export const UpdateOrgRoleRequestSchema = z
|
|
45
|
+
.object({
|
|
46
|
+
name: z.string().min(1).max(100).trim().optional(),
|
|
47
|
+
slug: z
|
|
48
|
+
.string()
|
|
49
|
+
.min(1)
|
|
50
|
+
.max(100)
|
|
51
|
+
.regex(/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/, 'Role slug must be lowercase letters, numbers, dashes, or underscores')
|
|
52
|
+
.optional(),
|
|
53
|
+
description: z.string().max(500).trim().nullable().optional(),
|
|
54
|
+
permissionKeys: z.array(PermissionKeySchema).optional()
|
|
55
|
+
})
|
|
56
|
+
.strict()
|
|
57
|
+
.refine(
|
|
58
|
+
(data) =>
|
|
59
|
+
data.name !== undefined ||
|
|
60
|
+
data.slug !== undefined ||
|
|
61
|
+
data.description !== undefined ||
|
|
62
|
+
data.permissionKeys !== undefined,
|
|
63
|
+
{ message: 'At least one field must be provided' }
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
export const AssignMembershipRoleRequestSchema = z
|
|
67
|
+
.object({
|
|
68
|
+
roleId: z.string().uuid()
|
|
69
|
+
})
|
|
70
|
+
.strict()
|
|
71
|
+
|
|
72
|
+
export type OrgRoleParams = z.infer<typeof OrgRoleParamsSchema>
|
|
73
|
+
export type OrgRolesParams = z.infer<typeof OrgRolesParamsSchema>
|
|
74
|
+
export type MembershipRoleParams = z.infer<typeof MembershipRoleParamsSchema>
|
|
75
|
+
export type MembershipParams = z.infer<typeof MembershipParamsSchema>
|
|
76
|
+
export type CreateOrgRoleInput = z.infer<typeof CreateOrgRoleRequestSchema>
|
|
77
|
+
export type UpdateOrgRoleInput = z.infer<typeof UpdateOrgRoleRequestSchema>
|
|
78
|
+
export type AssignMembershipRoleInput = z.infer<typeof AssignMembershipRoleRequestSchema>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AssignMembershipRoleRequestSchema,
|
|
3
|
+
CreateOrgRoleRequestSchema,
|
|
4
|
+
MembershipParamsSchema,
|
|
5
|
+
MembershipRoleParamsSchema,
|
|
6
|
+
OrgRoleParamsSchema,
|
|
7
|
+
OrgRolesParamsSchema,
|
|
8
|
+
UpdateOrgRoleRequestSchema,
|
|
9
|
+
type AssignMembershipRoleInput,
|
|
10
|
+
type CreateOrgRoleInput,
|
|
11
|
+
type MembershipParams,
|
|
12
|
+
type MembershipRoleParams,
|
|
13
|
+
type OrgRoleParams,
|
|
14
|
+
type OrgRolesParams,
|
|
15
|
+
type UpdateOrgRoleInput
|
|
16
|
+
} from './api-schemas'
|