@motiadev/core 0.1.0-alpha.4 → 0.1.0-alpha.6
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
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# @motiadev/core
|
|
2
|
+
|
|
3
|
+
Core functionality for the Motia framework, providing the foundation for building event-driven workflows.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @motiadev/core
|
|
9
|
+
# or
|
|
10
|
+
yarn add @motiadev/core
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @motiadev/core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
`@motiadev/core` is the foundation of the Motia framework, providing:
|
|
18
|
+
|
|
19
|
+
- Event-driven architecture with pub/sub capabilities
|
|
20
|
+
- Multi-language support (TypeScript, Python, Ruby)
|
|
21
|
+
- State management
|
|
22
|
+
- Cron job scheduling
|
|
23
|
+
- API route handling
|
|
24
|
+
- Logging infrastructure
|
|
25
|
+
|
|
26
|
+
## Key Components
|
|
27
|
+
|
|
28
|
+
### Server
|
|
29
|
+
|
|
30
|
+
Create and manage an HTTP server for handling API requests:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { createServer } from '@motiadev/core'
|
|
34
|
+
|
|
35
|
+
const server = await createServer(lockedData, eventManager, stateAdapter, config)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Event Management
|
|
39
|
+
|
|
40
|
+
Publish and subscribe to events across your application:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { createEventManager } from '@motiadev/core'
|
|
44
|
+
|
|
45
|
+
const eventManager = createEventManager()
|
|
46
|
+
|
|
47
|
+
// Subscribe to events
|
|
48
|
+
eventManager.subscribe({
|
|
49
|
+
event: 'user.created',
|
|
50
|
+
handlerName: 'sendWelcomeEmail',
|
|
51
|
+
filePath: '/path/to/handler.ts',
|
|
52
|
+
handler: (event) => {
|
|
53
|
+
// Handle the event
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// Emit events
|
|
58
|
+
eventManager.emit({
|
|
59
|
+
topic: 'user.created',
|
|
60
|
+
data: { userId: '123' },
|
|
61
|
+
traceId: 'trace-123',
|
|
62
|
+
logger: logger
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Step Handlers
|
|
67
|
+
|
|
68
|
+
Create handlers for different types of steps (API, Event, Cron):
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { createStepHandlers } from '@motiadev/core'
|
|
72
|
+
|
|
73
|
+
const stepHandlers = createStepHandlers(lockedData, eventManager, state, config)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### State Management
|
|
77
|
+
|
|
78
|
+
Manage application state with different adapters:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { createStateAdapter } from '@motiadev/core'
|
|
82
|
+
|
|
83
|
+
const stateAdapter = createStateAdapter({
|
|
84
|
+
adapter: 'redis',
|
|
85
|
+
host: 'localhost',
|
|
86
|
+
port: 6379
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// Use state in your handlers
|
|
90
|
+
await state.set(traceId, 'key', value)
|
|
91
|
+
const value = await state.get(traceId, 'key')
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Cron Jobs
|
|
95
|
+
|
|
96
|
+
Schedule and manage cron jobs:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { setupCronHandlers } from '@motiadev/core'
|
|
100
|
+
|
|
101
|
+
const cronManager = setupCronHandlers(lockedData, eventManager, state, loggerFactory)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Logging
|
|
105
|
+
|
|
106
|
+
Use the built-in logging system:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { globalLogger } from '@motiadev/core'
|
|
110
|
+
|
|
111
|
+
globalLogger.info('Application started')
|
|
112
|
+
globalLogger.error('Something went wrong', { error: err })
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Multi-language Support
|
|
116
|
+
|
|
117
|
+
Motia supports writing step handlers in multiple languages:
|
|
118
|
+
|
|
119
|
+
- TypeScript/JavaScript
|
|
120
|
+
- Python
|
|
121
|
+
- Ruby
|
|
122
|
+
|
|
123
|
+
Each language has its own runner that communicates with the core framework.
|
|
124
|
+
|
|
125
|
+
## Types
|
|
126
|
+
|
|
127
|
+
The package exports TypeScript types for all components:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import {
|
|
131
|
+
Event,
|
|
132
|
+
FlowContext,
|
|
133
|
+
ApiRouteConfig,
|
|
134
|
+
EventConfig,
|
|
135
|
+
CronConfig
|
|
136
|
+
} from '@motiadev/core'
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
This package is part of the Motia framework and is licensed under the same terms.
|
|
142
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
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.flowsConfigEndpoint = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const flowsConfigEndpoint = (app, baseDir) => {
|
|
10
|
+
const configPath = path_1.default.join(baseDir, 'motia-workbench.json');
|
|
11
|
+
app.post('/flows/:id/config', (req, res) => {
|
|
12
|
+
const newFlowConfig = req.body;
|
|
13
|
+
try {
|
|
14
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
15
|
+
fs_1.default.writeFileSync(configPath, JSON.stringify({}, null, 2));
|
|
16
|
+
}
|
|
17
|
+
const existingConfig = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
|
|
18
|
+
const updatedConfig = {
|
|
19
|
+
...existingConfig,
|
|
20
|
+
};
|
|
21
|
+
Object.entries(newFlowConfig).forEach(([flowName, filePathPositions]) => {
|
|
22
|
+
updatedConfig[flowName] = {
|
|
23
|
+
...(updatedConfig[flowName] || {}),
|
|
24
|
+
...filePathPositions,
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
fs_1.default.writeFileSync(configPath, JSON.stringify(updatedConfig, null, 2));
|
|
28
|
+
res.status(200).send({ message: 'Flow config saved successfully' });
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error('Error saving flow config:', error);
|
|
32
|
+
res.status(500).json({ error: 'Failed to save flow config' });
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
app.get('/flows/:id/config', (req, res) => {
|
|
36
|
+
const { id } = req.params;
|
|
37
|
+
try {
|
|
38
|
+
const file = fs_1.default.readFileSync(configPath, 'utf8');
|
|
39
|
+
const allFlowsConfig = JSON.parse(file);
|
|
40
|
+
const flowConfig = allFlowsConfig[id] || {};
|
|
41
|
+
res.status(200).send(flowConfig);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error('Error reading flow config:', error);
|
|
45
|
+
res.status(400).send({});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
exports.flowsConfigEndpoint = flowsConfigEndpoint;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.generateFlowsList = exports.flowsEndpoint = void 0;
|
|
7
7
|
const crypto_1 = require("crypto");
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
9
10
|
const guards_1 = require("./guards");
|
|
10
11
|
const get_step_language_1 = require("./get-step-language");
|
|
11
12
|
const flowsEndpoint = (lockedData, app) => {
|
|
@@ -36,6 +37,10 @@ const getNodeComponentPath = (filePath) => {
|
|
|
36
37
|
const tsxPath = filePathWithoutExtension + '.tsx';
|
|
37
38
|
return fs_1.default.existsSync(tsxPath) ? tsxPath : undefined;
|
|
38
39
|
};
|
|
40
|
+
const getRelativePath = (filePath) => {
|
|
41
|
+
const baseDir = process.cwd();
|
|
42
|
+
return path_1.default.relative(baseDir, filePath);
|
|
43
|
+
};
|
|
39
44
|
const createEdge = (sourceId, targetId, topic, label, variant, conditional) => ({
|
|
40
45
|
id: `${sourceId}-${targetId}`,
|
|
41
46
|
source: sourceId,
|
|
@@ -72,6 +77,7 @@ const createBaseStepResponse = (step, id) => ({
|
|
|
72
77
|
name: step.config.name,
|
|
73
78
|
description: step.config.description,
|
|
74
79
|
nodeComponentPath: getNodeComponentPath(step.filePath),
|
|
80
|
+
filePath: getRelativePath(step.filePath),
|
|
75
81
|
language: (0, get_step_language_1.getStepLanguage)(step.filePath),
|
|
76
82
|
});
|
|
77
83
|
const createApiStepResponse = (step, id) => {
|
package/dist/src/server.js
CHANGED
|
@@ -16,6 +16,7 @@ const steps_1 = require("./steps");
|
|
|
16
16
|
const call_step_file_1 = require("./call-step-file");
|
|
17
17
|
const LoggerFactory_1 = require("./LoggerFactory");
|
|
18
18
|
const generate_trace_id_1 = require("./generate-trace-id");
|
|
19
|
+
const flows_config_endpoint_1 = require("./flows-config-endpoint");
|
|
19
20
|
const createServer = async (lockedData, eventManager, state, config) => {
|
|
20
21
|
const printer = lockedData.printer;
|
|
21
22
|
const app = (0, express_1.default)();
|
|
@@ -103,6 +104,7 @@ const createServer = async (lockedData, eventManager, state, config) => {
|
|
|
103
104
|
allSteps.filter(guards_1.isApiStep).forEach(addRoute);
|
|
104
105
|
app.use(router);
|
|
105
106
|
(0, flows_endpoint_1.flowsEndpoint)(lockedData, app);
|
|
107
|
+
(0, flows_config_endpoint_1.flowsConfigEndpoint)(app, process.cwd());
|
|
106
108
|
server.on('error', (error) => {
|
|
107
109
|
console.error('Server error:', error);
|
|
108
110
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motiadev/core",
|
|
3
|
+
"description": "Core functionality for the Motia framework, providing the foundation for building event-driven workflows.",
|
|
3
4
|
"main": "dist/index.js",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
5
|
+
"version": "0.1.0-alpha.6",
|
|
5
6
|
"dependencies": {
|
|
6
7
|
"body-parser": "^1.20.3",
|
|
7
8
|
"colors": "^1.4.0",
|