@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
|
@@ -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
|
|
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;
|
package/dist/src/locked-data.js
CHANGED
|
@@ -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
|
|
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.
|
|
3
|
+
exports.BaseLoggerFactory = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
4
5
|
const logger_1 = require("./logger");
|
|
5
|
-
class
|
|
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
|
-
|
|
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.
|
|
27
|
+
exports.BaseLoggerFactory = BaseLoggerFactory;
|
package/dist/src/logger.d.ts
CHANGED
|
@@ -1,29 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export declare class
|
|
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
|
-
|
|
7
|
-
|
|
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
|
|
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;
|
package/dist/src/logger.js
CHANGED
|
@@ -1,24 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.globalLogger = exports.Logger =
|
|
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
|
|
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
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
+
};
|
|
@@ -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 (
|
|
63
|
-
|
|
64
|
-
|
|
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,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,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
|
+
}
|