@motiadev/core 0.2.1-beta.65-2533 → 0.2.1-beta.67

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/dist/index.d.ts CHANGED
@@ -12,3 +12,4 @@ export { StateAdapter } from './src/state/state-adapter';
12
12
  export { createMermaidGenerator } from './src/mermaid-generator';
13
13
  export { StateStream } from './src/state-stream';
14
14
  export { StateStreamConfig, IStateStream } from './src/types-stream';
15
+ export { getProjectIdentifier, getUserIdentifier, isAnalyticsEnabled, trackEvent } from './src/analytics/utils';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.StateStream = exports.createMermaidGenerator = exports.getStreamConfig = exports.getStepConfig = exports.LockedData = exports.isNoopStep = exports.isEventStep = exports.isCronStep = exports.isApiStep = exports.setupCronHandlers = exports.createStateAdapter = exports.Logger = exports.globalLogger = exports.createEventManager = exports.createStepHandlers = exports.createServer = void 0;
17
+ exports.trackEvent = exports.isAnalyticsEnabled = exports.getUserIdentifier = exports.getProjectIdentifier = exports.StateStream = exports.createMermaidGenerator = exports.getStreamConfig = exports.getStepConfig = exports.LockedData = exports.isNoopStep = exports.isEventStep = exports.isCronStep = exports.isApiStep = exports.setupCronHandlers = exports.createStateAdapter = exports.Logger = exports.globalLogger = exports.createEventManager = exports.createStepHandlers = exports.createServer = void 0;
18
18
  __exportStar(require("./src/types"), exports);
19
19
  var server_1 = require("./src/server");
20
20
  Object.defineProperty(exports, "createServer", { enumerable: true, get: function () { return server_1.createServer; } });
@@ -43,3 +43,8 @@ var mermaid_generator_1 = require("./src/mermaid-generator");
43
43
  Object.defineProperty(exports, "createMermaidGenerator", { enumerable: true, get: function () { return mermaid_generator_1.createMermaidGenerator; } });
44
44
  var state_stream_1 = require("./src/state-stream");
45
45
  Object.defineProperty(exports, "StateStream", { enumerable: true, get: function () { return state_stream_1.StateStream; } });
