motia 0.14.0-beta.165-958021 → 0.14.0-beta.165-246284
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/create/index.mjs +1 -1
- package/dist/create/index.mjs.map +1 -1
- package/dist/create/interactive.mjs +1 -2
- package/dist/create/interactive.mjs.map +1 -1
- package/dist/create/templates/index.mjs +1 -2
- package/dist/create/templates/index.mjs.map +1 -1
- package/dist/create/templates/index.ts +0 -1
- package/dist/create/templates/plugin/README.md.txt +57 -12
- package/dist/create/templates/plugin/package.json.txt +32 -24
- package/dist/create/templates/plugin/src/components/example-page.tsx.txt +1 -2
- package/dist/create/templates/plugin/src/index.ts.txt +0 -2
- package/dist/create/templates/plugin/tsdown.config.ts.txt +53 -0
- package/dist/cursor-rules/dot-files/.aider.conf.yml +32 -0
- package/dist/docker/setup.mjs +8 -2
- package/dist/docker/setup.mjs.map +1 -1
- package/package.json +8 -9
- package/dist/create/templates/hello_mixed/requirements.txt +0 -3
- package/dist/create/templates/hello_multilang/README.md.txt +0 -103
- package/dist/create/templates/hello_multilang/motia-workbench.json +0 -16
- package/dist/create/templates/hello_multilang/motia.config.ts.txt +0 -10
- package/dist/create/templates/hello_multilang/requirements.txt +0 -2
- package/dist/create/templates/hello_multilang/steps/hello/hello-api.step.ts.txt +0 -46
- package/dist/create/templates/hello_multilang/steps/hello/process_greeting_step.py.txt +0 -65
- package/dist/create/templates/plugin/vite.config.ts.txt +0 -30
package/dist/create/index.mjs
CHANGED
|
@@ -150,7 +150,7 @@ const create = async ({ projectName, template, cursorEnabled, context }) => {
|
|
|
150
150
|
let packageManager;
|
|
151
151
|
if (!isPluginTemplate) {
|
|
152
152
|
packageManager = await installNodeDependencies(rootDir, context);
|
|
153
|
-
if (template.includes("python")
|
|
153
|
+
if (template.includes("python")) await pythonInstall({ baseDir: rootDir });
|
|
154
154
|
await generateTypes(rootDir);
|
|
155
155
|
} else packageManager = await preparePackageManager(rootDir, context);
|
|
156
156
|
const projectDirName = path.basename(rootDir);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["packageManager: string"],"sources":["../../src/create/index.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport pc from 'picocolors'\nimport type { CliContext, Message } from '../cloud/config-utils'\nimport { generateTypes } from '../generate-types'\nimport { pythonInstall } from '../install'\nimport { pluginDependencies } from '../plugins/plugin-dependencies'\nimport { executeCommand } from '../utils/execute-command'\nimport { getPackageManager } from '../utils/get-package-manager'\nimport { version } from '../version'\nimport { pullRules } from './pull-rules'\nimport { setupTemplate } from './setup-template'\nimport { checkIfDirectoryExists, checkIfFileExists } from './utils'\n\nconst installRequiredDependencies = async (packageManager: string, rootDir: string, context: CliContext) => {\n context.log('installing-dependencies', (message: Message) => message.tag('info').append('Installing dependencies...'))\n\n const installCommand = {\n npm: 'npm install --save',\n yarn: 'yarn add',\n pnpm: 'pnpm add',\n }[packageManager]\n\n const dependencies = [\n `motia@${version}`,\n 'zod@4.1.12',\n `@motiadev/adapter-bullmq-events@${version}`,\n ...pluginDependencies.map((dep: string) => `${dep}@${version}`),\n ].join(' ')\n\n const devDependencies = ['ts-node@10.9.2', 'typescript@5.7.3', '@types/react@19.1.1'].join(' ')\n\n try {\n await executeCommand(`${installCommand} ${dependencies}`, rootDir)\n await executeCommand(`${installCommand} -D ${devDependencies}`, rootDir)\n\n context.log('dependencies-installed', (message: Message) => message.tag('success').append('Dependencies installed'))\n } catch (error) {\n console.error('❌ Failed to install dependencies:', error)\n }\n}\n\nconst preparePackageManager = async (rootDir: string, context: CliContext) => {\n let packageManager = 'npm'\n const detectedPackageManager = getPackageManager(rootDir)\n\n if (detectedPackageManager !== 'unknown') {\n context.log('package-manager-detected', (message: Message) =>\n message.tag('info').append('Detected package manager').append(detectedPackageManager, 'gray'),\n )\n packageManager = detectedPackageManager\n } else {\n context.log('package-manager-using-default', (message: Message) =>\n message.tag('info').append('Using default package manager').append(packageManager, 'gray'),\n )\n }\n\n return packageManager\n}\n\nconst installNodeDependencies = async (rootDir: string, context: CliContext) => {\n const packageManager = await preparePackageManager(rootDir, context)\n\n await installRequiredDependencies(packageManager, rootDir, context).catch((error: unknown) => {\n context.log('failed-to-install-dependencies', (message: Message) =>\n message.tag('failed').append('Failed to install dependencies'),\n )\n console.error(error)\n })\n\n return packageManager\n}\n\ntype Args = {\n projectName: string\n template: string\n cursorEnabled: boolean\n context: CliContext\n skipTutorialTemplates?: boolean\n}\n\nexport const create = async ({ projectName, template, cursorEnabled, context }: Args): Promise<void> => {\n console.log(\n '\\n\\n' +\n `\n _____ ______ ______ ______\n /'\\\\_/\\`\\\\/\\\\ __\\`\\\\/\\\\__ _\\\\/\\\\__ _\\\\ /\\\\ _ \\\\\n /\\\\ \\\\ \\\\ \\\\/\\\\ \\\\/_/\\\\ \\\\/\\\\/_/\\\\ \\\\/ \\\\ \\\\ \\\\L\\\\ \\\\\n \\\\ \\\\ \\\\__\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ __ \\\\\n \\\\ \\\\ \\\\_/\\\\ \\\\ \\\\ \\\\_\\\\ \\\\ \\\\ \\\\ \\\\ \\\\_\\\\ \\\\__\\\\ \\\\ \\\\/\\\\ \\\\\n \\\\ \\\\_\\\\\\\\ \\\\_\\\\ \\\\_____\\\\ \\\\ \\\\_\\\\ /\\\\_____\\\\\\\\ \\\\_\\\\ \\\\_\\\\\n \\\\/_/ \\\\/_/\\\\/_____/ \\\\/_/ \\\\/_____/ \\\\/_/\\\\/_/\n ` +\n '\\n\\n',\n )\n\n const isCurrentDir = projectName === '.' || projectName === './' || projectName === '.\\\\'\n const rootDir = isCurrentDir ? process.cwd() : path.join(process.cwd(), projectName)\n const isPluginTemplate = template === 'plugin'\n\n if (!isCurrentDir && !checkIfDirectoryExists(rootDir)) {\n fs.mkdirSync(path.join(rootDir))\n context.log('directory-created', (message: Message) =>\n message.tag('success').append('Directory created ').append(projectName, 'gray'),\n )\n } else {\n context.log('directory-using', (message: Message) => message.tag('info').append('Using current directory'))\n }\n\n // Plugin template handles package.json differently (via template)\n if (!isPluginTemplate && !checkIfFileExists(rootDir, 'package.json')) {\n const finalProjectName =\n !projectName || projectName === '.' || projectName === './' || projectName === '.\\\\'\n ? path.basename(process.cwd())\n : projectName.trim()\n\n const packageJsonContent = {\n name: finalProjectName,\n description: '',\n type: 'module',\n scripts: {\n postinstall: 'motia install',\n dev: 'motia dev',\n start: 'motia start',\n 'generate-types': 'motia generate-types',\n build: 'motia build',\n clean: 'rm -rf dist node_modules python_modules .motia .mermaid',\n //'generate:config': 'motia get-config --output ./', TODO: doesnt work at the moment\n },\n keywords: ['motia'],\n }\n\n fs.writeFileSync(path.join(rootDir, 'package.json'), JSON.stringify(packageJsonContent, null, 2))\n\n context.log('package-json-created', (message: Message) =>\n message.tag('success').append('File').append('package.json', 'cyan').append('has been created.'),\n )\n } else if (!isPluginTemplate) {\n const packageJsonPath = path.join(rootDir, 'package.json')\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))\n\n if (!packageJson.scripts) {\n packageJson.scripts = {}\n }\n\n if (!packageJson.scripts.dev) {\n packageJson.scripts.dev = 'motia dev'\n } else {\n packageJson.scripts.olddev = packageJson.scripts.dev\n packageJson.scripts.dev = 'motia dev'\n context.log('dev-command-already-exists', (message: Message) =>\n message.tag('warning').append('dev command already exists in package.json'),\n )\n }\n\n fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))\n context.log('dev-command-updated', (message: Message) =>\n message\n .tag('success')\n .append('Updated')\n .append('dev', 'gray')\n .append('command to')\n .append('package.json', 'gray'),\n )\n }\n\n // Plugin template handles tsconfig.json via template\n if (!isPluginTemplate && !checkIfFileExists(rootDir, 'tsconfig.json')) {\n const tsconfigContent = {\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n noEmit: true,\n esModuleInterop: true,\n strict: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n resolveJsonModule: true,\n allowJs: true,\n outDir: 'dist',\n rootDir: '.',\n baseUrl: '.',\n jsx: 'react-jsx',\n },\n include: ['**/*.ts', 'motia.config.ts', '**/*.tsx', 'types.d.ts', '**/*.jsx'],\n exclude: ['node_modules', 'dist', 'tests'],\n }\n\n fs.writeFileSync(path.join(rootDir, 'tsconfig.json'), JSON.stringify(tsconfigContent, null, 2))\n context.log('tsconfig-json-created', (message: Message) =>\n message.tag('success').append('File').append('tsconfig.json', 'cyan').append('has been created.'),\n )\n }\n\n // Plugin template handles .gitignore via template\n if (!isPluginTemplate && !checkIfFileExists(rootDir, '.gitignore')) {\n const gitignoreContent = [\n 'node_modules',\n 'python_modules',\n '.venv',\n 'venv',\n '.motia',\n '.mermaid',\n 'dist',\n '*.pyc',\n ].join('\\n')\n\n fs.writeFileSync(path.join(rootDir, '.gitignore'), gitignoreContent)\n context.log('gitignore-created', (message: Message) =>\n message.tag('success').append('File').append('.gitignore', 'cyan').append('has been created.'),\n )\n }\n\n // Skip cursor rules for plugin template\n if (!isPluginTemplate && cursorEnabled) {\n await pullRules({ force: true, rootDir }, context)\n }\n\n if (template) {\n await setupTemplate(template, rootDir, context)\n }\n\n let packageManager: string\n if (!isPluginTemplate) {\n packageManager = await installNodeDependencies(rootDir, context)\n\n if (template.includes('python') || template.includes('multilang')) {\n await pythonInstall({ baseDir: rootDir })\n }\n\n await generateTypes(rootDir)\n } else {\n // For plugin template, just detect the package manager\n packageManager = await preparePackageManager(rootDir, context)\n }\n\n const projectDirName = path.basename(rootDir)\n const devCommand = `${packageManager} run dev`\n const port = 3000\n const cdCommand = isCurrentDir ? '' : `${pc.cyan(`cd ${projectDirName}`)}\\n `\n\n context.log('success-blank', (message) => message.text(''))\n context.log('success-header', (message) =>\n message.text(`${pc.green('✨')} ${pc.bold('All set! Your project is ready to go.')}`),\n )\n context.log('success-blank-2', (message) => message.text(''))\n context.log('success-get-started', (message) => message.text('Get started:'))\n context.log('success-blank-3', (message) => message.text(''))\n context.log('success-commands', (message) => message.text(` ${cdCommand}${pc.cyan(devCommand)}`))\n context.log('success-blank-4', (message) => message.text(''))\n context.log('success-open', (message) => message.text(`Then open ${pc.cyan(`http://localhost:${port}`)}`))\n context.log('success-blank-5', (message: Message) => message.text(''))\n context.log('success-docs', (message) => message.text(`Docs: ${pc.cyan('https://www.motia.dev/docs')}`))\n context.log('success-blank-6', (message) => message.text(''))\n context.log('success-signoff', (message) => message.text('Happy coding! 🚀'))\n context.log('success-blank-7', (message) => message.text(''))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["packageManager: string"],"sources":["../../src/create/index.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport pc from 'picocolors'\nimport type { CliContext, Message } from '../cloud/config-utils'\nimport { generateTypes } from '../generate-types'\nimport { pythonInstall } from '../install'\nimport { pluginDependencies } from '../plugins/plugin-dependencies'\nimport { executeCommand } from '../utils/execute-command'\nimport { getPackageManager } from '../utils/get-package-manager'\nimport { version } from '../version'\nimport { pullRules } from './pull-rules'\nimport { setupTemplate } from './setup-template'\nimport { checkIfDirectoryExists, checkIfFileExists } from './utils'\n\nconst installRequiredDependencies = async (packageManager: string, rootDir: string, context: CliContext) => {\n context.log('installing-dependencies', (message: Message) => message.tag('info').append('Installing dependencies...'))\n\n const installCommand = {\n npm: 'npm install --save',\n yarn: 'yarn add',\n pnpm: 'pnpm add',\n }[packageManager]\n\n const dependencies = [\n `motia@${version}`,\n 'zod@4.1.12',\n `@motiadev/adapter-bullmq-events@${version}`,\n ...pluginDependencies.map((dep: string) => `${dep}@${version}`),\n ].join(' ')\n\n const devDependencies = ['ts-node@10.9.2', 'typescript@5.7.3', '@types/react@19.1.1'].join(' ')\n\n try {\n await executeCommand(`${installCommand} ${dependencies}`, rootDir)\n await executeCommand(`${installCommand} -D ${devDependencies}`, rootDir)\n\n context.log('dependencies-installed', (message: Message) => message.tag('success').append('Dependencies installed'))\n } catch (error) {\n console.error('❌ Failed to install dependencies:', error)\n }\n}\n\nconst preparePackageManager = async (rootDir: string, context: CliContext) => {\n let packageManager = 'npm'\n const detectedPackageManager = getPackageManager(rootDir)\n\n if (detectedPackageManager !== 'unknown') {\n context.log('package-manager-detected', (message: Message) =>\n message.tag('info').append('Detected package manager').append(detectedPackageManager, 'gray'),\n )\n packageManager = detectedPackageManager\n } else {\n context.log('package-manager-using-default', (message: Message) =>\n message.tag('info').append('Using default package manager').append(packageManager, 'gray'),\n )\n }\n\n return packageManager\n}\n\nconst installNodeDependencies = async (rootDir: string, context: CliContext) => {\n const packageManager = await preparePackageManager(rootDir, context)\n\n await installRequiredDependencies(packageManager, rootDir, context).catch((error: unknown) => {\n context.log('failed-to-install-dependencies', (message: Message) =>\n message.tag('failed').append('Failed to install dependencies'),\n )\n console.error(error)\n })\n\n return packageManager\n}\n\ntype Args = {\n projectName: string\n template: string\n cursorEnabled: boolean\n context: CliContext\n skipTutorialTemplates?: boolean\n}\n\nexport const create = async ({ projectName, template, cursorEnabled, context }: Args): Promise<void> => {\n console.log(\n '\\n\\n' +\n `\n _____ ______ ______ ______\n /'\\\\_/\\`\\\\/\\\\ __\\`\\\\/\\\\__ _\\\\/\\\\__ _\\\\ /\\\\ _ \\\\\n /\\\\ \\\\ \\\\ \\\\/\\\\ \\\\/_/\\\\ \\\\/\\\\/_/\\\\ \\\\/ \\\\ \\\\ \\\\L\\\\ \\\\\n \\\\ \\\\ \\\\__\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ __ \\\\\n \\\\ \\\\ \\\\_/\\\\ \\\\ \\\\ \\\\_\\\\ \\\\ \\\\ \\\\ \\\\ \\\\_\\\\ \\\\__\\\\ \\\\ \\\\/\\\\ \\\\\n \\\\ \\\\_\\\\\\\\ \\\\_\\\\ \\\\_____\\\\ \\\\ \\\\_\\\\ /\\\\_____\\\\\\\\ \\\\_\\\\ \\\\_\\\\\n \\\\/_/ \\\\/_/\\\\/_____/ \\\\/_/ \\\\/_____/ \\\\/_/\\\\/_/\n ` +\n '\\n\\n',\n )\n\n const isCurrentDir = projectName === '.' || projectName === './' || projectName === '.\\\\'\n const rootDir = isCurrentDir ? process.cwd() : path.join(process.cwd(), projectName)\n const isPluginTemplate = template === 'plugin'\n\n if (!isCurrentDir && !checkIfDirectoryExists(rootDir)) {\n fs.mkdirSync(path.join(rootDir))\n context.log('directory-created', (message: Message) =>\n message.tag('success').append('Directory created ').append(projectName, 'gray'),\n )\n } else {\n context.log('directory-using', (message: Message) => message.tag('info').append('Using current directory'))\n }\n\n // Plugin template handles package.json differently (via template)\n if (!isPluginTemplate && !checkIfFileExists(rootDir, 'package.json')) {\n const finalProjectName =\n !projectName || projectName === '.' || projectName === './' || projectName === '.\\\\'\n ? path.basename(process.cwd())\n : projectName.trim()\n\n const packageJsonContent = {\n name: finalProjectName,\n description: '',\n type: 'module',\n scripts: {\n postinstall: 'motia install',\n dev: 'motia dev',\n start: 'motia start',\n 'generate-types': 'motia generate-types',\n build: 'motia build',\n clean: 'rm -rf dist node_modules python_modules .motia .mermaid',\n //'generate:config': 'motia get-config --output ./', TODO: doesnt work at the moment\n },\n keywords: ['motia'],\n }\n\n fs.writeFileSync(path.join(rootDir, 'package.json'), JSON.stringify(packageJsonContent, null, 2))\n\n context.log('package-json-created', (message: Message) =>\n message.tag('success').append('File').append('package.json', 'cyan').append('has been created.'),\n )\n } else if (!isPluginTemplate) {\n const packageJsonPath = path.join(rootDir, 'package.json')\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))\n\n if (!packageJson.scripts) {\n packageJson.scripts = {}\n }\n\n if (!packageJson.scripts.dev) {\n packageJson.scripts.dev = 'motia dev'\n } else {\n packageJson.scripts.olddev = packageJson.scripts.dev\n packageJson.scripts.dev = 'motia dev'\n context.log('dev-command-already-exists', (message: Message) =>\n message.tag('warning').append('dev command already exists in package.json'),\n )\n }\n\n fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))\n context.log('dev-command-updated', (message: Message) =>\n message\n .tag('success')\n .append('Updated')\n .append('dev', 'gray')\n .append('command to')\n .append('package.json', 'gray'),\n )\n }\n\n // Plugin template handles tsconfig.json via template\n if (!isPluginTemplate && !checkIfFileExists(rootDir, 'tsconfig.json')) {\n const tsconfigContent = {\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n noEmit: true,\n esModuleInterop: true,\n strict: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n resolveJsonModule: true,\n allowJs: true,\n outDir: 'dist',\n rootDir: '.',\n baseUrl: '.',\n jsx: 'react-jsx',\n },\n include: ['**/*.ts', 'motia.config.ts', '**/*.tsx', 'types.d.ts', '**/*.jsx'],\n exclude: ['node_modules', 'dist', 'tests'],\n }\n\n fs.writeFileSync(path.join(rootDir, 'tsconfig.json'), JSON.stringify(tsconfigContent, null, 2))\n context.log('tsconfig-json-created', (message: Message) =>\n message.tag('success').append('File').append('tsconfig.json', 'cyan').append('has been created.'),\n )\n }\n\n // Plugin template handles .gitignore via template\n if (!isPluginTemplate && !checkIfFileExists(rootDir, '.gitignore')) {\n const gitignoreContent = [\n 'node_modules',\n 'python_modules',\n '.venv',\n 'venv',\n '.motia',\n '.mermaid',\n 'dist',\n '*.pyc',\n ].join('\\n')\n\n fs.writeFileSync(path.join(rootDir, '.gitignore'), gitignoreContent)\n context.log('gitignore-created', (message: Message) =>\n message.tag('success').append('File').append('.gitignore', 'cyan').append('has been created.'),\n )\n }\n\n // Skip cursor rules for plugin template\n if (!isPluginTemplate && cursorEnabled) {\n await pullRules({ force: true, rootDir }, context)\n }\n\n if (template) {\n await setupTemplate(template, rootDir, context)\n }\n\n let packageManager: string\n if (!isPluginTemplate) {\n packageManager = await installNodeDependencies(rootDir, context)\n\n if (template.includes('python')) {\n await pythonInstall({ baseDir: rootDir })\n }\n\n await generateTypes(rootDir)\n } else {\n // For plugin template, just detect the package manager\n packageManager = await preparePackageManager(rootDir, context)\n }\n\n const projectDirName = path.basename(rootDir)\n const devCommand = `${packageManager} run dev`\n const port = 3000\n const cdCommand = isCurrentDir ? '' : `${pc.cyan(`cd ${projectDirName}`)}\\n `\n\n context.log('success-blank', (message) => message.text(''))\n context.log('success-header', (message) =>\n message.text(`${pc.green('✨')} ${pc.bold('All set! Your project is ready to go.')}`),\n )\n context.log('success-blank-2', (message) => message.text(''))\n context.log('success-get-started', (message) => message.text('Get started:'))\n context.log('success-blank-3', (message) => message.text(''))\n context.log('success-commands', (message) => message.text(` ${cdCommand}${pc.cyan(devCommand)}`))\n context.log('success-blank-4', (message) => message.text(''))\n context.log('success-open', (message) => message.text(`Then open ${pc.cyan(`http://localhost:${port}`)}`))\n context.log('success-blank-5', (message: Message) => message.text(''))\n context.log('success-docs', (message) => message.text(`Docs: ${pc.cyan('https://www.motia.dev/docs')}`))\n context.log('success-blank-6', (message) => message.text(''))\n context.log('success-signoff', (message) => message.text('Happy coding! 🚀'))\n context.log('success-blank-7', (message) => message.text(''))\n}\n"],"mappings":"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"}
|
|
@@ -8,8 +8,7 @@ const choices = {
|
|
|
8
8
|
"motia-tutorial-python": "Tutorial (Python)",
|
|
9
9
|
"starter-typescript": "Starter (TypeScript)",
|
|
10
10
|
"starter-javascript": "Starter (JavaScript)",
|
|
11
|
-
"starter-python": "Starter (Python)"
|
|
12
|
-
"starter-multilang": "Starter (Multi-language: TypeScript + Python)"
|
|
11
|
+
"starter-python": "Starter (Python)"
|
|
13
12
|
};
|
|
14
13
|
const createInteractive = async (args, context) => {
|
|
15
14
|
context.log("welcome", (message) => message.append(`\n🚀 ${pc.bold(args.plugin ? "Welcome to Motia Plugin Creator!" : "Welcome to Motia Project Creator!")}`));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive.mjs","names":["choices: Record<string, string>","questions: QuestionCollection<never>[]","answers: InteractiveAnswers"],"sources":["../../src/create/interactive.ts"],"sourcesContent":["import inquirer, { type QuestionCollection } from 'inquirer'\nimport pc from 'picocolors'\nimport type { CliContext, Message } from '../cloud/config-utils'\nimport { create } from './index'\n\ninterface InteractiveAnswers {\n template: string\n projectName: string\n}\n\nconst choices: Record<string, string> = {\n 'motia-tutorial-typescript': 'Tutorial (TypeScript)',\n 'motia-tutorial-python': 'Tutorial (Python)',\n 'starter-typescript': 'Starter (TypeScript)',\n 'starter-javascript': 'Starter (JavaScript)',\n 'starter-python': 'Starter (Python)',\n
|
|
1
|
+
{"version":3,"file":"interactive.mjs","names":["choices: Record<string, string>","questions: QuestionCollection<never>[]","answers: InteractiveAnswers"],"sources":["../../src/create/interactive.ts"],"sourcesContent":["import inquirer, { type QuestionCollection } from 'inquirer'\nimport pc from 'picocolors'\nimport type { CliContext, Message } from '../cloud/config-utils'\nimport { create } from './index'\n\ninterface InteractiveAnswers {\n template: string\n projectName: string\n}\n\nconst choices: Record<string, string> = {\n 'motia-tutorial-typescript': 'Tutorial (TypeScript)',\n 'motia-tutorial-python': 'Tutorial (Python)',\n 'starter-typescript': 'Starter (TypeScript)',\n 'starter-javascript': 'Starter (JavaScript)',\n 'starter-python': 'Starter (Python)',\n}\n\ninterface CreateInteractiveArgs {\n name?: string\n template?: string\n plugin?: boolean\n}\n\nexport const createInteractive = async (args: CreateInteractiveArgs, context: CliContext): Promise<void> => {\n context.log('welcome', (message: Message) =>\n message.append(\n `\\n🚀 ${pc.bold(args.plugin ? 'Welcome to Motia Plugin Creator!' : 'Welcome to Motia Project Creator!')}`,\n ),\n )\n\n const questions: QuestionCollection<never>[] = []\n\n let name = args.name\n let template = args.template\n\n if (args.plugin) {\n if (!args.name) {\n context.log('failed', (message: Message) =>\n message.tag('failed').append(`Project name is required: ${pc.bold('motia create --plugin [project-name]')}\\n`),\n )\n return\n }\n\n return create({\n projectName: args.name,\n template: 'plugin',\n cursorEnabled: false,\n context,\n })\n } else if (!args.template) {\n questions.push({\n type: 'list',\n name: 'template',\n message: 'What template do you want to use? (Use arrow keys)',\n choices: Object.keys(choices).map((key) => ({\n name: choices[key],\n value: key,\n })),\n })\n }\n\n if (!args.name) {\n questions.push({\n type: 'input',\n name: 'projectName',\n message: 'Project name (leave blank to use current folder):',\n validate: (input: string) => {\n if (input && input.trim().length > 0) {\n if (!/^[a-zA-Z0-9][a-zA-Z0-9-_]*$/.test(input.trim())) {\n return 'Project name must start with a letter or number and contain only letters, numbers, hyphens, and underscores'\n }\n }\n return true\n },\n filter: (input: string) => input.trim(),\n })\n }\n\n if (questions.length > 0) {\n const answers: InteractiveAnswers = await inquirer.prompt(questions)\n name = args.name || answers.projectName\n template = args.template || answers.template\n }\n\n context.log('creating', (message: Message) => message.append('\\n🔨 Creating your Motia project...\\n'))\n\n await create({\n projectName: name || '.',\n template: template || 'motia-tutorial-typescript',\n cursorEnabled: true, // Default to true for cursor rules\n context,\n })\n\n process.exit(0)\n}\n"],"mappings":";;;;;AAUA,MAAMA,UAAkC;CACtC,6BAA6B;CAC7B,yBAAyB;CACzB,sBAAsB;CACtB,sBAAsB;CACtB,kBAAkB;CACnB;AAQD,MAAa,oBAAoB,OAAO,MAA6B,YAAuC;AAC1G,SAAQ,IAAI,YAAY,YACtB,QAAQ,OACN,QAAQ,GAAG,KAAK,KAAK,SAAS,qCAAqC,oCAAoC,GACxG,CACF;CAED,MAAMC,YAAyC,EAAE;CAEjD,IAAI,OAAO,KAAK;CAChB,IAAI,WAAW,KAAK;AAEpB,KAAI,KAAK,QAAQ;AACf,MAAI,CAAC,KAAK,MAAM;AACd,WAAQ,IAAI,WAAW,YACrB,QAAQ,IAAI,SAAS,CAAC,OAAO,6BAA6B,GAAG,KAAK,uCAAuC,CAAC,IAAI,CAC/G;AACD;;AAGF,SAAO,OAAO;GACZ,aAAa,KAAK;GAClB,UAAU;GACV,eAAe;GACf;GACD,CAAC;YACO,CAAC,KAAK,SACf,WAAU,KAAK;EACb,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS,OAAO,KAAK,QAAQ,CAAC,KAAK,SAAS;GAC1C,MAAM,QAAQ;GACd,OAAO;GACR,EAAE;EACJ,CAAC;AAGJ,KAAI,CAAC,KAAK,KACR,WAAU,KAAK;EACb,MAAM;EACN,MAAM;EACN,SAAS;EACT,WAAW,UAAkB;AAC3B,OAAI,SAAS,MAAM,MAAM,CAAC,SAAS,GACjC;QAAI,CAAC,8BAA8B,KAAK,MAAM,MAAM,CAAC,CACnD,QAAO;;AAGX,UAAO;;EAET,SAAS,UAAkB,MAAM,MAAM;EACxC,CAAC;AAGJ,KAAI,UAAU,SAAS,GAAG;EACxB,MAAMC,UAA8B,MAAM,SAAS,OAAO,UAAU;AACpE,SAAO,KAAK,QAAQ,QAAQ;AAC5B,aAAW,KAAK,YAAY,QAAQ;;AAGtC,SAAQ,IAAI,aAAa,YAAqB,QAAQ,OAAO,wCAAwC,CAAC;AAEtG,OAAM,OAAO;EACX,aAAa,QAAQ;EACrB,UAAU,YAAY;EACtB,eAAe;EACf;EACD,CAAC;AAEF,SAAQ,KAAK,EAAE"}
|
|
@@ -7,8 +7,7 @@ const templates = {
|
|
|
7
7
|
plugin: generatePluginTemplate("plugin"),
|
|
8
8
|
"starter-typescript": generateTemplateSteps("hello"),
|
|
9
9
|
"starter-javascript": generateTemplateSteps("hello_js"),
|
|
10
|
-
"starter-python": generateTemplateSteps("hello_python")
|
|
11
|
-
"starter-multilang": generateTemplateSteps("hello_multilang")
|
|
10
|
+
"starter-python": generateTemplateSteps("hello_python")
|
|
12
11
|
};
|
|
13
12
|
|
|
14
13
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["templates: Record<string, Generator>"],"sources":["../../../src/create/templates/index.ts"],"sourcesContent":["import { type Generator, generatePluginTemplate, generateTemplateSteps } from './generate'\n\nexport const templates: Record<string, Generator> = {\n 'motia-tutorial-typescript': generateTemplateSteps('nodejs'),\n 'motia-tutorial-python': generateTemplateSteps('python'),\n plugin: generatePluginTemplate('plugin'),\n 'starter-typescript': generateTemplateSteps('hello'),\n 'starter-javascript': generateTemplateSteps('hello_js'),\n 'starter-python': generateTemplateSteps('hello_python'),\n
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["templates: Record<string, Generator>"],"sources":["../../../src/create/templates/index.ts"],"sourcesContent":["import { type Generator, generatePluginTemplate, generateTemplateSteps } from './generate'\n\nexport const templates: Record<string, Generator> = {\n 'motia-tutorial-typescript': generateTemplateSteps('nodejs'),\n 'motia-tutorial-python': generateTemplateSteps('python'),\n plugin: generatePluginTemplate('plugin'),\n 'starter-typescript': generateTemplateSteps('hello'),\n 'starter-javascript': generateTemplateSteps('hello_js'),\n 'starter-python': generateTemplateSteps('hello_python'),\n}\n"],"mappings":";;;AAEA,MAAaA,YAAuC;CAClD,6BAA6B,sBAAsB,SAAS;CAC5D,yBAAyB,sBAAsB,SAAS;CACxD,QAAQ,uBAAuB,SAAS;CACxC,sBAAsB,sBAAsB,QAAQ;CACpD,sBAAsB,sBAAsB,WAAW;CACvD,kBAAkB,sBAAsB,eAAe;CACxD"}
|
|
@@ -7,5 +7,4 @@ export const templates: Record<string, Generator> = {
|
|
|
7
7
|
'starter-typescript': generateTemplateSteps('hello'),
|
|
8
8
|
'starter-javascript': generateTemplateSteps('hello_js'),
|
|
9
9
|
'starter-python': generateTemplateSteps('hello_python'),
|
|
10
|
-
'starter-multilang': generateTemplateSteps('hello_multilang'),
|
|
11
10
|
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @motiadev/plugin-example
|
|
2
2
|
|
|
3
|
-
A minimal plugin demonstrating the Motia plugin system.
|
|
3
|
+
A minimal example plugin demonstrating the Motia plugin system.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
7
|
This plugin serves as a reference implementation showing how to create custom workbench plugins for Motia. It demonstrates:
|
|
8
8
|
|
|
9
9
|
- Basic plugin structure and configuration
|
|
10
|
-
- Creating custom workbench tabs
|
|
11
|
-
- Using Motia's UI component library
|
|
12
|
-
- Building with
|
|
10
|
+
- Creating custom workbench tabs with position control
|
|
11
|
+
- Using Motia's UI component library (`@motiadev/ui`)
|
|
12
|
+
- Building with tsdown and TypeScript
|
|
13
|
+
- Tailwind CSS v4 styling with PostCSS
|
|
14
|
+
- React Compiler optimization via Babel
|
|
13
15
|
|
|
14
16
|
## Installation
|
|
15
17
|
|
|
@@ -35,30 +37,73 @@ pnpm run clean
|
|
|
35
37
|
To use this plugin in your Motia project, import it in your `motia.config.ts`:
|
|
36
38
|
|
|
37
39
|
```typescript
|
|
38
|
-
import examplePlugin from '
|
|
40
|
+
import examplePlugin from '@motiadev/plugin-example/plugin'
|
|
39
41
|
|
|
40
42
|
export default {
|
|
41
43
|
plugins: [examplePlugin],
|
|
42
44
|
}
|
|
43
45
|
```
|
|
44
46
|
|
|
47
|
+
## Plugin Configuration
|
|
48
|
+
|
|
49
|
+
The plugin exports a function that receives the `MotiaPluginContext` and returns a `MotiaPlugin` object:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import type { MotiaPlugin, MotiaPluginContext } from '@motiadev/core'
|
|
53
|
+
|
|
54
|
+
export default function plugin(_motia: MotiaPluginContext): MotiaPlugin {
|
|
55
|
+
return {
|
|
56
|
+
workbench: [
|
|
57
|
+
{
|
|
58
|
+
packageName: '@motiadev/plugin-example',
|
|
59
|
+
cssImports: ['@motiadev/plugin-example/dist/index.css'],
|
|
60
|
+
label: 'Example',
|
|
61
|
+
position: 'bottom',
|
|
62
|
+
componentName: 'ExamplePage',
|
|
63
|
+
labelIcon: 'sparkles',
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Workbench Options
|
|
71
|
+
|
|
72
|
+
| Option | Description |
|
|
73
|
+
| --------------- | ------------------------------------------ |
|
|
74
|
+
| `packageName` | The npm package name for dynamic imports |
|
|
75
|
+
| `cssImports` | Array of CSS files to load with the plugin |
|
|
76
|
+
| `label` | Display name shown in the workbench tab |
|
|
77
|
+
| `position` | Tab position: `'top'` or `'bottom'` |
|
|
78
|
+
| `componentName` | Name of the exported React component |
|
|
79
|
+
| `labelIcon` | Lucide icon name for the tab |
|
|
80
|
+
|
|
45
81
|
## Structure
|
|
46
82
|
|
|
47
83
|
```
|
|
48
|
-
|
|
84
|
+
plugin-example/
|
|
49
85
|
├── src/
|
|
50
86
|
│ ├── components/
|
|
51
87
|
│ │ └── example-page.tsx # Main UI component
|
|
52
|
-
│ ├── index.ts # Package entry point
|
|
88
|
+
│ ├── index.ts # Package entry point (exports components)
|
|
53
89
|
│ ├── plugin.ts # Plugin definition
|
|
54
|
-
│ └── styles.css # Tailwind styles
|
|
90
|
+
│ └── styles.css # Tailwind CSS styles
|
|
91
|
+
├── dist/ # Build output
|
|
55
92
|
├── package.json
|
|
56
93
|
├── tsconfig.json
|
|
57
|
-
├──
|
|
94
|
+
├── tsdown.config.ts # Build configuration
|
|
95
|
+
├── postcss.config.js # PostCSS/Tailwind config
|
|
58
96
|
└── README.md
|
|
59
97
|
```
|
|
60
98
|
|
|
61
|
-
##
|
|
99
|
+
## Features Demonstrated
|
|
62
100
|
|
|
63
|
-
|
|
101
|
+
- **Custom Workbench Tab**: Adds an "Example" tab to the bottom panel
|
|
102
|
+
- **UI Components**: Uses `Badge` and `Button` from `@motiadev/ui`
|
|
103
|
+
- **Icons**: Integrates Lucide React icons
|
|
104
|
+
- **Responsive Layout**: Grid-based responsive design with Tailwind CSS
|
|
105
|
+
- **Type Safety**: Full TypeScript support with proper type declarations
|
|
106
|
+
|
|
107
|
+
## Learn More
|
|
64
108
|
|
|
109
|
+
For detailed documentation on creating plugins, see the [Plugins Guide](../../packages/docs/content/docs/development-guide/plugins.mdx).
|
|
@@ -1,47 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "{{PROJECT_NAME}}",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.14.0-beta.164",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"require": "./dist/index.cjs"
|
|
9
|
+
"development": "./src/index.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
12
11
|
},
|
|
13
12
|
"./plugin": {
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"require": "./dist/plugin.cjs"
|
|
13
|
+
"development": "./src/plugin.ts",
|
|
14
|
+
"default": "./dist/plugin.js"
|
|
17
15
|
},
|
|
18
|
-
"./
|
|
16
|
+
"./package.json": "./package.json"
|
|
19
17
|
},
|
|
20
18
|
"files": [
|
|
21
19
|
"dist"
|
|
22
20
|
],
|
|
23
21
|
"scripts": {
|
|
24
|
-
"build": "
|
|
25
|
-
"dev": "
|
|
22
|
+
"build": "tsdown",
|
|
23
|
+
"dev": "tsdown --watch",
|
|
26
24
|
"clean": "rm -rf dist"
|
|
27
25
|
},
|
|
28
26
|
"dependencies": {
|
|
29
|
-
"lucide-react": "^0.
|
|
27
|
+
"lucide-react": "^0.555.0",
|
|
28
|
+
"react": "^19.2.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@motiadev/core": "workspace:*",
|
|
32
|
+
"@motiadev/ui": "workspace:*"
|
|
30
33
|
},
|
|
31
34
|
"devDependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"@
|
|
34
|
-
"
|
|
35
|
-
"@
|
|
36
|
-
"@types/
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"tailwindcss": "^4.1.16",
|
|
35
|
+
"@rollup/plugin-babel": "^6.1.0",
|
|
36
|
+
"@tailwindcss/postcss": "^4.1.17",
|
|
37
|
+
"rollup-plugin-postcss": "^4.0.2",
|
|
38
|
+
"@types/node": "^24.10.1",
|
|
39
|
+
"@types/react": "^19.2.7",
|
|
40
|
+
"babel-plugin-react-compiler": "^1.0.0",
|
|
41
|
+
"publint": "^0.3.15",
|
|
42
|
+
"tailwindcss": "^4.1.17",
|
|
43
|
+
"tsdown": "^0.16.8",
|
|
42
44
|
"typescript": "^5.9.3",
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
+
"unplugin-unused": "^0.5.6"
|
|
46
|
+
},
|
|
47
|
+
"module": "./dist/index.js",
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"exports": {
|
|
50
|
+
".": "./dist/index.js",
|
|
51
|
+
"./plugin": "./dist/plugin.js",
|
|
52
|
+
"./package.json": "./package.json"
|
|
53
|
+
}
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
|
-
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import pluginBabel from '@rollup/plugin-babel'
|
|
2
|
+
import postcss from 'rollup-plugin-postcss'
|
|
3
|
+
import { defineConfig } from 'tsdown'
|
|
4
|
+
|
|
5
|
+
export default defineConfig([
|
|
6
|
+
// Main JavaScript/TypeScript build
|
|
7
|
+
{
|
|
8
|
+
entry: {
|
|
9
|
+
index: './src/index.ts',
|
|
10
|
+
plugin: './src/plugin.ts',
|
|
11
|
+
},
|
|
12
|
+
format: 'esm',
|
|
13
|
+
platform: 'browser',
|
|
14
|
+
external: [/^react($|\/)/, 'react/jsx-runtime'],
|
|
15
|
+
dts: {
|
|
16
|
+
build: true,
|
|
17
|
+
},
|
|
18
|
+
exports: {
|
|
19
|
+
devExports: 'development',
|
|
20
|
+
},
|
|
21
|
+
clean: true,
|
|
22
|
+
publint: true,
|
|
23
|
+
unused: true,
|
|
24
|
+
outDir: 'dist',
|
|
25
|
+
plugins: [
|
|
26
|
+
pluginBabel({
|
|
27
|
+
babelHelpers: 'bundled',
|
|
28
|
+
parserOpts: {
|
|
29
|
+
sourceType: 'module',
|
|
30
|
+
plugins: ['jsx', 'typescript'],
|
|
31
|
+
},
|
|
32
|
+
plugins: ['babel-plugin-react-compiler'],
|
|
33
|
+
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
34
|
+
}),
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
// Separate CSS build
|
|
38
|
+
{
|
|
39
|
+
entry: {
|
|
40
|
+
index: './src/styles.css',
|
|
41
|
+
},
|
|
42
|
+
format: 'esm',
|
|
43
|
+
platform: 'browser',
|
|
44
|
+
outDir: 'dist',
|
|
45
|
+
clean: false,
|
|
46
|
+
plugins: [
|
|
47
|
+
postcss({
|
|
48
|
+
extract: true,
|
|
49
|
+
minimize: process.env.NODE_ENV === 'prod',
|
|
50
|
+
}),
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
])
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Aider Configuration for Motia Projects
|
|
2
|
+
# https://aider.chat/docs/config.html
|
|
3
|
+
|
|
4
|
+
# Read AGENTS.md for project overview and guide references
|
|
5
|
+
read:
|
|
6
|
+
- AGENTS.md
|
|
7
|
+
# Uncomment specific guides as needed for more context:
|
|
8
|
+
# - .cursor/rules/motia/api-steps.mdc
|
|
9
|
+
# - .cursor/rules/motia/event-steps.mdc
|
|
10
|
+
# - .cursor/rules/motia/cron-steps.mdc
|
|
11
|
+
# - .cursor/rules/motia/state-management.mdc
|
|
12
|
+
# - .cursor/rules/motia/middlewares.mdc
|
|
13
|
+
# - .cursor/rules/motia/realtime-streaming.mdc
|
|
14
|
+
# - .cursor/rules/motia/virtual-steps.mdc
|
|
15
|
+
# - .cursor/rules/motia/ui-steps.mdc
|
|
16
|
+
# - .cursor/architecture/architecture.mdc
|
|
17
|
+
# - .cursor/architecture/error-handling.mdc
|
|
18
|
+
|
|
19
|
+
# Note: AGENTS.md references all detailed guides in .cursor/rules/
|
|
20
|
+
# The AI will read those guides when needed based on AGENTS.md instructions
|
|
21
|
+
|
|
22
|
+
# Auto-commit changes (optional, uncomment to enable)
|
|
23
|
+
# auto-commits: true
|
|
24
|
+
|
|
25
|
+
# Model selection (uncomment your preferred model)
|
|
26
|
+
# model: gpt-4
|
|
27
|
+
# model: claude-3-5-sonnet-20241022
|
|
28
|
+
|
|
29
|
+
# Additional context files (optional)
|
|
30
|
+
# read:
|
|
31
|
+
# - config.yml
|
|
32
|
+
# - package.json
|
package/dist/docker/setup.mjs
CHANGED
|
@@ -8,6 +8,12 @@ import * as readline$1 from "readline";
|
|
|
8
8
|
|
|
9
9
|
//#region src/docker/setup.ts
|
|
10
10
|
const __dirname = path$1.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const resolveTemplatesDir = () => {
|
|
12
|
+
const localTemplates = path$1.join(__dirname, "./templates");
|
|
13
|
+
if (fs$1.existsSync(localTemplates)) return localTemplates;
|
|
14
|
+
return path$1.join(__dirname, "../../../docker/templates");
|
|
15
|
+
};
|
|
16
|
+
const templatesDir = resolveTemplatesDir();
|
|
11
17
|
const updatePackageJson = () => {
|
|
12
18
|
const packageJsonPath = path$1.join(process.cwd(), "package.json");
|
|
13
19
|
if (fs$1.existsSync(packageJsonPath)) {
|
|
@@ -36,7 +42,7 @@ const createDockerfile = async () => {
|
|
|
36
42
|
return;
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
|
-
const dockerfileContent = fs$1.readFileSync(path$1.join(
|
|
45
|
+
const dockerfileContent = fs$1.readFileSync(path$1.join(templatesDir, "MotiaDockerSample"), "utf-8");
|
|
40
46
|
try {
|
|
41
47
|
fs$1.writeFileSync(dockerfilePath, dockerfileContent);
|
|
42
48
|
console.log("Dockerfile generated successfully!");
|
|
@@ -48,7 +54,7 @@ const createDockerfile = async () => {
|
|
|
48
54
|
const createDockerignore = async () => {
|
|
49
55
|
identifyUser();
|
|
50
56
|
trackEvent("docker_setup_command", { project_name: getProjectIdentifier(process.cwd()) });
|
|
51
|
-
const dockerignoreContent = fs$1.readFileSync(path$1.join(
|
|
57
|
+
const dockerignoreContent = fs$1.readFileSync(path$1.join(templatesDir, ".dockerignore.sample"), "utf-8");
|
|
52
58
|
const dockerignorePath = path$1.join(process.cwd(), ".dockerignore");
|
|
53
59
|
if (fs$1.existsSync(dockerignorePath)) {
|
|
54
60
|
console.log(".dockerignore already exists");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.mjs","names":["path","fs","readline"],"sources":["../../src/docker/setup.ts"],"sourcesContent":["import { getProjectIdentifier, trackEvent } from '@motiadev/core'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport * as readline from 'readline'\nimport { fileURLToPath } from 'url'\nimport { identifyUser } from '../utils/analytics'\nimport { printMotiaDockerIntro } from './utils/print-intro'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nconst updatePackageJson = (): void => {\n const packageJsonPath = path.join(process.cwd(), 'package.json')\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))\n if (!packageJson.scripts) {\n packageJson.scripts = {}\n }\n packageJson.scripts.start = 'motia start'\n fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))\n console.log('Updated package.json with start script')\n }\n}\n\nconst createDockerfile = async () => {\n const dockerfilePath = path.join(process.cwd(), 'Dockerfile')\n\n if (fs.existsSync(dockerfilePath)) {\n console.log('Dockerfile already exists')\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n\n const shouldOverride = await new Promise<boolean>((resolve) => {\n rl.question('Do you want to override the existing Dockerfile? (y/N): ', (answer) => {\n rl.close()\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes')\n })\n })\n\n if (!shouldOverride) {\n console.log('Dockerfile generation cancelled')\n return\n }\n }\n\n const dockerfileContent = fs.readFileSync(path.join(
|
|
1
|
+
{"version":3,"file":"setup.mjs","names":["path","fs","readline"],"sources":["../../src/docker/setup.ts"],"sourcesContent":["import { getProjectIdentifier, trackEvent } from '@motiadev/core'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport * as readline from 'readline'\nimport { fileURLToPath } from 'url'\nimport { identifyUser } from '../utils/analytics'\nimport { printMotiaDockerIntro } from './utils/print-intro'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nconst resolveTemplatesDir = (): string => {\n const localTemplates = path.join(__dirname, './templates')\n if (fs.existsSync(localTemplates)) {\n return localTemplates\n }\n // Fallback for development: resolve to packages/docker/templates\n return path.join(__dirname, '../../../docker/templates')\n}\n\nconst templatesDir = resolveTemplatesDir()\n\nconst updatePackageJson = (): void => {\n const packageJsonPath = path.join(process.cwd(), 'package.json')\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))\n if (!packageJson.scripts) {\n packageJson.scripts = {}\n }\n packageJson.scripts.start = 'motia start'\n fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))\n console.log('Updated package.json with start script')\n }\n}\n\nconst createDockerfile = async () => {\n const dockerfilePath = path.join(process.cwd(), 'Dockerfile')\n\n if (fs.existsSync(dockerfilePath)) {\n console.log('Dockerfile already exists')\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n\n const shouldOverride = await new Promise<boolean>((resolve) => {\n rl.question('Do you want to override the existing Dockerfile? (y/N): ', (answer) => {\n rl.close()\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes')\n })\n })\n\n if (!shouldOverride) {\n console.log('Dockerfile generation cancelled')\n return\n }\n }\n\n const dockerfileContent = fs.readFileSync(path.join(templatesDir, 'MotiaDockerSample'), 'utf-8')\n\n try {\n fs.writeFileSync(dockerfilePath, dockerfileContent)\n console.log('Dockerfile generated successfully!')\n } catch (error) {\n console.error('Error generating Dockerfile:', (error as Error).message)\n throw error\n }\n}\n\nconst createDockerignore = async () => {\n identifyUser()\n\n trackEvent('docker_setup_command', {\n project_name: getProjectIdentifier(process.cwd()),\n })\n\n const dockerignoreContent = fs.readFileSync(path.join(templatesDir, '.dockerignore.sample'), 'utf-8')\n\n const dockerignorePath = path.join(process.cwd(), '.dockerignore')\n\n if (fs.existsSync(dockerignorePath)) {\n console.log('.dockerignore already exists')\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n\n const shouldOverride = await new Promise<boolean>((resolve) => {\n rl.question('Do you want to override the existing .dockerignore? (y/N): ', (answer) => {\n rl.close()\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes')\n })\n })\n\n if (!shouldOverride) {\n console.log('.dockerignore generation cancelled')\n return\n }\n }\n\n try {\n fs.writeFileSync(dockerignorePath, dockerignoreContent)\n console.log('.dockerignore generated successfully!')\n } catch (error) {\n console.error('Error generating .dockerignore:', (error as Error).message)\n throw error\n }\n}\n\nexport const setup = async (): Promise<void> => {\n printMotiaDockerIntro()\n\n await createDockerfile()\n await createDockerignore()\n updatePackageJson()\n}\n"],"mappings":";;;;;;;;;AAQA,MAAM,YAAYA,OAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAE9D,MAAM,4BAAoC;CACxC,MAAM,iBAAiBA,OAAK,KAAK,WAAW,cAAc;AAC1D,KAAIC,KAAG,WAAW,eAAe,CAC/B,QAAO;AAGT,QAAOD,OAAK,KAAK,WAAW,4BAA4B;;AAG1D,MAAM,eAAe,qBAAqB;AAE1C,MAAM,0BAAgC;CACpC,MAAM,kBAAkBA,OAAK,KAAK,QAAQ,KAAK,EAAE,eAAe;AAChE,KAAIC,KAAG,WAAW,gBAAgB,EAAE;EAClC,MAAM,cAAc,KAAK,MAAMA,KAAG,aAAa,iBAAiB,QAAQ,CAAC;AACzE,MAAI,CAAC,YAAY,QACf,aAAY,UAAU,EAAE;AAE1B,cAAY,QAAQ,QAAQ;AAC5B,OAAG,cAAc,iBAAiB,KAAK,UAAU,aAAa,MAAM,EAAE,CAAC;AACvE,UAAQ,IAAI,yCAAyC;;;AAIzD,MAAM,mBAAmB,YAAY;CACnC,MAAM,iBAAiBD,OAAK,KAAK,QAAQ,KAAK,EAAE,aAAa;AAE7D,KAAIC,KAAG,WAAW,eAAe,EAAE;AACjC,UAAQ,IAAI,4BAA4B;EAExC,MAAM,KAAKC,WAAS,gBAAgB;GAClC,OAAO,QAAQ;GACf,QAAQ,QAAQ;GACjB,CAAC;AASF,MAAI,CAPmB,MAAM,IAAI,SAAkB,YAAY;AAC7D,MAAG,SAAS,6DAA6D,WAAW;AAClF,OAAG,OAAO;AACV,YAAQ,OAAO,aAAa,KAAK,OAAO,OAAO,aAAa,KAAK,MAAM;KACvE;IACF,EAEmB;AACnB,WAAQ,IAAI,kCAAkC;AAC9C;;;CAIJ,MAAM,oBAAoBD,KAAG,aAAaD,OAAK,KAAK,cAAc,oBAAoB,EAAE,QAAQ;AAEhG,KAAI;AACF,OAAG,cAAc,gBAAgB,kBAAkB;AACnD,UAAQ,IAAI,qCAAqC;UAC1C,OAAO;AACd,UAAQ,MAAM,gCAAiC,MAAgB,QAAQ;AACvE,QAAM;;;AAIV,MAAM,qBAAqB,YAAY;AACrC,eAAc;AAEd,YAAW,wBAAwB,EACjC,cAAc,qBAAqB,QAAQ,KAAK,CAAC,EAClD,CAAC;CAEF,MAAM,sBAAsBC,KAAG,aAAaD,OAAK,KAAK,cAAc,uBAAuB,EAAE,QAAQ;CAErG,MAAM,mBAAmBA,OAAK,KAAK,QAAQ,KAAK,EAAE,gBAAgB;AAElE,KAAIC,KAAG,WAAW,iBAAiB,EAAE;AACnC,UAAQ,IAAI,+BAA+B;EAC3C,MAAM,KAAKC,WAAS,gBAAgB;GAClC,OAAO,QAAQ;GACf,QAAQ,QAAQ;GACjB,CAAC;AASF,MAAI,CAPmB,MAAM,IAAI,SAAkB,YAAY;AAC7D,MAAG,SAAS,gEAAgE,WAAW;AACrF,OAAG,OAAO;AACV,YAAQ,OAAO,aAAa,KAAK,OAAO,OAAO,aAAa,KAAK,MAAM;KACvE;IACF,EAEmB;AACnB,WAAQ,IAAI,qCAAqC;AACjD;;;AAIJ,KAAI;AACF,OAAG,cAAc,kBAAkB,oBAAoB;AACvD,UAAQ,IAAI,wCAAwC;UAC7C,OAAO;AACd,UAAQ,MAAM,mCAAoC,MAAgB,QAAQ;AAC1E,QAAM;;;AAIV,MAAa,QAAQ,YAA2B;AAC9C,wBAAuB;AAEvB,OAAM,kBAAkB;AACxB,OAAM,oBAAoB;AAC1B,oBAAmB"}
|
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.14.0-beta.165-
|
|
4
|
+
"version": "0.14.0-beta.165-246284",
|
|
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-
|
|
50
|
-
"@motiadev/adapter-
|
|
51
|
-
"@motiadev/adapter-redis-
|
|
52
|
-
"@motiadev/adapter-redis-
|
|
53
|
-
"@motiadev/core": "0.14.0-beta.165-
|
|
54
|
-
"@motiadev/stream-client-node": "0.14.0-beta.165-
|
|
55
|
-
"@motiadev/workbench": "0.14.0-beta.165-
|
|
49
|
+
"@motiadev/adapter-redis-state": "0.14.0-beta.165-246284",
|
|
50
|
+
"@motiadev/adapter-bullmq-events": "0.14.0-beta.165-246284",
|
|
51
|
+
"@motiadev/adapter-redis-cron": "0.14.0-beta.165-246284",
|
|
52
|
+
"@motiadev/adapter-redis-streams": "0.14.0-beta.165-246284",
|
|
53
|
+
"@motiadev/core": "0.14.0-beta.165-246284",
|
|
54
|
+
"@motiadev/stream-client-node": "0.14.0-beta.165-246284",
|
|
55
|
+
"@motiadev/workbench": "0.14.0-beta.165-246284"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@amplitude/analytics-types": "^2.9.2",
|
|
@@ -74,7 +74,6 @@
|
|
|
74
74
|
"move:python": "sh scripts/move-python.sh",
|
|
75
75
|
"move:dot-files": "sh scripts/move-dot-files.sh",
|
|
76
76
|
"build": "tsdown",
|
|
77
|
-
"postbuild": "sh scripts/post-build.sh",
|
|
78
77
|
"test": "NODE_OPTIONS='--experimental-vm-modules' jest",
|
|
79
78
|
"lint": "biome check .",
|
|
80
79
|
"lint:plugins": "eslint --config ../../eslint.config.js"
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# {{PROJECT_NAME}}
|
|
2
|
-
|
|
3
|
-
A Motia project created with the **multi-language** starter template (TypeScript + Python).
|
|
4
|
-
|
|
5
|
-
## What is Motia?
|
|
6
|
-
|
|
7
|
-
Motia is an open-source, unified backend framework that eliminates runtime fragmentation by bringing **APIs, background jobs, queueing, streaming, state, workflows, AI agents, observability, scaling, and deployment** into one unified system using a single core primitive, the **Step**.
|
|
8
|
-
|
|
9
|
-
## Polyglot Architecture
|
|
10
|
-
|
|
11
|
-
This template demonstrates Motia's polyglot capabilities by combining:
|
|
12
|
-
|
|
13
|
-
- **TypeScript**: API endpoint (`hello-api.step.ts`) - handles HTTP requests
|
|
14
|
-
- **Python**: Event processor (`process_greeting_step.py`) - handles background work
|
|
15
|
-
|
|
16
|
-
This shows how you can use the best language for each task while keeping everything in a single unified system.
|
|
17
|
-
|
|
18
|
-
## Quick Start
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
# Start the development server
|
|
22
|
-
npm run dev
|
|
23
|
-
# or
|
|
24
|
-
yarn dev
|
|
25
|
-
# or
|
|
26
|
-
pnpm dev
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
This starts the Motia runtime and the **Workbench** - a powerful UI for developing and debugging your workflows. By default, it's available at [`http://localhost:3000`](http://localhost:3000).
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
# Test your first endpoint
|
|
33
|
-
curl http://localhost:3000/hello
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## How It Works
|
|
37
|
-
|
|
38
|
-
1. **TypeScript API Step** receives the HTTP request at `/hello`
|
|
39
|
-
2. It emits a `process-greeting` event with the request data
|
|
40
|
-
3. **Python Event Step** picks up the event and processes it in the background
|
|
41
|
-
4. The result is stored in state using Python
|
|
42
|
-
|
|
43
|
-
## Step Types
|
|
44
|
-
|
|
45
|
-
Every Step has a `type` that defines how it triggers:
|
|
46
|
-
|
|
47
|
-
| Type | When it runs | Use case |
|
|
48
|
-
|------|--------------|----------|
|
|
49
|
-
| **`api`** | HTTP request | REST APIs, webhooks |
|
|
50
|
-
| **`event`** | Event emitted | Background jobs, workflows |
|
|
51
|
-
| **`cron`** | Schedule | Cleanup, reports, reminders |
|
|
52
|
-
|
|
53
|
-
## Development Commands
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
# Start Workbench and development server
|
|
57
|
-
npm run dev
|
|
58
|
-
# or
|
|
59
|
-
yarn dev
|
|
60
|
-
# or
|
|
61
|
-
pnpm dev
|
|
62
|
-
|
|
63
|
-
# Start production server (without hot reload)
|
|
64
|
-
npm run start
|
|
65
|
-
# or
|
|
66
|
-
yarn start
|
|
67
|
-
# or
|
|
68
|
-
pnpm start
|
|
69
|
-
|
|
70
|
-
# Generate TypeScript types from Step configs
|
|
71
|
-
npm run generate-types
|
|
72
|
-
# or
|
|
73
|
-
yarn generate-types
|
|
74
|
-
# or
|
|
75
|
-
pnpm generate-types
|
|
76
|
-
|
|
77
|
-
# Build project for deployment
|
|
78
|
-
npm run build
|
|
79
|
-
# or
|
|
80
|
-
yarn build
|
|
81
|
-
# or
|
|
82
|
-
pnpm build
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Project Structure
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
steps/ # Your Step definitions
|
|
89
|
-
├── hello/
|
|
90
|
-
│ ├── hello-api.step.ts # TypeScript API endpoint
|
|
91
|
-
│ └── process_greeting_step.py # Python event processor
|
|
92
|
-
motia.config.ts # Motia configuration
|
|
93
|
-
requirements.txt # Python dependencies
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Steps are auto-discovered from your `steps/` or `src/` directories - no manual registration required.
|
|
97
|
-
|
|
98
|
-
## Learn More
|
|
99
|
-
|
|
100
|
-
- [Documentation](https://motia.dev/docs) - Complete guides and API reference
|
|
101
|
-
- [Quick Start Guide](https://motia.dev/docs/getting-started/quick-start) - Detailed getting started tutorial
|
|
102
|
-
- [Core Concepts](https://motia.dev/docs/concepts/overview) - Learn about Steps and Motia architecture
|
|
103
|
-
- [Discord Community](https://discord.gg/motia) - Get help and connect with other developers
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { config } from '@motiadev/core'
|
|
2
|
-
import endpointPlugin from '@motiadev/plugin-endpoint/plugin'
|
|
3
|
-
import logsPlugin from '@motiadev/plugin-logs/plugin'
|
|
4
|
-
import observabilityPlugin from '@motiadev/plugin-observability/plugin'
|
|
5
|
-
import statesPlugin from '@motiadev/plugin-states/plugin'
|
|
6
|
-
import bullmqPlugin from '@motiadev/plugin-bullmq/plugin'
|
|
7
|
-
|
|
8
|
-
export default config({
|
|
9
|
-
plugins: [observabilityPlugin, statesPlugin, endpointPlugin, logsPlugin, bullmqPlugin],
|
|
10
|
-
})
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { ApiRouteConfig, Handlers } from 'motia';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
export const config: ApiRouteConfig = {
|
|
5
|
-
name: 'HelloAPI',
|
|
6
|
-
type: 'api',
|
|
7
|
-
path: '/hello',
|
|
8
|
-
method: 'GET',
|
|
9
|
-
description: 'Receives hello request and emits event for Python processing',
|
|
10
|
-
emits: ['process-greeting'],
|
|
11
|
-
flows: ['hello-world-flow'],
|
|
12
|
-
responseSchema: {
|
|
13
|
-
200: z.object({
|
|
14
|
-
message: z.string(),
|
|
15
|
-
status: z.string(),
|
|
16
|
-
appName: z.string()
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const handler: Handlers['HelloAPI'] = async (_, { emit, logger }) => {
|
|
22
|
-
const appName = process.env.APP_NAME || 'Motia App';
|
|
23
|
-
const timestamp = new Date().toISOString();
|
|
24
|
-
|
|
25
|
-
logger.info('Hello API endpoint called (TypeScript)', { appName, timestamp });
|
|
26
|
-
|
|
27
|
-
// Emit event for background processing in Python
|
|
28
|
-
await emit({
|
|
29
|
-
topic: 'process-greeting',
|
|
30
|
-
data: {
|
|
31
|
-
timestamp,
|
|
32
|
-
appName,
|
|
33
|
-
greetingPrefix: process.env.GREETING_PREFIX || 'Hello',
|
|
34
|
-
requestId: Math.random().toString(36).substring(7)
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
status: 200,
|
|
40
|
-
body: {
|
|
41
|
-
message: 'Hello request received! Processing in Python...',
|
|
42
|
-
status: 'processing',
|
|
43
|
-
appName
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
|
|
3
|
-
# Optional: Using Pydantic for validation (remove if not using Pydantic)
|
|
4
|
-
try:
|
|
5
|
-
from pydantic import BaseModel
|
|
6
|
-
|
|
7
|
-
class GreetingInput(BaseModel):
|
|
8
|
-
timestamp: str
|
|
9
|
-
appName: str
|
|
10
|
-
greetingPrefix: str
|
|
11
|
-
requestId: str
|
|
12
|
-
|
|
13
|
-
# If using Pydantic, we can generate the JSON schema
|
|
14
|
-
input_schema = GreetingInput.model_json_schema()
|
|
15
|
-
except ImportError:
|
|
16
|
-
# Without Pydantic, define JSON schema manually
|
|
17
|
-
input_schema = {
|
|
18
|
-
"type": "object",
|
|
19
|
-
"properties": {
|
|
20
|
-
"timestamp": {"type": "string"},
|
|
21
|
-
"appName": {"type": "string"},
|
|
22
|
-
"greetingPrefix": {"type": "string"},
|
|
23
|
-
"requestId": {"type": "string"}
|
|
24
|
-
},
|
|
25
|
-
"required": ["timestamp", "appName", "greetingPrefix", "requestId"]
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
config = {
|
|
29
|
-
"name": "ProcessGreeting",
|
|
30
|
-
"type": "event",
|
|
31
|
-
"description": "Processes greeting in the background (Python)",
|
|
32
|
-
"subscribes": ["process-greeting"],
|
|
33
|
-
"emits": [],
|
|
34
|
-
"flows": ["hello-world-flow"],
|
|
35
|
-
"input": input_schema
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async def handler(input_data, context):
|
|
39
|
-
# Extract data from input
|
|
40
|
-
timestamp = input_data.get("timestamp")
|
|
41
|
-
app_name = input_data.get("appName")
|
|
42
|
-
greeting_prefix = input_data.get("greetingPrefix")
|
|
43
|
-
request_id = input_data.get("requestId")
|
|
44
|
-
|
|
45
|
-
context.logger.info("Processing greeting (Python)", {
|
|
46
|
-
"request_id": request_id,
|
|
47
|
-
"app_name": app_name
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
greeting = f"{greeting_prefix} {app_name}!"
|
|
51
|
-
|
|
52
|
-
# Store result in state (demonstrates state usage)
|
|
53
|
-
# Note: The state.set method takes (groupId, key, value)
|
|
54
|
-
await context.state.set("greetings", request_id, {
|
|
55
|
-
"greeting": greeting,
|
|
56
|
-
"processedAt": datetime.utcnow().isoformat(),
|
|
57
|
-
"originalTimestamp": timestamp,
|
|
58
|
-
"processedBy": "python"
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
context.logger.info("Greeting processed successfully (Python)", {
|
|
62
|
-
"request_id": request_id,
|
|
63
|
-
"greeting": greeting,
|
|
64
|
-
"stored_in_state": True
|
|
65
|
-
})
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import tailwindcss from '@tailwindcss/vite'
|
|
2
|
-
import react from '@vitejs/plugin-react'
|
|
3
|
-
import { resolve } from 'path'
|
|
4
|
-
import { defineConfig } from 'vite'
|
|
5
|
-
import dts from 'vite-plugin-dts'
|
|
6
|
-
|
|
7
|
-
export default defineConfig({
|
|
8
|
-
plugins: [react(), tailwindcss(), dts({ insertTypesEntry: true })],
|
|
9
|
-
build: {
|
|
10
|
-
lib: {
|
|
11
|
-
entry: {
|
|
12
|
-
index: resolve(__dirname, 'src/index.ts'),
|
|
13
|
-
plugin: resolve(__dirname, 'src/plugin.ts'),
|
|
14
|
-
},
|
|
15
|
-
name: '{{PLUGIN_NAME}}',
|
|
16
|
-
formats: ['es', 'cjs'],
|
|
17
|
-
fileName: (format, entryName) => `${entryName}.${format === 'es' ? 'js' : 'cjs'}`,
|
|
18
|
-
},
|
|
19
|
-
rollupOptions: {
|
|
20
|
-
external: ['react', 'react-dom', '@motiadev/core', '@motiadev/ui'],
|
|
21
|
-
},
|
|
22
|
-
cssCodeSplit: false,
|
|
23
|
-
},
|
|
24
|
-
resolve: {
|
|
25
|
-
alias: {
|
|
26
|
-
'@': resolve(__dirname, 'src'),
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
})
|
|
30
|
-
|