motia 0.0.21 ā 0.0.23
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/src/cli.js +31 -0
- package/dist/src/create/index.js +2 -2
- package/dist/src/create-step/getAnswers.js +171 -0
- package/dist/src/create-step/index.js +47 -0
- package/dist/src/create-step/teamplateUtils.js +50 -0
- package/dist/src/create-step/templates/api/template.javascript.txt +25 -0
- package/dist/src/create-step/templates/api/template.python.txt +19 -0
- package/dist/src/create-step/templates/api/template.ruby.txt +22 -0
- package/dist/src/create-step/templates/api/template.typescript.txt +26 -0
- package/dist/src/create-step/templates/cron/template.javascript.txt +20 -0
- package/dist/src/create-step/templates/cron/template.python.txt +19 -0
- package/dist/src/create-step/templates/cron/template.ruby.txt +22 -0
- package/dist/src/create-step/templates/cron/template.type.txt +22 -0
- package/dist/src/create-step/templates/cron/template.typescript.txt +22 -0
- package/dist/src/create-step/templates/event/template.javascript.txt +27 -0
- package/dist/src/create-step/templates/event/template.python.txt +20 -0
- package/dist/src/create-step/templates/event/template.ruby.txt +22 -0
- package/dist/src/create-step/templates/event/template.typescript.txt +30 -0
- package/dist/src/create-step/templates/noop/template.javascript.txt +8 -0
- package/dist/src/create-step/templates/noop/template.python.txt +8 -0
- package/dist/src/create-step/templates/noop/template.ruby.txt +10 -0
- package/dist/src/create-step/templates/noop/template.typescript.txt +10 -0
- package/dist/src/create-step/templates/ui/api.step.txt +20 -0
- package/dist/src/create-step/templates/ui/cron.step.txt +15 -0
- package/dist/src/create-step/templates/ui/event.step.txt +15 -0
- package/dist/src/create-step/templates/ui/noop.step.txt +15 -0
- package/dist/src/create-step/templates/ui/overrides.js +26 -0
- package/dist/src/create-step/types.js +6 -0
- package/dist/src/create-step/utils.js +13 -0
- package/dist/src/generate-locked-data.js +5 -23
- package/dist/src/watcher.js +12 -15
- package/package.json +5 -3
- package/scripts/move-templates.sh +31 -17
package/dist/src/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
10
|
const defaultPort = 3000;
|
|
10
11
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
11
12
|
require('dotenv/config');
|
|
@@ -94,4 +95,34 @@ commander_1.program
|
|
|
94
95
|
process.exit(1);
|
|
95
96
|
}
|
|
96
97
|
});
|
|
98
|
+
const generate = commander_1.program.command('generate').description('Generate motia resources');
|
|
99
|
+
generate
|
|
100
|
+
.command('step')
|
|
101
|
+
.description('Create a new step with interactive prompts')
|
|
102
|
+
.option('-d, --dir <step file path>', 'The path relative to the steps directory, used to create the step file')
|
|
103
|
+
.action(async (arg) => {
|
|
104
|
+
const { createStep } = require('./create-step'); // eslint-disable-line @typescript-eslint/no-require-imports
|
|
105
|
+
await createStep({
|
|
106
|
+
stepFilePath: arg.dir,
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
const state = commander_1.program.command('state').description('Manage application state');
|
|
110
|
+
state
|
|
111
|
+
.command('list')
|
|
112
|
+
.description('List the current file state')
|
|
113
|
+
.action(async () => {
|
|
114
|
+
try {
|
|
115
|
+
const statePath = path_1.default.join(process.cwd(), '.motia', 'motia.state.json');
|
|
116
|
+
if (!fs_1.default.existsSync(statePath)) {
|
|
117
|
+
console.error('Error: State file not found at', statePath);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
const state = require(statePath); // eslint-disable-line @typescript-eslint/no-require-imports
|
|
121
|
+
console.log(JSON.stringify(state, null, 2));
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
97
128
|
commander_1.program.parse(process.argv);
|
package/dist/src/create/index.js
CHANGED
|
@@ -62,8 +62,8 @@ const installRequiredDependencies = async (packageManager, rootDir) => {
|
|
|
62
62
|
yarn: 'yarn add',
|
|
63
63
|
pnpm: 'pnpm add',
|
|
64
64
|
}[packageManager];
|
|
65
|
-
const dependencies = ['@motiadev/core', 'motia', '@motiadev/workbench', 'zod'].join(' ');
|
|
66
|
-
const devDependencies = ['ts-node@^10.9.2', 'typescript@^5.7.3'].join(' ');
|
|
65
|
+
const dependencies = ['@motiadev/core', 'motia', '@motiadev/workbench', 'zod', 'react@^19.0.0'].join(' ');
|
|
66
|
+
const devDependencies = ['ts-node@^10.9.2', 'typescript@^5.7.3', '@types/react@^18.3.18'].join(' ');
|
|
67
67
|
try {
|
|
68
68
|
await executeCommand(`${installCommand} ${dependencies}`, rootDir);
|
|
69
69
|
await executeCommand(`${installCommand} -D ${devDependencies}`, rootDir);
|
|
@@ -0,0 +1,171 @@
|
|
|
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.getStepAnswers = void 0;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
const colors_1 = __importDefault(require("colors"));
|
|
9
|
+
const types_1 = require("./types");
|
|
10
|
+
const getStepAnswers = async () => {
|
|
11
|
+
console.log('\nš ', colors_1.default.bold('Create a new Motia step\n'));
|
|
12
|
+
// Basic information prompts
|
|
13
|
+
const basicInfo = await inquirer_1.default.prompt([
|
|
14
|
+
{
|
|
15
|
+
type: 'input',
|
|
16
|
+
name: 'name',
|
|
17
|
+
message: 'Step name:',
|
|
18
|
+
validate: (input) => {
|
|
19
|
+
if (input.length === 0)
|
|
20
|
+
return 'Name is required';
|
|
21
|
+
if (!/^[a-zA-Z][a-zA-Z0-9-_]*$/.test(input)) {
|
|
22
|
+
return 'Name must start with a letter and contain only letters, numbers, hyphens, and underscores';
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: 'list',
|
|
29
|
+
name: 'type',
|
|
30
|
+
message: 'Select step type:',
|
|
31
|
+
choices: types_1.STEP_TYPES.map((type) => ({
|
|
32
|
+
name: type.toUpperCase(),
|
|
33
|
+
value: type,
|
|
34
|
+
})),
|
|
35
|
+
},
|
|
36
|
+
]);
|
|
37
|
+
let answers = { ...basicInfo };
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
const languageAnswer = {
|
|
40
|
+
type: 'list',
|
|
41
|
+
name: 'language',
|
|
42
|
+
message: 'Select language:',
|
|
43
|
+
choices: types_1.LANGUAGES.map((lang) => ({
|
|
44
|
+
name: lang.charAt(0).toUpperCase() + lang.slice(1),
|
|
45
|
+
value: lang,
|
|
46
|
+
})),
|
|
47
|
+
};
|
|
48
|
+
// Type-specific configuration prompts
|
|
49
|
+
if (answers.type === 'api') {
|
|
50
|
+
const apiConfig = await inquirer_1.default.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: 'list',
|
|
53
|
+
name: 'method',
|
|
54
|
+
message: 'HTTP method:',
|
|
55
|
+
choices: types_1.HTTP_METHODS,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
type: 'input',
|
|
59
|
+
name: 'path',
|
|
60
|
+
message: 'API path (e.g. /users):',
|
|
61
|
+
validate: (input) => {
|
|
62
|
+
if (!input.startsWith('/'))
|
|
63
|
+
return 'Path must start with /';
|
|
64
|
+
return true;
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
68
|
+
answers = { ...answers, ...apiConfig };
|
|
69
|
+
}
|
|
70
|
+
else if (answers.type === 'event') {
|
|
71
|
+
const eventConfig = await inquirer_1.default.prompt([
|
|
72
|
+
languageAnswer,
|
|
73
|
+
{
|
|
74
|
+
type: 'input',
|
|
75
|
+
name: 'subscriptions',
|
|
76
|
+
message: 'Event subscriptions (comma-separated):',
|
|
77
|
+
filter: (input) => input
|
|
78
|
+
.split(',')
|
|
79
|
+
.map((s) => s.trim())
|
|
80
|
+
.filter(Boolean),
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
answers = { ...answers, ...eventConfig };
|
|
84
|
+
}
|
|
85
|
+
else if (answers.type === 'cron') {
|
|
86
|
+
const cronConfig = await inquirer_1.default.prompt([
|
|
87
|
+
languageAnswer,
|
|
88
|
+
{
|
|
89
|
+
type: 'input',
|
|
90
|
+
name: 'cronExpression',
|
|
91
|
+
message: 'Cron expression:',
|
|
92
|
+
validate: (input) => {
|
|
93
|
+
if (!input)
|
|
94
|
+
return 'Cron expression is required';
|
|
95
|
+
const parts = input.split(' ');
|
|
96
|
+
if (parts.length !== 5)
|
|
97
|
+
return 'Invalid cron expression format';
|
|
98
|
+
return true;
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
]);
|
|
102
|
+
answers = { ...answers, ...cronConfig };
|
|
103
|
+
}
|
|
104
|
+
else if (answers.type === 'noop') {
|
|
105
|
+
const noopConfig = await inquirer_1.default.prompt([
|
|
106
|
+
languageAnswer,
|
|
107
|
+
{
|
|
108
|
+
type: 'input',
|
|
109
|
+
name: 'virtualEmits',
|
|
110
|
+
message: 'Virtual emits (comma-separated):',
|
|
111
|
+
filter: (input) => input
|
|
112
|
+
.split(',')
|
|
113
|
+
.map((s) => s.trim())
|
|
114
|
+
.filter(Boolean),
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'input',
|
|
118
|
+
name: 'virtualSubscribes',
|
|
119
|
+
message: 'Virtual subscribes (comma-separated):',
|
|
120
|
+
filter: (input) => input
|
|
121
|
+
.split(',')
|
|
122
|
+
.map((s) => s.trim())
|
|
123
|
+
.filter(Boolean),
|
|
124
|
+
},
|
|
125
|
+
]);
|
|
126
|
+
answers = { ...answers, ...noopConfig };
|
|
127
|
+
}
|
|
128
|
+
// Common configuration prompts
|
|
129
|
+
const commonConfig = await inquirer_1.default.prompt([
|
|
130
|
+
{
|
|
131
|
+
type: 'input',
|
|
132
|
+
name: 'flows',
|
|
133
|
+
message: 'Flow names (comma-separated):',
|
|
134
|
+
filter: (input) => input
|
|
135
|
+
.split(',')
|
|
136
|
+
.map((s) => s.trim())
|
|
137
|
+
.filter(Boolean),
|
|
138
|
+
validate: (input) => {
|
|
139
|
+
if (input.length === 0)
|
|
140
|
+
return 'At least one flow is required';
|
|
141
|
+
return true;
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'input',
|
|
146
|
+
name: 'emits',
|
|
147
|
+
message: 'Events to emit (comma-separated):',
|
|
148
|
+
filter: (input) => input
|
|
149
|
+
.split(',')
|
|
150
|
+
.map((s) => s.trim())
|
|
151
|
+
.filter(Boolean),
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
type: 'input',
|
|
155
|
+
name: 'description',
|
|
156
|
+
message: 'Step description:',
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
type: 'confirm',
|
|
160
|
+
name: 'createOverride',
|
|
161
|
+
message: 'Create UI component override?',
|
|
162
|
+
default: false,
|
|
163
|
+
},
|
|
164
|
+
]);
|
|
165
|
+
const nextAnswers = { ...answers, ...commonConfig };
|
|
166
|
+
return {
|
|
167
|
+
...nextAnswers,
|
|
168
|
+
language: nextAnswers.type === 'api' ? 'typescript' : nextAnswers.language,
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
exports.getStepAnswers = getStepAnswers;
|
|
@@ -0,0 +1,47 @@
|
|
|
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.createStep = createStep;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const colors_1 = __importDefault(require("colors"));
|
|
10
|
+
const teamplateUtils_1 = require("./teamplateUtils");
|
|
11
|
+
const overrides_1 = require("./templates/ui/overrides");
|
|
12
|
+
const getAnswers_1 = require("./getAnswers");
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
async function createStep(options) {
|
|
15
|
+
try {
|
|
16
|
+
const answers = await (0, getAnswers_1.getStepAnswers)();
|
|
17
|
+
// Create steps directory if it doesn't exist
|
|
18
|
+
const stepDir = path_1.default.join(process.cwd(), 'steps', options?.stepFilePath || '');
|
|
19
|
+
if (!fs_1.default.existsSync(stepDir)) {
|
|
20
|
+
fs_1.default.mkdirSync(stepDir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
// Create step file
|
|
23
|
+
const extension = (0, utils_1.getFileExtension)(answers.language);
|
|
24
|
+
const stepPath = path_1.default.join(stepDir, `${answers.name}${answers.type === 'api' ? '.api' : ''}.step${extension}`);
|
|
25
|
+
// Check if file already exists
|
|
26
|
+
if (fs_1.default.existsSync(stepPath)) {
|
|
27
|
+
console.error(colors_1.default.red(`\nā Error: Step file already exists at ${stepPath}`));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
// Generate and write step file
|
|
31
|
+
const stepContent = await (0, teamplateUtils_1.generateTemplate)(answers);
|
|
32
|
+
fs_1.default.writeFileSync(stepPath, stepContent);
|
|
33
|
+
console.log(colors_1.default.green(`\n⨠Created step file at ${stepPath}`));
|
|
34
|
+
// Create UI override if requested
|
|
35
|
+
if (answers.createOverride) {
|
|
36
|
+
const overridePath = path_1.default.join(stepDir, `${answers.name}.step.tsx`);
|
|
37
|
+
const overrideContent = await (0, overrides_1.generateOverride)(answers);
|
|
38
|
+
fs_1.default.writeFileSync(overridePath, overrideContent);
|
|
39
|
+
console.log(colors_1.default.green(`⨠Created UI override at ${overridePath}`));
|
|
40
|
+
}
|
|
41
|
+
console.log(colors_1.default.bold('\nš Step creation complete!'));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error(colors_1.default.red('\nā Error creating step:'), error);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -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.generateTemplate = generateTemplate;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Reads a template file and replaces variables
|
|
11
|
+
*/
|
|
12
|
+
async function readTemplate(templatePath, answers) {
|
|
13
|
+
const content = await fs_1.promises.readFile(templatePath, 'utf8');
|
|
14
|
+
return replaceTemplateVariables(content, answers);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Replaces template variables with actual values
|
|
18
|
+
*/
|
|
19
|
+
function replaceTemplateVariables(content, answers) {
|
|
20
|
+
const replacements = {
|
|
21
|
+
STEP_NAME: answers.name,
|
|
22
|
+
DESCRIPTION: answers.description || '',
|
|
23
|
+
FLOWS: JSON.stringify(answers.flows),
|
|
24
|
+
EMITS: JSON.stringify(answers.emits),
|
|
25
|
+
METHOD: answers.method || '',
|
|
26
|
+
PATH: answers.path || '',
|
|
27
|
+
SUBSCRIPTIONS: JSON.stringify(answers.subscriptions || []),
|
|
28
|
+
CRON_EXPRESSION: answers.cronExpression || '',
|
|
29
|
+
VIRTUAL_EMITS: JSON.stringify(answers.virtualEmits || []),
|
|
30
|
+
VIRTUAL_SUBSCRIBES: JSON.stringify(answers.virtualSubscribes || []),
|
|
31
|
+
};
|
|
32
|
+
return Object.entries(replacements).reduce((content, [key, value]) => {
|
|
33
|
+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
|
|
34
|
+
return content.replace(regex, String(value));
|
|
35
|
+
}, content);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generates the appropriate template based on language and type
|
|
39
|
+
*/
|
|
40
|
+
async function generateTemplate(answers) {
|
|
41
|
+
const templateDir = path_1.default.join(__dirname, 'templates', answers.type);
|
|
42
|
+
const templateFile = `template.${answers.language}.txt`;
|
|
43
|
+
const templatePath = path_1.default.join(templateDir, templateFile);
|
|
44
|
+
try {
|
|
45
|
+
return await readTemplate(templatePath, answers);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw new Error(`Failed to generate template: ${error}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { z } = require('zod')
|
|
2
|
+
|
|
3
|
+
export const config = {
|
|
4
|
+
type: 'api',
|
|
5
|
+
name: '{{STEP_NAME}}',
|
|
6
|
+
description: '{{DESCRIPTION}}',
|
|
7
|
+
path: '{{PATH}}',
|
|
8
|
+
method: '{{METHOD}}',
|
|
9
|
+
emits: {{EMITS}},
|
|
10
|
+
flows: {{FLOWS}},
|
|
11
|
+
bodySchema: z.object({
|
|
12
|
+
// Add your schema here
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const handler = async (req, { logger, emit }) => {
|
|
17
|
+
logger.info('Processing {{STEP_NAME}}', req)
|
|
18
|
+
|
|
19
|
+
// Add your handler logic here
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
status: 200,
|
|
23
|
+
body: { message: 'Success' }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
config = {
|
|
2
|
+
"type": "api",
|
|
3
|
+
"name": "{{STEP_NAME}}",
|
|
4
|
+
"description": "{{DESCRIPTION}}",
|
|
5
|
+
"path": "{{PATH}}",
|
|
6
|
+
"method": "{{METHOD}}",
|
|
7
|
+
"emits": {{EMITS}},
|
|
8
|
+
"flows": {{FLOWS}}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async def handler(req, context):
|
|
12
|
+
context.logger.info("Processing {{STEP_NAME}}", req)
|
|
13
|
+
|
|
14
|
+
# Add your handler logic here
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
"status": 200,
|
|
18
|
+
"body": {"message": "Success"}
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
def config
|
|
2
|
+
{
|
|
3
|
+
type: 'api',
|
|
4
|
+
name: '{{STEP_NAME}}',
|
|
5
|
+
description: '{{DESCRIPTION}}',
|
|
6
|
+
path: '{{PATH}}',
|
|
7
|
+
method: '{{METHOD}}',
|
|
8
|
+
emits: {{EMITS}},
|
|
9
|
+
flows: {{FLOWS}}
|
|
10
|
+
}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def handler(req, context)
|
|
14
|
+
context.logger.info('Processing {{STEP_NAME}}', req)
|
|
15
|
+
|
|
16
|
+
# Add your handler logic here
|
|
17
|
+
|
|
18
|
+
{
|
|
19
|
+
status: 200,
|
|
20
|
+
body: { message: 'Success' }
|
|
21
|
+
}
|
|
22
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ApiRouteConfig, StepHandler } from '@motiadev/core'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
export const config: ApiRouteConfig = {
|
|
5
|
+
type: 'api',
|
|
6
|
+
name: '{{STEP_NAME}}',
|
|
7
|
+
description: '{{DESCRIPTION}}',
|
|
8
|
+
path: '{{PATH}}',
|
|
9
|
+
method: '{{METHOD}}',
|
|
10
|
+
emits: {{EMITS}},
|
|
11
|
+
flows: {{FLOWS}},
|
|
12
|
+
bodySchema: z.object({
|
|
13
|
+
// Add your schema here
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const handler: StepHandler<typeof config> = async (req, { logger, emit }) => {
|
|
18
|
+
logger.info('Processing {{STEP_NAME}}', req)
|
|
19
|
+
|
|
20
|
+
// Add your handler logic here
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
status: 200,
|
|
24
|
+
body: { message: 'Success' }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const config = {
|
|
2
|
+
type: 'cron',
|
|
3
|
+
name: '{{STEP_NAME}}',
|
|
4
|
+
description: '{{DESCRIPTION}}',
|
|
5
|
+
cron: '{{CRON_EXPRESSION}}',
|
|
6
|
+
emits: {{EMITS}},
|
|
7
|
+
flows: {{FLOWS}}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const handler = async ({ logger, emit }) => {
|
|
11
|
+
logger.info('Running {{STEP_NAME}} cron job')
|
|
12
|
+
|
|
13
|
+
// Add your cron logic here
|
|
14
|
+
|
|
15
|
+
// Example emit
|
|
16
|
+
// await emit({
|
|
17
|
+
// type: 'event-type',
|
|
18
|
+
// data: {}
|
|
19
|
+
// })
|
|
20
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
config = {
|
|
2
|
+
"type": "cron",
|
|
3
|
+
"name": "{{STEP_NAME}}",
|
|
4
|
+
"description": "{{DESCRIPTION}}",
|
|
5
|
+
"cron": "{{CRON_EXPRESSION}}",
|
|
6
|
+
"emits": {{EMITS}},
|
|
7
|
+
"flows": {{FLOWS}}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async def handler(context):
|
|
11
|
+
context.logger.info("Running {{STEP_NAME}} cron job")
|
|
12
|
+
|
|
13
|
+
# Add your cron logic here
|
|
14
|
+
|
|
15
|
+
# Example emit
|
|
16
|
+
# await context.emit({
|
|
17
|
+
# "type": "event-type",
|
|
18
|
+
# "data": {}
|
|
19
|
+
# })
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
def config
|
|
2
|
+
{
|
|
3
|
+
type: 'cron',
|
|
4
|
+
name: '{{STEP_NAME}}',
|
|
5
|
+
description: '{{DESCRIPTION}}',
|
|
6
|
+
cron: '{{CRON_EXPRESSION}}',
|
|
7
|
+
emits: {{EMITS}},
|
|
8
|
+
flows: {{FLOWS}}
|
|
9
|
+
}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def handler(context)
|
|
13
|
+
context.logger.info('Running {{STEP_NAME}} cron job')
|
|
14
|
+
|
|
15
|
+
# Add your cron logic here
|
|
16
|
+
|
|
17
|
+
# Example emit
|
|
18
|
+
# context.emit({
|
|
19
|
+
# type: 'event-type',
|
|
20
|
+
# data: {}
|
|
21
|
+
# })
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CronConfig, StepHandler } from '@motiadev/core'
|
|
2
|
+
|
|
3
|
+
export const config: CronConfig = {
|
|
4
|
+
type: 'cron',
|
|
5
|
+
name: '{{STEP_NAME}}',
|
|
6
|
+
description: '{{DESCRIPTION}}',
|
|
7
|
+
cron: '{{CRON_EXPRESSION}}',
|
|
8
|
+
emits: {{EMITS}},
|
|
9
|
+
flows: {{FLOWS}}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const handler: StepHandler<typeof config> = async ({ logger, emit }) => {
|
|
13
|
+
logger.info('Running {{STEP_NAME}} cron job')
|
|
14
|
+
|
|
15
|
+
// Add your cron logic here
|
|
16
|
+
|
|
17
|
+
// Example emit
|
|
18
|
+
// await emit({
|
|
19
|
+
// type: 'event-type',
|
|
20
|
+
// data: {}
|
|
21
|
+
// })
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CronConfig, FlowContext } from '@motiadev/core'
|
|
2
|
+
|
|
3
|
+
export const config = {
|
|
4
|
+
type: 'cron',
|
|
5
|
+
name: '{{STEP_NAME}}',
|
|
6
|
+
description: '{{DESCRIPTION}}',
|
|
7
|
+
cron: '{{CRON_EXPRESSION}}',
|
|
8
|
+
emits: {{EMITS}},
|
|
9
|
+
flows: {{FLOWS}}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const handler = async ({ logger, emit }: FlowContext) => {
|
|
13
|
+
logger.info('Running {{STEP_NAME}} cron job')
|
|
14
|
+
|
|
15
|
+
// Add your cron logic here
|
|
16
|
+
|
|
17
|
+
// Example emit
|
|
18
|
+
// await emit({
|
|
19
|
+
// type: 'event-type',
|
|
20
|
+
// data: {}
|
|
21
|
+
// })
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const { z } = require('zod')
|
|
2
|
+
|
|
3
|
+
const inputSchema = z.object({
|
|
4
|
+
// Add your schema here
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
export const config = {
|
|
8
|
+
type: 'event',
|
|
9
|
+
name: '{{STEP_NAME}}',
|
|
10
|
+
description: '{{DESCRIPTION}}',
|
|
11
|
+
subscribes: {{SUBSCRIPTIONS}},
|
|
12
|
+
emits: {{EMITS}},
|
|
13
|
+
input: inputSchema,
|
|
14
|
+
flows: {{FLOWS}}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const handler = async (input, { logger, emit }) => {
|
|
18
|
+
logger.info('Processing {{STEP_NAME}}', input)
|
|
19
|
+
|
|
20
|
+
// Add your handler logic here
|
|
21
|
+
|
|
22
|
+
// Example emit
|
|
23
|
+
// await emit({
|
|
24
|
+
// type: 'event-type',
|
|
25
|
+
// data: {}
|
|
26
|
+
// })
|
|
27
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
config = {
|
|
2
|
+
"type": "event",
|
|
3
|
+
"name": "{{STEP_NAME}}",
|
|
4
|
+
"description": "{{DESCRIPTION}}",
|
|
5
|
+
"subscribes": {{SUBSCRIPTIONS}},
|
|
6
|
+
"emits": {{EMITS}},
|
|
7
|
+
"flows": {{FLOWS}},
|
|
8
|
+
"input": None, # No schema validation in Python
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async def handler(args, ctx):
|
|
12
|
+
ctx.logger.info('Processing {{STEP_NAME}}', args)
|
|
13
|
+
|
|
14
|
+
# Add your handler logic here
|
|
15
|
+
|
|
16
|
+
# Add your handler logic here
|
|
17
|
+
# await ctx.emit({
|
|
18
|
+
# type: 'event-type',
|
|
19
|
+
# data: {}
|
|
20
|
+
# })
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
def config
|
|
2
|
+
{
|
|
3
|
+
type: 'event',
|
|
4
|
+
name: '{{STEP_NAME}}',
|
|
5
|
+
description: '{{DESCRIPTION}}',
|
|
6
|
+
subscribes: {{SUBSCRIPTIONS}},
|
|
7
|
+
emits: {{EMITS}},
|
|
8
|
+
flows: {{FLOWS}}
|
|
9
|
+
}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def handler(input, context)
|
|
13
|
+
context.logger.info('Processing {{STEP_NAME}}', input)
|
|
14
|
+
|
|
15
|
+
# Add your handler logic here
|
|
16
|
+
|
|
17
|
+
# Example emit
|
|
18
|
+
# context.emit({
|
|
19
|
+
# type: 'event-type',
|
|
20
|
+
# data: {}
|
|
21
|
+
# })
|
|
22
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { EventConfig, StepHandler } from '@motiadev/core'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
type Input = typeof inputSchema
|
|
5
|
+
|
|
6
|
+
const inputSchema = z.object({
|
|
7
|
+
// Add your schema here
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export const config: EventConfig = {
|
|
11
|
+
type: 'event',
|
|
12
|
+
name: '{{STEP_NAME}}',
|
|
13
|
+
description: '{{DESCRIPTION}}',
|
|
14
|
+
subscribes: {{SUBSCRIPTIONS}},
|
|
15
|
+
emits: {{EMITS}},
|
|
16
|
+
input: inputSchema,
|
|
17
|
+
flows: {{FLOWS}}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const handler: StepHandler<typeof config> = async (input, { logger, emit }) => {
|
|
21
|
+
logger.info('Processing {{STEP_NAME}}', input)
|
|
22
|
+
|
|
23
|
+
// Add your handler logic here
|
|
24
|
+
|
|
25
|
+
// Example emit
|
|
26
|
+
// await emit({
|
|
27
|
+
// type: 'event-type',
|
|
28
|
+
// data: {}
|
|
29
|
+
// })
|
|
30
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NoopConfig } from '@motiadev/core'
|
|
2
|
+
|
|
3
|
+
export const config: NoopConfig = {
|
|
4
|
+
type: 'noop',
|
|
5
|
+
name: '{{STEP_NAME}}',
|
|
6
|
+
description: '{{DESCRIPTION}}',
|
|
7
|
+
virtualEmits: {{VIRTUAL_EMITS}},
|
|
8
|
+
virtualSubscribes: {{VIRTUAL_SUBSCRIBES}},
|
|
9
|
+
flows: {{FLOWS}}
|
|
10
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { ApiNode, Button, ApiNodeProps } from '@motiadev/workbench'
|
|
3
|
+
|
|
4
|
+
export const Node: React.FC<ApiNodeProps> = ({ data }) => {
|
|
5
|
+
const doSomething = () => {
|
|
6
|
+
window.alert('Replace this with your custom logic')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<ApiNode data={{ ...data, description: undefined }}>
|
|
12
|
+
<div className="flex flex-row gap-4">
|
|
13
|
+
<div className="flex flex-col items-center text-sm">{data.description}</div>
|
|
14
|
+
<div className="flex flex-col items-end text-sm">
|
|
15
|
+
<Button onClick={doSomething}>Play</Button>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</ApiNode>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { BaseNode, Button, CronNodeProps } from '@motiadev/workbench'
|
|
3
|
+
|
|
4
|
+
export const Node: React.FC<CronNodeProps> = ({ data }) => {
|
|
5
|
+
const doSomething = () => {
|
|
6
|
+
window.alert('Replace this with your custom logic')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<BaseNode title="{{STEP_NAME}}" variant="noop" {...data} disableTargetHandle>
|
|
12
|
+
<Button onClick={doSomething}>Click me</Button>
|
|
13
|
+
</BaseNode>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { BaseNode, Button, EventNodeProps } from '@motiadev/workbench'
|
|
3
|
+
|
|
4
|
+
export const Node: React.FC<EventNodeProps> = ({ data }) => {
|
|
5
|
+
const doSomething = () => {
|
|
6
|
+
window.alert('Replace this with your custom logic')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<BaseNode title="{{STEP_NAME}}" variant="noop" {...data} disableTargetHandle>
|
|
12
|
+
<Button onClick={doSomething}>Click me</Button>
|
|
13
|
+
</BaseNode>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { BaseNode, Button, NoopNodeProps } from '@motiadev/workbench'
|
|
3
|
+
|
|
4
|
+
export const Node: React.FC<NoopNodeProps> = ({ data }) => {
|
|
5
|
+
const doSomething = () => {
|
|
6
|
+
window.alert('Replace this with your custom logic')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<BaseNode title="{{STEP_NAME}}" variant="noop" {...data} disableTargetHandle>
|
|
12
|
+
<Button onClick={doSomething}>Click me</Button>
|
|
13
|
+
</BaseNode>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
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.generateOverride = generateOverride;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Generates a React component override for the step
|
|
11
|
+
*/
|
|
12
|
+
async function generateOverride(answers) {
|
|
13
|
+
const templatePath = path_1.default.join(__dirname, `${answers.type}.step.txt`);
|
|
14
|
+
const content = await fs_1.promises.readFile(templatePath, 'utf8');
|
|
15
|
+
const replacements = {
|
|
16
|
+
STEP_NAME: answers.name,
|
|
17
|
+
DESCRIPTION: answers.description || '',
|
|
18
|
+
TYPE: answers.type,
|
|
19
|
+
FLOWS: JSON.stringify(answers.flows),
|
|
20
|
+
EMITS: JSON.stringify(answers.emits),
|
|
21
|
+
};
|
|
22
|
+
return Object.entries(replacements).reduce((content, [key, value]) => {
|
|
23
|
+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
|
|
24
|
+
return content.replace(regex, String(value));
|
|
25
|
+
}, content);
|
|
26
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HTTP_METHODS = exports.LANGUAGES = exports.STEP_TYPES = void 0;
|
|
4
|
+
exports.STEP_TYPES = ['api', 'event', 'cron', 'noop'];
|
|
5
|
+
exports.LANGUAGES = ['typescript', 'javascript', 'python', 'ruby'];
|
|
6
|
+
exports.HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE'];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFileExtension = void 0;
|
|
4
|
+
const getFileExtension = (language) => {
|
|
5
|
+
const extensions = {
|
|
6
|
+
typescript: '.ts',
|
|
7
|
+
javascript: '.js',
|
|
8
|
+
python: '.py',
|
|
9
|
+
ruby: '.rb',
|
|
10
|
+
};
|
|
11
|
+
return extensions[language];
|
|
12
|
+
};
|
|
13
|
+
exports.getFileExtension = getFileExtension;
|
|
@@ -3,45 +3,28 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.generateLockedData =
|
|
6
|
+
exports.generateLockedData = void 0;
|
|
7
7
|
const core_1 = require("@motiadev/core");
|
|
8
8
|
const crypto_1 = require("crypto");
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const yaml_1 = __importDefault(require("yaml"));
|
|
12
11
|
const version = `${(0, crypto_1.randomUUID)()}:${Math.floor(Date.now() / 1000)}`;
|
|
13
|
-
const baseFlowRegex = new RegExp(/flows"?\s?.*\s*\[([^\]]+)\]/);
|
|
14
|
-
// Helper function to read config.yml
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
-
const readConfig = (configPath) => {
|
|
17
|
-
if (!fs_1.default.existsSync(configPath)) {
|
|
18
|
-
console.warn(`Config file not found at ${configPath}`);
|
|
19
|
-
return {};
|
|
20
|
-
}
|
|
21
|
-
const configContent = fs_1.default.readFileSync(configPath, 'utf-8');
|
|
22
|
-
return yaml_1.default.parse(configContent);
|
|
23
|
-
};
|
|
24
|
-
exports.readConfig = readConfig;
|
|
25
12
|
// Helper function to recursively collect flow data
|
|
26
|
-
const collectFlows = async (baseDir) => {
|
|
13
|
+
const collectFlows = async (baseDir, lockedData) => {
|
|
27
14
|
const folderItems = fs_1.default.readdirSync(baseDir, { withFileTypes: true });
|
|
28
15
|
let steps = [];
|
|
29
16
|
for (const item of folderItems) {
|
|
30
17
|
const filePath = path_1.default.join(baseDir, item.name);
|
|
31
18
|
if (item.isDirectory()) {
|
|
32
|
-
steps = steps.concat(await collectFlows(filePath));
|
|
19
|
+
steps = steps.concat(await collectFlows(filePath, lockedData));
|
|
33
20
|
}
|
|
34
21
|
else if (item.name.match(/\.step\.(ts|js|py|rb)$/)) {
|
|
35
|
-
const fileContent = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
36
|
-
const flowMatch = fileContent.match(baseFlowRegex);
|
|
37
22
|
const config = await (0, core_1.getStepConfig)(filePath);
|
|
38
23
|
if (!config) {
|
|
39
24
|
console.warn(`No config found in step ${filePath}, step skipped`);
|
|
40
25
|
continue;
|
|
41
26
|
}
|
|
42
|
-
|
|
43
|
-
steps.push({ filePath, version, config });
|
|
44
|
-
}
|
|
27
|
+
lockedData.createStep({ filePath, version, config });
|
|
45
28
|
}
|
|
46
29
|
}
|
|
47
30
|
return steps;
|
|
@@ -52,9 +35,8 @@ const generateLockedData = async (projectDir) => {
|
|
|
52
35
|
* NOTE: right now for performance and simplicity let's enforce a folder,
|
|
53
36
|
* but we might want to remove this and scan the entire current directory
|
|
54
37
|
*/
|
|
55
|
-
const sourceSteps = await collectFlows(path_1.default.join(projectDir, 'steps'));
|
|
56
38
|
const lockedData = new core_1.LockedData(projectDir);
|
|
57
|
-
|
|
39
|
+
await collectFlows(path_1.default.join(projectDir, 'steps'), lockedData);
|
|
58
40
|
return lockedData;
|
|
59
41
|
}
|
|
60
42
|
catch (error) {
|
package/dist/src/watcher.js
CHANGED
|
@@ -30,9 +30,10 @@ class Watcher {
|
|
|
30
30
|
console.warn(`No step create handler, step skipped`);
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
const config = await (0, core_1.getStepConfig)(path)
|
|
33
|
+
const config = await (0, core_1.getStepConfig)(path).catch((err) => {
|
|
34
|
+
console.error(err);
|
|
35
|
+
});
|
|
34
36
|
if (!config) {
|
|
35
|
-
console.warn(`No config found in step ${path}, step skipped`);
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
39
|
const version = `${(0, crypto_1.randomUUID)()}:${Math.floor(Date.now() / 1000)}`;
|
|
@@ -40,14 +41,11 @@ class Watcher {
|
|
|
40
41
|
this.stepCreateHandler?.(step);
|
|
41
42
|
}
|
|
42
43
|
async onFileChange(path) {
|
|
43
|
-
|
|
44
|
-
console.
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
const config = await (0, core_1.getStepConfig)(path);
|
|
44
|
+
const config = await (0, core_1.getStepConfig)(path).catch((err) => {
|
|
45
|
+
console.error(err);
|
|
46
|
+
});
|
|
48
47
|
const step = this.findStep(path);
|
|
49
48
|
if (!step && !config) {
|
|
50
|
-
console.warn(`Step ${path} not found, step skipped`);
|
|
51
49
|
return;
|
|
52
50
|
}
|
|
53
51
|
// didn't have a step, but now we have a config
|
|
@@ -67,10 +65,6 @@ class Watcher {
|
|
|
67
65
|
}
|
|
68
66
|
}
|
|
69
67
|
async onFileDelete(path) {
|
|
70
|
-
if (!this.stepDeleteHandler) {
|
|
71
|
-
console.warn(`No step delete handler, step skipped`);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
68
|
const step = this.findStep(path);
|
|
75
69
|
if (!step) {
|
|
76
70
|
console.warn(`Step ${path} not found, step skipped`);
|
|
@@ -81,9 +75,12 @@ class Watcher {
|
|
|
81
75
|
init() {
|
|
82
76
|
this.watcher = chokidar_1.default
|
|
83
77
|
.watch(this.dir, { persistent: true, ignoreInitial: true })
|
|
84
|
-
.on('add', (path) => this.onFileAdd(path))
|
|
85
|
-
.on('change', (path) => this.onFileChange(path))
|
|
86
|
-
.on('unlink', (path) => this.onFileDelete(path));
|
|
78
|
+
.on('add', (path) => this.isStepFile(path) && this.onFileAdd(path))
|
|
79
|
+
.on('change', (path) => this.isStepFile(path) && this.onFileChange(path))
|
|
80
|
+
.on('unlink', (path) => this.isStepFile(path) && this.onFileDelete(path));
|
|
81
|
+
}
|
|
82
|
+
isStepFile(path) {
|
|
83
|
+
return /\.step\.[^.]+$/.test(path) && !/\.tsx$/.test(path);
|
|
87
84
|
}
|
|
88
85
|
async stop() {
|
|
89
86
|
if (this.watcher) {
|
package/package.json
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "motia",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bin": {
|
|
6
6
|
"motia": "dist/src/cli.js"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"chokidar": "^4.0.3",
|
|
10
|
+
"colors": "^1.4.0",
|
|
10
11
|
"commander": "^13.0.0",
|
|
11
12
|
"dotenv": "^16.4.7",
|
|
12
13
|
"figlet": "^1.8.0",
|
|
14
|
+
"inquirer": "^12.4.1",
|
|
13
15
|
"ts-node": "^10.9.2",
|
|
14
16
|
"yaml": "^2.7.0",
|
|
15
|
-
"@motiadev/core": "0.0.
|
|
16
|
-
"@motiadev/workbench": "0.0.
|
|
17
|
+
"@motiadev/core": "0.0.23",
|
|
18
|
+
"@motiadev/workbench": "0.0.23"
|
|
17
19
|
},
|
|
18
20
|
"devDependencies": {
|
|
19
21
|
"@types/figlet": "^1.7.0",
|
|
@@ -1,20 +1,34 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
|
+
copy_templates() {
|
|
4
|
+
local src_dir="$1"
|
|
5
|
+
local dest_dir="$2"
|
|
6
|
+
|
|
7
|
+
# Create the destination directory if it doesn't exist
|
|
8
|
+
mkdir -p "$dest_dir"
|
|
9
|
+
|
|
10
|
+
# Copy all .txt files while preserving the directory structure
|
|
11
|
+
find "$src_dir" -type f -name "*.txt" | while read -r file; do
|
|
12
|
+
# Get the relative path of the file
|
|
13
|
+
rel_path="${file#$src_dir/}"
|
|
14
|
+
# Create the destination directory for the file
|
|
15
|
+
mkdir -p "$dest_dir/$(dirname "$rel_path")"
|
|
16
|
+
# Copy the file to the destination directory
|
|
17
|
+
cp "$file" "$dest_dir/$rel_path"
|
|
18
|
+
done
|
|
19
|
+
|
|
20
|
+
echo "All .txt files from $src_dir have been copied successfully to $dest_dir."
|
|
21
|
+
}
|
|
22
|
+
|
|
3
23
|
# Define source and destination directories
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
mkdir -p "$DEST_DIR/$(dirname "$rel_path")"
|
|
16
|
-
# Copy the file to the destination directory
|
|
17
|
-
cp "$file" "$DEST_DIR/$rel_path"
|
|
18
|
-
done
|
|
19
|
-
|
|
20
|
-
echo "All .txt files have been copied successfully."
|
|
24
|
+
CREATE_TEMPLATES_SRC_DIR="$(dirname "$0")/../src/create/templates"
|
|
25
|
+
CREATE_TEMPLATES_DEST_DIR="$(dirname "$0")/../dist/src/create/templates"
|
|
26
|
+
|
|
27
|
+
# Call the function with the directories
|
|
28
|
+
copy_templates "$CREATE_TEMPLATES_SRC_DIR" "$CREATE_TEMPLATES_DEST_DIR"
|
|
29
|
+
|
|
30
|
+
CREATE_STEP_TEMPLATES_SRC_DIR="$(dirname "$0")/../src/create-step/templates"
|
|
31
|
+
CREATE_STEP_TEMPLATES_DEST_DIR="$(dirname "$0")/../dist/src/create-step/templates"
|
|
32
|
+
|
|
33
|
+
# Call the function with the directories
|
|
34
|
+
copy_templates "$CREATE_STEP_TEMPLATES_SRC_DIR" "$CREATE_STEP_TEMPLATES_DEST_DIR"
|