@mastra/platform-workspace 1.3.0 → 1.4.0
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/CHANGELOG.md +21 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/direct-exec.d.ts +1 -1
- package/dist/direct-exec.d.ts.map +1 -1
- package/dist/e2b-exec.d.ts +7 -0
- package/dist/e2b-exec.d.ts.map +1 -0
- package/dist/index.cjs +88 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +88 -10
- package/dist/index.js.map +1 -1
- package/dist/sandbox.d.ts +9 -5
- package/dist/sandbox.d.ts.map +1 -1
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Buffer } from "buffer";
|
|
2
2
|
import nodePath from "path";
|
|
3
3
|
import { FileExistsError, FileNotFoundError, MastraFilesystem, MastraSandbox, ProcessHandle, SandboxNotReadyError, SandboxProcessManager, UnsupportedStdinCloseError, WorkspaceReadOnlyError } from "@mastra/core/workspace";
|
|
4
|
+
import { CommandExitError, Sandbox, TimeoutError } from "e2b";
|
|
4
5
|
//#region src/client.ts
|
|
5
6
|
const DEFAULT_PROXY_URL = "https://workspaces.mastra.ai";
|
|
6
7
|
/**
|
|
@@ -13,12 +14,20 @@ function requireOption(value, name) {
|
|
|
13
14
|
if (!value) throw new Error(`${name} is required`);
|
|
14
15
|
return value;
|
|
15
16
|
}
|
|
17
|
+
function resolveSandboxProvider(value) {
|
|
18
|
+
const provider = value?.trim() || "railway";
|
|
19
|
+
if (provider !== "railway" && provider !== "e2b") throw new Error("SANDBOX_PROVIDER must be either \"railway\" or \"e2b\"");
|
|
20
|
+
return provider;
|
|
21
|
+
}
|
|
16
22
|
function resolvePlatformOptions(options) {
|
|
23
|
+
const configuredSandboxProvider = process.env.SANDBOX_PROVIDER?.trim();
|
|
17
24
|
return {
|
|
18
25
|
accessToken: requireOption(options.accessToken ?? process.env.MASTRA_PLATFORM_ACCESS_TOKEN, "accessToken"),
|
|
19
26
|
projectId: requireOption(options.projectId ?? process.env.MASTRA_PROJECT_ID, "projectId"),
|
|
20
27
|
actingUserId: options.actingUserId?.trim() || void 0,
|
|
21
28
|
proxyUrl: (process.env.MASTRA_WORKSPACE_PROXY_URL ?? DEFAULT_PROXY_URL).replace(/\/$/, ""),
|
|
29
|
+
sandboxProvider: resolveSandboxProvider(configuredSandboxProvider),
|
|
30
|
+
useLegacyRoutes: !configuredSandboxProvider,
|
|
22
31
|
sessionId: options.sessionId,
|
|
23
32
|
threadId: options.threadId,
|
|
24
33
|
fetch: options.fetch ?? fetch
|
|
@@ -65,6 +74,8 @@ var PlatformClient = class {
|
|
|
65
74
|
projectId;
|
|
66
75
|
actingUserId;
|
|
67
76
|
proxyUrl;
|
|
77
|
+
sandboxProvider;
|
|
78
|
+
useLegacyRoutes;
|
|
68
79
|
/** Advisory session correlation id — see {@link PlatformClientOptions.sessionId}. */
|
|
69
80
|
sessionId;
|
|
70
81
|
/** Advisory thread correlation id — see {@link PlatformClientOptions.threadId}. */
|
|
@@ -76,12 +87,15 @@ var PlatformClient = class {
|
|
|
76
87
|
this.projectId = resolved.projectId;
|
|
77
88
|
this.actingUserId = resolved.actingUserId;
|
|
78
89
|
this.proxyUrl = resolved.proxyUrl;
|
|
90
|
+
this.sandboxProvider = resolved.sandboxProvider;
|
|
91
|
+
this.useLegacyRoutes = resolved.useLegacyRoutes;
|
|
79
92
|
this.sessionId = resolved.sessionId;
|
|
80
93
|
this.threadId = resolved.threadId;
|
|
81
94
|
this.fetch = resolved.fetch;
|
|
82
95
|
}
|
|
83
96
|
async request(path, options = {}) {
|
|
84
|
-
const
|
|
97
|
+
const providerPath = this.useLegacyRoutes ? "" : `/${this.sandboxProvider}`;
|
|
98
|
+
const url = new URL(`${this.proxyUrl}/v1${providerPath}/projects/${encodeURIComponent(this.projectId)}${path}`);
|
|
85
99
|
for (const [key, value] of Object.entries(options.query ?? {})) if (value !== void 0) url.searchParams.set(key, String(value));
|
|
86
100
|
const headers = new Headers(options.headers);
|
|
87
101
|
headers.set("authorization", `Bearer ${this.accessToken}`);
|
|
@@ -502,6 +516,62 @@ function execViaLease(lease, options) {
|
|
|
502
516
|
});
|
|
503
517
|
}
|
|
504
518
|
//#endregion
|
|
519
|
+
//#region src/e2b-exec.ts
|
|
520
|
+
const E2B_ENVD_VERSION = "0.4.0";
|
|
521
|
+
const execViaE2BLease = async (lease, options) => {
|
|
522
|
+
const stdoutChunks = [];
|
|
523
|
+
const stderrChunks = [];
|
|
524
|
+
const onStdout = (data) => {
|
|
525
|
+
stdoutChunks.push(data);
|
|
526
|
+
options.onStdout?.(data);
|
|
527
|
+
};
|
|
528
|
+
const onStderr = (data) => {
|
|
529
|
+
stderrChunks.push(data);
|
|
530
|
+
options.onStderr?.(data);
|
|
531
|
+
};
|
|
532
|
+
try {
|
|
533
|
+
const result = await new Sandbox({
|
|
534
|
+
sandboxId: lease.sandboxId,
|
|
535
|
+
envdVersion: E2B_ENVD_VERSION,
|
|
536
|
+
envdAccessToken: lease.jwt,
|
|
537
|
+
sandboxUrl: lease.wsEndpoint,
|
|
538
|
+
validateApiKey: false
|
|
539
|
+
}).commands.run(options.command, {
|
|
540
|
+
cwd: options.cwd,
|
|
541
|
+
envs: options.env,
|
|
542
|
+
timeoutMs: options.timeoutMs,
|
|
543
|
+
onStdout,
|
|
544
|
+
onStderr
|
|
545
|
+
});
|
|
546
|
+
return {
|
|
547
|
+
exitCode: result.exitCode,
|
|
548
|
+
stdout: result.stdout,
|
|
549
|
+
stderr: result.stderr,
|
|
550
|
+
truncated: false,
|
|
551
|
+
timedOut: false,
|
|
552
|
+
opened: true
|
|
553
|
+
};
|
|
554
|
+
} catch (error) {
|
|
555
|
+
if (error instanceof CommandExitError) return {
|
|
556
|
+
exitCode: error.exitCode,
|
|
557
|
+
stdout: error.stdout,
|
|
558
|
+
stderr: error.stderr,
|
|
559
|
+
truncated: false,
|
|
560
|
+
timedOut: false,
|
|
561
|
+
opened: true
|
|
562
|
+
};
|
|
563
|
+
return {
|
|
564
|
+
exitCode: null,
|
|
565
|
+
stdout: stdoutChunks.join(""),
|
|
566
|
+
stderr: stderrChunks.join(""),
|
|
567
|
+
truncated: false,
|
|
568
|
+
timedOut: error instanceof TimeoutError,
|
|
569
|
+
closeReason: error instanceof Error ? error.message : String(error),
|
|
570
|
+
opened: true
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
//#endregion
|
|
505
575
|
//#region src/private-net-exec.ts
|
|
506
576
|
/**
|
|
507
577
|
* Thrown by {@link execViaPrivateNetwork} when the sidecar returns a non-2xx
|
|
@@ -843,6 +913,7 @@ var PlatformSandbox = class PlatformSandbox extends MastraSandbox {
|
|
|
843
913
|
_instructionsOverride;
|
|
844
914
|
_createdAt = null;
|
|
845
915
|
_webSocketFactory;
|
|
916
|
+
_e2bExecRunner;
|
|
846
917
|
_privateNetFetch;
|
|
847
918
|
/**
|
|
848
919
|
* Registry that maps `sandboxId → instanceUrl` for the private-network
|
|
@@ -940,6 +1011,7 @@ var PlatformSandbox = class PlatformSandbox extends MastraSandbox {
|
|
|
940
1011
|
this._timeout = options.timeout;
|
|
941
1012
|
this._instructionsOverride = options.instructions;
|
|
942
1013
|
this._webSocketFactory = options.webSocketFactory;
|
|
1014
|
+
this._e2bExecRunner = options.e2bExecRunner ?? execViaE2BLease;
|
|
943
1015
|
this._privateNetFetch = options.privateNetFetch;
|
|
944
1016
|
this._addressRegistry = options.addressRegistry;
|
|
945
1017
|
}
|
|
@@ -960,6 +1032,7 @@ var PlatformSandbox = class PlatformSandbox extends MastraSandbox {
|
|
|
960
1032
|
*/
|
|
961
1033
|
clone(options = {}) {
|
|
962
1034
|
const id = options.id ?? options.checkpointName;
|
|
1035
|
+
const seedCheckpointName = options.seedCheckpointName ?? (this._client.sandboxProvider === "e2b" ? options.checkpointName : void 0) ?? this._seedCheckpointName;
|
|
963
1036
|
return new PlatformSandbox({
|
|
964
1037
|
...id !== void 0 && { id },
|
|
965
1038
|
accessToken: this._client.accessToken,
|
|
@@ -970,13 +1043,14 @@ var PlatformSandbox = class PlatformSandbox extends MastraSandbox {
|
|
|
970
1043
|
fetch: this._client.fetch,
|
|
971
1044
|
environmentId: this._environmentId,
|
|
972
1045
|
...options.sandboxId !== void 0 && { sandboxId: options.sandboxId },
|
|
973
|
-
...
|
|
1046
|
+
...seedCheckpointName !== void 0 && { seedCheckpointName },
|
|
974
1047
|
idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,
|
|
975
1048
|
...this._networkIsolation !== void 0 && { networkIsolation: this._networkIsolation },
|
|
976
1049
|
env: options.env ?? this._env,
|
|
977
1050
|
...this._timeout !== void 0 && { timeout: this._timeout },
|
|
978
1051
|
...this._instructionsOverride !== void 0 && { instructions: this._instructionsOverride },
|
|
979
1052
|
...this._webSocketFactory !== void 0 && { webSocketFactory: this._webSocketFactory },
|
|
1053
|
+
e2bExecRunner: this._e2bExecRunner,
|
|
980
1054
|
...this._privateNetFetch !== void 0 && { privateNetFetch: this._privateNetFetch },
|
|
981
1055
|
...this._addressRegistry !== void 0 && { addressRegistry: this._addressRegistry }
|
|
982
1056
|
});
|
|
@@ -1177,7 +1251,7 @@ var PlatformSandbox = class PlatformSandbox extends MastraSandbox {
|
|
|
1177
1251
|
* it. Any in-flight capture is awaited first so the preserved checkpoint
|
|
1178
1252
|
* reflects the latest disk state we asked for.
|
|
1179
1253
|
*
|
|
1180
|
-
* Corresponds to `DELETE /v1/projects/:pid/sandbox/:sandboxId` on
|
|
1254
|
+
* Corresponds to `DELETE /v1/:provider/projects/:pid/sandbox/:sandboxId` on
|
|
1181
1255
|
* workspace-proxy, which by contract does not touch the checkpoint. Use
|
|
1182
1256
|
* {@link destroy} when you want the checkpoint released too.
|
|
1183
1257
|
*/
|
|
@@ -1198,15 +1272,15 @@ var PlatformSandbox = class PlatformSandbox extends MastraSandbox {
|
|
|
1198
1272
|
* transient proxy error must not leave the caller with a half-torn-down
|
|
1199
1273
|
* sandbox they can't safely retry.
|
|
1200
1274
|
*
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
1275
|
+
* Railway requires a caller-supplied recovery `id` before it can have a
|
|
1276
|
+
* checkpoint to delete. E2B also permits capture with the automatic id, so
|
|
1277
|
+
* destroy releases that named snapshot even when no recovery id was supplied.
|
|
1204
1278
|
*/
|
|
1205
1279
|
async destroy() {
|
|
1206
1280
|
if (!this._sandboxId) return;
|
|
1207
1281
|
const destroyedSandboxId = this._sandboxId;
|
|
1208
1282
|
this._captureInFlight = null;
|
|
1209
|
-
if (this._hasRecoveryKey) try {
|
|
1283
|
+
if (this._hasRecoveryKey || this._client.sandboxProvider === "e2b") try {
|
|
1210
1284
|
await this._client.request(`/sandbox/${encodeURIComponent(destroyedSandboxId)}/checkpoint`, {
|
|
1211
1285
|
method: "DELETE",
|
|
1212
1286
|
headers: { "content-type": "application/json" },
|
|
@@ -1289,7 +1363,7 @@ var PlatformSandbox = class PlatformSandbox extends MastraSandbox {
|
|
|
1289
1363
|
* to a skip as described above.
|
|
1290
1364
|
*/
|
|
1291
1365
|
async captureCheckpoint() {
|
|
1292
|
-
if (!this._hasRecoveryKey) {
|
|
1366
|
+
if (!this._hasRecoveryKey && this._client.sandboxProvider !== "e2b") {
|
|
1293
1367
|
this.logger.debug(`captureCheckpoint skipped: no recovery key configured for sandbox ${this._sandboxId ?? "(unstarted)"}`);
|
|
1294
1368
|
return {
|
|
1295
1369
|
status: "skipped",
|
|
@@ -1472,13 +1546,14 @@ var PlatformSandbox = class PlatformSandbox extends MastraSandbox {
|
|
|
1472
1546
|
}
|
|
1473
1547
|
lastLease = lease;
|
|
1474
1548
|
attemptsMade = attempt + 1;
|
|
1475
|
-
const
|
|
1549
|
+
const execOptions = {
|
|
1476
1550
|
command: fullCommand,
|
|
1477
1551
|
...options?.cwd !== void 0 && { cwd: options.cwd },
|
|
1478
1552
|
...filteredEnv !== void 0 && { env: filteredEnv },
|
|
1479
1553
|
...effectiveTimeout != null && effectiveTimeout > 0 && { timeoutMs: effectiveTimeout },
|
|
1480
1554
|
...this._webSocketFactory && { webSocketFactory: this._webSocketFactory }
|
|
1481
|
-
}
|
|
1555
|
+
};
|
|
1556
|
+
const result = lease.provider === "e2b" ? await this._e2bExecRunner(lease, execOptions) : await execViaLease(lease, execOptions);
|
|
1482
1557
|
lastResult = result;
|
|
1483
1558
|
if (result.exitCode !== null || result.timedOut) return result;
|
|
1484
1559
|
}
|
|
@@ -1561,6 +1636,9 @@ var PlatformSandbox = class PlatformSandbox extends MastraSandbox {
|
|
|
1561
1636
|
const json = await (await this._client.request(`/sandbox/${encodeURIComponent(sandboxId)}/exec-lease`, { method: "POST" })).json();
|
|
1562
1637
|
const expiresAtMs = json.expiresAt ? Date.parse(json.expiresAt) : null;
|
|
1563
1638
|
const lease = {
|
|
1639
|
+
provider: json.provider,
|
|
1640
|
+
sandboxId: json.sandboxId,
|
|
1641
|
+
providerResourceId: json.providerResourceId,
|
|
1564
1642
|
jwt: json.jwt,
|
|
1565
1643
|
wsEndpoint: json.wsEndpoint,
|
|
1566
1644
|
subprotocol: json.subprotocol,
|