motia 0.15.5-beta.173 → 0.15.5-beta.174-105737
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/cli.mjs +9 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/cloud/new-deployment/build.mjs +11 -1
- package/dist/cloud/new-deployment/build.mjs.map +1 -1
- package/dist/create/index.mjs +3 -3
- package/dist/dev.mjs +8 -2
- package/dist/dev.mjs.map +1 -1
- package/dist/generate-locked-data.d.mts.map +1 -1
- package/dist/generate-locked-data.mjs +0 -2
- package/dist/generate-locked-data.mjs.map +1 -1
- package/dist/install.mjs +1 -1
- package/dist/plugins/install-plugin-dependencies.mjs +2 -2
- package/dist/start.mjs +8 -2
- package/dist/start.mjs.map +1 -1
- package/dist/utils/activate-python-env.mjs +9 -15
- package/dist/utils/activate-python-env.mjs.map +1 -1
- package/dist/utils/get-package-manager.mjs +10 -4
- package/dist/utils/get-package-manager.mjs.map +1 -1
- package/dist/utils/validate-python-environment.mjs +84 -0
- package/dist/utils/validate-python-environment.mjs.map +1 -0
- package/package.json +8 -8
package/dist/cli.mjs
CHANGED
|
@@ -85,11 +85,19 @@ generate.command("step").description("Create a new step with interactive prompts
|
|
|
85
85
|
return createStep({ stepFilePath: arg.dir });
|
|
86
86
|
}));
|
|
87
87
|
generate.command("openapi").description("Generate OpenAPI spec for your project").option("-t, --title <title>", "Title for the OpenAPI document. Defaults to project name").option("-v, --version <version>", "Version for the OpenAPI document. Defaults to 1.0.0", "1.0.0").option("-o, --output <output>", "Output file for the OpenAPI document. Defaults to openapi.json", "openapi.json").action(wrapAction(async (options) => {
|
|
88
|
-
const { generateLockedData } = await import("./generate-locked-data.mjs");
|
|
88
|
+
const { generateLockedData, getStepFiles, getStreamFiles } = await import("./generate-locked-data.mjs");
|
|
89
|
+
const { validatePythonEnvironment } = await import("./utils/validate-python-environment.mjs");
|
|
90
|
+
const { activatePythonVenv } = await import("./utils/activate-python-env.mjs");
|
|
89
91
|
const { generateOpenApi } = await import("./openapi/generate.mjs");
|
|
90
92
|
const { MemoryStreamAdapterManager } = await import("@motiadev/core");
|
|
91
93
|
const baseDir = process.cwd();
|
|
92
94
|
const appConfig = await loadMotiaConfig(baseDir);
|
|
95
|
+
const hasPythonFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)].some((file) => file.endsWith(".py"));
|
|
96
|
+
if (!(await validatePythonEnvironment({
|
|
97
|
+
baseDir,
|
|
98
|
+
hasPythonFiles
|
|
99
|
+
})).success) process.exit(1);
|
|
100
|
+
if (hasPythonFiles) activatePythonVenv({ baseDir });
|
|
93
101
|
const apiSteps = (await generateLockedData({
|
|
94
102
|
projectDir: baseDir,
|
|
95
103
|
streamAdapter: new MemoryStreamAdapterManager(),
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport 'dotenv/config'\n\nimport { program } from 'commander'\nimport { type CliContext, handler } from './cloud/config-utils'\nimport './cloud/index'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { wrapAction } from './utils/analytics'\nimport { version } from './version'\n\nconst defaultPort = 3000\nconst defaultHost = '0.0.0.0'\n\nprogram\n .command('version')\n .description('Display detailed version information')\n .action(() => {\n console.log(`Motia CLI v${version}`)\n process.exit(0)\n })\n\nprogram\n .command('create [name]')\n .description('Create a new motia project')\n .option('-t, --template <template>', 'The template to use for your project')\n .option('-p, --plugin', 'Create a plugin project')\n .option('-i, --interactive', 'Use interactive prompts to create project') // it's default\n .option('--skip-redis', 'Skip Redis binary installation and use external Redis')\n .action((projectName, options) => {\n const mergedArgs = { ...options, name: projectName }\n return handler(async (arg: any, context: CliContext) => {\n const { createInteractive } = await import('./create/interactive')\n await createInteractive(\n {\n name: arg.name,\n template: arg.template,\n plugin: !!arg.plugin,\n skipRedis: !!arg.skipRedis,\n },\n context,\n )\n })(mergedArgs)\n })\n\nprogram\n .command('rules')\n .command('pull')\n .description('Install essential AI development guides (AGENTS.md, CLAUDE.md) and optional Cursor IDE rules')\n .option('-f, --force', 'Overwrite existing files')\n .action(\n handler(async (arg: any, context: CliContext) => {\n const { pullRules } = await import('./create/pull-rules')\n await pullRules({ force: arg.force, rootDir: process.cwd() }, context)\n }),\n )\n\nprogram\n .command('generate-types')\n .description('Generate types.d.ts file for your project')\n .action(\n wrapAction(async () => {\n const { generateTypes } = await import('./generate-types')\n await generateTypes(process.cwd())\n process.exit(0)\n }),\n )\n\nprogram\n .command('install')\n .description('Sets up Python virtual environment and install dependencies')\n .option('-v, --verbose', 'Enable verbose logging')\n .action(\n wrapAction(async (options: any) => {\n const { install } = await import('./install')\n await install({ isVerbose: options.verbose })\n }),\n )\n\nprogram\n .command('dev')\n .description('Start the development server')\n .option('-p, --port <port>', 'The port to run the server on', `${defaultPort}`)\n .option('-H, --host [host]', 'The host address for the server', `${defaultHost}`)\n .option('-v, --disable-verbose', 'Disable verbose logging')\n .option('-d, --debug', 'Enable debug logging')\n .option('-m, --mermaid', 'Enable mermaid diagram generation')\n .option('--motia-dir <path>', 'Path where .motia folder will be created')\n .action(\n wrapAction(async (arg: any) => {\n if (arg.debug) {\n console.log('🔍 Debug logging enabled')\n process.env.LOG_LEVEL = 'debug'\n }\n\n const port = arg.port ? parseInt(arg.port) : defaultPort\n const host = arg.host ? arg.host : defaultHost\n const { dev } = await import('./dev')\n await dev(port, host, arg.disableVerbose, arg.mermaid, arg.motiaDir)\n }),\n )\n\nprogram\n .command('start')\n .description('Start a server to run your Motia project')\n .option('-p, --port <port>', 'The port to run the server on', `${defaultPort}`)\n .option('-H, --host [host]', 'The host address for the server', `${defaultHost}`)\n .option('-v, --disable-verbose', 'Disable verbose logging')\n .option('-d, --debug', 'Enable debug logging')\n .option('--motia-dir <path>', 'Path where .motia folder will be created')\n .action(\n wrapAction(async (arg: any) => {\n if (arg.debug) {\n console.log('🔍 Debug logging enabled')\n process.env.LOG_LEVEL = 'debug'\n }\n\n const port = arg.port ? parseInt(arg.port) : defaultPort\n const host = arg.host ? arg.host : defaultHost\n const { start } = await import('./start')\n await start(port, host, arg.disableVerbose, arg.motiaDir)\n }),\n )\n\nprogram\n .command('emit')\n .description('Emit an event to the Motia server')\n .requiredOption('--topic <topic>', 'Event topic/type to emit')\n .requiredOption('--message <message>', 'Event payload as JSON string')\n .option('-p, --port <number>', 'Port number (default: 3000)')\n .action(\n wrapAction(async (options: any) => {\n const port = options.port || 3000\n const url = `http://localhost:${port}/emit`\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n topic: options.topic,\n data: JSON.parse(options.message),\n }),\n })\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`)\n }\n\n const result = await response.json()\n console.log('Event emitted successfully:', result)\n }),\n )\n\nconst generate = program.command('generate').description('Generate motia resources')\n\ngenerate\n .command('step')\n .description('Create a new step with interactive prompts')\n .option('-d, --dir <step file path>', 'The path relative to the steps directory, used to create the step file')\n .action(\n wrapAction(async (arg: any) => {\n const { createStep } = await import('./create-step/index')\n return createStep({\n stepFilePath: arg.dir,\n })\n }),\n )\n\ngenerate\n .command('openapi')\n .description('Generate OpenAPI spec for your project')\n .option('-t, --title <title>', 'Title for the OpenAPI document. Defaults to project name')\n .option('-v, --version <version>', 'Version for the OpenAPI document. Defaults to 1.0.0', '1.0.0')\n .option('-o, --output <output>', 'Output file for the OpenAPI document. Defaults to openapi.json', 'openapi.json')\n .action(\n wrapAction(async (options: any) => {\n const { generateLockedData } = await import('./generate-locked-data')\n const { generateOpenApi } = await import('./openapi/generate')\n const { MemoryStreamAdapterManager } = await import('@motiadev/core')\n\n const baseDir = process.cwd()\n const appConfig = await loadMotiaConfig(baseDir)\n\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: new MemoryStreamAdapterManager(),\n streamAuth: appConfig.streamAuth,\n printerType: 'disabled',\n })\n const apiSteps = lockedData.apiSteps()\n\n generateOpenApi(process.cwd(), apiSteps, options.title, options.version, options.output)\n process.exit(0)\n }),\n )\n\nconst docker = program.command('docker').description('Motia docker commands')\n\ndocker\n .command('setup')\n .description('Setup a motia-docker for your project')\n .action(\n wrapAction(async () => {\n const { setup } = await import('./docker/setup')\n await setup()\n process.exit(0)\n }),\n )\n\ndocker\n .command('run')\n .description('Build and run your project in a docker container')\n .option('-p, --port <port>', 'The port to run the server on', `${defaultPort}`)\n .option('-n, --project-name <project name>', 'The name for your project')\n .option('-s, --skip-build', 'Skip docker build')\n .action(\n wrapAction(async (arg: any) => {\n const { run } = await import('./docker/run')\n await run(arg.port, arg.projectName, arg.skipBuild)\n process.exit(0)\n }),\n )\n\ndocker\n .command('build')\n .description('Build your project in a docker container')\n .option('-n, --project-name <project name>', 'The name for your project')\n .action(\n wrapAction(async (arg: any) => {\n const { build } = await import('./docker/build')\n await build(arg.projectName)\n process.exit(0)\n }),\n )\n\nprogram.version(version, '-V, --version', 'Output the current version')\nprogram.parseAsync(process.argv).catch(() => {\n process.exit(1)\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport 'dotenv/config'\n\nimport { program } from 'commander'\nimport { type CliContext, handler } from './cloud/config-utils'\nimport './cloud/index'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { wrapAction } from './utils/analytics'\nimport { version } from './version'\n\nconst defaultPort = 3000\nconst defaultHost = '0.0.0.0'\n\nprogram\n .command('version')\n .description('Display detailed version information')\n .action(() => {\n console.log(`Motia CLI v${version}`)\n process.exit(0)\n })\n\nprogram\n .command('create [name]')\n .description('Create a new motia project')\n .option('-t, --template <template>', 'The template to use for your project')\n .option('-p, --plugin', 'Create a plugin project')\n .option('-i, --interactive', 'Use interactive prompts to create project') // it's default\n .option('--skip-redis', 'Skip Redis binary installation and use external Redis')\n .action((projectName, options) => {\n const mergedArgs = { ...options, name: projectName }\n return handler(async (arg: any, context: CliContext) => {\n const { createInteractive } = await import('./create/interactive')\n await createInteractive(\n {\n name: arg.name,\n template: arg.template,\n plugin: !!arg.plugin,\n skipRedis: !!arg.skipRedis,\n },\n context,\n )\n })(mergedArgs)\n })\n\nprogram\n .command('rules')\n .command('pull')\n .description('Install essential AI development guides (AGENTS.md, CLAUDE.md) and optional Cursor IDE rules')\n .option('-f, --force', 'Overwrite existing files')\n .action(\n handler(async (arg: any, context: CliContext) => {\n const { pullRules } = await import('./create/pull-rules')\n await pullRules({ force: arg.force, rootDir: process.cwd() }, context)\n }),\n )\n\nprogram\n .command('generate-types')\n .description('Generate types.d.ts file for your project')\n .action(\n wrapAction(async () => {\n const { generateTypes } = await import('./generate-types')\n await generateTypes(process.cwd())\n process.exit(0)\n }),\n )\n\nprogram\n .command('install')\n .description('Sets up Python virtual environment and install dependencies')\n .option('-v, --verbose', 'Enable verbose logging')\n .action(\n wrapAction(async (options: any) => {\n const { install } = await import('./install')\n await install({ isVerbose: options.verbose })\n }),\n )\n\nprogram\n .command('dev')\n .description('Start the development server')\n .option('-p, --port <port>', 'The port to run the server on', `${defaultPort}`)\n .option('-H, --host [host]', 'The host address for the server', `${defaultHost}`)\n .option('-v, --disable-verbose', 'Disable verbose logging')\n .option('-d, --debug', 'Enable debug logging')\n .option('-m, --mermaid', 'Enable mermaid diagram generation')\n .option('--motia-dir <path>', 'Path where .motia folder will be created')\n .action(\n wrapAction(async (arg: any) => {\n if (arg.debug) {\n console.log('🔍 Debug logging enabled')\n process.env.LOG_LEVEL = 'debug'\n }\n\n const port = arg.port ? parseInt(arg.port) : defaultPort\n const host = arg.host ? arg.host : defaultHost\n const { dev } = await import('./dev')\n await dev(port, host, arg.disableVerbose, arg.mermaid, arg.motiaDir)\n }),\n )\n\nprogram\n .command('start')\n .description('Start a server to run your Motia project')\n .option('-p, --port <port>', 'The port to run the server on', `${defaultPort}`)\n .option('-H, --host [host]', 'The host address for the server', `${defaultHost}`)\n .option('-v, --disable-verbose', 'Disable verbose logging')\n .option('-d, --debug', 'Enable debug logging')\n .option('--motia-dir <path>', 'Path where .motia folder will be created')\n .action(\n wrapAction(async (arg: any) => {\n if (arg.debug) {\n console.log('🔍 Debug logging enabled')\n process.env.LOG_LEVEL = 'debug'\n }\n\n const port = arg.port ? parseInt(arg.port) : defaultPort\n const host = arg.host ? arg.host : defaultHost\n const { start } = await import('./start')\n await start(port, host, arg.disableVerbose, arg.motiaDir)\n }),\n )\n\nprogram\n .command('emit')\n .description('Emit an event to the Motia server')\n .requiredOption('--topic <topic>', 'Event topic/type to emit')\n .requiredOption('--message <message>', 'Event payload as JSON string')\n .option('-p, --port <number>', 'Port number (default: 3000)')\n .action(\n wrapAction(async (options: any) => {\n const port = options.port || 3000\n const url = `http://localhost:${port}/emit`\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n topic: options.topic,\n data: JSON.parse(options.message),\n }),\n })\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`)\n }\n\n const result = await response.json()\n console.log('Event emitted successfully:', result)\n }),\n )\n\nconst generate = program.command('generate').description('Generate motia resources')\n\ngenerate\n .command('step')\n .description('Create a new step with interactive prompts')\n .option('-d, --dir <step file path>', 'The path relative to the steps directory, used to create the step file')\n .action(\n wrapAction(async (arg: any) => {\n const { createStep } = await import('./create-step/index')\n return createStep({\n stepFilePath: arg.dir,\n })\n }),\n )\n\ngenerate\n .command('openapi')\n .description('Generate OpenAPI spec for your project')\n .option('-t, --title <title>', 'Title for the OpenAPI document. Defaults to project name')\n .option('-v, --version <version>', 'Version for the OpenAPI document. Defaults to 1.0.0', '1.0.0')\n .option('-o, --output <output>', 'Output file for the OpenAPI document. Defaults to openapi.json', 'openapi.json')\n .action(\n wrapAction(async (options: any) => {\n const { generateLockedData, getStepFiles, getStreamFiles } = await import('./generate-locked-data')\n const { validatePythonEnvironment } = await import('./utils/validate-python-environment')\n const { activatePythonVenv } = await import('./utils/activate-python-env')\n const { generateOpenApi } = await import('./openapi/generate')\n const { MemoryStreamAdapterManager } = await import('@motiadev/core')\n\n const baseDir = process.cwd()\n const appConfig = await loadMotiaConfig(baseDir)\n\n const stepFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)]\n const hasPythonFiles = stepFiles.some((file) => file.endsWith('.py'))\n\n const pythonValidation = await validatePythonEnvironment({ baseDir, hasPythonFiles })\n if (!pythonValidation.success) {\n process.exit(1)\n }\n\n if (hasPythonFiles) {\n activatePythonVenv({ baseDir })\n }\n\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: new MemoryStreamAdapterManager(),\n streamAuth: appConfig.streamAuth,\n printerType: 'disabled',\n })\n const apiSteps = lockedData.apiSteps()\n\n generateOpenApi(process.cwd(), apiSteps, options.title, options.version, options.output)\n process.exit(0)\n }),\n )\n\nconst docker = program.command('docker').description('Motia docker commands')\n\ndocker\n .command('setup')\n .description('Setup a motia-docker for your project')\n .action(\n wrapAction(async () => {\n const { setup } = await import('./docker/setup')\n await setup()\n process.exit(0)\n }),\n )\n\ndocker\n .command('run')\n .description('Build and run your project in a docker container')\n .option('-p, --port <port>', 'The port to run the server on', `${defaultPort}`)\n .option('-n, --project-name <project name>', 'The name for your project')\n .option('-s, --skip-build', 'Skip docker build')\n .action(\n wrapAction(async (arg: any) => {\n const { run } = await import('./docker/run')\n await run(arg.port, arg.projectName, arg.skipBuild)\n process.exit(0)\n }),\n )\n\ndocker\n .command('build')\n .description('Build your project in a docker container')\n .option('-n, --project-name <project name>', 'The name for your project')\n .action(\n wrapAction(async (arg: any) => {\n const { build } = await import('./docker/build')\n await build(arg.projectName)\n process.exit(0)\n }),\n )\n\nprogram.version(version, '-V, --version', 'Output the current version')\nprogram.parseAsync(process.argv).catch(() => {\n process.exit(1)\n})\n"],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { BuildError, BuildErrorType } from "../../utils/errors/build.error.mjs";
|
|
2
2
|
import { collectFlows, getStepFiles, getStreamFiles } from "../../generate-locked-data.mjs";
|
|
3
|
+
import { activatePythonVenv } from "../../utils/activate-python-env.mjs";
|
|
4
|
+
import { validatePythonEnvironment } from "../../utils/validate-python-environment.mjs";
|
|
3
5
|
import { Builder } from "../build/builder.mjs";
|
|
4
6
|
import { distDir, projectDir, stepsConfigPath } from "./constants.mjs";
|
|
5
7
|
import { NodeBuilder } from "../build/builders/node/index.mjs";
|
|
@@ -23,7 +25,15 @@ const build = async (listener) => {
|
|
|
23
25
|
});
|
|
24
26
|
fs.mkdirSync(distDir, { recursive: true });
|
|
25
27
|
const lockedData = new LockedData(projectDir, new MemoryStreamAdapterManager(), new NoPrinter());
|
|
26
|
-
|
|
28
|
+
const hasPython = hasPythonSteps([...stepFiles, ...streamFiles]);
|
|
29
|
+
if (!(await validatePythonEnvironment({
|
|
30
|
+
baseDir: projectDir,
|
|
31
|
+
hasPythonFiles: hasPython
|
|
32
|
+
})).success) throw new BuildError(BuildErrorType.COMPILATION, void 0, "");
|
|
33
|
+
if (hasPython) {
|
|
34
|
+
activatePythonVenv({ baseDir: projectDir });
|
|
35
|
+
builder.registerBuilder("python", new PythonBuilder(builder, listener));
|
|
36
|
+
}
|
|
27
37
|
if ((await collectFlows(projectDir, lockedData).catch((err) => {
|
|
28
38
|
const finalMessage = `${err.filePath ? `Build error in ${err.filePath}` : "Build error"}\nPlease check the logs above for details`;
|
|
29
39
|
throw new BuildError(BuildErrorType.COMPILATION, err.filePath, finalMessage, err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.mjs","names":["stepsFile: StepsConfigFile"],"sources":["../../../src/cloud/new-deployment/build.ts"],"sourcesContent":["import { isApiStep, LockedData, MemoryStreamAdapterManager, NoPrinter } from '@motiadev/core'\nimport fs from 'fs'\nimport { collectFlows, getStepFiles, getStreamFiles } from '../../generate-locked-data'\nimport { BuildError, BuildErrorType } from '../../utils/errors/build.error'\nimport { Builder, type StepsConfigFile } from '../build/builder'\nimport { NodeBuilder } from '../build/builders/node/index'\nimport { PythonBuilder } from '../build/builders/python/index'\nimport { distDir, projectDir, stepsConfigPath } from './constants'\nimport type { BuildListener } from './listeners/listener.types'\n\nconst hasPythonSteps = (stepFiles: string[]) => {\n return stepFiles.some((file) => file.endsWith('.py'))\n}\n\nexport const build = async (listener: BuildListener): Promise<Builder> => {\n const builder = new Builder(projectDir, listener)\n const stepFiles = getStepFiles(projectDir)\n const streamFiles = getStreamFiles(projectDir)\n\n if (stepFiles.length === 0) {\n throw new Error('Project contains no steps, please add some steps before building')\n }\n\n // Register language-specific builders\n builder.registerBuilder('node', new NodeBuilder(builder, listener))\n\n fs.rmSync(distDir, { recursive: true, force: true })\n fs.mkdirSync(distDir, { recursive: true })\n\n const lockedData = new LockedData(projectDir, new MemoryStreamAdapterManager(), new NoPrinter())\n\n
|
|
1
|
+
{"version":3,"file":"build.mjs","names":["stepsFile: StepsConfigFile"],"sources":["../../../src/cloud/new-deployment/build.ts"],"sourcesContent":["import { isApiStep, LockedData, MemoryStreamAdapterManager, NoPrinter } from '@motiadev/core'\nimport fs from 'fs'\nimport { collectFlows, getStepFiles, getStreamFiles } from '../../generate-locked-data'\nimport { activatePythonVenv } from '../../utils/activate-python-env'\nimport { BuildError, BuildErrorType } from '../../utils/errors/build.error'\nimport { validatePythonEnvironment } from '../../utils/validate-python-environment'\nimport { Builder, type StepsConfigFile } from '../build/builder'\nimport { NodeBuilder } from '../build/builders/node/index'\nimport { PythonBuilder } from '../build/builders/python/index'\nimport { distDir, projectDir, stepsConfigPath } from './constants'\nimport type { BuildListener } from './listeners/listener.types'\n\nconst hasPythonSteps = (stepFiles: string[]) => {\n return stepFiles.some((file) => file.endsWith('.py'))\n}\n\nexport const build = async (listener: BuildListener): Promise<Builder> => {\n const builder = new Builder(projectDir, listener)\n const stepFiles = getStepFiles(projectDir)\n const streamFiles = getStreamFiles(projectDir)\n\n if (stepFiles.length === 0) {\n throw new Error('Project contains no steps, please add some steps before building')\n }\n\n // Register language-specific builders\n builder.registerBuilder('node', new NodeBuilder(builder, listener))\n\n fs.rmSync(distDir, { recursive: true, force: true })\n fs.mkdirSync(distDir, { recursive: true })\n\n const lockedData = new LockedData(projectDir, new MemoryStreamAdapterManager(), new NoPrinter())\n\n const hasPython = hasPythonSteps([...stepFiles, ...streamFiles])\n const pythonValidation = await validatePythonEnvironment({ baseDir: projectDir, hasPythonFiles: hasPython })\n if (!pythonValidation.success) {\n throw new BuildError(BuildErrorType.COMPILATION, undefined, '')\n }\n\n if (hasPython) {\n activatePythonVenv({ baseDir: projectDir })\n builder.registerBuilder('python', new PythonBuilder(builder, listener))\n }\n\n const invalidSteps = await collectFlows(projectDir, lockedData).catch((err) => {\n const errorMessage = err.filePath ? `Build error in ${err.filePath}` : 'Build error'\n\n const finalMessage = `${errorMessage}\\nPlease check the logs above for details`\n\n throw new BuildError(BuildErrorType.COMPILATION, err.filePath, finalMessage, err)\n })\n\n if (invalidSteps.length > 0) {\n throw new Error('Project contains invalid steps, please fix them before building')\n }\n\n await Promise.all(lockedData.activeSteps.map((step) => builder.buildStep(step)))\n await builder.buildApiSteps(lockedData.activeSteps.filter(isApiStep))\n\n const streams = lockedData.listStreams()\n\n for (const stream of streams) {\n if (stream.config.baseConfig.storageType === 'default') {\n builder.registerStateStream(stream)\n } else {\n listener.onWarning(stream.filePath, 'Custom streams are not supported yet in the cloud')\n }\n }\n\n const stepsFile: StepsConfigFile = {\n steps: builder.stepsConfig,\n streams: builder.streamsConfig,\n routers: builder.routersConfig,\n }\n fs.writeFileSync(stepsConfigPath, JSON.stringify(stepsFile, null, 2))\n\n return builder\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,kBAAkB,cAAwB;AAC9C,QAAO,UAAU,MAAM,SAAS,KAAK,SAAS,MAAM,CAAC;;AAGvD,MAAa,QAAQ,OAAO,aAA8C;CACxE,MAAM,UAAU,IAAI,QAAQ,YAAY,SAAS;CACjD,MAAM,YAAY,aAAa,WAAW;CAC1C,MAAM,cAAc,eAAe,WAAW;AAE9C,KAAI,UAAU,WAAW,EACvB,OAAM,IAAI,MAAM,mEAAmE;AAIrF,SAAQ,gBAAgB,QAAQ,IAAI,YAAY,SAAS,SAAS,CAAC;AAEnE,IAAG,OAAO,SAAS;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AACpD,IAAG,UAAU,SAAS,EAAE,WAAW,MAAM,CAAC;CAE1C,MAAM,aAAa,IAAI,WAAW,YAAY,IAAI,4BAA4B,EAAE,IAAI,WAAW,CAAC;CAEhG,MAAM,YAAY,eAAe,CAAC,GAAG,WAAW,GAAG,YAAY,CAAC;AAEhE,KAAI,EADqB,MAAM,0BAA0B;EAAE,SAAS;EAAY,gBAAgB;EAAW,CAAC,EACtF,QACpB,OAAM,IAAI,WAAW,eAAe,aAAa,QAAW,GAAG;AAGjE,KAAI,WAAW;AACb,qBAAmB,EAAE,SAAS,YAAY,CAAC;AAC3C,UAAQ,gBAAgB,UAAU,IAAI,cAAc,SAAS,SAAS,CAAC;;AAWzE,MARqB,MAAM,aAAa,YAAY,WAAW,CAAC,OAAO,QAAQ;EAG7E,MAAM,eAAe,GAFA,IAAI,WAAW,kBAAkB,IAAI,aAAa,cAElC;AAErC,QAAM,IAAI,WAAW,eAAe,aAAa,IAAI,UAAU,cAAc,IAAI;GACjF,EAEe,SAAS,EACxB,OAAM,IAAI,MAAM,kEAAkE;AAGpF,OAAM,QAAQ,IAAI,WAAW,YAAY,KAAK,SAAS,QAAQ,UAAU,KAAK,CAAC,CAAC;AAChF,OAAM,QAAQ,cAAc,WAAW,YAAY,OAAO,UAAU,CAAC;CAErE,MAAM,UAAU,WAAW,aAAa;AAExC,MAAK,MAAM,UAAU,QACnB,KAAI,OAAO,OAAO,WAAW,gBAAgB,UAC3C,SAAQ,oBAAoB,OAAO;KAEnC,UAAS,UAAU,OAAO,UAAU,oDAAoD;CAI5F,MAAMA,YAA6B;EACjC,OAAO,QAAQ;EACf,SAAS,QAAQ;EACjB,SAAS,QAAQ;EAClB;AACD,IAAG,cAAc,iBAAiB,KAAK,UAAU,WAAW,MAAM,EAAE,CAAC;AAErE,QAAO"}
|
package/dist/create/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { executeCommand } from "../utils/execute-command.mjs";
|
|
2
1
|
import { version } from "../version.mjs";
|
|
2
|
+
import { executeCommand } from "../utils/execute-command.mjs";
|
|
3
|
+
import { checkIfDirectoryExists, checkIfFileExists } from "./utils.mjs";
|
|
4
|
+
import { getPackageManager } from "../utils/get-package-manager.mjs";
|
|
3
5
|
import { generateTypes } from "../generate-types.mjs";
|
|
4
6
|
import { pythonInstall } from "../install.mjs";
|
|
5
7
|
import { pluginDependencies } from "../plugins/plugin-dependencies.mjs";
|
|
6
|
-
import { checkIfDirectoryExists, checkIfFileExists } from "./utils.mjs";
|
|
7
|
-
import { getPackageManager } from "../utils/get-package-manager.mjs";
|
|
8
8
|
import { pullRules } from "./pull-rules.mjs";
|
|
9
9
|
import { setupTemplate } from "./setup-template.mjs";
|
|
10
10
|
import fs from "fs";
|
package/dist/dev.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { activatePythonVenv } from "./utils/activate-python-env.mjs";
|
|
2
1
|
import { generateLockedData, getStepFiles, getStreamFiles } from "./generate-locked-data.mjs";
|
|
3
2
|
import { version } from "./version.mjs";
|
|
4
3
|
import { identifyUser } from "./utils/analytics.mjs";
|
|
4
|
+
import { activatePythonVenv } from "./utils/activate-python-env.mjs";
|
|
5
|
+
import { validatePythonEnvironment } from "./utils/validate-python-environment.mjs";
|
|
5
6
|
import { loadMotiaConfig } from "./load-motia-config.mjs";
|
|
6
7
|
import { deployEndpoints } from "./cloud/endpoints.mjs";
|
|
7
8
|
import { isTutorialDisabled, workbenchBase } from "./constants.mjs";
|
|
@@ -31,7 +32,12 @@ const dev = async (port, hostname, disableVerbose, enableMermaid, motiaFileStora
|
|
|
31
32
|
total_step_files: stepFiles.length,
|
|
32
33
|
project_name: getProjectIdentifier(baseDir)
|
|
33
34
|
});
|
|
34
|
-
|
|
35
|
+
const pythonValidation = await validatePythonEnvironment({
|
|
36
|
+
baseDir,
|
|
37
|
+
hasPythonFiles
|
|
38
|
+
});
|
|
39
|
+
if (!pythonValidation.success) process.exit(1);
|
|
40
|
+
if (pythonValidation.hasPythonFiles) {
|
|
35
41
|
activatePythonVenv({
|
|
36
42
|
baseDir,
|
|
37
43
|
isVerbose
|
package/dist/dev.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.mjs","names":["redisClient: RedisClientType","plugins: MotiaPlugin[]"],"sources":["../src/dev.ts"],"sourcesContent":["import { flush } from '@amplitude/analytics-node'\nimport { BullMQEventAdapter } from '@motiadev/adapter-bullmq-events'\nimport { RedisCronAdapter } from '@motiadev/adapter-redis-cron'\nimport { RedisStateAdapter } from '@motiadev/adapter-redis-state'\nimport { RedisStreamAdapterManager } from '@motiadev/adapter-redis-streams'\nimport {\n createMermaidGenerator,\n createServer,\n getProjectIdentifier,\n type MotiaPlugin,\n trackEvent,\n} from '@motiadev/core'\nimport type { RedisClientType } from 'redis'\nimport { deployEndpoints } from './cloud/endpoints'\nimport { isTutorialDisabled, workbenchBase } from './constants'\nimport { createDevWatchers } from './dev-watchers'\nimport { generateLockedData, getStepFiles, getStreamFiles } from './generate-locked-data'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { processPlugins } from './plugins'\nimport { getRedisClient, getRedisConnectionInfo, stopRedisConnection } from './redis/connection'\nimport { activatePythonVenv } from './utils/activate-python-env'\nimport { identifyUser } from './utils/analytics'\nimport { version } from './version'\n\nexport const dev = async (\n port: number,\n hostname: string,\n disableVerbose: boolean,\n enableMermaid: boolean,\n motiaFileStorageDir?: string,\n): Promise<void> => {\n const baseDir = process.cwd()\n const isVerbose = !disableVerbose\n\n identifyUser()\n\n const stepFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)]\n const hasPythonFiles = stepFiles.some((file) => file.endsWith('.py'))\n\n trackEvent('dev_server_started', {\n port,\n verbose_mode: isVerbose,\n mermaid_enabled: enableMermaid,\n has_python_files: hasPythonFiles,\n total_step_files: stepFiles.length,\n project_name: getProjectIdentifier(baseDir),\n })\n\n if (hasPythonFiles) {\n activatePythonVenv({ baseDir, isVerbose })\n trackEvent('python_environment_activated')\n }\n\n const motiaFileStoragePath = motiaFileStorageDir || '.motia'\n\n const appConfig = await loadMotiaConfig(baseDir)\n\n const redisClient: RedisClientType = await getRedisClient(motiaFileStoragePath, appConfig)\n\n const adapters = {\n eventAdapter:\n appConfig.adapters?.events ||\n new BullMQEventAdapter({\n connection: getRedisConnectionInfo(),\n prefix: 'motia:events',\n }),\n cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),\n streamAdapter: appConfig.adapters?.streams || new RedisStreamAdapterManager(redisClient),\n }\n\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: adapters.streamAdapter,\n redisClient,\n streamAuth: appConfig.streamAuth,\n })\n\n const state = appConfig.adapters?.state || new RedisStateAdapter(redisClient)\n\n const config = { isVerbose }\n\n const motiaServer = createServer(lockedData, state, config, adapters, appConfig.app)\n const watcher = createDevWatchers(lockedData, motiaServer, motiaServer.motiaEventManager, motiaServer.cronManager)\n const plugins: MotiaPlugin[] = await processPlugins(motiaServer)\n\n // Initialize mermaid generator\n if (enableMermaid) {\n const mermaidGenerator = createMermaidGenerator(baseDir)\n mermaidGenerator.initialize(lockedData)\n trackEvent('mermaid_generator_initialized')\n }\n\n deployEndpoints(motiaServer, lockedData)\n\n motiaServer.app.get('/__motia', (_, res) => {\n const meta = {\n version,\n isDev: true,\n isTutorialDisabled,\n workbenchBase,\n }\n\n res //\n .header('Access-Control-Allow-Origin', '*')\n .header('Access-Control-Allow-Private-Network', 'true')\n .status(200)\n .json(meta)\n })\n\n trackEvent('dev_server_ready', {\n port,\n flows_count: lockedData.flows?.length || 0,\n steps_count: lockedData.activeSteps?.length || 0,\n flows: Object.keys(lockedData.flows || {}),\n steps: lockedData.activeSteps.map((step) => step.config.name),\n streams: Object.keys(lockedData.getStreams() || {}),\n runtime_version: version,\n environment: process.env.NODE_ENV || 'development',\n })\n\n const { applyMiddleware } = await import('@motiadev/workbench/middleware')\n\n await applyMiddleware({\n app: motiaServer.app,\n port,\n workbenchBase,\n plugins: plugins.flatMap((item) => item.workbench),\n })\n\n motiaServer.server.listen(port, hostname)\n console.log('🚀 Server ready and listening on port', port)\n console.log(`🔗 Open http://localhost:${port}${workbenchBase} to open workbench 🛠️`)\n\n process.on('SIGTERM', async () => {\n trackEvent('dev_server_shutdown', { reason: 'SIGTERM' })\n motiaServer.server.close()\n await watcher.stop()\n await stopRedisConnection()\n await flush().promise\n process.exit(0)\n })\n\n process.on('SIGINT', async () => {\n trackEvent('dev_server_shutdown', { reason: 'SIGINT' })\n motiaServer.server.close()\n await watcher.stop()\n await stopRedisConnection()\n await flush().promise\n process.exit(0)\n })\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"dev.mjs","names":["redisClient: RedisClientType","plugins: MotiaPlugin[]"],"sources":["../src/dev.ts"],"sourcesContent":["import { flush } from '@amplitude/analytics-node'\nimport { BullMQEventAdapter } from '@motiadev/adapter-bullmq-events'\nimport { RedisCronAdapter } from '@motiadev/adapter-redis-cron'\nimport { RedisStateAdapter } from '@motiadev/adapter-redis-state'\nimport { RedisStreamAdapterManager } from '@motiadev/adapter-redis-streams'\nimport {\n createMermaidGenerator,\n createServer,\n getProjectIdentifier,\n type MotiaPlugin,\n trackEvent,\n} from '@motiadev/core'\nimport type { RedisClientType } from 'redis'\nimport { deployEndpoints } from './cloud/endpoints'\nimport { isTutorialDisabled, workbenchBase } from './constants'\nimport { createDevWatchers } from './dev-watchers'\nimport { generateLockedData, getStepFiles, getStreamFiles } from './generate-locked-data'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { processPlugins } from './plugins'\nimport { getRedisClient, getRedisConnectionInfo, stopRedisConnection } from './redis/connection'\nimport { activatePythonVenv } from './utils/activate-python-env'\nimport { identifyUser } from './utils/analytics'\nimport { validatePythonEnvironment } from './utils/validate-python-environment'\nimport { version } from './version'\n\nexport const dev = async (\n port: number,\n hostname: string,\n disableVerbose: boolean,\n enableMermaid: boolean,\n motiaFileStorageDir?: string,\n): Promise<void> => {\n const baseDir = process.cwd()\n const isVerbose = !disableVerbose\n\n identifyUser()\n\n const stepFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)]\n const hasPythonFiles = stepFiles.some((file) => file.endsWith('.py'))\n\n trackEvent('dev_server_started', {\n port,\n verbose_mode: isVerbose,\n mermaid_enabled: enableMermaid,\n has_python_files: hasPythonFiles,\n total_step_files: stepFiles.length,\n project_name: getProjectIdentifier(baseDir),\n })\n\n const pythonValidation = await validatePythonEnvironment({ baseDir, hasPythonFiles })\n if (!pythonValidation.success) {\n process.exit(1)\n }\n\n if (pythonValidation.hasPythonFiles) {\n activatePythonVenv({ baseDir, isVerbose })\n trackEvent('python_environment_activated')\n }\n\n const motiaFileStoragePath = motiaFileStorageDir || '.motia'\n\n const appConfig = await loadMotiaConfig(baseDir)\n\n const redisClient: RedisClientType = await getRedisClient(motiaFileStoragePath, appConfig)\n\n const adapters = {\n eventAdapter:\n appConfig.adapters?.events ||\n new BullMQEventAdapter({\n connection: getRedisConnectionInfo(),\n prefix: 'motia:events',\n }),\n cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),\n streamAdapter: appConfig.adapters?.streams || new RedisStreamAdapterManager(redisClient),\n }\n\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: adapters.streamAdapter,\n redisClient,\n streamAuth: appConfig.streamAuth,\n })\n\n const state = appConfig.adapters?.state || new RedisStateAdapter(redisClient)\n\n const config = { isVerbose }\n\n const motiaServer = createServer(lockedData, state, config, adapters, appConfig.app)\n const watcher = createDevWatchers(lockedData, motiaServer, motiaServer.motiaEventManager, motiaServer.cronManager)\n const plugins: MotiaPlugin[] = await processPlugins(motiaServer)\n\n // Initialize mermaid generator\n if (enableMermaid) {\n const mermaidGenerator = createMermaidGenerator(baseDir)\n mermaidGenerator.initialize(lockedData)\n trackEvent('mermaid_generator_initialized')\n }\n\n deployEndpoints(motiaServer, lockedData)\n\n motiaServer.app.get('/__motia', (_, res) => {\n const meta = {\n version,\n isDev: true,\n isTutorialDisabled,\n workbenchBase,\n }\n\n res //\n .header('Access-Control-Allow-Origin', '*')\n .header('Access-Control-Allow-Private-Network', 'true')\n .status(200)\n .json(meta)\n })\n\n trackEvent('dev_server_ready', {\n port,\n flows_count: lockedData.flows?.length || 0,\n steps_count: lockedData.activeSteps?.length || 0,\n flows: Object.keys(lockedData.flows || {}),\n steps: lockedData.activeSteps.map((step) => step.config.name),\n streams: Object.keys(lockedData.getStreams() || {}),\n runtime_version: version,\n environment: process.env.NODE_ENV || 'development',\n })\n\n const { applyMiddleware } = await import('@motiadev/workbench/middleware')\n\n await applyMiddleware({\n app: motiaServer.app,\n port,\n workbenchBase,\n plugins: plugins.flatMap((item) => item.workbench),\n })\n\n motiaServer.server.listen(port, hostname)\n console.log('🚀 Server ready and listening on port', port)\n console.log(`🔗 Open http://localhost:${port}${workbenchBase} to open workbench 🛠️`)\n\n process.on('SIGTERM', async () => {\n trackEvent('dev_server_shutdown', { reason: 'SIGTERM' })\n motiaServer.server.close()\n await watcher.stop()\n await stopRedisConnection()\n await flush().promise\n process.exit(0)\n })\n\n process.on('SIGINT', async () => {\n trackEvent('dev_server_shutdown', { reason: 'SIGINT' })\n motiaServer.server.close()\n await watcher.stop()\n await stopRedisConnection()\n await flush().promise\n process.exit(0)\n })\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-locked-data.d.mts","names":[],"sources":["../src/generate-locked-data.ts"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"generate-locked-data.d.mts","names":[],"sources":["../src/generate-locked-data.ts"],"sourcesContent":[],"mappings":";;;;AAwDa,cAAA,YA4EZ,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,UAAA,EA5EkE,UA4ElE,EAAA,GA5E+E,OA4E/E,CA5EuF,IA4EvF,EAAA,CAAA;KAEI,iBAAA,GA9E8D;EAAqB,YAAA,EA+ExE,gBA/EwE,CAAA,cAAA,CAAA;EAAR,aAAA,CAAA,EAgF9D,UAhF8D;CAAO;AA8ElF,cAKQ,kBAJG,EAAA,CAAA,MAAA,EAAA;EAIH,UAAA,EAAA,MAAA;EAEK,aAAA,CAAA,EAAA,oBAAA;EACF,WAAA,CAAA,EAAA,eAAA;EAED,WAAA,CAAA,EAAA,UAAA,GAAA,SAAA;EACH,UAAA,CAAA,EADG,iBACH;CAAR,EAAA,GAAA,OAAA,CAAQ,UAAR,CAAA"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { activatePythonVenv } from "./utils/activate-python-env.mjs";
|
|
2
1
|
import { CompilationError } from "./utils/errors/compilation.error.mjs";
|
|
3
2
|
import { LockedDataGenerationError } from "./utils/errors/locked-data-generation.error.mjs";
|
|
4
3
|
import { LockedData, MemoryStreamAdapterManager, NoPrinter, Printer, getStepConfig, getStreamConfig } from "@motiadev/core";
|
|
@@ -53,7 +52,6 @@ const collectFlows = async (projectDir, lockedData) => {
|
|
|
53
52
|
absolute: true,
|
|
54
53
|
cwd: srcDir
|
|
55
54
|
}) : []];
|
|
56
|
-
if (stepFiles.some((file) => file.endsWith(".py")) || streamFiles.some((file) => file.endsWith(".py"))) activatePythonVenv({ baseDir: projectDir });
|
|
57
55
|
for (const filePath of stepFiles) try {
|
|
58
56
|
const config = await getStepConfig(filePath, projectDir);
|
|
59
57
|
if (!config) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-locked-data.mjs","names":["invalidSteps: Step[]"],"sources":["../src/generate-locked-data.ts"],"sourcesContent":["import {\n getStepConfig,\n getStreamConfig,\n type JsonSchema,\n LockedData,\n MemoryStreamAdapterManager,\n NoPrinter,\n Printer,\n type Step,\n type StreamAdapterManager,\n type StreamAuthConfig,\n} from '@motiadev/core'\nimport { randomUUID } from 'crypto'\nimport { existsSync } from 'fs'\nimport { globSync } from 'glob'\nimport path from 'path'\nimport pc from 'picocolors'\nimport type { RedisClientType } from 'redis'\nimport {
|
|
1
|
+
{"version":3,"file":"generate-locked-data.mjs","names":["invalidSteps: Step[]"],"sources":["../src/generate-locked-data.ts"],"sourcesContent":["import {\n getStepConfig,\n getStreamConfig,\n type JsonSchema,\n LockedData,\n MemoryStreamAdapterManager,\n NoPrinter,\n Printer,\n type Step,\n type StreamAdapterManager,\n type StreamAuthConfig,\n} from '@motiadev/core'\nimport { randomUUID } from 'crypto'\nimport { existsSync } from 'fs'\nimport { globSync } from 'glob'\nimport path from 'path'\nimport pc from 'picocolors'\nimport type { RedisClientType } from 'redis'\nimport { CompilationError } from './utils/errors/compilation.error'\nimport { LockedDataGenerationError } from './utils/errors/locked-data-generation.error'\n\nconst version = `${randomUUID()}:${Math.floor(Date.now() / 1000)}`\n\nconst getStepFilesFromDir = (dir: string): string[] => {\n if (!existsSync(dir)) {\n return []\n }\n return [\n ...globSync('**/*.step.{ts,js,rb}', { absolute: true, cwd: dir }),\n ...globSync('**/*_step.{ts,js,py,rb}', { absolute: true, cwd: dir }),\n ]\n}\n\nexport const getStepFiles = (projectDir: string): string[] => {\n const stepsDir = path.join(projectDir, 'steps')\n const srcDir = path.join(projectDir, 'src')\n return [...getStepFilesFromDir(stepsDir), ...getStepFilesFromDir(srcDir)]\n}\n\nconst getStreamFilesFromDir = (dir: string): string[] => {\n if (!existsSync(dir)) {\n return []\n }\n return [\n ...globSync('**/*.stream.{ts,js,rb}', { absolute: true, cwd: dir }),\n ...globSync('**/*_stream.{ts,js,py,rb}', { absolute: true, cwd: dir }),\n ]\n}\n\nexport const getStreamFiles = (projectDir: string): string[] => {\n const stepsDir = path.join(projectDir, 'steps')\n const srcDir = path.join(projectDir, 'src')\n return [...getStreamFilesFromDir(stepsDir), ...getStreamFilesFromDir(srcDir)]\n}\n\n// Helper function to recursively collect flow data\nexport const collectFlows = async (projectDir: string, lockedData: LockedData): Promise<Step[]> => {\n const invalidSteps: Step[] = []\n const stepFiles = getStepFiles(projectDir)\n const streamFiles = getStreamFiles(projectDir)\n const stepsDir = path.join(projectDir, 'steps')\n const srcDir = path.join(projectDir, 'src')\n const deprecatedSteps = [\n ...(existsSync(stepsDir) ? globSync('**/*.step.py', { absolute: true, cwd: stepsDir }) : []),\n ...(existsSync(srcDir) ? globSync('**/*.step.py', { absolute: true, cwd: srcDir }) : []),\n ]\n\n for (const filePath of stepFiles) {\n try {\n const config = await getStepConfig(filePath, projectDir)\n\n if (!config) {\n console.warn(`No config found in step ${filePath}, step skipped`)\n continue\n }\n\n const result = lockedData.createStep({ filePath, version, config }, { disableTypeCreation: true })\n\n if (!result) {\n invalidSteps.push({ filePath, version, config })\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err)\n if (errorMessage.includes('Executable ruby not found') || errorMessage.includes('Executable python not found')) {\n console.warn(pc.yellow(`! [WARNING] Skipping step ${filePath}: ${errorMessage}`))\n continue\n }\n throw new CompilationError(`Error collecting flow ${filePath}`, path.relative(projectDir, filePath), err as Error)\n }\n }\n\n for (const filePath of streamFiles) {\n const config = await getStreamConfig(filePath)\n\n if (!config) {\n console.warn(`No config found in stream ${filePath}, stream skipped`)\n continue\n }\n\n lockedData.createStream({ filePath, config }, { disableTypeCreation: true })\n }\n\n if (deprecatedSteps.length > 0) {\n const warning = pc.yellow('! [WARNING]')\n console.warn(\n pc.yellow(\n [\n '',\n '========================================',\n warning,\n '',\n `Python steps with ${pc.gray('.step.py')} extensions are no longer supported.`,\n `Please rename them to ${pc.gray('_step.py')}.`,\n '',\n pc.bold('Steps:'),\n ...deprecatedSteps.map((step) =>\n pc.reset(\n `- ${pc.cyan(pc.bold(step.replace(projectDir, '')))} rename to ${pc.gray(`${step.replace(projectDir, '').replace('.step.py', '_step.py')}`)}`,\n ),\n ),\n\n '',\n 'Make sure the step names are importable from Python:',\n `- Don't use numbers, dots, dashes, commas, spaces, colons, or special characters`,\n '========================================',\n '',\n ].join('\\n'),\n ),\n )\n }\n\n return invalidSteps\n}\n\ntype StreamAuthOptions = {\n authenticate: StreamAuthConfig['authenticate']\n contextSchema?: JsonSchema\n}\n\nexport const generateLockedData = async (config: {\n projectDir: string\n streamAdapter?: StreamAdapterManager\n redisClient?: RedisClientType\n printerType?: 'disabled' | 'default'\n streamAuth?: StreamAuthOptions\n}): Promise<LockedData> => {\n try {\n const {\n projectDir,\n streamAdapter = new MemoryStreamAdapterManager(),\n printerType = 'default',\n redisClient,\n streamAuth,\n } = config\n const printer = printerType === 'disabled' ? new NoPrinter() : new Printer(projectDir)\n /*\n * NOTE: right now for performance and simplicity let's enforce a folder,\n * but we might want to remove this and scan the entire current directory\n */\n const lockedData = new LockedData(projectDir, streamAdapter, printer, redisClient)\n lockedData.setStreamAuthConfig(streamAuth)\n\n await collectFlows(projectDir, lockedData)\n lockedData.saveTypes()\n\n return lockedData\n } catch (error) {\n console.error(error)\n\n throw new LockedDataGenerationError(\n 'Failed to parse the project, generating locked data step failed',\n error as Error,\n )\n }\n}\n"],"mappings":";;;;;;;;;;AAqBA,MAAM,UAAU,GAAG,YAAY,CAAC,GAAG,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;AAEhE,MAAM,uBAAuB,QAA0B;AACrD,KAAI,CAAC,WAAW,IAAI,CAClB,QAAO,EAAE;AAEX,QAAO,CACL,GAAG,SAAS,wBAAwB;EAAE,UAAU;EAAM,KAAK;EAAK,CAAC,EACjE,GAAG,SAAS,2BAA2B;EAAE,UAAU;EAAM,KAAK;EAAK,CAAC,CACrE;;AAGH,MAAa,gBAAgB,eAAiC;CAC5D,MAAM,WAAW,KAAK,KAAK,YAAY,QAAQ;CAC/C,MAAM,SAAS,KAAK,KAAK,YAAY,MAAM;AAC3C,QAAO,CAAC,GAAG,oBAAoB,SAAS,EAAE,GAAG,oBAAoB,OAAO,CAAC;;AAG3E,MAAM,yBAAyB,QAA0B;AACvD,KAAI,CAAC,WAAW,IAAI,CAClB,QAAO,EAAE;AAEX,QAAO,CACL,GAAG,SAAS,0BAA0B;EAAE,UAAU;EAAM,KAAK;EAAK,CAAC,EACnE,GAAG,SAAS,6BAA6B;EAAE,UAAU;EAAM,KAAK;EAAK,CAAC,CACvE;;AAGH,MAAa,kBAAkB,eAAiC;CAC9D,MAAM,WAAW,KAAK,KAAK,YAAY,QAAQ;CAC/C,MAAM,SAAS,KAAK,KAAK,YAAY,MAAM;AAC3C,QAAO,CAAC,GAAG,sBAAsB,SAAS,EAAE,GAAG,sBAAsB,OAAO,CAAC;;AAI/E,MAAa,eAAe,OAAO,YAAoB,eAA4C;CACjG,MAAMA,eAAuB,EAAE;CAC/B,MAAM,YAAY,aAAa,WAAW;CAC1C,MAAM,cAAc,eAAe,WAAW;CAC9C,MAAM,WAAW,KAAK,KAAK,YAAY,QAAQ;CAC/C,MAAM,SAAS,KAAK,KAAK,YAAY,MAAM;CAC3C,MAAM,kBAAkB,CACtB,GAAI,WAAW,SAAS,GAAG,SAAS,gBAAgB;EAAE,UAAU;EAAM,KAAK;EAAU,CAAC,GAAG,EAAE,EAC3F,GAAI,WAAW,OAAO,GAAG,SAAS,gBAAgB;EAAE,UAAU;EAAM,KAAK;EAAQ,CAAC,GAAG,EAAE,CACxF;AAED,MAAK,MAAM,YAAY,UACrB,KAAI;EACF,MAAM,SAAS,MAAM,cAAc,UAAU,WAAW;AAExD,MAAI,CAAC,QAAQ;AACX,WAAQ,KAAK,2BAA2B,SAAS,gBAAgB;AACjE;;AAKF,MAAI,CAFW,WAAW,WAAW;GAAE;GAAU;GAAS;GAAQ,EAAE,EAAE,qBAAqB,MAAM,CAAC,CAGhG,cAAa,KAAK;GAAE;GAAU;GAAS;GAAQ,CAAC;UAE3C,KAAK;EACZ,MAAM,eAAe,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AACrE,MAAI,aAAa,SAAS,4BAA4B,IAAI,aAAa,SAAS,8BAA8B,EAAE;AAC9G,WAAQ,KAAK,GAAG,OAAO,6BAA6B,SAAS,IAAI,eAAe,CAAC;AACjF;;AAEF,QAAM,IAAI,iBAAiB,yBAAyB,YAAY,KAAK,SAAS,YAAY,SAAS,EAAE,IAAa;;AAItH,MAAK,MAAM,YAAY,aAAa;EAClC,MAAM,SAAS,MAAM,gBAAgB,SAAS;AAE9C,MAAI,CAAC,QAAQ;AACX,WAAQ,KAAK,6BAA6B,SAAS,kBAAkB;AACrE;;AAGF,aAAW,aAAa;GAAE;GAAU;GAAQ,EAAE,EAAE,qBAAqB,MAAM,CAAC;;AAG9E,KAAI,gBAAgB,SAAS,GAAG;EAC9B,MAAM,UAAU,GAAG,OAAO,cAAc;AACxC,UAAQ,KACN,GAAG,OACD;GACE;GACA;GACA;GACA;GACA,qBAAqB,GAAG,KAAK,WAAW,CAAC;GACzC,yBAAyB,GAAG,KAAK,WAAW,CAAC;GAC7C;GACA,GAAG,KAAK,SAAS;GACjB,GAAG,gBAAgB,KAAK,SACtB,GAAG,MACD,KAAK,GAAG,KAAK,GAAG,KAAK,KAAK,QAAQ,YAAY,GAAG,CAAC,CAAC,CAAC,aAAa,GAAG,KAAK,GAAG,KAAK,QAAQ,YAAY,GAAG,CAAC,QAAQ,YAAY,WAAW,GAAG,GAC5I,CACF;GAED;GACA;GACA;GACA;GACA;GACD,CAAC,KAAK,KAAK,CACb,CACF;;AAGH,QAAO;;AAQT,MAAa,qBAAqB,OAAO,WAMd;AACzB,KAAI;EACF,MAAM,EACJ,YACA,gBAAgB,IAAI,4BAA4B,EAChD,cAAc,WACd,aACA,eACE;EAMJ,MAAM,aAAa,IAAI,WAAW,YAAY,eAL9B,gBAAgB,aAAa,IAAI,WAAW,GAAG,IAAI,QAAQ,WAAW,EAKhB,YAAY;AAClF,aAAW,oBAAoB,WAAW;AAE1C,QAAM,aAAa,YAAY,WAAW;AAC1C,aAAW,WAAW;AAEtB,SAAO;UACA,OAAO;AACd,UAAQ,MAAM,MAAM;AAEpB,QAAM,IAAI,0BACR,mEACA,MACD"}
|
package/dist/install.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { getStepFiles, getStreamFiles } from "./generate-locked-data.mjs";
|
|
1
2
|
import { executeCommand } from "./utils/execute-command.mjs";
|
|
2
3
|
import { getPythonCommand } from "./utils/python-version-utils.mjs";
|
|
3
4
|
import { activatePythonVenv } from "./utils/activate-python-env.mjs";
|
|
4
|
-
import { getStepFiles, getStreamFiles } from "./generate-locked-data.mjs";
|
|
5
5
|
import { ensureUvInstalled } from "./utils/ensure-uv.mjs";
|
|
6
6
|
import { installLambdaPythonPackages } from "./utils/install-lambda-python-packages.mjs";
|
|
7
7
|
import fs from "fs";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { executeCommand } from "../utils/execute-command.mjs";
|
|
2
1
|
import { version } from "../version.mjs";
|
|
3
|
-
import {
|
|
2
|
+
import { executeCommand } from "../utils/execute-command.mjs";
|
|
4
3
|
import { getPackageManager } from "../utils/get-package-manager.mjs";
|
|
4
|
+
import { pluginDependencies } from "./plugin-dependencies.mjs";
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
|
package/dist/start.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { activatePythonVenv } from "./utils/activate-python-env.mjs";
|
|
2
1
|
import { generateLockedData, getStepFiles, getStreamFiles } from "./generate-locked-data.mjs";
|
|
3
2
|
import { version } from "./version.mjs";
|
|
3
|
+
import { activatePythonVenv } from "./utils/activate-python-env.mjs";
|
|
4
|
+
import { validatePythonEnvironment } from "./utils/validate-python-environment.mjs";
|
|
4
5
|
import { loadMotiaConfig } from "./load-motia-config.mjs";
|
|
5
6
|
import { workbenchBase } from "./constants.mjs";
|
|
6
7
|
import { processPlugins } from "./plugins/process-plugins.mjs";
|
|
@@ -17,7 +18,12 @@ import { RedisStreamAdapterManager } from "@motiadev/adapter-redis-streams";
|
|
|
17
18
|
const start = async (port, hostname, disableVerbose, motiaFileStorageDir) => {
|
|
18
19
|
const baseDir = process.cwd();
|
|
19
20
|
const isVerbose = !disableVerbose;
|
|
20
|
-
|
|
21
|
+
const pythonValidation = await validatePythonEnvironment({
|
|
22
|
+
baseDir,
|
|
23
|
+
hasPythonFiles: [...getStepFiles(baseDir), ...getStreamFiles(baseDir)].some((file) => file.endsWith(".py"))
|
|
24
|
+
});
|
|
25
|
+
if (!pythonValidation.success) process.exit(1);
|
|
26
|
+
if (pythonValidation.hasPythonFiles) {
|
|
21
27
|
console.log("⚙️ Activating Python environment...");
|
|
22
28
|
activatePythonVenv({
|
|
23
29
|
baseDir,
|
package/dist/start.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.mjs","names":["redisClient: RedisClientType","plugins: MotiaPlugin[]"],"sources":["../src/start.ts"],"sourcesContent":["import { BullMQEventAdapter } from '@motiadev/adapter-bullmq-events'\nimport { RedisCronAdapter } from '@motiadev/adapter-redis-cron'\nimport { RedisStateAdapter } from '@motiadev/adapter-redis-state'\nimport { RedisStreamAdapterManager } from '@motiadev/adapter-redis-streams'\nimport { createServer, type MotiaPlugin } from '@motiadev/core'\nimport path from 'path'\nimport type { RedisClientType } from 'redis'\nimport { workbenchBase } from './constants'\nimport { generateLockedData, getStepFiles, getStreamFiles } from './generate-locked-data'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { processPlugins } from './plugins/index'\nimport { getRedisClient, getRedisConnectionInfo, stopRedisConnection } from './redis/connection'\nimport { activatePythonVenv } from './utils/activate-python-env'\nimport { version } from './version'\n\nexport const start = async (\n port: number,\n hostname: string,\n disableVerbose: boolean,\n motiaFileStorageDir?: string,\n): Promise<void> => {\n const baseDir = process.cwd()\n const isVerbose = !disableVerbose\n\n const stepFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)]\n const hasPythonFiles = stepFiles.some((file) => file.endsWith('.py'))\n\n if (hasPythonFiles) {\n console.log('⚙️ Activating Python environment...')\n activatePythonVenv({ baseDir, isVerbose })\n }\n\n const motiaFileStoragePath = motiaFileStorageDir || '.motia'\n\n const dotMotia = path.join(baseDir, motiaFileStoragePath)\n const appConfig = await loadMotiaConfig(baseDir)\n\n const redisClient: RedisClientType = await getRedisClient(dotMotia, appConfig)\n\n const adapters = {\n eventAdapter:\n appConfig.adapters?.events ||\n new BullMQEventAdapter({\n connection: getRedisConnectionInfo(),\n }),\n cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),\n streamAdapter: appConfig.adapters?.streams || new RedisStreamAdapterManager(redisClient),\n }\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: adapters.streamAdapter,\n redisClient,\n streamAuth: appConfig.streamAuth,\n })\n\n const state = appConfig.adapters?.state || new RedisStateAdapter(redisClient)\n\n const config = { isVerbose, isDev: false, version }\n\n const motiaServer = createServer(lockedData, state, config, adapters, appConfig.app)\n const plugins: MotiaPlugin[] = await processPlugins(motiaServer)\n\n if (!process.env.MOTIA_DOCKER_DISABLE_WORKBENCH) {\n const { applyMiddleware } = await import('@motiadev/workbench/middleware')\n await applyMiddleware({\n app: motiaServer.app,\n port,\n workbenchBase,\n plugins: plugins.flatMap((item) => item.workbench),\n })\n }\n\n motiaServer.server.listen(port, hostname)\n console.log('🚀 Server ready and listening on port', port)\n console.log(`🔗 Open http://${hostname}:${port}${workbenchBase} to open workbench 🛠️`)\n\n process.on('SIGTERM', async () => {\n motiaServer.server.close()\n await stopRedisConnection()\n process.exit(0)\n })\n\n process.on('SIGINT', async () => {\n motiaServer.server.close()\n await stopRedisConnection()\n process.exit(0)\n })\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"start.mjs","names":["redisClient: RedisClientType","plugins: MotiaPlugin[]"],"sources":["../src/start.ts"],"sourcesContent":["import { BullMQEventAdapter } from '@motiadev/adapter-bullmq-events'\nimport { RedisCronAdapter } from '@motiadev/adapter-redis-cron'\nimport { RedisStateAdapter } from '@motiadev/adapter-redis-state'\nimport { RedisStreamAdapterManager } from '@motiadev/adapter-redis-streams'\nimport { createServer, type MotiaPlugin } from '@motiadev/core'\nimport path from 'path'\nimport type { RedisClientType } from 'redis'\nimport { workbenchBase } from './constants'\nimport { generateLockedData, getStepFiles, getStreamFiles } from './generate-locked-data'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { processPlugins } from './plugins/index'\nimport { getRedisClient, getRedisConnectionInfo, stopRedisConnection } from './redis/connection'\nimport { activatePythonVenv } from './utils/activate-python-env'\nimport { validatePythonEnvironment } from './utils/validate-python-environment'\nimport { version } from './version'\n\nexport const start = async (\n port: number,\n hostname: string,\n disableVerbose: boolean,\n motiaFileStorageDir?: string,\n): Promise<void> => {\n const baseDir = process.cwd()\n const isVerbose = !disableVerbose\n\n const stepFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)]\n const hasPythonFiles = stepFiles.some((file) => file.endsWith('.py'))\n\n const pythonValidation = await validatePythonEnvironment({ baseDir, hasPythonFiles })\n if (!pythonValidation.success) {\n process.exit(1)\n }\n\n if (pythonValidation.hasPythonFiles) {\n console.log('⚙️ Activating Python environment...')\n activatePythonVenv({ baseDir, isVerbose })\n }\n\n const motiaFileStoragePath = motiaFileStorageDir || '.motia'\n\n const dotMotia = path.join(baseDir, motiaFileStoragePath)\n const appConfig = await loadMotiaConfig(baseDir)\n\n const redisClient: RedisClientType = await getRedisClient(dotMotia, appConfig)\n\n const adapters = {\n eventAdapter:\n appConfig.adapters?.events ||\n new BullMQEventAdapter({\n connection: getRedisConnectionInfo(),\n }),\n cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),\n streamAdapter: appConfig.adapters?.streams || new RedisStreamAdapterManager(redisClient),\n }\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: adapters.streamAdapter,\n redisClient,\n streamAuth: appConfig.streamAuth,\n })\n\n const state = appConfig.adapters?.state || new RedisStateAdapter(redisClient)\n\n const config = { isVerbose, isDev: false, version }\n\n const motiaServer = createServer(lockedData, state, config, adapters, appConfig.app)\n const plugins: MotiaPlugin[] = await processPlugins(motiaServer)\n\n if (!process.env.MOTIA_DOCKER_DISABLE_WORKBENCH) {\n const { applyMiddleware } = await import('@motiadev/workbench/middleware')\n await applyMiddleware({\n app: motiaServer.app,\n port,\n workbenchBase,\n plugins: plugins.flatMap((item) => item.workbench),\n })\n }\n\n motiaServer.server.listen(port, hostname)\n console.log('🚀 Server ready and listening on port', port)\n console.log(`🔗 Open http://${hostname}:${port}${workbenchBase} to open workbench 🛠️`)\n\n process.on('SIGTERM', async () => {\n motiaServer.server.close()\n await stopRedisConnection()\n process.exit(0)\n })\n\n process.on('SIGINT', async () => {\n motiaServer.server.close()\n await stopRedisConnection()\n process.exit(0)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAgBA,MAAa,QAAQ,OACnB,MACA,UACA,gBACA,wBACkB;CAClB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,YAAY,CAAC;CAKnB,MAAM,mBAAmB,MAAM,0BAA0B;EAAE;EAAS,gBAHlD,CAAC,GAAG,aAAa,QAAQ,EAAE,GAAG,eAAe,QAAQ,CAAC,CACvC,MAAM,SAAS,KAAK,SAAS,MAAM,CAAC;EAEe,CAAC;AACrF,KAAI,CAAC,iBAAiB,QACpB,SAAQ,KAAK,EAAE;AAGjB,KAAI,iBAAiB,gBAAgB;AACnC,UAAQ,IAAI,sCAAsC;AAClD,qBAAmB;GAAE;GAAS;GAAW,CAAC;;CAG5C,MAAM,uBAAuB,uBAAuB;CAEpD,MAAM,WAAW,KAAK,KAAK,SAAS,qBAAqB;CACzD,MAAM,YAAY,MAAM,gBAAgB,QAAQ;CAEhD,MAAMA,cAA+B,MAAM,eAAe,UAAU,UAAU;CAE9E,MAAM,WAAW;EACf,cACE,UAAU,UAAU,UACpB,IAAI,mBAAmB,EACrB,YAAY,wBAAwB,EACrC,CAAC;EACJ,aAAa,UAAU,UAAU,QAAQ,IAAI,iBAAiB,YAAY;EAC1E,eAAe,UAAU,UAAU,WAAW,IAAI,0BAA0B,YAAY;EACzF;CAYD,MAAM,cAAc,aAXD,MAAM,mBAAmB;EAC1C,YAAY;EACZ,eAAe,SAAS;EACxB;EACA,YAAY,UAAU;EACvB,CAAC,EAEY,UAAU,UAAU,SAAS,IAAI,kBAAkB,YAAY,EAE9D;EAAE;EAAW,OAAO;EAAO;EAAS,EAES,UAAU,UAAU,IAAI;CACpF,MAAMC,UAAyB,MAAM,eAAe,YAAY;AAEhE,KAAI,CAAC,QAAQ,IAAI,gCAAgC;EAC/C,MAAM,EAAE,oBAAoB,MAAM,OAAO;AACzC,QAAM,gBAAgB;GACpB,KAAK,YAAY;GACjB;GACA;GACA,SAAS,QAAQ,SAAS,SAAS,KAAK,UAAU;GACnD,CAAC;;AAGJ,aAAY,OAAO,OAAO,MAAM,SAAS;AACzC,SAAQ,IAAI,yCAAyC,KAAK;AAC1D,SAAQ,IAAI,kBAAkB,SAAS,GAAG,OAAO,cAAc,wBAAwB;AAEvF,SAAQ,GAAG,WAAW,YAAY;AAChC,cAAY,OAAO,OAAO;AAC1B,QAAM,qBAAqB;AAC3B,UAAQ,KAAK,EAAE;GACf;AAEF,SAAQ,GAAG,UAAU,YAAY;AAC/B,cAAY,OAAO,OAAO;AAC1B,QAAM,qBAAqB;AAC3B,UAAQ,KAAK,EAAE;GACf"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { internalLogger } from "./internal-logger.mjs";
|
|
2
2
|
import { findPythonSitePackagesDir } from "./python-version-utils.mjs";
|
|
3
|
-
import fs from "fs";
|
|
4
3
|
import path from "path";
|
|
5
4
|
|
|
6
5
|
//#region src/utils/activate-python-env.ts
|
|
@@ -17,20 +16,15 @@ const activatePythonVenv = ({ baseDir, isVerbose = false, pythonVersion = "3.13"
|
|
|
17
16
|
baseDir,
|
|
18
17
|
pythonVersion
|
|
19
18
|
});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
internalLogger.info("Site-packages path", relativePath(sitePackagesPath));
|
|
30
|
-
}
|
|
31
|
-
} else {
|
|
32
|
-
internalLogger.error("Python virtual environment not found in python_modules/");
|
|
33
|
-
internalLogger.error("Please run `motia install` to create a new virtual environment");
|
|
19
|
+
process.env.PATH = `${venvBinPath}${path.delimiter}${process.env.PATH}`;
|
|
20
|
+
process.env.VIRTUAL_ENV = venvPath;
|
|
21
|
+
process.env.PYTHON_SITE_PACKAGES = sitePackagesPath;
|
|
22
|
+
delete process.env.PYTHONHOME;
|
|
23
|
+
if (isVerbose) {
|
|
24
|
+
const pythonPath = process.platform === "win32" ? path.join(venvBinPath, "python.exe") : path.join(venvBinPath, "python");
|
|
25
|
+
const relativePath = (path$1) => path$1.replace(baseDir, "<projectDir>");
|
|
26
|
+
internalLogger.info("Using Python", relativePath(pythonPath));
|
|
27
|
+
internalLogger.info("Site-packages path", relativePath(sitePackagesPath));
|
|
34
28
|
}
|
|
35
29
|
};
|
|
36
30
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activate-python-env.mjs","names":["path"],"sources":["../../src/utils/activate-python-env.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { internalLogger } from './internal-logger'\nimport { findPythonSitePackagesDir } from './python-version-utils'\n\ninterface VenvConfig {\n baseDir: string\n isVerbose?: boolean\n pythonVersion?: string\n}\n\nexport const getSitePackagesPath = ({ baseDir, pythonVersion = '3.13' }: VenvConfig): string => {\n const venvPath = path.join(baseDir, 'python_modules')\n const libPath = path.join(venvPath, 'lib')\n const actualPythonVersionPath = findPythonSitePackagesDir(libPath, pythonVersion)\n return path.join(venvPath, 'lib', actualPythonVersionPath, 'site-packages')\n}\n\nexport const activatePythonVenv = ({ baseDir, isVerbose = false, pythonVersion = '3.13' }: VenvConfig): void => {\n internalLogger.info('Activating Python environment')\n\n // Set the virtual environment path\n const venvPath = path.join(baseDir, 'python_modules')\n const venvBinPath = path.join(venvPath, process.platform === 'win32' ? 'Scripts' : 'bin')\n\n // Find the Python version directory using the utility function\n const sitePackagesPath = getSitePackagesPath({ baseDir, pythonVersion })\n\n //
|
|
1
|
+
{"version":3,"file":"activate-python-env.mjs","names":["path"],"sources":["../../src/utils/activate-python-env.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { internalLogger } from './internal-logger'\nimport { findPythonSitePackagesDir } from './python-version-utils'\n\ninterface VenvConfig {\n baseDir: string\n isVerbose?: boolean\n pythonVersion?: string\n}\n\nexport const getSitePackagesPath = ({ baseDir, pythonVersion = '3.13' }: VenvConfig): string => {\n const venvPath = path.join(baseDir, 'python_modules')\n const libPath = path.join(venvPath, 'lib')\n const actualPythonVersionPath = findPythonSitePackagesDir(libPath, pythonVersion)\n return path.join(venvPath, 'lib', actualPythonVersionPath, 'site-packages')\n}\n\nexport const activatePythonVenv = ({ baseDir, isVerbose = false, pythonVersion = '3.13' }: VenvConfig): void => {\n internalLogger.info('Activating Python environment')\n\n // Set the virtual environment path\n const venvPath = path.join(baseDir, 'python_modules')\n const venvBinPath = path.join(venvPath, process.platform === 'win32' ? 'Scripts' : 'bin')\n\n // Find the Python version directory using the utility function\n const sitePackagesPath = getSitePackagesPath({ baseDir, pythonVersion })\n\n // Add virtual environment to PATH\n process.env.PATH = `${venvBinPath}${path.delimiter}${process.env.PATH}`\n // Set VIRTUAL_ENV environment variable\n process.env.VIRTUAL_ENV = venvPath\n // Set PYTHON_SITE_PACKAGES with the site-packages path\n process.env.PYTHON_SITE_PACKAGES = sitePackagesPath\n // Remove PYTHONHOME if it exists as it can interfere with venv\n delete process.env.PYTHONHOME\n\n // Log Python environment information if verbose mode is enabled\n if (isVerbose) {\n const pythonPath =\n process.platform === 'win32' ? path.join(venvBinPath, 'python.exe') : path.join(venvBinPath, 'python')\n\n const relativePath = (path: string) => path.replace(baseDir, '<projectDir>')\n\n internalLogger.info('Using Python', relativePath(pythonPath))\n internalLogger.info('Site-packages path', relativePath(sitePackagesPath))\n }\n}\n"],"mappings":";;;;;AAWA,MAAa,uBAAuB,EAAE,SAAS,gBAAgB,aAAiC;CAC9F,MAAM,WAAW,KAAK,KAAK,SAAS,iBAAiB;CAErD,MAAM,0BAA0B,0BADhB,KAAK,KAAK,UAAU,MAAM,EACyB,cAAc;AACjF,QAAO,KAAK,KAAK,UAAU,OAAO,yBAAyB,gBAAgB;;AAG7E,MAAa,sBAAsB,EAAE,SAAS,YAAY,OAAO,gBAAgB,aAA+B;AAC9G,gBAAe,KAAK,gCAAgC;CAGpD,MAAM,WAAW,KAAK,KAAK,SAAS,iBAAiB;CACrD,MAAM,cAAc,KAAK,KAAK,UAAU,QAAQ,aAAa,UAAU,YAAY,MAAM;CAGzF,MAAM,mBAAmB,oBAAoB;EAAE;EAAS;EAAe,CAAC;AAGxE,SAAQ,IAAI,OAAO,GAAG,cAAc,KAAK,YAAY,QAAQ,IAAI;AAEjE,SAAQ,IAAI,cAAc;AAE1B,SAAQ,IAAI,uBAAuB;AAEnC,QAAO,QAAQ,IAAI;AAGnB,KAAI,WAAW;EACb,MAAM,aACJ,QAAQ,aAAa,UAAU,KAAK,KAAK,aAAa,aAAa,GAAG,KAAK,KAAK,aAAa,SAAS;EAExG,MAAM,gBAAgB,WAAiBA,OAAK,QAAQ,SAAS,eAAe;AAE5E,iBAAe,KAAK,gBAAgB,aAAa,WAAW,CAAC;AAC7D,iBAAe,KAAK,sBAAsB,aAAa,iBAAiB,CAAC"}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { checkIfFileExists } from "../create/utils.mjs";
|
|
2
|
+
import path from "path";
|
|
2
3
|
|
|
3
4
|
//#region src/utils/get-package-manager.ts
|
|
4
5
|
const getPackageManager = (dir) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
let currentDir = dir;
|
|
7
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
8
|
+
if (checkIfFileExists(currentDir, "yarn.lock")) return "yarn";
|
|
9
|
+
else if (checkIfFileExists(currentDir, "pnpm-lock.yaml")) return "pnpm";
|
|
10
|
+
else if (checkIfFileExists(currentDir, "package-lock.json")) return "npm";
|
|
11
|
+
else if (checkIfFileExists(currentDir, "bun.lockb") || checkIfFileExists(currentDir, "bun.lock")) return "bun";
|
|
12
|
+
currentDir = path.dirname(currentDir);
|
|
13
|
+
}
|
|
14
|
+
return "npm";
|
|
9
15
|
};
|
|
10
16
|
|
|
11
17
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-package-manager.mjs","names":[],"sources":["../../src/utils/get-package-manager.ts"],"sourcesContent":["import { checkIfFileExists } from '../create/utils'\n\nexport const getPackageManager = (dir: string): string => {\n if (checkIfFileExists(
|
|
1
|
+
{"version":3,"file":"get-package-manager.mjs","names":[],"sources":["../../src/utils/get-package-manager.ts"],"sourcesContent":["import path from 'path'\nimport { checkIfFileExists } from '../create/utils'\n\nexport const getPackageManager = (dir: string): string => {\n let currentDir = dir\n\n while (currentDir !== path.dirname(currentDir)) {\n if (checkIfFileExists(currentDir, 'yarn.lock')) {\n return 'yarn'\n } else if (checkIfFileExists(currentDir, 'pnpm-lock.yaml')) {\n return 'pnpm'\n } else if (checkIfFileExists(currentDir, 'package-lock.json')) {\n return 'npm'\n } else if (checkIfFileExists(currentDir, 'bun.lockb') || checkIfFileExists(currentDir, 'bun.lock')) {\n return 'bun'\n }\n currentDir = path.dirname(currentDir)\n }\n\n return 'npm'\n}\n"],"mappings":";;;;AAGA,MAAa,qBAAqB,QAAwB;CACxD,IAAI,aAAa;AAEjB,QAAO,eAAe,KAAK,QAAQ,WAAW,EAAE;AAC9C,MAAI,kBAAkB,YAAY,YAAY,CAC5C,QAAO;WACE,kBAAkB,YAAY,iBAAiB,CACxD,QAAO;WACE,kBAAkB,YAAY,oBAAoB,CAC3D,QAAO;WACE,kBAAkB,YAAY,YAAY,IAAI,kBAAkB,YAAY,WAAW,CAChG,QAAO;AAET,eAAa,KAAK,QAAQ,WAAW;;AAGvC,QAAO"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { internalLogger } from "./internal-logger.mjs";
|
|
2
|
+
import { getPythonCommand } from "./python-version-utils.mjs";
|
|
3
|
+
import { getPackageManager } from "./get-package-manager.mjs";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
//#region src/utils/validate-python-environment.ts
|
|
8
|
+
function getInstallCommand(baseDir) {
|
|
9
|
+
switch (getPackageManager(baseDir)) {
|
|
10
|
+
case "yarn": return "yarn install";
|
|
11
|
+
case "pnpm": return "pnpm install";
|
|
12
|
+
case "bun": return "bun install";
|
|
13
|
+
case "npm":
|
|
14
|
+
default: return "npm install";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function validatePythonEnvironment({ baseDir, hasPythonFiles, pythonVersion = "3.13" }) {
|
|
18
|
+
if (!hasPythonFiles) return {
|
|
19
|
+
success: true,
|
|
20
|
+
hasPythonFiles: false
|
|
21
|
+
};
|
|
22
|
+
try {
|
|
23
|
+
await getPythonCommand(pythonVersion, baseDir);
|
|
24
|
+
} catch {
|
|
25
|
+
internalLogger.error("Python is not installed");
|
|
26
|
+
internalLogger.info("Python files were detected in your project but Python 3 is not available");
|
|
27
|
+
internalLogger.info("Please install Python 3.10 or higher: https://www.python.org/downloads/");
|
|
28
|
+
return {
|
|
29
|
+
success: false,
|
|
30
|
+
hasPythonFiles: true
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const venvPath = path.join(baseDir, "python_modules");
|
|
34
|
+
if (!fs.existsSync(venvPath)) {
|
|
35
|
+
const installCmd = getInstallCommand(baseDir);
|
|
36
|
+
internalLogger.error("Python environment not configured");
|
|
37
|
+
internalLogger.info("The python_modules directory was not found");
|
|
38
|
+
internalLogger.info(`Run '${installCmd}' to set up your Python environment`);
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
hasPythonFiles: true
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const libPath = path.join(venvPath, "lib");
|
|
45
|
+
if (!fs.existsSync(libPath)) {
|
|
46
|
+
const installCmd = getInstallCommand(baseDir);
|
|
47
|
+
internalLogger.error("Python environment is incomplete");
|
|
48
|
+
internalLogger.info("The python_modules directory exists but appears to be corrupted");
|
|
49
|
+
internalLogger.info(`Run '${installCmd}' to recreate your Python environment`);
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
hasPythonFiles: true
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
if (fs.readdirSync(libPath).filter((item) => item.startsWith("python3")).length === 0) {
|
|
57
|
+
const installCmd = getInstallCommand(baseDir);
|
|
58
|
+
internalLogger.error("Python environment is incomplete");
|
|
59
|
+
internalLogger.info("The python_modules/lib directory exists but contains no Python version directories");
|
|
60
|
+
internalLogger.info(`Run '${installCmd}' to recreate your Python environment`);
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
hasPythonFiles: true
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
const installCmd = getInstallCommand(baseDir);
|
|
68
|
+
internalLogger.error("Python environment is incomplete");
|
|
69
|
+
internalLogger.info("The python_modules/lib directory cannot be read");
|
|
70
|
+
internalLogger.info(`Run '${installCmd}' to recreate your Python environment`);
|
|
71
|
+
return {
|
|
72
|
+
success: false,
|
|
73
|
+
hasPythonFiles: true
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
success: true,
|
|
78
|
+
hasPythonFiles: true
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
export { validatePythonEnvironment };
|
|
84
|
+
//# sourceMappingURL=validate-python-environment.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-python-environment.mjs","names":["error: any"],"sources":["../../src/utils/validate-python-environment.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { getPackageManager } from './get-package-manager'\nimport { internalLogger } from './internal-logger'\nimport { getPythonCommand } from './python-version-utils'\n\nexport interface ValidationResult {\n success: boolean\n hasPythonFiles: boolean\n}\n\ninterface ValidateConfig {\n baseDir: string\n hasPythonFiles: boolean\n pythonVersion?: string\n}\n\nfunction getInstallCommand(baseDir: string): string {\n const pm = getPackageManager(baseDir)\n switch (pm) {\n case 'yarn':\n return 'yarn install'\n case 'pnpm':\n return 'pnpm install'\n case 'bun':\n return 'bun install'\n case 'npm':\n default:\n return 'npm install'\n }\n}\n\nexport async function validatePythonEnvironment({\n baseDir,\n hasPythonFiles,\n pythonVersion = '3.13',\n}: ValidateConfig): Promise<ValidationResult> {\n if (!hasPythonFiles) {\n return { success: true, hasPythonFiles: false }\n }\n\n try {\n await getPythonCommand(pythonVersion, baseDir)\n } catch {\n internalLogger.error('Python is not installed')\n internalLogger.info('Python files were detected in your project but Python 3 is not available')\n internalLogger.info('Please install Python 3.10 or higher: https://www.python.org/downloads/')\n return { success: false, hasPythonFiles: true }\n }\n\n const venvPath = path.join(baseDir, 'python_modules')\n if (!fs.existsSync(venvPath)) {\n const installCmd = getInstallCommand(baseDir)\n internalLogger.error('Python environment not configured')\n internalLogger.info('The python_modules directory was not found')\n internalLogger.info(`Run '${installCmd}' to set up your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n\n const libPath = path.join(venvPath, 'lib')\n if (!fs.existsSync(libPath)) {\n const installCmd = getInstallCommand(baseDir)\n internalLogger.error('Python environment is incomplete')\n internalLogger.info('The python_modules directory exists but appears to be corrupted')\n internalLogger.info(`Run '${installCmd}' to recreate your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n\n try {\n const libContents = fs.readdirSync(libPath)\n const pythonDirs = libContents.filter((item) => item.startsWith('python3'))\n\n if (pythonDirs.length === 0) {\n const installCmd = getInstallCommand(baseDir)\n internalLogger.error('Python environment is incomplete')\n internalLogger.info('The python_modules/lib directory exists but contains no Python version directories')\n internalLogger.info(`Run '${installCmd}' to recreate your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n } catch (error: any) {\n const installCmd = getInstallCommand(baseDir)\n internalLogger.error('Python environment is incomplete')\n internalLogger.info('The python_modules/lib directory cannot be read')\n internalLogger.info(`Run '${installCmd}' to recreate your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n\n return { success: true, hasPythonFiles: true }\n}\n"],"mappings":";;;;;;;AAiBA,SAAS,kBAAkB,SAAyB;AAElD,SADW,kBAAkB,QAAQ,EACrC;EACE,KAAK,OACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,KAAK;EACL,QACE,QAAO;;;AAIb,eAAsB,0BAA0B,EAC9C,SACA,gBACA,gBAAgB,UAC4B;AAC5C,KAAI,CAAC,eACH,QAAO;EAAE,SAAS;EAAM,gBAAgB;EAAO;AAGjD,KAAI;AACF,QAAM,iBAAiB,eAAe,QAAQ;SACxC;AACN,iBAAe,MAAM,0BAA0B;AAC/C,iBAAe,KAAK,2EAA2E;AAC/F,iBAAe,KAAK,0EAA0E;AAC9F,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;CAGjD,MAAM,WAAW,KAAK,KAAK,SAAS,iBAAiB;AACrD,KAAI,CAAC,GAAG,WAAW,SAAS,EAAE;EAC5B,MAAM,aAAa,kBAAkB,QAAQ;AAC7C,iBAAe,MAAM,oCAAoC;AACzD,iBAAe,KAAK,6CAA6C;AACjE,iBAAe,KAAK,QAAQ,WAAW,qCAAqC;AAC5E,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;CAGjD,MAAM,UAAU,KAAK,KAAK,UAAU,MAAM;AAC1C,KAAI,CAAC,GAAG,WAAW,QAAQ,EAAE;EAC3B,MAAM,aAAa,kBAAkB,QAAQ;AAC7C,iBAAe,MAAM,mCAAmC;AACxD,iBAAe,KAAK,kEAAkE;AACtF,iBAAe,KAAK,QAAQ,WAAW,uCAAuC;AAC9E,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;AAGjD,KAAI;AAIF,MAHoB,GAAG,YAAY,QAAQ,CACZ,QAAQ,SAAS,KAAK,WAAW,UAAU,CAAC,CAE5D,WAAW,GAAG;GAC3B,MAAM,aAAa,kBAAkB,QAAQ;AAC7C,kBAAe,MAAM,mCAAmC;AACxD,kBAAe,KAAK,qFAAqF;AACzG,kBAAe,KAAK,QAAQ,WAAW,uCAAuC;AAC9E,UAAO;IAAE,SAAS;IAAO,gBAAgB;IAAM;;UAE1CA,OAAY;EACnB,MAAM,aAAa,kBAAkB,QAAQ;AAC7C,iBAAe,MAAM,mCAAmC;AACxD,iBAAe,KAAK,kDAAkD;AACtE,iBAAe,KAAK,QAAQ,WAAW,uCAAuC;AAC9E,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;AAGjD,QAAO;EAAE,SAAS;EAAM,gBAAgB;EAAM"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "motia",
|
|
3
3
|
"description": "Build production-grade backends with a single primitive. APIs, background jobs, Queues, Workflows, and AI agents - unified in one system with built-in State management, Streaming, and Observability.",
|
|
4
|
-
"version": "0.15.5-beta.
|
|
4
|
+
"version": "0.15.5-beta.174-105737",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
"table": "^6.9.0",
|
|
47
47
|
"ts-node": "^10.9.2",
|
|
48
48
|
"zod": "^4.1.12",
|
|
49
|
-
"@motiadev/adapter-bullmq-events": "0.15.5-beta.
|
|
50
|
-
"@motiadev/adapter-redis-state": "0.15.5-beta.
|
|
51
|
-
"@motiadev/adapter-redis-
|
|
52
|
-
"@motiadev/core": "0.15.5-beta.
|
|
53
|
-
"@motiadev/
|
|
54
|
-
"@motiadev/
|
|
55
|
-
"@motiadev/workbench": "0.15.5-beta.
|
|
49
|
+
"@motiadev/adapter-bullmq-events": "0.15.5-beta.174-105737",
|
|
50
|
+
"@motiadev/adapter-redis-state": "0.15.5-beta.174-105737",
|
|
51
|
+
"@motiadev/adapter-redis-streams": "0.15.5-beta.174-105737",
|
|
52
|
+
"@motiadev/core": "0.15.5-beta.174-105737",
|
|
53
|
+
"@motiadev/adapter-redis-cron": "0.15.5-beta.174-105737",
|
|
54
|
+
"@motiadev/stream-client-node": "0.15.5-beta.174-105737",
|
|
55
|
+
"@motiadev/workbench": "0.15.5-beta.174-105737"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@amplitude/analytics-types": "^2.9.2",
|