serverless-event-orchestrator 2.0.1 → 2.3.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/LICENSE +21 -21
- package/README.md +489 -434
- package/dist/dispatcher.d.ts +6 -1
- package/dist/dispatcher.d.ts.map +1 -1
- package/dist/dispatcher.js +66 -7
- package/dist/dispatcher.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/event-type.enum.d.ts +1 -0
- package/dist/types/event-type.enum.d.ts.map +1 -1
- package/dist/types/event-type.enum.js +1 -0
- package/dist/types/event-type.enum.js.map +1 -1
- package/dist/types/routes.d.ts +6 -0
- package/dist/types/routes.d.ts.map +1 -1
- package/jest.config.js +32 -32
- package/package.json +82 -81
- package/src/dispatcher.ts +586 -519
- package/src/http/body-parser.ts +60 -60
- package/src/http/cors.ts +76 -76
- package/src/http/index.ts +3 -3
- package/src/http/response.ts +209 -209
- package/src/identity/extractor.ts +207 -207
- package/src/identity/index.ts +2 -2
- package/src/identity/jwt-verifier.ts +41 -41
- package/src/index.ts +128 -127
- package/src/middleware/crm-guard.ts +51 -51
- package/src/middleware/index.ts +3 -3
- package/src/middleware/init-tenant-context.ts +59 -59
- package/src/middleware/tenant-guard.ts +54 -54
- package/src/tenant/TenantContext.ts +115 -115
- package/src/tenant/helpers.ts +112 -112
- package/src/tenant/index.ts +21 -21
- package/src/tenant/types.ts +101 -101
- package/src/types/event-type.enum.ts +21 -20
- package/src/types/index.ts +2 -2
- package/src/types/routes.ts +218 -211
- package/src/utils/headers.ts +72 -72
- package/src/utils/index.ts +2 -2
- package/src/utils/path-matcher.ts +84 -84
- package/tests/cors.test.ts +133 -133
- package/tests/dispatcher.test.ts +795 -715
- package/tests/headers.test.ts +99 -99
- package/tests/identity.test.ts +301 -301
- package/tests/middleware/crm-guard.test.ts +69 -69
- package/tests/middleware/init-tenant-context.test.ts +147 -147
- package/tests/middleware/tenant-guard.test.ts +100 -100
- package/tests/path-matcher.test.ts +102 -102
- package/tests/response.test.ts +155 -155
- package/tests/tenant/TenantContext.test.ts +134 -134
- package/tests/tenant/helpers.test.ts +187 -187
- package/tsconfig.json +24 -24
package/src/tenant/types.ts
CHANGED
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tenant types for the multi-tenant system.
|
|
3
|
-
* - ORG: Organization/Agency (tenantId = orgProfileId)
|
|
4
|
-
* - PERSON: Independent agent (tenantId = personProfileId)
|
|
5
|
-
*/
|
|
6
|
-
export type TenantType = 'ORG' | 'PERSON';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* SaaS subscription plans.
|
|
10
|
-
* Determine the features available for a tenant.
|
|
11
|
-
* Stored in the Tenants table and injected into JWT via Pre Token Generation.
|
|
12
|
-
*/
|
|
13
|
-
export type Plan = 'FREE' | 'BASIC' | 'PRO' | 'ENTERPRISE';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Features enabled per plan.
|
|
17
|
-
* Stored in the Tenants table and queried from JWT claim or table directly.
|
|
18
|
-
*/
|
|
19
|
-
export interface TenantFeatures {
|
|
20
|
-
maxProperties: number;
|
|
21
|
-
hasWhiteLabelWebsite: boolean;
|
|
22
|
-
hasCRMAccess: boolean;
|
|
23
|
-
hasAdvancedAnalytics: boolean;
|
|
24
|
-
maxAgents: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Tenant information that travels in the context of each request.
|
|
29
|
-
* Propagated via AsyncLocalStorage and available throughout the async chain.
|
|
30
|
-
*
|
|
31
|
-
* Filled from JWT claims (private/backoffice routes) or from headers
|
|
32
|
-
* X-Tenant-Id (internal routes, Lambda-to-Lambda).
|
|
33
|
-
*/
|
|
34
|
-
export interface TenantInfo {
|
|
35
|
-
/** Tenant ID: orgProfileId (ORG) or personProfileId (PERSON) */
|
|
36
|
-
tenantId: string;
|
|
37
|
-
|
|
38
|
-
/** Tenant type */
|
|
39
|
-
tenantType: TenantType;
|
|
40
|
-
|
|
41
|
-
/** Authenticated user ID (Cognito sub or custom:userId) */
|
|
42
|
-
userId: string;
|
|
43
|
-
|
|
44
|
-
/** PersonProfileId of the user (always present, it's their personal profile) */
|
|
45
|
-
personProfileId?: string;
|
|
46
|
-
|
|
47
|
-
/** OrgProfileId if belongs to an organization (only for TenantType = ORG) */
|
|
48
|
-
orgProfileId?: string;
|
|
49
|
-
|
|
50
|
-
/** User's country code (ISO 3166-1 alpha-2, e.g., 'CO', 'MX', 'US') */
|
|
51
|
-
countryCode: string;
|
|
52
|
-
|
|
53
|
-
/** Tenant's plan (optional, filled if present in JWT) */
|
|
54
|
-
plan?: Plan;
|
|
55
|
-
|
|
56
|
-
/** Whether the tenant has CRM access (shortcut for features.hasCRMAccess) */
|
|
57
|
-
hasCRM?: boolean;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Custom claims injected into the Cognito JWT via Pre Token Generation.
|
|
62
|
-
* These claims are available in event.context.identity.claims
|
|
63
|
-
* after the orchestrator extracts the identity.
|
|
64
|
-
*/
|
|
65
|
-
export interface TenantClaims {
|
|
66
|
-
'custom:tenantId': string;
|
|
67
|
-
'custom:tenantType': TenantType;
|
|
68
|
-
'custom:userId': string;
|
|
69
|
-
'custom:personProfileId': string;
|
|
70
|
-
'custom:orgProfileId'?: string;
|
|
71
|
-
'custom:countryCode': string;
|
|
72
|
-
'custom:plan'?: Plan;
|
|
73
|
-
'custom:hasCRM'?: string; // 'true' | 'false' (Cognito only accepts strings)
|
|
74
|
-
'custom:hasWhiteLabel'?: string; // 'true' | 'false'
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Headers used to propagate tenant in Lambda-to-Lambda calls.
|
|
79
|
-
*/
|
|
80
|
-
export const TENANT_HEADERS = {
|
|
81
|
-
TENANT_ID: 'x-tenant-id',
|
|
82
|
-
TENANT_TYPE: 'x-tenant-type',
|
|
83
|
-
USER_ID: 'x-user-id',
|
|
84
|
-
COUNTRY_CODE: 'x-country-code',
|
|
85
|
-
PERSON_PROFILE_ID: 'x-person-profile-id',
|
|
86
|
-
ORG_PROFILE_ID: 'x-org-profile-id',
|
|
87
|
-
} as const;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Type guard: checks if a value is a valid TenantType.
|
|
91
|
-
*/
|
|
92
|
-
export function isTenantType(value: unknown): value is TenantType {
|
|
93
|
-
return value === 'ORG' || value === 'PERSON';
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Type guard: checks if a value is a valid Plan.
|
|
98
|
-
*/
|
|
99
|
-
export function isPlan(value: unknown): value is Plan {
|
|
100
|
-
return value === 'FREE' || value === 'BASIC' || value === 'PRO' || value === 'ENTERPRISE';
|
|
101
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Tenant types for the multi-tenant system.
|
|
3
|
+
* - ORG: Organization/Agency (tenantId = orgProfileId)
|
|
4
|
+
* - PERSON: Independent agent (tenantId = personProfileId)
|
|
5
|
+
*/
|
|
6
|
+
export type TenantType = 'ORG' | 'PERSON';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SaaS subscription plans.
|
|
10
|
+
* Determine the features available for a tenant.
|
|
11
|
+
* Stored in the Tenants table and injected into JWT via Pre Token Generation.
|
|
12
|
+
*/
|
|
13
|
+
export type Plan = 'FREE' | 'BASIC' | 'PRO' | 'ENTERPRISE';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Features enabled per plan.
|
|
17
|
+
* Stored in the Tenants table and queried from JWT claim or table directly.
|
|
18
|
+
*/
|
|
19
|
+
export interface TenantFeatures {
|
|
20
|
+
maxProperties: number;
|
|
21
|
+
hasWhiteLabelWebsite: boolean;
|
|
22
|
+
hasCRMAccess: boolean;
|
|
23
|
+
hasAdvancedAnalytics: boolean;
|
|
24
|
+
maxAgents: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Tenant information that travels in the context of each request.
|
|
29
|
+
* Propagated via AsyncLocalStorage and available throughout the async chain.
|
|
30
|
+
*
|
|
31
|
+
* Filled from JWT claims (private/backoffice routes) or from headers
|
|
32
|
+
* X-Tenant-Id (internal routes, Lambda-to-Lambda).
|
|
33
|
+
*/
|
|
34
|
+
export interface TenantInfo {
|
|
35
|
+
/** Tenant ID: orgProfileId (ORG) or personProfileId (PERSON) */
|
|
36
|
+
tenantId: string;
|
|
37
|
+
|
|
38
|
+
/** Tenant type */
|
|
39
|
+
tenantType: TenantType;
|
|
40
|
+
|
|
41
|
+
/** Authenticated user ID (Cognito sub or custom:userId) */
|
|
42
|
+
userId: string;
|
|
43
|
+
|
|
44
|
+
/** PersonProfileId of the user (always present, it's their personal profile) */
|
|
45
|
+
personProfileId?: string;
|
|
46
|
+
|
|
47
|
+
/** OrgProfileId if belongs to an organization (only for TenantType = ORG) */
|
|
48
|
+
orgProfileId?: string;
|
|
49
|
+
|
|
50
|
+
/** User's country code (ISO 3166-1 alpha-2, e.g., 'CO', 'MX', 'US') */
|
|
51
|
+
countryCode: string;
|
|
52
|
+
|
|
53
|
+
/** Tenant's plan (optional, filled if present in JWT) */
|
|
54
|
+
plan?: Plan;
|
|
55
|
+
|
|
56
|
+
/** Whether the tenant has CRM access (shortcut for features.hasCRMAccess) */
|
|
57
|
+
hasCRM?: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Custom claims injected into the Cognito JWT via Pre Token Generation.
|
|
62
|
+
* These claims are available in event.context.identity.claims
|
|
63
|
+
* after the orchestrator extracts the identity.
|
|
64
|
+
*/
|
|
65
|
+
export interface TenantClaims {
|
|
66
|
+
'custom:tenantId': string;
|
|
67
|
+
'custom:tenantType': TenantType;
|
|
68
|
+
'custom:userId': string;
|
|
69
|
+
'custom:personProfileId': string;
|
|
70
|
+
'custom:orgProfileId'?: string;
|
|
71
|
+
'custom:countryCode': string;
|
|
72
|
+
'custom:plan'?: Plan;
|
|
73
|
+
'custom:hasCRM'?: string; // 'true' | 'false' (Cognito only accepts strings)
|
|
74
|
+
'custom:hasWhiteLabel'?: string; // 'true' | 'false'
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Headers used to propagate tenant in Lambda-to-Lambda calls.
|
|
79
|
+
*/
|
|
80
|
+
export const TENANT_HEADERS = {
|
|
81
|
+
TENANT_ID: 'x-tenant-id',
|
|
82
|
+
TENANT_TYPE: 'x-tenant-type',
|
|
83
|
+
USER_ID: 'x-user-id',
|
|
84
|
+
COUNTRY_CODE: 'x-country-code',
|
|
85
|
+
PERSON_PROFILE_ID: 'x-person-profile-id',
|
|
86
|
+
ORG_PROFILE_ID: 'x-org-profile-id',
|
|
87
|
+
} as const;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Type guard: checks if a value is a valid TenantType.
|
|
91
|
+
*/
|
|
92
|
+
export function isTenantType(value: unknown): value is TenantType {
|
|
93
|
+
return value === 'ORG' || value === 'PERSON';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Type guard: checks if a value is a valid Plan.
|
|
98
|
+
*/
|
|
99
|
+
export function isPlan(value: unknown): value is Plan {
|
|
100
|
+
return value === 'FREE' || value === 'BASIC' || value === 'PRO' || value === 'ENTERPRISE';
|
|
101
|
+
}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Supported AWS event types for dispatching
|
|
3
|
-
*/
|
|
4
|
-
export enum EventType {
|
|
5
|
-
EventBridge = 'eventbridge',
|
|
6
|
-
ApiGateway = 'apigateway',
|
|
7
|
-
Lambda = 'lambda',
|
|
8
|
-
Sqs = 'sqs',
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Supported AWS event types for dispatching
|
|
3
|
+
*/
|
|
4
|
+
export enum EventType {
|
|
5
|
+
EventBridge = 'eventbridge',
|
|
6
|
+
ApiGateway = 'apigateway',
|
|
7
|
+
Lambda = 'lambda',
|
|
8
|
+
Sqs = 'sqs',
|
|
9
|
+
Scheduled = 'scheduled',
|
|
10
|
+
Unknown = 'unknown',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Route segments for access control categorization
|
|
15
|
+
*/
|
|
16
|
+
export enum RouteSegment {
|
|
17
|
+
Public = 'public',
|
|
18
|
+
Private = 'private',
|
|
19
|
+
Backoffice = 'backoffice',
|
|
20
|
+
Internal = 'internal',
|
|
21
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './event-type.enum.js';
|
|
2
|
-
export * from './routes.js';
|
|
1
|
+
export * from './event-type.enum.js';
|
|
2
|
+
export * from './routes.js';
|