@mastra/platform-workspace 1.7.0-alpha.0 → 1.7.0-alpha.2

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.cjs CHANGED
@@ -1151,10 +1151,21 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
1151
1151
  * on a later start.
1152
1152
  */
1153
1153
  templatePending;
1154
+ /**
1155
+ * The platform's id for the provisioned sandbox, as returned by the create
1156
+ * or reattach response. Persist this to reattach later via the `sandboxId`
1157
+ * option. Undefined until the sandbox has been started in this process; a
1158
+ * `sandboxId` passed to the constructor is only a hint for `start()` and is
1159
+ * not reported here until the proxy confirms it.
1160
+ */
1161
+ get sandboxId() {
1162
+ return this.status === "running" ? this._sandboxId : void 0;
1163
+ }
1154
1164
  _client;
1155
1165
  _usesProviderRoutes;
1156
1166
  _environmentId;
1157
1167
  _sandboxId;
1168
+ _reattach;
1158
1169
  _seedCheckpointName;
1159
1170
  _templateDefinition;
1160
1171
  _templateBuildEnvs;
@@ -1246,6 +1257,7 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
1246
1257
  this._environmentId = options.environmentId ?? process.env.MASTRA_ENVIRONMENT_ID ?? "";
1247
1258
  if (!this._environmentId && !options.sandboxId) throw new Error("environmentId is required");
1248
1259
  this._sandboxId = options.sandboxId;
1260
+ this._reattach = options.reattach ?? "best-effort";
1249
1261
  this._seedCheckpointName = options.seedCheckpointName;
1250
1262
  this._usesProviderRoutes = options.template !== void 0;
1251
1263
  this._template = options.template;
@@ -1262,6 +1274,16 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
1262
1274
  generateId() {
1263
1275
  return `platform-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1264
1276
  }
1277
+ _failIfReattachRequired(reason, cause) {
1278
+ if (this._reattach !== "required") return;
1279
+ throw new _mastra_core_workspace.SandboxError(`Platform sandbox ${this._sandboxId} could not be reattached (${reason}); refusing to provision a replacement because reattach is 'required'. Clear the persisted sandboxId to start a fresh sandbox.`, "SANDBOX_REATTACH_FAILED", {
1280
+ provider: "platform",
1281
+ sandboxId: this._sandboxId,
1282
+ logicalId: this.id,
1283
+ reason,
1284
+ ...cause !== void 0 && { cause }
1285
+ });
1286
+ }
1265
1287
  _request(path, options = {}) {
1266
1288
  return this._usesProviderRoutes ? this._client.requestProvider(path, options) : this._client.request(path, options);
1267
1289
  }
@@ -1291,6 +1313,7 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
1291
1313
  fetch: this._client.fetch,
1292
1314
  environmentId: this._environmentId,
1293
1315
  ...options.sandboxId !== void 0 && { sandboxId: options.sandboxId },
1316
+ reattach: this._reattach,
1294
1317
  ...seedCheckpointName !== void 0 && { seedCheckpointName },
1295
1318
  ...this._template !== void 0 && { template: this._template },
1296
1319
  idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,
@@ -1333,9 +1356,11 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
1333
1356
  this._logStartComplete(json.id, startedAt, requestMs, "reattach");
1334
1357
  return { outcome: "connected" };
1335
1358
  }
1359
+ this._failIfReattachRequired("destroyed");
1336
1360
  this._sandboxId = void 0;
1337
1361
  } catch (error) {
1338
- if (!(error instanceof PlatformApiError) || error.status !== 404) throw error;
1362
+ if (!(error instanceof PlatformApiError) || error.status !== 404 && error.status !== 410) throw error;
1363
+ this._failIfReattachRequired(String(error.status), error);
1339
1364
  this._sandboxId = void 0;
1340
1365
  }
1341
1366
  if (!this._environmentId) throw new Error("environmentId is required");
@@ -1518,23 +1543,28 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
1518
1543
  await Promise.race([this._transportReadyPromise, new Promise((r) => setTimeout(r, TRANSPORT_READY_WAIT_MS))]);
1519
1544
  }
1520
1545
  /**
1521
- * Stop the sandbox while **preserving its recovery checkpoint**.
1546
+ * Stop this process's use of the sandbox without touching the remote one.
1522
1547
  *
1523
- * Semantic parity with `@mastra/railway` `RailwaySandbox.stop()`: the VM
1524
- * is released but the on-provider checkpoint survives, so a subsequent
1525
- * `start()` on a sandbox constructed with the same `id` can restore from
1526
- * it. Any in-flight capture is awaited first so the preserved checkpoint
1527
- * reflects the latest disk state we asked for.
1548
+ * Nothing is sent to workspace-proxy. The VM keeps running and idles out
1549
+ * under the environment's own idle policy, the recovery checkpoint stays,
1550
+ * and `_sandboxId` is kept so a later `start()` on this instance, or on a
1551
+ * new instance constructed with the same `id` or `sandboxId`, reattaches
1552
+ * instead of provisioning. `Mastra.shutdown()` stops every registered
1553
+ * workspace on SIGINT; releasing the VM here would destroy every live
1554
+ * session on a host restart. Use {@link destroy} to release the VM and
1555
+ * its checkpoint.
1528
1556
  *
1529
- * Corresponds to `DELETE /v1/:provider/projects/:pid/sandbox/:sandboxId` on
1530
- * workspace-proxy, which by contract does not touch the checkpoint. Use
1531
- * {@link destroy} when you want the checkpoint released too.
1557
+ * Any in-flight capture is awaited first so the checkpoint reflects the
1558
+ * latest disk state the caller asked for.
1532
1559
  */
1533
1560
  async stop() {
1534
1561
  if (this._captureInFlight) await this._captureInFlight.catch((error) => {
1535
- this.logger.warn(`stop(): failed to flush in-flight capture before teardown:`, error);
1562
+ this.logger.warn(`stop(): failed to flush in-flight capture before stop:`, error);
1536
1563
  });
1537
- await this._teardownSandbox();
1564
+ this._probeGeneration++;
1565
+ this._probeTarget = null;
1566
+ this._transportReadyPromise = null;
1567
+ this._lease = null;
1538
1568
  }
1539
1569
  /**
1540
1570
  * Destroy the sandbox **and release its recovery checkpoint**.
@@ -1571,12 +1601,9 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
1571
1601
  /**
1572
1602
  * Release the remote sandbox VM and clear the local state pointing at it.
1573
1603
  *
1574
- * Shared body of {@link stop} and {@link destroy} — both funnel through
1575
- * here after they've dealt with the checkpoint (preserve vs release).
1576
- * The VM DELETE is safe to issue in either mode: the proxy's DELETE
1577
- * route does not touch the checkpoint on its own, so `stop()` correctly
1578
- * leaves the checkpoint intact and `destroy()` has already removed it
1579
- * before this call.
1604
+ * Body of {@link destroy}, called after the checkpoint has been released.
1605
+ * The proxy's DELETE route releases the VM (on E2B that kills it), so
1606
+ * only destroy() may reach here; stop() never does.
1580
1607
  */
1581
1608
  async _teardownSandbox() {
1582
1609
  if (!this._sandboxId) return;
@@ -1955,7 +1982,7 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
1955
1982
  }
1956
1983
  }
1957
1984
  async getInfo() {
1958
- if (!this._sandboxId) return {
1985
+ if (!this._sandboxId || this.status !== "running") return {
1959
1986
  id: this.id,
1960
1987
  name: this.name,
1961
1988
  provider: this.provider,