motia 0.8.2-beta.140-131607 → 0.8.2-beta.140-799293

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.
Files changed (117) hide show
  1. package/dist/cjs/cli.js +5 -3
  2. package/dist/cjs/cloud/build/build-validation.d.ts +5 -3
  3. package/dist/cjs/cloud/build/build-validation.js +140 -27
  4. package/dist/cjs/create/index.js +3 -1
  5. package/dist/cjs/dev.d.ts +1 -1
  6. package/dist/cjs/dev.js +4 -3
  7. package/dist/cjs/generate-locked-data.d.ts +6 -1
  8. package/dist/cjs/generate-locked-data.js +3 -2
  9. package/dist/cjs/generate-plugins.js +7 -0
  10. package/dist/cjs/start.d.ts +1 -1
  11. package/dist/cjs/start.js +4 -3
  12. package/dist/esm/cli.js +5 -3
  13. package/dist/esm/cloud/build/build-validation.d.ts +5 -3
  14. package/dist/esm/cloud/build/build-validation.js +104 -27
  15. package/dist/esm/create/index.js +3 -1
  16. package/dist/esm/dev.d.ts +1 -1
  17. package/dist/esm/dev.js +4 -3
  18. package/dist/esm/generate-locked-data.d.ts +6 -1
  19. package/dist/esm/generate-locked-data.js +3 -2
  20. package/dist/esm/generate-plugins.js +7 -0
  21. package/dist/esm/start.d.ts +1 -1
  22. package/dist/esm/start.js +4 -3
  23. package/dist/types/cloud/build/build-validation.d.ts +5 -3
  24. package/dist/types/dev.d.ts +1 -1
  25. package/dist/types/generate-locked-data.d.ts +6 -1
  26. package/dist/types/start.d.ts +1 -1
  27. package/package.json +4 -4
  28. package/dist/cjs/cloud/build/__tests__/infrastructure-serialization.test.d.ts +0 -1
  29. package/dist/cjs/cloud/build/__tests__/infrastructure-serialization.test.js +0 -324
  30. package/dist/cjs/cloud/build/__tests__/infrastructure-validation.test.d.ts +0 -1
  31. package/dist/cjs/cloud/build/__tests__/infrastructure-validation.test.js +0 -673
  32. package/dist/cjs/cloud/build/validations/__tests__/api-endpoints.validator.test.d.ts +0 -1
  33. package/dist/cjs/cloud/build/validations/__tests__/api-endpoints.validator.test.js +0 -71
  34. package/dist/cjs/cloud/build/validations/__tests__/build-validation.test.d.ts +0 -1
  35. package/dist/cjs/cloud/build/validations/__tests__/build-validation.test.js +0 -96
  36. package/dist/cjs/cloud/build/validations/__tests__/cron-expressions.validator.test.d.ts +0 -1
  37. package/dist/cjs/cloud/build/validations/__tests__/cron-expressions.validator.test.js +0 -68
  38. package/dist/cjs/cloud/build/validations/__tests__/duplicate-step-names.validator.test.d.ts +0 -1
  39. package/dist/cjs/cloud/build/validations/__tests__/duplicate-step-names.validator.test.js +0 -66
  40. package/dist/cjs/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.d.ts +0 -1
  41. package/dist/cjs/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.js +0 -71
  42. package/dist/cjs/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.d.ts +0 -1
  43. package/dist/cjs/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.js +0 -69
  44. package/dist/cjs/cloud/build/validations/__tests__/step-name-lengths.validator.test.d.ts +0 -1
  45. package/dist/cjs/cloud/build/validations/__tests__/step-name-lengths.validator.test.js +0 -68
  46. package/dist/cjs/cloud/build/validations/api-endpoints.validator.d.ts +0 -2
  47. package/dist/cjs/cloud/build/validations/api-endpoints.validator.js +0 -36
  48. package/dist/cjs/cloud/build/validations/constants.d.ts +0 -6
  49. package/dist/cjs/cloud/build/validations/constants.js +0 -9
  50. package/dist/cjs/cloud/build/validations/cron-expressions.validator.d.ts +0 -2
  51. package/dist/cjs/cloud/build/validations/cron-expressions.validator.js +0 -62
  52. package/dist/cjs/cloud/build/validations/duplicate-step-names.validator.d.ts +0 -2
  53. package/dist/cjs/cloud/build/validations/duplicate-step-names.validator.js +0 -26
  54. package/dist/cjs/cloud/build/validations/infrastructure-configs.validator.d.ts +0 -2
  55. package/dist/cjs/cloud/build/validations/infrastructure-configs.validator.js +0 -32
  56. package/dist/cjs/cloud/build/validations/router-bundle-sizes.validator.d.ts +0 -2
  57. package/dist/cjs/cloud/build/validations/router-bundle-sizes.validator.js +0 -31
  58. package/dist/cjs/cloud/build/validations/step-bundle-sizes.validator.d.ts +0 -2
  59. package/dist/cjs/cloud/build/validations/step-bundle-sizes.validator.js +0 -36
  60. package/dist/cjs/cloud/build/validations/step-name-lengths.validator.d.ts +0 -2
  61. package/dist/cjs/cloud/build/validations/step-name-lengths.validator.js +0 -27
  62. package/dist/cjs/cloud/build/validations/types.d.ts +0 -7
  63. package/dist/cjs/cloud/build/validations/types.js +0 -2
  64. package/dist/esm/cloud/build/__tests__/infrastructure-serialization.test.d.ts +0 -1
  65. package/dist/esm/cloud/build/__tests__/infrastructure-serialization.test.js +0 -322
  66. package/dist/esm/cloud/build/__tests__/infrastructure-validation.test.d.ts +0 -1
  67. package/dist/esm/cloud/build/__tests__/infrastructure-validation.test.js +0 -671
  68. package/dist/esm/cloud/build/validations/__tests__/api-endpoints.validator.test.d.ts +0 -1
  69. package/dist/esm/cloud/build/validations/__tests__/api-endpoints.validator.test.js +0 -69
  70. package/dist/esm/cloud/build/validations/__tests__/build-validation.test.d.ts +0 -1
  71. package/dist/esm/cloud/build/validations/__tests__/build-validation.test.js +0 -94
  72. package/dist/esm/cloud/build/validations/__tests__/cron-expressions.validator.test.d.ts +0 -1
  73. package/dist/esm/cloud/build/validations/__tests__/cron-expressions.validator.test.js +0 -66
  74. package/dist/esm/cloud/build/validations/__tests__/duplicate-step-names.validator.test.d.ts +0 -1
  75. package/dist/esm/cloud/build/validations/__tests__/duplicate-step-names.validator.test.js +0 -64
  76. package/dist/esm/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.d.ts +0 -1
  77. package/dist/esm/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.js +0 -69
  78. package/dist/esm/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.d.ts +0 -1
  79. package/dist/esm/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.js +0 -67
  80. package/dist/esm/cloud/build/validations/__tests__/step-name-lengths.validator.test.d.ts +0 -1
  81. package/dist/esm/cloud/build/validations/__tests__/step-name-lengths.validator.test.js +0 -66
  82. package/dist/esm/cloud/build/validations/api-endpoints.validator.d.ts +0 -2
  83. package/dist/esm/cloud/build/validations/api-endpoints.validator.js +0 -29
  84. package/dist/esm/cloud/build/validations/constants.d.ts +0 -6
  85. package/dist/esm/cloud/build/validations/constants.js +0 -6
  86. package/dist/esm/cloud/build/validations/cron-expressions.validator.d.ts +0 -2
  87. package/dist/esm/cloud/build/validations/cron-expressions.validator.js +0 -22
  88. package/dist/esm/cloud/build/validations/duplicate-step-names.validator.d.ts +0 -2
  89. package/dist/esm/cloud/build/validations/duplicate-step-names.validator.js +0 -19
  90. package/dist/esm/cloud/build/validations/infrastructure-configs.validator.d.ts +0 -2
  91. package/dist/esm/cloud/build/validations/infrastructure-configs.validator.js +0 -25
  92. package/dist/esm/cloud/build/validations/router-bundle-sizes.validator.d.ts +0 -2
  93. package/dist/esm/cloud/build/validations/router-bundle-sizes.validator.js +0 -24
  94. package/dist/esm/cloud/build/validations/step-bundle-sizes.validator.d.ts +0 -2
  95. package/dist/esm/cloud/build/validations/step-bundle-sizes.validator.js +0 -29
  96. package/dist/esm/cloud/build/validations/step-name-lengths.validator.d.ts +0 -2
  97. package/dist/esm/cloud/build/validations/step-name-lengths.validator.js +0 -20
  98. package/dist/esm/cloud/build/validations/types.d.ts +0 -7
  99. package/dist/esm/cloud/build/validations/types.js +0 -1
  100. package/dist/types/cloud/build/__tests__/infrastructure-serialization.test.d.ts +0 -1
  101. package/dist/types/cloud/build/__tests__/infrastructure-validation.test.d.ts +0 -1
  102. package/dist/types/cloud/build/validations/__tests__/api-endpoints.validator.test.d.ts +0 -1
  103. package/dist/types/cloud/build/validations/__tests__/build-validation.test.d.ts +0 -1
  104. package/dist/types/cloud/build/validations/__tests__/cron-expressions.validator.test.d.ts +0 -1
  105. package/dist/types/cloud/build/validations/__tests__/duplicate-step-names.validator.test.d.ts +0 -1
  106. package/dist/types/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.d.ts +0 -1
  107. package/dist/types/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.d.ts +0 -1
  108. package/dist/types/cloud/build/validations/__tests__/step-name-lengths.validator.test.d.ts +0 -1
  109. package/dist/types/cloud/build/validations/api-endpoints.validator.d.ts +0 -2
  110. package/dist/types/cloud/build/validations/constants.d.ts +0 -6
  111. package/dist/types/cloud/build/validations/cron-expressions.validator.d.ts +0 -2
  112. package/dist/types/cloud/build/validations/duplicate-step-names.validator.d.ts +0 -2
  113. package/dist/types/cloud/build/validations/infrastructure-configs.validator.d.ts +0 -2
  114. package/dist/types/cloud/build/validations/router-bundle-sizes.validator.d.ts +0 -2
  115. package/dist/types/cloud/build/validations/step-bundle-sizes.validator.d.ts +0 -2
  116. package/dist/types/cloud/build/validations/step-name-lengths.validator.d.ts +0 -2
  117. package/dist/types/cloud/build/validations/types.d.ts +0 -7
