@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.
Files changed (38) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/index.js +10 -11
  3. package/dist/organization-model/index.d.ts +2 -2
  4. package/dist/organization-model/index.js +10 -11
  5. package/dist/test-utils/index.d.ts +10 -3
  6. package/dist/test-utils/index.js +6 -6
  7. package/package.json +1 -1
  8. package/src/__tests__/template-core-compatibility.test.ts +6 -15
  9. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +27 -270
  10. package/src/auth/multi-tenancy/credentials/server/encryption.ts +83 -39
  11. package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +47 -0
  12. package/src/auth/multi-tenancy/index.ts +3 -0
  13. package/src/auth/multi-tenancy/invitations/api-schemas.ts +104 -107
  14. package/src/auth/multi-tenancy/memberships/api-schemas.ts +6 -5
  15. package/src/auth/multi-tenancy/memberships/membership.ts +130 -138
  16. package/src/auth/multi-tenancy/role-management/api-schemas.ts +78 -0
  17. package/src/auth/multi-tenancy/role-management/index.ts +16 -0
  18. package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +299 -293
  19. package/src/execution/engine/tools/integration/service.test.ts +214 -0
  20. package/src/execution/engine/tools/integration/service.ts +169 -161
  21. package/src/integrations/credentials/__tests__/api-schemas.test.ts +420 -496
  22. package/src/integrations/credentials/api-schemas.ts +127 -143
  23. package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +327 -318
  24. package/src/integrations/webhook-endpoints/api-schemas.ts +103 -102
  25. package/src/integrations/webhook-endpoints/types.ts +58 -51
  26. package/src/operations/activities/api-schemas.ts +80 -79
  27. package/src/operations/activities/types.ts +64 -63
  28. package/src/organization-model/contracts.ts +1 -1
  29. package/src/organization-model/defaults.ts +6 -6
  30. package/src/organization-model/domains/navigation.ts +38 -37
  31. package/src/organization-model/foundation.ts +2 -3
  32. package/src/organization-model/published.ts +3 -3
  33. package/src/platform/constants/versions.ts +1 -1
  34. package/src/reference/_generated/contracts.md +27 -270
  35. package/src/scaffold-registry/__tests__/index.test.ts +72 -7
  36. package/src/scaffold-registry/index.ts +159 -26
  37. package/src/server.ts +281 -272
  38. 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
- * - Role enum prevents privilege escalation
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(
95
- (data) => data.organizationId || data.userId,
96
- { message: 'Either organizationId or userId must be provided' }
97
- )
98
-
99
- // ============================================================================
100
- // TypeScript Type Exports
101
- // ============================================================================
102
-
103
- // Export inferred types for use in route handlers
104
- export type SendInvitationInput = z.infer<typeof SendInvitationSchema>
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
- * Restricts to valid role slugs only
22
+ * Accepts any non-empty role slug (max 64 chars).
23
23
  *
24
- * Security: Prevents privilege escalation by limiting role values
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.enum(['admin', 'member'])
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 enum prevents privilege escalation
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
- * - Enum validation prevents privilege escalation
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'