motia 0.5.11-beta.120-357906 → 0.5.11-beta.120-207545
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/cjs/cloud/build/builders/node/index.js +4 -1
- package/dist/cjs/cloud/build/builders/python/index.d.ts +1 -2
- package/dist/cjs/cloud/build/builders/python/index.js +37 -37
- package/dist/cjs/cloud/build/builders/python/uv-packager.d.ts +1 -2
- package/dist/cjs/cloud/build/builders/python/uv-packager.js +38 -37
- package/dist/cjs/cloud/cli/deploy.js +8 -4
- package/dist/cjs/cloud/endpoints.d.ts +2 -0
- package/dist/cjs/cloud/endpoints.js +102 -0
- package/dist/cjs/cloud/new-deployment/cloud-api/create-deployment.d.ts +3 -1
- package/dist/cjs/cloud/new-deployment/cloud-api/index.d.ts +3 -1
- package/dist/cjs/cloud/new-deployment/listeners/streaming-deployment-listener.d.ts +44 -0
- package/dist/cjs/cloud/new-deployment/listeners/streaming-deployment-listener.js +278 -0
- package/dist/cjs/cloud/new-deployment/streams/deployment-stream.d.ts +46 -0
- package/dist/cjs/cloud/new-deployment/streams/deployment-stream.js +108 -0
- package/dist/cjs/create/templates/python/steps/state_audit_cron_step.py.txt +1 -1
- package/dist/cjs/create/templates/typescript/steps/state-audit-cron.step.ts.txt +1 -1
- package/dist/cjs/cursor-rules/index.js +32 -3
- package/dist/cjs/dev.js +3 -1
- package/dist/cjs/install.js +5 -0
- package/dist/cjs/utils/ensure-uv.d.ts +1 -0
- package/dist/cjs/utils/ensure-uv.js +81 -0
- package/dist/esm/cloud/build/builders/node/index.js +4 -1
- package/dist/esm/cloud/build/builders/python/index.d.ts +1 -2
- package/dist/esm/cloud/build/builders/python/index.js +38 -38
- package/dist/esm/cloud/build/builders/python/uv-packager.d.ts +1 -2
- package/dist/esm/cloud/build/builders/python/uv-packager.js +38 -37
- package/dist/esm/cloud/cli/deploy.js +8 -4
- package/dist/esm/cloud/endpoints.d.ts +2 -0
- package/dist/esm/cloud/endpoints.js +98 -0
- package/dist/esm/cloud/new-deployment/cloud-api/create-deployment.d.ts +3 -1
- package/dist/esm/cloud/new-deployment/cloud-api/index.d.ts +3 -1
- package/dist/esm/cloud/new-deployment/listeners/streaming-deployment-listener.d.ts +44 -0
- package/dist/esm/cloud/new-deployment/listeners/streaming-deployment-listener.js +274 -0
- package/dist/esm/cloud/new-deployment/streams/deployment-stream.d.ts +46 -0
- package/dist/esm/cloud/new-deployment/streams/deployment-stream.js +103 -0
- package/dist/esm/create/templates/python/steps/state_audit_cron_step.py.txt +1 -1
- package/dist/esm/create/templates/typescript/steps/state-audit-cron.step.ts.txt +1 -1
- package/dist/esm/cursor-rules/index.js +32 -3
- package/dist/esm/dev.js +3 -1
- package/dist/esm/install.js +5 -0
- package/dist/esm/utils/ensure-uv.d.ts +1 -0
- package/dist/esm/utils/ensure-uv.js +77 -0
- package/dist/types/cloud/build/builders/python/index.d.ts +1 -2
- package/dist/types/cloud/build/builders/python/uv-packager.d.ts +1 -2
- package/dist/types/cloud/endpoints.d.ts +2 -0
- package/dist/types/cloud/new-deployment/cloud-api/create-deployment.d.ts +3 -1
- package/dist/types/cloud/new-deployment/cloud-api/index.d.ts +3 -1
- package/dist/types/cloud/new-deployment/listeners/streaming-deployment-listener.d.ts +44 -0
- package/dist/types/cloud/new-deployment/streams/deployment-stream.d.ts +46 -0
- package/dist/types/utils/ensure-uv.d.ts +1 -0
- package/package.json +4 -4
- package/dist/cjs/utils/uv-install.d.ts +0 -6
- package/dist/cjs/utils/uv-install.js +0 -129
- package/dist/dot-files/.cursor/rules/ai-agent-patterns.mdc +0 -725
- package/dist/dot-files/.cursor/rules/api-design-patterns.mdc +0 -740
- package/dist/dot-files/.cursor/rules/api-steps.mdc +0 -230
- package/dist/dot-files/.cursor/rules/architecture.mdc +0 -189
- package/dist/dot-files/.cursor/rules/authentication-patterns.mdc +0 -620
- package/dist/dot-files/.cursor/rules/background-job-patterns.mdc +0 -628
- package/dist/dot-files/.cursor/rules/complete-application-patterns.mdc +0 -433
- package/dist/dot-files/.cursor/rules/complete-backend-generator.mdc +0 -415
- package/dist/dot-files/.cursor/rules/cron-steps.mdc +0 -257
- package/dist/dot-files/.cursor/rules/event-steps.mdc +0 -504
- package/dist/dot-files/.cursor/rules/instructions.mdc +0 -15
- package/dist/dot-files/.cursor/rules/multi-language-workflows.mdc +0 -1059
- package/dist/dot-files/.cursor/rules/noop-steps.mdc +0 -57
- package/dist/dot-files/.cursor/rules/production-deployment.mdc +0 -668
- package/dist/dot-files/.cursor/rules/realtime-streaming.mdc +0 -656
- package/dist/dot-files/.cursor/rules/state-management.mdc +0 -371
- package/dist/dot-files/.cursor/rules/steps.mdc +0 -373
- package/dist/dot-files/.cursor/rules/testing.mdc +0 -329
- package/dist/dot-files/.cursor/rules/typescript.mdc +0 -409
- package/dist/dot-files/.cursor/rules/ui-steps.mdc +0 -90
- package/dist/dot-files/.cursor/rules/workflow-patterns.mdc +0 -938
- package/dist/dot-files/AGENTS.md +0 -397
- package/dist/dot-files/CLAUDE.md +0 -1032
- package/dist/dot-files/README.md +0 -58
- package/dist/esm/utils/uv-install.d.ts +0 -6
- package/dist/esm/utils/uv-install.js +0 -122
- package/dist/types/utils/uv-install.d.ts +0 -6
|
@@ -68,7 +68,10 @@ class NodeBuilder {
|
|
|
68
68
|
async buildApiSteps(steps) {
|
|
69
69
|
const relativePath = path_1.default.relative(constants_1.distDir, this.builder.projectDir);
|
|
70
70
|
const getStepPath = (step) => {
|
|
71
|
-
return step.filePath
|
|
71
|
+
return step.filePath
|
|
72
|
+
.replace(this.builder.projectDir, relativePath)
|
|
73
|
+
.replace(/(.*)\.(ts|js)$/, '$1.js')
|
|
74
|
+
.replace(/\\/g, '/');
|
|
72
75
|
};
|
|
73
76
|
const file = fs_1.default
|
|
74
77
|
.readFileSync(path_1.default.join(__dirname, 'router-template.ts'), 'utf-8')
|
|
@@ -5,9 +5,7 @@ export declare class PythonBuilder implements StepBuilder {
|
|
|
5
5
|
private readonly builder;
|
|
6
6
|
private readonly listener;
|
|
7
7
|
private uvPackager;
|
|
8
|
-
private uvConfig;
|
|
9
8
|
constructor(builder: Builder, listener: BuildListener);
|
|
10
|
-
private loadUvConfig;
|
|
11
9
|
buildApiSteps(steps: Step<ApiRouteConfig>[]): Promise<RouterBuildResult>;
|
|
12
10
|
build(step: Step): Promise<void>;
|
|
13
11
|
private addStepToArchive;
|
|
@@ -18,4 +16,5 @@ export declare class PythonBuilder implements StepBuilder {
|
|
|
18
16
|
private findInternalFiles;
|
|
19
17
|
private resolveModulePaths;
|
|
20
18
|
private getModuleName;
|
|
19
|
+
private waitForDirectoryReady;
|
|
21
20
|
}
|
|
@@ -10,40 +10,22 @@ const archiver_1 = require("../archiver");
|
|
|
10
10
|
const include_static_files_1 = require("../include-static-files");
|
|
11
11
|
const constants_1 = require("../../../new-deployment/constants");
|
|
12
12
|
const uv_packager_1 = require("./uv-packager");
|
|
13
|
+
const activate_python_env_1 = require("../../../../utils/activate-python-env");
|
|
13
14
|
class PythonBuilder {
|
|
14
15
|
constructor(builder, listener) {
|
|
15
16
|
this.builder = builder;
|
|
16
17
|
this.listener = listener;
|
|
17
|
-
|
|
18
|
-
this.uvPackager = new uv_packager_1.UvPackager(this.builder.projectDir
|
|
19
|
-
}
|
|
20
|
-
loadUvConfig() {
|
|
21
|
-
const configFiles = ['uv.config.json', '.uvrc.json'];
|
|
22
|
-
for (const configFile of configFiles) {
|
|
23
|
-
const configPath = path_1.default.join(this.builder.projectDir, configFile);
|
|
24
|
-
if (fs_1.default.existsSync(configPath)) {
|
|
25
|
-
try {
|
|
26
|
-
const configContent = fs_1.default.readFileSync(configPath, 'utf-8');
|
|
27
|
-
return JSON.parse(configContent);
|
|
28
|
-
}
|
|
29
|
-
catch (err) {
|
|
30
|
-
console.warn(`Warning: Failed to load UV config from ${configFile}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return {};
|
|
18
|
+
(0, activate_python_env_1.activatePythonVenv)({ baseDir: this.builder.projectDir });
|
|
19
|
+
this.uvPackager = new uv_packager_1.UvPackager(this.builder.projectDir);
|
|
35
20
|
}
|
|
36
21
|
async buildApiSteps(steps) {
|
|
37
22
|
const zipName = 'router-python.zip';
|
|
38
23
|
const archive = new archiver_1.Archiver(path_1.default.join(constants_1.distDir, zipName));
|
|
39
|
-
if (!await this.uvPackager.checkUvInstalled()) {
|
|
40
|
-
throw new Error('UV is not installed. Please install UV: curl -LsSf https://astral.sh/uv/install.sh | sh');
|
|
41
|
-
}
|
|
42
24
|
const tempSitePackages = path_1.default.join(constants_1.distDir, `temp-python-packages-${Date.now()}`);
|
|
43
25
|
try {
|
|
44
26
|
await this.uvPackager.packageDependencies(tempSitePackages);
|
|
45
|
-
//
|
|
46
|
-
await
|
|
27
|
+
// Wait for directory to be ready with proper access checks
|
|
28
|
+
await this.waitForDirectoryReady(tempSitePackages);
|
|
47
29
|
await this.addPackagesToArchive(archive, tempSitePackages);
|
|
48
30
|
for (const step of steps) {
|
|
49
31
|
await this.addStepToArchive(step, archive);
|
|
@@ -70,15 +52,12 @@ class PythonBuilder {
|
|
|
70
52
|
this.builder.registerStep({ entrypointPath, bundlePath, step, type: 'python' });
|
|
71
53
|
this.listener.onBuildStart(step);
|
|
72
54
|
try {
|
|
73
|
-
if (!await this.uvPackager.checkUvInstalled()) {
|
|
74
|
-
throw new Error('UV is not installed. Please install UV: curl -LsSf https://astral.sh/uv/install.sh | sh');
|
|
75
|
-
}
|
|
76
55
|
fs_1.default.mkdirSync(path_1.default.dirname(outfile), { recursive: true });
|
|
77
56
|
const archive = new archiver_1.Archiver(outfile);
|
|
78
57
|
const tempSitePackages = path_1.default.join(constants_1.distDir, `temp-python-packages-${Date.now()}`);
|
|
79
58
|
try {
|
|
80
59
|
await this.uvPackager.packageDependencies(tempSitePackages);
|
|
81
|
-
await
|
|
60
|
+
await this.waitForDirectoryReady(tempSitePackages);
|
|
82
61
|
await this.addStepToArchive(step, archive);
|
|
83
62
|
await this.addPackagesToArchive(archive, tempSitePackages);
|
|
84
63
|
(0, include_static_files_1.includeStaticFiles)([step], this.builder, archive);
|
|
@@ -113,7 +92,6 @@ class PythonBuilder {
|
|
|
113
92
|
console.warn(`Warning: Site packages directory not found: ${sitePackagesDir}`);
|
|
114
93
|
return;
|
|
115
94
|
}
|
|
116
|
-
// Verificar se o diretório está acessível
|
|
117
95
|
try {
|
|
118
96
|
fs_1.default.accessSync(sitePackagesDir, fs_1.default.constants.R_OK);
|
|
119
97
|
}
|
|
@@ -208,13 +186,11 @@ class PythonBuilder {
|
|
|
208
186
|
files.push(path_1.default.relative(this.builder.projectDir, filePath));
|
|
209
187
|
try {
|
|
210
188
|
const content = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
211
|
-
// Regex melhorada para capturar imports mais complexos
|
|
212
189
|
const importRegex = /^(?:from\s+([a-zA-Z_][a-zA-Z0-9_.]*)\s+import|import\s+([a-zA-Z_][a-zA-Z0-9_.]*))/gm;
|
|
213
190
|
let match;
|
|
214
191
|
while ((match = importRegex.exec(content)) !== null) {
|
|
215
192
|
const moduleName = match[1] || match[2]; // from X import Y ou import X
|
|
216
|
-
|
|
217
|
-
this.resolveModulePaths(moduleName, path_1.default.dirname(filePath)).forEach(possiblePath => {
|
|
193
|
+
this.resolveModulePaths(moduleName, path_1.default.dirname(filePath)).forEach((possiblePath) => {
|
|
218
194
|
if (fs_1.default.existsSync(possiblePath)) {
|
|
219
195
|
analyzeFile(possiblePath);
|
|
220
196
|
}
|
|
@@ -233,23 +209,47 @@ class PythonBuilder {
|
|
|
233
209
|
const baseName = parts[0];
|
|
234
210
|
const subPath = parts.length > 1 ? path_1.default.join(...parts) : baseName;
|
|
235
211
|
return [
|
|
236
|
-
// Relativo ao arquivo atual
|
|
237
212
|
path_1.default.join(currentDir, `${baseName}.py`),
|
|
238
213
|
path_1.default.join(currentDir, baseName, '__init__.py'),
|
|
239
214
|
path_1.default.join(currentDir, `${subPath}.py`),
|
|
240
|
-
// Relativo ao diretório do projeto
|
|
241
215
|
path_1.default.join(this.builder.projectDir, `${baseName}.py`),
|
|
242
216
|
path_1.default.join(this.builder.projectDir, baseName, '__init__.py'),
|
|
243
217
|
path_1.default.join(this.builder.projectDir, `${subPath}.py`),
|
|
244
|
-
// Para utils.database -> utils/database.py
|
|
245
218
|
path_1.default.join(this.builder.projectDir, subPath + '.py'),
|
|
246
219
|
path_1.default.join(this.builder.projectDir, subPath, '__init__.py'),
|
|
247
220
|
];
|
|
248
221
|
}
|
|
249
222
|
getModuleName(step) {
|
|
250
|
-
return this.normalizeStepPath(step, true)
|
|
251
|
-
|
|
252
|
-
|
|
223
|
+
return this.normalizeStepPath(step, true).replace(/\.py$/, '').replace(/\//g, '.');
|
|
224
|
+
}
|
|
225
|
+
async waitForDirectoryReady(dirPath, maxRetries = 10, initialDelayMs = 10) {
|
|
226
|
+
let lastError = null;
|
|
227
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
228
|
+
try {
|
|
229
|
+
const exists = await fs_1.default.promises
|
|
230
|
+
.access(dirPath, fs_1.default.constants.F_OK)
|
|
231
|
+
.then(() => true)
|
|
232
|
+
.catch(() => false);
|
|
233
|
+
if (!exists) {
|
|
234
|
+
// Directory doesn't exist yet, wait
|
|
235
|
+
lastError = new Error(`Directory ${dirPath} does not exist yet`);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
await fs_1.default.promises.access(dirPath, fs_1.default.constants.R_OK);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
lastError = error;
|
|
244
|
+
}
|
|
245
|
+
if (i === maxRetries - 1) {
|
|
246
|
+
throw new Error(`Directory ${dirPath} is not accessible after ${maxRetries} attempts. ` +
|
|
247
|
+
`Last error: ${lastError?.message || 'Unknown error'}`);
|
|
248
|
+
}
|
|
249
|
+
// Exponential backoff: 10ms, 20ms, 40ms, 80ms, etc.
|
|
250
|
+
const delay = initialDelayMs * Math.pow(2, i);
|
|
251
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(delay, 1000))); // Cap at 1 second
|
|
252
|
+
}
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
exports.PythonBuilder = PythonBuilder;
|
|
@@ -8,7 +8,6 @@ export declare class UvPackager {
|
|
|
8
8
|
private readonly projectDir;
|
|
9
9
|
private readonly config;
|
|
10
10
|
constructor(projectDir: string, config?: UvPackageConfig);
|
|
11
|
-
|
|
11
|
+
private runCommand;
|
|
12
12
|
packageDependencies(targetDir: string): Promise<void>;
|
|
13
|
-
private runUvCommand;
|
|
14
13
|
}
|
|
@@ -8,53 +8,28 @@ const child_process_1 = require("child_process");
|
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
exports.defaultUvConfig = {
|
|
11
|
-
pythonVersion: '3.13',
|
|
12
|
-
platform: 'x86_64-manylinux2014',
|
|
13
|
-
onlyBinary:
|
|
11
|
+
pythonVersion: process.env.MOTIA_PYTHON_VERSION || '3.13',
|
|
12
|
+
platform: process.env.MOTIA_PLATFORM || 'x86_64-manylinux2014',
|
|
13
|
+
onlyBinary: process.env.MOTIA_ONLY_BINARY !== 'false',
|
|
14
14
|
};
|
|
15
15
|
class UvPackager {
|
|
16
16
|
constructor(projectDir, config = exports.defaultUvConfig) {
|
|
17
17
|
this.projectDir = projectDir;
|
|
18
18
|
this.config = config;
|
|
19
19
|
}
|
|
20
|
-
async
|
|
21
|
-
return new Promise((resolve) => {
|
|
22
|
-
const child = (0, child_process_1.spawn)('uv', ['--version'], { stdio: 'pipe' });
|
|
23
|
-
child.on('close', (code) => resolve(code === 0));
|
|
24
|
-
child.on('error', () => resolve(false));
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
async packageDependencies(targetDir) {
|
|
28
|
-
if (!fs_1.default.existsSync(targetDir)) {
|
|
29
|
-
fs_1.default.mkdirSync(targetDir, { recursive: true });
|
|
30
|
-
}
|
|
31
|
-
const requirementsFile = path_1.default.join(this.projectDir, 'requirements.txt');
|
|
32
|
-
if (!fs_1.default.existsSync(requirementsFile)) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
const args = [
|
|
36
|
-
'pip', 'install',
|
|
37
|
-
'--target', targetDir,
|
|
38
|
-
'--requirement', requirementsFile,
|
|
39
|
-
'--python-version', this.config.pythonVersion || '3.13',
|
|
40
|
-
'--python-platform', this.config.platform || 'x86_64-manylinux2014',
|
|
41
|
-
'--force-reinstall'
|
|
42
|
-
];
|
|
43
|
-
if (this.config.onlyBinary) {
|
|
44
|
-
args.push('--only-binary=:all:');
|
|
45
|
-
}
|
|
46
|
-
await this.runUvCommand(args);
|
|
47
|
-
}
|
|
48
|
-
async runUvCommand(args) {
|
|
20
|
+
async runCommand(command, args, options) {
|
|
49
21
|
return new Promise((resolve, reject) => {
|
|
50
|
-
const child = (0, child_process_1.spawn)(
|
|
51
|
-
cwd:
|
|
52
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
22
|
+
const child = (0, child_process_1.spawn)(command, args, {
|
|
23
|
+
cwd: options?.cwd,
|
|
24
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
53
25
|
});
|
|
54
26
|
let stdout = '';
|
|
55
27
|
let stderr = '';
|
|
56
28
|
child.stdout?.on('data', (data) => {
|
|
57
29
|
stdout += data.toString();
|
|
30
|
+
if (options?.showOutput) {
|
|
31
|
+
process.stdout.write(data);
|
|
32
|
+
}
|
|
58
33
|
});
|
|
59
34
|
child.stderr?.on('data', (data) => {
|
|
60
35
|
stderr += data.toString();
|
|
@@ -64,13 +39,39 @@ class UvPackager {
|
|
|
64
39
|
resolve(stdout);
|
|
65
40
|
}
|
|
66
41
|
else {
|
|
67
|
-
|
|
42
|
+
const errorPrefix = `Command '${command}'`;
|
|
43
|
+
reject(new Error(`${errorPrefix} failed: ${stderr || stdout}`));
|
|
68
44
|
}
|
|
69
45
|
});
|
|
70
46
|
child.on('error', (error) => {
|
|
71
|
-
reject(new Error(`Failed to spawn
|
|
47
|
+
reject(new Error(`Failed to spawn ${command}: ${error.message}`));
|
|
72
48
|
});
|
|
73
49
|
});
|
|
74
50
|
}
|
|
51
|
+
async packageDependencies(targetDir) {
|
|
52
|
+
if (!fs_1.default.existsSync(targetDir)) {
|
|
53
|
+
fs_1.default.mkdirSync(targetDir, { recursive: true });
|
|
54
|
+
}
|
|
55
|
+
const requirementsFile = path_1.default.join(this.projectDir, 'requirements.txt');
|
|
56
|
+
if (!fs_1.default.existsSync(requirementsFile)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const args = [
|
|
60
|
+
'pip',
|
|
61
|
+
'install',
|
|
62
|
+
'--target',
|
|
63
|
+
targetDir,
|
|
64
|
+
'--requirement',
|
|
65
|
+
requirementsFile,
|
|
66
|
+
'--python-version',
|
|
67
|
+
this.config.pythonVersion || '3.13',
|
|
68
|
+
'--python-platform',
|
|
69
|
+
this.config.platform || 'x86_64-manylinux2014',
|
|
70
|
+
];
|
|
71
|
+
if (this.config.onlyBinary) {
|
|
72
|
+
args.push('--only-binary=:all:');
|
|
73
|
+
}
|
|
74
|
+
await this.runCommand('uv', args, { cwd: this.projectDir });
|
|
75
|
+
}
|
|
75
76
|
}
|
|
76
77
|
exports.UvPackager = UvPackager;
|
|
@@ -13,11 +13,13 @@ cli_1.cloudCli
|
|
|
13
13
|
.command('deploy')
|
|
14
14
|
.description('Deploy a new version to Motia Cloud')
|
|
15
15
|
.requiredOption('-k, --api-key <key>', 'The API key for authentication', process.env.MOTIA_API_KEY)
|
|
16
|
-
.requiredOption('-v, --version-name <version>', 'The version to deploy')
|
|
17
16
|
.option('-p, --project-id <id>', 'Project ID (Deprecated)')
|
|
17
|
+
.option('-n, --project-name <name>', 'Project name (used when creating a new project)')
|
|
18
18
|
.option('-s, --environment-id <id>', 'Environment ID', process.env.MOTIA_ENVIRONMENT_ID)
|
|
19
|
+
.option('--environment-name <name>', 'Environment name')
|
|
19
20
|
.option('-e, --env-file <path>', 'Path to environment file')
|
|
20
|
-
.
|
|
21
|
+
.requiredOption('-v, --version-name <version>', 'The version to deploy')
|
|
22
|
+
.option('-d, --version-description <description>', 'The description of the version')
|
|
21
23
|
.action((0, config_utils_1.handler)(async (arg, context) => {
|
|
22
24
|
const listener = new cli_listener_1.CliListener(context);
|
|
23
25
|
const builder = await (0, build_1.build)(listener);
|
|
@@ -30,9 +32,11 @@ cli_1.cloudCli
|
|
|
30
32
|
const deployment = await cloud_api_1.cloudApi
|
|
31
33
|
.createDeployment({
|
|
32
34
|
apiKey: arg.apiKey,
|
|
33
|
-
versionName: arg.versionName,
|
|
34
|
-
environmentId: arg.environmentId,
|
|
35
35
|
projectName: arg.projectName,
|
|
36
|
+
environmentId: arg.environmentId,
|
|
37
|
+
environmentName: arg.environmentName,
|
|
38
|
+
versionName: arg.versionName,
|
|
39
|
+
versionDescription: arg.versionDescription,
|
|
36
40
|
})
|
|
37
41
|
.catch((error) => {
|
|
38
42
|
context.log('creating-deployment', (message) => message.tag('failed').append('Failed to create deployment'));
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deployEndpoints = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const build_validation_1 = require("./build/build-validation");
|
|
6
|
+
const streaming_deployment_listener_1 = require("./new-deployment/listeners/streaming-deployment-listener");
|
|
7
|
+
const build_1 = require("./new-deployment/build");
|
|
8
|
+
const upload_artifacts_1 = require("./new-deployment/upload-artifacts");
|
|
9
|
+
const deployment_stream_1 = require("./new-deployment/streams/deployment-stream");
|
|
10
|
+
const cloud_api_1 = require("./new-deployment/cloud-api");
|
|
11
|
+
const version_1 = require("../version");
|
|
12
|
+
const deployEndpoints = (server, lockedData) => {
|
|
13
|
+
const { app } = server;
|
|
14
|
+
// Criar stream de deployment se não existir
|
|
15
|
+
const deploymentStream = lockedData.createStream({
|
|
16
|
+
filePath: '__motia.deployment',
|
|
17
|
+
hidden: true,
|
|
18
|
+
config: {
|
|
19
|
+
name: '__motia.deployment',
|
|
20
|
+
baseConfig: { storageType: 'default' },
|
|
21
|
+
schema: null,
|
|
22
|
+
},
|
|
23
|
+
})();
|
|
24
|
+
const deploymentManager = new deployment_stream_1.DeploymentStreamManager(deploymentStream);
|
|
25
|
+
app.get('/__motia', (_, res) => {
|
|
26
|
+
res.status(200).json({ version: version_1.version });
|
|
27
|
+
});
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
app.post('/__motia/cloud/deploy/start', async (req, res) => {
|
|
30
|
+
try {
|
|
31
|
+
const { deploymentToken, deploymentId, envs } = req.body;
|
|
32
|
+
const sessionId = deploymentId || (0, crypto_1.randomUUID)();
|
|
33
|
+
if (!deploymentToken || !deploymentId) {
|
|
34
|
+
return res.status(400).json({
|
|
35
|
+
success: false,
|
|
36
|
+
error: 'deploymentToken and deploymentId are required',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
await deploymentManager.startDeployment(sessionId);
|
|
40
|
+
const listener = new streaming_deployment_listener_1.StreamingDeploymentListener(sessionId, deploymentStream);
|
|
41
|
+
res.json({
|
|
42
|
+
success: true,
|
|
43
|
+
message: 'Deployment started',
|
|
44
|
+
deploymentId: sessionId,
|
|
45
|
+
streamName: 'deployment-status',
|
|
46
|
+
groupId: 'deployments',
|
|
47
|
+
itemId: sessionId,
|
|
48
|
+
});
|
|
49
|
+
setImmediate(async () => {
|
|
50
|
+
try {
|
|
51
|
+
await listener.startBuildPhase();
|
|
52
|
+
const builder = await (0, build_1.build)(listener).catch(() => {
|
|
53
|
+
throw new Error('Build failed, check the logs for more information');
|
|
54
|
+
});
|
|
55
|
+
const isValid = (0, build_validation_1.buildValidation)(builder, listener);
|
|
56
|
+
if (!isValid) {
|
|
57
|
+
await listener.onBuildErrors(listener.getErrors());
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
await listener.startUploadPhase();
|
|
61
|
+
await (0, upload_artifacts_1.uploadArtifacts)(builder, deploymentToken, listener);
|
|
62
|
+
await listener.startDeployPhase();
|
|
63
|
+
await cloud_api_1.cloudApi.startDeployment({
|
|
64
|
+
deploymentToken,
|
|
65
|
+
envVars: envs,
|
|
66
|
+
steps: builder.stepsConfig,
|
|
67
|
+
streams: builder.streamsConfig,
|
|
68
|
+
routers: builder.routersConfig,
|
|
69
|
+
});
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error('Deployment failed:', error);
|
|
74
|
+
// Update stream with error
|
|
75
|
+
if (listener) {
|
|
76
|
+
await listener.onDeployError(error.message);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error('Failed to start deployment:', error);
|
|
84
|
+
res.status(500).json({ success: false, error: error.message });
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
88
|
+
app.get('/__motia/cloud/deploy/status/:deploymentId', async (req, res) => {
|
|
89
|
+
try {
|
|
90
|
+
const { deploymentId } = req.params;
|
|
91
|
+
const deployment = await deploymentManager.getDeployment(deploymentId);
|
|
92
|
+
return deployment
|
|
93
|
+
? res.status(200).json({ success: true, deployment })
|
|
94
|
+
: res.status(404).json({ success: false, error: 'Deployment not found' });
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
res.status(500).json({ success: false, error: error.message });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
exports.deployEndpoints = deployEndpoints;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
type CreateDeploymentRequest = {
|
|
2
2
|
apiKey: string;
|
|
3
|
+
projectName?: string;
|
|
3
4
|
environmentId?: string;
|
|
5
|
+
environmentName?: string;
|
|
4
6
|
versionName: string;
|
|
5
|
-
|
|
7
|
+
versionDescription?: string;
|
|
6
8
|
};
|
|
7
9
|
type CreateDeploymentResult = {
|
|
8
10
|
deploymentId: string;
|
|
@@ -11,9 +11,11 @@ export declare const cloudApi: {
|
|
|
11
11
|
}>;
|
|
12
12
|
createDeployment: (request: {
|
|
13
13
|
apiKey: string;
|
|
14
|
+
projectName?: string;
|
|
14
15
|
environmentId?: string;
|
|
16
|
+
environmentName?: string;
|
|
15
17
|
versionName: string;
|
|
16
|
-
|
|
18
|
+
versionDescription?: string;
|
|
17
19
|
}) => Promise<{
|
|
18
20
|
deploymentId: string;
|
|
19
21
|
deploymentToken: string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Step, MotiaStream } from '@motiadev/core';
|
|
2
|
+
import { Stream } from '@motiadev/core/dist/src/types-stream';
|
|
3
|
+
import { BuildStepConfig } from '../../build/builder';
|
|
4
|
+
import { ValidationError } from '../../build/build-validation';
|
|
5
|
+
import { DeploymentListener, DeployData } from './listener.types';
|
|
6
|
+
import { DeploymentData } from '../streams/deployment-stream';
|
|
7
|
+
export declare class StreamingDeploymentListener implements DeploymentListener {
|
|
8
|
+
private deploymentId;
|
|
9
|
+
private errors;
|
|
10
|
+
private warnings;
|
|
11
|
+
private streamManager;
|
|
12
|
+
constructor(deploymentId: string, deploymentStream: MotiaStream<DeploymentData>);
|
|
13
|
+
private relativePath;
|
|
14
|
+
private getStepType;
|
|
15
|
+
private getLanguage;
|
|
16
|
+
private updateStream;
|
|
17
|
+
getErrors(): ValidationError[];
|
|
18
|
+
onBuildStart(step: Step): Promise<void>;
|
|
19
|
+
onBuildProgress(step: Step, message: string): Promise<void>;
|
|
20
|
+
onBuildEnd(step: Step, size: number): Promise<void>;
|
|
21
|
+
onBuildError(step: Step, error: Error): Promise<void>;
|
|
22
|
+
onBuildSkip(step: Step, reason: string): Promise<void>;
|
|
23
|
+
onStreamCreated(stream: Stream): Promise<void>;
|
|
24
|
+
onApiRouterBuilding(language: string): Promise<void>;
|
|
25
|
+
onApiRouterBuilt(language: string, size: number): Promise<void>;
|
|
26
|
+
onWarning(id: string, warning: string): Promise<void>;
|
|
27
|
+
onBuildWarning(warning: ValidationError): Promise<void>;
|
|
28
|
+
onBuildErrors(errors: ValidationError[]): Promise<void>;
|
|
29
|
+
stepUploadStart(stepPath: string, step: BuildStepConfig): Promise<void>;
|
|
30
|
+
stepUploadProgress(stepPath: string, step: BuildStepConfig, progress: number): Promise<void>;
|
|
31
|
+
stepUploadEnd(stepPath: string, step: BuildStepConfig): Promise<void>;
|
|
32
|
+
stepUploadError(stepPath: string, step: BuildStepConfig): Promise<void>;
|
|
33
|
+
routeUploadStart(path: string, language: string): Promise<void>;
|
|
34
|
+
routeUploadProgress(path: string, language: string, progress: number): Promise<void>;
|
|
35
|
+
routeUploadEnd(path: string, language: string): Promise<void>;
|
|
36
|
+
routeUploadError(path: string, language: string): Promise<void>;
|
|
37
|
+
onDeployStart(): Promise<void>;
|
|
38
|
+
onDeployProgress(data: DeployData): Promise<void>;
|
|
39
|
+
onDeployEnd(): Promise<void>;
|
|
40
|
+
onDeployError(errorMessage: string): Promise<void>;
|
|
41
|
+
startBuildPhase(): Promise<void>;
|
|
42
|
+
startUploadPhase(): Promise<void>;
|
|
43
|
+
startDeployPhase(): Promise<void>;
|
|
44
|
+
}
|