@motiadev/core 0.16.1-beta.179 → 0.17.0-beta.180
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 +2 -1
- package/dist/index.mjs +2 -1
- package/dist/src/call-step-file.mjs +200 -180
- package/dist/src/call-step-file.mjs.map +1 -1
- package/dist/src/get-step-config.d.mts +1 -0
- package/dist/src/get-step-config.d.mts.map +1 -1
- package/dist/src/get-step-config.mjs +14 -12
- package/dist/src/get-step-config.mjs.map +1 -1
- package/dist/src/language-runner.mjs +6 -0
- package/dist/src/language-runner.mjs.map +1 -1
- package/dist/src/logger.d.mts +1 -1
- package/dist/src/logger.mjs +5 -1
- package/dist/src/logger.mjs.map +1 -1
- package/dist/src/node/node-runner.mjs +22 -8
- package/dist/src/node/node-runner.mjs.map +1 -1
- package/dist/src/ts-compiler.d.mts +5 -0
- package/dist/src/ts-compiler.d.mts.map +1 -0
- package/dist/src/ts-compiler.mjs +130 -0
- package/dist/src/ts-compiler.mjs.map +1 -0
- package/package.json +2 -1
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
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
36
|
+
context: "StepExecution",
|
|
37
|
+
projectRoot: motia.lockedData.baseDir
|
|
119
38
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(`
|
|
193
|
-
}
|
|
212
|
+
reject(`Failed to spawn process: ${error}`);
|
|
213
|
+
});
|
|
194
214
|
});
|
|
195
|
-
}
|
|
196
|
-
|
|
215
|
+
} catch (error) {
|
|
216
|
+
const err = error;
|
|
197
217
|
await tracer.end({
|
|
198
|
-
message:
|
|
199
|
-
code:
|
|
200
|
-
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:
|
|
206
|
-
message:
|
|
225
|
+
code: err.code,
|
|
226
|
+
message: err.message
|
|
207
227
|
});
|
|
208
|
-
|
|
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":"
|
|
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
|
|
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;
|
|
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"}
|
package/dist/src/logger.d.mts
CHANGED
|
@@ -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):
|
|
25
|
+
removeListener(listener: LogListener): boolean;
|
|
26
26
|
}
|
|
27
27
|
//#endregion
|
|
28
28
|
export { Logger };
|
package/dist/src/logger.mjs
CHANGED
|
@@ -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
|
|
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();
|
package/dist/src/logger.mjs.map
CHANGED
|
@@ -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
|
+
{"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
|
-
|
|
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
|
|
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
|
|
76
|
-
message:
|
|
77
|
-
code:
|
|
89
|
+
const errorObj = {
|
|
90
|
+
message: error.message || "",
|
|
91
|
+
code: error.code || null,
|
|
78
92
|
stack: stack.join("\n")
|
|
79
93
|
};
|
|
80
|
-
sender.sendNoWait("close",
|
|
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:
|
|
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 @@
|
|
|
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.
|
|
14
|
+
"version": "0.17.0-beta.180",
|
|
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",
|