@motiadev/core 0.2.2 → 0.3.0-beta.79
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/README.md +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -1
- package/dist/src/call-step-file.d.ts +9 -12
- package/dist/src/call-step-file.js +84 -28
- package/dist/src/cron-handler.d.ts +3 -4
- package/dist/src/cron-handler.js +5 -14
- package/dist/src/flows-config-endpoint.d.ts +2 -1
- package/dist/src/flows-config-endpoint.js +15 -32
- package/dist/src/flows-endpoint.d.ts +1 -41
- package/dist/src/flows-endpoint.js +13 -146
- package/dist/src/helper/flows-helper.d.ts +3 -0
- package/dist/src/helper/flows-helper.js +134 -0
- package/dist/src/locked-data.d.ts +2 -3
- package/dist/src/locked-data.js +3 -7
- package/dist/src/logger-factory.d.ts +4 -1
- package/dist/src/logger-factory.js +17 -4
- package/dist/src/logger.d.ts +17 -20
- package/dist/src/logger.js +23 -57
- package/dist/src/motia.d.ts +13 -0
- package/dist/src/motia.js +2 -0
- package/dist/src/node/node-runner.js +15 -4
- package/dist/src/observability/create-trace.d.ts +3 -0
- package/dist/src/observability/create-trace.js +21 -0
- package/dist/src/observability/index.d.ts +13 -0
- package/dist/src/observability/index.js +2 -0
- package/dist/src/observability/no-tracer.d.ts +8 -0
- package/dist/src/observability/no-tracer.js +13 -0
- package/dist/src/observability/stream-tracer.d.ts +21 -0
- package/dist/src/observability/stream-tracer.js +97 -0
- package/dist/src/observability/trace-manager.d.ts +12 -0
- package/dist/src/observability/trace-manager.js +23 -0
- package/dist/src/observability/tracer.d.ts +14 -0
- package/dist/src/observability/tracer.js +53 -0
- package/dist/src/observability/types.d.ts +74 -0
- package/dist/src/observability/types.js +2 -0
- package/dist/src/printer.d.ts +1 -1
- package/dist/src/printer.js +2 -2
- package/dist/src/process-communication/process-manager.d.ts +2 -2
- package/dist/src/python/python-runner.py +15 -6
- package/dist/src/python/type_definitions.py +0 -1
- package/dist/src/server.d.ts +5 -1
- package/dist/src/server.js +18 -22
- package/dist/src/state/adapters/default-state-adapter.js +1 -0
- package/dist/src/state/adapters/memory-state-adapter.d.ts +1 -1
- package/dist/src/state/adapters/memory-state-adapter.js +0 -2
- package/dist/src/step-handlers.d.ts +3 -3
- package/dist/src/step-handlers.js +10 -19
- package/dist/src/streams/flows-config-stream.d.ts +13 -0
- package/dist/src/streams/flows-config-stream.js +50 -0
- package/dist/src/streams/flows-stream.d.ts +6 -9
- package/dist/src/streams/flows-stream.js +11 -7
- package/dist/src/types/flows-config-types.d.ts +9 -0
- package/dist/src/types/flows-config-types.js +2 -0
- package/dist/src/types/flows-types.d.ts +37 -0
- package/dist/src/types/flows-types.js +2 -0
- package/dist/src/types.d.ts +4 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Create and manage an HTTP server for handling API requests:
|
|
|
32
32
|
```typescript
|
|
33
33
|
import { createServer } from '@motiadev/core'
|
|
34
34
|
|
|
35
|
-
const server =
|
|
35
|
+
const server = createServer(lockedData, eventManager, stateAdapter, config)
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
### Event Management
|
package/dist/index.d.ts
CHANGED
|
@@ -12,3 +12,6 @@ export { StateAdapter } from './src/state/state-adapter';
|
|
|
12
12
|
export { createMermaidGenerator } from './src/mermaid-generator';
|
|
13
13
|
export { StreamConfig, MotiaStream } from './src/types-stream';
|
|
14
14
|
export { getProjectIdentifier, getUserIdentifier, isAnalyticsEnabled, trackEvent } from './src/analytics/utils';
|
|
15
|
+
export { Motia } from './src/motia';
|
|
16
|
+
export { NoPrinter, Printer } from './src/printer';
|
|
17
|
+
export { NoTracer } from './src/observability/no-tracer';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.trackEvent = exports.isAnalyticsEnabled = exports.getUserIdentifier = exports.getProjectIdentifier = exports.createMermaidGenerator = exports.getStreamConfig = exports.getStepConfig = exports.LockedData = exports.isNoopStep = exports.isEventStep = exports.isCronStep = exports.isApiStep = exports.setupCronHandlers = exports.createStateAdapter = exports.Logger = exports.createEventManager = exports.createStepHandlers = exports.createServer = void 0;
|
|
17
|
+
exports.NoTracer = exports.Printer = exports.NoPrinter = exports.trackEvent = exports.isAnalyticsEnabled = exports.getUserIdentifier = exports.getProjectIdentifier = exports.createMermaidGenerator = exports.getStreamConfig = exports.getStepConfig = exports.LockedData = exports.isNoopStep = exports.isEventStep = exports.isCronStep = exports.isApiStep = exports.setupCronHandlers = exports.createStateAdapter = exports.Logger = exports.createEventManager = exports.createStepHandlers = exports.createServer = void 0;
|
|
18
18
|
__exportStar(require("./src/types"), exports);
|
|
19
19
|
var server_1 = require("./src/server");
|
|
20
20
|
Object.defineProperty(exports, "createServer", { enumerable: true, get: function () { return server_1.createServer; } });
|
|
@@ -45,3 +45,8 @@ Object.defineProperty(exports, "getProjectIdentifier", { enumerable: true, get:
|
|
|
45
45
|
Object.defineProperty(exports, "getUserIdentifier", { enumerable: true, get: function () { return utils_1.getUserIdentifier; } });
|
|
46
46
|
Object.defineProperty(exports, "isAnalyticsEnabled", { enumerable: true, get: function () { return utils_1.isAnalyticsEnabled; } });
|
|
47
47
|
Object.defineProperty(exports, "trackEvent", { enumerable: true, get: function () { return utils_1.trackEvent; } });
|
|
48
|
+
var printer_1 = require("./src/printer");
|
|
49
|
+
Object.defineProperty(exports, "NoPrinter", { enumerable: true, get: function () { return printer_1.NoPrinter; } });
|
|
50
|
+
Object.defineProperty(exports, "Printer", { enumerable: true, get: function () { return printer_1.Printer; } });
|
|
51
|
+
var no_tracer_1 = require("./src/observability/no-tracer");
|
|
52
|
+
Object.defineProperty(exports, "NoTracer", { enumerable: true, get: function () { return no_tracer_1.NoTracer; } });
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Motia } from './motia';
|
|
2
|
+
import { Step } from './types';
|
|
3
|
+
import { Logger } from './logger';
|
|
4
|
+
import { Tracer } from './observability';
|
|
5
5
|
type CallStepFileOptions = {
|
|
6
6
|
step: Step;
|
|
7
|
-
logger: BaseLogger;
|
|
8
|
-
eventManager: EventManager;
|
|
9
|
-
state: InternalStateManager;
|
|
10
7
|
traceId: string;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
data?: unknown;
|
|
9
|
+
contextInFirstArg?: boolean;
|
|
10
|
+
logger: Logger;
|
|
11
|
+
tracer: Tracer;
|
|
15
12
|
};
|
|
16
|
-
export declare const callStepFile: <TData>(options: CallStepFileOptions) => Promise<TData | undefined>;
|
|
13
|
+
export declare const callStepFile: <TData>(options: CallStepFileOptions, motia: Motia) => Promise<TData | undefined>;
|
|
17
14
|
export {};
|
|
@@ -5,9 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.callStepFile = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const utils_1 = require("./utils");
|
|
8
|
+
const utils_1 = require("./analytics/utils");
|
|
9
9
|
const process_manager_1 = require("./process-communication/process-manager");
|
|
10
|
-
const utils_2 = require("./
|
|
10
|
+
const utils_2 = require("./utils");
|
|
11
11
|
const getLanguageBasedRunner = (stepFilePath = '') => {
|
|
12
12
|
const isPython = stepFilePath.endsWith('.py');
|
|
13
13
|
const isRuby = stepFilePath.endsWith('.rb');
|
|
@@ -30,50 +30,96 @@ const getLanguageBasedRunner = (stepFilePath = '') => {
|
|
|
30
30
|
}
|
|
31
31
|
throw Error(`Unsupported file extension ${stepFilePath}`);
|
|
32
32
|
};
|
|
33
|
-
const callStepFile = (options) => {
|
|
34
|
-
const { step,
|
|
35
|
-
const logger = options.logger.child({ step: step.config.name });
|
|
33
|
+
const callStepFile = (options, motia) => {
|
|
34
|
+
const { step, traceId, data, tracer, logger, contextInFirstArg = false } = options;
|
|
36
35
|
const flows = step.config.flows;
|
|
37
36
|
return new Promise((resolve, reject) => {
|
|
38
|
-
const streamConfig = lockedData.getStreams();
|
|
37
|
+
const streamConfig = motia.lockedData.getStreams();
|
|
39
38
|
const streams = Object.keys(streamConfig).map((name) => ({ name }));
|
|
40
39
|
const jsonData = JSON.stringify({ data, flows, traceId, contextInFirstArg, streams });
|
|
41
40
|
const { runner, command, args } = getLanguageBasedRunner(step.filePath);
|
|
42
41
|
let result;
|
|
43
|
-
// Create process manager with unified communication handling
|
|
44
42
|
const processManager = new process_manager_1.ProcessManager({
|
|
45
43
|
command,
|
|
46
44
|
args: [...args, runner, step.filePath, jsonData],
|
|
47
45
|
logger,
|
|
48
46
|
context: 'StepExecution',
|
|
49
47
|
});
|
|
50
|
-
(0,
|
|
48
|
+
(0, utils_1.trackEvent)('step_execution_started', { language: command, type: step.config.type, streams: streams.length });
|
|
51
49
|
processManager
|
|
52
50
|
.spawn()
|
|
53
51
|
.then(() => {
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
processManager.handler('close', async (err) => {
|
|
53
|
+
processManager.kill();
|
|
54
|
+
if (err) {
|
|
55
|
+
(0, utils_1.trackEvent)('step_execution_error', {
|
|
56
|
+
stepName: step.config.name,
|
|
57
|
+
traceId,
|
|
58
|
+
message: err.message,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (err) {
|
|
62
|
+
tracer.end({
|
|
63
|
+
message: err.message,
|
|
64
|
+
code: err.code,
|
|
65
|
+
stack: err.stack?.replace(new RegExp(`${motia.lockedData.baseDir}/`), ''),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
tracer.end();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
56
72
|
processManager.handler('log', async (input) => logger.log(input));
|
|
57
|
-
processManager.handler('state.get', (input) =>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
processManager.handler(
|
|
73
|
+
processManager.handler('state.get', async (input) => {
|
|
74
|
+
tracer.stateOperation('get', input);
|
|
75
|
+
return motia.state.get(input.traceId, input.key);
|
|
76
|
+
});
|
|
77
|
+
processManager.handler('state.set', async (input) => {
|
|
78
|
+
tracer.stateOperation('set', { traceId: input.traceId, key: input.key, value: true });
|
|
79
|
+
return motia.state.set(input.traceId, input.key, input.value);
|
|
80
|
+
});
|
|
81
|
+
processManager.handler('state.delete', async (input) => {
|
|
82
|
+
tracer.stateOperation('delete', input);
|
|
83
|
+
return motia.state.delete(input.traceId, input.key);
|
|
84
|
+
});
|
|
85
|
+
processManager.handler('state.clear', async (input) => {
|
|
86
|
+
tracer.stateOperation('clear', input);
|
|
87
|
+
return motia.state.clear(input.traceId);
|
|
88
|
+
});
|
|
89
|
+
processManager.handler(`state.getGroup`, (input) => {
|
|
90
|
+
tracer.stateOperation('getGroup', input);
|
|
91
|
+
return motia.state.getGroup(input.groupId);
|
|
92
|
+
});
|
|
62
93
|
processManager.handler('result', async (input) => {
|
|
63
94
|
result = input;
|
|
64
95
|
});
|
|
65
96
|
processManager.handler('emit', async (input) => {
|
|
66
|
-
|
|
67
|
-
|
|
97
|
+
const flows = step.config.flows;
|
|
98
|
+
if (!(0, utils_2.isAllowedToEmit)(step, input.topic)) {
|
|
99
|
+
tracer.emitOperation(input.topic, input.data, false);
|
|
100
|
+
return motia.printer.printInvalidEmit(step, input.topic);
|
|
68
101
|
}
|
|
69
|
-
|
|
102
|
+
tracer.emitOperation(input.topic, input.data, true);
|
|
103
|
+
return motia.eventManager.emit({ ...input, traceId, flows, logger, tracer }, step.filePath);
|
|
70
104
|
});
|
|
71
105
|
Object.entries(streamConfig).forEach(([name, streamFactory]) => {
|
|
72
106
|
const stateStream = streamFactory();
|
|
73
|
-
processManager.handler(`streams.${name}.get`, (input) =>
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
107
|
+
processManager.handler(`streams.${name}.get`, async (input) => {
|
|
108
|
+
tracer.streamOperation(name, 'get', input);
|
|
109
|
+
return stateStream.get(input.groupId, input.id);
|
|
110
|
+
});
|
|
111
|
+
processManager.handler(`streams.${name}.set`, async (input) => {
|
|
112
|
+
tracer.streamOperation(name, 'set', { groupId: input.groupId, id: input.id, data: true });
|
|
113
|
+
return stateStream.set(input.groupId, input.id, input.data);
|
|
114
|
+
});
|
|
115
|
+
processManager.handler(`streams.${name}.delete`, async (input) => {
|
|
116
|
+
tracer.streamOperation(name, 'delete', input);
|
|
117
|
+
return stateStream.delete(input.groupId, input.id);
|
|
118
|
+
});
|
|
119
|
+
processManager.handler(`streams.${name}.getGroup`, async (input) => {
|
|
120
|
+
tracer.streamOperation(name, 'getGroup', input);
|
|
121
|
+
return stateStream.getGroup(input.groupId);
|
|
122
|
+
});
|
|
77
123
|
});
|
|
78
124
|
processManager.onStdout((data) => {
|
|
79
125
|
try {
|
|
@@ -84,24 +130,29 @@ const callStepFile = (options) => {
|
|
|
84
130
|
logger.info(Buffer.from(data).toString());
|
|
85
131
|
}
|
|
86
132
|
});
|
|
87
|
-
// Handle stderr
|
|
88
133
|
processManager.onStderr((data) => logger.error(Buffer.from(data).toString()));
|
|
89
|
-
// Handle process close
|
|
90
134
|
processManager.onProcessClose((code) => {
|
|
91
135
|
processManager.close();
|
|
92
136
|
if (code !== 0 && code !== null) {
|
|
93
|
-
|
|
137
|
+
const error = { message: `Process exited with code ${code}`, code };
|
|
138
|
+
tracer.end(error);
|
|
139
|
+
(0, utils_1.trackEvent)('step_execution_error', { stepName: step.config.name, traceId, code });
|
|
94
140
|
reject(`Process exited with code ${code}`);
|
|
95
141
|
}
|
|
96
142
|
else {
|
|
143
|
+
tracer.end();
|
|
97
144
|
resolve(result);
|
|
98
145
|
}
|
|
99
146
|
});
|
|
100
|
-
// Handle process errors
|
|
101
147
|
processManager.onProcessError((error) => {
|
|
102
148
|
processManager.close();
|
|
149
|
+
tracer.end({
|
|
150
|
+
message: error.message,
|
|
151
|
+
code: error.code,
|
|
152
|
+
stack: error.stack,
|
|
153
|
+
});
|
|
103
154
|
if (error.code === 'ENOENT') {
|
|
104
|
-
(0,
|
|
155
|
+
(0, utils_1.trackEvent)('step_execution_error', {
|
|
105
156
|
stepName: step.config.name,
|
|
106
157
|
traceId,
|
|
107
158
|
code: error.code,
|
|
@@ -115,7 +166,12 @@ const callStepFile = (options) => {
|
|
|
115
166
|
});
|
|
116
167
|
})
|
|
117
168
|
.catch((error) => {
|
|
118
|
-
|
|
169
|
+
tracer.end({
|
|
170
|
+
message: error.message,
|
|
171
|
+
code: error.code,
|
|
172
|
+
stack: error.stack,
|
|
173
|
+
});
|
|
174
|
+
(0, utils_1.trackEvent)('step_execution_error', {
|
|
119
175
|
stepName: step.config.name,
|
|
120
176
|
traceId,
|
|
121
177
|
code: error.code,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { CronConfig, EventManager, InternalStateManager, Step } from './types';
|
|
1
|
+
import { Motia } from './motia';
|
|
2
|
+
import { CronConfig, Step } from './types';
|
|
4
3
|
export type CronManager = {
|
|
5
4
|
createCronJob: (step: Step<CronConfig>) => void;
|
|
6
5
|
removeCronJob: (step: Step<CronConfig>) => void;
|
|
7
6
|
close: () => void;
|
|
8
7
|
};
|
|
9
|
-
export declare const setupCronHandlers: (
|
|
8
|
+
export declare const setupCronHandlers: (motia: Motia) => {
|
|
10
9
|
createCronJob: (step: Step<CronConfig>) => void;
|
|
11
10
|
removeCronJob: (step: Step<CronConfig>) => void;
|
|
12
11
|
close: () => void;
|
package/dist/src/cron-handler.js
CHANGED
|
@@ -38,9 +38,8 @@ const cron = __importStar(require("node-cron"));
|
|
|
38
38
|
const call_step_file_1 = require("./call-step-file");
|
|
39
39
|
const generate_trace_id_1 = require("./generate-trace-id");
|
|
40
40
|
const logger_1 = require("./logger");
|
|
41
|
-
const setupCronHandlers = (
|
|
41
|
+
const setupCronHandlers = (motia) => {
|
|
42
42
|
const cronJobs = new Map();
|
|
43
|
-
const printer = lockedData.printer;
|
|
44
43
|
const createCronJob = (step) => {
|
|
45
44
|
const { config, filePath } = step;
|
|
46
45
|
const { cron: cronExpression, name: stepName, flows } = config;
|
|
@@ -58,18 +57,10 @@ const setupCronHandlers = (lockedData, eventManager, state, loggerFactory) => {
|
|
|
58
57
|
});
|
|
59
58
|
const task = cron.schedule(cronExpression, async () => {
|
|
60
59
|
const traceId = (0, generate_trace_id_1.generateTraceId)();
|
|
61
|
-
const logger = loggerFactory.create({ traceId, flows, stepName });
|
|
60
|
+
const logger = motia.loggerFactory.create({ traceId, flows, stepName });
|
|
61
|
+
const tracer = motia.tracerFactory.createTracer(traceId, step, logger);
|
|
62
62
|
try {
|
|
63
|
-
await (0, call_step_file_1.callStepFile)({
|
|
64
|
-
contextInFirstArg: true,
|
|
65
|
-
lockedData,
|
|
66
|
-
step,
|
|
67
|
-
eventManager,
|
|
68
|
-
printer,
|
|
69
|
-
state,
|
|
70
|
-
traceId,
|
|
71
|
-
logger,
|
|
72
|
-
});
|
|
63
|
+
await (0, call_step_file_1.callStepFile)({ contextInFirstArg: true, step, traceId, tracer, logger }, motia);
|
|
73
64
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
74
65
|
}
|
|
75
66
|
catch (error) {
|
|
@@ -92,7 +83,7 @@ const setupCronHandlers = (lockedData, eventManager, state, loggerFactory) => {
|
|
|
92
83
|
cronJobs.forEach((task) => task.stop());
|
|
93
84
|
cronJobs.clear();
|
|
94
85
|
};
|
|
95
|
-
lockedData.cronSteps().forEach(createCronJob);
|
|
86
|
+
motia.lockedData.cronSteps().forEach(createCronJob);
|
|
96
87
|
return { createCronJob, removeCronJob, close };
|
|
97
88
|
};
|
|
98
89
|
exports.setupCronHandlers = setupCronHandlers;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { Express } from 'express';
|
|
2
|
-
|
|
2
|
+
import { LockedData } from './locked-data';
|
|
3
|
+
export declare const flowsConfigEndpoint: (app: Express, baseDir: string, lockedData: LockedData) => void;
|
|
@@ -4,30 +4,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.flowsConfigEndpoint = void 0;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
7
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const
|
|
8
|
+
const zod_1 = require("zod");
|
|
9
|
+
const flows_config_stream_1 = require("./streams/flows-config-stream");
|
|
10
|
+
const flowsConfigEndpoint = (app, baseDir, lockedData) => {
|
|
10
11
|
const configPath = path_1.default.join(baseDir, 'motia-workbench.json');
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
const stream = new flows_config_stream_1.FlowsConfigStream(configPath);
|
|
13
|
+
lockedData.createStream({
|
|
14
|
+
filePath: '__motia.flowsConfig',
|
|
15
|
+
hidden: true,
|
|
16
|
+
config: {
|
|
17
|
+
name: '__motia.flowsConfig',
|
|
18
|
+
schema: zod_1.z.object({ name: zod_1.z.string(), steps: zod_1.z.any(), edges: zod_1.z.any() }),
|
|
19
|
+
baseConfig: { storageType: 'custom', factory: () => stream },
|
|
20
|
+
},
|
|
21
|
+
}, { disableTypeCreation: true })();
|
|
22
|
+
app.post('/flows/:id/config', async (req, res) => {
|
|
18
23
|
const newFlowConfig = req.body;
|
|
19
24
|
try {
|
|
20
|
-
|
|
21
|
-
const updatedConfig = {
|
|
22
|
-
...existingConfig,
|
|
23
|
-
};
|
|
24
|
-
Object.entries(newFlowConfig).forEach(([flowName, filePathPositions]) => {
|
|
25
|
-
updatedConfig[flowName] = {
|
|
26
|
-
...(updatedConfig[flowName] || {}),
|
|
27
|
-
...filePathPositions,
|
|
28
|
-
};
|
|
29
|
-
});
|
|
30
|
-
fs_1.default.writeFileSync(configPath, JSON.stringify(updatedConfig, null, 2));
|
|
25
|
+
await stream.set('default', newFlowConfig.id, newFlowConfig);
|
|
31
26
|
res.status(200).send({ message: 'Flow config saved successfully' });
|
|
32
27
|
}
|
|
33
28
|
catch (error) {
|
|
@@ -35,17 +30,5 @@ const flowsConfigEndpoint = (app, baseDir) => {
|
|
|
35
30
|
res.status(500).json({ error: 'Failed to save flow config' });
|
|
36
31
|
}
|
|
37
32
|
});
|
|
38
|
-
app.get('/flows/:id/config', (req, res) => {
|
|
39
|
-
const { id } = req.params;
|
|
40
|
-
try {
|
|
41
|
-
const allFlowsConfig = getConfig();
|
|
42
|
-
const flowConfig = allFlowsConfig[id] || {};
|
|
43
|
-
res.status(200).send(flowConfig);
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
console.error('Error reading flow config:', error.message);
|
|
47
|
-
res.status(400).send({ error: 'Failed to read flow config' });
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
33
|
};
|
|
51
34
|
exports.flowsConfigEndpoint = flowsConfigEndpoint;
|
|
@@ -1,42 +1,2 @@
|
|
|
1
|
-
import { Express } from 'express';
|
|
2
1
|
import { LockedData } from './locked-data';
|
|
3
|
-
|
|
4
|
-
type FlowListResponse = {
|
|
5
|
-
id: string;
|
|
6
|
-
name: string;
|
|
7
|
-
};
|
|
8
|
-
export type EdgeData = {
|
|
9
|
-
variant: 'event' | 'virtual';
|
|
10
|
-
topic: string;
|
|
11
|
-
label?: string;
|
|
12
|
-
labelVariant?: 'default' | 'conditional';
|
|
13
|
-
};
|
|
14
|
-
type FlowEdge = {
|
|
15
|
-
id: string;
|
|
16
|
-
source: string;
|
|
17
|
-
target: string;
|
|
18
|
-
data: EdgeData;
|
|
19
|
-
};
|
|
20
|
-
type FlowStepResponse = {
|
|
21
|
-
id: string;
|
|
22
|
-
name: string;
|
|
23
|
-
type: 'event' | 'api' | 'noop' | 'cron';
|
|
24
|
-
description?: string;
|
|
25
|
-
subscribes?: string[];
|
|
26
|
-
emits: Emit[];
|
|
27
|
-
virtualEmits?: Emit[];
|
|
28
|
-
action?: 'webhook';
|
|
29
|
-
webhookUrl?: string;
|
|
30
|
-
bodySchema?: unknown;
|
|
31
|
-
language?: string;
|
|
32
|
-
nodeComponentPath?: string;
|
|
33
|
-
filePath?: string;
|
|
34
|
-
cronExpression?: string;
|
|
35
|
-
};
|
|
36
|
-
type FlowResponse = FlowListResponse & {
|
|
37
|
-
steps: FlowStepResponse[];
|
|
38
|
-
edges: FlowEdge[];
|
|
39
|
-
};
|
|
40
|
-
export declare const flowsEndpoint: (lockedData: LockedData, app: Express) => void;
|
|
41
|
-
export declare const generateFlow: (flowId: string, flowSteps: Step[]) => FlowResponse;
|
|
42
|
-
export {};
|
|
2
|
+
export declare const flowsEndpoint: (lockedData: LockedData) => void;
|
|
@@ -1,162 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
const crypto_1 = require("crypto");
|
|
8
|
-
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
3
|
+
exports.flowsEndpoint = void 0;
|
|
10
4
|
const zod_1 = require("zod");
|
|
11
|
-
const get_step_language_1 = require("./get-step-language");
|
|
12
|
-
const guards_1 = require("./guards");
|
|
13
5
|
const flows_stream_1 = require("./streams/flows-stream");
|
|
14
|
-
const
|
|
6
|
+
const flows_helper_1 = require("./helper/flows-helper");
|
|
7
|
+
const flowsEndpoint = (lockedData) => {
|
|
15
8
|
const flowsStream = lockedData.createStream({
|
|
16
9
|
filePath: '__motia.flows',
|
|
17
10
|
hidden: true,
|
|
18
11
|
config: {
|
|
19
12
|
name: '__motia.flows',
|
|
20
|
-
schema: zod_1.z.object({ id: zod_1.z.string(), name: zod_1.z.string() }),
|
|
13
|
+
schema: zod_1.z.object({ id: zod_1.z.string(), name: zod_1.z.string(), steps: zod_1.z.any(), edges: zod_1.z.any() }),
|
|
21
14
|
baseConfig: { storageType: 'custom', factory: () => new flows_stream_1.FlowsStream(lockedData) },
|
|
22
15
|
},
|
|
23
16
|
}, { disableTypeCreation: true })();
|
|
24
|
-
lockedData.on('flow-created', (
|
|
25
|
-
lockedData.on('flow-updated', (flow) => flowsStream.set('default', flow, { id: flow, name: flow }));
|
|
26
|
-
lockedData.on('flow-removed', (flow) => flowsStream.delete('default', flow));
|
|
27
|
-
app.get('/flows/:id', async (req, res) => {
|
|
28
|
-
const flowId = req.params.id;
|
|
17
|
+
lockedData.on('flow-created', (flowId) => {
|
|
29
18
|
const flow = lockedData.flows[flowId];
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
res.status(200).send((0, exports.generateFlow)(flowId, flow.steps));
|
|
35
|
-
}
|
|
19
|
+
const response = (0, flows_helper_1.generateFlow)(flowId, flow.steps);
|
|
20
|
+
flowsStream.set('default', flowId, response);
|
|
36
21
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const filePathWithoutExtension = filePath.replace(/\.[^/.]+$/, '');
|
|
42
|
-
const tsxPath = filePathWithoutExtension + '.tsx';
|
|
43
|
-
return fs_1.default.existsSync(tsxPath) ? tsxPath : undefined;
|
|
44
|
-
};
|
|
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) => ({
|
|
50
|
-
id: `${sourceId}-${targetId}`,
|
|
51
|
-
source: sourceId,
|
|
52
|
-
target: targetId,
|
|
53
|
-
data: {
|
|
54
|
-
variant,
|
|
55
|
-
label,
|
|
56
|
-
topic,
|
|
57
|
-
labelVariant: conditional ? 'conditional' : 'default',
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
const processEmit = (emit) => {
|
|
61
|
-
const isString = typeof emit === 'string';
|
|
62
|
-
return {
|
|
63
|
-
topic: isString ? emit : emit.topic,
|
|
64
|
-
label: isString ? undefined : emit.label,
|
|
65
|
-
conditional: isString ? undefined : emit.conditional,
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
const createEdgesForEmits = (sourceStep, targetSteps, emits, variant) => {
|
|
69
|
-
const edges = [];
|
|
70
|
-
emits.forEach((emit) => {
|
|
71
|
-
const { topic, label, conditional } = processEmit(emit);
|
|
72
|
-
targetSteps.forEach((targetStep) => {
|
|
73
|
-
if (targetStep.subscribes?.includes(topic)) {
|
|
74
|
-
edges.push(createEdge(sourceStep.id, targetStep.id, topic, label, variant, conditional));
|
|
75
|
-
}
|
|
76
|
-
});
|
|
22
|
+
lockedData.on('flow-updated', (flowId) => {
|
|
23
|
+
const flow = lockedData.flows[flowId];
|
|
24
|
+
const response = (0, flows_helper_1.generateFlow)(flowId, flow.steps);
|
|
25
|
+
flowsStream.set('default', flowId, response);
|
|
77
26
|
});
|
|
78
|
-
|
|
79
|
-
};
|
|
80
|
-
const createBaseStepResponse = (step, id) => ({
|
|
81
|
-
id,
|
|
82
|
-
name: step.config.name,
|
|
83
|
-
description: step.config.description,
|
|
84
|
-
nodeComponentPath: getNodeComponentPath(step.filePath),
|
|
85
|
-
filePath: getRelativePath(step.filePath),
|
|
86
|
-
language: (0, get_step_language_1.getStepLanguage)(step.filePath),
|
|
87
|
-
});
|
|
88
|
-
const createApiStepResponse = (step, id) => {
|
|
89
|
-
if (!(0, guards_1.isApiStep)(step)) {
|
|
90
|
-
throw new Error('Attempted to create API step response with non-API step');
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
...createBaseStepResponse(step, id),
|
|
94
|
-
type: 'api',
|
|
95
|
-
emits: step.config.emits,
|
|
96
|
-
virtualEmits: step.config.virtualEmits ?? [],
|
|
97
|
-
subscribes: step.config.virtualSubscribes ?? undefined,
|
|
98
|
-
action: 'webhook',
|
|
99
|
-
webhookUrl: `${step.config.method} ${step.config.path}`,
|
|
100
|
-
bodySchema: step.config.bodySchema ?? undefined,
|
|
101
|
-
};
|
|
27
|
+
lockedData.on('flow-removed', (flowId) => flowsStream.delete('default', flowId));
|
|
102
28
|
};
|
|
103
|
-
|
|
104
|
-
if (!(0, guards_1.isEventStep)(step)) {
|
|
105
|
-
throw new Error('Attempted to create Event step response with non-Event step');
|
|
106
|
-
}
|
|
107
|
-
return {
|
|
108
|
-
...createBaseStepResponse(step, id),
|
|
109
|
-
type: 'event',
|
|
110
|
-
emits: step.config.emits,
|
|
111
|
-
virtualEmits: step.config.virtualEmits ?? [],
|
|
112
|
-
subscribes: step.config.subscribes,
|
|
113
|
-
};
|
|
114
|
-
};
|
|
115
|
-
const createNoopStepResponse = (step, id) => {
|
|
116
|
-
if (!(0, guards_1.isNoopStep)(step)) {
|
|
117
|
-
throw new Error('Attempted to create Noop step response with non-Noop step');
|
|
118
|
-
}
|
|
119
|
-
return {
|
|
120
|
-
...createBaseStepResponse(step, id),
|
|
121
|
-
type: 'noop',
|
|
122
|
-
emits: [],
|
|
123
|
-
virtualEmits: step.config.virtualEmits,
|
|
124
|
-
subscribes: step.config.virtualSubscribes,
|
|
125
|
-
};
|
|
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
|
-
};
|
|
138
|
-
const createStepResponse = (step) => {
|
|
139
|
-
const id = (0, crypto_1.randomUUID)();
|
|
140
|
-
if ((0, guards_1.isApiStep)(step))
|
|
141
|
-
return createApiStepResponse(step, id);
|
|
142
|
-
if ((0, guards_1.isEventStep)(step))
|
|
143
|
-
return createEventStepResponse(step, id);
|
|
144
|
-
if ((0, guards_1.isNoopStep)(step))
|
|
145
|
-
return createNoopStepResponse(step, id);
|
|
146
|
-
if ((0, guards_1.isCronStep)(step))
|
|
147
|
-
return createCronStepResponse(step, id);
|
|
148
|
-
throw new Error(`Unknown step type for step: ${step.config.name}`);
|
|
149
|
-
};
|
|
150
|
-
const createEdgesForStep = (sourceStep, allSteps) => {
|
|
151
|
-
const regularEdges = createEdgesForEmits(sourceStep, allSteps, sourceStep.emits, 'event');
|
|
152
|
-
const virtualEdges = sourceStep.virtualEmits
|
|
153
|
-
? createEdgesForEmits(sourceStep, allSteps, sourceStep.virtualEmits, 'virtual')
|
|
154
|
-
: [];
|
|
155
|
-
return [...regularEdges, ...virtualEdges];
|
|
156
|
-
};
|
|
157
|
-
const generateFlow = (flowId, flowSteps) => {
|
|
158
|
-
const steps = flowSteps.map(createStepResponse);
|
|
159
|
-
const edges = steps.flatMap((step) => createEdgesForStep(step, steps));
|
|
160
|
-
return { id: flowId, name: flowId, steps, edges };
|
|
161
|
-
};
|
|
162
|
-
exports.generateFlow = generateFlow;
|
|
29
|
+
exports.flowsEndpoint = flowsEndpoint;
|