@teaminabottle/domain-cdk-packer 0.1.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 (44) hide show
  1. package/README.md +83 -0
  2. package/dist/DomainStack.d.ts +36 -0
  3. package/dist/DomainStack.js +360 -0
  4. package/dist/__tests__/domain-stack.test.d.ts +1 -0
  5. package/dist/__tests__/domain-stack.test.js +138 -0
  6. package/dist/__tests__/lambda-factory.test.d.ts +1 -0
  7. package/dist/__tests__/lambda-factory.test.js +30 -0
  8. package/dist/__tests__/pack-flows.test.d.ts +1 -0
  9. package/dist/__tests__/pack-flows.test.js +121 -0
  10. package/dist/__tests__/registry.test.d.ts +1 -0
  11. package/dist/__tests__/registry.test.js +34 -0
  12. package/dist/__tests__/step-functions-codegen.test.d.ts +1 -0
  13. package/dist/__tests__/step-functions-codegen.test.js +159 -0
  14. package/dist/constructs/action-construct.d.ts +30 -0
  15. package/dist/constructs/action-construct.js +32 -0
  16. package/dist/constructs/api-construct.d.ts +30 -0
  17. package/dist/constructs/api-construct.js +64 -0
  18. package/dist/constructs/job-construct.d.ts +33 -0
  19. package/dist/constructs/job-construct.js +54 -0
  20. package/dist/constructs/schedule-construct.d.ts +27 -0
  21. package/dist/constructs/schedule-construct.js +54 -0
  22. package/dist/constructs/subscriber-construct.d.ts +30 -0
  23. package/dist/constructs/subscriber-construct.js +63 -0
  24. package/dist/constructs/webhook-construct.d.ts +33 -0
  25. package/dist/constructs/webhook-construct.js +50 -0
  26. package/dist/flow-registry.d.ts +78 -0
  27. package/dist/flow-registry.js +2 -0
  28. package/dist/grouped-lambda-factory.d.ts +34 -0
  29. package/dist/grouped-lambda-factory.js +40 -0
  30. package/dist/iam/iam-policy-builder.d.ts +64 -0
  31. package/dist/iam/iam-policy-builder.js +132 -0
  32. package/dist/index.d.ts +28 -0
  33. package/dist/index.js +13 -0
  34. package/dist/lambda-factory.d.ts +46 -0
  35. package/dist/lambda-factory.js +72 -0
  36. package/dist/pack-domain.d.ts +30 -0
  37. package/dist/pack-domain.js +30 -0
  38. package/dist/pack-flows.d.ts +26 -0
  39. package/dist/pack-flows.js +112 -0
  40. package/dist/registry.d.ts +209 -0
  41. package/dist/registry.js +1 -0
  42. package/dist/step-functions-codegen.d.ts +65 -0
  43. package/dist/step-functions-codegen.js +55 -0
  44. package/package.json +31 -0
