@motiadev/core 0.7.3-beta.136 → 0.8.1-beta.138

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 (37) hide show
  1. package/dist/src/call-step-file.js +1 -0
  2. package/dist/src/{analytics-endpoint.js → endpoints/analytics-endpoint.js} +4 -6
  3. package/dist/src/{streams → endpoints}/api-endpoints.js +2 -1
  4. package/dist/src/{flows-config-endpoint.d.ts → endpoints/flows-config-endpoint.d.ts} +1 -1
  5. package/dist/src/{flows-config-endpoint.js → endpoints/flows-config-endpoint.js} +2 -2
  6. package/dist/src/{flows-endpoint.d.ts → endpoints/flows-endpoint.d.ts} +1 -1
  7. package/dist/src/{flows-endpoint.js → endpoints/flows-endpoint.js} +2 -2
  8. package/dist/src/endpoints/state-endpoints.d.ts +3 -0
  9. package/dist/src/endpoints/state-endpoints.js +42 -0
  10. package/dist/src/{step-endpoint.d.ts → endpoints/step-endpoint.d.ts} +1 -1
  11. package/dist/src/{step-endpoint.js → endpoints/step-endpoint.js} +1 -1
  12. package/dist/src/endpoints/trace-endpoint.d.ts +3 -0
  13. package/dist/src/endpoints/trace-endpoint.js +10 -0
  14. package/dist/src/get-step-config.d.ts +2 -2
  15. package/dist/src/get-step-config.js +6 -5
  16. package/dist/src/helper/flows-helper.js +3 -4
  17. package/dist/src/observability/index.d.ts +1 -0
  18. package/dist/src/observability/no-tracer.d.ts +1 -0
  19. package/dist/src/observability/no-tracer.js +1 -0
  20. package/dist/src/observability/tracer.d.ts +2 -0
  21. package/dist/src/observability/tracer.js +10 -1
  22. package/dist/src/process-communication/communication-config.d.ts +1 -1
  23. package/dist/src/process-communication/communication-config.js +7 -1
  24. package/dist/src/process-communication/process-manager.d.ts +1 -0
  25. package/dist/src/process-communication/process-manager.js +2 -2
  26. package/dist/src/server.d.ts +4 -3
  27. package/dist/src/server.js +11 -7
  28. package/dist/src/step-validator.js +2 -0
  29. package/dist/src/types/flows-types.d.ts +1 -0
  30. package/dist/src/types/generate-type-from-schema.js +12 -1
  31. package/dist/src/types/merge-schemas.js +16 -0
  32. package/dist/src/types/schema.types.d.ts +5 -1
  33. package/dist/src/types/schema.types.js +5 -1
  34. package/dist/src/types.d.ts +2 -0
  35. package/package.json +1 -1
  36. /package/dist/src/{analytics-endpoint.d.ts → endpoints/analytics-endpoint.d.ts} +0 -0
  37. /package/dist/src/{streams → endpoints}/api-endpoints.d.ts +0 -0
@@ -44,6 +44,7 @@ const callStepFile = (options, motia) => {
44
44
  args: [...args, runner, step.filePath, jsonData],
45
45
  logger,
46
46
  context: 'StepExecution',
47
+ projectRoot: motia.lockedData.baseDir,
47
48
  });
