@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.
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
@@ -0,0 +1,134 @@
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.generateFlow = void 0;
7
+ const guards_1 = require("../guards");
8
+ const crypto_1 = require("crypto");
9
+ const get_step_language_1 = require("../get-step-language");
10
+ const path_1 = __importDefault(require("path"));
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const getNodeComponentPath = (filePath) => {
13
+ const filePathWithoutExtension = filePath.replace(/\.[^/.]+$/, '');
14
+ const tsxPath = filePathWithoutExtension + '.tsx';
15
+ return fs_1.default.existsSync(tsxPath) ? tsxPath : undefined;
16
+ };
17
+ const getRelativePath = (filePath) => {
18
+ const baseDir = process.cwd();
19
+ return path_1.default.relative(baseDir, filePath);
20
+ };
21
+ const createEdge = (sourceId, targetId, topic, label, variant, conditional) => ({
22
+ id: `${sourceId}-${targetId}`,
23
+ source: sourceId,
24
+ target: targetId,
25
+ data: {
26
+ variant,
27
+ label,
28
+ topic,
29
+ labelVariant: conditional ? 'conditional' : 'default',
30
+ },
31
+ });
32
+ const processEmit = (emit) => {
33
+ const isString = typeof emit === 'string';
34
+ return {
35
+ topic: isString ? emit : emit.topic,
36
+ label: isString ? undefined : emit.label,
37
+ conditional: isString ? undefined : emit.conditional,
38
+ };
39
+ };
40
+ const createEdgesForEmits = (sourceStep, targetSteps, emits, variant) => {
41
+ const edges = [];
42
+ emits.forEach((emit) => {
43
+ const { topic, label, conditional } = processEmit(emit);
44
+ targetSteps.forEach((targetStep) => {
45
+ if (targetStep.subscribes?.includes(topic)) {
46
+ edges.push(createEdge(sourceStep.id, targetStep.id, topic, label, variant, conditional));
47
+ }
48
+ });
49
+ });
50
+ return edges;
51
+ };
52
+ const createBaseStepResponse = (step, id) => ({
53
+ id,
54
+ name: step.config.name,
55
+ description: step.config.description,
56
+ nodeComponentPath: getNodeComponentPath(step.filePath),
57
+ filePath: getRelativePath(step.filePath),
58
+ language: (0, get_step_language_1.getStepLanguage)(step.filePath),
59
+ });
60
+ const createApiStepResponse = (step, id) => {
61
+ if (!(0, guards_1.isApiStep)(step)) {
62
+ throw new Error('Attempted to create API step response with non-API step');
63
+ }
64
+ return {
65
+ ...createBaseStepResponse(step, id),
66
+ type: 'api',
67
+ emits: step.config.emits,
68
+ virtualEmits: step.config.virtualEmits ?? [],
69
+ subscribes: step.config.virtualSubscribes ?? undefined,
70
+ action: 'webhook',
71
+ webhookUrl: `${step.config.method} ${step.config.path}`,
72
+ bodySchema: step.config.bodySchema ?? undefined,
73
+ };
74
+ };
75
+ const createEventStepResponse = (step, id) => {
76
+ if (!(0, guards_1.isEventStep)(step)) {
77
+ throw new Error('Attempted to create Event step response with non-Event step');
78
+ }
79
+ return {
80
+ ...createBaseStepResponse(step, id),
81
+ type: 'event',
82
+ emits: step.config.emits,
83
+ virtualEmits: step.config.virtualEmits ?? [],
84
+ subscribes: step.config.subscribes,
85
+ };
86
+ };
87
+ const createNoopStepResponse = (step, id) => {
88
+ if (!(0, guards_1.isNoopStep)(step)) {
89
+ throw new Error('Attempted to create Noop step response with non-Noop step');
90
+ }
91
+ return {
92
+ ...createBaseStepResponse(step, id),
93
+ type: 'noop',
94
+ emits: [],
95
+ virtualEmits: step.config.virtualEmits,
96
+ subscribes: step.config.virtualSubscribes,
97
+ };
98
+ };
99
+ const createCronStepResponse = (step, id) => {
100
+ if (!(0, guards_1.isCronStep)(step)) {
101
+ throw new Error('Attempted to create Cron step response with non-Cron step');
102
+ }
103
+ return {
104
+ ...createBaseStepResponse(step, id),
105
+ type: 'cron',
106
+ emits: step.config.emits,
107
+ cronExpression: step.config.cron,
108
+ };
109
+ };
110
+ const createStepResponse = (step) => {
111
+ const id = (0, crypto_1.randomUUID)();
112
+ if ((0, guards_1.isApiStep)(step))
113
+ return createApiStepResponse(step, id);
114
+ if ((0, guards_1.isEventStep)(step))
115
+ return createEventStepResponse(step, id);
116
+ if ((0, guards_1.isNoopStep)(step))
117
+ return createNoopStepResponse(step, id);
118
+ if ((0, guards_1.isCronStep)(step))
119
+ return createCronStepResponse(step, id);
120
+ throw new Error(`Unknown step type for step: ${step.config.name}`);
121
+ };
122
+ const createEdgesForStep = (sourceStep, allSteps) => {
123
+ const regularEdges = createEdgesForEmits(sourceStep, allSteps, sourceStep.emits, 'event');
124
+ const virtualEdges = sourceStep.virtualEmits
125
+ ? createEdgesForEmits(sourceStep, allSteps, sourceStep.virtualEmits, 'virtual')
126
+ : [];
127
+ return [...regularEdges, ...virtualEdges];
128
+ };
129
+ const generateFlow = (flowId, flowSteps) => {
130
+ const steps = flowSteps.map(createStepResponse);
131
+ const edges = steps.flatMap((step) => createEdgesForStep(step, steps));
132
+ return { id: flowId, name: flowId, steps, edges };
133
+ };
134
+ exports.generateFlow = generateFlow;
@@ -9,18 +9,17 @@ type StreamWrapper<TData> = (streamName: string, factory: StreamFactory<TData>)
9
9
  export declare class LockedData {
10
10
  readonly baseDir: string;
11
11
  private readonly streamAdapter;
12
+ private readonly printer;
12
13
  flows: Record<string, Flow>;
13
14
  activeSteps: Step[];
14
15
  devSteps: Step[];
15
- printer: Printer;
16
16
  private stepsMap;
17
17
  private handlers;
18
18
  private stepHandlers;
19
19
  private streamHandlers;
20
20
  private streams;
21
21
  private streamWrapper?;
22
- constructor(baseDir: string, streamAdapter?: 'file' | 'memory');
23
- disablePrinter(): void;
22
+ constructor(baseDir: string, streamAdapter: "file" | "memory" | undefined, printer: Printer);
24
23
  applyStreamWrapper<TData>(streamWrapper: StreamWrapper<TData>): void;
25
24
  saveTypes(): void;
26
25
  on(event: FlowEvent, handler: (flowName: string) => void): void;
@@ -7,20 +7,19 @@ exports.LockedData = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const guards_1 = require("./guards");
10
- const printer_1 = require("./printer");
11
10
  const step_validator_1 = require("./step-validator");
12
11
  const file_stream_adapter_1 = require("./streams/adapters/file-stream-adapter");
13
12
  const memory_stream_adapter_1 = require("./streams/adapters/memory-stream-adapter");
14
13
  const generate_types_1 = require("./types/generate-types");
15
14
  class LockedData {
16
- constructor(baseDir, streamAdapter = 'file') {
15
+ constructor(baseDir, streamAdapter = 'file', printer) {
17
16
  this.baseDir = baseDir;
18
17
  this.streamAdapter = streamAdapter;
18
+ this.printer = printer;
19
19
  this.flows = {};
20
20
  this.activeSteps = [];
21
21
  this.devSteps = [];
22
22
  this.stepsMap = {};
23
- this.printer = new printer_1.Printer(baseDir);
24
23
  this.handlers = {
25
24
  'flow-created': [],
26
25
  'flow-removed': [],
@@ -38,9 +37,6 @@ class LockedData {
38
37
  };
39
38
  this.streams = {};
40
39
  }
41
- disablePrinter() {
42
- this.printer = new printer_1.NoPrinter(this.baseDir);
43
- }
44
40
  applyStreamWrapper(streamWrapper) {
45
41
  this.streamWrapper = streamWrapper;
46
42
  }
@@ -107,6 +103,7 @@ class LockedData {
107
103
  const addedFlows = newStep.config.flows?.filter((flowName) => !oldStep.config.flows?.includes(flowName)) ?? [];
108
104
  const removedFlows = oldStep.config.flows?.filter((flowName) => !newStep.config.flows?.includes(flowName)) ?? [];
109
105
  const untouchedFlows = oldStep.config.flows?.filter((flowName) => newStep.config.flows?.includes(flowName)) ?? [];
106
+ savedStep.config = newStep.config;
110
107
  untouchedFlows.forEach((flowName) => this.onFlowUpdated(flowName));
111
108
  for (const flowName of addedFlows) {
112
109
  if (!this.flows[flowName]) {
@@ -128,7 +125,6 @@ class LockedData {
128
125
  this.onFlowUpdated(flowName);
129
126
  }
130
127
  }
131
- savedStep.config = newStep.config;
132
128
  if (!options.disableTypeCreation) {
133
129
  this.saveTypes();
134
130
  }
@@ -6,7 +6,10 @@ type CreateLogger = {
6
6
  flows?: string[];
7
7
  stepName: string;
8
8
  };
9
- export declare class LoggerFactory {
9
+ export interface LoggerFactory {
10
+ create: (args: CreateLogger) => Logger;
11
+ }
12
+ export declare class BaseLoggerFactory implements LoggerFactory {
10
13
  private readonly isVerbose;
11
14
  private readonly logStream;
12
15
  constructor(isVerbose: boolean, logStream: StreamAdapter<Log>);
@@ -1,14 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LoggerFactory = void 0;
3
+ exports.BaseLoggerFactory = void 0;
4
+ const crypto_1 = require("crypto");
4
5
  const logger_1 = require("./logger");
5
- class LoggerFactory {
6
+ class BaseLoggerFactory {
6
7
  constructor(isVerbose, logStream) {
7
8
  this.isVerbose = isVerbose;
8
9
  this.logStream = logStream;
9
10
  }
10
11
  create({ stepName, traceId, flows }) {
11
- return new logger_1.Logger(traceId, flows, stepName, this.isVerbose, this.logStream);
12
+ const streamListener = (level, msg, args) => {
13
+ const id = (0, crypto_1.randomUUID)();
14
+ this.logStream.set('default', id, {
15
+ id,
16
+ ...(args ?? {}),
17
+ level,
18
+ time: Date.now(),
19
+ msg,
20
+ traceId,
21
+ flows: flows ?? [],
22
+ });
23
+ };
24
+ return new logger_1.Logger(this.isVerbose, { traceId, flows, step: stepName }, [streamListener]);
12
25
  }
13
26
  }
14
- exports.LoggerFactory = LoggerFactory;
27
+ exports.BaseLoggerFactory = BaseLoggerFactory;
@@ -1,29 +1,26 @@
1
- import { Log } from './streams/logs-stream';
2
- import { StreamAdapter } from './streams/adapters/stream-adapter';
3
- export declare class BaseLogger {
1
+ import { Step } from './types';
2
+ export type LogListener = (level: string, msg: string, args?: unknown) => void;
3
+ export declare class Logger {
4
4
  readonly isVerbose: boolean;
5
5
  private readonly meta;
6
- constructor(isVerbose?: boolean, meta?: Record<string, unknown>);
7
- child(meta?: Record<string, unknown>): this;
6
+ private readonly coreListeners;
7
+ /**
8
+ * Why do we need two level of listeners?
9
+ *
10
+ * Core listeners pass along to children loggers.
11
+ *
12
+ * However, base listeners do not pass along to children loggers.
13
+ * Those are specific to each logger in the hierarchy.
14
+ */
15
+ private readonly listeners;
16
+ constructor(isVerbose?: boolean, meta?: Record<string, unknown>, coreListeners?: LogListener[]);
17
+ child(step: Step): Logger;
8
18
  private _log;
9
19
  info(message: string, args?: unknown): void;
10
20
  error(message: string, args?: unknown): void;
11
21
  debug(message: string, args?: unknown): void;
12
22
  warn(message: string, args?: unknown): void;
13
23
  log(args: any): void;
24
+ addListener(listener: LogListener): void;
14
25
  }
15
- export declare class Logger extends BaseLogger {
16
- private readonly traceId;
17
- private readonly flows;
18
- private readonly step;
19
- private readonly logStream?;
20
- private emitLog;
21
- constructor(traceId: string, flows: string[] | undefined, step: string, isVerbose: boolean, logStream?: StreamAdapter<Log> | undefined);
22
- child(meta?: Record<string, unknown>): this;
23
- log(message: any): void;
24
- info: (message: string, args?: unknown) => void;
25
- error: (message: string, args?: unknown) => void;
26
- debug: (message: string, args?: unknown) => void;
27
- warn: (message: string, args?: unknown) => void;
28
- }
29
- export declare const globalLogger: BaseLogger;
26
+ export declare const globalLogger: Logger;
@@ -1,24 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.globalLogger = exports.Logger = exports.BaseLogger = void 0;
4
- const crypto_1 = require("crypto");
3
+ exports.globalLogger = exports.Logger = void 0;
5
4
  const pretty_print_1 = require("./pretty-print");
6
5
  const logLevel = process.env.LOG_LEVEL ?? 'info';
7
6
  const isDebugEnabled = logLevel === 'debug';
8
7
  const isInfoEnabled = ['info', 'debug'].includes(logLevel);
9
8
  const isWarnEnabled = ['warn', 'info', 'debug', 'trace'].includes(logLevel);
10
- class BaseLogger {
11
- constructor(isVerbose = false, meta = {}) {
9
+ class Logger {
10
+ constructor(isVerbose = false, meta = {}, coreListeners = []) {
12
11
  this.isVerbose = isVerbose;
13
12
  this.meta = meta;
14
- }
15
- child(meta = {}) {
16
- return new BaseLogger(this.isVerbose, { ...this.meta, ...meta });
13
+ this.coreListeners = coreListeners;
14
+ /**
15
+ * Why do we need two level of listeners?
16
+ *
17
+ * Core listeners pass along to children loggers.
18
+ *
19
+ * However, base listeners do not pass along to children loggers.
20
+ * Those are specific to each logger in the hierarchy.
21
+ */
22
+ this.listeners = [];
23
+ }
24
+ child(step) {
25
+ return new Logger(this.isVerbose, { ...this.meta, step: step.config.name }, this.coreListeners);
17
26
  }
18
27
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
28
  _log(level, msg, args) {
20
29
  const time = Date.now();
21
- (0, pretty_print_1.prettyPrint)({ level, time, msg, ...this.meta, ...(args ?? {}) }, !this.isVerbose);
30
+ const meta = { ...this.meta, ...(args ?? {}) };
31
+ (0, pretty_print_1.prettyPrint)({ level, time, msg, ...meta }, !this.isVerbose);
32
+ this.coreListeners.forEach((listener) => listener(level, msg, meta));
33
+ this.listeners.forEach((listener) => listener(level, msg, meta));
22
34
  }
23
35
  info(message, args) {
24
36
  if (isInfoEnabled) {
@@ -42,55 +54,9 @@ class BaseLogger {
42
54
  log(args) {
43
55
  this._log('info', args.msg, args);
44
56
  }
45
- }
46
- exports.BaseLogger = BaseLogger;
47
- class Logger extends BaseLogger {
48
- constructor(traceId, flows, step, isVerbose, logStream) {
49
- super(isVerbose, { traceId, flows, step });
50
- this.traceId = traceId;
51
- this.flows = flows;
52
- this.step = step;
53
- this.logStream = logStream;
54
- this.info = (message, args) => {
55
- super.info(message, args);
56
- this.emitLog('info', message, args);
57
- };
58
- this.error = (message, args) => {
59
- super.error(message, args);
60
- this.emitLog('error', message, args);
61
- };
62
- this.debug = (message, args) => {
63
- if (isDebugEnabled) {
64
- super.debug(message, args);
65
- this.emitLog('debug', message, args);
66
- }
67
- };
68
- this.warn = (message, args) => {
69
- super.warn(message, args);
70
- this.emitLog('warn', message, args);
71
- };
72
- this.emitLog = (level, msg, args) => {
73
- const id = (0, crypto_1.randomUUID)();
74
- this.logStream?.set('default', id, {
75
- id,
76
- step: this.step,
77
- ...(args ?? {}),
78
- level,
79
- time: Date.now(),
80
- msg,
81
- traceId: this.traceId,
82
- flows: this.flows ?? [],
83
- });
84
- };
85
- }
86
- child(meta = {}) {
87
- return new Logger(this.traceId, this.flows, meta.step, this.isVerbose, this.logStream);
88
- }
89
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
90
- log(message) {
91
- super.log(message);
92
- this.emitLog(message.level, message.msg, message);
57
+ addListener(listener) {
58
+ this.listeners.push(listener);
93
59
  }
94
60
  }
95
61
  exports.Logger = Logger;
96
- exports.globalLogger = new BaseLogger();
62
+ exports.globalLogger = new Logger();
@@ -0,0 +1,13 @@
1
+ import { Printer } from './printer';
2
+ import { TracerFactory } from './observability';
3
+ import { EventManager, InternalStateManager } from './types';
4
+ import { LockedData } from './locked-data';
5
+ import { LoggerFactory } from './logger-factory';
6
+ export type Motia = {
7
+ loggerFactory: LoggerFactory;
8
+ eventManager: EventManager;
9
+ state: InternalStateManager;
10
+ lockedData: LockedData;
11
+ printer: Printer;
12
+ tracerFactory: TracerFactory;
13
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -25,6 +25,7 @@ function parseArgs(arg) {
25
25
  }
26
26
  }
27
27
  async function runTypescriptModule(filePath, event) {
28
+ const sender = new rpc_1.RpcSender(process);
28
29
  try {
29
30
  // eslint-disable-next-line @typescript-eslint/no-require-imports
30
31
  const module = require(path_1.default.resolve(filePath));
@@ -33,7 +34,6 @@ async function runTypescriptModule(filePath, event) {
33
34
  throw new Error(`Function handler not found in module ${filePath}`);
34
35
  }
35
36
  const { traceId, flows, contextInFirstArg } = event;
36
- const sender = new rpc_1.RpcSender(process);
37
37
  const logger = new logger_1.Logger(traceId, flows, sender);
38
38
  const state = new rpc_state_manager_1.RpcStateManager(sender);
39
39
  const emit = async (data) => sender.send('emit', data);
@@ -58,10 +58,21 @@ async function runTypescriptModule(filePath, event) {
58
58
  await sender.send('result', result);
59
59
  await sender.close();
60
60
  process.exit(0);
61
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
62
  }
62
- catch (error) {
63
- console.error('Error running TypeScript module:', error);
64
- process.exit(1);
63
+ catch (err) {
64
+ const stack = err.stack?.split('\n') ?? [];
65
+ if (stack) {
66
+ const index = stack.findIndex((line) => line.includes('src/node/node-runner'));
67
+ stack.splice(index, stack.length - index);
68
+ stack.splice(0, 1); // remove first line which has the error message
69
+ }
70
+ const error = {
71
+ message: err.message || '',
72
+ code: err.code || null,
73
+ stack: stack.join('\n'),
74
+ };
75
+ sender.sendNoWait('close', error);
65
76
  }
66
77
  }
67
78
  const [, , filePath, arg] = process.argv;
@@ -0,0 +1,3 @@
1
+ import { Step } from '../types';
2
+ import { Trace, TraceGroup } from './types';
3
+ export declare const createTrace: (traceGroup: TraceGroup, step: Step) => Trace;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTrace = void 0;
4
+ const createTrace = (traceGroup, step) => {
5
+ const id = crypto.randomUUID();
6
+ const trace = {
7
+ id,
8
+ name: step.config.name,
9
+ correlationId: traceGroup.correlationId,
10
+ parentTraceId: traceGroup.id,
11
+ status: 'running',
12
+ startTime: Date.now(),
13
+ endTime: undefined,
14
+ entryPoint: { type: step.config.type, stepName: step.config.name },
15
+ events: [],
16
+ };
17
+ traceGroup.metadata.totalSteps++;
18
+ traceGroup.metadata.activeSteps++;
19
+ return trace;
20
+ };
21
+ exports.createTrace = createTrace;
@@ -0,0 +1,13 @@
1
+ import { Logger } from '../logger';
2
+ import { Step } from '../types';
3
+ import { StateOperation, StreamOperation, TraceError } from './types';
4
+ export interface TracerFactory {
5
+ createTracer(traceId: string, step: Step, logger: Logger): Tracer;
6
+ }
7
+ export interface Tracer {
8
+ end(err?: TraceError): void;
9
+ stateOperation(operation: StateOperation, input: unknown): void;
10
+ emitOperation(topic: string, data: unknown, success: boolean): void;
11
+ streamOperation(streamName: string, operation: StreamOperation, input: unknown): void;
12
+ child(step: Step, logger: Logger): Tracer;
13
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ import { Tracer } from '.';
2
+ export declare class NoTracer implements Tracer {
3
+ end(): void;
4
+ stateOperation(): void;
5
+ emitOperation(): void;
6
+ streamOperation(): void;
7
+ child(): this;
8
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NoTracer = void 0;
4
+ class NoTracer {
5
+ end() { }
6
+ stateOperation() { }
7
+ emitOperation() { }
8
+ streamOperation() { }
9
+ child() {
10
+ return this;
11
+ }
12
+ }
13
+ exports.NoTracer = NoTracer;
@@ -0,0 +1,21 @@
1
+ import { Tracer } from '.';
2
+ import { Logger } from '../logger';
3
+ import { Step } from '../types';
4
+ import { TraceManager } from './trace-manager';
5
+ import { StateOperation, StreamOperation, Trace, TraceError, TraceGroup } from './types';
6
+ export declare class StreamTracer implements Tracer {
7
+ private readonly manager;
8
+ private readonly traceGroup;
9
+ private readonly trace;
10
+ constructor(manager: TraceManager, traceGroup: TraceGroup, trace: Trace, logger: Logger);
11
+ end(err?: TraceError): void;
12
+ stateOperation(operation: StateOperation, input: unknown): void;
13
+ emitOperation(topic: string, data: unknown, success: boolean): void;
14
+ streamOperation(streamName: string, operation: StreamOperation, input: {
15
+ groupId: string;
16
+ id: string;
17
+ data?: unknown;
18
+ }): void;
19
+ child(step: Step, logger: Logger): StreamTracer;
20
+ private addEvent;
21
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StreamTracer = void 0;
4
+ const create_trace_1 = require("./create-trace");
5
+ class StreamTracer {
6
+ constructor(manager, traceGroup, trace, logger) {
7
+ this.manager = manager;
8
+ this.traceGroup = traceGroup;
9
+ this.trace = trace;
10
+ logger.addListener((level, msg, args) => {
11
+ this.addEvent({
12
+ type: 'log',
13
+ timestamp: Date.now(),
14
+ level,
15
+ message: msg,
16
+ metadata: args,
17
+ });
18
+ });
19
+ }
20
+ end(err) {
21
+ if (this.trace.endTime) {
22
+ // avoiding updating twice
23
+ return;
24
+ }
25
+ this.trace.status = err ? 'failed' : 'completed';
26
+ this.trace.endTime = Date.now();
27
+ this.trace.error = err;
28
+ this.traceGroup.metadata.completedSteps++;
29
+ this.traceGroup.metadata.activeSteps--;
30
+ if (this.traceGroup.metadata.activeSteps === 0) {
31
+ if (this.traceGroup.status === 'running') {
32
+ this.traceGroup.status = 'completed';
33
+ }
34
+ this.traceGroup.endTime = Date.now();
35
+ }
36
+ if (err) {
37
+ this.traceGroup.status = 'failed';
38
+ }
39
+ this.manager.updateTrace();
40
+ this.manager.updateTraceGroup();
41
+ }
42
+ stateOperation(operation, input) {
43
+ this.addEvent({
44
+ type: 'state',
45
+ timestamp: Date.now(),
46
+ operation,
47
+ data: input,
48
+ });
49
+ }
50
+ emitOperation(topic, data, success) {
51
+ this.addEvent({
52
+ type: 'emit',
53
+ timestamp: Date.now(),
54
+ topic,
55
+ success,
56
+ data,
57
+ });
58
+ }
59
+ streamOperation(streamName, operation, input) {
60
+ if (operation === 'set') {
61
+ const lastEvent = this.trace.events[this.trace.events.length - 1];
62
+ if (lastEvent &&
63
+ lastEvent.type === 'stream' &&
64
+ lastEvent.streamName === streamName &&
65
+ lastEvent.data.groupId === input.groupId &&
66
+ lastEvent.data.id === input.id) {
67
+ lastEvent.calls++;
68
+ lastEvent.data.data = input.data;
69
+ lastEvent.maxTimestamp = Date.now();
70
+ this.traceGroup.lastActivity = lastEvent.maxTimestamp;
71
+ this.manager.updateTrace();
72
+ this.manager.updateTraceGroup();
73
+ return;
74
+ }
75
+ }
76
+ this.addEvent({
77
+ type: 'stream',
78
+ timestamp: Date.now(),
79
+ operation,
80
+ data: input,
81
+ streamName,
82
+ calls: 1,
83
+ });
84
+ }
85
+ child(step, logger) {
86
+ const trace = (0, create_trace_1.createTrace)(this.traceGroup, step);
87
+ const manager = this.manager.child(trace);
88
+ return new StreamTracer(manager, this.traceGroup, trace, logger);
89
+ }
90
+ addEvent(event) {
91
+ this.trace.events.push(event);
92
+ this.traceGroup.lastActivity = event.timestamp;
93
+ this.manager.updateTrace();
94
+ this.manager.updateTraceGroup();
95
+ }
96
+ }
97
+ exports.StreamTracer = StreamTracer;
@@ -0,0 +1,12 @@
1
+ import { MotiaStream } from '../types-stream';
2
+ import { Trace, TraceGroup } from './types';
3
+ export declare class TraceManager {
4
+ private readonly traceStream;
5
+ private readonly traceGroupStream;
6
+ private readonly traceGroup;
7
+ private readonly trace;
8
+ constructor(traceStream: MotiaStream<Trace>, traceGroupStream: MotiaStream<TraceGroup>, traceGroup: TraceGroup, trace: Trace);
9
+ updateTrace(): void;
10
+ updateTraceGroup(): void;
11
+ child(trace: Trace): TraceManager;
12
+ }