46
+ var utils_1 = require("./src/analytics/utils");
47
+ Object.defineProperty(exports, "getProjectIdentifier", { enumerable: true, get: function () { return utils_1.getProjectIdentifier; } });
48
+ Object.defineProperty(exports, "getUserIdentifier", { enumerable: true, get: function () { return utils_1.getUserIdentifier; } });
49
+ Object.defineProperty(exports, "isAnalyticsEnabled", { enumerable: true, get: function () { return utils_1.isAnalyticsEnabled; } });
50
+ Object.defineProperty(exports, "trackEvent", { enumerable: true, get: function () { return utils_1.trackEvent; } });
@@ -0,0 +1,5 @@
1
+ export declare const getProjectName: (baseDir: string) => string;
2
+ export declare const getUserIdentifier: () => string;
3
+ export declare const getProjectIdentifier: (baseDir: string) => string;
4
+ export declare const isAnalyticsEnabled: () => boolean;
5
+ export declare const trackEvent: (eventName: string, properties?: Record<string, any>) => void;
@@ -0,0 +1,50 @@
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.trackEvent = exports.isAnalyticsEnabled = exports.getProjectIdentifier = exports.getUserIdentifier = exports.getProjectName = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const os_1 = __importDefault(require("os"));
10
+ const crypto_1 = __importDefault(require("crypto"));
11
+ const analytics_node_1 = require("@amplitude/analytics-node");
12
+ const getProjectName = (baseDir) => {
13
+ const packageJsonPath = path_1.default.join(baseDir, 'package.json');
14
+ if (fs_1.default.existsSync(packageJsonPath)) {
15
+ const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
16
+ return packageJson.name || path_1.default.basename(baseDir);
17
+ }
18
+ return 'unknown';
19
+ };
20
+ exports.getProjectName = getProjectName;
21
+ const getUserIdentifier = () => {
22
+ const userInfo = `${os_1.default.userInfo().username}${os_1.default.hostname()}`;
23
+ return crypto_1.default.createHash('sha256').update(userInfo).digest('hex').substring(0, 16);
24
+ };
25
+ exports.getUserIdentifier = getUserIdentifier;
26
+ const getProjectIdentifier = (baseDir) => {
27
+ try {
28
+ return crypto_1.default.createHash('sha256').update((0, exports.getProjectName)(baseDir)).digest('hex').substring(0, 16);
29
+ }
30
+ catch (error) {
31
+ return 'unknown';
32
+ }
33
+ };
34
+ exports.getProjectIdentifier = getProjectIdentifier;
35
+ const isAnalyticsEnabled = () => {
36
+ return process.env.MOTIA_ANALYTICS_DISABLED !== 'true';
37
+ };
38
+ exports.isAnalyticsEnabled = isAnalyticsEnabled;
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ const trackEvent = (eventName, properties = {}) => {
41
+ try {
42
+ (0, analytics_node_1.track)(eventName, properties, {
43
+ user_id: (0, exports.getUserIdentifier)() || 'unknown',
44
+ });
45
+ }
46
+ catch (error) {
47
+ // Silently fail to not disrupt dev server
48
+ }
49
+ };
50
+ exports.trackEvent = trackEvent;
@@ -0,0 +1,2 @@
1
+ import { Express } from 'express';
2
+ export declare const analyticsEndpoint: (app: Express, baseDir: string) => void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyticsEndpoint = void 0;
4
+ const utils_1 = require("./analytics/utils");
5
+ const analyticsEndpoint = (app, baseDir) => {
6
+ app.get('/motia/analytics/user', (req, res) => {
7
+ const analyticsEnabled = (0, utils_1.isAnalyticsEnabled)();
8
+ if (!analyticsEnabled) {
9
+ res.json({
10
+ userId: null,
11
+ projectId: null,
12
+ motiaVersion: null,
13
+ analyticsEnabled: false,
14
+ });
15
+ return;
16
+ }
17
+ res.json({
18
+ userId: (0, utils_1.getUserIdentifier)(),
19
+ projectId: (0, utils_1.getProjectIdentifier)(baseDir),
20
+ motiaVersion: process.env.npm_package_dependencies_motia || 'unknown',
21
+ analyticsEnabled: true,
22
+ });
23
+ });
24
+ app.get('/motia/analytics/status', (req, res) => {
25
+ res.json({
26
+ analyticsEnabled: (0, utils_1.isAnalyticsEnabled)(),
27
+ });
28
+ });
29
+ };
30
+ exports.analyticsEndpoint = analyticsEndpoint;
@@ -7,6 +7,7 @@ exports.callStepFile = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const utils_1 = require("./utils");
9
9
  const process_manager_1 = require("./process-communication/process-manager");
10
+ const utils_2 = require("./analytics/utils");
10
11
  const getLanguageBasedRunner = (stepFilePath = '') => {
11
12
  const isPython = stepFilePath.endsWith('.py');
12
13
  const isRuby = stepFilePath.endsWith('.rb');
@@ -46,6 +47,7 @@ const callStepFile = (options) => {
46
47
  logger,
47
48
  context: 'StepExecution',
48
49
  });
50
+ (0, utils_2.trackEvent)('step_execution_started', { language: command, type: step.config.type, streams: streams.length });
49
51
  processManager
50
52
  .spawn()