48
49
  (0, utils_1.trackEvent)('step_execution_started', {
49
50
  stepName: step.config.name,
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.analyticsEndpoint = void 0;
4
- const utils_1 = require("./analytics/utils");
4
+ const utils_1 = require("../analytics/utils");
5
5
  const analyticsEndpoint = (app, baseDir) => {
6
- app.get('/motia/analytics/user', (req, res) => {
6
+ app.get('/motia/analytics/user', (_req, res) => {
7
7
  const analyticsEnabled = (0, utils_1.isAnalyticsEnabled)();
8
8
  if (!analyticsEnabled) {
9
9
  res.json({
@@ -21,10 +21,8 @@ const analyticsEndpoint = (app, baseDir) => {
21
21
  analyticsEnabled: true,
22
22
  });
23
23
  });
24
- app.get('/motia/analytics/status', (req, res) => {
25
- res.json({
26
- analyticsEnabled: (0, utils_1.isAnalyticsEnabled)(),
27
- });
24
+ app.get('/motia/analytics/status', (_req, res) => {
25
+ res.json({ analyticsEnabled: (0, utils_1.isAnalyticsEnabled)() });
28
26
  });
29
27
  };
30
28
  exports.analyticsEndpoint = analyticsEndpoint;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.apiEndpoints = void 0;
4
4
  const guards_1 = require("../guards");
5
- const stream_adapter_1 = require("./adapters/stream-adapter");
5
+ const stream_adapter_1 = require("../streams/adapters/stream-adapter");
6
6
  const mapEndpoint = (step) => {
7
7
  return {
8
8
  id: step.filePath,
@@ -12,6 +12,7 @@ const mapEndpoint = (step) => {
12
12
  queryParams: step.config.queryParams,
13
13
  responseSchema: step.config.responseSchema,
14
14
  bodySchema: step.config.bodySchema,
15
+ flows: step.config.flows,
15
16
  };
16
17
  };
17
18
  class ApiEndpointsStream extends stream_adapter_1.StreamAdapter {
@@ -1,3 +1,3 @@
1
1
  import { Express } from 'express';
2
- import { LockedData } from './locked-data';
2
+ import { LockedData } from '../locked-data';
3
3
  export declare const flowsConfigEndpoint: (app: Express, baseDir: string, lockedData: LockedData) => void;
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.flowsConfigEndpoint = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const zod_1 = require("zod");
9
- const flows_config_stream_1 = require("./streams/flows-config-stream");
9
+ const flows_config_stream_1 = require("../streams/flows-config-stream");
10
10
  const flowsConfigEndpoint = (app, baseDir, lockedData) => {
11
11
  const configPath = path_1.default.join(baseDir, 'motia-workbench.json');
12
12
  const stream = new flows_config_stream_1.FlowsConfigStream(configPath);
@@ -19,7 +19,7 @@ const flowsConfigEndpoint = (app, baseDir, lockedData) => {
19
19
  baseConfig: { storageType: 'custom', factory: () => stream },
20
20
  },
21
21
  }, { disableTypeCreation: true })();
22
- app.post('/flows/:id/config', async (req, res) => {
22
+ app.post('/__motia/flows/:id/config', async (req, res) => {
23
23
  const newFlowConfig = req.body;
24
24
  try {
25
25
  await stream.set('default', newFlowConfig.id, newFlowConfig);
@@ -1,2 +1,2 @@
1
- import { LockedData } from './locked-data';
1
+ import { LockedData } from '../locked-data';
2
2
  export declare const flowsEndpoint: (lockedData: LockedData) => void;
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.flowsEndpoint = void 0;
4
4
  const zod_1 = require("zod");
5
- const flows_stream_1 = require("./streams/flows-stream");
6
- const flows_helper_1 = require("./helper/flows-helper");
5
+ const flows_stream_1 = require("../streams/flows-stream");
6
+ const flows_helper_1 = require("../helper/flows-helper");
7
7
  const flowsEndpoint = (lockedData) => {
8
8
  const flowsStream = lockedData.createStream({
9
9
  filePath: '__motia.flows',
@@ -0,0 +1,3 @@
1
+ import { Express } from 'express';
2
+ import { StateAdapter } from '../state/state-adapter';
3
+ export declare const stateEndpoints: (app: Express, stateAdapter: StateAdapter) => void;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stateEndpoints = void 0;
4
+ const stateEndpoints = (app, stateAdapter) => {
5
+ app.get('/__motia/state', async (req, res) => {
6
+ try {
7
+ const groupId = req.query.groupId;
8
+ const filter = req.query.filter ? JSON.parse(req.query.filter) : undefined;
9
+ const items = await stateAdapter.items({ groupId, filter });
10
+ res.json(items);
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ }
13
+ catch (error) {
14
+ res.status(500).json({ error: error.message });
15
+ }
16
+ });
17
+ app.post('/__motia/state', async (req, res) => {
18
+ try {
19
+ const { key, groupId, value } = req.body;
20
+ await stateAdapter.set(groupId, key, value);
21
+ res.json({ key, groupId, value });
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ }
24
+ catch (error) {
25
+ res.status(500).json({ error: error.message });
26
+ }
27
+ });
28
+ app.post('/__motia/state/delete', async (req, res) => {
29
+ try {
30
+ for (const id of req.body.ids) {
31
+ const [groupId, key] = id.split(':');
32
+ await stateAdapter.delete(groupId, key);
33
+ }
34
+ res.status(204).send();
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ }
37
+ catch (error) {
38
+ res.status(500).json({ error: error.message });
39
+ }
40
+ });
41
+ };
42
+ exports.stateEndpoints = stateEndpoints;
@@ -1,3 +1,3 @@
1
- import { LockedData } from './locked-data';
2
1
  import { Express } from 'express';
2
+ import { LockedData } from '../locked-data';
3
3
  export declare const stepEndpoint: (app: Express, lockedData: LockedData) => void;
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.stepEndpoint = void 0;
7
7
  const promises_1 = __importDefault(require("fs/promises"));
8
- const flows_helper_1 = require("./helper/flows-helper");
8
+ const flows_helper_1 = require("../helper/flows-helper");
9
9
  const getFeatures = async (filePath) => {
10
10
  const stat = await promises_1.default.stat(filePath + '-features.json').catch(() => null);
11
11
  if (!stat || stat.isDirectory()) {
@@ -0,0 +1,3 @@
1
+ import { Express } from 'express';
2
+ import { TracerFactory } from '../observability';
3
+ export declare const traceEndpoint: (app: Express, tracerFactory: TracerFactory) => void;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.traceEndpoint = void 0;
4
+ const traceEndpoint = (app, tracerFactory) => {
5
+ app.post('/__motia/trace/clear', async (req, res) => {
6
+ await tracerFactory.clear();
7
+ res.json({ message: 'Traces cleared' });
8
+ });
9
+ };
10
+ exports.traceEndpoint = traceEndpoint;
@@ -1,4 +1,4 @@
1
1
  import { StepConfig } from './types';
2
2
  import { StreamConfig } from './types-stream';
3
- export declare const getStepConfig: (file: string) => Promise<StepConfig | null>;
4
- export declare const getStreamConfig: (file: string) => Promise<StreamConfig | null>;
3
+ export declare const getStepConfig: (file: string, projectRoot?: string) => Promise<StepConfig | null>;
4
+ export declare const getStreamConfig: (file: string, projectRoot?: string) => Promise<StreamConfig | null>;
@@ -29,7 +29,7 @@ const getLanguageBasedRunner = (stepFilePath = '') => {
29
29
  }
30
30
  throw Error(`Unsupported file extension ${stepFilePath}`);
31
31
  };
32
- const getConfig = (file) => {
32
+ const getConfig = (file, projectRoot) => {
33
33
  const { runner, command, args } = getLanguageBasedRunner(file);
34
34
  return new Promise((resolve, reject) => {
35
35
  let config = null;
@@ -38,6 +38,7 @@ const getConfig = (file) => {
38
38
  args: [...args, runner, file],
39
39
  logger: logger_1.globalLogger,
40
40
  context: 'Config',
41
+ projectRoot,
41
42
  });
42
43
  processManager
43
44
  .spawn()
@@ -78,11 +79,11 @@ const getConfig = (file) => {
78
79
  });
79
80
  });
80
81
  };
81
- const getStepConfig = (file) => {
82
- return getConfig(file);
82
+ const getStepConfig = (file, projectRoot) => {
83
+ return getConfig(file, projectRoot);
83
84
  };
84
85
  exports.getStepConfig = getStepConfig;
85
- const getStreamConfig = (file) => {
86
- return getConfig(file);
86
+ const getStreamConfig = (file, projectRoot) => {
87
+ return getConfig(file, projectRoot);
87
88
  };
88
89
  exports.getStreamConfig = getStreamConfig;
@@ -46,7 +46,7 @@ const createEdgesForEmits = (sourceStep, targetSteps, emits, variant) => {
46
46
  emits.forEach((emit) => {
47
47
  const { topic, label, conditional } = processEmit(emit);
48
48
  targetSteps.forEach((targetStep) => {
49
- if (targetStep.subscribes?.includes(topic)) {
49
+ if (targetStep.subscribes?.includes(topic) || targetStep.virtualSubscribes?.includes(topic)) {
50
50
  edges.push(createEdge(sourceStep.id, targetStep.id, topic, label, variant, conditional));
51
51
  }
52
52
  });
@@ -60,6 +60,8 @@ const createBaseStepResponse = (step, id) => ({
60
60
  nodeComponentPath: getNodeComponentPath(step.filePath),
61
61
  filePath: getRelativePath(step.filePath),
62
62
  language: (0, get_step_language_1.getStepLanguage)(step.filePath),
63
+ virtualEmits: step.config.virtualEmits ?? undefined,
64
+ virtualSubscribes: step.config.virtualSubscribes ?? undefined,
63
65
  });
64
66
  const createApiStepResponse = (step, id) => {
65
67
  if (!(0, guards_1.isApiStep)(step)) {
@@ -69,7 +71,6 @@ const createApiStepResponse = (step, id) => {
69
71
  ...createBaseStepResponse(step, id),
70
72
  type: 'api',
71
73
  emits: step.config.emits,
72
- virtualEmits: step.config.virtualEmits ?? [],
73
74
  subscribes: step.config.virtualSubscribes ?? undefined,
74
75
  action: 'webhook',
75
76
  webhookUrl: `${step.config.method} ${step.config.path}`,
@@ -84,7 +85,6 @@ const createEventStepResponse = (step, id) => {
84
85
  ...createBaseStepResponse(step, id),
85
86
  type: 'event',
86
87
  emits: step.config.emits,
87
- virtualEmits: step.config.virtualEmits ?? [],
88
88
  subscribes: step.config.subscribes,
89
89
  };
90
90
  };
@@ -96,7 +96,6 @@ const createNoopStepResponse = (step, id) => {
96
96
  ...createBaseStepResponse(step, id),
97
97
  type: 'noop',
98
98
  emits: [],
99
- virtualEmits: step.config.virtualEmits,
100
99
  subscribes: step.config.virtualSubscribes,
101
100
  };
102
101
  };
@@ -3,6 +3,7 @@ import { Step } from '../types';
3
3
  import { StateOperation, StreamOperation, TraceError } from './types';
4
4
  export interface TracerFactory {
5
5
  createTracer(traceId: string, step: Step, logger: Logger): Promise<Tracer> | Tracer;
6
+ clear(): Promise<void>;
6
7
  }
7
8
  export interface Tracer {
8
9
  end(err?: TraceError): void;
@@ -4,5 +4,6 @@ export declare class NoTracer implements Tracer {
4
4
  stateOperation(): void;
5
5
  emitOperation(): void;
6
6
  streamOperation(): void;
7
+ clear(): void;
7
8
  child(): this;
8
9
  }
@@ -6,6 +6,7 @@ class NoTracer {
6
6
  stateOperation() { }
7
7
  emitOperation() { }
8
8
  streamOperation() { }
9
+ clear() { }
9
10
  child() {
10
11
  return this;
11
12
  }
@@ -9,7 +9,9 @@ export declare class BaseTracerFactory implements TracerFactory {
9
9
  private readonly traceStream;
10
10
  private readonly traceGroupStream;
11
11
  constructor(traceStream: MotiaStream<Trace>, traceGroupStream: MotiaStream<TraceGroup>);
12
+ private getAllGroups;
12
13
  private deleteGroup;
14
+ clear(): Promise<void>;
13
15
  createTracer(traceId: string, step: Step, logger: Logger): Promise<StreamTracer>;
14
16
  }
15
17
  export declare const createTracerFactory: (lockedData: LockedData) => TracerFactory;
@@ -13,6 +13,9 @@ class BaseTracerFactory {
13
13
  this.traceStream = traceStream;
14
14
  this.traceGroupStream = traceGroupStream;
15
15
  }
16
+ async getAllGroups() {
17
+ return await this.traceGroupStream.getGroup('default');
18
+ }
16
19
  async deleteGroup(group) {
17
20
  const traces = await this.traceStream.getGroup(group.id);
18
21
  for (const trace of traces) {
@@ -20,6 +23,12 @@ class BaseTracerFactory {
20
23
  }
21
24
  await this.traceGroupStream.delete('default', group.id);
22
25
  }
26
+ async clear() {
27
+ const groups = await this.getAllGroups();
28
+ for (const group of groups) {
29
+ await this.deleteGroup(group);
30
+ }
31
+ }
23
32
  async createTracer(traceId, step, logger) {
24
33
  const traceGroup = {
25
34
  id: traceId,
@@ -34,7 +43,7 @@ class BaseTracerFactory {
34
43
  status: 'running',
35
44
  startTime: Date.now(),
36
45
  };
37
- const groups = await this.traceGroupStream.getGroup('default');
46
+ const groups = await this.getAllGroups();
38
47
  if (groups.length >= MAX_TRACE_GROUPS) {
39
48
  const groupsToDelete = groups
40
49
  .sort((a, b) => a.startTime - b.startTime) // date ascending
@@ -4,4 +4,4 @@ export interface CommunicationConfig {
4
4
  type: CommunicationType;
5
5
  spawnOptions: SpawnOptions;
6
6
  }
7
- export declare function createCommunicationConfig(command: string): CommunicationConfig;
7
+ export declare function createCommunicationConfig(command: string, projectRoot?: string): CommunicationConfig;
@@ -1,12 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createCommunicationConfig = createCommunicationConfig;
4
- function createCommunicationConfig(command) {
4
+ function createCommunicationConfig(command, projectRoot) {
5
5
  const type = command === 'python' && process.platform === 'win32' ? 'rpc' : 'ipc';
6
6
  const spawnOptions = {
7
7
  stdio: type === 'rpc'
8
8
  ? ['pipe', 'pipe', 'inherit'] // RPC: capture stdout
9
9
  : ['inherit', 'inherit', 'inherit', 'ipc'], // IPC: include IPC channel
10
10
  };
11
+ if (command === 'python') {
12
+ spawnOptions.env = {
13
+ ...process.env,
14
+ PYTHONPATH: projectRoot || process.cwd(),
15
+ };
16
+ }
11
17
  return { type, spawnOptions };
12
18
  }
@@ -7,6 +7,7 @@ export interface ProcessManagerOptions {
7
7
  args: string[];
8
8
  logger: Logger;
9
9
  context?: string;
10
+ projectRoot?: string;
10
11
  }
11
12
  export declare class ProcessManager {
12
13
  private options;
@@ -10,9 +10,9 @@ class ProcessManager {
10
10
  this.options = options;
11
11
  }
12
12
  async spawn() {
13
- const { command, args, logger, context = 'Process' } = this.options;
13
+ const { command, args, logger, context = 'Process', projectRoot } = this.options;
14
14
  // Get communication configuration
15
- const commConfig = (0, communication_config_1.createCommunicationConfig)(command);
15
+ const commConfig = (0, communication_config_1.createCommunicationConfig)(command, projectRoot);
16
16
  this.communicationType = commConfig.type;
17
17
  logger.debug(`[${context}] Spawning process`, {
18
18
  command,
@@ -3,9 +3,10 @@ import http from 'http';
3
3
  import { Server as WsServer } from 'ws';
4
4
  import { CronManager } from './cron-handler';
5
5
  import { LockedData } from './locked-data';
6
- import { MotiaEventManager } from './step-handlers';
7
- import { ApiRouteConfig, EventManager, InternalStateManager, Step } from './types';
8
6
  import { Printer } from './printer';
7
+ import { StateAdapter } from './state/state-adapter';
8
+ import { MotiaEventManager } from './step-handlers';
9
+ import { ApiRouteConfig, EventManager, Step } from './types';
9
10
  export type MotiaServer = {
10
11
  app: Express;
11
12
  server: http.Server;
@@ -20,5 +21,5 @@ type MotiaServerConfig = {
20
21
  isVerbose: boolean;
21
22
  printer?: Printer;
22
23
  };
23
- export declare const createServer: (lockedData: LockedData, eventManager: EventManager, state: InternalStateManager, config: MotiaServerConfig) => MotiaServer;
24
+ export declare const createServer: (lockedData: LockedData, eventManager: EventManager, state: StateAdapter, config: MotiaServerConfig) => MotiaServer;
24
25
  export {};
@@ -8,24 +8,26 @@ const body_parser_1 = __importDefault(require("body-parser"));
8
8
  const cors_1 = __importDefault(require("cors"));
9
9
  const express_1 = __importDefault(require("express"));
10
10
  const http_1 = __importDefault(require("http"));
11
- const analytics_endpoint_1 = require("./analytics-endpoint");
12
11
  const utils_1 = require("./analytics/utils");
13
12
  const call_step_file_1 = require("./call-step-file");
14
13
  const cron_handler_1 = require("./cron-handler");
15
- const flows_config_endpoint_1 = require("./flows-config-endpoint");
16
- const flows_endpoint_1 = require("./flows-endpoint");
14
+ const analytics_endpoint_1 = require("./endpoints/analytics-endpoint");
15
+ const api_endpoints_1 = require("./endpoints/api-endpoints");
16
+ const flows_config_endpoint_1 = require("./endpoints/flows-config-endpoint");
17
+ const flows_endpoint_1 = require("./endpoints/flows-endpoint");
18
+ const state_endpoints_1 = require("./endpoints/state-endpoints");
19
+ const step_endpoint_1 = require("./endpoints/step-endpoint");
20
+ const trace_endpoint_1 = require("./endpoints/trace-endpoint");
17
21
  const generate_trace_id_1 = require("./generate-trace-id");
18
22
  const guards_1 = require("./guards");
23
+ const logger_1 = require("./logger");
19
24
  const logger_factory_1 = require("./logger-factory");
20
25
  const tracer_1 = require("./observability/tracer");
26
+ const printer_1 = require("./printer");
21
27
  const socket_server_1 = require("./socket-server");
22
28
  const step_handlers_1 = require("./step-handlers");
23
29
  const steps_1 = require("./steps");
24
- const api_endpoints_1 = require("./streams/api-endpoints");
25
30
  const logs_stream_1 = require("./streams/logs-stream");
26
- const logger_1 = require("./logger");
27
- const printer_1 = require("./printer");
28
- const step_endpoint_1 = require("./step-endpoint");
29
31
  const createServer = (lockedData, eventManager, state, config) => {
30
32
  const printer = config.printer ?? new printer_1.Printer(process.cwd());
31
33
  const app = (0, express_1.default)();
@@ -191,11 +193,13 @@ const createServer = (lockedData, eventManager, state, config) => {
191
193
  allSteps.filter(guards_1.isApiStep).forEach(addRoute);
192
194
  app.use((0, cors_1.default)());
193
195
  app.use(router);
196
+ (0, state_endpoints_1.stateEndpoints)(app, state);
194
197
  (0, api_endpoints_1.apiEndpoints)(lockedData);
195
198
  (0, flows_endpoint_1.flowsEndpoint)(lockedData);
196
199
  (0, flows_config_endpoint_1.flowsConfigEndpoint)(app, process.cwd(), lockedData);
197
200
  (0, analytics_endpoint_1.analyticsEndpoint)(app, process.cwd());
198
201
  (0, step_endpoint_1.stepEndpoint)(app, lockedData);
202
+ (0, trace_endpoint_1.traceEndpoint)(app, tracerFactory);
199
203
  server.on('error', (error) => {
200
204
  console.error('Server error:', error);
201
205
  });
@@ -56,6 +56,7 @@ const eventSchema = zod_1.z
56
56
  subscribes: zod_1.z.array(zod_1.z.string()),
57
57
  emits: emits,
58
58
  virtualEmits: emits.optional(),
59
+ virtualSubscribes: zod_1.z.array(zod_1.z.string()).optional(),
59
60
  input: zod_1.z.union([jsonSchema, zod_1.z.object({}), zod_1.z.null()]).optional(),
60
61
  flows: zod_1.z.array(zod_1.z.string()).optional(),
61
62
  includeFiles: zod_1.z.array(zod_1.z.string()).optional(),
@@ -86,6 +87,7 @@ const cronSchema = zod_1.z
86
87
  description: zod_1.z.string().optional(),
87
88
  cron: zod_1.z.string(),
88
89
  virtualEmits: emits.optional(),
90
+ virtualSubscribes: zod_1.z.array(zod_1.z.string()).optional(),
89
91
  emits: emits,
90
92
  flows: zod_1.z.array(zod_1.z.string()).optional(),
91
93
  includeFiles: zod_1.z.array(zod_1.z.string()).optional(),
@@ -23,6 +23,7 @@ export type FlowStepResponse = {
23
23
  subscribes?: string[];
24
24
  emits: Emit[];
25
25
  virtualEmits?: Emit[];
26
+ virtualSubscribes?: string[];
26
27
  action?: 'webhook';
27
28
  webhookUrl?: string;
28
29
  bodySchema?: unknown;
@@ -1,10 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateTypeFromSchema = void 0;
4
+ const schema_types_1 = require("./schema.types");
4
5
  const generateTypeFromSchema = (schema) => {
6
+ if (!schema) {
7
+ return 'unknown';
8
+ }
9
+ if ((0, schema_types_1.isAnyOf)(schema)) {
10
+ const types = schema.anyOf.map(exports.generateTypeFromSchema);
11
+ return types.join(' | ');
12
+ }
5
13
  if (schema.type === 'array') {
6
14
  const itemType = schema.items ? (0, exports.generateTypeFromSchema)(schema.items) : 'unknown';
7
- return `${itemType}[]`;
15
+ return `Array<${itemType}>`;
8
16
  }
9
17
  if (schema.type === 'object' && schema.properties) {
10
18
  const props = Object.entries(schema.properties).map(([key, prop]) => {
@@ -23,6 +31,9 @@ const generateTypeFromSchema = (schema) => {
23
31
  ? schema.enum.map((value) => `'${value}'`).join(' | ')
24
32
  : 'string';
25
33
  }
34
+ if (typeof schema === 'object' && schema !== null && 'not' in schema) {
35
+ return 'undefined';
36
+ }
26
37
  switch (schema.type) {
27
38
  case 'number':
28
39
  return 'number';
@@ -3,6 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mergeSchemas = exports.isCompatible = void 0;
4
4
  const schema_types_1 = require("./schema.types");
5
5
  const isCompatible = (schema, otherSchema) => {
6
+ if ((0, schema_types_1.isAnyOf)(schema)) {
7
+ return schema.anyOf.every((item) => (0, exports.isCompatible)(item, otherSchema));
8
+ }
9
+ else if ((0, schema_types_1.isAnyOf)(otherSchema)) {
10
+ return otherSchema.anyOf.every((item) => (0, exports.isCompatible)(schema, item));
11
+ }
6
12
  if (schema.type !== otherSchema.type) {
7
13
  return false; // different types
8
14
  }
@@ -30,6 +36,16 @@ const mergeSchemas = (schema, otherSchema) => {
30
36
  if (!(0, exports.isCompatible)(schema, otherSchema)) {
31
37
  throw new schema_types_1.JsonSchemaError('Cannot merge schemas of different types');
32
38
  }
39
+ if ((0, schema_types_1.isAnyOf)(schema)) {
40
+ return {
41
+ anyOf: schema.anyOf.map((item) => (0, exports.mergeSchemas)(item, otherSchema)),
42
+ };
43
+ }
44
+ else if ((0, schema_types_1.isAnyOf)(otherSchema)) {
45
+ return {
46
+ anyOf: otherSchema.anyOf.map((item) => (0, exports.mergeSchemas)(schema, item)),
47
+ };
48
+ }
33
49
  if (schema.type === 'object' && otherSchema.type === 'object') {
34
50
  const mergedProperties = { ...schema.properties, ...otherSchema.properties };
35
51
  const otherSchemaKeys = Object.keys(otherSchema.properties).reduce((acc, key) => ({ ...acc, [key]: true }), {});
@@ -16,11 +16,15 @@ export type JsonString = {
16
16
  description?: string;
17
17
  enum?: string[];
18
18
  };
19
+ export type JsonAnyOf = {
20
+ anyOf: JsonSchema[];
21
+ };
19
22
  export type JsonProperty = {
20
23
  type: JsonSchemaType;
21
24
  description?: string;
22
25
  };
23
- export type JsonSchema = JsonArray | JsonObject | JsonString | JsonProperty;
26
+ export type JsonSchema = JsonArray | JsonObject | JsonString | JsonProperty | JsonAnyOf;
24
27
  export declare class JsonSchemaError extends Error {
25
28
  constructor(message: string);
26
29
  }
30
+ export declare const isAnyOf: (schema: JsonSchema) => schema is JsonAnyOf;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.JsonSchemaError = void 0;
3
+ exports.isAnyOf = exports.JsonSchemaError = void 0;
4
4
  class JsonSchemaError extends Error {
5
5
  constructor(message) {
6
6
  super(message);
@@ -8,3 +8,7 @@ class JsonSchemaError extends Error {
8
8
  }
9
9
  }
10
10
  exports.JsonSchemaError = JsonSchemaError;
11
+ const isAnyOf = (schema) => {
12
+ return typeof schema === 'object' && schema !== null && 'anyOf' in schema;
13
+ };
14
+ exports.isAnyOf = isAnyOf;
@@ -36,6 +36,7 @@ export type EventConfig = {
36
36
  subscribes: string[];
37
37
  emits: Emit[];
38
38
  virtualEmits?: Emit[];
39
+ virtualSubscribes?: string[];
39
40
  input: ZodInput;
40
41
  flows?: string[];
41
42
  /**
@@ -96,6 +97,7 @@ export type CronConfig = {
96
97
  description?: string;
97
98
  cron: string;
98
99
  virtualEmits?: Emit[];
100
+ virtualSubscribes?: string[];
99
101
  emits: Emit[];
100
102
  flows?: string[];
101
103
  /**
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@motiadev/core",
3
3
  "description": "Core functionality for the Motia framework, providing the foundation for building event-driven workflows.",
4
4
  "main": "dist/index.js",
5
- "version": "0.7.3-beta.136",
5
+ "version": "0.8.1-beta.138",
6
6
  "dependencies": {
7
7
  "@amplitude/analytics-node": "^1.3.8",
8
8
  "body-parser": "^1.20.3",