@@ -0,0 +1,72 @@
1
+ import * as cdk from 'aws-cdk-lib';
2
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
3
+ import * as lambdaNode from 'aws-cdk-lib/aws-lambda-nodejs';
4
+ import * as logs from 'aws-cdk-lib/aws-logs';
5
+ import path from 'node:path';
6
+ /**
7
+ * Factory for creating CDK NodejsFunction instances from domain registry entries with consistent defaults.
8
+ */
9
+ export class LambdaFactory {
10
+ scope;
11
+ registry;
12
+ domainRoot;
13
+ sharedEnv;
14
+ /**
15
+ * Create a new LambdaFactory instance.
16
+ * @param props - Factory configuration
17
+ */
18
+ constructor(props) {
19
+ this.scope = props.scope;
20
+ this.registry = props.registry;
21
+ this.domainRoot = props.domainRoot;
22
+ this.sharedEnv = props.sharedEnv;
23
+ }
24
+ /**
25
+ * Convert a kebab-case or snake_case string to PascalCase.
26
+ * @param s - Input string
27
+ * @returns PascalCase string
28
+ */
29
+ toPascalCase(s) {
30
+ return s
31
+ .split(/[-_]/)
32
+ .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
33
+ .join('');
34
+ }
35
+ /**
36
+ * Create a NodejsFunction from a registry entry.
37
+ * @param entry - Registry entry with handlerFile property
38
+ * @param overrides - Optional deployment configuration overrides
39
+ * @param extraEnv - Optional extra environment variables
40
+ * @returns Created NodejsFunction
41
+ */
42
+ createFunction(entry, overrides, extraEnv) {
43
+ const merged = { ...this.registry.domain.defaultDeployment, ...overrides };
44
+ const architecture = merged.architecture === 'x86_64'
45
+ ? lambda.Architecture.X86_64
46
+ : lambda.Architecture.ARM_64;
47
+ const environment = {
48
+ DOMAIN_ID: this.registry.domain.id,
49
+ NODE_OPTIONS: '--enable-source-maps',
50
+ ...this.sharedEnv,
51
+ ...extraEnv,
52
+ };
53
+ return new lambdaNode.NodejsFunction(this.scope, `${this.toPascalCase(entry.id)}Fn`, {
54
+ runtime: lambda.Runtime.NODEJS_22_X,
55
+ architecture,
56
+ tracing: lambda.Tracing.ACTIVE,
57
+ logRetention: logs.RetentionDays.ONE_WEEK,
58
+ memorySize: merged.memory ?? 512,
59
+ timeout: cdk.Duration.seconds(merged.timeout ?? 30),
60
+ ...(merged.reservedConcurrency !== undefined
61
+ ? { reservedConcurrentExecutions: merged.reservedConcurrency }
62
+ : {}),
63
+ entry: path.join(this.domainRoot, entry.handlerFile),
64
+ handler: 'handler',
65
+ bundling: {
66
+ externalModules: ['@aws-sdk/*'],
67
+ sourceMap: true,
68
+ },
69
+ environment,
70
+ });
71
+ }
72
+ }
@@ -0,0 +1,30 @@
1
+ import * as cdk from 'aws-cdk-lib';
2
+ import { DomainStack } from './DomainStack.js';
3
+ import type { DomainRegistry } from './registry.js';
4
+ /**
5
+ * Options for packDomain function.
6
+ */
7
+ export interface PackDomainOptions {
8
+ /** Optional CDK environment (account + region). */
9
+ env?: cdk.Environment;
10
+ /** Optional Cognito User Pool ARN for JWT-authenticated routes. */
11
+ userPoolArn?: string;
12
+ /** Optional Cognito User Pool Client ID — required when userPoolArn is provided. */
13
+ userPoolClientId?: string;
14
+ /** Optional database connection URL. */
15
+ databaseUrl?: string;
16
+ /** Optional Secrets Manager ARN for database master credentials. */
17
+ dbSecretArn?: string;
18
+ }
19
+ /**
20
+ * Convenience entry-point: constructs a DomainStack from a compiled registry.
21
+ * Intended to be called from a CDK app entrypoint (e.g. bin/app.ts in the project's infra).
22
+ * Supports both old (env as 5th arg) and new (options object) calling conventions.
23
+ * @param registry - The compiled domain registry read from .tib/domain-registry.json.
24
+ * @param app - The CDK App instance.
25
+ * @param stackId - CloudFormation stack logical ID.
26
+ * @param eventBusArn - ARN of the named EventBridge event bus for event subscribers.
27
+ * @param options - Optional configuration (env, userPoolArn, userPoolClientId, databaseUrl, dbSecretArn).
28
+ * @returns The constructed DomainStack.
29
+ */
30
+ export declare function packDomain(registry: DomainRegistry, app: cdk.App, stackId: string, eventBusArn: string, options?: PackDomainOptions | cdk.Environment): DomainStack;
@@ -0,0 +1,30 @@
1
+ import { DomainStack } from './DomainStack.js';
2
+ /**
3
+ * Convenience entry-point: constructs a DomainStack from a compiled registry.
4
+ * Intended to be called from a CDK app entrypoint (e.g. bin/app.ts in the project's infra).
5
+ * Supports both old (env as 5th arg) and new (options object) calling conventions.
6
+ * @param registry - The compiled domain registry read from .tib/domain-registry.json.
7
+ * @param app - The CDK App instance.
8
+ * @param stackId - CloudFormation stack logical ID.
9
+ * @param eventBusArn - ARN of the named EventBridge event bus for event subscribers.
10
+ * @param options - Optional configuration (env, userPoolArn, userPoolClientId, databaseUrl, dbSecretArn).
11
+ * @returns The constructed DomainStack.
12
+ */
13
+ export function packDomain(registry, app, stackId, eventBusArn, options) {
14
+ // Support both old (env as 5th arg) and new (options object) calling conventions
15
+ // Check if options looks like a CDK Environment (has 'account' and/or 'region' props, not the full options interface)
16
+ const opts = options && typeof options === 'object'
17
+ && ('account' in options || 'region' in options)
18
+ && !('userPoolArn' in options || 'userPoolClientId' in options || 'databaseUrl' in options || 'dbSecretArn' in options)
19
+ ? { env: options }
20
+ : options || {};
21
+ return new DomainStack(app, stackId, {
22
+ registry,
23
+ eventBusArn,
24
+ env: opts.env,
25
+ userPoolArn: opts.userPoolArn,
26
+ userPoolClientId: opts.userPoolClientId,
27
+ databaseUrl: opts.databaseUrl,
28
+ dbSecretArn: opts.dbSecretArn,
29
+ });
30
+ }
@@ -0,0 +1,26 @@
1
+ import * as cdk from 'aws-cdk-lib';
2
+ import { Construct } from 'constructs';
3
+ import type { FlowRegistry } from './flow-registry.js';
4
+ /** Options for packFlows. */
5
+ export interface PackFlowsOptions {
6
+ env?: cdk.Environment;
7
+ /** Map of "{domainId}-{primitiveType}" -> grouped Lambda function ARN. */
8
+ domainLambdaArns: Record<string, string>;
9
+ /** EventBridge bus ARN for domain-event steps and triggers. */
10
+ eventBusArn: string;
11
+ }
12
+ /** CDK stack containing one Step Functions state machine per flow in the registry. */
13
+ export declare class FlowsStack extends cdk.Stack {
14
+ /** Map of flow id -> SFN ARN. Used by domain Lambdas via FLOWS_SFN_ARN_MAP env var. */
15
+ readonly flowArnMap: Record<string, string>;
16
+ constructor(scope: Construct, id: string, props: {
17
+ registry: FlowRegistry;
18
+ options: PackFlowsOptions;
19
+ } & cdk.StackProps);
20
+ private buildStateMachine;
21
+ private translateToAsl;
22
+ private translateStep;
23
+ private translateFlowControl;
24
+ }
25
+ /** Convenience: construct a FlowsStack from a registry. */
26
+ export declare function packFlows(registry: FlowRegistry, app: cdk.App, stackId: string, options: PackFlowsOptions): FlowsStack;
@@ -0,0 +1,112 @@
1
+ import * as cdk from 'aws-cdk-lib';
2
+ import * as sfn from 'aws-cdk-lib/aws-stepfunctions';
3
+ import * as events from 'aws-cdk-lib/aws-events';
4
+ import * as eventsTargets from 'aws-cdk-lib/aws-events-targets';
5
+ /** CDK stack containing one Step Functions state machine per flow in the registry. */
6
+ export class FlowsStack extends cdk.Stack {
7
+ /** Map of flow id -> SFN ARN. Used by domain Lambdas via FLOWS_SFN_ARN_MAP env var. */
8
+ flowArnMap = {};
9
+ constructor(scope, id, props) {
10
+ super(scope, id, props);
11
+ const { registry, options } = props;
12
+ for (const flow of registry.flows) {
13
+ const stateMachine = this.buildStateMachine(flow, options);
14
+ this.flowArnMap[flow.id] = stateMachine.stateMachineArn;
15
+ if (flow.trigger?.type === 'event') {
16
+ const bus = events.EventBus.fromEventBusArn(this, `${flow.id}TriggerBus`, options.eventBusArn);
17
+ new events.Rule(this, `${flow.id}TriggerRule`, {
18
+ eventBus: bus,
19
+ eventPattern: { detailType: [flow.trigger.eventId] },
20
+ targets: [new eventsTargets.SfnStateMachine(stateMachine)],
21
+ });
22
+ }
23
+ new cdk.CfnOutput(this, `${flow.id}FlowArn`, {
24
+ value: stateMachine.stateMachineArn,
25
+ exportName: `${this.stackName}-flow-${flow.id}`,
26
+ });
27
+ }
28
+ }
29
+ buildStateMachine(flow, options) {
30
+ const definition = this.translateToAsl(flow, options);
31
+ return new sfn.StateMachine(this, `${flow.id}StateMachine`, {
32
+ stateMachineName: `${this.stackName}-flow-${flow.id}`,
33
+ definitionBody: sfn.DefinitionBody.fromString(JSON.stringify(definition)),
34
+ stateMachineType: sfn.StateMachineType.STANDARD,
35
+ });
36
+ }
37
+ translateToAsl(flow, options) {
38
+ if (flow.steps.length === 0)
39
+ throw new Error(`packFlows: flow ${flow.id} has no steps`);
40
+ const states = {};
41
+ for (const step of flow.steps) {
42
+ states[step.name] = this.translateStep(step, options, flow.id);
43
+ }
44
+ return { StartAt: flow.steps[0].name, States: states };
45
+ }
46
+ translateStep(step, options, flowId) {
47
+ switch (step.type) {
48
+ case 'domain-action': {
49
+ const arnKey = `${step.domainId}-action`;
50
+ const fnArn = options.domainLambdaArns[arnKey];
51
+ if (!fnArn)
52
+ throw new Error(`packFlows: no Lambda ARN for ${arnKey} (flow ${flowId} step ${step.name})`);
53
+ return {
54
+ Type: 'Task',
55
+ Resource: 'arn:aws:states:::lambda:invoke',
56
+ Parameters: { FunctionName: fnArn, Payload: { actionId: `${step.domainId}.${step.actionId}`, 'input.$': '$', ...(step.parameters ?? {}) } },
57
+ ...(step.next ? { Next: step.next } : { End: true }),
58
+ };
59
+ }
60
+ case 'domain-api': {
61
+ const arnKey = `${step.domainId}-api`;
62
+ const fnArn = options.domainLambdaArns[arnKey];
63
+ if (!fnArn)
64
+ throw new Error(`packFlows: no Lambda ARN for ${arnKey} (flow ${flowId} step ${step.name})`);
65
+ return {
66
+ Type: 'Task',
67
+ Resource: 'arn:aws:states:::lambda:invoke',
68
+ Parameters: { FunctionName: fnArn, Payload: { apiId: `${step.domainId}.${step.apiId}`, 'input.$': '$', ...(step.parameters ?? {}) } },
69
+ ...(step.next ? { Next: step.next } : { End: true }),
70
+ };
71
+ }
72
+ case 'domain-event': {
73
+ return {
74
+ Type: 'Task',
75
+ Resource: 'arn:aws:states:::events:putEvents',
76
+ Parameters: {
77
+ Entries: [{
78
+ EventBusName: options.eventBusArn,
79
+ Source: `tib.${step.eventId.split('.')[0]}`,
80
+ DetailType: step.eventId,
81
+ Detail: JSON.stringify(step.payload),
82
+ }],
83
+ },
84
+ ...(step.next ? { Next: step.next } : { End: true }),
85
+ };
86
+ }
87
+ case 'flow-control':
88
+ return this.translateFlowControl(step);
89
+ }
90
+ }
91
+ translateFlowControl(step) {
92
+ switch (step.control) {
93
+ case 'choice':
94
+ return { Type: 'Choice', Choices: step.choices.map(c => ({ Variable: '$.path', StringEquals: c.when, Next: c.next })), Default: step.default };
95
+ case 'parallel':
96
+ // TODO(#1787): full nested branch translation. For Wave 2, single linear branch only.
97
+ return { Type: 'Parallel', Branches: step.branches.map(() => ({ StartAt: 'Pass', States: { Pass: { Type: 'Pass', End: true } } })), ...(step.next ? { Next: step.next } : { End: true }) };
98
+ case 'wait':
99
+ return { Type: 'Wait', Seconds: step.seconds, ...(step.next ? { Next: step.next } : { End: true }) };
100
+ case 'succeed':
101
+ return { Type: 'Succeed' };
102
+ case 'fail':
103
+ return { Type: 'Fail', Cause: step.cause, Error: step.error };
104
+ case 'pass':
105
+ return { Type: 'Pass', Result: step.result, ...(step.next ? { Next: step.next } : { End: true }) };
106
+ }
107
+ }
108
+ }
109
+ /** Convenience: construct a FlowsStack from a registry. */
110
+ export function packFlows(registry, app, stackId, options) {
111
+ return new FlowsStack(app, stackId, { registry, options, env: options.env });
112
+ }
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Serialized JSON Schema representation.
3
+ */
4
+ export type SchemaSnapshot = Record<string, unknown>;
5
+ /**
6
+ * Kind discriminant for registry entries.
7
+ */
8
+ export type RegistryEntryKind = 'api' | 'webhook' | 'subscriber' | 'schedule' | 'job' | 'action' | 'integration' | 'event' | 'domain';
9
+ /**
10
+ * Plain-value subset of DeploymentConfig for serialization.
11
+ */
12
+ export interface SerialDeploymentConfig {
13
+ /** Target deployment strategy: 'single' or 'split'. */
14
+ target?: 'single' | 'split';
15
+ /** Lambda memory in MB. */
16
+ memory?: number;
17
+ /** Lambda timeout in seconds. */
18
+ timeout?: number;
19
+ /** Reserved concurrency limit. */
20
+ reservedConcurrency?: number;
21
+ /** CPU architecture. */
22
+ architecture?: 'arm64' | 'x86_64';
23
+ /** Isolation level: 'dedicated' creates one Lambda per handler, 'shared' uses grouped Lambdas. */
24
+ isolation?: 'dedicated' | 'shared';
25
+ }
26
+ /**
27
+ * Base registry entry with common properties.
28
+ */
29
+ export interface BaseRegistryEntry {
30
+ /** Unique identifier. */
31
+ id: string;
32
+ /** Entry kind discriminant. */
33
+ kind: RegistryEntryKind;
34
+ /** Path to handler file, relative to domain root. */
35
+ handlerFile?: string;
36
+ }
37
+ /**
38
+ * API registry entry for HTTP endpoint handlers.
39
+ */
40
+ export interface ApiRegistryEntry extends BaseRegistryEntry {
41
+ /** Discriminant. */
42
+ kind: 'api';
43
+ /** Handler file path (required for API). */
44
+ handlerFile: string;
45
+ /** HTTP route path, e.g. '/users/:id'. */
46
+ path: string;
47
+ /** HTTP method. */
48
+ method: string;
49
+ /** Authentication type. */
50
+ authType: 'jwt' | 'api-key' | 'none';
51
+ /** Optional deployment overrides. */
52
+ deployment?: SerialDeploymentConfig;
53
+ /** JSON Schema snapshot for the HTTP request body. */
54
+ requestSchema?: SchemaSnapshot;
55
+ /** JSON Schema snapshot for the HTTP response body. */
56
+ responseSchema?: SchemaSnapshot;
57
+ }
58
+ /**
59
+ * Webhook registry entry for webhook handlers.
60
+ */
61
+ export interface WebhookRegistryEntry extends BaseRegistryEntry {
62
+ /** Discriminant. */
63
+ kind: 'webhook';
64
+ /** Handler file path (required for webhook). */
65
+ handlerFile: string;
66
+ /** Webhook path, e.g. '/github/push'. */
67
+ path: string;
68
+ /** Webhook provider. */
69
+ provider: string;
70
+ /** HMAC algorithm for signature verification. */
71
+ hmacAlgorithm?: string;
72
+ /** Reference to HMAC secret in secrets store. */
73
+ hmacSecretRef?: string;
74
+ /** Optional deployment overrides. */
75
+ deployment?: SerialDeploymentConfig;
76
+ }
77
+ /**
78
+ * Event subscriber registry entry.
79
+ */
80
+ export interface SubscriberRegistryEntry extends BaseRegistryEntry {
81
+ /** Discriminant. */
82
+ kind: 'subscriber';
83
+ /** Handler file path (required for subscriber). */
84
+ handlerFile: string;
85
+ /** Event type to subscribe to. */
86
+ event: string;
87
+ /** Semver range for event versions. */
88
+ semverRange: string;
89
+ /** Concurrency limit for event processing. */
90
+ concurrency?: number;
91
+ /** Optional deployment overrides. */
92
+ deployment?: SerialDeploymentConfig;
93
+ }
94
+ /**
95
+ * Schedule (cron) registry entry.
96
+ */
97
+ export interface ScheduleRegistryEntry extends BaseRegistryEntry {
98
+ /** Discriminant. */
99
+ kind: 'schedule';
100
+ /** Handler file path (required for schedule). */
101
+ handlerFile: string;
102
+ /** Cron expression in AWS EventBridge format. */
103
+ cron: string;
104
+ /** Whether the schedule is enabled. */
105
+ enabled: boolean;
106
+ /** Optional deployment overrides. */
107
+ deployment?: SerialDeploymentConfig;
108
+ }
109
+ /**
110
+ * Background job registry entry.
111
+ */
112
+ export interface JobRegistryEntry extends BaseRegistryEntry {
113
+ /** Discriminant. */
114
+ kind: 'job';
115
+ /** Handler file path (required for job). */
116
+ handlerFile: string;
117
+ /** Maximum number of retry attempts. */
118
+ maxRetries: number;
119
+ /** Visibility timeout in seconds for SQS message. */
120
+ visibilityTimeoutSeconds: number;
121
+ /** Optional deployment overrides. */
122
+ deployment?: SerialDeploymentConfig;
123
+ }
124
+ /**
125
+ * Action registry entry for callable domain actions.
126
+ */
127
+ export interface ActionRegistryEntry extends BaseRegistryEntry {
128
+ /** Discriminant. */
129
+ kind: 'action';
130
+ /** Handler file path (required for action). */
131
+ handlerFile: string;
132
+ /** Visibility scope: 'private', 'domain', or 'workspace'. */
133
+ visibility: 'private' | 'domain' | 'workspace';
134
+ /** Whether the action enforces idempotency. */
135
+ idempotent: boolean;
136
+ /** Optional deployment overrides. */
137
+ deployment?: SerialDeploymentConfig;
138
+ /** JSON Schema snapshot for the action input. */
139
+ inputSchema?: SchemaSnapshot;
140
+ /** JSON Schema snapshot for the action output. */
141
+ outputSchema?: SchemaSnapshot;
142
+ }
143
+ /**
144
+ * Integration registry entry for external service integrations.
145
+ */
146
+ export interface IntegrationRegistryEntry extends BaseRegistryEntry {
147
+ /** Discriminant. */
148
+ kind: 'integration';
149
+ /** Base URL of the external service. */
150
+ baseUrl: string;
151
+ }
152
+ /**
153
+ * Event registry entry for event type definitions.
154
+ */
155
+ export interface EventRegistryEntry extends BaseRegistryEntry {
156
+ /** Discriminant. */
157
+ kind: 'event';
158
+ /** Event bus name. */
159
+ busName: string;
160
+ /** Versioned schemas for this event type. */
161
+ versions?: Array<{
162
+ version: number;
163
+ schema: SchemaSnapshot;
164
+ }>;
165
+ }
166
+ /**
167
+ * Domain registry entry representing the domain itself.
168
+ */
169
+ export interface DomainRegistryEntry extends BaseRegistryEntry {
170
+ /** Discriminant. */
171
+ kind: 'domain';
172
+ /** Human-readable domain name. */
173
+ name: string;
174
+ /** Tenancy mode: 'required', 'none', or 'system'. */
175
+ tenancy: string;
176
+ /** Optional default deployment configuration for the domain. */
177
+ defaultDeployment?: SerialDeploymentConfig;
178
+ }
179
+ /**
180
+ * Union type of all registry entry kinds.
181
+ */
182
+ export type RegistryEntry = ApiRegistryEntry | WebhookRegistryEntry | SubscriberRegistryEntry | ScheduleRegistryEntry | JobRegistryEntry | ActionRegistryEntry | IntegrationRegistryEntry | EventRegistryEntry | DomainRegistryEntry;
183
+ /**
184
+ * Top-level domain registry — the compiled snapshot for CDK packer.
185
+ */
186
+ export interface DomainRegistry {
187
+ /** Schema version. */
188
+ schemaVersion: '1';
189
+ /** Root directory of the domain. */
190
+ domainRoot: string;
191
+ /** The domain itself. */
192
+ domain: DomainRegistryEntry;
193
+ /** All API endpoints. */
194
+ apis: ApiRegistryEntry[];
195
+ /** All webhook receivers. */
196
+ webhooks: WebhookRegistryEntry[];
197
+ /** All event subscribers. */
198
+ subscribers: SubscriberRegistryEntry[];
199
+ /** All scheduled tasks. */
200
+ schedules: ScheduleRegistryEntry[];
201
+ /** All background jobs. */
202
+ jobs: JobRegistryEntry[];
203
+ /** All callable actions. */
204
+ actions: ActionRegistryEntry[];
205
+ /** All external integrations. */
206
+ integrations: IntegrationRegistryEntry[];
207
+ /** All event type definitions. */
208
+ events: EventRegistryEntry[];
209
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,65 @@
1
+ /**
2
+ * A domain-action node from a TIB Flow definition.
3
+ */
4
+ export interface DomainActionFlowNode {
5
+ /** Node type discriminant. */
6
+ type: 'domain-action';
7
+ /** The domain ID (e.g. 'payments'). */
8
+ domainId: string;
9
+ /** The action ID within the domain (e.g. 'charge-card'). */
10
+ actionId: string;
11
+ /** Display label for this step. */
12
+ label?: string;
13
+ /** Static input parameters merged into the task payload. */
14
+ parameters?: Record<string, unknown>;
15
+ /** Step name for the next state (undefined = End). */
16
+ next?: string;
17
+ }
18
+ /**
19
+ * A minimal Step Functions ASL Task state for a domain-action node.
20
+ */
21
+ export interface StepFunctionsTaskState {
22
+ /** Always 'Task' for Lambda invocations. */
23
+ Type: 'Task';
24
+ /** Lambda ARN pattern using the function name and $LATEST alias. */
25
+ Resource: string;
26
+ /** Parameters passed to the Lambda. */
27
+ Parameters?: Record<string, unknown>;
28
+ /** Next state name. */
29
+ Next?: string;
30
+ /** True when there is no Next (terminal state). */
31
+ End?: true;
32
+ /** Human-readable comment. */
33
+ Comment?: string;
34
+ }
35
+ /**
36
+ * Generates Step Functions ASL Task states for domain-action flow nodes.
37
+ *
38
+ * Each domain action maps to a Lambda invoke task targeting the function name
39
+ * `${domainId}-${actionId}` with the `$LATEST` alias.
40
+ */
41
+ export declare class StepFunctionsCodegen {
42
+ /**
43
+ * Generate a Step Functions ASL Task state for a single domain-action node.
44
+ *
45
+ * The Resource ARN uses the intrinsic `arn:aws:states:::lambda:invoke` resource
46
+ * and a FunctionName parameter of the form `${domainId}-${actionId}`.
47
+ *
48
+ * @param node - The domain-action flow node to generate a task state for.
49
+ * @returns A Step Functions ASL Task state object.
50
+ */
51
+ generateTaskState(node: DomainActionFlowNode): StepFunctionsTaskState;
52
+ /**
53
+ * Generate a full Step Functions state machine definition from a list of
54
+ * domain-action nodes. Nodes are ordered by their `next` links; the first
55
+ * node that has no `next` becomes the terminal state.
56
+ *
57
+ * @param nodes - Ordered list of domain-action nodes.
58
+ * @param startAt - Name of the first state. Defaults to the first node's label or actionId.
59
+ * @returns A Step Functions state machine definition object.
60
+ */
61
+ generateStateMachine(nodes: DomainActionFlowNode[], startAt?: string): {
62
+ StartAt: string;
63
+ States: Record<string, StepFunctionsTaskState>;
64
+ };
65
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Generates Step Functions ASL Task states for domain-action flow nodes.
3
+ *
4
+ * Each domain action maps to a Lambda invoke task targeting the function name
5
+ * `${domainId}-${actionId}` with the `$LATEST` alias.
6
+ */
7
+ export class StepFunctionsCodegen {
8
+ /**
9
+ * Generate a Step Functions ASL Task state for a single domain-action node.
10
+ *
11
+ * The Resource ARN uses the intrinsic `arn:aws:states:::lambda:invoke` resource
12
+ * and a FunctionName parameter of the form `${domainId}-${actionId}`.
13
+ *
14
+ * @param node - The domain-action flow node to generate a task state for.
15
+ * @returns A Step Functions ASL Task state object.
16
+ */
17
+ generateTaskState(node) {
18
+ const functionName = `${node.domainId}-${node.actionId}`;
19
+ const state = {
20
+ Type: 'Task',
21
+ Resource: 'arn:aws:states:::lambda:invoke',
22
+ Parameters: {
23
+ FunctionName: functionName,
24
+ 'Payload.$': '$',
25
+ ...(node.parameters ?? {}),
26
+ },
27
+ Comment: node.label ?? `Invoke domain action ${node.domainId}/${node.actionId}`,
28
+ };
29
+ if (node.next) {
30
+ state.Next = node.next;
31
+ }
32
+ else {
33
+ state.End = true;
34
+ }
35
+ return state;
36
+ }
37
+ /**
38
+ * Generate a full Step Functions state machine definition from a list of
39
+ * domain-action nodes. Nodes are ordered by their `next` links; the first
40
+ * node that has no `next` becomes the terminal state.
41
+ *
42
+ * @param nodes - Ordered list of domain-action nodes.
43
+ * @param startAt - Name of the first state. Defaults to the first node's label or actionId.
44
+ * @returns A Step Functions state machine definition object.
45
+ */
46
+ generateStateMachine(nodes, startAt) {
47
+ const states = {};
48
+ for (const node of nodes) {
49
+ const stateName = node.label ?? `${node.domainId}/${node.actionId}`;
50
+ states[stateName] = this.generateTaskState(node);
51
+ }
52
+ const firstStateName = startAt ?? (nodes[0] ? (nodes[0].label ?? `${nodes[0].domainId}/${nodes[0].actionId}`) : 'Start');
53
+ return { StartAt: firstStateName, States: states };
54
+ }
55
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@teaminabottle/domain-cdk-packer",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "registry": "https://registry.npmjs.org",
7
+ "access": "public"
8
+ },
9
+ "files": ["dist"],
10
+ "exports": {
11
+ ".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" }
12
+ },
13
+ "scripts": {
14
+ "typecheck": "tsc --noEmit -p tsconfig.json",
15
+ "build": "tsc -p tsconfig.json",
16
+ "test": "vitest"
17
+ },
18
+ "peerDependencies": {
19
+ "aws-cdk-lib": "^2.0.0",
20
+ "constructs": "^10.0.0"
21
+ },
22
+ "devDependencies": {
23
+ "aws-cdk-lib": "^2.100.0",
24
+ "constructs": "^10.3.0",
25
+ "esbuild": "^0.21.0",
26
+ "typescript": "^5.0.0",
27
+ "vitest": "^2.0.0",
28
+ "@types/node": "^20.0.0"
29
+ },
30
+ "dependencies": {}
31
+ }