@motiadev/core 0.0.6 → 0.0.7-build.20250529215343
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 -0
- package/README.md +142 -0
- package/dist/index.d.ts +13 -8
- package/dist/index.js +28 -8
- package/dist/src/call-step-file.d.ts +17 -2
- package/dist/src/call-step-file.js +88 -47
- package/dist/src/cron-handler.d.ts +13 -0
- package/dist/src/cron-handler.js +98 -0
- package/dist/src/event-manager.js +10 -5
- package/dist/src/flows-config-endpoint.d.ts +2 -0
- package/dist/src/flows-config-endpoint.js +51 -0
- package/dist/src/flows-endpoint.d.ts +11 -7
- package/dist/src/flows-endpoint.js +53 -22
- package/dist/src/generate-trace-id.d.ts +2 -0
- package/dist/src/generate-trace-id.js +14 -0
- package/dist/src/get-step-config.d.ts +4 -0
- package/dist/src/get-step-config.js +88 -0
- package/dist/src/guards.d.ts +3 -2
- package/dist/src/guards.js +3 -1
- package/dist/src/locked-data.d.ts +60 -0
- package/dist/src/locked-data.js +278 -0
- package/dist/src/logger-factory.d.ts +15 -0
- package/dist/src/logger-factory.js +14 -0
- package/dist/src/logger.d.ts +21 -15
- package/dist/src/logger.js +49 -29
- package/dist/src/mermaid-generator.d.ts +4 -0
- package/dist/src/mermaid-generator.js +203 -0
- package/dist/src/node/get-config.d.ts +1 -2
- package/dist/src/node/get-config.js +51 -8
- package/dist/src/node/logger.d.ts +10 -6
- package/dist/src/node/logger.js +27 -16
- package/dist/src/node/middleware-compose.d.ts +1 -0
- package/dist/src/node/middleware-compose.js +12 -0
- package/dist/src/node/node-runner.js +28 -9
- package/dist/src/node/rpc-state-manager.d.ts +3 -2
- package/dist/src/node/rpc-state-manager.js +5 -2
- package/dist/src/node/rpc.d.ts +3 -1
- package/dist/src/node/rpc.js +21 -3
- package/dist/src/pretty-print.d.ts +1 -0
- package/dist/src/pretty-print.js +66 -0
- package/dist/src/printer.d.ts +45 -0
- package/dist/src/printer.js +121 -0
- package/dist/src/process-communication/communication-config.d.ts +7 -0
- package/dist/src/process-communication/communication-config.js +12 -0
- package/dist/src/process-communication/process-manager.d.ts +30 -0
- package/dist/src/process-communication/process-manager.js +88 -0
- package/dist/src/process-communication/rpc-processor-interface.d.ts +9 -0
- package/dist/src/process-communication/rpc-processor-interface.js +2 -0
- package/dist/src/python/communication_factory.py +35 -0
- package/dist/src/python/context.py +21 -0
- package/dist/src/python/get-config.py +31 -13
- package/dist/src/python/ipc_communication.py +145 -0
- package/dist/src/python/logger.py +4 -6
- package/dist/src/python/middleware.py +17 -0
- package/dist/src/python/python-runner.py +105 -39
- package/dist/src/python/rpc.py +33 -68
- package/dist/src/python/rpc_communication.py +125 -0
- package/dist/src/python/rpc_state_manager.py +49 -11
- package/dist/src/python/type_definitions.py +34 -0
- package/dist/src/python/validation.py +56 -0
- package/dist/src/ruby/get-config.rb +61 -0
- package/dist/src/ruby/logger.rb +21 -16
- package/dist/src/ruby/rpc.rb +118 -0
- package/dist/src/ruby/rpc_state_manager.rb +41 -0
- package/dist/src/ruby/ruby-runner.rb +94 -0
- package/dist/src/server.d.ts +14 -12
- package/dist/src/server.js +149 -28
- package/dist/src/socket-server.d.ts +39 -0
- package/dist/src/socket-server.js +76 -0
- package/dist/src/state/adapters/default-state-adapter.d.ts +7 -3
- package/dist/src/state/adapters/default-state-adapter.js +37 -14
- package/dist/src/state/adapters/memory-state-adapter.d.ts +14 -0
- package/dist/src/state/adapters/memory-state-adapter.js +58 -0
- package/dist/src/state/create-state-adapter.d.ts +5 -6
- package/dist/src/state/create-state-adapter.js +2 -10
- package/dist/src/state/state-adapter.d.ts +4 -4
- package/dist/src/state-stream.d.ts +19 -0
- package/dist/src/state-stream.js +28 -0
- package/dist/src/step-handler-rpc-processor.d.ts +13 -4
- package/dist/src/step-handler-rpc-processor.js +33 -3
- package/dist/src/step-handler-rpc-stdin-processor.d.ts +22 -0
- package/dist/src/step-handler-rpc-stdin-processor.js +84 -0
- package/dist/src/step-handlers.d.ts +7 -2
- package/dist/src/step-handlers.js +47 -19
- package/dist/src/step-validator.d.ts +14 -0
- package/dist/src/step-validator.js +138 -0
- package/dist/src/steps/emit.step.d.ts +11 -0
- package/dist/src/steps/emit.step.js +27 -0
- package/dist/src/steps/emit.step.ts +34 -0
- package/dist/src/steps/index.d.ts +2 -0
- package/dist/src/steps/index.js +16 -0
- package/dist/src/streams/api-endpoints.d.ts +2 -0
- package/dist/src/streams/api-endpoints.js +71 -0
- package/dist/src/streams/flows-stream.d.ts +14 -0
- package/dist/src/streams/flows-stream.js +29 -0
- package/dist/src/streams/logs-stream.d.ts +16 -0
- package/dist/src/streams/logs-stream.js +22 -0
- package/dist/src/types/generate-type-from-schema.d.ts +2 -0
- package/dist/src/types/generate-type-from-schema.js +28 -0
- package/dist/src/types/generate-types-from-response.d.ts +2 -0
- package/dist/src/types/generate-types-from-response.js +13 -0
- package/dist/src/types/generate-types.d.ts +12 -0
- package/dist/src/types/generate-types.js +108 -0
- package/dist/src/types/merge-schemas.d.ts +3 -0
- package/dist/src/types/merge-schemas.js +59 -0
- package/dist/src/types/schema.types.d.ts +20 -0
- package/dist/src/types/schema.types.js +10 -0
- package/dist/src/types-stream.d.ts +34 -0
- package/dist/src/types-stream.js +2 -0
- package/dist/src/types.d.ts +93 -47
- package/dist/src/utils.d.ts +2 -0
- package/dist/src/utils.js +12 -0
- package/package.json +20 -9
- package/requirements.txt +1 -0
- package/dist/src/node/get-module-export.d.ts +0 -1
- package/dist/src/node/get-module-export.js +0 -63
- package/dist/src/python/get-python-config.d.ts +0 -2
- package/dist/src/python/get-python-config.js +0 -34
- package/dist/src/ruby/get_config.rb +0 -78
- package/dist/src/ruby/ruby_runner.rb +0 -80
- package/dist/src/ruby/state_adapter.rb +0 -62
- package/dist/src/state/adapters/redis-state-adapter.d.ts +0 -19
- package/dist/src/state/adapters/redis-state-adapter.js +0 -44
- package/tsconfig.json +0 -20
|
@@ -3,59 +3,75 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.generateFlow = exports.flowsEndpoint = void 0;
|
|
7
7
|
const crypto_1 = require("crypto");
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const
|
|
10
|
-
const
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const zod_1 = require("zod");
|
|
11
11
|
const get_step_language_1 = require("./get-step-language");
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
const guards_1 = require("./guards");
|
|
13
|
+
const flows_stream_1 = require("./streams/flows-stream");
|
|
14
|
+
const flowsEndpoint = (lockedData, app) => {
|
|
15
|
+
const flowsStream = lockedData.createStream({
|
|
16
|
+
filePath: '__motia.flows',
|
|
17
|
+
hidden: true,
|
|
18
|
+
config: {
|
|
19
|
+
name: '__motia.flows',
|
|
20
|
+
schema: zod_1.z.object({ id: zod_1.z.string(), name: zod_1.z.string() }),
|
|
21
|
+
baseConfig: { storageType: 'custom', factory: () => new flows_stream_1.FlowsStream(lockedData) },
|
|
22
|
+
},
|
|
23
|
+
}, { disableTypeCreation: true })();
|
|
24
|
+
lockedData.on('flow-created', (flow) => flowsStream.set('default', flow, { id: flow, name: flow }));
|
|
25
|
+
lockedData.on('flow-updated', (flow) => flowsStream.set('default', flow, { id: flow, name: flow }));
|
|
26
|
+
lockedData.on('flow-removed', (flow) => flowsStream.delete('default', flow));
|
|
17
27
|
app.get('/flows/:id', async (req, res) => {
|
|
18
|
-
const
|
|
19
|
-
const flow =
|
|
28
|
+
const flowId = req.params.id;
|
|
29
|
+
const flow = lockedData.flows[flowId];
|
|
20
30
|
if (!flow) {
|
|
21
31
|
res.status(404).send({ error: 'Flow not found' });
|
|
22
32
|
}
|
|
23
33
|
else {
|
|
24
|
-
res.status(200).send(flow);
|
|
34
|
+
res.status(200).send((0, exports.generateFlow)(flowId, flow.steps));
|
|
25
35
|
}
|
|
26
36
|
});
|
|
27
37
|
};
|
|
28
38
|
exports.flowsEndpoint = flowsEndpoint;
|
|
29
|
-
const generateFlowsList = (flows) => {
|
|
30
|
-
return Object.entries(flows).map(([flowId, flow]) => generateFlow(flowId, flow.steps));
|
|
31
|
-
};
|
|
32
|
-
exports.generateFlowsList = generateFlowsList;
|
|
33
39
|
// Helper functions
|
|
34
40
|
const getNodeComponentPath = (filePath) => {
|
|
35
41
|
const filePathWithoutExtension = filePath.replace(/\.[^/.]+$/, '');
|
|
36
42
|
const tsxPath = filePathWithoutExtension + '.tsx';
|
|
37
43
|
return fs_1.default.existsSync(tsxPath) ? tsxPath : undefined;
|
|
38
44
|
};
|
|
39
|
-
const
|
|
45
|
+
const getRelativePath = (filePath) => {
|
|
46
|
+
const baseDir = process.cwd();
|
|
47
|
+
return path_1.default.relative(baseDir, filePath);
|
|
48
|
+
};
|
|
49
|
+
const createEdge = (sourceId, targetId, topic, label, variant, conditional) => ({
|
|
40
50
|
id: `${sourceId}-${targetId}`,
|
|
41
51
|
source: sourceId,
|
|
42
52
|
target: targetId,
|
|
43
|
-
data: {
|
|
53
|
+
data: {
|
|
54
|
+
variant,
|
|
55
|
+
label,
|
|
56
|
+
topic,
|
|
57
|
+
labelVariant: conditional ? 'conditional' : 'default',
|
|
58
|
+
},
|
|
44
59
|
});
|
|
45
60
|
const processEmit = (emit) => {
|
|
46
61
|
const isString = typeof emit === 'string';
|
|
47
62
|
return {
|
|
48
|
-
|
|
63
|
+
topic: isString ? emit : emit.topic,
|
|
49
64
|
label: isString ? undefined : emit.label,
|
|
65
|
+
conditional: isString ? undefined : emit.conditional,
|
|
50
66
|
};
|
|
51
67
|
};
|
|
52
68
|
const createEdgesForEmits = (sourceStep, targetSteps, emits, variant) => {
|
|
53
69
|
const edges = [];
|
|
54
70
|
emits.forEach((emit) => {
|
|
55
|
-
const {
|
|
71
|
+
const { topic, label, conditional } = processEmit(emit);
|
|
56
72
|
targetSteps.forEach((targetStep) => {
|
|
57
|
-
if (targetStep.subscribes?.includes(
|
|
58
|
-
edges.push(createEdge(sourceStep.id, targetStep.id,
|
|
73
|
+
if (targetStep.subscribes?.includes(topic)) {
|
|
74
|
+
edges.push(createEdge(sourceStep.id, targetStep.id, topic, label, variant, conditional));
|
|
59
75
|
}
|
|
60
76
|
});
|
|
61
77
|
});
|
|
@@ -66,6 +82,7 @@ const createBaseStepResponse = (step, id) => ({
|
|
|
66
82
|
name: step.config.name,
|
|
67
83
|
description: step.config.description,
|
|
68
84
|
nodeComponentPath: getNodeComponentPath(step.filePath),
|
|
85
|
+
filePath: getRelativePath(step.filePath),
|
|
69
86
|
language: (0, get_step_language_1.getStepLanguage)(step.filePath),
|
|
70
87
|
});
|
|
71
88
|
const createApiStepResponse = (step, id) => {
|
|
@@ -80,7 +97,7 @@ const createApiStepResponse = (step, id) => {
|
|
|
80
97
|
subscribes: step.config.virtualSubscribes ?? undefined,
|
|
81
98
|
action: 'webhook',
|
|
82
99
|
webhookUrl: `${step.config.method} ${step.config.path}`,
|
|
83
|
-
bodySchema: step.config.bodySchema
|
|
100
|
+
bodySchema: step.config.bodySchema ?? undefined,
|
|
84
101
|
};
|
|
85
102
|
};
|
|
86
103
|
const createEventStepResponse = (step, id) => {
|
|
@@ -107,6 +124,17 @@ const createNoopStepResponse = (step, id) => {
|
|
|
107
124
|
subscribes: step.config.virtualSubscribes,
|
|
108
125
|
};
|
|
109
126
|
};
|
|
127
|
+
const createCronStepResponse = (step, id) => {
|
|
128
|
+
if (!(0, guards_1.isCronStep)(step)) {
|
|
129
|
+
throw new Error('Attempted to create Cron step response with non-Cron step');
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
...createBaseStepResponse(step, id),
|
|
133
|
+
type: 'cron',
|
|
134
|
+
emits: step.config.emits,
|
|
135
|
+
cronExpression: step.config.cron,
|
|
136
|
+
};
|
|
137
|
+
};
|
|
110
138
|
const createStepResponse = (step) => {
|
|
111
139
|
const id = (0, crypto_1.randomUUID)();
|
|
112
140
|
if ((0, guards_1.isApiStep)(step))
|
|
@@ -115,6 +143,8 @@ const createStepResponse = (step) => {
|
|
|
115
143
|
return createEventStepResponse(step, id);
|
|
116
144
|
if ((0, guards_1.isNoopStep)(step))
|
|
117
145
|
return createNoopStepResponse(step, id);
|
|
146
|
+
if ((0, guards_1.isCronStep)(step))
|
|
147
|
+
return createCronStepResponse(step, id);
|
|
118
148
|
throw new Error(`Unknown step type for step: ${step.config.name}`);
|
|
119
149
|
};
|
|
120
150
|
const createEdgesForStep = (sourceStep, allSteps) => {
|
|
@@ -129,3 +159,4 @@ const generateFlow = (flowId, flowSteps) => {
|
|
|
129
159
|
const edges = steps.flatMap((step) => createEdgesForStep(step, steps));
|
|
130
160
|
return { id: flowId, name: flowId, steps, edges };
|
|
131
161
|
};
|
|
162
|
+
exports.generateFlow = generateFlow;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateTraceId = exports.generateCode = void 0;
|
|
4
|
+
const generateCode = (length = 6) => {
|
|
5
|
+
const chars = 'ABCDEFGHJKMNPQRSTUVWXYZ123456789';
|
|
6
|
+
return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join('');
|
|
7
|
+
};
|
|
8
|
+
exports.generateCode = generateCode;
|
|
9
|
+
const generateTraceId = () => {
|
|
10
|
+
const datePart = String(Date.now()).slice(6);
|
|
11
|
+
const randomPart = (0, exports.generateCode)(5);
|
|
12
|
+
return `${randomPart}-${datePart}`;
|
|
13
|
+
};
|
|
14
|
+
exports.generateTraceId = generateTraceId;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getStreamConfig = exports.getStepConfig = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const logger_1 = require("./logger");
|
|
9
|
+
const process_manager_1 = require("./process-communication/process-manager");
|
|
10
|
+
const getLanguageBasedRunner = (stepFilePath = '') => {
|
|
11
|
+
const isPython = stepFilePath.endsWith('.py');
|
|
12
|
+
const isRuby = stepFilePath.endsWith('.rb');
|
|
13
|
+
const isNode = stepFilePath.endsWith('.js') || stepFilePath.endsWith('.ts');
|
|
14
|
+
if (isPython) {
|
|
15
|
+
const pythonRunner = path_1.default.join(__dirname, 'python', 'get-config.py');
|
|
16
|
+
return { runner: pythonRunner, command: 'python', args: [] };
|
|
17
|
+
}
|
|
18
|
+
else if (isRuby) {
|
|
19
|
+
const rubyRunner = path_1.default.join(__dirname, 'ruby', 'get-config.rb');
|
|
20
|
+
return { runner: rubyRunner, command: 'ruby', args: [] };
|
|
21
|
+
}
|
|
22
|
+
else if (isNode) {
|
|
23
|
+
if (process.env._MOTIA_TEST_MODE === 'true') {
|
|
24
|
+
const nodeRunner = path_1.default.join(__dirname, 'node', 'get-config.ts');
|
|
25
|
+
return { runner: nodeRunner, command: 'node', args: ['-r', 'ts-node/register'] };
|
|
26
|
+
}
|
|
27
|
+
const nodeRunner = path_1.default.join(__dirname, 'node', 'get-config.js');
|
|
28
|
+
return { runner: nodeRunner, command: 'node', args: [] };
|
|
29
|
+
}
|
|
30
|
+
throw Error(`Unsupported file extension ${stepFilePath}`);
|
|
31
|
+
};
|
|
32
|
+
const getConfig = (file) => {
|
|
33
|
+
const { runner, command, args } = getLanguageBasedRunner(file);
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
let config = null;
|
|
36
|
+
const processManager = new process_manager_1.ProcessManager({
|
|
37
|
+
command,
|
|
38
|
+
args: [...args, runner, file],
|
|
39
|
+
logger: logger_1.globalLogger,
|
|
40
|
+
context: 'Config',
|
|
41
|
+
});
|
|
42
|
+
processManager
|
|
43
|
+
.spawn()
|
|
44
|
+
.then(() => {
|
|
45
|
+
processManager.onMessage((message) => {
|
|
46
|
+
config = message;
|
|
47
|
+
logger_1.globalLogger.debug(`[Config] Read config via ${processManager.commType?.toUpperCase()}`, {
|
|
48
|
+
config,
|
|
49
|
+
communicationType: processManager.commType,
|
|
50
|
+
});
|
|
51
|
+
resolve(config);
|
|
52
|
+
processManager.kill();
|
|
53
|
+
});
|
|
54
|
+
processManager.onProcessClose((code) => {
|
|
55
|
+
processManager.close();
|
|
56
|
+
if (config) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
else if (code !== 0) {
|
|
60
|
+
reject(`Process exited with code ${code}`);
|
|
61
|
+
}
|
|
62
|
+
else if (!config) {
|
|
63
|
+
reject(`No config found for file ${file}`);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
processManager.onProcessError((error) => {
|
|
67
|
+
processManager.close();
|
|
68
|
+
if (error.code === 'ENOENT') {
|
|
69
|
+
reject(`Executable ${command} not found`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
reject(error);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
})
|
|
76
|
+
.catch((error) => {
|
|
77
|
+
reject(`Failed to spawn process: ${error}`);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
const getStepConfig = (file) => {
|
|
82
|
+
return getConfig(file);
|
|
83
|
+
};
|
|
84
|
+
exports.getStepConfig = getStepConfig;
|
|
85
|
+
const getStreamConfig = (file) => {
|
|
86
|
+
return getConfig(file);
|
|
87
|
+
};
|
|
88
|
+
exports.getStreamConfig = getStreamConfig;
|
package/dist/src/guards.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ApiRouteConfig, EventConfig, NoopConfig, Step } from './types';
|
|
1
|
+
import { ApiRouteConfig, EventConfig, NoopConfig, Step, CronConfig } from './types';
|
|
2
2
|
export declare const isApiStep: (step: Step) => step is Step<ApiRouteConfig>;
|
|
3
|
-
export declare const isEventStep: (step: Step) => step is Step<EventConfig
|
|
3
|
+
export declare const isEventStep: (step: Step) => step is Step<EventConfig>;
|
|
4
4
|
export declare const isNoopStep: (step: Step) => step is Step<NoopConfig>;
|
|
5
|
+
export declare const isCronStep: (step: Step) => step is Step<CronConfig>;
|
package/dist/src/guards.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isNoopStep = exports.isEventStep = exports.isApiStep = void 0;
|
|
3
|
+
exports.isCronStep = exports.isNoopStep = exports.isEventStep = exports.isApiStep = void 0;
|
|
4
4
|
const isApiStep = (step) => step.config.type === 'api';
|
|
5
5
|
exports.isApiStep = isApiStep;
|
|
6
6
|
const isEventStep = (step) => step.config.type === 'event';
|
|
7
7
|
exports.isEventStep = isEventStep;
|
|
8
8
|
const isNoopStep = (step) => step.config.type === 'noop';
|
|
9
9
|
exports.isNoopStep = isNoopStep;
|
|
10
|
+
const isCronStep = (step) => step.config.type === 'cron';
|
|
11
|
+
exports.isCronStep = isCronStep;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Printer } from './printer';
|
|
2
|
+
import { StateStreamFactory } from './state-stream';
|
|
3
|
+
import { ApiRouteConfig, CronConfig, EventConfig, Flow, InternalStateManager, Step } from './types';
|
|
4
|
+
import { Stream } from './types-stream';
|
|
5
|
+
type FlowEvent = 'flow-created' | 'flow-removed' | 'flow-updated';
|
|
6
|
+
type StepEvent = 'step-created' | 'step-removed' | 'step-updated';
|
|
7
|
+
type StreamEvent = 'stream-created' | 'stream-removed' | 'stream-updated';
|
|
8
|
+
type StreamWrapper<TData> = (streamName: string, factory: StateStreamFactory<TData>) => StateStreamFactory<TData>;
|
|
9
|
+
export declare class LockedData {
|
|
10
|
+
readonly baseDir: string;
|
|
11
|
+
flows: Record<string, Flow>;
|
|
12
|
+
activeSteps: Step[];
|
|
13
|
+
devSteps: Step[];
|
|
14
|
+
printer: Printer;
|
|
15
|
+
private stepsMap;
|
|
16
|
+
private handlers;
|
|
17
|
+
private stepHandlers;
|
|
18
|
+
private streamHandlers;
|
|
19
|
+
private streams;
|
|
20
|
+
private state;
|
|
21
|
+
private streamWrapper?;
|
|
22
|
+
constructor(baseDir: string);
|
|
23
|
+
disablePrinter(): void;
|
|
24
|
+
applyStreamWrapper<TData>(state: InternalStateManager, streamWrapper: StreamWrapper<TData>): void;
|
|
25
|
+
saveTypes(): void;
|
|
26
|
+
on(event: FlowEvent, handler: (flowName: string) => void): void;
|
|
27
|
+
onStep(event: StepEvent, handler: (step: Step) => void): void;
|
|
28
|
+
onStream(event: StreamEvent, handler: (stream: Stream) => void): void;
|
|
29
|
+
eventSteps(): Step<EventConfig>[];
|
|
30
|
+
apiSteps(): Step<ApiRouteConfig>[];
|
|
31
|
+
cronSteps(): Step<CronConfig>[];
|
|
32
|
+
pythonSteps(): Step[];
|
|
33
|
+
tsSteps(): Step[];
|
|
34
|
+
getStreams(): Record<string, StateStreamFactory<any>>;
|
|
35
|
+
findStream(path: string): Stream | undefined;
|
|
36
|
+
updateStep(oldStep: Step, newStep: Step, options?: {
|
|
37
|
+
disableTypeCreation?: boolean;
|
|
38
|
+
}): boolean;
|
|
39
|
+
createStep(step: Step, options?: {
|
|
40
|
+
disableTypeCreation?: boolean;
|
|
41
|
+
}): boolean;
|
|
42
|
+
deleteStep(step: Step, options?: {
|
|
43
|
+
disableTypeCreation?: boolean;
|
|
44
|
+
}): void;
|
|
45
|
+
private createFactoryWrapper;
|
|
46
|
+
createStream<TData>(stream: Stream, options?: {
|
|
47
|
+
disableTypeCreation?: boolean;
|
|
48
|
+
}): StateStreamFactory<TData>;
|
|
49
|
+
deleteStream(stream: Stream, options?: {
|
|
50
|
+
disableTypeCreation?: boolean;
|
|
51
|
+
}): void;
|
|
52
|
+
updateStream(oldStream: Stream, stream: Stream, options?: {
|
|
53
|
+
disableTypeCreation?: boolean;
|
|
54
|
+
}): void;
|
|
55
|
+
private createFlow;
|
|
56
|
+
private removeFlow;
|
|
57
|
+
private onFlowUpdated;
|
|
58
|
+
private isValidStep;
|
|
59
|
+
}
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LockedData = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const guards_1 = require("./guards");
|
|
10
|
+
const printer_1 = require("./printer");
|
|
11
|
+
const state_stream_1 = require("./state-stream");
|
|
12
|
+
const step_validator_1 = require("./step-validator");
|
|
13
|
+
const generate_types_1 = require("./types/generate-types");
|
|
14
|
+
class LockedData {
|
|
15
|
+
constructor(baseDir) {
|
|
16
|
+
this.baseDir = baseDir;
|
|
17
|
+
this.state = null;
|
|
18
|
+
this.flows = {};
|
|
19
|
+
this.activeSteps = [];
|
|
20
|
+
this.devSteps = [];
|
|
21
|
+
this.stepsMap = {};
|
|
22
|
+
this.printer = new printer_1.Printer(baseDir);
|
|
23
|
+
this.handlers = {
|
|
24
|
+
'flow-created': [],
|
|
25
|
+
'flow-removed': [],
|
|
26
|
+
'flow-updated': [],
|
|
27
|
+
};
|
|
28
|
+
this.stepHandlers = {
|
|
29
|
+
'step-created': [],
|
|
30
|
+
'step-removed': [],
|
|
31
|
+
'step-updated': [],
|
|
32
|
+
};
|
|
33
|
+
this.streamHandlers = {
|
|
34
|
+
'stream-created': [],
|
|
35
|
+
'stream-removed': [],
|
|
36
|
+
'stream-updated': [],
|
|
37
|
+
};
|
|
38
|
+
this.streams = {};
|
|
39
|
+
}
|
|
40
|
+
disablePrinter() {
|
|
41
|
+
this.printer = new printer_1.NoPrinter(this.baseDir);
|
|
42
|
+
}
|
|
43
|
+
applyStreamWrapper(state, streamWrapper) {
|
|
44
|
+
this.streamWrapper = streamWrapper;
|
|
45
|
+
this.state = state;
|
|
46
|
+
}
|
|
47
|
+
saveTypes() {
|
|
48
|
+
const types = (0, generate_types_1.generateTypesFromSteps)(this.activeSteps, this.printer);
|
|
49
|
+
const streams = (0, generate_types_1.generateTypesFromStreams)(this.streams);
|
|
50
|
+
const typesString = (0, generate_types_1.generateTypesString)(types, streams);
|
|
51
|
+
fs_1.default.writeFileSync(path_1.default.join(this.baseDir, 'types.d.ts'), typesString);
|
|
52
|
+
}
|
|
53
|
+
on(event, handler) {
|
|
54
|
+
this.handlers[event].push(handler);
|
|
55
|
+
}
|
|
56
|
+
onStep(event, handler) {
|
|
57
|
+
this.stepHandlers[event].push(handler);
|
|
58
|
+
}
|
|
59
|
+
onStream(event, handler) {
|
|
60
|
+
this.streamHandlers[event].push(handler);
|
|
61
|
+
}
|
|
62
|
+
eventSteps() {
|
|
63
|
+
return this.activeSteps.filter(guards_1.isEventStep);
|
|
64
|
+
}
|
|
65
|
+
apiSteps() {
|
|
66
|
+
return this.activeSteps.filter(guards_1.isApiStep);
|
|
67
|
+
}
|
|
68
|
+
cronSteps() {
|
|
69
|
+
return this.activeSteps.filter(guards_1.isCronStep);
|
|
70
|
+
}
|
|
71
|
+
pythonSteps() {
|
|
72
|
+
return this.activeSteps.filter((step) => step.filePath.endsWith('.py'));
|
|
73
|
+
}
|
|
74
|
+
tsSteps() {
|
|
75
|
+
return this.activeSteps.filter((step) => step.filePath.endsWith('.ts'));
|
|
76
|
+
}
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
|
+
getStreams() {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
80
|
+
const streams = {};
|
|
81
|
+
for (const [key, value] of Object.entries(this.streams)) {
|
|
82
|
+
const baseConfig = value.config.baseConfig;
|
|
83
|
+
const streamFactory = baseConfig.storageType === 'custom' ? baseConfig.factory : null;
|
|
84
|
+
if (streamFactory) {
|
|
85
|
+
streams[key] = streamFactory;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return streams;
|
|
89
|
+
}
|
|
90
|
+
findStream(path) {
|
|
91
|
+
return Object.values(this.streams).find((stream) => stream.filePath === path);
|
|
92
|
+
}
|
|
93
|
+
updateStep(oldStep, newStep, options = {}) {
|
|
94
|
+
if (!this.isValidStep(newStep)) {
|
|
95
|
+
this.deleteStep(oldStep);
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
if (oldStep.config.type !== newStep.config.type) {
|
|
99
|
+
this.activeSteps = this.activeSteps.filter((s) => s.filePath !== oldStep.filePath);
|
|
100
|
+
this.devSteps = this.devSteps.filter((s) => s.filePath !== oldStep.filePath);
|
|
101
|
+
if (newStep.config.type === 'noop') {
|
|
102
|
+
this.devSteps.push(newStep);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
this.activeSteps.push(newStep);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const savedStep = this.stepsMap[newStep.filePath];
|
|
109
|
+
const addedFlows = newStep.config.flows?.filter((flowName) => !oldStep.config.flows?.includes(flowName)) ?? [];
|
|
110
|
+
const removedFlows = oldStep.config.flows?.filter((flowName) => !newStep.config.flows?.includes(flowName)) ?? [];
|
|
111
|
+
const untouchedFlows = oldStep.config.flows?.filter((flowName) => newStep.config.flows?.includes(flowName)) ?? [];
|
|
112
|
+
untouchedFlows.forEach((flowName) => this.onFlowUpdated(flowName));
|
|
113
|
+
for (const flowName of addedFlows) {
|
|
114
|
+
if (!this.flows[flowName]) {
|
|
115
|
+
const flow = this.createFlow(flowName);
|
|
116
|
+
flow.steps.push(savedStep);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
this.flows[flowName].steps.push(savedStep);
|
|
120
|
+
this.onFlowUpdated(flowName);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (const flowName of removedFlows) {
|
|
124
|
+
const flowSteps = this.flows[flowName].steps;
|
|
125
|
+
this.flows[flowName].steps = flowSteps.filter(({ filePath }) => filePath !== newStep.filePath);
|
|
126
|
+
if (this.flows[flowName].steps.length === 0) {
|
|
127
|
+
this.removeFlow(flowName);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
this.onFlowUpdated(flowName);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
savedStep.config = newStep.config;
|
|
134
|
+
if (!options.disableTypeCreation) {
|
|
135
|
+
this.saveTypes();
|
|
136
|
+
}
|
|
137
|
+
this.stepHandlers['step-updated'].forEach((handler) => handler(newStep));
|
|
138
|
+
this.printer.printStepUpdated(newStep);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
createStep(step, options = {}) {
|
|
142
|
+
if (!this.isValidStep(step)) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
this.stepsMap[step.filePath] = step;
|
|
146
|
+
if (step.config.type === 'noop') {
|
|
147
|
+
this.devSteps.push(step);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
this.activeSteps.push(step);
|
|
151
|
+
}
|
|
152
|
+
for (const flowName of step.config.flows ?? []) {
|
|
153
|
+
if (!this.flows[flowName]) {
|
|
154
|
+
const flow = this.createFlow(flowName);
|
|
155
|
+
flow.steps.push(step);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
this.flows[flowName].steps.push(step);
|
|
159
|
+
this.onFlowUpdated(flowName);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (!options.disableTypeCreation) {
|
|
163
|
+
this.saveTypes();
|
|
164
|
+
}
|
|
165
|
+
this.stepHandlers['step-created'].forEach((handler) => handler(step));
|
|
166
|
+
this.printer.printStepCreated(step);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
deleteStep(step, options = {}) {
|
|
170
|
+
// Remove step from active and dev steps
|
|
171
|
+
this.activeSteps = this.activeSteps.filter(({ filePath }) => filePath !== step.filePath);
|
|
172
|
+
this.devSteps = this.devSteps.filter(({ filePath }) => filePath !== step.filePath);
|
|
173
|
+
delete this.stepsMap[step.filePath];
|
|
174
|
+
for (const flowName of step.config.flows ?? []) {
|
|
175
|
+
const stepFlows = this.flows[flowName]?.steps;
|
|
176
|
+
if (stepFlows) {
|
|
177
|
+
this.flows[flowName].steps = stepFlows.filter(({ filePath }) => filePath !== step.filePath);
|
|
178
|
+
}
|
|
179
|
+
if (this.flows[flowName].steps.length === 0) {
|
|
180
|
+
this.removeFlow(flowName);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
this.onFlowUpdated(flowName);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (!options.disableTypeCreation) {
|
|
187
|
+
this.saveTypes();
|
|
188
|
+
}
|
|
189
|
+
this.stepHandlers['step-removed'].forEach((handler) => handler(step));
|
|
190
|
+
this.printer.printStepRemoved(step);
|
|
191
|
+
}
|
|
192
|
+
createFactoryWrapper(stream, factory) {
|
|
193
|
+
return () => {
|
|
194
|
+
const streamFactory = this.streamWrapper //
|
|
195
|
+
? this.streamWrapper(stream.config.name, factory)
|
|
196
|
+
: factory;
|
|
197
|
+
return streamFactory();
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
createStream(stream, options = {}) {
|
|
201
|
+
this.streams[stream.config.name] = stream;
|
|
202
|
+
this.streamHandlers['stream-created'].forEach((handler) => handler(stream));
|
|
203
|
+
let factory;
|
|
204
|
+
if (stream.config.baseConfig.storageType === 'state') {
|
|
205
|
+
factory = this.createFactoryWrapper(stream, () => new state_stream_1.InternalStateStream(this.state));
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
factory = this.createFactoryWrapper(stream, stream.config.baseConfig.factory);
|
|
209
|
+
}
|
|
210
|
+
stream.config.baseConfig = { storageType: 'custom', factory };
|
|
211
|
+
if (!stream.hidden) {
|
|
212
|
+
this.printer.printStreamCreated(stream);
|
|
213
|
+
if (!options.disableTypeCreation) {
|
|
214
|
+
this.saveTypes();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return factory;
|
|
218
|
+
}
|
|
219
|
+
deleteStream(stream, options = {}) {
|
|
220
|
+
Object.entries(this.streams).forEach(([streamName, { filePath }]) => {
|
|
221
|
+
if (stream.filePath === filePath) {
|
|
222
|
+
delete this.streams[streamName];
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
this.streamHandlers['stream-removed'].forEach((handler) => handler(stream));
|
|
226
|
+
if (!stream.hidden) {
|
|
227
|
+
this.printer.printStreamRemoved(stream);
|
|
228
|
+
if (!options.disableTypeCreation) {
|
|
229
|
+
this.saveTypes();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
updateStream(oldStream, stream, options = {}) {
|
|
234
|
+
if (oldStream.config.name !== stream.config.name) {
|
|
235
|
+
delete this.streams[oldStream.config.name];
|
|
236
|
+
}
|
|
237
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
238
|
+
let factory;
|
|
239
|
+
if (stream.config.baseConfig.storageType === 'state') {
|
|
240
|
+
factory = this.createFactoryWrapper(stream, () => new state_stream_1.InternalStateStream(this.state));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
factory = this.createFactoryWrapper(stream, stream.config.baseConfig.factory);
|
|
244
|
+
}
|
|
245
|
+
stream.config.baseConfig = { storageType: 'custom', factory };
|
|
246
|
+
this.streams[stream.config.name] = stream;
|
|
247
|
+
this.streamHandlers['stream-updated'].forEach((handler) => handler(stream));
|
|
248
|
+
if (!stream.hidden) {
|
|
249
|
+
this.printer.printStreamUpdated(stream);
|
|
250
|
+
if (!options.disableTypeCreation) {
|
|
251
|
+
this.saveTypes();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
createFlow(flowName) {
|
|
256
|
+
const flow = { name: flowName, description: '', steps: [] };
|
|
257
|
+
this.flows[flowName] = flow;
|
|
258
|
+
this.handlers['flow-created'].forEach((handler) => handler(flowName));
|
|
259
|
+
this.printer.printFlowCreated(flowName);
|
|
260
|
+
return flow;
|
|
261
|
+
}
|
|
262
|
+
removeFlow(flowName) {
|
|
263
|
+
delete this.flows[flowName];
|
|
264
|
+
this.handlers['flow-removed'].forEach((handler) => handler(flowName));
|
|
265
|
+
this.printer.printFlowRemoved(flowName);
|
|
266
|
+
}
|
|
267
|
+
onFlowUpdated(flowName) {
|
|
268
|
+
this.handlers['flow-updated'].forEach((handler) => handler(flowName));
|
|
269
|
+
}
|
|
270
|
+
isValidStep(step) {
|
|
271
|
+
const validationResult = (0, step_validator_1.validateStep)(step);
|
|
272
|
+
if (!validationResult.success) {
|
|
273
|
+
this.printer.printValidationError(step.filePath, validationResult);
|
|
274
|
+
}
|
|
275
|
+
return validationResult.success;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
exports.LockedData = LockedData;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Logger } from './logger';
|
|
2
|
+
import { StateStream } from './state-stream';
|
|
3
|
+
import { Log } from './streams/logs-stream';
|
|
4
|
+
type CreateLogger = {
|
|
5
|
+
traceId: string;
|
|
6
|
+
flows?: string[];
|
|
7
|
+
stepName: string;
|
|
8
|
+
};
|
|
9
|
+
export declare class LoggerFactory {
|
|
10
|
+
private readonly isVerbose;
|
|
11
|
+
private readonly logStream;
|
|
12
|
+
constructor(isVerbose: boolean, logStream: StateStream<Log>);
|
|
13
|
+
create({ stepName, traceId, flows }: CreateLogger): Logger;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoggerFactory = void 0;
|
|
4
|
+
const logger_1 = require("./logger");
|
|
5
|
+
class LoggerFactory {
|
|
6
|
+
constructor(isVerbose, logStream) {
|
|
7
|
+
this.isVerbose = isVerbose;
|
|
8
|
+
this.logStream = logStream;
|
|
9
|
+
}
|
|
10
|
+
create({ stepName, traceId, flows }) {
|
|
11
|
+
return new logger_1.Logger(traceId, flows, stepName, this.isVerbose, this.logStream);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.LoggerFactory = LoggerFactory;
|