serverless-event-orchestrator 2.2.0 → 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.
Files changed (43) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +489 -489
  3. package/dist/dispatcher.d.ts +6 -1
  4. package/dist/dispatcher.d.ts.map +1 -1
  5. package/dist/dispatcher.js +31 -7
  6. package/dist/dispatcher.js.map +1 -1
  7. package/jest.config.js +32 -32
  8. package/package.json +82 -81
  9. package/src/dispatcher.ts +586 -558
  10. package/src/http/body-parser.ts +60 -60
  11. package/src/http/cors.ts +76 -76
  12. package/src/http/index.ts +3 -3
  13. package/src/http/response.ts +209 -209
  14. package/src/identity/extractor.ts +207 -207
  15. package/src/identity/index.ts +2 -2
  16. package/src/identity/jwt-verifier.ts +41 -41
  17. package/src/index.ts +128 -128
  18. package/src/middleware/crm-guard.ts +51 -51
  19. package/src/middleware/index.ts +3 -3
  20. package/src/middleware/init-tenant-context.ts +59 -59
  21. package/src/middleware/tenant-guard.ts +54 -54
  22. package/src/tenant/TenantContext.ts +115 -115
  23. package/src/tenant/helpers.ts +112 -112
  24. package/src/tenant/index.ts +21 -21
  25. package/src/tenant/types.ts +101 -101
  26. package/src/types/event-type.enum.ts +21 -21
  27. package/src/types/index.ts +2 -2
  28. package/src/types/routes.ts +218 -218
  29. package/src/utils/headers.ts +72 -72
  30. package/src/utils/index.ts +2 -2
  31. package/src/utils/path-matcher.ts +84 -84
  32. package/tests/cors.test.ts +133 -133
  33. package/tests/dispatcher.test.ts +795 -715
  34. package/tests/headers.test.ts +99 -99
  35. package/tests/identity.test.ts +301 -301
  36. package/tests/middleware/crm-guard.test.ts +69 -69
  37. package/tests/middleware/init-tenant-context.test.ts +147 -147
  38. package/tests/middleware/tenant-guard.test.ts +100 -100
  39. package/tests/path-matcher.test.ts +102 -102
  40. package/tests/response.test.ts +155 -155
  41. package/tests/tenant/TenantContext.test.ts +134 -134
  42. package/tests/tenant/helpers.test.ts +187 -187
  43. package/tsconfig.json +24 -24
@@ -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,21 +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
- 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
- }
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
+ }
@@ -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';