@motiadev/core 0.3.0-beta.81 → 0.3.1-beta.82

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.
@@ -58,7 +58,7 @@ const setupCronHandlers = (motia) => {
58
58
  const task = cron.schedule(cronExpression, async () => {
59
59
  const traceId = (0, generate_trace_id_1.generateTraceId)();
60
60
  const logger = motia.loggerFactory.create({ traceId, flows, stepName });
61
- const tracer = motia.tracerFactory.createTracer(traceId, step, logger);
61
+ const tracer = await motia.tracerFactory.createTracer(traceId, step, logger);
62
62
  try {
63
63
  await (0, call_step_file_1.callStepFile)({ contextInFirstArg: true, step, traceId, tracer, logger }, motia);
64
64
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -8,7 +8,7 @@ type StreamEvent = 'stream-created' | 'stream-removed' | 'stream-updated';
8
8
  type StreamWrapper<TData> = (streamName: string, factory: StreamFactory<TData>) => StreamFactory<TData>;
9
9
  export declare class LockedData {
10
10
  readonly baseDir: string;
11
- private readonly streamAdapter;
11
+ readonly streamAdapter: 'file' | 'memory';
12
12
  private readonly printer;
13
13
  flows: Record<string, Flow>;
14
14
  activeSteps: Step[];
@@ -2,7 +2,7 @@ import { Logger } from '../logger';
2
2
  import { Step } from '../types';
3
3
  import { StateOperation, StreamOperation, TraceError } from './types';
4
4
  export interface TracerFactory {
5
- createTracer(traceId: string, step: Step, logger: Logger): Tracer;
5
+ createTracer(traceId: string, step: Step, logger: Logger): Promise<Tracer> | Tracer;
6
6
  }
7
7
  export interface Tracer {
8
8
  end(err?: TraceError): void;
@@ -0,0 +1,11 @@
1
+ import { FileStreamAdapter } from '../streams/adapters/file-stream-adapter';
2
+ import { BaseStreamItem } from '../types-stream';
3
+ export declare class TraceStreamAdapter<TData> extends FileStreamAdapter<TData> {
4
+ private state;
5
+ private isDirty;
6
+ constructor(filePath: string, streamName: string, streamAdapter: 'file' | 'memory');
7
+ get(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
8
+ set(groupId: string, id: string, data: TData): Promise<BaseStreamItem<TData>>;
9
+ delete(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
10
+ getGroup(groupId: string): Promise<BaseStreamItem<TData>[]>;
11
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TraceStreamAdapter = void 0;
4
+ const file_stream_adapter_1 = require("../streams/adapters/file-stream-adapter");
5
+ class TraceStreamAdapter extends file_stream_adapter_1.FileStreamAdapter {
6
+ constructor(filePath, streamName, streamAdapter) {
7
+ super(filePath ?? '', streamName);
8
+ this.state = {};
9
+ this.isDirty = false;
10
+ if (streamAdapter === 'file') {
11
+ const state = this._readFile();
12
+ Object.entries(state).forEach(([key, value]) => {
13
+ if (typeof value === 'string') {
14
+ this.state[key] = JSON.parse(value);
15
+ }
16
+ else {
17
+ this.state[key] = value;
18
+ }
19
+ });
20
+ setInterval(() => {
21
+ if (this.isDirty) {
22
+ this._writeFile(this.state);
23
+ this.isDirty = false;
24
+ }
25
+ }, 30000);
26
+ }
27
+ }
28
+ async get(groupId, id) {
29
+ const key = this._makeKey(groupId, id);
30
+ return this.state[key] ? this.state[key] : null;
31
+ }
32
+ async set(groupId, id, data) {
33
+ const key = this._makeKey(groupId, id);
34
+ this.state[key] = data;
35
+ this.isDirty = true;
36
+ return { ...data, id };
37
+ }
38
+ async delete(groupId, id) {
39
+ const key = this._makeKey(groupId, id);
40
+ const value = await this.get(groupId, id);
41
+ if (value) {
42
+ delete this.state[key];
43
+ this.isDirty = true;
44
+ }
45
+ return value;
46
+ }
47
+ async getGroup(groupId) {
48
+ return Object.entries(this.state)
49
+ .filter(([key]) => key.startsWith(groupId))
50
+ .map(([, value]) => value);
51
+ }
52
+ }
53
+ exports.TraceStreamAdapter = TraceStreamAdapter;
@@ -9,6 +9,7 @@ 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
- createTracer(traceId: string, step: Step, logger: Logger): StreamTracer;
12
+ private deleteGroup;
13
+ createTracer(traceId: string, step: Step, logger: Logger): Promise<StreamTracer>;
13
14
  }
14
15
  export declare const createTracerFactory: (lockedData: LockedData) => TracerFactory;
@@ -4,12 +4,23 @@ exports.createTracerFactory = exports.BaseTracerFactory = void 0;
4
4
  const create_trace_1 = require("./create-trace");
5
5
  const stream_tracer_1 = require("./stream-tracer");
6
6
  const trace_manager_1 = require("./trace-manager");
7
+ const trace_stream_adapter_1 = require("./trace-stream-adapter");
8
+ const MAX_TRACE_GROUPS = process.env.MOTIA_MAX_TRACE_GROUPS //
9
+ ? parseInt(process.env.MOTIA_MAX_TRACE_GROUPS)
10
+ : 50;
7
11
  class BaseTracerFactory {
8
12
  constructor(traceStream, traceGroupStream) {
9
13
  this.traceStream = traceStream;
10
14
  this.traceGroupStream = traceGroupStream;
11
15
  }
12
- createTracer(traceId, step, logger) {
16
+ async deleteGroup(group) {
17
+ const traces = await this.traceStream.getGroup(group.id);
18
+ for (const trace of traces) {
19
+ await this.traceStream.delete(group.id, trace.id);
20
+ }
21
+ await this.traceGroupStream.delete('default', group.id);
22
+ }
23
+ async createTracer(traceId, step, logger) {
13
24
  const traceGroup = {
14
25
  id: traceId,
15
26
  name: step.config.name,
@@ -23,6 +34,15 @@ class BaseTracerFactory {
23
34
  status: 'running',
24
35
  startTime: Date.now(),
25
36
  };
37
+ const groups = await this.traceGroupStream.getGroup('default');
38
+ if (groups.length >= MAX_TRACE_GROUPS) {
39
+ const groupsToDelete = groups
40
+ .sort((a, b) => a.startTime - b.startTime) // date ascending
41
+ .slice(0, groups.length - MAX_TRACE_GROUPS + 1);
42
+ for (const group of groupsToDelete) {
43
+ await this.deleteGroup(group);
44
+ }
45
+ }
26
46
  const trace = (0, create_trace_1.createTrace)(traceGroup, step);
27
47
  const manager = new trace_manager_1.TraceManager(this.traceStream, this.traceGroupStream, traceGroup, trace);
28
48
  return new stream_tracer_1.StreamTracer(manager, traceGroup, trace, logger);
@@ -30,21 +50,25 @@ class BaseTracerFactory {
30
50
  }
31
51
  exports.BaseTracerFactory = BaseTracerFactory;
32
52
  const createTracerFactory = (lockedData) => {
53
+ const traceStreamName = 'motia-trace';
54
+ const traceStreamAdapter = new trace_stream_adapter_1.TraceStreamAdapter(lockedData.baseDir, traceStreamName, lockedData.streamAdapter);
33
55
  const traceStream = lockedData.createStream({
34
- filePath: '__motia.trace',
56
+ filePath: traceStreamName,
35
57
  hidden: true,
36
58
  config: {
37
- name: 'motia-trace',
38
- baseConfig: { storageType: 'default' },
59
+ name: traceStreamName,
60
+ baseConfig: { storageType: 'custom', factory: () => traceStreamAdapter },
39
61
  schema: null,
40
62
  },
41
63
  })();
64
+ const traceGroupName = 'motia-trace-group';
65
+ const traceGroupStreamAdapter = new trace_stream_adapter_1.TraceStreamAdapter(lockedData.baseDir, traceGroupName, lockedData.streamAdapter);
42
66
  const traceGroupStream = lockedData.createStream({
43
- filePath: '__motia.trace-group',
67
+ filePath: traceGroupName,
44
68
  hidden: true,
45
69
  config: {
46
- name: 'motia-trace-group',
47
- baseConfig: { storageType: 'default' },
70
+ name: traceGroupName,
71
+ baseConfig: { storageType: 'custom', factory: () => traceGroupStreamAdapter },
48
72
  schema: null,
49
73
  },
50
74
  })();
@@ -118,7 +118,7 @@ const createServer = (lockedData, eventManager, state, config) => {
118
118
  const traceId = (0, generate_trace_id_1.generateTraceId)();
119
119
  const { name: stepName, flows } = step.config;
120
120
  const logger = loggerFactory.create({ traceId, flows, stepName });
121
- const tracer = motia.tracerFactory.createTracer(traceId, step, logger);
121
+ const tracer = await motia.tracerFactory.createTracer(traceId, step, logger);
122
122
  logger.debug('[API] Received request, processing step', { path: req.path });
123
123
  const data = {
124
124
  body: req.body,
@@ -1,4 +1,5 @@
1
1
  import { StreamAdapter } from './stream-adapter';
2
+ import { BaseStreamItem } from '../../types-stream';
2
3
  export type FileAdapterConfig = {
3
4
  filePath: string;
4
5
  };
@@ -7,14 +8,14 @@ export declare class FileStreamAdapter<TData> extends StreamAdapter<TData> {
7
8
  private readonly streamsDir;
8
9
  constructor(filePath: string, streamName: string);
9
10
  init(): void;
10
- getGroup<T>(groupId: string): Promise<T[]>;
11
- get<T>(groupId: string, key: string): Promise<T | null>;
12
- set<T>(groupId: string, id: string, value: T): Promise<T & {
11
+ getGroup(groupId: string): Promise<BaseStreamItem<TData>[]>;
12
+ get(groupId: string, key: string): Promise<BaseStreamItem<TData> | null>;
13
+ set(groupId: string, id: string, value: TData): Promise<TData & {
13
14
  id: string;
14
15
  }>;
15
- delete<T>(groupId: string, id: string): Promise<T | null>;
16
+ delete(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
16
17
  clear(groupId: string): Promise<void>;
17
- private _makeKey;
18
- private _readFile;
19
- private _writeFile;
18
+ protected _makeKey(groupId: string, id: string): string;
19
+ protected _readFile(): Record<string, string>;
20
+ protected _writeFile(data: unknown): void;
20
21
  }
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.3.0-beta.81",
5
+ "version": "0.3.1-beta.82",
6
6
  "dependencies": {
7
7
  "@amplitude/analytics-node": "^1.3.8",
8
8
  "body-parser": "^1.20.3",