@motiadev/core 0.2.2 → 0.3.0-beta.78

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 (58) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.js +6 -1
  4. package/dist/src/call-step-file.d.ts +9 -12
  5. package/dist/src/call-step-file.js +84 -28
  6. package/dist/src/cron-handler.d.ts +3 -4
  7. package/dist/src/cron-handler.js +5 -14
  8. package/dist/src/flows-config-endpoint.d.ts +2 -1
  9. package/dist/src/flows-config-endpoint.js +15 -32
  10. package/dist/src/flows-endpoint.d.ts +1 -41
  11. package/dist/src/flows-endpoint.js +13 -146
  12. package/dist/src/helper/flows-helper.d.ts +3 -0
  13. package/dist/src/helper/flows-helper.js +134 -0
  14. package/dist/src/locked-data.d.ts +2 -3
  15. package/dist/src/locked-data.js +3 -7
  16. package/dist/src/logger-factory.d.ts +4 -1
  17. package/dist/src/logger-factory.js +17 -4
  18. package/dist/src/logger.d.ts +17 -20
  19. package/dist/src/logger.js +23 -57
  20. package/dist/src/motia.d.ts +13 -0
  21. package/dist/src/motia.js +2 -0
  22. package/dist/src/node/node-runner.js +15 -4
  23. package/dist/src/observability/create-trace.d.ts +3 -0
  24. package/dist/src/observability/create-trace.js +21 -0
  25. package/dist/src/observability/index.d.ts +13 -0
  26. package/dist/src/observability/index.js +2 -0
  27. package/dist/src/observability/no-tracer.d.ts +8 -0
  28. package/dist/src/observability/no-tracer.js +13 -0
  29. package/dist/src/observability/stream-tracer.d.ts +21 -0
  30. package/dist/src/observability/stream-tracer.js +97 -0
  31. package/dist/src/observability/trace-manager.d.ts +12 -0
  32. package/dist/src/observability/trace-manager.js +23 -0
  33. package/dist/src/observability/tracer.d.ts +14 -0
  34. package/dist/src/observability/tracer.js +53 -0
  35. package/dist/src/observability/types.d.ts +74 -0
  36. package/dist/src/observability/types.js +2 -0
  37. package/dist/src/printer.d.ts +1 -1
  38. package/dist/src/printer.js +2 -2
  39. package/dist/src/process-communication/process-manager.d.ts +2 -2
  40. package/dist/src/python/python-runner.py +15 -6
  41. package/dist/src/python/type_definitions.py +0 -1
  42. package/dist/src/server.d.ts +5 -1
  43. package/dist/src/server.js +18 -22
  44. package/dist/src/state/adapters/default-state-adapter.js +1 -0
  45. package/dist/src/state/adapters/memory-state-adapter.d.ts +1 -1
  46. package/dist/src/state/adapters/memory-state-adapter.js +0 -2
  47. package/dist/src/step-handlers.d.ts +3 -3
  48. package/dist/src/step-handlers.js +10 -19
  49. package/dist/src/streams/flows-config-stream.d.ts +13 -0
  50. package/dist/src/streams/flows-config-stream.js +50 -0
  51. package/dist/src/streams/flows-stream.d.ts +6 -9
  52. package/dist/src/streams/flows-stream.js +11 -7
  53. package/dist/src/types/flows-config-types.d.ts +9 -0
  54. package/dist/src/types/flows-config-types.js +2 -0
  55. package/dist/src/types/flows-types.d.ts +37 -0
  56. package/dist/src/types/flows-types.js +2 -0
  57. package/dist/src/types.d.ts +4 -2
  58. 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 = await createServer(lockedData, eventManager, stateAdapter, config)
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 { EventManager, InternalStateManager, Step } from './types';
2
- import { LockedData } from './locked-data';
3
- import { BaseLogger } from './logger';
4
- import { Printer } from './printer';
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
- lockedData: LockedData;
12
- printer: Printer;
13
- data?: any;
14
- contextInFirstArg: boolean;
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("./analytics/utils");
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, printer, eventManager, state, traceId, data, contextInFirstArg, lockedData } = options;
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, utils_2.trackEvent)('step_execution_started', { language: command, type: step.config.type, streams: streams.length });
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
- // Register all step handlers
55
- processManager.handler('close', async () => processManager.kill());
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) => state.get(input.traceId, input.key));
58
- processManager.handler('state.set', (input) => state.set(input.traceId, input.key, input.value));
59
- processManager.handler('state.delete', (input) => state.delete(input.traceId, input.key));
60
- processManager.handler('state.clear', (input) => state.clear(input.traceId));
61
- processManager.handler(`state.getGroup`, (input) => state.getGroup(input.groupId));
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
- if (!(0, utils_1.isAllowedToEmit)(step, input.topic)) {
67
- return printer.printInvalidEmit(step, input.topic);
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
- return eventManager.emit({ ...input, traceId, flows: step.config.flows, logger }, step.filePath);
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) => stateStream.get(input.groupId, input.id));
74
- processManager.handler(`streams.${name}.set`, (input) => stateStream.set(input.groupId, input.id, input.data));
75
- processManager.handler(`streams.${name}.delete`, (input) => stateStream.delete(input.groupId, input.id));
76
- processManager.handler(`streams.${name}.getGroup`, (input) => stateStream.getGroup(input.groupId));
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
- (0, utils_2.trackEvent)('step_execution_error', { stepName: step.config.name, traceId, code });
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, utils_2.trackEvent)('step_execution_error', {
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
- (0, utils_2.trackEvent)('step_execution_error', {
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 { LoggerFactory } from './logger-factory';
2
- import { LockedData } from './locked-data';
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: (lockedData: LockedData, eventManager: EventManager, state: InternalStateManager, loggerFactory: LoggerFactory) => {
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;
@@ -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 = (lockedData, eventManager, state, loggerFactory) => {
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
- export declare const flowsConfigEndpoint: (app: Express, baseDir: string) => void;
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 flowsConfigEndpoint = (app, baseDir) => {
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 getConfig = () => {
12
- if (fs_1.default.existsSync(configPath)) {
13
- return JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
14
- }
15
- return {};
16
- };
17
- app.post('/flows/:id/config', (req, res) => {
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
- const existingConfig = getConfig();
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
- import { Emit, Step } from './types';
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.generateFlow = exports.flowsEndpoint = void 0;
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 flowsEndpoint = (lockedData, app) => {
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', (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));
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
- if (!flow) {
31
- res.status(404).send({ error: 'Flow not found' });
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
- exports.flowsEndpoint = flowsEndpoint;
39
- // Helper functions
40
- const getNodeComponentPath = (filePath) => {
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
- return edges;
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
- const createEventStepResponse = (step, id) => {
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;
@@ -0,0 +1,3 @@
1
+ import { Step } from 'src/types';
2
+ import { FlowResponse } from '../types/flows-types';
3
+ export declare const generateFlow: (flowId: string, flowSteps: Step[]) => FlowResponse;