@simplesteps/cdk
v0.2.0
Published
AWS CDK construct for SimpleSteps — compile TypeScript workflows into Step Functions state machines
Maintainers
Readme
@simplesteps/cdk
AWS CDK construct for SimpleSteps — compile TypeScript workflows into Step Functions state machines and deploy them with CDK.
Install
npm install @simplesteps/core @simplesteps/cdkExample
Define your workflow inline with real CDK resources. The compiler runs at synth time — CDK tokens like function ARNs and table names are automatically propagated through CloudFormation intrinsics.
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as sns from 'aws-cdk-lib/aws-sns';
import { Construct } from 'constructs';
import { SimpleStepsStateMachine } from '@simplesteps/cdk';
import { Steps, SimpleStepContext } from '@simplesteps/core/runtime';
import { Lambda, DynamoDB, SNS } from '@simplesteps/core/runtime/services';
export class OrderStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const validateFn = new lambda.Function(this, 'ValidateOrder', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda/validate-order'),
});
const enrichFn = new lambda.Function(this, 'EnrichCustomer', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda/enrich-customer'),
});
const ordersTable = new dynamodb.Table(this, 'OrdersTable', {
partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'sk', type: dynamodb.AttributeType.STRING },
});
const topic = new sns.Topic(this, 'OrderNotifications');
// Typed service bindings — CDK token ARNs resolve at synth time
const validateOrder = Lambda<{ orderId: string }, { valid: boolean; total: number }>(
validateFn.functionArn,
);
const enrichCustomer = Lambda<{ customerId: string }, { tier: string; email: string }>(
enrichFn.functionArn,
);
const orders = new DynamoDB(ordersTable.tableName);
const notifications = new SNS(topic.topicArn);
const machine = new SimpleStepsStateMachine(this, 'OrderWorkflow', {
workflow: Steps.createFunction(
async (context: SimpleStepContext, input: { orderId: string; customerId: string }) => {
// Validate and enrich in parallel
const [order, customer] = await Promise.all([
validateOrder.call({ orderId: input.orderId }),
enrichCustomer.call({ customerId: input.customerId }),
]);
if (!order.valid) {
throw new Error('Order validation failed');
}
const discount = customer.tier === 'premium' ? 0.1 : 0;
const finalTotal = Math.round(order.total * (1 - discount));
await orders.putItem({
Item: {
pk: { S: input.orderId },
sk: { S: input.customerId },
total: { N: String(finalTotal) },
status: { S: 'CONFIRMED' },
},
});
await notifications.publish({
Message: `Order ${input.orderId} confirmed — $${String(finalTotal)}`,
Subject: 'Order Confirmed',
});
return { orderId: input.orderId, total: finalTotal, tier: customer.tier };
},
),
});
// Standard CDK grants — machine extends sfn.StateMachine
validateFn.grantInvoke(machine);
enrichFn.grantInvoke(machine);
ordersTable.grantWriteData(machine);
topic.grantPublish(machine);
}
}File-based compilation
Workflows can also live in separate files:
new SimpleStepsStateMachine(this, 'Workflow', {
sourceFile: require.resolve('./workflow'),
bindings: {
validateOrder: validateFn.functionArn,
orders: ordersTable.tableName,
},
});Features
- Compiles TypeScript to ASL at synth time
- Automatic CDK token substitution (
Fn::GetAtt,Ref) for Lambda ARNs, table names, queue URLs, etc. - Standard CDK permissions —
fn.grantInvoke(machine),table.grantReadWriteData(machine) - JSONata (default) and JSONPath query languages
- Source map annotations for debugging
Documentation
License
MIT
