@deliverr/serverless-offline-step-functions
Version:
Serverless Offline Plugin to Support Step Functions for Local Development
102 lines (101 loc) • 4.89 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StepFunctionSimulatorServer = void 0;
const http_terminator_1 = require("http-terminator");
const express_1 = __importDefault(require("express"));
const StateMachineExecutor_1 = require("./StateMachineExecutor");
const Logger_1 = require("./utils/Logger");
const StateMachineContext_1 = require("./Context/StateMachineContext");
const ExecutionContext_1 = require("./Context/ExecutionContext");
const Context_1 = require("./Context/Context");
const StateContext_1 = require("./Context/StateContext");
class StepFunctionSimulatorServer {
constructor(options) {
this.pendingStateMachineExecutions = {};
this.options = options;
this.stateMachines = this.options.stateMachines;
this.logger = Logger_1.Logger.getInstance();
this.express = express_1.default();
this.setupMiddlewares();
}
async initServer() {
let httpServer;
try {
httpServer = this.express.listen(this.options.port, () => {
this.logger.success(`Server ready on port ${this.options.port} 🚀`);
});
}
catch (err) {
this.logger.error(`Unexpected error while starting serverless-offline server on port ${this.options.port}: ${err.stack}`);
process.exit(1);
}
this.httpTerminator = http_terminator_1.createHttpTerminator({ server: httpServer });
}
async shutdown() {
var _a;
this.logger.warning('Killing Step Functions API Simulator 🔪');
await ((_a = this.httpTerminator) === null || _a === void 0 ? void 0 : _a.terminate());
}
setupMiddlewares() {
this.express.use(express_1.default.json({
type(req) {
const contentType = req.headers['content-type'] || '';
return ['application/x-amz-json-1.0'].includes(contentType);
},
limit: '262144b',
}));
this.express.use(this.resolveStateMachine.bind(this));
}
isSendTaskSuccess(body) {
return !!body.taskToken && !!body.output;
}
isSendTaskFailure(body) {
return !!body.taskToken && !body.output;
}
async resolveStateMachine(req, res) {
this.logger.log(`Got request for ${req.method} ${req.url}`);
if (req.body.taskToken) {
if (this.isSendTaskSuccess(req.body)) {
if (typeof this.pendingStateMachineExecutions[req.body.taskToken] !== 'function') {
this.logger.log(`No step function to resume with taskToken '${req.body.taskToken}.'`);
return;
}
this.logger.log(`Going to resume taskToken "${req.body.taskToken}" with output "${req.body.output}"`);
this.pendingStateMachineExecutions[req.body.taskToken](JSON.parse(req.body.output));
return;
}
if (this.isSendTaskFailure(req.body)) {
}
}
const executionInput = req.body;
const stateMachineContext = StateMachineContext_1.StateMachineContext.create(executionInput.stateMachineArn);
const stateMachineToExecute = this.stateMachines.getStateMachineBy(stateMachineContext.Name);
if (!stateMachineToExecute) {
const errorMessage = `No stateMachineToExecute for name "${stateMachineContext.Name}"`;
this.logger.error(errorMessage);
return res.status(404).send();
}
const executionContext = ExecutionContext_1.ExecutionContext.create(stateMachineContext, executionInput.input);
const firstStateContext = StateContext_1.StateContext.create(stateMachineToExecute.definition.StartAt);
const context = Context_1.Context.create(executionContext, stateMachineContext, firstStateContext);
this.logger.debug('State definitions:');
this.logger.debug(JSON.stringify(stateMachineToExecute.definition.States));
const startAtState = stateMachineToExecute.definition.States[firstStateContext.Name];
const sme = new StateMachineExecutor_1.StateMachineExecutor(stateMachineToExecute, context);
await new Promise((resolve) => {
const output = {
startDate: new Date(context.Execution.StartTime),
executionArn: context.Execution.Id,
};
resolve(res.status(200).json(output));
});
const executionResult = await sme.execute(startAtState, executionContext.Input);
if (typeof executionResult === 'function') {
this.pendingStateMachineExecutions[context.Task.Token] = executionResult;
}
}
}
exports.StepFunctionSimulatorServer = StepFunctionSimulatorServer;