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

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 (158) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/__tests__/openapi/generate.test.d.ts +1 -0
  3. package/dist/cjs/__tests__/openapi/generate.test.js +287 -0
  4. package/dist/cjs/cli.js +16 -4
  5. package/dist/cjs/cloud/build/__tests__/infrastructure-serialization.test.d.ts +1 -0
  6. package/dist/cjs/cloud/build/__tests__/infrastructure-serialization.test.js +324 -0
  7. package/dist/cjs/cloud/build/__tests__/infrastructure-validation.test.d.ts +1 -0
  8. package/dist/cjs/cloud/build/__tests__/infrastructure-validation.test.js +673 -0
  9. package/dist/cjs/cloud/build/build-validation.d.ts +3 -5
  10. package/dist/cjs/cloud/build/build-validation.js +27 -140
  11. package/dist/cjs/cloud/build/validations/__tests__/api-endpoints.validator.test.d.ts +1 -0
  12. package/dist/cjs/cloud/build/validations/__tests__/api-endpoints.validator.test.js +71 -0
  13. package/dist/cjs/cloud/build/validations/__tests__/build-validation.test.d.ts +1 -0
  14. package/dist/cjs/cloud/build/validations/__tests__/build-validation.test.js +96 -0
  15. package/dist/cjs/cloud/build/validations/__tests__/cron-expressions.validator.test.d.ts +1 -0
  16. package/dist/cjs/cloud/build/validations/__tests__/cron-expressions.validator.test.js +68 -0
  17. package/dist/cjs/cloud/build/validations/__tests__/duplicate-step-names.validator.test.d.ts +1 -0
  18. package/dist/cjs/cloud/build/validations/__tests__/duplicate-step-names.validator.test.js +66 -0
  19. package/dist/cjs/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.d.ts +1 -0
  20. package/dist/cjs/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.js +71 -0
  21. package/dist/cjs/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.d.ts +1 -0
  22. package/dist/cjs/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.js +69 -0
  23. package/dist/cjs/cloud/build/validations/__tests__/step-name-lengths.validator.test.d.ts +1 -0
  24. package/dist/cjs/cloud/build/validations/__tests__/step-name-lengths.validator.test.js +68 -0
  25. package/dist/cjs/cloud/build/validations/api-endpoints.validator.d.ts +2 -0
  26. package/dist/cjs/cloud/build/validations/api-endpoints.validator.js +36 -0
  27. package/dist/cjs/cloud/build/validations/constants.d.ts +6 -0
  28. package/dist/cjs/cloud/build/validations/constants.js +9 -0
  29. package/dist/cjs/cloud/build/validations/cron-expressions.validator.d.ts +2 -0
  30. package/dist/cjs/cloud/build/validations/cron-expressions.validator.js +62 -0
  31. package/dist/cjs/cloud/build/validations/duplicate-step-names.validator.d.ts +2 -0
  32. package/dist/cjs/cloud/build/validations/duplicate-step-names.validator.js +26 -0
  33. package/dist/cjs/cloud/build/validations/infrastructure-configs.validator.d.ts +2 -0
  34. package/dist/cjs/cloud/build/validations/infrastructure-configs.validator.js +32 -0
  35. package/dist/cjs/cloud/build/validations/router-bundle-sizes.validator.d.ts +2 -0
  36. package/dist/cjs/cloud/build/validations/router-bundle-sizes.validator.js +31 -0
  37. package/dist/cjs/cloud/build/validations/step-bundle-sizes.validator.d.ts +2 -0
  38. package/dist/cjs/cloud/build/validations/step-bundle-sizes.validator.js +36 -0
  39. package/dist/cjs/cloud/build/validations/step-name-lengths.validator.d.ts +2 -0
  40. package/dist/cjs/cloud/build/validations/step-name-lengths.validator.js +27 -0
  41. package/dist/cjs/cloud/build/validations/types.d.ts +7 -0
  42. package/dist/cjs/cloud/build/validations/types.js +2 -0
  43. package/dist/cjs/create/index.js +6 -5
  44. package/dist/cjs/cursor-rules/dot-files/.claude/agents/motia-developer.md +95 -0
  45. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/api-steps.mdc +2 -2
  46. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/cron-steps.mdc +2 -2
  47. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/event-steps.mdc +2 -2
  48. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/realtime-streaming.mdc +3 -3
  49. package/dist/cjs/cursor-rules/dot-files/AGENTS.md +212 -0
  50. package/dist/cjs/cursor-rules/dot-files/CLAUDE.md +58 -0
  51. package/dist/cjs/cursor-rules/dot-files/opencode.json +20 -0
  52. package/dist/cjs/dev.js +12 -5
  53. package/dist/cjs/generate-locked-data.js +5 -0
  54. package/dist/cjs/generate-plugins.d.ts +2 -0
  55. package/dist/cjs/generate-plugins.js +56 -0
  56. package/dist/cjs/install.d.ts +2 -3
  57. package/dist/cjs/install.js +6 -6
  58. package/dist/cjs/openapi/generate.d.ts +2 -0
  59. package/dist/cjs/openapi/generate.js +125 -0
  60. package/dist/cjs/openapi/process-schema.d.ts +2 -0
  61. package/dist/cjs/openapi/process-schema.js +54 -0
  62. package/dist/cjs/openapi/utils.d.ts +2 -0
  63. package/dist/cjs/openapi/utils.js +7 -0
  64. package/dist/cjs/start.js +9 -2
  65. package/dist/cjs/utils/install-lambda-python-packages.d.ts +1 -2
  66. package/dist/cjs/utils/install-lambda-python-packages.js +2 -2
  67. package/dist/esm/__tests__/openapi/generate.test.d.ts +1 -0
  68. package/dist/esm/__tests__/openapi/generate.test.js +252 -0
  69. package/dist/esm/cli.js +16 -4
  70. package/dist/esm/cloud/build/__tests__/infrastructure-serialization.test.d.ts +1 -0
  71. package/dist/esm/cloud/build/__tests__/infrastructure-serialization.test.js +322 -0
  72. package/dist/esm/cloud/build/__tests__/infrastructure-validation.test.d.ts +1 -0
  73. package/dist/esm/cloud/build/__tests__/infrastructure-validation.test.js +671 -0
  74. package/dist/esm/cloud/build/build-validation.d.ts +3 -5
  75. package/dist/esm/cloud/build/build-validation.js +27 -104
  76. package/dist/esm/cloud/build/validations/__tests__/api-endpoints.validator.test.d.ts +1 -0
  77. package/dist/esm/cloud/build/validations/__tests__/api-endpoints.validator.test.js +69 -0
  78. package/dist/esm/cloud/build/validations/__tests__/build-validation.test.d.ts +1 -0
  79. package/dist/esm/cloud/build/validations/__tests__/build-validation.test.js +94 -0
  80. package/dist/esm/cloud/build/validations/__tests__/cron-expressions.validator.test.d.ts +1 -0
  81. package/dist/esm/cloud/build/validations/__tests__/cron-expressions.validator.test.js +66 -0
  82. package/dist/esm/cloud/build/validations/__tests__/duplicate-step-names.validator.test.d.ts +1 -0
  83. package/dist/esm/cloud/build/validations/__tests__/duplicate-step-names.validator.test.js +64 -0
  84. package/dist/esm/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.d.ts +1 -0
  85. package/dist/esm/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.js +69 -0
  86. package/dist/esm/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.d.ts +1 -0
  87. package/dist/esm/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.js +67 -0
  88. package/dist/esm/cloud/build/validations/__tests__/step-name-lengths.validator.test.d.ts +1 -0
  89. package/dist/esm/cloud/build/validations/__tests__/step-name-lengths.validator.test.js +66 -0
  90. package/dist/esm/cloud/build/validations/api-endpoints.validator.d.ts +2 -0
  91. package/dist/esm/cloud/build/validations/api-endpoints.validator.js +29 -0
  92. package/dist/esm/cloud/build/validations/constants.d.ts +6 -0
  93. package/dist/esm/cloud/build/validations/constants.js +6 -0
  94. package/dist/esm/cloud/build/validations/cron-expressions.validator.d.ts +2 -0
  95. package/dist/esm/cloud/build/validations/cron-expressions.validator.js +22 -0
  96. package/dist/esm/cloud/build/validations/duplicate-step-names.validator.d.ts +2 -0
  97. package/dist/esm/cloud/build/validations/duplicate-step-names.validator.js +19 -0
  98. package/dist/esm/cloud/build/validations/infrastructure-configs.validator.d.ts +2 -0
  99. package/dist/esm/cloud/build/validations/infrastructure-configs.validator.js +25 -0
  100. package/dist/esm/cloud/build/validations/router-bundle-sizes.validator.d.ts +2 -0
  101. package/dist/esm/cloud/build/validations/router-bundle-sizes.validator.js +24 -0
  102. package/dist/esm/cloud/build/validations/step-bundle-sizes.validator.d.ts +2 -0
  103. package/dist/esm/cloud/build/validations/step-bundle-sizes.validator.js +29 -0
  104. package/dist/esm/cloud/build/validations/step-name-lengths.validator.d.ts +2 -0
  105. package/dist/esm/cloud/build/validations/step-name-lengths.validator.js +20 -0
  106. package/dist/esm/cloud/build/validations/types.d.ts +7 -0
  107. package/dist/esm/cloud/build/validations/types.js +1 -0
  108. package/dist/esm/create/index.js +7 -6
  109. package/dist/esm/cursor-rules/dot-files/.claude/agents/motia-developer.md +95 -0
  110. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/api-steps.mdc +2 -2
  111. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/cron-steps.mdc +2 -2
  112. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/event-steps.mdc +2 -2
  113. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/realtime-streaming.mdc +3 -3
  114. package/dist/esm/cursor-rules/dot-files/AGENTS.md +212 -0
  115. package/dist/esm/cursor-rules/dot-files/CLAUDE.md +58 -0
  116. package/dist/esm/cursor-rules/dot-files/opencode.json +20 -0
  117. package/dist/esm/dev.js +12 -5
  118. package/dist/esm/generate-locked-data.js +5 -0
  119. package/dist/esm/generate-plugins.d.ts +2 -0
  120. package/dist/esm/generate-plugins.js +19 -0
  121. package/dist/esm/install.d.ts +2 -3
  122. package/dist/esm/install.js +6 -6
  123. package/dist/esm/openapi/generate.d.ts +2 -0
  124. package/dist/esm/openapi/generate.js +89 -0
  125. package/dist/esm/openapi/process-schema.d.ts +2 -0
  126. package/dist/esm/openapi/process-schema.js +51 -0
  127. package/dist/esm/openapi/utils.d.ts +2 -0
  128. package/dist/esm/openapi/utils.js +4 -0
  129. package/dist/esm/start.js +9 -2
  130. package/dist/esm/utils/install-lambda-python-packages.d.ts +1 -2
  131. package/dist/esm/utils/install-lambda-python-packages.js +2 -2
  132. package/dist/types/__tests__/openapi/generate.test.d.ts +1 -0
  133. package/dist/types/cloud/build/__tests__/infrastructure-serialization.test.d.ts +1 -0
  134. package/dist/types/cloud/build/__tests__/infrastructure-validation.test.d.ts +1 -0
  135. package/dist/types/cloud/build/build-validation.d.ts +3 -5
  136. package/dist/types/cloud/build/validations/__tests__/api-endpoints.validator.test.d.ts +1 -0
  137. package/dist/types/cloud/build/validations/__tests__/build-validation.test.d.ts +1 -0
  138. package/dist/types/cloud/build/validations/__tests__/cron-expressions.validator.test.d.ts +1 -0
  139. package/dist/types/cloud/build/validations/__tests__/duplicate-step-names.validator.test.d.ts +1 -0
  140. package/dist/types/cloud/build/validations/__tests__/router-bundle-sizes.validator.test.d.ts +1 -0
  141. package/dist/types/cloud/build/validations/__tests__/step-bundle-sizes.validator.test.d.ts +1 -0
  142. package/dist/types/cloud/build/validations/__tests__/step-name-lengths.validator.test.d.ts +1 -0
  143. package/dist/types/cloud/build/validations/api-endpoints.validator.d.ts +2 -0
  144. package/dist/types/cloud/build/validations/constants.d.ts +6 -0
  145. package/dist/types/cloud/build/validations/cron-expressions.validator.d.ts +2 -0
  146. package/dist/types/cloud/build/validations/duplicate-step-names.validator.d.ts +2 -0
  147. package/dist/types/cloud/build/validations/infrastructure-configs.validator.d.ts +2 -0
  148. package/dist/types/cloud/build/validations/router-bundle-sizes.validator.d.ts +2 -0
  149. package/dist/types/cloud/build/validations/step-bundle-sizes.validator.d.ts +2 -0
  150. package/dist/types/cloud/build/validations/step-name-lengths.validator.d.ts +2 -0
  151. package/dist/types/cloud/build/validations/types.d.ts +7 -0
  152. package/dist/types/generate-plugins.d.ts +2 -0
  153. package/dist/types/install.d.ts +2 -3
  154. package/dist/types/openapi/generate.d.ts +2 -0
  155. package/dist/types/openapi/process-schema.d.ts +2 -0
  156. package/dist/types/openapi/utils.d.ts +2 -0
  157. package/dist/types/utils/install-lambda-python-packages.d.ts +1 -2
  158. package/package.json +6 -5
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  [💡 Motia Manifesto](https://www.motia.dev/manifesto) •
12
12
  [🚀 Quick Start](https://www.motia.dev/docs/getting-started/quick-start) •
13
- [📋 Defining Steps](https://www.motia.dev/docs/concepts/steps/defining-steps) •
13
+ [📋 Defining Steps](https://www.motia.dev/docs/concepts/steps/steps) •
14
14
  [📚 Docs](https://www.motia.dev/docs)
15
15
 
16
16
  ---
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,287 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const fs = __importStar(require("fs"));
37
+ const path = __importStar(require("path"));
38
+ const generate_1 = require("../../openapi/generate");
39
+ jest.mock('fs', () => ({
40
+ readFileSync: jest.fn(),
41
+ writeFileSync: jest.fn(),
42
+ }));
43
+ describe('generateOpenApi', () => {
44
+ const mockProjectDir = '/mock/project';
45
+ const mockOutputFile = 'mock-project-openapi.json';
46
+ beforeEach(() => {
47
+ jest.clearAllMocks();
48
+ fs.readFileSync.mockReturnValue(JSON.stringify({ name: 'test-project', version: '1.0.0' }));
49
+ });
50
+ const MOCK_API_STEP = {
51
+ filePath: '/mock/project/steps/test.ts',
52
+ version: '1.0.0',
53
+ config: {
54
+ type: 'api',
55
+ name: 'testApi',
56
+ path: '/test',
57
+ method: 'GET',
58
+ emits: [],
59
+ },
60
+ };
61
+ it('should generate a basic OpenAPI spec with default info', () => {
62
+ const apiSteps = [MOCK_API_STEP];
63
+ (0, generate_1.generateOpenApi)(mockProjectDir, apiSteps, undefined, undefined, mockOutputFile);
64
+ const expectedOpenApi = {
65
+ openapi: '3.0.0',
66
+ info: {
67
+ title: 'test-project',
68
+ version: '1.0.0',
69
+ },
70
+ paths: {
71
+ '/test': {
72
+ get: {
73
+ summary: 'testApi',
74
+ description: undefined,
75
+ requestBody: undefined,
76
+ responses: {},
77
+ },
78
+ },
79
+ },
80
+ components: {
81
+ schemas: {},
82
+ },
83
+ };
84
+ expect(fs.writeFileSync).toHaveBeenCalledWith(path.join(mockProjectDir, mockOutputFile), JSON.stringify(expectedOpenApi, null, 2));
85
+ });
86
+ it('should handle bodySchema and responseSchema correctly', () => {
87
+ const mockBodySchema = {
88
+ type: 'object',
89
+ properties: {
90
+ id: { type: 'string' },
91
+ },
92
+ };
93
+ const mockResponseSchema = {
94
+ 200: {
95
+ type: 'object',
96
+ properties: {
97
+ message: { type: 'string' },
98
+ },
99
+ },
100
+ };
101
+ const mockApiStep = {
102
+ ...MOCK_API_STEP,
103
+ config: {
104
+ ...MOCK_API_STEP.config,
105
+ type: 'api',
106
+ name: 'testApiWithSchemas',
107
+ path: '/test-schemas',
108
+ method: 'POST',
109
+ bodySchema: mockBodySchema,
110
+ responseSchema: mockResponseSchema,
111
+ emits: [],
112
+ },
113
+ };
114
+ const apiSteps = [mockApiStep];
115
+ (0, generate_1.generateOpenApi)(mockProjectDir, apiSteps, undefined, undefined, mockOutputFile);
116
+ const expectedOpenApi = {
117
+ openapi: '3.0.0',
118
+ info: {
119
+ title: 'test-project',
120
+ version: '1.0.0',
121
+ },
122
+ paths: {
123
+ '/test-schemas': {
124
+ post: {
125
+ summary: 'testApiWithSchemas',
126
+ description: undefined,
127
+ requestBody: {
128
+ content: {
129
+ 'application/json': {
130
+ schema: mockBodySchema,
131
+ },
132
+ },
133
+ },
134
+ responses: {
135
+ 200: {
136
+ description: 'Response for status code 200',
137
+ content: {
138
+ 'application/json': {
139
+ schema: mockResponseSchema[200],
140
+ },
141
+ },
142
+ },
143
+ },
144
+ },
145
+ },
146
+ },
147
+ components: {
148
+ schemas: {},
149
+ },
150
+ };
151
+ expect(fs.writeFileSync).toHaveBeenCalledWith(path.join(mockProjectDir, mockOutputFile), JSON.stringify(expectedOpenApi, null, 2));
152
+ });
153
+ it('should use provided title', () => {
154
+ const apiSteps = [MOCK_API_STEP];
155
+ const customTitle = 'Custom API';
156
+ (0, generate_1.generateOpenApi)(mockProjectDir, apiSteps, customTitle);
157
+ const expectedOpenApi = {
158
+ openapi: '3.0.0',
159
+ info: {
160
+ title: customTitle,
161
+ version: '1.0.0',
162
+ },
163
+ paths: {
164
+ '/test': {
165
+ get: {
166
+ summary: 'testApi',
167
+ description: undefined,
168
+ requestBody: undefined,
169
+ responses: {},
170
+ },
171
+ },
172
+ },
173
+ components: {
174
+ schemas: {},
175
+ },
176
+ };
177
+ expect(fs.writeFileSync).toHaveBeenCalledWith(path.join(mockProjectDir, 'openapi.json'), JSON.stringify(expectedOpenApi, null, 2));
178
+ });
179
+ it('should use provided version', () => {
180
+ const apiSteps = [MOCK_API_STEP];
181
+ const customVersion = '2.0.0';
182
+ (0, generate_1.generateOpenApi)(mockProjectDir, apiSteps, undefined, customVersion, mockOutputFile);
183
+ const expectedOpenApi = {
184
+ openapi: '3.0.0',
185
+ info: {
186
+ title: 'test-project',
187
+ version: customVersion,
188
+ },
189
+ paths: {
190
+ '/test': {
191
+ get: {
192
+ summary: 'testApi',
193
+ description: undefined,
194
+ requestBody: undefined,
195
+ responses: {},
196
+ },
197
+ },
198
+ },
199
+ components: {
200
+ schemas: {},
201
+ },
202
+ };
203
+ expect(fs.writeFileSync).toHaveBeenCalledWith(path.join(mockProjectDir, mockOutputFile), JSON.stringify(expectedOpenApi, null, 2));
204
+ });
205
+ it('should handle complex bodySchema with anyOf, nullable, and $ref', () => {
206
+ const mockUserSchema = {
207
+ type: 'object',
208
+ properties: {
209
+ name: { type: 'string' },
210
+ email: { type: 'string', format: 'email' },
211
+ },
212
+ required: ['name', 'email'],
213
+ };
214
+ const mockComplexBodySchema = {
215
+ type: 'object',
216
+ properties: {
217
+ id: { type: 'string' },
218
+ status: {
219
+ anyOf: [{ type: 'string', enum: ['active', 'inactive'] }, { type: 'number', enum: [0, 1] }, { type: 'null' }],
220
+ },
221
+ user: { $ref: '#/components/schemas/User' },
222
+ },
223
+ required: ['id'],
224
+ $defs: {
225
+ User: mockUserSchema,
226
+ },
227
+ };
228
+ const mockApiStep = {
229
+ ...MOCK_API_STEP,
230
+ filePath: '/mock/project/steps/complex.ts',
231
+ config: {
232
+ ...MOCK_API_STEP.config,
233
+ type: 'api',
234
+ name: 'testComplexApi',
235
+ path: '/test-complex',
236
+ method: 'PUT',
237
+ emits: [],
238
+ bodySchema: mockComplexBodySchema,
239
+ },
240
+ };
241
+ const apiSteps = [mockApiStep];
242
+ (0, generate_1.generateOpenApi)(mockProjectDir, apiSteps, undefined, undefined, mockOutputFile);
243
+ const expectedOpenApi = {
244
+ openapi: '3.0.0',
245
+ info: {
246
+ title: 'test-project',
247
+ version: '1.0.0',
248
+ },
249
+ paths: {
250
+ '/test-complex': {
251
+ put: {
252
+ summary: 'testComplexApi',
253
+ description: undefined,
254
+ requestBody: {
255
+ content: {
256
+ 'application/json': {
257
+ schema: {
258
+ type: 'object',
259
+ properties: {
260
+ id: { type: 'string' },
261
+ status: {
262
+ anyOf: [
263
+ { type: 'string', enum: ['active', 'inactive'] },
264
+ { type: 'number', enum: [0, 1] },
265
+ ],
266
+ nullable: true,
267
+ },
268
+ user: { $ref: '#/components/schemas/User' },
269
+ },
270
+ required: ['id'],
271
+ },
272
+ },
273
+ },
274
+ },
275
+ responses: {},
276
+ },
277
+ },
278
+ },
279
+ components: {
280
+ schemas: {
281
+ User: mockUserSchema,
282
+ },
283
+ },
284
+ };
285
+ expect(fs.writeFileSync).toHaveBeenCalledWith(path.join(mockProjectDir, mockOutputFile), JSON.stringify(expectedOpenApi, null, 2));
286
+ });
287
+ });
package/dist/cjs/cli.js CHANGED
@@ -4,8 +4,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  /* eslint-disable @typescript-eslint/no-require-imports */
5
5
  const commander_1 = require("commander");
6
6
  require("./cloud");
7
- const version_1 = require("./version");
8
7
  const config_utils_1 = require("./cloud/config-utils");
8
+ const version_1 = require("./version");
9
9
  const defaultPort = 3000;
10
10
  const defaultHost = '0.0.0.0';
11
11
  require('dotenv/config');
@@ -56,11 +56,9 @@ commander_1.program
56
56
  .command('install')
57
57
  .description('Sets up Python virtual environment and install dependencies')
58
58
  .option('-v, --verbose', 'Enable verbose logging')
59
- .option('-p, --python <python_version>', 'Specify the python version to use, only supported >3.12')
60
- .option('-d, --docker', 'Indicate if the install is for a motia docker install')
61
59
  .action(async (options) => {
62
60
  const { install } = require('./install');
63
- await install({ isVerbose: options.verbose, pythonVersion: options.python, skipPythonPlatform: !!options.docker });
61
+ await install({ isVerbose: options.verbose });
64
62
  });
65
63
  commander_1.program
66
64
  .command('dev')
@@ -137,6 +135,20 @@ generate
137
135
  stepFilePath: arg.dir,
138
136
  });
139
137
  });
138
+ generate
139
+ .command('openapi')
140
+ .description('Generate OpenAPI spec for your project')
141
+ .option('-t, --title <title>', 'Title for the OpenAPI document. Defaults to project name')
142
+ .option('-v, --version <version>', 'Version for the OpenAPI document. Defaults to 1.0.0', '1.0.0')
143
+ .option('-o, --output <output>', 'Output file for the OpenAPI document. Defaults to openapi.json', 'openapi.json')
144
+ .action(async (options) => {
145
+ const { generateLockedData } = require('./generate-locked-data');
146
+ const { generateOpenApi } = require('./openapi/generate');
147
+ const lockedData = await generateLockedData(process.cwd());
148
+ const apiSteps = lockedData.apiSteps();
149
+ generateOpenApi(process.cwd(), apiSteps, options.title, options.version, options.output);
150
+ process.exit(0);
151
+ });
140
152
  const docker = commander_1.program.command('docker').description('Motia docker commands');
141
153
  docker
142
154
  .command('setup')
@@ -0,0 +1,324 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const zod_1 = require("@motiadev/core/node_modules/zod");
4
+ describe('Infrastructure Config Serialization', () => {
5
+ function createMockStepWithInfrastructure() {
6
+ const inputSchema = zod_1.z.object({
7
+ traceId: zod_1.z.string(),
8
+ userId: zod_1.z.string(),
9
+ });
10
+ return {
11
+ type: 'node',
12
+ entrypointPath: '/mock/steps/testStep.step.ts',
13
+ filePath: '/mock/project/steps/testStep.step.ts',
14
+ config: {
15
+ type: 'event',
16
+ name: 'testStep',
17
+ description: 'Test step with infrastructure',
18
+ subscribes: ['test.event'],
19
+ emits: [],
20
+ input: inputSchema,
21
+ infrastructure: {
22
+ handler: {
23
+ ram: 2048,
24
+ timeout: 30,
25
+ cpu: 1,
26
+ },
27
+ queue: {
28
+ type: 'fifo',
29
+ visibilityTimeout: 31,
30
+ messageGroupId: 'traceId',
31
+ maxRetries: 5,
32
+ },
33
+ },
34
+ },
35
+ };
36
+ }
37
+ function createMockStepWithoutInfrastructure() {
38
+ return {
39
+ type: 'node',
40
+ entrypointPath: '/mock/steps/legacyStep.step.ts',
41
+ filePath: '/mock/project/steps/legacyStep.step.ts',
42
+ config: {
43
+ type: 'event',
44
+ name: 'legacyStep',
45
+ description: 'Legacy step without infrastructure',
46
+ subscribes: ['test.event'],
47
+ emits: [],
48
+ input: {},
49
+ },
50
+ };
51
+ }
52
+ function createMockStepWithPartialInfrastructure() {
53
+ return {
54
+ type: 'node',
55
+ entrypointPath: '/mock/steps/partialStep.step.ts',
56
+ filePath: '/mock/project/steps/partialStep.step.ts',
57
+ config: {
58
+ type: 'event',
59
+ name: 'partialStep',
60
+ description: 'Step with partial infrastructure',
61
+ subscribes: ['test.event'],
62
+ emits: [],
63
+ input: {},
64
+ infrastructure: {
65
+ handler: {
66
+ ram: 4096,
67
+ timeout: 60,
68
+ },
69
+ },
70
+ },
71
+ };
72
+ }
73
+ describe('JSON Serialization', () => {
74
+ it('should serialize step with infrastructure config correctly', () => {
75
+ const step = createMockStepWithInfrastructure();
76
+ const stepsConfig = { testStep: step };
77
+ const stepsFile = {
78
+ steps: stepsConfig,
79
+ streams: {},
80
+ routers: {},
81
+ };
82
+ const json = JSON.stringify(stepsFile, null, 2);
83
+ const parsed = JSON.parse(json);
84
+ expect(parsed.steps.testStep).toBeDefined();
85
+ expect(parsed.steps.testStep.config.infrastructure).toBeDefined();
86
+ expect(parsed.steps.testStep.config.infrastructure.handler).toBeDefined();
87
+ expect(parsed.steps.testStep.config.infrastructure.queue).toBeDefined();
88
+ });
89
+ it('should serialize handler configuration correctly', () => {
90
+ const step = createMockStepWithInfrastructure();
91
+ const stepsConfig = { testStep: step };
92
+ const stepsFile = {
93
+ steps: stepsConfig,
94
+ streams: {},
95
+ routers: {},
96
+ };
97
+ const json = JSON.stringify(stepsFile);
98
+ const parsed = JSON.parse(json);
99
+ const handler = parsed.steps.testStep.config.infrastructure.handler;
100
+ expect(handler.ram).toBe(2048);
101
+ expect(handler.timeout).toBe(30);
102
+ expect(handler.cpu).toBe(1);
103
+ });
104
+ it('should serialize queue configuration correctly', () => {
105
+ const step = createMockStepWithInfrastructure();
106
+ const stepsConfig = { testStep: step };
107
+ const stepsFile = {
108
+ steps: stepsConfig,
109
+ streams: {},
110
+ routers: {},
111
+ };
112
+ const json = JSON.stringify(stepsFile);
113
+ const parsed = JSON.parse(json);
114
+ const queue = parsed.steps.testStep.config.infrastructure.queue;
115
+ expect(queue.type).toBe('fifo');
116
+ expect(queue.visibilityTimeout).toBe(31);
117
+ expect(queue.messageGroupId).toBe('traceId');
118
+ expect(queue.maxRetries).toBe(5);
119
+ });
120
+ it('should serialize partial infrastructure config correctly', () => {
121
+ const step = createMockStepWithPartialInfrastructure();
122
+ const stepsConfig = { partialStep: step };
123
+ const stepsFile = {
124
+ steps: stepsConfig,
125
+ streams: {},
126
+ routers: {},
127
+ };
128
+ const json = JSON.stringify(stepsFile);
129
+ const parsed = JSON.parse(json);
130
+ expect(parsed.steps.partialStep.config.infrastructure).toBeDefined();
131
+ expect(parsed.steps.partialStep.config.infrastructure.handler).toBeDefined();
132
+ expect(parsed.steps.partialStep.config.infrastructure.queue).toBeUndefined();
133
+ const handler = parsed.steps.partialStep.config.infrastructure.handler;
134
+ expect(handler.ram).toBe(4096);
135
+ expect(handler.timeout).toBe(60);
136
+ });
137
+ });
138
+ describe('Backward Compatibility', () => {
139
+ it('should serialize step without infrastructure config correctly', () => {
140
+ const step = createMockStepWithoutInfrastructure();
141
+ const stepsConfig = { legacyStep: step };
142
+ const stepsFile = {
143
+ steps: stepsConfig,
144
+ streams: {},
145
+ routers: {},
146
+ };
147
+ const json = JSON.stringify(stepsFile, null, 2);
148
+ const parsed = JSON.parse(json);
149
+ expect(parsed.steps.legacyStep).toBeDefined();
150
+ expect(parsed.steps.legacyStep.config.name).toBe('legacyStep');
151
+ expect(parsed.steps.legacyStep.config.type).toBe('event');
152
+ expect(parsed.steps.legacyStep.config.infrastructure).toBeUndefined();
153
+ });
154
+ it('should handle mixed steps (with and without infrastructure)', () => {
155
+ const stepWithInfra = createMockStepWithInfrastructure();
156
+ const stepWithoutInfra = createMockStepWithoutInfrastructure();
157
+ const stepsConfig = {
158
+ testStep: stepWithInfra,
159
+ legacyStep: stepWithoutInfra,
160
+ };
161
+ const stepsFile = {
162
+ steps: stepsConfig,
163
+ streams: {},
164
+ routers: {},
165
+ };
166
+ const json = JSON.stringify(stepsFile);
167
+ const parsed = JSON.parse(json);
168
+ expect(parsed.steps.testStep.config.infrastructure).toBeDefined();
169
+ expect(parsed.steps.legacyStep.config.infrastructure).toBeUndefined();
170
+ });
171
+ it('should maintain all existing step properties when infrastructure is added', () => {
172
+ const step = createMockStepWithInfrastructure();
173
+ const stepsConfig = { testStep: step };
174
+ const stepsFile = {
175
+ steps: stepsConfig,
176
+ streams: {},
177
+ routers: {},
178
+ };
179
+ const json = JSON.stringify(stepsFile);
180
+ const parsed = JSON.parse(json);
181
+ const config = parsed.steps.testStep.config;
182
+ expect(config.type).toBe('event');
183
+ expect(config.name).toBe('testStep');
184
+ expect(config.description).toBe('Test step with infrastructure');
185
+ expect(config.subscribes).toEqual(['test.event']);
186
+ expect(config.emits).toEqual([]);
187
+ });
188
+ it('should not break existing step configs when infrastructure field is absent', () => {
189
+ const apiStep = {
190
+ type: 'node',
191
+ entrypointPath: '/mock/steps/apiStep.step.ts',
192
+ filePath: '/mock/project/steps/apiStep.step.ts',
193
+ config: {
194
+ type: 'api',
195
+ name: 'apiStep',
196
+ description: 'API step without infrastructure',
197
+ path: '/test',
198
+ method: 'GET',
199
+ emits: [],
200
+ },
201
+ };
202
+ const stepsConfig = { apiStep };
203
+ const stepsFile = {
204
+ steps: stepsConfig,
205
+ streams: {},
206
+ routers: {},
207
+ };
208
+ const json = JSON.stringify(stepsFile);
209
+ const parsed = JSON.parse(json);
210
+ expect(parsed.steps.apiStep.config.type).toBe('api');
211
+ expect(parsed.steps.apiStep.config.path).toBe('/test');
212
+ expect(parsed.steps.apiStep.config.method).toBe('GET');
213
+ expect(parsed.steps.apiStep.config.infrastructure).toBeUndefined();
214
+ });
215
+ it('should not break existing cron step configs', () => {
216
+ const cronStep = {
217
+ type: 'node',
218
+ entrypointPath: '/mock/steps/cronStep.step.ts',
219
+ filePath: '/mock/project/steps/cronStep.step.ts',
220
+ config: {
221
+ type: 'cron',
222
+ name: 'cronStep',
223
+ description: 'Cron step without infrastructure',
224
+ cron: '0 0 * * *',
225
+ emits: [],
226
+ },
227
+ };
228
+ const stepsConfig = { cronStep };
229
+ const stepsFile = {
230
+ steps: stepsConfig,
231
+ streams: {},
232
+ routers: {},
233
+ };
234
+ const json = JSON.stringify(stepsFile);
235
+ const parsed = JSON.parse(json);
236
+ expect(parsed.steps.cronStep.config.type).toBe('cron');
237
+ expect(parsed.steps.cronStep.config.cron).toBe('0 0 * * *');
238
+ expect(parsed.steps.cronStep.config.infrastructure).toBeUndefined();
239
+ });
240
+ });
241
+ describe('Deserialization', () => {
242
+ it('should deserialize step with infrastructure config correctly', () => {
243
+ const jsonString = JSON.stringify({
244
+ steps: {
245
+ testStep: {
246
+ type: 'node',
247
+ entrypointPath: '/mock/steps/testStep.step.ts',
248
+ filePath: '/mock/project/steps/testStep.step.ts',
249
+ config: {
250
+ type: 'event',
251
+ name: 'testStep',
252
+ subscribes: ['test.event'],
253
+ emits: [],
254
+ infrastructure: {
255
+ handler: {
256
+ ram: 2048,
257
+ timeout: 30,
258
+ },
259
+ queue: {
260
+ type: 'standard',
261
+ visibilityTimeout: 60,
262
+ maxRetries: 3,
263
+ },
264
+ },
265
+ },
266
+ },
267
+ },
268
+ streams: {},
269
+ routers: {},
270
+ });
271
+ const parsed = JSON.parse(jsonString);
272
+ expect(parsed.steps.testStep).toBeDefined();
273
+ const config = parsed.steps.testStep.config;
274
+ expect(config.infrastructure).toBeDefined();
275
+ const infra = config.infrastructure;
276
+ expect(infra.handler.ram).toBe(2048);
277
+ expect(infra.queue.type).toBe('standard');
278
+ });
279
+ it('should deserialize step without infrastructure config correctly', () => {
280
+ const jsonString = JSON.stringify({
281
+ steps: {
282
+ legacyStep: {
283
+ type: 'node',
284
+ entrypointPath: '/mock/steps/legacyStep.step.ts',
285
+ filePath: '/mock/project/steps/legacyStep.step.ts',
286
+ config: {
287
+ type: 'event',
288
+ name: 'legacyStep',
289
+ subscribes: ['test.event'],
290
+ emits: [],
291
+ },
292
+ },
293
+ },
294
+ streams: {},
295
+ routers: {},
296
+ });
297
+ const parsed = JSON.parse(jsonString);
298
+ expect(parsed.steps.legacyStep).toBeDefined();
299
+ expect(parsed.steps.legacyStep.config.infrastructure).toBeUndefined();
300
+ });
301
+ });
302
+ describe('Type Safety', () => {
303
+ it('should maintain type safety with infrastructure config', () => {
304
+ const step = createMockStepWithInfrastructure();
305
+ const config = step.config;
306
+ expect(config.infrastructure).toBeDefined();
307
+ expect(typeof config.infrastructure).toBe('object');
308
+ const infra = config.infrastructure;
309
+ expect(typeof infra.handler).toBe('object');
310
+ expect(typeof infra.queue).toBe('object');
311
+ });
312
+ it('should handle undefined infrastructure gracefully', () => {
313
+ const step = createMockStepWithoutInfrastructure();
314
+ const config = step.config;
315
+ expect(config.infrastructure).toBeUndefined();
316
+ expect(() => {
317
+ const infra = config.infrastructure;
318
+ if (infra) {
319
+ console.log(infra.handler);
320
+ }
321
+ }).not.toThrow();
322
+ });
323
+ });
324
+ });