@motiadev/core 0.16.1-beta.179 → 0.17.0-beta.181

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/index.d.mts CHANGED
@@ -25,6 +25,7 @@ import "./src/adapters/defaults/index.mjs";
25
25
  import { getProjectIdentifier, getProjectName, getUserIdentifier, isAnalyticsEnabled, trackEvent } from "./src/analytics/utils.mjs";
26
26
  import { config } from "./src/config.mjs";
27
27
  import { CronManager, setupCronHandlers } from "./src/cron-handler.mjs";
28
+ import { invalidate } from "./src/ts-compiler.mjs";
28
29
  import { getStepConfig, getStreamConfig } from "./src/get-step-config.mjs";
29
30
  import { isApiStep, isCronStep, isEventStep, isNoopStep } from "./src/guards.mjs";
30
31
  import { InfrastructureValidationError, InfrastructureValidationResult } from "./src/infrastructure-validator/types.mjs";
@@ -35,4 +36,4 @@ import { NoTracer } from "./src/observability/no-tracer.mjs";
35
36
  import { MotiaEventManager, createStepHandlers } from "./src/step-handlers.mjs";
36
37
  import { MotiaServer, createServer } from "./src/server.mjs";
37
38
  import { createStateAdapter } from "./src/state/create-state-adapter.mjs";
38
- export { type AdapterConfig, ApiMiddleware, ApiRequest, ApiResponse, ApiRouteConfig, ApiRouteHandler, ApiRouteMethod, type BaseStreamItem, type Config, type CronAdapter, type CronAdapterConfig, type CronConfig, CronHandler, type CronLock, type CronLockInfo, type CronManager, InMemoryCronAdapter as DefaultCronAdapter, InMemoryQueueEventAdapter as DefaultQueueEventAdapter, Emit, EmitData, Emitter, Event, type EventAdapter, EventConfig, EventHandler, FileStateAdapter, FileStreamAdapter, FileStreamAdapterManager, Flow, FlowContext, FlowContextStateStreams, Handler, HandlerConfig, Handlers, InfrastructureConfig, type InfrastructureValidationError, type InfrastructureValidationResult, InternalStateManager, JsonSchema, JsonSchemaError, LockedData, Logger, MemoryStateAdapter, MemoryStreamAdapter, MemoryStreamAdapterManager, type Metric, type Motia, type MotiaEventManager, MotiaPlugin, MotiaPluginBuilder, type MotiaPluginContext, type MotiaServer, type MotiaStream, NoPrinter, NoTracer, NoopConfig, type ObservabilityAdapter, PLUGIN_FLOW_ID, type PluginApiConfig, PluginStep, Printer, QueryParam, QueueConfig, QueueManager, type QueueMetrics, RedisConfig, type StateAdapter, type StateFilter, type StateItem, type StateItemsInput, type StateStreamEvent, type StateStreamEventChannel, Step, StepConfig, StepHandler, StepSchemaInput, type Stream, StreamAdapter, type StreamAdapterManager, StreamAuthConfig, type StreamAuthRequest, type StreamConfig, type StreamQueryFilter, type StreamSubscription, SubscribeConfig, type SubscriptionHandle, type Tracer, type UnregisterMotiaPluginApi, UnsubscribeConfig, WorkbenchPlugin, ZodInput, config, createMermaidGenerator, createServer, createStateAdapter, createStepHandlers, getProjectIdentifier, getProjectName, getStepConfig, getStreamConfig, getUserIdentifier, isAnalyticsEnabled, isAnyOf, isApiStep, isCronStep, isEventStep, isNoopStep, setupCronHandlers, trackEvent, validateInfrastructureConfig };
39
+ export { type AdapterConfig, ApiMiddleware, ApiRequest, ApiResponse, ApiRouteConfig, ApiRouteHandler, ApiRouteMethod, type BaseStreamItem, type Config, type CronAdapter, type CronAdapterConfig, type CronConfig, CronHandler, type CronLock, type CronLockInfo, type CronManager, InMemoryCronAdapter as DefaultCronAdapter, InMemoryQueueEventAdapter as DefaultQueueEventAdapter, Emit, EmitData, Emitter, Event, type EventAdapter, EventConfig, EventHandler, FileStateAdapter, FileStreamAdapter, FileStreamAdapterManager, Flow, FlowContext, FlowContextStateStreams, Handler, HandlerConfig, Handlers, InfrastructureConfig, type InfrastructureValidationError, type InfrastructureValidationResult, InternalStateManager, JsonSchema, JsonSchemaError, LockedData, Logger, MemoryStateAdapter, MemoryStreamAdapter, MemoryStreamAdapterManager, type Metric, type Motia, type MotiaEventManager, MotiaPlugin, MotiaPluginBuilder, type MotiaPluginContext, type MotiaServer, type MotiaStream, NoPrinter, NoTracer, NoopConfig, type ObservabilityAdapter, PLUGIN_FLOW_ID, type PluginApiConfig, PluginStep, Printer, QueryParam, QueueConfig, QueueManager, type QueueMetrics, RedisConfig, type StateAdapter, type StateFilter, type StateItem, type StateItemsInput, type StateStreamEvent, type StateStreamEventChannel, Step, StepConfig, StepHandler, StepSchemaInput, type Stream, StreamAdapter, type StreamAdapterManager, StreamAuthConfig, type StreamAuthRequest, type StreamConfig, type StreamQueryFilter, type StreamSubscription, SubscribeConfig, type SubscriptionHandle, type Tracer, type UnregisterMotiaPluginApi, UnsubscribeConfig, WorkbenchPlugin, ZodInput, config, createMermaidGenerator, createServer, createStateAdapter, createStepHandlers, getProjectIdentifier, getProjectName, getStepConfig, getStreamConfig, getUserIdentifier, invalidate, isAnalyticsEnabled, isAnyOf, isApiStep, isCronStep, isEventStep, isNoopStep, setupCronHandlers, trackEvent, validateInfrastructureConfig };
package/dist/index.mjs CHANGED
@@ -12,6 +12,7 @@ import { MemoryStreamAdapterManager } from "./src/adapters/defaults/stream/memor
12
12
  import "./src/adapters/defaults/index.mjs";
13
13
  import { getProjectIdentifier, getProjectName, getUserIdentifier, isAnalyticsEnabled, trackEvent } from "./src/analytics/utils.mjs";
14
14
  import { config } from "./src/config.mjs";
15
+ import { invalidate } from "./src/ts-compiler.mjs";
15
16
  import { isApiStep, isCronStep, isEventStep, isNoopStep } from "./src/guards.mjs";
16
17
  import { setupCronHandlers } from "./src/cron-handler.mjs";
17
18
  import { getStepConfig, getStreamConfig } from "./src/get-step-config.mjs";
@@ -27,4 +28,4 @@ import { createStepHandlers } from "./src/step-handlers.mjs";
27
28
  import { createServer } from "./src/server.mjs";
28
29
  import { createStateAdapter } from "./src/state/create-state-adapter.mjs";
29
30
 
30
- export { InMemoryCronAdapter as DefaultCronAdapter, InMemoryQueueEventAdapter as DefaultQueueEventAdapter, FileStateAdapter, FileStreamAdapter, FileStreamAdapterManager, JsonSchemaError, LockedData, Logger, MemoryStateAdapter, MemoryStreamAdapter, MemoryStreamAdapterManager, NoPrinter, NoTracer, PLUGIN_FLOW_ID, Printer, QueueManager, StreamAdapter, config, createMermaidGenerator, createServer, createStateAdapter, createStepHandlers, getProjectIdentifier, getProjectName, getStepConfig, getStreamConfig, getUserIdentifier, isAnalyticsEnabled, isAnyOf, isApiStep, isCronStep, isEventStep, isNoopStep, setupCronHandlers, trackEvent, validateInfrastructureConfig };
31
+ export { InMemoryCronAdapter as DefaultCronAdapter, InMemoryQueueEventAdapter as DefaultQueueEventAdapter, FileStateAdapter, FileStreamAdapter, FileStreamAdapterManager, JsonSchemaError, LockedData, Logger, MemoryStateAdapter, MemoryStreamAdapter, MemoryStreamAdapterManager, NoPrinter, NoTracer, PLUGIN_FLOW_ID, Printer, QueueManager, StreamAdapter, config, createMermaidGenerator, createServer, createStateAdapter, createStepHandlers, getProjectIdentifier, getProjectName, getStepConfig, getStreamConfig, getUserIdentifier, invalidate, isAnalyticsEnabled, isAnyOf, isApiStep, isCronStep, isEventStep, isNoopStep, setupCronHandlers, trackEvent, validateInfrastructureConfig };
@@ -1,213 +1,233 @@
1
1
  import { trackEvent } from "./analytics/utils.mjs";
2
2
  import { getLanguageBasedRunner } from "./language-runner.mjs";
3
3
  import { ProcessManager } from "./process-communication/process-manager.mjs";
4
+ import { compile } from "./ts-compiler.mjs";
4
5
  import { isAllowedToEmit } from "./utils.mjs";
5
6
 
6
7
  //#region src/call-step-file.ts