51
53
  .then(() => {
@@ -88,6 +90,7 @@ const callStepFile = (options) => {
88
90
  processManager.onProcessClose((code) => {
89
91
  processManager.close();
90
92
  if (code !== 0 && code !== null) {
93
+ (0, utils_2.trackEvent)('step_execution_error', { stepName: step.config.name, traceId, code });
91
94
  reject(`Process exited with code ${code}`);
92
95
  }
93
96
  else {
@@ -98,6 +101,12 @@ const callStepFile = (options) => {
98
101
  processManager.onProcessError((error) => {
99
102
  processManager.close();
100
103
  if (error.code === 'ENOENT') {
104
+ (0, utils_2.trackEvent)('step_execution_error', {
105
+ stepName: step.config.name,
106
+ traceId,
107
+ code: error.code,
108
+ message: error.message,
109
+ });
101
110
  reject(`Executable ${command} not found`);
102
111
  }
103
112
  else {
@@ -106,6 +115,12 @@ const callStepFile = (options) => {
106
115
  });
107
116
  })
108
117
  .catch((error) => {
118
+ (0, utils_2.trackEvent)('step_execution_error', {
119
+ stepName: step.config.name,
120
+ traceId,
121
+ code: error.code,
122
+ message: error.message,
123
+ });
109
124
  reject(`Failed to spawn process: ${error}`);
110
125
  });
111
126
  });
@@ -20,6 +20,8 @@ const flows_config_endpoint_1 = require("./flows-config-endpoint");
20
20
  const api_endpoints_1 = require("./streams/api-endpoints");
21
21
  const socket_server_1 = require("./socket-server");
22
22
  const logs_stream_1 = require("./streams/logs-stream");
23
+ const analytics_endpoint_1 = require("./analytics-endpoint");
24
+ const utils_1 = require("./analytics/utils");
23
25
  const createServer = async (lockedData, eventManager, state, config) => {
24
26
  const printer = lockedData.printer;
25
27
  const app = (0, express_1.default)();
@@ -135,6 +137,11 @@ const createServer = async (lockedData, eventManager, state, config) => {
135
137
  res.json(result.body);
136
138
  }
137
139
  catch (error) {
140
+ (0, utils_1.trackEvent)('api_call_error', {
141
+ stepName,
142
+ traceId,
143
+ error: error instanceof Error ? error.message : 'Unknown error',
144
+ });
138
145
  logger.error('[API] Internal server error', { error });
139
146
  console.log(error);
140
147
  res.status(500).json({ error: 'Internal server error' });
@@ -182,6 +189,7 @@ const createServer = async (lockedData, eventManager, state, config) => {
182
189
  (0, api_endpoints_1.apiEndpoints)(lockedData);
183
190
  (0, flows_endpoint_1.flowsEndpoint)(lockedData, app);
184
191
  (0, flows_config_endpoint_1.flowsConfigEndpoint)(app, process.cwd());
192
+ (0, analytics_endpoint_1.analyticsEndpoint)(app, process.cwd());
185
193
  server.on('error', (error) => {
186
194
  console.error('Server error:', error);
187
195
  });
@@ -4,9 +4,9 @@ export type FileAdapterConfig = {
4
4
  filePath: string;
5
5
  };
6
6
  export declare class FileStateAdapter implements StateAdapter {
7
- private filePath;
7
+ private readonly filePath;
8
8
  constructor(config: FileAdapterConfig);
9
- init(): Promise<void>;
9
+ init(): void;
10
10
  getGroup<T>(groupId: string): Promise<T[]>;
11
11
  get<T>(traceId: string, key: string): Promise<T | null>;
12
12
  set<T>(traceId: string, key: string, value: T): Promise<T>;
@@ -43,7 +43,7 @@ class FileStateAdapter {
43
43
  constructor(config) {
44
44
  this.filePath = path.join(config.filePath, 'motia.state.json');
45
45
  }
46
- async init() {
46
+ init() {
47
47
  const dir = this.filePath.replace('motia.state.json', '');
48
48
  try {
49
49
  fs_1.default.realpathSync(dir);
@@ -115,11 +115,23 @@ class FileStateAdapter {
115
115
  return `${traceId}:${key}`;
116
116
  }
117
117
  _readFile() {
118
- const content = fs_1.default.readFileSync(this.filePath, 'utf-8');
119
- return JSON.parse(content);
118
+ try {
119
+ const content = fs_1.default.readFileSync(this.filePath, 'utf-8');
120
+ return JSON.parse(content);
121
+ }
122
+ catch (error) {
123
+ this.init();
124
+ return {};
125
+ }
120
126
  }
121
127
  _writeFile(data) {
122
- fs_1.default.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');
128
+ try {
129
+ fs_1.default.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');
130
+ }
131
+ catch (error) {
132
+ this.init();
133
+ fs_1.default.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');
134
+ }
123
135
  }
124
136
  }
125
137
  exports.FileStateAdapter = FileStateAdapter;
package/package.json CHANGED
@@ -2,8 +2,9 @@
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.2.1-beta.65-2533",
5
+ "version": "0.2.1-beta.67",
6
6
  "dependencies": {
7
+ "@amplitude/analytics-node": "^1.3.8",
7
8
  "body-parser": "^1.20.3",
8
9
  "colors": "^1.4.0",
9
10
  "cors": "^2.8.5",