package/dist/cjs/cli.js CHANGED
@@ -68,6 +68,7 @@ commander_1.program
68
68
  .option('-v, --disable-verbose', 'Disable verbose logging')
69
69
  .option('-d, --debug', 'Enable debug logging')
70
70
  .option('-m, --mermaid', 'Enable mermaid diagram generation')
71
+ .option('--motia-dir <path>', 'Path where .motia folder will be created')
71
72
  .action(async (arg) => {
72
73
  if (arg.debug) {
73
74
  console.log('🔍 Debug logging enabled');
@@ -76,7 +77,7 @@ commander_1.program
76
77
  const port = arg.port ? parseInt(arg.port) : defaultPort;
77
78
  const host = arg.host ? arg.host : defaultHost;
78
79
  const { dev } = require('./dev');
79
- await dev(port, host, arg.disableVerbose, arg.mermaid);
80
+ await dev(port, host, arg.disableVerbose, arg.mermaid, arg.motiaDir);
80
81
  });
81
82
  commander_1.program
82
83
  .command('start')
@@ -85,6 +86,7 @@ commander_1.program
85
86
  .option('-H, --host [host]', 'The host address for the server', `${defaultHost}`)
86
87
  .option('-v, --disable-verbose', 'Disable verbose logging')
87
88
  .option('-d, --debug', 'Enable debug logging')
89
+ .option('--motia-dir <path>', 'Path where .motia folder will be created')
88
90
  .action(async (arg) => {
89
91
  if (arg.debug) {
90
92
  console.log('🔍 Debug logging enabled');
@@ -93,7 +95,7 @@ commander_1.program
93
95
  const port = arg.port ? parseInt(arg.port) : defaultPort;
94
96
  const host = arg.host ? arg.host : defaultHost;
95
97
  const { start } = require('./start');
96
- await start(port, host, arg.disableVerbose);
98
+ await start(port, host, arg.disableVerbose, arg.motiaDir);
97
99
  });
98
100
  commander_1.program
99
101
  .command('emit')
@@ -144,7 +146,7 @@ generate
144
146
  .action(async (options) => {
145
147
  const { generateLockedData } = require('./generate-locked-data');
146
148
  const { generateOpenApi } = require('./openapi/generate');
147
- const lockedData = await generateLockedData(process.cwd());
149
+ const lockedData = await generateLockedData({ projectDir: process.cwd() });
148
150
  const apiSteps = lockedData.apiSteps();
149
151
  generateOpenApi(process.cwd(), apiSteps, options.title, options.version, options.output);
150
152
  process.exit(0);
@@ -1,5 +1,7 @@
1
- import { BuildListener } from '../new-deployment/listeners/listener.types';
1
+ import { BuildListener, ValidationError } from '../new-deployment/listeners/listener.types';
2
2
  import { Builder } from './builder';
3
- import { ValidationResult } from './validations/types';
4
3
  export declare const buildValidation: (builder: Builder, listener: BuildListener) => boolean;
5
- export declare const validateStepsConfig: (builder: Builder) => ValidationResult;
4
+ export declare const validateStepsConfig: (builder: Builder) => {
5
+ errors: ValidationError[];
6
+ warnings: ValidationError[];
7
+ };
@@ -1,17 +1,49 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
2
38
  Object.defineProperty(exports, "__esModule", { value: true });
3
39
  exports.validateStepsConfig = exports.buildValidation = void 0;
4
- const duplicate_step_names_validator_1 = require("./validations/duplicate-step-names.validator");
5
- const step_bundle_sizes_validator_1 = require("./validations/step-bundle-sizes.validator");
6
- const cron_expressions_validator_1 = require("./validations/cron-expressions.validator");
7
- const api_endpoints_validator_1 = require("./validations/api-endpoints.validator");
8
- const step_name_lengths_validator_1 = require("./validations/step-name-lengths.validator");
9
- const infrastructure_configs_validator_1 = require("./validations/infrastructure-configs.validator");
10
- const router_bundle_sizes_validator_1 = require("./validations/router-bundle-sizes.validator");
40
+ const colors_1 = __importDefault(require("colors"));
41
+ const cron = __importStar(require("node-cron"));
42
+ const path_1 = __importDefault(require("path"));
11
43
  const buildValidation = (builder, listener) => {
12
44
  const { errors, warnings } = (0, exports.validateStepsConfig)(builder);
13
45
  if (warnings.length > 0) {
14
- warnings.forEach((warning) => listener.onBuildWarning(warning));
46
+ warnings.map((warning) => listener.onBuildWarning(warning));
15
47
  }
16
48
  if (errors.length > 0) {
17
49
  listener.onBuildErrors(errors);
@@ -20,25 +52,106 @@ const buildValidation = (builder, listener) => {
20
52
  return true;
21
53
  };
22
54
  exports.buildValidation = buildValidation;
23
- const validationPipeline = [
24
- duplicate_step_names_validator_1.duplicateStepNamesValidator,
25
- step_bundle_sizes_validator_1.stepBundleSizesValidator,
26
- cron_expressions_validator_1.cronExpressionsValidator,
27
- api_endpoints_validator_1.apiEndpointsValidator,
28
- step_name_lengths_validator_1.stepNameLengthsValidator,
29
- infrastructure_configs_validator_1.infrastructureConfigsValidator,
30
- router_bundle_sizes_validator_1.routerBundleSizesValidator,
31
- ];
32
- const runValidationPipeline = (builder, validators) => {
33
- return validators.reduce((acc, validator) => {
34
- const result = validator(builder);
35
- return {
36
- errors: [...acc.errors, ...result.errors],
37
- warnings: [...acc.warnings, ...result.warnings],
38
- };
39
- }, { errors: [], warnings: [] });
40
- };
41
55
  const validateStepsConfig = (builder) => {
42
- return runValidationPipeline(builder, validationPipeline);
56
+ const errors = [];
57
+ const warnings = [];
58
+ const endpoints = new Map();
59
+ const stepNames = new Set();
60
+ for (const step of Object.values(builder.stepsConfig)) {
61
+ if (stepNames.has(step.config.name)) {
62
+ errors.push({
63
+ relativePath: path_1.default.relative(builder.projectDir, step.filePath),
64
+ message: [`Duplicate step names: ${colors_1.default.red(step.config.name)}`].join('\n'),
65
+ step,
66
+ });
67
+ }
68
+ else {
69
+ stepNames.add(step.config.name);
70
+ }
71
+ }
72
+ for (const step of Object.values(builder.stepsConfig)) {
73
+ const relativePath = path_1.default.relative(builder.projectDir, step.filePath);
74
+ // Check individual step bundle size (150MB limit - uncompressed)
75
+ const stepUncompressedSize = builder.stepUncompressedSizes.get(step.filePath);
76
+ if (stepUncompressedSize !== undefined) {
77
+ const maxSize = 250 * 1024 * 1024; // 250MB in bytes
78
+ if (stepUncompressedSize > maxSize) {
79
+ const sizeMB = (stepUncompressedSize / (1024 * 1024)).toFixed(2);
80
+ const compressedSize = builder.stepCompressedSizes.get(step.filePath);
81
+ const compressedSizeMB = compressedSize ? (compressedSize / (1024 * 1024)).toFixed(2) : 'unknown';
82
+ errors.push({
83
+ relativePath,
84
+ message: [
85
+ 'Step bundle size exceeds 250MB limit (uncompressed).',
86
+ ` ${colors_1.default.red('➜')} Uncompressed size: ${colors_1.default.magenta(sizeMB + 'MB')}`,
87
+ ` ${colors_1.default.red('➜')} Compressed size: ${colors_1.default.cyan(compressedSizeMB + 'MB')}`,
88
+ ` ${colors_1.default.red('➜')} Maximum allowed: ${colors_1.default.blue('250MB')}`,
89
+ ].join('\n'),
90
+ step,
91
+ });
92
+ }
93
+ }
94
+ if (step.config.type === 'cron') {
95
+ if (!cron.validate(step.config.cron)) {
96
+ errors.push({
97
+ relativePath,
98
+ message: [
99
+ 'Cron step has an invalid cron expression.',
100
+ ` ${colors_1.default.red('➜')} ${colors_1.default.magenta(step.config.cron)}`,
101
+ ].join('\n'),
102
+ step,
103
+ });
104
+ }
105
+ }
106
+ else if (step.config.type === 'api') {
107
+ const entrypoint = path_1.default.relative(builder.projectDir, step.filePath);
108
+ const endpoint = `${step.config.method} ${step.config.path}`;
109
+ if (endpoints.has(endpoint)) {
110
+ errors.push({
111
+ relativePath,
112
+ message: [
113
+ `Endpoint conflict`,
114
+ ` ${colors_1.default.red('➜')} ${colors_1.default.magenta(endpoint)} is defined in the following files`,
115
+ ` ${colors_1.default.red('➜')} ${colors_1.default.blue(entrypoint)}`,
116
+ ` ${colors_1.default.red('➜')} ${colors_1.default.blue(endpoints.get(endpoint))}`,
117
+ ].join('\n'),
118
+ step,
119
+ });
120
+ }
121
+ else {
122
+ endpoints.set(endpoint, entrypoint);
123
+ }
124
+ }
125
+ if (step.config.name.length > 40) {
126
+ errors.push({
127
+ relativePath,
128
+ message: [
129
+ `Step name is too long. Maximum is 40 characters.`,
130
+ ` ${colors_1.default.red('➜')} ${colors_1.default.magenta(step.config.name)}`,
131
+ ].join('\n'),
132
+ step,
133
+ });
134
+ }
135
+ }
136
+ // Check API router bundle sizes (150MB limit - uncompressed)
137
+ const maxRouterSize = 150 * 1024 * 1024; // 150MB in bytes
138
+ for (const [routerType, uncompressedSize] of builder.routerUncompressedSizes.entries()) {
139
+ if (uncompressedSize > maxRouterSize) {
140
+ const uncompressedSizeMB = (uncompressedSize / (1024 * 1024)).toFixed(2);
141
+ const compressedSize = builder.routerCompressedSizes.get(routerType);
142
+ const compressedSizeMB = compressedSize ? (compressedSize / (1024 * 1024)).toFixed(2) : 'unknown';
143
+ errors.push({
144
+ relativePath: `${routerType} API router`,
145
+ message: [
146
+ `${routerType.charAt(0).toUpperCase() + routerType.slice(1)} API router bundle size exceeds 150MB limit (uncompressed).`,
147
+ ` ${colors_1.default.red('➜')} Uncompressed size: ${colors_1.default.magenta(uncompressedSizeMB + 'MB')}`,
148
+ ` ${colors_1.default.red('➜')} Compressed size: ${colors_1.default.cyan(compressedSizeMB + 'MB')}`,
149
+ ` ${colors_1.default.red('➜')} Maximum allowed: ${colors_1.default.blue('150MB')}`,
150
+ ].join('\n'),
151
+ step: Object.values(builder.stepsConfig)[0], // Use first step as reference
152
+ });
153
+ }
154
+ }
155
+ return { errors, warnings };
43
156
  };
44
157
  exports.validateStepsConfig = validateStepsConfig;
@@ -96,7 +96,9 @@ const create = async ({ projectName, template, cursorEnabled, context }) => {
96
96
  context.log('directory-using', (message) => message.tag('info').append('Using current directory'));
97
97
  }
98
98
  if (!(0, utils_1.checkIfFileExists)(rootDir, 'package.json')) {
99
- const finalProjectName = isCurrentDir ? path_1.default.basename(rootDir) : projectName;
99
+ const finalProjectName = !projectName || projectName === '.' || projectName === './' || projectName === '.\\'
100
+ ? path_1.default.basename(process.cwd())
101
+ : projectName.trim();
100
102
  const packageJsonContent = {
101
103
  name: finalProjectName,
102
104
  description: '',
package/dist/cjs/dev.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const dev: (port: number, hostname: string, disableVerbose: boolean, enableMermaid: boolean) => Promise<void>;
1
+ export declare const dev: (port: number, hostname: string, disableVerbose: boolean, enableMermaid: boolean, motiaFileStorageDir?: string) => Promise<void>;
package/dist/cjs/dev.js CHANGED
@@ -22,7 +22,7 @@ require('ts-node').register({
22
22
  transpileOnly: true,
23
23
  compilerOptions: { module: 'commonjs' },
24
24
  });
25
- const dev = async (port, hostname, disableVerbose, enableMermaid) => {
25
+ const dev = async (port, hostname, disableVerbose, enableMermaid, motiaFileStorageDir) => {
26
26
  const baseDir = process.cwd();
27
27
  const isVerbose = !disableVerbose;
28
28
  (0, analytics_1.identifyUser)();
@@ -40,11 +40,12 @@ const dev = async (port, hostname, disableVerbose, enableMermaid) => {
40
40
  (0, activate_python_env_1.activatePythonVenv)({ baseDir, isVerbose });
41
41
  (0, core_1.trackEvent)('python_environment_activated');
42
42
  }
43
- const lockedData = await (0, generate_locked_data_1.generateLockedData)(baseDir);
43
+ const motiaFileStoragePath = motiaFileStorageDir || '.motia';
44
+ const lockedData = await (0, generate_locked_data_1.generateLockedData)({ projectDir: baseDir, motiaFileStoragePath });
44
45
  const eventManager = (0, core_1.createEventManager)();
45
46
  const state = (0, core_1.createStateAdapter)({
46
47
  adapter: 'default',
47
- filePath: path_1.default.join(baseDir, '.motia'),
48
+ filePath: path_1.default.join(baseDir, motiaFileStoragePath),
48
49
  });
49
50
  const config = { isVerbose };
50
51
  const motiaServer = (0, core_1.createServer)(lockedData, eventManager, state, config);
@@ -2,4 +2,9 @@ import { LockedData, Step } from '@motiadev/core';
2
2
  export declare const getStepFiles: (projectDir: string) => string[];
3
3
  export declare const getStreamFiles: (projectDir: string) => string[];
4
4
  export declare const collectFlows: (projectDir: string, lockedData: LockedData) => Promise<Step[]>;
5
- export declare const generateLockedData: (projectDir: string, streamAdapter?: "file" | "memory", printerType?: "disabled" | "default") => Promise<LockedData>;
5
+ export declare const generateLockedData: (config: {
6
+ projectDir: string;
7
+ streamAdapter?: "file" | "memory";
8
+ printerType?: "disabled" | "default";
9
+ motiaFileStoragePath?: string;
10
+ }) => Promise<LockedData>;
@@ -85,14 +85,15 @@ const collectFlows = async (projectDir, lockedData) => {
85
85
  return invalidSteps;
86
86
  };
87
87
  exports.collectFlows = collectFlows;
88
- const generateLockedData = async (projectDir, streamAdapter = 'file', printerType = 'default') => {
88
+ const generateLockedData = async (config) => {
89
89
  try {
90
+ const { projectDir, streamAdapter = 'file', printerType = 'default', motiaFileStoragePath = '.motia' } = config;
90
91
  const printer = printerType === 'disabled' ? new printer_1.NoPrinter() : new printer_1.Printer(projectDir);
91
92
  /*
92
93
  * NOTE: right now for performance and simplicity let's enforce a folder,
93
94
  * but we might want to remove this and scan the entire current directory
94
95
  */
95
- const lockedData = new core_1.LockedData(projectDir, streamAdapter, printer);
96
+ const lockedData = new core_1.LockedData(projectDir, streamAdapter, printer, motiaFileStoragePath);
96
97
  await (0, exports.collectFlows)(projectDir, lockedData);
97
98
  lockedData.saveTypes();
98
99
  return lockedData;
@@ -43,6 +43,13 @@ const defaultPlugins = [
43
43
  },
44
44
  ],
45
45
  },
46
+ {
47
+ workbench: [
48
+ {
49
+ packageName: '@motiadev/plugin-logs',
50
+ },
51
+ ],
52
+ },
46
53
  ];
47
54
  const generatePlugins = async (motia) => {
48
55
  const configFiles = (0, glob_1.globSync)('motia.config.{ts,js}', { absolute: true, cwd: motia.lockedData.baseDir });
@@ -1 +1 @@
1
- export declare const start: (port: number, hostname: string, disableVerbose: boolean) => Promise<void>;
1
+ export declare const start: (port: number, hostname: string, disableVerbose: boolean, motiaFileStorageDir?: string) => Promise<void>;
package/dist/cjs/start.js CHANGED
@@ -16,7 +16,7 @@ require('ts-node').register({
16
16
  transpileOnly: true,
17
17
  compilerOptions: { module: 'commonjs' },
18
18
  });
19
- const start = async (port, hostname, disableVerbose) => {
19
+ const start = async (port, hostname, disableVerbose, motiaFileStorageDir) => {
20
20
  const baseDir = process.cwd();
21
21
  const isVerbose = !disableVerbose;
22
22
  const stepFiles = (0, generate_locked_data_1.getStepFiles)(baseDir);
@@ -25,8 +25,9 @@ const start = async (port, hostname, disableVerbose) => {
25
25
  console.log('⚙️ Activating Python environment...');
26
26
  (0, activate_python_env_1.activatePythonVenv)({ baseDir, isVerbose });
27
27
  }
28
- const dotMotia = path_1.default.join(baseDir, '.motia');
29
- const lockedData = await (0, generate_locked_data_1.generateLockedData)(baseDir);
28
+ const motiaFileStoragePath = motiaFileStorageDir || '.motia';
29
+ const dotMotia = path_1.default.join(baseDir, motiaFileStoragePath);
30
+ const lockedData = await (0, generate_locked_data_1.generateLockedData)({ projectDir: baseDir, motiaFileStoragePath });
30
31
  const eventManager = (0, core_1.createEventManager)();
31
32
  const state = (0, core_1.createStateAdapter)({ adapter: 'default', filePath: dotMotia });
32
33
  const config = { isVerbose, isDev: false, version: version_1.version };
package/dist/esm/cli.js CHANGED
@@ -66,6 +66,7 @@ program
66
66
  .option('-v, --disable-verbose', 'Disable verbose logging')
67
67
  .option('-d, --debug', 'Enable debug logging')
68
68
  .option('-m, --mermaid', 'Enable mermaid diagram generation')
69
+ .option('--motia-dir <path>', 'Path where .motia folder will be created')
69
70
  .action(async (arg) => {
70
71
  if (arg.debug) {
71
72
  console.log('🔍 Debug logging enabled');
@@ -74,7 +75,7 @@ program
74
75
  const port = arg.port ? parseInt(arg.port) : defaultPort;
75
76
  const host = arg.host ? arg.host : defaultHost;
76
77
  const { dev } = require('./dev');
77
- await dev(port, host, arg.disableVerbose, arg.mermaid);
78
+ await dev(port, host, arg.disableVerbose, arg.mermaid, arg.motiaDir);
78
79
  });
79
80
  program
80
81
  .command('start')
@@ -83,6 +84,7 @@ program
83
84
  .option('-H, --host [host]', 'The host address for the server', `${defaultHost}`)
84
85
  .option('-v, --disable-verbose', 'Disable verbose logging')
85
86
  .option('-d, --debug', 'Enable debug logging')
87
+ .option('--motia-dir <path>', 'Path where .motia folder will be created')
86
88
  .action(async (arg) => {
87
89
  if (arg.debug) {
88
90
  console.log('🔍 Debug logging enabled');
@@ -91,7 +93,7 @@ program
91
93
  const port = arg.port ? parseInt(arg.port) : defaultPort;
92
94
  const host = arg.host ? arg.host : defaultHost;
93
95
  const { start } = require('./start');
94
- await start(port, host, arg.disableVerbose);
96
+ await start(port, host, arg.disableVerbose, arg.motiaDir);
95
97
  });
96
98
  program
97
99
  .command('emit')
@@ -142,7 +144,7 @@ generate
142
144
  .action(async (options) => {
143
145
  const { generateLockedData } = require('./generate-locked-data');
144
146
  const { generateOpenApi } = require('./openapi/generate');
145
- const lockedData = await generateLockedData(process.cwd());
147
+ const lockedData = await generateLockedData({ projectDir: process.cwd() });
146
148
  const apiSteps = lockedData.apiSteps();
147
149
  generateOpenApi(process.cwd(), apiSteps, options.title, options.version, options.output);
148
150
  process.exit(0);
@@ -1,5 +1,7 @@
1
- import { BuildListener } from '../new-deployment/listeners/listener.types';
1
+ import { BuildListener, ValidationError } from '../new-deployment/listeners/listener.types';
2
2
  import { Builder } from './builder';
3
- import { ValidationResult } from './validations/types';
4
3
  export declare const buildValidation: (builder: Builder, listener: BuildListener) => boolean;
5
- export declare const validateStepsConfig: (builder: Builder) => ValidationResult;
4
+ export declare const validateStepsConfig: (builder: Builder) => {
5
+ errors: ValidationError[];
6
+ warnings: ValidationError[];
7
+ };
@@ -1,14 +1,10 @@
1
- import { duplicateStepNamesValidator } from './validations/duplicate-step-names.validator';
2
- import { stepBundleSizesValidator } from './validations/step-bundle-sizes.validator';
3
- import { cronExpressionsValidator } from './validations/cron-expressions.validator';
4
- import { apiEndpointsValidator } from './validations/api-endpoints.validator';
5
- import { stepNameLengthsValidator } from './validations/step-name-lengths.validator';
6
- import { infrastructureConfigsValidator } from './validations/infrastructure-configs.validator';
7
- import { routerBundleSizesValidator } from './validations/router-bundle-sizes.validator';
1
+ import colors from 'colors';
2
+ import * as cron from 'node-cron';
3
+ import path from 'path';
8
4
  export const buildValidation = (builder, listener) => {
9
5
  const { errors, warnings } = validateStepsConfig(builder);
10
6
  if (warnings.length > 0) {
11
- warnings.forEach((warning) => listener.onBuildWarning(warning));
7
+ warnings.map((warning) => listener.onBuildWarning(warning));
12
8
  }
13
9
  if (errors.length > 0) {
14
10
  listener.onBuildErrors(errors);
@@ -16,24 +12,105 @@ export const buildValidation = (builder, listener) => {
16
12
  }
17
13
  return true;
18
14
  };
19
- const validationPipeline = [
20
- duplicateStepNamesValidator,
21
- stepBundleSizesValidator,
22
- cronExpressionsValidator,
23
- apiEndpointsValidator,
24
- stepNameLengthsValidator,
25
- infrastructureConfigsValidator,
26
- routerBundleSizesValidator,
27
- ];
28
- const runValidationPipeline = (builder, validators) => {
29
- return validators.reduce((acc, validator) => {
30
- const result = validator(builder);
31
- return {
32
- errors: [...acc.errors, ...result.errors],
33
- warnings: [...acc.warnings, ...result.warnings],
34
- };
35
- }, { errors: [], warnings: [] });
36
- };
37
15
  export const validateStepsConfig = (builder) => {
38
- return runValidationPipeline(builder, validationPipeline);
16
+ const errors = [];
17
+ const warnings = [];
18
+ const endpoints = new Map();
19
+ const stepNames = new Set();
20
+ for (const step of Object.values(builder.stepsConfig)) {
21
+ if (stepNames.has(step.config.name)) {
22
+ errors.push({
23
+ relativePath: path.relative(builder.projectDir, step.filePath),
24
+ message: [`Duplicate step names: ${colors.red(step.config.name)}`].join('\n'),
25
+ step,
26
+ });
27
+ }
28
+ else {
29
+ stepNames.add(step.config.name);
30
+ }
31
+ }
32
+ for (const step of Object.values(builder.stepsConfig)) {
33
+ const relativePath = path.relative(builder.projectDir, step.filePath);
34
+ // Check individual step bundle size (150MB limit - uncompressed)
35
+ const stepUncompressedSize = builder.stepUncompressedSizes.get(step.filePath);
36
+ if (stepUncompressedSize !== undefined) {
37
+ const maxSize = 250 * 1024 * 1024; // 250MB in bytes
38
+ if (stepUncompressedSize > maxSize) {
39
+ const sizeMB = (stepUncompressedSize / (1024 * 1024)).toFixed(2);
40
+ const compressedSize = builder.stepCompressedSizes.get(step.filePath);
41
+ const compressedSizeMB = compressedSize ? (compressedSize / (1024 * 1024)).toFixed(2) : 'unknown';
42
+ errors.push({
43
+ relativePath,
44
+ message: [
45
+ 'Step bundle size exceeds 250MB limit (uncompressed).',
46
+ ` ${colors.red('➜')} Uncompressed size: ${colors.magenta(sizeMB + 'MB')}`,
47
+ ` ${colors.red('➜')} Compressed size: ${colors.cyan(compressedSizeMB + 'MB')}`,
48
+ ` ${colors.red('➜')} Maximum allowed: ${colors.blue('250MB')}`,
49
+ ].join('\n'),
50
+ step,
51
+ });
52
+ }
53
+ }
54
+ if (step.config.type === 'cron') {
55
+ if (!cron.validate(step.config.cron)) {
56
+ errors.push({
57
+ relativePath,
58
+ message: [
59
+ 'Cron step has an invalid cron expression.',
60
+ ` ${colors.red('➜')} ${colors.magenta(step.config.cron)}`,
61
+ ].join('\n'),
62
+ step,
63
+ });
64
+ }
65
+ }
66
+ else if (step.config.type === 'api') {
67
+ const entrypoint = path.relative(builder.projectDir, step.filePath);
68
+ const endpoint = `${step.config.method} ${step.config.path}`;
69
+ if (endpoints.has(endpoint)) {
70
+ errors.push({
71
+ relativePath,
72
+ message: [
73
+ `Endpoint conflict`,
74
+ ` ${colors.red('➜')} ${colors.magenta(endpoint)} is defined in the following files`,
75
+ ` ${colors.red('➜')} ${colors.blue(entrypoint)}`,
76
+ ` ${colors.red('➜')} ${colors.blue(endpoints.get(endpoint))}`,
77
+ ].join('\n'),
78
+ step,
79
+ });
80
+ }
81
+ else {
82
+ endpoints.set(endpoint, entrypoint);
83
+ }
84
+ }
85
+ if (step.config.name.length > 40) {
86
+ errors.push({
87
+ relativePath,
88
+ message: [
89
+ `Step name is too long. Maximum is 40 characters.`,
90
+ ` ${colors.red('➜')} ${colors.magenta(step.config.name)}`,
91
+ ].join('\n'),
92
+ step,
93
+ });
94
+ }
95
+ }
96
+ // Check API router bundle sizes (150MB limit - uncompressed)
97
+ const maxRouterSize = 150 * 1024 * 1024; // 150MB in bytes
98
+ for (const [routerType, uncompressedSize] of builder.routerUncompressedSizes.entries()) {
99
+ if (uncompressedSize > maxRouterSize) {
100
+ const uncompressedSizeMB = (uncompressedSize / (1024 * 1024)).toFixed(2);
101
+ const compressedSize = builder.routerCompressedSizes.get(routerType);
102
+ const compressedSizeMB = compressedSize ? (compressedSize / (1024 * 1024)).toFixed(2) : 'unknown';
103
+ errors.push({
104
+ relativePath: `${routerType} API router`,
105
+ message: [
106
+ `${routerType.charAt(0).toUpperCase() + routerType.slice(1)} API router bundle size exceeds 150MB limit (uncompressed).`,
107
+ ` ${colors.red('➜')} Uncompressed size: ${colors.magenta(uncompressedSizeMB + 'MB')}`,
108
+ ` ${colors.red('➜')} Compressed size: ${colors.cyan(compressedSizeMB + 'MB')}`,
109
+ ` ${colors.red('➜')} Maximum allowed: ${colors.blue('150MB')}`,
110
+ ].join('\n'),
111
+ step: Object.values(builder.stepsConfig)[0], // Use first step as reference
112
+ });
113
+ }
114
+ }
115
+ return { errors, warnings };
39
116
  };
@@ -90,7 +90,9 @@ export const create = async ({ projectName, template, cursorEnabled, context })
90
90
  context.log('directory-using', (message) => message.tag('info').append('Using current directory'));
91
91
  }
92
92
  if (!checkIfFileExists(rootDir, 'package.json')) {
93
- const finalProjectName = isCurrentDir ? path.basename(rootDir) : projectName;
93
+ const finalProjectName = !projectName || projectName === '.' || projectName === './' || projectName === '.\\'
94
+ ? path.basename(process.cwd())
95
+ : projectName.trim();
94
96
  const packageJsonContent = {
95
97
  name: finalProjectName,
96
98
  description: '',
package/dist/esm/dev.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const dev: (port: number, hostname: string, disableVerbose: boolean, enableMermaid: boolean) => Promise<void>;
1
+ export declare const dev: (port: number, hostname: string, disableVerbose: boolean, enableMermaid: boolean, motiaFileStorageDir?: string) => Promise<void>;
package/dist/esm/dev.js CHANGED
@@ -16,7 +16,7 @@ require('ts-node').register({
16
16
  transpileOnly: true,
17
17
  compilerOptions: { module: 'commonjs' },
18
18
  });
19
- export const dev = async (port, hostname, disableVerbose, enableMermaid) => {
19
+ export const dev = async (port, hostname, disableVerbose, enableMermaid, motiaFileStorageDir) => {
20
20
  const baseDir = process.cwd();
21
21
  const isVerbose = !disableVerbose;
22
22
  identifyUser();
@@ -34,11 +34,12 @@ export const dev = async (port, hostname, disableVerbose, enableMermaid) => {
34
34
  activatePythonVenv({ baseDir, isVerbose });
35
35
  trackEvent('python_environment_activated');
36
36
  }
37
- const lockedData = await generateLockedData(baseDir);
37
+ const motiaFileStoragePath = motiaFileStorageDir || '.motia';
38
+ const lockedData = await generateLockedData({ projectDir: baseDir, motiaFileStoragePath });
38
39
  const eventManager = createEventManager();
39
40
  const state = createStateAdapter({
40
41
  adapter: 'default',
41
- filePath: path.join(baseDir, '.motia'),
42
+ filePath: path.join(baseDir, motiaFileStoragePath),
42
43
  });
43
44
  const config = { isVerbose };
44
45
  const motiaServer = createServer(lockedData, eventManager, state, config);
@@ -2,4 +2,9 @@ import { LockedData, Step } from '@motiadev/core';
2
2
  export declare const getStepFiles: (projectDir: string) => string[];
3
3
  export declare const getStreamFiles: (projectDir: string) => string[];
4
4
  export declare const collectFlows: (projectDir: string, lockedData: LockedData) => Promise<Step[]>;
5
- export declare const generateLockedData: (projectDir: string, streamAdapter?: "file" | "memory", printerType?: "disabled" | "default") => Promise<LockedData>;
5
+ export declare const generateLockedData: (config: {
6
+ projectDir: string;
7
+ streamAdapter?: "file" | "memory";
8
+ printerType?: "disabled" | "default";
9
+ motiaFileStoragePath?: string;
10
+ }) => Promise<LockedData>;
@@ -76,14 +76,15 @@ export const collectFlows = async (projectDir, lockedData) => {
76
76
  }
77
77
  return invalidSteps;
78
78
  };
79
- export const generateLockedData = async (projectDir, streamAdapter = 'file', printerType = 'default') => {
79
+ export const generateLockedData = async (config) => {
80
80
  try {
81
+ const { projectDir, streamAdapter = 'file', printerType = 'default', motiaFileStoragePath = '.motia' } = config;
81
82
  const printer = printerType === 'disabled' ? new NoPrinter() : new Printer(projectDir);
82
83
  /*
83
84
  * NOTE: right now for performance and simplicity let's enforce a folder,
84
85
  * but we might want to remove this and scan the entire current directory
85
86
  */
86
- const lockedData = new LockedData(projectDir, streamAdapter, printer);
87
+ const lockedData = new LockedData(projectDir, streamAdapter, printer, motiaFileStoragePath);
87
88
  await collectFlows(projectDir, lockedData);
88
89
  lockedData.saveTypes();
89
90
  return lockedData;
@@ -7,6 +7,13 @@ const defaultPlugins = [
7
7
  },
8
8
  ],
9
9
  },
10
+ {
11
+ workbench: [
12
+ {
13
+ packageName: '@motiadev/plugin-logs',
14
+ },
15
+ ],
16
+ },
10
17
  ];
11
18
  export const generatePlugins = async (motia) => {
12
19
  const configFiles = globSync('motia.config.{ts,js}', { absolute: true, cwd: motia.lockedData.baseDir });
@@ -1 +1 @@
1
- export declare const start: (port: number, hostname: string, disableVerbose: boolean) => Promise<void>;
1
+ export declare const start: (port: number, hostname: string, disableVerbose: boolean, motiaFileStorageDir?: string) => Promise<void>;