7
8
  const callStepFile = (options, motia) => {
8
9
  const { step, traceId, data, tracer, logger, contextInFirstArg = false, infrastructure } = options;
9
10
  const flows = step.config.flows;
10
- return new Promise((resolve, reject) => {
11
- const streamConfig = motia.lockedData.getStreams();
12
- const streams = Object.keys(streamConfig).map((name) => ({ name }));
13
- const jsonData = JSON.stringify({
14
- data,
15
- flows,
16
- traceId,
17
- contextInFirstArg,
18
- streams
19
- });
20
- const { runner, command, args } = getLanguageBasedRunner(step.filePath);
21
- let result;
22
- let timeoutId;
23
- const processManager = new ProcessManager({
24
- command,
25
- args: [
26
- ...args,
27
- runner,
28
- step.filePath,
29
- jsonData
30
- ],
31
- logger,
32
- context: "StepExecution",
33
- projectRoot: motia.lockedData.baseDir
34
- });
35
- trackEvent("step_execution_started", {
36
- stepName: step.config.name,
37
- language: command,
38
- type: step.config.type,
39
- streams: streams.length
40
- });
41
- const timeoutSeconds = infrastructure?.handler?.timeout;
42
- if (timeoutSeconds) timeoutId = setTimeout(async () => {
43
- processManager.kill();
44
- const errorMessage = `Step execution timed out after ${timeoutSeconds} seconds`;
45
- logger.error(errorMessage, {
46
- step: step.config.name,
47
- timeout: timeoutSeconds
48
- });
49
- await tracer.end({ message: errorMessage });
50
- trackEvent("step_execution_timeout", {
51
- stepName: step.config.name,
11
+ return (async () => {
12
+ try {
13
+ const streamConfig = motia.lockedData.getStreams();
14
+ const streams = Object.keys(streamConfig).map((name) => ({ name }));
15
+ const jsonData = JSON.stringify({
16
+ data,
17
+ flows,
52
18
  traceId,
53
- timeout: timeoutSeconds
54
- });
55
- reject(new Error(errorMessage));
56
- }, timeoutSeconds * 1e3);
57
- processManager.spawn().then(() => {
58
- processManager.handler("close", async (err) => {
59
- if (err) {
60
- if (timeoutId) clearTimeout(timeoutId);
61
- processManager.close();
62
- trackEvent("step_execution_error", {
63
- stepName: step.config.name,
64
- traceId,
65
- message: err.message
66
- });
67
- await tracer.end({
68
- message: err.message,
69
- code: err.code,
70
- stack: err.stack?.replace(/* @__PURE__ */ new RegExp(`${motia.lockedData.baseDir}/`), "")
71
- });
72
- reject(err ?? /* @__PURE__ */ new Error("Handler execution failed"));
73
- } else await tracer.end();
74
- processManager.kill();
75
- });
76
- processManager.handler("log", async (input) => logger.log(input));
77
- processManager.handler("state.get", async (input) => {
78
- await tracer.stateOperation("get", input);
79
- return motia.state.get(input.traceId, input.key);
80
- });
81
- processManager.handler("state.set", async (input) => {
82
- await tracer.stateOperation("set", {
83
- traceId: input.traceId,
84
- key: input.key,
85
- value: input.value
86
- });
87
- return motia.state.set(input.traceId, input.key, input.value);
88
- });
89
- processManager.handler("state.delete", async (input) => {
90
- await tracer.stateOperation("delete", input);
91
- return motia.state.delete(input.traceId, input.key);
92
- });
93
- processManager.handler("state.clear", async (input) => {
94
- await tracer.stateOperation("clear", input);
95
- return motia.state.clear(input.traceId);
96
- });
97
- processManager.handler(`state.getGroup`, async (input) => {
98
- await tracer.stateOperation("getGroup", input);
99
- return motia.state.getGroup(input.groupId);
100
- });
101
- processManager.handler("result", async (input) => {
102
- const anyInput = { ...input };
103
- if (anyInput.body && anyInput.body.type === "Buffer") anyInput.body = Buffer.from(anyInput.body.data);
104
- result = anyInput;
105
- });
106
- processManager.handler("emit", async (input) => {
107
- const flows$1 = step.config.flows;
108
- if (!isAllowedToEmit(step, input.topic)) {
109
- await tracer.emitOperation(input.topic, input.data, false);
110
- return motia.printer.printInvalidEmit(step, input.topic);
111
- }
112
- await tracer.emitOperation(input.topic, input.data, true);
113
- return motia.eventAdapter.emit({
114
- ...input,
115
- traceId,
116
- flows: flows$1,
19
+ contextInFirstArg,
20
+ streams
21
+ });
22
+ const filePathToExecute = step.filePath.endsWith(".ts") ? await compile(step.filePath, motia.lockedData.baseDir) : step.filePath;
23
+ const { runner, command, args } = getLanguageBasedRunner(step.filePath);
24
+ let result;
25
+ let timeoutId;
26
+ return new Promise((resolve, reject) => {
27
+ const processManager = new ProcessManager({
28
+ command,
29
+ args: [
30
+ ...args,
31
+ runner,
32
+ filePathToExecute,
33
+ jsonData
34
+ ],
117
35
  logger,
118
- tracer
36
+ context: "StepExecution",
37
+ projectRoot: motia.lockedData.baseDir
119
38
  });
120
- });
121
- Object.entries(streamConfig).forEach(([name, streamFactory]) => {
122
- const stateStream = streamFactory();
123
- processManager.handler(`streams.${name}.get`, async (input) => {
124
- await tracer.streamOperation(name, "get", input);
125
- return stateStream.get(input.groupId, input.id);
39
+ trackEvent("step_execution_started", {
40
+ stepName: step.config.name,
41
+ language: command,
42
+ type: step.config.type,
43
+ streams: streams.length
126
44
  });
127
- processManager.handler(`streams.${name}.set`, async (input) => {
128
- await tracer.streamOperation(name, "set", {
129
- groupId: input.groupId,
130
- id: input.id,
131
- data: input.data
45
+ const timeoutSeconds = infrastructure?.handler?.timeout;
46
+ if (timeoutSeconds) timeoutId = setTimeout(async () => {
47
+ processManager.kill();
48
+ const errorMessage = `Step execution timed out after ${timeoutSeconds} seconds`;
49
+ logger.error(errorMessage, {
50
+ step: step.config.name,
51
+ timeout: timeoutSeconds
132
52
  });
133
- return stateStream.set(input.groupId, input.id, input.data);
134
- });
135
- processManager.handler(`streams.${name}.delete`, async (input) => {
136
- await tracer.streamOperation(name, "delete", input);
137
- return stateStream.delete(input.groupId, input.id);
138
- });
139
- processManager.handler(`streams.${name}.getGroup`, async (input) => {
140
- await tracer.streamOperation(name, "getGroup", input);
141
- return stateStream.getGroup(input.groupId);
142
- });
143
- processManager.handler(`streams.${name}.send`, async (input) => {
144
- await tracer.streamOperation(name, "send", input);
145
- return stateStream.send(input.channel, input.event);
146
- });
147
- });
148
- processManager.onStdout((data$1) => {
149
- try {
150
- const message = JSON.parse(data$1.toString());
151
- logger.log(message);
152
- } catch {
153
- logger.info(Buffer.from(data$1).toString());
154
- }
155
- });
156
- processManager.onStderr((data$1) => logger.error(Buffer.from(data$1).toString()));
157
- processManager.onProcessClose(async (code) => {
158
- if (timeoutId) clearTimeout(timeoutId);
159
- processManager.close();
160
- if (code !== 0 && code !== null) {
161
- const error = {
162
- message: `Process exited with code ${code}`,
163
- code
164
- };
165
- await tracer.end(error);
166
- trackEvent("step_execution_error", {
53
+ await tracer.end({ message: errorMessage });
54
+ trackEvent("step_execution_timeout", {
167
55
  stepName: step.config.name,
168
56
  traceId,
169
- code
57
+ timeout: timeoutSeconds
58
+ });
59
+ reject(new Error(errorMessage));
60
+ }, timeoutSeconds * 1e3);
61
+ processManager.spawn().then(() => {
62
+ processManager.handler("close", async (err) => {
63
+ if (err) {
64
+ if (timeoutId) clearTimeout(timeoutId);
65
+ processManager.close();
66
+ trackEvent("step_execution_error", {
67
+ stepName: step.config.name,
68
+ traceId,
69
+ message: err.message
70
+ });
71
+ await tracer.end({
72
+ message: err.message,
73
+ code: err.code,
74
+ stack: err.stack?.replace(/* @__PURE__ */ new RegExp(`${motia.lockedData.baseDir}/`), "")
75
+ });
76
+ reject(err ?? /* @__PURE__ */ new Error("Handler execution failed"));
77
+ } else await tracer.end();
78
+ processManager.kill();
79
+ });
80
+ processManager.handler("log", async (input) => logger.log(input));
81
+ processManager.handler("state.get", async (input) => {
82
+ await tracer.stateOperation("get", input);
83
+ return motia.state.get(input.traceId, input.key);
84
+ });
85
+ processManager.handler("state.set", async (input) => {
86
+ await tracer.stateOperation("set", {
87
+ traceId: input.traceId,
88
+ key: input.key,
89
+ value: input.value
90
+ });
91
+ return motia.state.set(input.traceId, input.key, input.value);
92
+ });
93
+ processManager.handler("state.delete", async (input) => {
94
+ await tracer.stateOperation("delete", input);
95
+ return motia.state.delete(input.traceId, input.key);
96
+ });
97
+ processManager.handler("state.clear", async (input) => {
98
+ await tracer.stateOperation("clear", input);
99
+ return motia.state.clear(input.traceId);
100
+ });
101
+ processManager.handler(`state.getGroup`, async (input) => {
102
+ await tracer.stateOperation("getGroup", input);
103
+ return motia.state.getGroup(input.groupId);
104
+ });
105
+ processManager.handler("result", async (input) => {
106
+ const inputWithBody = input;
107
+ if (inputWithBody.body && inputWithBody.body.type === "Buffer") inputWithBody.body = Buffer.from(inputWithBody.body.data || []);
108
+ result = inputWithBody;
109
+ });
110
+ processManager.handler("emit", async (input) => {
111
+ const flows$1 = step.config.flows;
112
+ if (!isAllowedToEmit(step, input.topic)) {
113
+ await tracer.emitOperation(input.topic, input.data, false);
114
+ return motia.printer.printInvalidEmit(step, input.topic);
115
+ }
116
+ await tracer.emitOperation(input.topic, input.data, true);
117
+ return motia.eventAdapter.emit({
118
+ ...input,
119
+ traceId,
120
+ flows: flows$1,
121
+ logger,
122
+ tracer
123
+ });
124
+ });
125
+ Object.entries(streamConfig).forEach(([name, streamFactory]) => {
126
+ const stateStream = streamFactory();
127
+ processManager.handler(`streams.${name}.get`, async (input) => {
128
+ await tracer.streamOperation(name, "get", input);
129
+ return stateStream.get(input.groupId, input.id);
130
+ });
131
+ processManager.handler(`streams.${name}.set`, async (input) => {
132
+ await tracer.streamOperation(name, "set", {
133
+ groupId: input.groupId,
134
+ id: input.id,
135
+ data: input.data
136
+ });
137
+ return stateStream.set(input.groupId, input.id, input.data);
138
+ });
139
+ processManager.handler(`streams.${name}.delete`, async (input) => {
140
+ await tracer.streamOperation(name, "delete", input);
141
+ return stateStream.delete(input.groupId, input.id);
142
+ });
143
+ processManager.handler(`streams.${name}.getGroup`, async (input) => {
144
+ await tracer.streamOperation(name, "getGroup", input);
145
+ return stateStream.getGroup(input.groupId);
146
+ });
147
+ processManager.handler(`streams.${name}.send`, async (input) => {
148
+ await tracer.streamOperation(name, "send", input);
149
+ return stateStream.send(input.channel, input.event);
150
+ });
151
+ });
152
+ processManager.onStdout((data$1) => {
153
+ try {
154
+ const message = JSON.parse(data$1.toString());
155
+ logger.log(message);
156
+ } catch {
157
+ logger.info(Buffer.from(data$1).toString());
158
+ }
159
+ });
160
+ processManager.onStderr((data$1) => logger.error(Buffer.from(data$1).toString()));
161
+ processManager.onProcessClose(async (code) => {
162
+ if (timeoutId) clearTimeout(timeoutId);
163
+ processManager.close();
164
+ if (code !== 0 && code !== null) {
165
+ const error = {
166
+ message: `Process exited with code ${code}`,
167
+ code
168
+ };
169
+ await tracer.end(error);
170
+ trackEvent("step_execution_error", {
171
+ stepName: step.config.name,
172
+ traceId,
173
+ code
174
+ });
175
+ reject(`Process exited with code ${code}`);
176
+ } else {
177
+ await tracer.end();
178
+ resolve(result);
179
+ }
180
+ });
181
+ processManager.onProcessError(async (error) => {
182
+ if (timeoutId) clearTimeout(timeoutId);
183
+ processManager.close();
184
+ await tracer.end({
185
+ message: error.message,
186
+ code: error.code,
187
+ stack: error.stack
188
+ });
189
+ if (error.code === "ENOENT") {
190
+ trackEvent("step_execution_error", {
191
+ stepName: step.config.name,
192
+ traceId,
193
+ code: error.code,
194
+ message: error.message
195
+ });
196
+ reject(`Executable ${command} not found`);
197
+ } else reject(error);
198
+ });
199
+ }).catch(async (error) => {
200
+ if (timeoutId) clearTimeout(timeoutId);
201
+ await tracer.end({
202
+ message: error.message,
203
+ code: error.code,
204
+ stack: error.stack
170
205
  });
171
- reject(`Process exited with code ${code}`);
172
- } else {
173
- await tracer.end();
174
- resolve(result);
175
- }
176
- });
177
- processManager.onProcessError(async (error) => {
178
- if (timeoutId) clearTimeout(timeoutId);
179
- processManager.close();
180
- await tracer.end({
181
- message: error.message,
182
- code: error.code,
183
- stack: error.stack
184
- });
185
- if (error.code === "ENOENT") {
186
206
  trackEvent("step_execution_error", {
187
207
  stepName: step.config.name,
188
208
  traceId,
189
209
  code: error.code,
190
210
  message: error.message
191
211
  });
192
- reject(`Executable ${command} not found`);
193
- } else reject(error);
212
+ reject(`Failed to spawn process: ${error}`);
213
+ });
194
214
  });
195
- }).catch(async (error) => {
196
- if (timeoutId) clearTimeout(timeoutId);
215
+ } catch (error) {
216
+ const err = error;
197
217
  await tracer.end({
198
- message: error.message,
199
- code: error.code,
200
- stack: error.stack
218
+ message: err.message,
219
+ code: err.code,
220
+ stack: err.stack
201
221
  });
202
222
  trackEvent("step_execution_error", {
203
223
  stepName: step.config.name,
204
224
  traceId,
205
- code: error.code,
206
- message: error.message
225
+ code: err.code,
226
+ message: err.message
207
227
  });
208
- reject(`Failed to spawn process: ${error}`);
209
- });
210
- });
228
+ throw err;
229
+ }
230
+ })();
211
231
  };
212
232
 
213
233
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"call-step-file.mjs","names":["result: TData | undefined","timeoutId: NodeJS.Timeout | undefined","anyInput: any","flows","data"],"sources":["../../src/call-step-file.ts"],"sourcesContent":["import { trackEvent } from './analytics/utils'\nimport { getLanguageBasedRunner } from './language-runner'\nimport type { Logger } from './logger'\nimport type { Motia } from './motia'\nimport type { Tracer } from './observability'\nimport type { TraceError } from './observability/types'\nimport { ProcessManager } from './process-communication/process-manager'\nimport type { Event, InfrastructureConfig, Step } from './types'\nimport type { BaseStreamItem, StateStreamEvent, StateStreamEventChannel } from './types-stream'\nimport { isAllowedToEmit } from './utils'\n\ntype StateGetInput = { traceId: string; key: string }\ntype StateSetInput = { traceId: string; key: string; value: unknown }\ntype StateDeleteInput = { traceId: string; key: string }\ntype StateClearInput = { traceId: string }\n\ntype StateStreamGetInput = { groupId: string; id: string }\ntype StateStreamSendInput = { channel: StateStreamEventChannel; event: StateStreamEvent<unknown> }\ntype StateStreamMutateInput = { groupId: string; id: string; data: BaseStreamItem }\n\ntype CallStepFileOptions = {\n step: Step\n traceId: string\n data?: unknown\n contextInFirstArg?: boolean\n logger: Logger\n tracer: Tracer\n infrastructure?: Partial<InfrastructureConfig>\n}\n\nexport const callStepFile = <TData>(options: CallStepFileOptions, motia: Motia): Promise<TData | undefined> => {\n const { step, traceId, data, tracer, logger, contextInFirstArg = false, infrastructure } = options\n\n const flows = step.config.flows\n\n return new Promise((resolve, reject) => {\n const streamConfig = motia.lockedData.getStreams()\n const streams = Object.keys(streamConfig).map((name) => ({ name }))\n const jsonData = JSON.stringify({ data, flows, traceId, contextInFirstArg, streams })\n const { runner, command, args } = getLanguageBasedRunner(step.filePath)\n let result: TData | undefined\n let timeoutId: NodeJS.Timeout | undefined\n\n const processManager = new ProcessManager({\n command,\n args: [...args, runner, step.filePath, jsonData],\n logger,\n context: 'StepExecution',\n projectRoot: motia.lockedData.baseDir,\n })\n\n trackEvent('step_execution_started', {\n stepName: step.config.name,\n language: command,\n type: step.config.type,\n streams: streams.length,\n })\n\n const timeoutSeconds = infrastructure?.handler?.timeout\n if (timeoutSeconds) {\n timeoutId = setTimeout(async () => {\n processManager.kill()\n const errorMessage = `Step execution timed out after ${timeoutSeconds} seconds`\n logger.error(errorMessage, { step: step.config.name, timeout: timeoutSeconds })\n await tracer.end({ message: errorMessage })\n trackEvent('step_execution_timeout', {\n stepName: step.config.name,\n traceId,\n timeout: timeoutSeconds,\n })\n reject(new Error(errorMessage))\n }, timeoutSeconds * 1000)\n }\n\n processManager\n .spawn()\n .then(() => {\n processManager.handler<TraceError | undefined>('close', async (err) => {\n if (err) {\n if (timeoutId) clearTimeout(timeoutId)\n processManager.close()\n\n trackEvent('step_execution_error', {\n stepName: step.config.name,\n traceId,\n message: err.message,\n })\n\n await tracer.end({\n message: err.message,\n code: err.code,\n stack: err.stack?.replace(new RegExp(`${motia.lockedData.baseDir}/`), ''),\n })\n\n const error = err ?? new Error('Handler execution failed')\n\n reject(error)\n } else {\n await tracer.end()\n }\n\n processManager.kill()\n })\n processManager.handler<unknown>('log', async (input: unknown) => logger.log(input))\n\n processManager.handler<StateGetInput, unknown>('state.get', async (input) => {\n await tracer.stateOperation('get', input)\n return motia.state.get(input.traceId, input.key)\n })\n\n processManager.handler<StateSetInput, unknown>('state.set', async (input) => {\n await tracer.stateOperation('set', { traceId: input.traceId, key: input.key, value: input.value })\n return motia.state.set(input.traceId, input.key, input.value)\n })\n\n processManager.handler<StateDeleteInput, unknown>('state.delete', async (input) => {\n await tracer.stateOperation('delete', input)\n return motia.state.delete(input.traceId, input.key)\n })\n\n processManager.handler<StateClearInput, void>('state.clear', async (input) => {\n await tracer.stateOperation('clear', input)\n return motia.state.clear(input.traceId)\n })\n\n processManager.handler<StateStreamGetInput>(`state.getGroup`, async (input) => {\n await tracer.stateOperation('getGroup', input)\n return motia.state.getGroup(input.groupId)\n })\n\n processManager.handler<TData, void>('result', async (input) => {\n const anyInput: any = { ...input }\n\n if (anyInput.body && anyInput.body.type === 'Buffer') {\n anyInput.body = Buffer.from(anyInput.body.data)\n }\n result = anyInput\n })\n\n processManager.handler<Event, unknown>('emit', async (input) => {\n const flows = step.config.flows\n\n if (!isAllowedToEmit(step, input.topic)) {\n await tracer.emitOperation(input.topic, input.data, false)\n return motia.printer.printInvalidEmit(step, input.topic)\n }\n\n await tracer.emitOperation(input.topic, input.data, true)\n return motia.eventAdapter.emit({ ...input, traceId, flows, logger, tracer })\n })\n\n Object.entries(streamConfig).forEach(([name, streamFactory]) => {\n const stateStream = streamFactory()\n\n processManager.handler<StateStreamGetInput>(`streams.${name}.get`, async (input) => {\n await tracer.streamOperation(name, 'get', input)\n return stateStream.get(input.groupId, input.id)\n })\n\n processManager.handler<StateStreamMutateInput>(`streams.${name}.set`, async (input) => {\n await tracer.streamOperation(name, 'set', { groupId: input.groupId, id: input.id, data: input.data })\n return stateStream.set(input.groupId, input.id, input.data)\n })\n\n processManager.handler<StateStreamGetInput>(`streams.${name}.delete`, async (input) => {\n await tracer.streamOperation(name, 'delete', input)\n return stateStream.delete(input.groupId, input.id)\n })\n\n processManager.handler<StateStreamGetInput>(`streams.${name}.getGroup`, async (input) => {\n await tracer.streamOperation(name, 'getGroup', input)\n return stateStream.getGroup(input.groupId)\n })\n\n processManager.handler<StateStreamSendInput>(`streams.${name}.send`, async (input) => {\n await tracer.streamOperation(name, 'send', input)\n return stateStream.send(input.channel, input.event)\n })\n })\n\n processManager.onStdout((data) => {\n try {\n const message = JSON.parse(data.toString())\n logger.log(message)\n } catch {\n logger.info(Buffer.from(data).toString())\n }\n })\n\n processManager.onStderr((data) => logger.error(Buffer.from(data).toString()))\n\n processManager.onProcessClose(async (code) => {\n if (timeoutId) clearTimeout(timeoutId)\n processManager.close()\n\n if (code !== 0 && code !== null) {\n const error = { message: `Process exited with code ${code}`, code }\n await tracer.end(error)\n trackEvent('step_execution_error', { stepName: step.config.name, traceId, code })\n reject(`Process exited with code ${code}`)\n } else {\n await tracer.end()\n resolve(result)\n }\n })\n\n processManager.onProcessError(async (error) => {\n if (timeoutId) clearTimeout(timeoutId)\n processManager.close()\n await tracer.end({\n message: error.message,\n code: error.code,\n stack: error.stack,\n })\n\n if (error.code === 'ENOENT') {\n trackEvent('step_execution_error', {\n stepName: step.config.name,\n traceId,\n code: error.code,\n message: error.message,\n })\n reject(`Executable ${command} not found`)\n } else {\n reject(error)\n }\n })\n })\n .catch(async (error) => {\n if (timeoutId) clearTimeout(timeoutId)\n await tracer.end({\n message: error.message,\n code: error.code,\n stack: error.stack,\n })\n\n trackEvent('step_execution_error', {\n stepName: step.config.name,\n traceId,\n code: error.code,\n message: error.message,\n })\n reject(`Failed to spawn process: ${error}`)\n })\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"call-step-file.mjs","names":["result: TData | undefined","timeoutId: NodeJS.Timeout | undefined","flows","data","error: unknown"],"sources":["../../src/call-step-file.ts"],"sourcesContent":["import { trackEvent } from './analytics/utils'\nimport { getLanguageBasedRunner } from './language-runner'\nimport type { Logger } from './logger'\nimport type { Motia } from './motia'\nimport type { Tracer } from './observability'\nimport type { TraceError } from './observability/types'\nimport { ProcessManager } from './process-communication/process-manager'\nimport { compile } from './ts-compiler'\nimport type { Event, InfrastructureConfig, Step } from './types'\nimport type { BaseStreamItem, StateStreamEvent, StateStreamEventChannel } from './types-stream'\nimport { isAllowedToEmit } from './utils'\n\ntype StateGetInput = { traceId: string; key: string }\ntype StateSetInput = { traceId: string; key: string; value: unknown }\ntype StateDeleteInput = { traceId: string; key: string }\ntype StateClearInput = { traceId: string }\n\ntype StateStreamGetInput = { groupId: string; id: string }\ntype StateStreamSendInput = { channel: StateStreamEventChannel; event: StateStreamEvent<unknown> }\ntype StateStreamMutateInput = { groupId: string; id: string; data: BaseStreamItem }\n\ntype CallStepFileOptions = {\n step: Step\n traceId: string\n data?: unknown\n contextInFirstArg?: boolean\n logger: Logger\n tracer: Tracer\n infrastructure?: Partial<InfrastructureConfig>\n}\n\nexport const callStepFile = <TData>(options: CallStepFileOptions, motia: Motia): Promise<TData | undefined> => {\n const { step, traceId, data, tracer, logger, contextInFirstArg = false, infrastructure } = options\n\n const flows = step.config.flows\n\n return (async () => {\n try {\n const streamConfig = motia.lockedData.getStreams()\n const streams = Object.keys(streamConfig).map((name) => ({ name }))\n const jsonData = JSON.stringify({ data, flows, traceId, contextInFirstArg, streams })\n\n const filePathToExecute = step.filePath.endsWith('.ts')\n ? await compile(step.filePath, motia.lockedData.baseDir)\n : step.filePath\n\n const { runner, command, args } = getLanguageBasedRunner(step.filePath)\n let result: TData | undefined\n let timeoutId: NodeJS.Timeout | undefined\n\n return new Promise<TData | undefined>((resolve, reject) => {\n const processManager = new ProcessManager({\n command,\n args: [...args, runner, filePathToExecute, jsonData],\n logger,\n context: 'StepExecution',\n projectRoot: motia.lockedData.baseDir,\n })\n\n trackEvent('step_execution_started', {\n stepName: step.config.name,\n language: command,\n type: step.config.type,\n streams: streams.length,\n })\n\n const timeoutSeconds = infrastructure?.handler?.timeout\n if (timeoutSeconds) {\n timeoutId = setTimeout(async () => {\n processManager.kill()\n const errorMessage = `Step execution timed out after ${timeoutSeconds} seconds`\n logger.error(errorMessage, { step: step.config.name, timeout: timeoutSeconds })\n await tracer.end({ message: errorMessage })\n trackEvent('step_execution_timeout', {\n stepName: step.config.name,\n traceId,\n timeout: timeoutSeconds,\n })\n reject(new Error(errorMessage))\n }, timeoutSeconds * 1000)\n }\n\n processManager\n .spawn()\n .then(() => {\n processManager.handler<TraceError | undefined>('close', async (err) => {\n if (err) {\n if (timeoutId) clearTimeout(timeoutId)\n processManager.close()\n\n trackEvent('step_execution_error', {\n stepName: step.config.name,\n traceId,\n message: err.message,\n })\n\n await tracer.end({\n message: err.message,\n code: err.code,\n stack: err.stack?.replace(new RegExp(`${motia.lockedData.baseDir}/`), ''),\n })\n\n const error = err ?? new Error('Handler execution failed')\n\n reject(error)\n } else {\n await tracer.end()\n }\n\n processManager.kill()\n })\n processManager.handler<unknown>('log', async (input: unknown) => logger.log(input))\n\n processManager.handler<StateGetInput, unknown>('state.get', async (input) => {\n await tracer.stateOperation('get', input)\n return motia.state.get(input.traceId, input.key)\n })\n\n processManager.handler<StateSetInput, unknown>('state.set', async (input) => {\n await tracer.stateOperation('set', { traceId: input.traceId, key: input.key, value: input.value })\n return motia.state.set(input.traceId, input.key, input.value)\n })\n\n processManager.handler<StateDeleteInput, unknown>('state.delete', async (input) => {\n await tracer.stateOperation('delete', input)\n return motia.state.delete(input.traceId, input.key)\n })\n\n processManager.handler<StateClearInput, void>('state.clear', async (input) => {\n await tracer.stateOperation('clear', input)\n return motia.state.clear(input.traceId)\n })\n\n processManager.handler<StateStreamGetInput>(`state.getGroup`, async (input) => {\n await tracer.stateOperation('getGroup', input)\n return motia.state.getGroup(input.groupId)\n })\n\n processManager.handler<TData, void>('result', async (input) => {\n const inputWithBody = input as TData & { body?: { type?: string; data?: number[] } }\n\n if (inputWithBody.body && inputWithBody.body.type === 'Buffer') {\n inputWithBody.body = Buffer.from(inputWithBody.body.data || []) as unknown as typeof inputWithBody.body\n }\n result = inputWithBody as TData\n })\n\n processManager.handler<Event, unknown>('emit', async (input) => {\n const flows = step.config.flows\n\n if (!isAllowedToEmit(step, input.topic)) {\n await tracer.emitOperation(input.topic, input.data, false)\n return motia.printer.printInvalidEmit(step, input.topic)\n }\n\n await tracer.emitOperation(input.topic, input.data, true)\n return motia.eventAdapter.emit({ ...input, traceId, flows, logger, tracer })\n })\n\n Object.entries(streamConfig).forEach(([name, streamFactory]) => {\n const stateStream = streamFactory()\n\n processManager.handler<StateStreamGetInput>(`streams.${name}.get`, async (input) => {\n await tracer.streamOperation(name, 'get', input)\n return stateStream.get(input.groupId, input.id)\n })\n\n processManager.handler<StateStreamMutateInput>(`streams.${name}.set`, async (input) => {\n await tracer.streamOperation(name, 'set', { groupId: input.groupId, id: input.id, data: input.data })\n return stateStream.set(input.groupId, input.id, input.data)\n })\n\n processManager.handler<StateStreamGetInput>(`streams.${name}.delete`, async (input) => {\n await tracer.streamOperation(name, 'delete', input)\n return stateStream.delete(input.groupId, input.id)\n })\n\n processManager.handler<StateStreamGetInput>(`streams.${name}.getGroup`, async (input) => {\n await tracer.streamOperation(name, 'getGroup', input)\n return stateStream.getGroup(input.groupId)\n })\n\n processManager.handler<StateStreamSendInput>(`streams.${name}.send`, async (input) => {\n await tracer.streamOperation(name, 'send', input)\n return stateStream.send(input.channel, input.event)\n })\n })\n\n processManager.onStdout((data) => {\n try {\n const message = JSON.parse(data.toString())\n logger.log(message)\n } catch {\n logger.info(Buffer.from(data).toString())\n }\n })\n\n processManager.onStderr((data) => logger.error(Buffer.from(data).toString()))\n\n processManager.onProcessClose(async (code) => {\n if (timeoutId) clearTimeout(timeoutId)\n processManager.close()\n\n if (code !== 0 && code !== null) {\n const error = { message: `Process exited with code ${code}`, code }\n await tracer.end(error)\n trackEvent('step_execution_error', { stepName: step.config.name, traceId, code })\n reject(`Process exited with code ${code}`)\n } else {\n await tracer.end()\n resolve(result)\n }\n })\n\n processManager.onProcessError(async (error) => {\n if (timeoutId) clearTimeout(timeoutId)\n processManager.close()\n await tracer.end({\n message: error.message,\n code: error.code,\n stack: error.stack,\n })\n\n if (error.code === 'ENOENT') {\n trackEvent('step_execution_error', {\n stepName: step.config.name,\n traceId,\n code: error.code,\n message: error.message,\n })\n reject(`Executable ${command} not found`)\n } else {\n reject(error)\n }\n })\n })\n .catch(async (error) => {\n if (timeoutId) clearTimeout(timeoutId)\n await tracer.end({\n message: error.message,\n code: error.code,\n stack: error.stack,\n })\n\n trackEvent('step_execution_error', {\n stepName: step.config.name,\n traceId,\n code: error.code,\n message: error.message,\n })\n reject(`Failed to spawn process: ${error}`)\n })\n })\n } catch (error: unknown) {\n const err = error as Error & { code?: string }\n await tracer.end({\n message: err.message,\n code: err.code,\n stack: err.stack,\n })\n trackEvent('step_execution_error', {\n stepName: step.config.name,\n traceId,\n code: err.code,\n message: err.message,\n })\n throw err\n }\n })()\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { StreamConfig } from "./types-stream.mjs";
2
2
  import { StepConfig } from "./types.mjs";
3
+ import { invalidate } from "./ts-compiler.mjs";
3
4
 
4
5
  //#region src/get-step-config.d.ts
5
6
  declare const getStepConfig: (file: string, projectRoot?: string) => Promise<StepConfig | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"get-step-config.d.mts","names":[],"sources":["../../src/get-step-config.ts"],"sourcesContent":[],"mappings":";;;;cA+Da,uDAAsD,QAAQ;cAI9D,yDAAwD,QAAQ"}
1
+ {"version":3,"file":"get-step-config.d.mts","names":[],"sources":["../../src/get-step-config.ts"],"sourcesContent":[],"mappings":";;;;;cAkEa,uDAAsD,QAAQ;cAI9D,yDAAwD,QAAQ"}
@@ -1,9 +1,11 @@
1
1
  import { globalLogger } from "./logger.mjs";
2
2
  import { getLanguageBasedRunner } from "./language-runner.mjs";
3
3
  import { ProcessManager } from "./process-communication/process-manager.mjs";
4
+ import { compile, invalidate } from "./ts-compiler.mjs";
4
5
 
5
6
  //#region src/get-step-config.ts
6
- const getConfig = (file, projectRoot) => {
7
+ const getConfig = async (file, projectRoot) => {
8
+ const filePathToExecute = file.endsWith(".ts") ? await compile(file, projectRoot || process.cwd()) : file;
7
9
  const { runner, command, args } = getLanguageBasedRunner(file, {
8
10
  python: "get-config.py",
9
11
  ruby: "get-config.rb",
@@ -12,19 +14,19 @@ const getConfig = (file, projectRoot) => {
12
14
  ts: "get-config.ts"
13
15
  }
14
16
  });
17
+ const processManager = new ProcessManager({
18
+ command,
19
+ args: [
20
+ ...args,
21
+ runner,
22
+ filePathToExecute
23
+ ],
24
+ logger: globalLogger,
25
+ context: "Config",
26
+ projectRoot
27
+ });
15
28
  return new Promise((resolve, reject) => {
16
29
  let config = null;
17
- const processManager = new ProcessManager({
18
- command,
19
- args: [
20
- ...args,
21
- runner,
22
- file
23
- ],
24
- logger: globalLogger,
25
- context: "Config",
26
- projectRoot
27
- });
28
30
  processManager.spawn().then(() => {
29
31
  processManager.onMessage((message) => {
30
32
  config = message;
@@ -1 +1 @@
1
- {"version":3,"file":"get-step-config.mjs","names":["config: T | null"],"sources":["../../src/get-step-config.ts"],"sourcesContent":["import { getLanguageBasedRunner } from './language-runner'\nimport { globalLogger } from './logger'\nimport { ProcessManager } from './process-communication/process-manager'\nimport type { StepConfig } from './types'\nimport type { StreamConfig } from './types-stream'\n\nconst getConfig = <T>(file: string, projectRoot?: string): Promise<T | null> => {\n const { runner, command, args } = getLanguageBasedRunner(file, {\n python: 'get-config.py',\n ruby: 'get-config.rb',\n node: { js: 'get-config.mjs', ts: 'get-config.ts' },\n })\n\n return new Promise((resolve, reject) => {\n let config: T | null = null\n\n const processManager = new ProcessManager({\n command,\n args: [...args, runner, file],\n logger: globalLogger,\n context: 'Config',\n projectRoot,\n })\n\n processManager\n .spawn()\n .then(() => {\n processManager.onMessage<T>((message) => {\n config = message\n globalLogger.debug(`[Config] Read config via ${processManager.commType?.toUpperCase()}`, {\n config,\n communicationType: processManager.commType,\n })\n resolve(config)\n processManager.kill()\n })\n\n processManager.onProcessClose((code) => {\n processManager.close()\n if (config) {\n return\n } else if (code !== 0) {\n reject(`Process exited with code ${code}`)\n } else if (!config) {\n reject(`No config found for file ${file}`)\n }\n })\n\n processManager.onProcessError((error) => {\n processManager.close()\n if (error.code === 'ENOENT') {\n reject(`Executable ${command} not found`)\n } else {\n reject(error)\n }\n })\n })\n .catch((error) => {\n reject(`Failed to spawn process: ${error}`)\n })\n })\n}\n\nexport const getStepConfig = (file: string, projectRoot?: string): Promise<StepConfig | null> => {\n return getConfig<StepConfig>(file, projectRoot)\n}\n\nexport const getStreamConfig = (file: string, projectRoot?: string): Promise<StreamConfig | null> => {\n return getConfig<StreamConfig>(file, projectRoot)\n}\n"],"mappings":";;;;;AAMA,MAAM,aAAgB,MAAc,gBAA4C;CAC9E,MAAM,EAAE,QAAQ,SAAS,SAAS,uBAAuB,MAAM;EAC7D,QAAQ;EACR,MAAM;EACN,MAAM;GAAE,IAAI;GAAkB,IAAI;GAAiB;EACpD,CAAC;AAEF,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,IAAIA,SAAmB;EAEvB,MAAM,iBAAiB,IAAI,eAAe;GACxC;GACA,MAAM;IAAC,GAAG;IAAM;IAAQ;IAAK;GAC7B,QAAQ;GACR,SAAS;GACT;GACD,CAAC;AAEF,iBACG,OAAO,CACP,WAAW;AACV,kBAAe,WAAc,YAAY;AACvC,aAAS;AACT,iBAAa,MAAM,4BAA4B,eAAe,UAAU,aAAa,IAAI;KACvF;KACA,mBAAmB,eAAe;KACnC,CAAC;AACF,YAAQ,OAAO;AACf,mBAAe,MAAM;KACrB;AAEF,kBAAe,gBAAgB,SAAS;AACtC,mBAAe,OAAO;AACtB,QAAI,OACF;aACS,SAAS,EAClB,QAAO,4BAA4B,OAAO;aACjC,CAAC,OACV,QAAO,4BAA4B,OAAO;KAE5C;AAEF,kBAAe,gBAAgB,UAAU;AACvC,mBAAe,OAAO;AACtB,QAAI,MAAM,SAAS,SACjB,QAAO,cAAc,QAAQ,YAAY;QAEzC,QAAO,MAAM;KAEf;IACF,CACD,OAAO,UAAU;AAChB,UAAO,4BAA4B,QAAQ;IAC3C;GACJ;;AAGJ,MAAa,iBAAiB,MAAc,gBAAqD;AAC/F,QAAO,UAAsB,MAAM,YAAY;;AAGjD,MAAa,mBAAmB,MAAc,gBAAuD;AACnG,QAAO,UAAwB,MAAM,YAAY"}
1
+ {"version":3,"file":"get-step-config.mjs","names":["config: T | null"],"sources":["../../src/get-step-config.ts"],"sourcesContent":["import { getLanguageBasedRunner } from './language-runner'\nimport { globalLogger } from './logger'\nimport { ProcessManager } from './process-communication/process-manager'\nimport { compile } from './ts-compiler'\nimport type { StepConfig } from './types'\nimport type { StreamConfig } from './types-stream'\n\nconst getConfig = async <T>(file: string, projectRoot?: string): Promise<T | null> => {\n const filePathToExecute = file.endsWith('.ts') ? await compile(file, projectRoot || process.cwd()) : file\n\n const { runner, command, args } = getLanguageBasedRunner(file, {\n python: 'get-config.py',\n ruby: 'get-config.rb',\n node: { js: 'get-config.mjs', ts: 'get-config.ts' },\n })\n\n const processManager = new ProcessManager({\n command,\n args: [...args, runner, filePathToExecute],\n logger: globalLogger,\n context: 'Config',\n projectRoot,\n })\n\n return new Promise((resolve, reject) => {\n let config: T | null = null\n\n processManager\n .spawn()\n .then(() => {\n processManager.onMessage<T>((message) => {\n config = message\n globalLogger.debug(`[Config] Read config via ${processManager.commType?.toUpperCase()}`, {\n config,\n communicationType: processManager.commType,\n })\n resolve(config)\n processManager.kill()\n })\n\n processManager.onProcessClose((code) => {\n processManager.close()\n if (config) {\n return\n } else if (code !== 0) {\n reject(`Process exited with code ${code}`)\n } else if (!config) {\n reject(`No config found for file ${file}`)\n }\n })\n\n processManager.onProcessError((error) => {\n processManager.close()\n if (error.code === 'ENOENT') {\n reject(`Executable ${command} not found`)\n } else {\n reject(error)\n }\n })\n })\n .catch((error) => {\n reject(`Failed to spawn process: ${error}`)\n })\n })\n}\n\nexport const getStepConfig = (file: string, projectRoot?: string): Promise<StepConfig | null> => {\n return getConfig<StepConfig>(file, projectRoot)\n}\n\nexport const getStreamConfig = (file: string, projectRoot?: string): Promise<StreamConfig | null> => {\n return getConfig<StreamConfig>(file, projectRoot)\n}\n\nexport { invalidate } from './ts-compiler'\n"],"mappings":";;;;;;AAOA,MAAM,YAAY,OAAU,MAAc,gBAA4C;CACpF,MAAM,oBAAoB,KAAK,SAAS,MAAM,GAAG,MAAM,QAAQ,MAAM,eAAe,QAAQ,KAAK,CAAC,GAAG;CAErG,MAAM,EAAE,QAAQ,SAAS,SAAS,uBAAuB,MAAM;EAC7D,QAAQ;EACR,MAAM;EACN,MAAM;GAAE,IAAI;GAAkB,IAAI;GAAiB;EACpD,CAAC;CAEF,MAAM,iBAAiB,IAAI,eAAe;EACxC;EACA,MAAM;GAAC,GAAG;GAAM;GAAQ;GAAkB;EAC1C,QAAQ;EACR,SAAS;EACT;EACD,CAAC;AAEF,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,IAAIA,SAAmB;AAEvB,iBACG,OAAO,CACP,WAAW;AACV,kBAAe,WAAc,YAAY;AACvC,aAAS;AACT,iBAAa,MAAM,4BAA4B,eAAe,UAAU,aAAa,IAAI;KACvF;KACA,mBAAmB,eAAe;KACnC,CAAC;AACF,YAAQ,OAAO;AACf,mBAAe,MAAM;KACrB;AAEF,kBAAe,gBAAgB,SAAS;AACtC,mBAAe,OAAO;AACtB,QAAI,OACF;aACS,SAAS,EAClB,QAAO,4BAA4B,OAAO;aACjC,CAAC,OACV,QAAO,4BAA4B,OAAO;KAE5C;AAEF,kBAAe,gBAAgB,UAAU;AACvC,mBAAe,OAAO;AACtB,QAAI,MAAM,SAAS,SACjB,QAAO,cAAc,QAAQ,YAAY;QAEzC,QAAO,MAAM;KAEf;IACF,CACD,OAAO,UAAU;AAChB,UAAO,4BAA4B,QAAQ;IAC3C;GACJ;;AAGJ,MAAa,iBAAiB,MAAc,gBAAqD;AAC/F,QAAO,UAAsB,MAAM,YAAY;;AAGjD,MAAa,mBAAmB,MAAc,gBAAuD;AACnG,QAAO,UAAwB,MAAM,YAAY"}
@@ -29,6 +29,7 @@ const getLanguageBasedRunner = (stepFilePath = "", overrides) => {
29
29
  };
30
30
  else if (isNode) {
31
31
  const defaultNodeOverrides = overrides?.node;
32
+ const isTypeScript = stepFilePath.endsWith(".ts");
32
33
  if (process.env._MOTIA_TEST_MODE === "true") {
33
34
  const runnerFile = defaultNodeOverrides?.ts ?? "node-runner.ts";
34
35
  return {
@@ -42,6 +43,11 @@ const getLanguageBasedRunner = (stepFilePath = "", overrides) => {
42
43
  };
43
44
  }
44
45
  const jsRunner = path.join(__dirname, "node", defaultNodeOverrides?.js ?? "node-runner.mjs");
46
+ if (isTypeScript) return {
47
+ runner: jsRunner,
48
+ command: "node",
49
+ args: []
50
+ };
45
51
  const tsxPath = getTsxPath();
46
52
  if (tsxPath !== "tsx") return {
47
53
  runner: jsRunner,
@@ -1 +1 @@
1
- {"version":3,"file":"language-runner.mjs","names":[],"sources":["../../src/language-runner.ts"],"sourcesContent":["import { createRequire } from 'module'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\n\nexport type LanguageRunnerConfig = {\n command: string\n runner: string\n args: string[]\n}\n\nexport type LanguageRunnerOverrides = {\n python?: string\n ruby?: string\n node?: {\n js: string\n ts?: string\n }\n}\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\nconst require = createRequire(import.meta.url)\n\nconst getTsxPath = () => {\n try {\n const tsxModule = require.resolve('tsx/package.json')\n return path.join(path.dirname(tsxModule), 'dist', 'cli.mjs')\n } catch {\n return 'tsx'\n }\n}\n\nexport const getLanguageBasedRunner = (\n stepFilePath = '',\n overrides?: LanguageRunnerOverrides,\n): LanguageRunnerConfig => {\n const isPython = stepFilePath.endsWith('.py')\n const isRuby = stepFilePath.endsWith('.rb')\n const isNode = stepFilePath.endsWith('.js') || stepFilePath.endsWith('.ts')\n\n if (isPython) {\n const pythonRunner = path.join(__dirname, 'python', overrides?.python ?? 'python-runner.py')\n return { runner: pythonRunner, command: 'python', args: [] }\n } else if (isRuby) {\n const rubyRunner = path.join(__dirname, 'ruby', overrides?.ruby ?? 'ruby-runner.rb')\n return { runner: rubyRunner, command: 'ruby', args: [] }\n } else if (isNode) {\n const defaultNodeOverrides = overrides?.node\n\n if (process.env._MOTIA_TEST_MODE === 'true') {\n const runnerFile = defaultNodeOverrides?.ts ?? 'node-runner.ts'\n return {\n runner: path.join(__dirname, 'node', runnerFile),\n command: 'node',\n args: ['--loader', 'ts-node/esm', '--no-warnings=ExperimentalWarning'],\n }\n }\n const jsRunner = path.join(__dirname, 'node', defaultNodeOverrides?.js ?? 'node-runner.mjs')\n const tsxPath = getTsxPath()\n // When tsx resolves to a file path, run it through node (tsx CLI is an .mjs file)\n // When tsx falls back to 'tsx' string, use it directly as a command (assumes tsx is in PATH)\n if (tsxPath !== 'tsx') {\n return { runner: jsRunner, command: 'node', args: [tsxPath] }\n }\n return { runner: jsRunner, command: tsxPath, args: [] }\n }\n\n throw Error(`Unsupported file extension ${stepFilePath}`)\n}\n"],"mappings":";;;;;AAmBA,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAC9D,MAAM,UAAU,cAAc,OAAO,KAAK,IAAI;AAE9C,MAAM,mBAAmB;AACvB,KAAI;EACF,MAAM,YAAY,QAAQ,QAAQ,mBAAmB;AACrD,SAAO,KAAK,KAAK,KAAK,QAAQ,UAAU,EAAE,QAAQ,UAAU;SACtD;AACN,SAAO;;;AAIX,MAAa,0BACX,eAAe,IACf,cACyB;CACzB,MAAM,WAAW,aAAa,SAAS,MAAM;CAC7C,MAAM,SAAS,aAAa,SAAS,MAAM;CAC3C,MAAM,SAAS,aAAa,SAAS,MAAM,IAAI,aAAa,SAAS,MAAM;AAE3E,KAAI,SAEF,QAAO;EAAE,QADY,KAAK,KAAK,WAAW,UAAU,WAAW,UAAU,mBAAmB;EAC7D,SAAS;EAAU,MAAM,EAAE;EAAE;UACnD,OAET,QAAO;EAAE,QADU,KAAK,KAAK,WAAW,QAAQ,WAAW,QAAQ,iBAAiB;EACvD,SAAS;EAAQ,MAAM,EAAE;EAAE;UAC/C,QAAQ;EACjB,MAAM,uBAAuB,WAAW;AAExC,MAAI,QAAQ,IAAI,qBAAqB,QAAQ;GAC3C,MAAM,aAAa,sBAAsB,MAAM;AAC/C,UAAO;IACL,QAAQ,KAAK,KAAK,WAAW,QAAQ,WAAW;IAChD,SAAS;IACT,MAAM;KAAC;KAAY;KAAe;KAAoC;IACvE;;EAEH,MAAM,WAAW,KAAK,KAAK,WAAW,QAAQ,sBAAsB,MAAM,kBAAkB;EAC5F,MAAM,UAAU,YAAY;AAG5B,MAAI,YAAY,MACd,QAAO;GAAE,QAAQ;GAAU,SAAS;GAAQ,MAAM,CAAC,QAAQ;GAAE;AAE/D,SAAO;GAAE,QAAQ;GAAU,SAAS;GAAS,MAAM,EAAE;GAAE;;AAGzD,OAAM,MAAM,8BAA8B,eAAe"}
1
+ {"version":3,"file":"language-runner.mjs","names":[],"sources":["../../src/language-runner.ts"],"sourcesContent":["import { createRequire } from 'module'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\n\nexport type LanguageRunnerConfig = {\n command: string\n runner: string\n args: string[]\n}\n\nexport type LanguageRunnerOverrides = {\n python?: string\n ruby?: string\n node?: {\n js: string\n ts?: string\n }\n}\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\nconst require = createRequire(import.meta.url)\n\nconst getTsxPath = () => {\n try {\n const tsxModule = require.resolve('tsx/package.json')\n return path.join(path.dirname(tsxModule), 'dist', 'cli.mjs')\n } catch {\n return 'tsx'\n }\n}\n\nexport const getLanguageBasedRunner = (\n stepFilePath = '',\n overrides?: LanguageRunnerOverrides,\n): LanguageRunnerConfig => {\n const isPython = stepFilePath.endsWith('.py')\n const isRuby = stepFilePath.endsWith('.rb')\n const isNode = stepFilePath.endsWith('.js') || stepFilePath.endsWith('.ts')\n\n if (isPython) {\n const pythonRunner = path.join(__dirname, 'python', overrides?.python ?? 'python-runner.py')\n return { runner: pythonRunner, command: 'python', args: [] }\n } else if (isRuby) {\n const rubyRunner = path.join(__dirname, 'ruby', overrides?.ruby ?? 'ruby-runner.rb')\n return { runner: rubyRunner, command: 'ruby', args: [] }\n } else if (isNode) {\n const defaultNodeOverrides = overrides?.node\n const isTypeScript = stepFilePath.endsWith('.ts')\n\n if (process.env._MOTIA_TEST_MODE === 'true') {\n const runnerFile = defaultNodeOverrides?.ts ?? 'node-runner.ts'\n return {\n runner: path.join(__dirname, 'node', runnerFile),\n command: 'node',\n args: ['--loader', 'ts-node/esm', '--no-warnings=ExperimentalWarning'],\n }\n }\n const jsRunner = path.join(__dirname, 'node', defaultNodeOverrides?.js ?? 'node-runner.mjs')\n\n if (isTypeScript) {\n return { runner: jsRunner, command: 'node', args: [] }\n }\n\n const tsxPath = getTsxPath()\n // When tsx resolves to a file path, run it through node (tsx CLI is an .mjs file)\n // When tsx falls back to 'tsx' string, use it directly as a command (assumes tsx is in PATH)\n if (tsxPath !== 'tsx') {\n return { runner: jsRunner, command: 'node', args: [tsxPath] }\n }\n return { runner: jsRunner, command: tsxPath, args: [] }\n }\n\n throw Error(`Unsupported file extension ${stepFilePath}`)\n}\n"],"mappings":";;;;;AAmBA,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAC9D,MAAM,UAAU,cAAc,OAAO,KAAK,IAAI;AAE9C,MAAM,mBAAmB;AACvB,KAAI;EACF,MAAM,YAAY,QAAQ,QAAQ,mBAAmB;AACrD,SAAO,KAAK,KAAK,KAAK,QAAQ,UAAU,EAAE,QAAQ,UAAU;SACtD;AACN,SAAO;;;AAIX,MAAa,0BACX,eAAe,IACf,cACyB;CACzB,MAAM,WAAW,aAAa,SAAS,MAAM;CAC7C,MAAM,SAAS,aAAa,SAAS,MAAM;CAC3C,MAAM,SAAS,aAAa,SAAS,MAAM,IAAI,aAAa,SAAS,MAAM;AAE3E,KAAI,SAEF,QAAO;EAAE,QADY,KAAK,KAAK,WAAW,UAAU,WAAW,UAAU,mBAAmB;EAC7D,SAAS;EAAU,MAAM,EAAE;EAAE;UACnD,OAET,QAAO;EAAE,QADU,KAAK,KAAK,WAAW,QAAQ,WAAW,QAAQ,iBAAiB;EACvD,SAAS;EAAQ,MAAM,EAAE;EAAE;UAC/C,QAAQ;EACjB,MAAM,uBAAuB,WAAW;EACxC,MAAM,eAAe,aAAa,SAAS,MAAM;AAEjD,MAAI,QAAQ,IAAI,qBAAqB,QAAQ;GAC3C,MAAM,aAAa,sBAAsB,MAAM;AAC/C,UAAO;IACL,QAAQ,KAAK,KAAK,WAAW,QAAQ,WAAW;IAChD,SAAS;IACT,MAAM;KAAC;KAAY;KAAe;KAAoC;IACvE;;EAEH,MAAM,WAAW,KAAK,KAAK,WAAW,QAAQ,sBAAsB,MAAM,kBAAkB;AAE5F,MAAI,aACF,QAAO;GAAE,QAAQ;GAAU,SAAS;GAAQ,MAAM,EAAE;GAAE;EAGxD,MAAM,UAAU,YAAY;AAG5B,MAAI,YAAY,MACd,QAAO;GAAE,QAAQ;GAAU,SAAS;GAAQ,MAAM,CAAC,QAAQ;GAAE;AAE/D,SAAO;GAAE,QAAQ;GAAU,SAAS;GAAS,MAAM,EAAE;GAAE;;AAGzD,OAAM,MAAM,8BAA8B,eAAe"}
@@ -22,7 +22,7 @@ declare class Logger {
22
22
  warn(message: string, args?: unknown): void;
23
23
  log(args: any): void;
24
24
  addListener(listener: LogListener): void;
25
- removeListener(listener: LogListener): void;
25
+ removeListener(listener: LogListener): boolean;
26
26
  }
27
27
  //#endregion
28
28
  export { Logger };
@@ -73,7 +73,11 @@ var Logger = class Logger {
73
73
  }
74
74
  removeListener(listener) {
75
75
  const index = this.listeners.indexOf(listener);
76
- if (index > -1) this.listeners.splice(index, 1);
76
+ if (index !== -1) {
77
+ this.listeners.splice(index, 1);
78
+ return true;
79
+ }
80
+ return false;
77
81
  }
78
82
  };
79
83
  const globalLogger = new Logger();
@@ -1 +1 @@
1
- {"version":3,"file":"logger.mjs","names":["levelMap: Record<string, number>","isVerbose: boolean","meta: Record<string, unknown>","coreListeners: LogListener[]"],"sources":["../../src/logger.ts"],"sourcesContent":["import { prettyPrint } from './pretty-print'\n\nconst LEVELS = {\n NOTSET: 0,\n DEBUG: 10,\n INFO: 20,\n WARNING: 30,\n ERROR: 40,\n CRITICAL: 50,\n} as const\n\nconst levelMap: Record<string, number> = {\n debug: LEVELS.DEBUG,\n info: LEVELS.INFO,\n warn: LEVELS.WARNING,\n warning: LEVELS.WARNING,\n error: LEVELS.ERROR,\n critical: LEVELS.CRITICAL,\n}\n\nconst getLogLevel = (): number => {\n const level = process.env.LOG_LEVEL ?? 'info'\n return levelMap[level] ?? LEVELS.INFO\n}\n\nconst shouldLog = (messageLevel: number): boolean => {\n return messageLevel >= getLogLevel()\n}\n\nexport type LogListener = (level: string, msg: string, args?: unknown) => void\n\nexport class Logger {\n /**\n * Why do we need two level of listeners?\n *\n * Core listeners pass along to children loggers.\n *\n * However, base listeners do not pass along to children loggers.\n * Those are specific to each logger in the hierarchy.\n */\n private readonly listeners: LogListener[] = []\n\n constructor(\n readonly isVerbose: boolean = false,\n private readonly meta: Record<string, unknown> = {},\n private readonly coreListeners: LogListener[] = [],\n ) {}\n\n child(meta: Record<string, unknown>): Logger {\n return new Logger(this.isVerbose, { ...this.meta, ...meta }, this.coreListeners)\n }\n\n private _log(level: string, msg: string, args?: any) {\n const time = Date.now()\n const meta = { ...this.meta, ...(args ?? {}) }\n prettyPrint({ level, time, msg, ...meta }, !this.isVerbose)\n\n this.coreListeners.forEach((listener) => listener(level, msg, meta))\n this.listeners.forEach((listener) => listener(level, msg, meta))\n }\n\n info(message: string, args?: unknown) {\n if (shouldLog(LEVELS.INFO)) {\n this._log('info', message, args)\n }\n }\n\n error(message: string, args?: unknown) {\n if (shouldLog(LEVELS.ERROR)) {\n this._log('error', message, args)\n }\n }\n\n debug(message: string, args?: unknown) {\n if (shouldLog(LEVELS.DEBUG)) {\n this._log('debug', message, args)\n }\n }\n\n warn(message: string, args?: unknown) {\n if (shouldLog(LEVELS.WARNING)) {\n this._log('warn', message, args)\n }\n }\n\n log(args: any) {\n const level = args.level ?? 'info'\n const messageLevel = levelMap[level] ?? LEVELS.INFO\n\n if (!shouldLog(messageLevel)) return\n\n this._log(level, args.msg, args)\n }\n\n addListener(listener: LogListener) {\n this.listeners.push(listener)\n }\n\n removeListener(listener: LogListener) {\n const index = this.listeners.indexOf(listener)\n if (index > -1) {\n this.listeners.splice(index, 1)\n }\n }\n}\n\nexport const globalLogger = new Logger()\n"],"mappings":";;;AAEA,MAAM,SAAS;CACb,QAAQ;CACR,OAAO;CACP,MAAM;CACN,SAAS;CACT,OAAO;CACP,UAAU;CACX;AAED,MAAMA,WAAmC;CACvC,OAAO,OAAO;CACd,MAAM,OAAO;CACb,MAAM,OAAO;CACb,SAAS,OAAO;CAChB,OAAO,OAAO;CACd,UAAU,OAAO;CAClB;AAED,MAAM,oBAA4B;AAEhC,QAAO,SADO,QAAQ,IAAI,aAAa,WACb,OAAO;;AAGnC,MAAM,aAAa,iBAAkC;AACnD,QAAO,gBAAgB,aAAa;;AAKtC,IAAa,SAAb,MAAa,OAAO;CAWlB,YACE,AAASC,YAAqB,OAC9B,AAAiBC,OAAgC,EAAE,EACnD,AAAiBC,gBAA+B,EAAE,EAClD;EAHS;EACQ;EACA;mBALyB,EAAE;;CAQ9C,MAAM,MAAuC;AAC3C,SAAO,IAAI,OAAO,KAAK,WAAW;GAAE,GAAG,KAAK;GAAM,GAAG;GAAM,EAAE,KAAK,cAAc;;CAGlF,AAAQ,KAAK,OAAe,KAAa,MAAY;EACnD,MAAM,OAAO,KAAK,KAAK;EACvB,MAAM,OAAO;GAAE,GAAG,KAAK;GAAM,GAAI,QAAQ,EAAE;GAAG;AAC9C,cAAY;GAAE;GAAO;GAAM;GAAK,GAAG;GAAM,EAAE,CAAC,KAAK,UAAU;AAE3D,OAAK,cAAc,SAAS,aAAa,SAAS,OAAO,KAAK,KAAK,CAAC;AACpE,OAAK,UAAU,SAAS,aAAa,SAAS,OAAO,KAAK,KAAK,CAAC;;CAGlE,KAAK,SAAiB,MAAgB;AACpC,MAAI,UAAU,OAAO,KAAK,CACxB,MAAK,KAAK,QAAQ,SAAS,KAAK;;CAIpC,MAAM,SAAiB,MAAgB;AACrC,MAAI,UAAU,OAAO,MAAM,CACzB,MAAK,KAAK,SAAS,SAAS,KAAK;;CAIrC,MAAM,SAAiB,MAAgB;AACrC,MAAI,UAAU,OAAO,MAAM,CACzB,MAAK,KAAK,SAAS,SAAS,KAAK;;CAIrC,KAAK,SAAiB,MAAgB;AACpC,MAAI,UAAU,OAAO,QAAQ,CAC3B,MAAK,KAAK,QAAQ,SAAS,KAAK;;CAIpC,IAAI,MAAW;EACb,MAAM,QAAQ,KAAK,SAAS;AAG5B,MAAI,CAAC,UAFgB,SAAS,UAAU,OAAO,KAEnB,CAAE;AAE9B,OAAK,KAAK,OAAO,KAAK,KAAK,KAAK;;CAGlC,YAAY,UAAuB;AACjC,OAAK,UAAU,KAAK,SAAS;;CAG/B,eAAe,UAAuB;EACpC,MAAM,QAAQ,KAAK,UAAU,QAAQ,SAAS;AAC9C,MAAI,QAAQ,GACV,MAAK,UAAU,OAAO,OAAO,EAAE;;;AAKrC,MAAa,eAAe,IAAI,QAAQ"}
1
+ {"version":3,"file":"logger.mjs","names":["levelMap: Record<string, number>","isVerbose: boolean","meta: Record<string, unknown>","coreListeners: LogListener[]"],"sources":["../../src/logger.ts"],"sourcesContent":["import { prettyPrint } from './pretty-print'\n\nconst LEVELS = {\n NOTSET: 0,\n DEBUG: 10,\n INFO: 20,\n WARNING: 30,\n ERROR: 40,\n CRITICAL: 50,\n} as const\n\nconst levelMap: Record<string, number> = {\n debug: LEVELS.DEBUG,\n info: LEVELS.INFO,\n warn: LEVELS.WARNING,\n warning: LEVELS.WARNING,\n error: LEVELS.ERROR,\n critical: LEVELS.CRITICAL,\n}\n\nconst getLogLevel = (): number => {\n const level = process.env.LOG_LEVEL ?? 'info'\n return levelMap[level] ?? LEVELS.INFO\n}\n\nconst shouldLog = (messageLevel: number): boolean => {\n return messageLevel >= getLogLevel()\n}\n\nexport type LogListener = (level: string, msg: string, args?: unknown) => void\n\nexport class Logger {\n /**\n * Why do we need two level of listeners?\n *\n * Core listeners pass along to children loggers.\n *\n * However, base listeners do not pass along to children loggers.\n * Those are specific to each logger in the hierarchy.\n */\n private readonly listeners: LogListener[] = []\n\n constructor(\n readonly isVerbose: boolean = false,\n private readonly meta: Record<string, unknown> = {},\n private readonly coreListeners: LogListener[] = [],\n ) {}\n\n child(meta: Record<string, unknown>): Logger {\n return new Logger(this.isVerbose, { ...this.meta, ...meta }, this.coreListeners)\n }\n\n private _log(level: string, msg: string, args?: any) {\n const time = Date.now()\n const meta = { ...this.meta, ...(args ?? {}) }\n prettyPrint({ level, time, msg, ...meta }, !this.isVerbose)\n\n this.coreListeners.forEach((listener) => listener(level, msg, meta))\n this.listeners.forEach((listener) => listener(level, msg, meta))\n }\n\n info(message: string, args?: unknown) {\n if (shouldLog(LEVELS.INFO)) {\n this._log('info', message, args)\n }\n }\n\n error(message: string, args?: unknown) {\n if (shouldLog(LEVELS.ERROR)) {\n this._log('error', message, args)\n }\n }\n\n debug(message: string, args?: unknown) {\n if (shouldLog(LEVELS.DEBUG)) {\n this._log('debug', message, args)\n }\n }\n\n warn(message: string, args?: unknown) {\n if (shouldLog(LEVELS.WARNING)) {\n this._log('warn', message, args)\n }\n }\n\n log(args: any) {\n const level = args.level ?? 'info'\n const messageLevel = levelMap[level] ?? LEVELS.INFO\n\n if (!shouldLog(messageLevel)) return\n\n this._log(level, args.msg, args)\n }\n\n addListener(listener: LogListener) {\n this.listeners.push(listener)\n }\n\n removeListener(listener: LogListener): boolean {\n const index = this.listeners.indexOf(listener)\n if (index !== -1) {\n this.listeners.splice(index, 1)\n return true\n }\n return false\n }\n}\n\nexport const globalLogger = new Logger()\n"],"mappings":";;;AAEA,MAAM,SAAS;CACb,QAAQ;CACR,OAAO;CACP,MAAM;CACN,SAAS;CACT,OAAO;CACP,UAAU;CACX;AAED,MAAMA,WAAmC;CACvC,OAAO,OAAO;CACd,MAAM,OAAO;CACb,MAAM,OAAO;CACb,SAAS,OAAO;CAChB,OAAO,OAAO;CACd,UAAU,OAAO;CAClB;AAED,MAAM,oBAA4B;AAEhC,QAAO,SADO,QAAQ,IAAI,aAAa,WACb,OAAO;;AAGnC,MAAM,aAAa,iBAAkC;AACnD,QAAO,gBAAgB,aAAa;;AAKtC,IAAa,SAAb,MAAa,OAAO;CAWlB,YACE,AAASC,YAAqB,OAC9B,AAAiBC,OAAgC,EAAE,EACnD,AAAiBC,gBAA+B,EAAE,EAClD;EAHS;EACQ;EACA;mBALyB,EAAE;;CAQ9C,MAAM,MAAuC;AAC3C,SAAO,IAAI,OAAO,KAAK,WAAW;GAAE,GAAG,KAAK;GAAM,GAAG;GAAM,EAAE,KAAK,cAAc;;CAGlF,AAAQ,KAAK,OAAe,KAAa,MAAY;EACnD,MAAM,OAAO,KAAK,KAAK;EACvB,MAAM,OAAO;GAAE,GAAG,KAAK;GAAM,GAAI,QAAQ,EAAE;GAAG;AAC9C,cAAY;GAAE;GAAO;GAAM;GAAK,GAAG;GAAM,EAAE,CAAC,KAAK,UAAU;AAE3D,OAAK,cAAc,SAAS,aAAa,SAAS,OAAO,KAAK,KAAK,CAAC;AACpE,OAAK,UAAU,SAAS,aAAa,SAAS,OAAO,KAAK,KAAK,CAAC;;CAGlE,KAAK,SAAiB,MAAgB;AACpC,MAAI,UAAU,OAAO,KAAK,CACxB,MAAK,KAAK,QAAQ,SAAS,KAAK;;CAIpC,MAAM,SAAiB,MAAgB;AACrC,MAAI,UAAU,OAAO,MAAM,CACzB,MAAK,KAAK,SAAS,SAAS,KAAK;;CAIrC,MAAM,SAAiB,MAAgB;AACrC,MAAI,UAAU,OAAO,MAAM,CACzB,MAAK,KAAK,SAAS,SAAS,KAAK;;CAIrC,KAAK,SAAiB,MAAgB;AACpC,MAAI,UAAU,OAAO,QAAQ,CAC3B,MAAK,KAAK,QAAQ,SAAS,KAAK;;CAIpC,IAAI,MAAW;EACb,MAAM,QAAQ,KAAK,SAAS;AAG5B,MAAI,CAAC,UAFgB,SAAS,UAAU,OAAO,KAEnB,CAAE;AAE9B,OAAK,KAAK,OAAO,KAAK,KAAK,KAAK;;CAGlC,YAAY,UAAuB;AACjC,OAAK,UAAU,KAAK,SAAS;;CAG/B,eAAe,UAAgC;EAC7C,MAAM,QAAQ,KAAK,UAAU,QAAQ,SAAS;AAC9C,MAAI,UAAU,IAAI;AAChB,QAAK,UAAU,OAAO,OAAO,EAAE;AAC/B,UAAO;;AAET,SAAO;;;AAIX,MAAa,eAAe,IAAI,QAAQ"}
@@ -15,10 +15,23 @@ function parseArgs(arg$1) {
15
15
  return arg$1;
16
16
  }
17
17
  }
18
+ const importCompiledModule = async (filePath$1) => {
19
+ try {
20
+ return import(pathToFileURL(path.resolve(filePath$1)).href);
21
+ } catch (importError) {
22
+ const err = importError;
23
+ throw {
24
+ message: `Failed to import module ${filePath$1}: ${err.message}`,
25
+ code: err.code || "IMPORT_ERROR",
26
+ stack: err.stack || ""
27
+ };
28
+ }
29
+ };
18
30
  async function runTypescriptModule(filePath$1, event) {
19
31
  const sender = new RpcSender(process);
20
32
  try {
21
- const importedModule = await import(pathToFileURL(path.resolve(filePath$1)).href);
33
+ sender.init();
34
+ const importedModule = await importCompiledModule(filePath$1);
22
35
  const handler = importedModule.handler || importedModule.default?.handler;
23
36
  const config = importedModule.config || importedModule.default?.config || {};
24
37
  if (typeof handler !== "function") throw new Error(`Function handler not found in module ${filePath$1}`);
@@ -56,28 +69,29 @@ async function runTypescriptModule(filePath$1, event) {
56
69
  return acc;
57
70
  }, {})
58
71
  };
59
- sender.init();
60
72
  const composedMiddleware = composeMiddleware(...Array.isArray(config.middleware) ? config.middleware : []);
61
73
  const handlerFn = () => {
62
74
  return contextInFirstArg ? handler(context) : handler(event.data, context);
63
75
  };
64
76
  const result = await composedMiddleware(event.data, context, handlerFn);
65
- await sender.send("result", result);
77
+ if (result !== void 0 && result !== null) await sender.send("result", result);
78
+ sender.sendNoWait("close", void 0);
66
79
  await sender.close();
67
80
  process.exit(0);
68
81
  } catch (err) {
69
- const stack = err.stack?.split("\n") ?? [];
82
+ const error = err;
83
+ const stack = error.stack?.split("\n") ?? [];
70
84
  if (stack) {
71
85
  const index = stack.findIndex((line) => line.includes("src/node/node-runner"));
72
86
  stack.splice(index, stack.length - index);
73
87
  stack.splice(0, 1);
74
88
  }
75
- const error = {
76
- message: err.message || "",
77
- code: err.code || null,
89
+ const errorObj = {
90
+ message: error.message || "",
91
+ code: error.code || null,
78
92
  stack: stack.join("\n")
79
93
  };
80
- sender.sendNoWait("close", error);
94
+ sender.sendNoWait("close", errorObj);
81
95
  }
82
96
  }
83
97
  const [, , filePath, arg] = process.argv;
@@ -1 +1 @@
1
- {"version":3,"file":"node-runner.mjs","names":["arg","filePath","err: any","stack: string[]"],"sources":["../../../src/node/node-runner.ts"],"sourcesContent":["import dotenv from 'dotenv'\nimport path from 'path'\nimport { pathToFileURL } from 'url'\nimport type { StateStreamEvent, StateStreamEventChannel, StreamConfig } from '../types-stream'\nimport { Logger } from './logger'\nimport { composeMiddleware } from './middleware-compose'\nimport { RpcSender } from './rpc'\nimport { RpcStateManager } from './rpc-state-manager'\n\ndotenv.config()\n\nfunction parseArgs(arg: string) {\n try {\n return JSON.parse(arg)\n } catch {\n return arg\n }\n}\n\nasync function runTypescriptModule(filePath: string, event: Record<string, unknown>) {\n const sender = new RpcSender(process)\n\n try {\n const importedModule = await import(pathToFileURL(path.resolve(filePath)).href)\n const handler = importedModule.handler || importedModule.default?.handler\n const config = importedModule.config || importedModule.default?.config || {}\n\n // Check if the specified function exists in the module\n if (typeof handler !== 'function') {\n throw new Error(`Function handler not found in module ${filePath}`)\n }\n\n const { traceId, flows, contextInFirstArg } = event\n\n const logger = new Logger(traceId as string, flows as string[], sender)\n const state = new RpcStateManager(sender)\n\n const emit = async (data: unknown) => sender.send('emit', data)\n const streamsConfig = event.streams as StreamConfig[]\n const streams = (streamsConfig ?? []).reduce(\n (acc, streams) => {\n acc[streams.name] = {\n get: (groupId: string, id: string) => sender.send(`streams.${streams.name}.get`, { groupId, id }),\n set: (groupId: string, id: string, data: unknown) =>\n sender.send(`streams.${streams.name}.set`, { groupId, id, data }),\n delete: (groupId: string, id: string) => sender.send(`streams.${streams.name}.delete`, { groupId, id }),\n getGroup: (groupId: string) => sender.send(`streams.${streams.name}.getGroup`, { groupId }),\n send: (channel: StateStreamEventChannel, event: StateStreamEvent<unknown>) =>\n sender.send(`streams.${streams.name}.send`, { channel, event }),\n }\n return acc\n },\n {} as Record<string, unknown>,\n )\n\n const context = { traceId, flows, logger, state, emit, streams }\n\n sender.init()\n\n const middlewares = Array.isArray(config.middleware) ? config.middleware : []\n\n const composedMiddleware = composeMiddleware(...middlewares)\n const handlerFn = () => {\n return contextInFirstArg ? handler(context) : handler(event.data, context)\n }\n\n const result = await composedMiddleware(event.data, context, handlerFn)\n\n await sender.send('result', result)\n await sender.close()\n\n process.exit(0)\n } catch (err: any) {\n const stack: string[] = err.stack?.split('\\n') ?? []\n\n if (stack) {\n const index = stack.findIndex((line) => line.includes('src/node/node-runner'))\n stack.splice(index, stack.length - index)\n stack.splice(0, 1) // remove first line which has the error message\n }\n\n const error = {\n message: err.message || '',\n code: err.code || null,\n stack: stack.join('\\n'),\n }\n sender.sendNoWait('close', error)\n }\n}\n\nconst [, , filePath, arg] = process.argv\n\nif (!filePath) {\n console.error('Usage: node node-runner.mjs <file-path> <arg>')\n process.exit(1)\n}\n\nrunTypescriptModule(filePath, parseArgs(arg)).catch((err) => {\n console.error('Error:', err)\n process.exit(1)\n})\n"],"mappings":";;;;;;;;;AASA,OAAO,QAAQ;AAEf,SAAS,UAAU,OAAa;AAC9B,KAAI;AACF,SAAO,KAAK,MAAMA,MAAI;SAChB;AACN,SAAOA;;;AAIX,eAAe,oBAAoB,YAAkB,OAAgC;CACnF,MAAM,SAAS,IAAI,UAAU,QAAQ;AAErC,KAAI;EACF,MAAM,iBAAiB,MAAM,OAAO,cAAc,KAAK,QAAQC,WAAS,CAAC,CAAC;EAC1E,MAAM,UAAU,eAAe,WAAW,eAAe,SAAS;EAClE,MAAM,SAAS,eAAe,UAAU,eAAe,SAAS,UAAU,EAAE;AAG5E,MAAI,OAAO,YAAY,WACrB,OAAM,IAAI,MAAM,wCAAwCA,aAAW;EAGrE,MAAM,EAAE,SAAS,OAAO,sBAAsB;EAE9C,MAAM,SAAS,IAAI,OAAO,SAAmB,OAAmB,OAAO;EACvE,MAAM,QAAQ,IAAI,gBAAgB,OAAO;EAEzC,MAAM,OAAO,OAAO,SAAkB,OAAO,KAAK,QAAQ,KAAK;EAkB/D,MAAM,UAAU;GAAE;GAAS;GAAO;GAAQ;GAAO;GAAM,UAjBjC,MAAM,WACM,EAAE,EAAE,QACnC,KAAK,YAAY;AAChB,QAAI,QAAQ,QAAQ;KAClB,MAAM,SAAiB,OAAe,OAAO,KAAK,WAAW,QAAQ,KAAK,OAAO;MAAE;MAAS;MAAI,CAAC;KACjG,MAAM,SAAiB,IAAY,SACjC,OAAO,KAAK,WAAW,QAAQ,KAAK,OAAO;MAAE;MAAS;MAAI;MAAM,CAAC;KACnE,SAAS,SAAiB,OAAe,OAAO,KAAK,WAAW,QAAQ,KAAK,UAAU;MAAE;MAAS;MAAI,CAAC;KACvG,WAAW,YAAoB,OAAO,KAAK,WAAW,QAAQ,KAAK,YAAY,EAAE,SAAS,CAAC;KAC3F,OAAO,SAAkC,YACvC,OAAO,KAAK,WAAW,QAAQ,KAAK,QAAQ;MAAE;MAAS;MAAO,CAAC;KAClE;AACD,WAAO;MAET,EAAE,CACH;GAE+D;AAEhE,SAAO,MAAM;EAIb,MAAM,qBAAqB,kBAAkB,GAFzB,MAAM,QAAQ,OAAO,WAAW,GAAG,OAAO,aAAa,EAAE,CAEjB;EAC5D,MAAM,kBAAkB;AACtB,UAAO,oBAAoB,QAAQ,QAAQ,GAAG,QAAQ,MAAM,MAAM,QAAQ;;EAG5E,MAAM,SAAS,MAAM,mBAAmB,MAAM,MAAM,SAAS,UAAU;AAEvE,QAAM,OAAO,KAAK,UAAU,OAAO;AACnC,QAAM,OAAO,OAAO;AAEpB,UAAQ,KAAK,EAAE;UACRC,KAAU;EACjB,MAAMC,QAAkB,IAAI,OAAO,MAAM,KAAK,IAAI,EAAE;AAEpD,MAAI,OAAO;GACT,MAAM,QAAQ,MAAM,WAAW,SAAS,KAAK,SAAS,uBAAuB,CAAC;AAC9E,SAAM,OAAO,OAAO,MAAM,SAAS,MAAM;AACzC,SAAM,OAAO,GAAG,EAAE;;EAGpB,MAAM,QAAQ;GACZ,SAAS,IAAI,WAAW;GACxB,MAAM,IAAI,QAAQ;GAClB,OAAO,MAAM,KAAK,KAAK;GACxB;AACD,SAAO,WAAW,SAAS,MAAM;;;AAIrC,MAAM,KAAK,UAAU,OAAO,QAAQ;AAEpC,IAAI,CAAC,UAAU;AACb,SAAQ,MAAM,gDAAgD;AAC9D,SAAQ,KAAK,EAAE;;AAGjB,oBAAoB,UAAU,UAAU,IAAI,CAAC,CAAC,OAAO,QAAQ;AAC3D,SAAQ,MAAM,UAAU,IAAI;AAC5B,SAAQ,KAAK,EAAE;EACf"}
1
+ {"version":3,"file":"node-runner.mjs","names":["arg","filePath","importError: unknown","importedModule: FileModule","err: unknown","stack: string[]"],"sources":["../../../src/node/node-runner.ts"],"sourcesContent":["import dotenv from 'dotenv'\nimport path from 'path'\nimport { pathToFileURL } from 'url'\nimport type { StateStreamEvent, StateStreamEventChannel, StreamConfig } from '../types-stream'\nimport { Logger } from './logger'\nimport { composeMiddleware } from './middleware-compose'\nimport { RpcSender } from './rpc'\nimport { RpcStateManager } from './rpc-state-manager'\n\ndotenv.config()\n\ntype FileModule = { handler?: unknown; default?: { handler?: unknown; config?: unknown }; config?: unknown }\n\nfunction parseArgs(arg: string) {\n try {\n return JSON.parse(arg)\n } catch {\n return arg\n }\n}\n\nconst importCompiledModule = async (filePath: string): Promise<FileModule> => {\n try {\n return import(pathToFileURL(path.resolve(filePath)).href)\n } catch (importError: unknown) {\n const err = importError as Error & { code?: string }\n const error = {\n message: `Failed to import module ${filePath}: ${err.message}`,\n code: err.code || 'IMPORT_ERROR',\n stack: err.stack || '',\n }\n\n throw error\n }\n}\nasync function runTypescriptModule(filePath: string, event: Record<string, unknown>) {\n const sender = new RpcSender(process)\n\n try {\n sender.init()\n\n const importedModule: FileModule = await importCompiledModule(filePath)\n\n const handler = importedModule.handler || importedModule.default?.handler\n const config = (importedModule.config || importedModule.default?.config || {}) as { middleware?: unknown[] }\n\n // Check if the specified function exists in the module\n if (typeof handler !== 'function') {\n throw new Error(`Function handler not found in module ${filePath}`)\n }\n\n const { traceId, flows, contextInFirstArg } = event\n\n const logger = new Logger(traceId as string, flows as string[], sender)\n const state = new RpcStateManager(sender)\n\n const emit = async (data: unknown) => sender.send('emit', data)\n const streamsConfig = event.streams as StreamConfig[]\n const streams = (streamsConfig ?? []).reduce(\n (acc, streams) => {\n acc[streams.name] = {\n get: (groupId: string, id: string) => sender.send(`streams.${streams.name}.get`, { groupId, id }),\n set: (groupId: string, id: string, data: unknown) =>\n sender.send(`streams.${streams.name}.set`, { groupId, id, data }),\n delete: (groupId: string, id: string) => sender.send(`streams.${streams.name}.delete`, { groupId, id }),\n getGroup: (groupId: string) => sender.send(`streams.${streams.name}.getGroup`, { groupId }),\n send: (channel: StateStreamEventChannel, event: StateStreamEvent<unknown>) =>\n sender.send(`streams.${streams.name}.send`, { channel, event }),\n }\n return acc\n },\n {} as Record<string, unknown>,\n )\n\n const context = { traceId, flows, logger, state, emit, streams }\n\n const middlewares = Array.isArray(config.middleware) ? config.middleware : []\n\n const composedMiddleware = composeMiddleware(...middlewares)\n const handlerFn = () => {\n return contextInFirstArg ? handler(context) : handler(event.data, context)\n }\n\n const result = await composedMiddleware(event.data, context, handlerFn)\n\n if (result !== undefined && result !== null) {\n await sender.send('result', result)\n }\n\n sender.sendNoWait('close', undefined)\n await sender.close()\n process.exit(0)\n } catch (err: unknown) {\n const error = err as Error & { code?: string }\n const stack: string[] = error.stack?.split('\\n') ?? []\n\n if (stack) {\n const index = stack.findIndex((line) => line.includes('src/node/node-runner'))\n stack.splice(index, stack.length - index)\n stack.splice(0, 1)\n }\n\n const errorObj = {\n message: error.message || '',\n code: error.code || null,\n stack: stack.join('\\n'),\n }\n sender.sendNoWait('close', errorObj)\n }\n}\n\nconst [, , filePath, arg] = process.argv\n\nif (!filePath) {\n console.error('Usage: node node-runner.mjs <file-path> <arg>')\n process.exit(1)\n}\n\nrunTypescriptModule(filePath, parseArgs(arg)).catch((err) => {\n console.error('Error:', err)\n process.exit(1)\n})\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ //#region src/ts-compiler.d.ts
2
+ declare const invalidate: (tsFilePath: string) => void;
3
+ //#endregion
4
+ export { invalidate };
5
+ //# sourceMappingURL=ts-compiler.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ts-compiler.d.mts","names":[],"sources":["../../src/ts-compiler.ts"],"sourcesContent":[],"mappings":";AAiMa,cAAA,UAEZ,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,GAAA,IAAA"}
@@ -0,0 +1,130 @@
1
+ import { existsSync, mkdirSync, statSync, writeFileSync } from "fs";
2
+ import path from "path";
3
+ import * as esbuild from "esbuild";
4
+
5
+ //#region src/ts-compiler.ts
6
+ const COMPILED_DIR = ".motia/compiled";
7
+ const TS_EXTENSIONS = [
8
+ ".ts",
9
+ ".tsx",
10
+ ".stream.ts",
11
+ ".stream"
12
+ ];
13
+ const EXT_TO_JS_MAP = {
14
+ ".stream.ts": ".stream.js",
15
+ ".tsx": ".js",
16
+ ".ts": ".js",
17
+ ".stream": ".stream.js"
18
+ };
19
+ const cache = /* @__PURE__ */ new Map();
20
+ const getCompiledPath = (tsFilePath, projectRoot) => {
21
+ const compiledRelativePath = path.relative(projectRoot, tsFilePath).replace(/\.ts$/, ".js");
22
+ return path.join(projectRoot, COMPILED_DIR, compiledRelativePath);
23
+ };
24
+ const getSourceMtime = (filePath) => {
25
+ try {
26
+ return statSync(filePath).mtimeMs;
27
+ } catch {
28
+ return 0;
29
+ }
30
+ };
31
+ const ensureCompiledDir = (compiledPath) => {
32
+ const dir = path.dirname(compiledPath);
33
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
34
+ };
35
+ const replaceExtensionWithJs = (filePath) => {
36
+ for (const [ext, jsExt] of Object.entries(EXT_TO_JS_MAP)) if (filePath.endsWith(ext)) return filePath.replace(/* @__PURE__ */ new RegExp(`${ext.replace(".", "\\.")}$`), jsExt);
37
+ return filePath;
38
+ };
39
+ const resolveImportPath = (importPath, dir, projectRoot, compiledPath) => {
40
+ const fullImportPath = path.resolve(dir, importPath);
41
+ for (const ext of TS_EXTENSIONS) {
42
+ const testPath = fullImportPath + (ext.startsWith(".") ? ext : `.${ext}`);
43
+ if (existsSync(testPath)) {
44
+ const compiledFileName = replaceExtensionWithJs(path.relative(projectRoot, testPath));
45
+ const compiledImportPath = path.join(COMPILED_DIR, compiledFileName);
46
+ const relativeCompiledPath = path.relative(path.dirname(compiledPath), path.join(projectRoot, compiledImportPath)).replace(/\\/g, "/");
47
+ return {
48
+ sourcePath: testPath,
49
+ compiledImportPath: relativeCompiledPath.startsWith(".") ? relativeCompiledPath : `./${relativeCompiledPath}`
50
+ };
51
+ }
52
+ }
53
+ return null;
54
+ };
55
+ const transformImportPaths = (code, tsFilePath, compiledPath, projectRoot) => {
56
+ const dir = path.dirname(tsFilePath);
57
+ const dependencies = [];
58
+ return {
59
+ code: code.replace(/from\s+['"](\.\/?[^'"]+)['"]/g, (match, importPath) => {
60
+ if (!importPath.startsWith(".")) return match;
61
+ if (importPath.endsWith(".js") || importPath.endsWith(".json")) return match;
62
+ const resolved = resolveImportPath(importPath, dir, projectRoot, compiledPath);
63
+ if (resolved) {
64
+ dependencies.push(resolved.sourcePath);
65
+ return match.replace(importPath, resolved.compiledImportPath);
66
+ }
67
+ if (!importPath.match(/\.(ts|tsx|js|jsx|json|stream)$/)) return match.replace(importPath, `${importPath}.js`);
68
+ return match.replace(importPath, importPath.replace(/\.(ts|tsx|stream\.ts|stream)$/, ".js"));
69
+ }),
70
+ dependencies: dependencies.filter((dep) => dep.endsWith(".ts") || dep.endsWith(".tsx") || dep.endsWith(".stream.ts"))
71
+ };
72
+ };
73
+ const isCacheValid = (tsFilePath) => {
74
+ const cached = cache.get(tsFilePath);
75
+ if (!cached) return false;
76
+ const sourceMtime = getSourceMtime(tsFilePath);
77
+ return cached.sourceMtime === sourceMtime && existsSync(cached.compiledPath);
78
+ };
79
+ const buildWithEsbuild = async (tsFilePath, compiledPath) => {
80
+ const result = await esbuild.build({
81
+ entryPoints: [tsFilePath],
82
+ bundle: false,
83
+ format: "esm",
84
+ target: "node18",
85
+ platform: "node",
86
+ outfile: compiledPath,
87
+ sourcemap: "inline",
88
+ write: false,
89
+ resolveExtensions: [
90
+ ".ts",
91
+ ".tsx",
92
+ ".js",
93
+ ".jsx",
94
+ ".json"
95
+ ],
96
+ packages: "external"
97
+ });
98
+ if (!result.outputFiles || result.outputFiles.length === 0) throw new Error(`Failed to compile ${tsFilePath}`);
99
+ return result.outputFiles[0].text;
100
+ };
101
+ const compileDependencies = async (dependencies, projectRoot) => {
102
+ for (const dep of dependencies) await compile(dep, projectRoot);
103
+ };
104
+ const updateCache = (tsFilePath, compiledPath) => {
105
+ const sourceMtime = getSourceMtime(tsFilePath);
106
+ cache.set(tsFilePath, {
107
+ compiledPath,
108
+ sourceMtime
109
+ });
110
+ };
111
+ const compile = async (tsFilePath, projectRoot) => {
112
+ const compiledPath = getCompiledPath(tsFilePath, projectRoot);
113
+ if (isCacheValid(tsFilePath)) {
114
+ const cached = cache.get(tsFilePath);
115
+ if (cached) return cached.compiledPath;
116
+ }
117
+ ensureCompiledDir(compiledPath);
118
+ const { code, dependencies } = transformImportPaths(await buildWithEsbuild(tsFilePath, compiledPath), tsFilePath, compiledPath, projectRoot);
119
+ await compileDependencies(dependencies, projectRoot);
120
+ writeFileSync(compiledPath, code, "utf-8");
121
+ updateCache(tsFilePath, compiledPath);
122
+ return compiledPath;
123
+ };
124
+ const invalidate = (tsFilePath) => {
125
+ cache.delete(tsFilePath);
126
+ };
127
+
128
+ //#endregion
129
+ export { compile, invalidate };
130
+ //# sourceMappingURL=ts-compiler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ts-compiler.mjs","names":["EXT_TO_JS_MAP: Record<string, string>","dependencies: string[]"],"sources":["../../src/ts-compiler.ts"],"sourcesContent":["import * as esbuild from 'esbuild'\nimport { existsSync, mkdirSync, statSync, writeFileSync } from 'fs'\nimport path from 'path'\n\nconst COMPILED_DIR = '.motia/compiled'\n\nconst TS_EXTENSIONS = ['.ts', '.tsx', '.stream.ts', '.stream']\nconst EXT_TO_JS_MAP: Record<string, string> = {\n '.stream.ts': '.stream.js',\n '.tsx': '.js',\n '.ts': '.js',\n '.stream': '.stream.js',\n}\n\ninterface CompileCache {\n compiledPath: string\n sourceMtime: number\n}\n\ninterface ResolvedImport {\n sourcePath: string\n compiledImportPath: string\n}\n\ninterface TransformResult {\n code: string\n dependencies: string[]\n}\n\nconst cache = new Map<string, CompileCache>()\n\nconst getCompiledPath = (tsFilePath: string, projectRoot: string): string => {\n const relativePath = path.relative(projectRoot, tsFilePath)\n const compiledRelativePath = relativePath.replace(/\\.ts$/, '.js')\n return path.join(projectRoot, COMPILED_DIR, compiledRelativePath)\n}\n\nconst getSourceMtime = (filePath: string): number => {\n try {\n return statSync(filePath).mtimeMs\n } catch {\n return 0\n }\n}\n\nconst ensureCompiledDir = (compiledPath: string): void => {\n const dir = path.dirname(compiledPath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n}\n\nconst replaceExtensionWithJs = (filePath: string): string => {\n for (const [ext, jsExt] of Object.entries(EXT_TO_JS_MAP)) {\n if (filePath.endsWith(ext)) {\n return filePath.replace(new RegExp(`${ext.replace('.', '\\\\.')}$`), jsExt)\n }\n }\n return filePath\n}\n\nconst resolveImportPath = (\n importPath: string,\n dir: string,\n projectRoot: string,\n compiledPath: string,\n): ResolvedImport | null => {\n const fullImportPath = path.resolve(dir, importPath)\n\n for (const ext of TS_EXTENSIONS) {\n const testPath = fullImportPath + (ext.startsWith('.') ? ext : `.${ext}`)\n if (existsSync(testPath)) {\n const relativeToProject = path.relative(projectRoot, testPath)\n const compiledFileName = replaceExtensionWithJs(relativeToProject)\n const compiledImportPath = path.join(COMPILED_DIR, compiledFileName)\n const relativeCompiledPath = path\n .relative(path.dirname(compiledPath), path.join(projectRoot, compiledImportPath))\n .replace(/\\\\/g, '/')\n\n return {\n sourcePath: testPath,\n compiledImportPath: relativeCompiledPath.startsWith('.') ? relativeCompiledPath : `./${relativeCompiledPath}`,\n }\n }\n }\n\n return null\n}\n\nconst transformImportPaths = (\n code: string,\n tsFilePath: string,\n compiledPath: string,\n projectRoot: string,\n): TransformResult => {\n const dir = path.dirname(tsFilePath)\n const dependencies: string[] = []\n\n const transformedCode = code.replace(/from\\s+['\"](\\.\\/?[^'\"]+)['\"]/g, (match, importPath) => {\n if (!importPath.startsWith('.')) {\n return match\n }\n if (importPath.endsWith('.js') || importPath.endsWith('.json')) {\n return match\n }\n\n const resolved = resolveImportPath(importPath, dir, projectRoot, compiledPath)\n if (resolved) {\n dependencies.push(resolved.sourcePath)\n return match.replace(importPath, resolved.compiledImportPath)\n }\n\n if (!importPath.match(/\\.(ts|tsx|js|jsx|json|stream)$/)) {\n return match.replace(importPath, `${importPath}.js`)\n }\n\n return match.replace(importPath, importPath.replace(/\\.(ts|tsx|stream\\.ts|stream)$/, '.js'))\n })\n\n return {\n code: transformedCode,\n dependencies: dependencies.filter(\n (dep) => dep.endsWith('.ts') || dep.endsWith('.tsx') || dep.endsWith('.stream.ts'),\n ),\n }\n}\n\nconst isCacheValid = (tsFilePath: string): boolean => {\n const cached = cache.get(tsFilePath)\n if (!cached) {\n return false\n }\n\n const sourceMtime = getSourceMtime(tsFilePath)\n return cached.sourceMtime === sourceMtime && existsSync(cached.compiledPath)\n}\n\nconst buildWithEsbuild = async (tsFilePath: string, compiledPath: string): Promise<string> => {\n const result = await esbuild.build({\n entryPoints: [tsFilePath],\n bundle: false,\n format: 'esm',\n target: 'node18',\n platform: 'node',\n outfile: compiledPath,\n sourcemap: 'inline',\n write: false,\n resolveExtensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],\n packages: 'external',\n })\n\n if (!result.outputFiles || result.outputFiles.length === 0) {\n throw new Error(`Failed to compile ${tsFilePath}`)\n }\n\n return result.outputFiles[0].text\n}\n\nconst compileDependencies = async (dependencies: string[], projectRoot: string): Promise<void> => {\n for (const dep of dependencies) {\n await compile(dep, projectRoot)\n }\n}\n\nconst updateCache = (tsFilePath: string, compiledPath: string): void => {\n const sourceMtime = getSourceMtime(tsFilePath)\n cache.set(tsFilePath, {\n compiledPath,\n sourceMtime,\n })\n}\n\nexport const compile = async (tsFilePath: string, projectRoot: string): Promise<string> => {\n const compiledPath = getCompiledPath(tsFilePath, projectRoot)\n\n if (isCacheValid(tsFilePath)) {\n const cached = cache.get(tsFilePath)\n if (cached) {\n return cached.compiledPath\n }\n }\n\n ensureCompiledDir(compiledPath)\n const compiledCode = await buildWithEsbuild(tsFilePath, compiledPath)\n const { code, dependencies } = transformImportPaths(compiledCode, tsFilePath, compiledPath, projectRoot)\n\n await compileDependencies(dependencies, projectRoot)\n writeFileSync(compiledPath, code, 'utf-8')\n updateCache(tsFilePath, compiledPath)\n\n return compiledPath\n}\n\nexport const invalidate = (tsFilePath: string): void => {\n cache.delete(tsFilePath)\n}\n\nexport const invalidateAll = (): void => {\n cache.clear()\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "import": "./dist/index.mjs"
12
12
  }
13
13
  },
14
- "version": "0.16.1-beta.179",
14
+ "version": "0.17.0-beta.181",
15
15
  "dependencies": {
16
16
  "@amplitude/analytics-node": "^1.5.26",
17
17
  "@standard-schema/spec": "^1.0.0",
@@ -19,6 +19,7 @@
19
19
  "body-parser": "^1.20.3",
20
20
  "picocolors": "^1.1.1",
21
21
  "dotenv": "^16.4.7",
22
+ "esbuild": "^0.25.0",
22
23
  "express": "^4.21.2",
23
24
  "tsx": "^4.20.6",
24
25
  "node-cron": "^3.0.3",