@mastra/deployer-sandbox 0.0.0-monorepo-flexibility-20260722142608

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/LICENSE.md +30 -0
  3. package/README.md +72 -0
  4. package/dist/alias.d.ts +10 -0
  5. package/dist/alias.d.ts.map +1 -0
  6. package/dist/chunk-CSXC6CZL.cjs +115 -0
  7. package/dist/chunk-CSXC6CZL.cjs.map +1 -0
  8. package/dist/chunk-Z636GNUQ.js +101 -0
  9. package/dist/chunk-Z636GNUQ.js.map +1 -0
  10. package/dist/client/index.cjs +159 -0
  11. package/dist/client/index.cjs.map +1 -0
  12. package/dist/client/index.d.ts +98 -0
  13. package/dist/client/index.d.ts.map +1 -0
  14. package/dist/client/index.js +155 -0
  15. package/dist/client/index.js.map +1 -0
  16. package/dist/deployer.d.ts +57 -0
  17. package/dist/deployer.d.ts.map +1 -0
  18. package/dist/engine.d.ts +19 -0
  19. package/dist/engine.d.ts.map +1 -0
  20. package/dist/index.cjs +381 -0
  21. package/dist/index.cjs.map +1 -0
  22. package/dist/index.d.ts +6 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +372 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/manifest.d.ts +7 -0
  27. package/dist/manifest.d.ts.map +1 -0
  28. package/dist/shared.d.ts +63 -0
  29. package/dist/shared.d.ts.map +1 -0
  30. package/dist/studio/assets/CommitMono-400-Regular-DzkyLZ26.woff2 +0 -0
  31. package/dist/studio/assets/CommitMono-700-Regular-DmOSN4kd.woff2 +0 -0
  32. package/dist/studio/assets/MonaSans-VariableFont_wdth-wght-CX-7s9jm.ttf +0 -0
  33. package/dist/studio/assets/babel-lWBcy2sH.js +16 -0
  34. package/dist/studio/assets/bash-atvbtKCR.js +1 -0
  35. package/dist/studio/assets/core-DU951QSU.js +12 -0
  36. package/dist/studio/assets/engine-compile-BkERmzkH.js +137 -0
  37. package/dist/studio/assets/engine-javascript-CSIo_1eZ.js +1 -0
  38. package/dist/studio/assets/estree-Dd9JfUIE.js +44 -0
  39. package/dist/studio/assets/github-dark-DHJKELXO.js +1 -0
  40. package/dist/studio/assets/github-light-DAi9KRSo.js +1 -0
  41. package/dist/studio/assets/index-DXL-DzAe.js +2 -0
  42. package/dist/studio/assets/index-yUiD89B4.js +1 -0
  43. package/dist/studio/assets/javascript-ySlJ1b_l.js +1 -0
  44. package/dist/studio/assets/json-BQoSv7ci.js +1 -0
  45. package/dist/studio/assets/jsx-BAng5TT0.js +1 -0
  46. package/dist/studio/assets/livekit-client.esm-CKIgC2IJ.js +39 -0
  47. package/dist/studio/assets/main-DJh4NnSE.js +780 -0
  48. package/dist/studio/assets/markdown-UIAJJxZW.js +1 -0
  49. package/dist/studio/assets/preload-helper-PPVm8Dsz.js +1 -0
  50. package/dist/studio/assets/python-DhUJRlN_.js +1 -0
  51. package/dist/studio/assets/shell-CjFT_Tl9.js +1 -0
  52. package/dist/studio/assets/standalone-Dfz2oS5J.js +29 -0
  53. package/dist/studio/assets/style-C6ZDnGn9.css +1 -0
  54. package/dist/studio/assets/tsx-B6W0miNI.js +1 -0
  55. package/dist/studio/assets/typescript-Dj6nwHGl.js +1 -0
  56. package/dist/studio/index.html +100 -0
  57. package/dist/studio/mastra.svg +17 -0
  58. package/dist/studio/routes-manifest.json +27 -0
  59. package/dist/types.d.ts +90 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/package.json +78 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,117 @@
1
+ # @mastra/deployer-sandbox
2
+
3
+ ## 0.0.0-monorepo-flexibility-20260722142608
4
+
5
+ ### Minor Changes
6
+
7
+ - New package: deploy a full Mastra server (including Studio) into any workspace sandbox that supports networking, and get a live public URL in seconds. Works with `@mastra/vercel`, `@mastra/e2b`, and `@mastra/daytona` sandboxes. Built for ephemeral environments: instant previews, PR/CI smoke deploys, agent-built app verification, and multi-tenant untrusted instances. ([#19577](https://github.com/mastra-ai/mastra/pull/19577))
8
+
9
+ **Deploy from your Mastra config**
10
+
11
+ ```typescript
12
+ import { Mastra } from '@mastra/core/mastra';
13
+ import { SandboxDeployer } from '@mastra/deployer-sandbox';
14
+ import { VercelSandbox } from '@mastra/vercel';
15
+
16
+ export const mastra = new Mastra({
17
+ deployer: new SandboxDeployer({
18
+ sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }),
19
+ }),
20
+ });
21
+ ```
22
+
23
+ Then run `mastra build` — it bundles the project and deploys it into the sandbox in one step. Redeploys reuse the same sandbox and skip dependency installs when the install inputs (`package.json`, bundled lockfiles, and the install command) are unchanged.
24
+
25
+ **Manage the deployment**
26
+
27
+ The sandbox name is the identity — `getDeployment()` retrieves the deployment from any process or codebase, without importing the Mastra project:
28
+
29
+ ```typescript
30
+ import { getDeployment } from '@mastra/deployer-sandbox/client';
31
+ import { VercelSandbox } from '@mastra/vercel';
32
+
33
+ const dep = await getDeployment({
34
+ sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }),
35
+ }); // never wakes a stopped sandbox
36
+ await dep.stop(); // snapshot-stop (resumable)
37
+ await dep.destroy(); // permanent delete
38
+ ```
39
+
40
+ **Deploy programmatically (CI / agents)**
41
+
42
+ ```typescript
43
+ import { deployToSandbox } from '@mastra/deployer-sandbox';
44
+ import { VercelSandbox } from '@mastra/vercel';
45
+
46
+ const sandbox = new VercelSandbox({ sandboxName: 'ci-preview', ports: [4111] });
47
+ const deployment = await deployToSandbox({ sandbox, dir: '.mastra/output' });
48
+ console.info(deployment.url);
49
+ ```
50
+
51
+ **Resolve and route at runtime**
52
+
53
+ The server-only `@mastra/deployer-sandbox/client` export includes `getDeployment()` to resolve the current URL and manage the deployment (`stop()`, `destroy()`, `logs()`, with optional wake-on-demand), plus `createSandboxHandler()` and `createSandboxProxy()` helpers to serve a sandbox behind a stable URL on your own domain.
54
+
55
+ ### Patch Changes
56
+
57
+ - Updated dependencies [[`ec857fc`](https://github.com/mastra-ai/mastra/commit/ec857fc79c264b53b38e16478c789b7177f2ad59), [`41a5392`](https://github.com/mastra-ai/mastra/commit/41a5392d9f6c5e18d6b227f0fc0ddf49c50774e9), [`3b77e77`](https://github.com/mastra-ai/mastra/commit/3b77e7704936522e4769d29de1b5ea6901f302bd), [`1426af2`](https://github.com/mastra-ai/mastra/commit/1426af24975879c000d13ac75673f630fcc970c1), [`a40adeb`](https://github.com/mastra-ai/mastra/commit/a40adeb222b961a56a58af56a106106525721b74), [`8a0d145`](https://github.com/mastra-ai/mastra/commit/8a0d145aadbdf7278665aceaaec364b35dd9bd94), [`bd2f1d2`](https://github.com/mastra-ai/mastra/commit/bd2f1d274d05e60e2366f005ea0d94d5cea0d5ff), [`e1f2fae`](https://github.com/mastra-ai/mastra/commit/e1f2faebaf048c3d4c2e2c01d293767c195d5794), [`63aa799`](https://github.com/mastra-ai/mastra/commit/63aa799c6b44eacc7806cda6846b7c5bbee06b37), [`b7e79c3`](https://github.com/mastra-ai/mastra/commit/b7e79c3c02ac5cd415db34ba0975ceafc1464333), [`675fbff`](https://github.com/mastra-ai/mastra/commit/675fbff84d3274391b33e852f76083c38a5514e5), [`da009e1`](https://github.com/mastra-ai/mastra/commit/da009e1aacd89ed94b8d1b2af09c9d4fe7c4db49), [`3b77e77`](https://github.com/mastra-ai/mastra/commit/3b77e7704936522e4769d29de1b5ea6901f302bd), [`21a0eb8`](https://github.com/mastra-ai/mastra/commit/21a0eb86746ba0b703acea360d4f84c6a5a493f2), [`8b20926`](https://github.com/mastra-ai/mastra/commit/8b20926cd59e2ba3d66458e062fa0e6e2ada3e68), [`975295d`](https://github.com/mastra-ai/mastra/commit/975295d418552f0d46a59edfef4c3ee555f9930a), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`6b1bf3b`](https://github.com/mastra-ai/mastra/commit/6b1bf3b9494bd51aa8f654c68c9355d6046fa2a1), [`35c2181`](https://github.com/mastra-ai/mastra/commit/35c2181e6a50e47c90ba36260db7c9723d54696f), [`0a2c22c`](https://github.com/mastra-ai/mastra/commit/0a2c22c902604439ec490319e14c17f331e0c84c), [`4cfdd64`](https://github.com/mastra-ai/mastra/commit/4cfdd645794feaea0c4ea711e70ecdfbef0c5b8e), [`b75d749`](https://github.com/mastra-ai/mastra/commit/b75d749621ff5d17e86bcb4ee809d301fb4f7cf3), [`821648b`](https://github.com/mastra-ai/mastra/commit/821648bf2871ef840100c7bacbecf676010bd12a), [`de86fd7`](https://github.com/mastra-ai/mastra/commit/de86fd7119f0438381d1a642e3d258143c0b9c29), [`2745031`](https://github.com/mastra-ai/mastra/commit/2745031d1d4a4978f037092da371428c32e2842a), [`b4b7ea8`](https://github.com/mastra-ai/mastra/commit/b4b7ea8733f033fc441ea47ed03f6afb17ec2248), [`3a8024c`](https://github.com/mastra-ai/mastra/commit/3a8024ce615f8aa89479c0d71fe61d10bb0040be), [`74faf8b`](https://github.com/mastra-ai/mastra/commit/74faf8bd9c1018f2492653c06b1e25fc8300e9e6), [`675fbff`](https://github.com/mastra-ai/mastra/commit/675fbff84d3274391b33e852f76083c38a5514e5), [`1fadac4`](https://github.com/mastra-ai/mastra/commit/1fadac44537caeefe81f9f775ae2f2f3d94e9069), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`76b7181`](https://github.com/mastra-ai/mastra/commit/76b71810366e6d90b9d3973149d1c7ba3659ffb9), [`23cf854`](https://github.com/mastra-ai/mastra/commit/23cf8547c7e92c4cb01df7b686e695c22c6831fd), [`792ec9a`](https://github.com/mastra-ai/mastra/commit/792ec9a0869bab8274cf5e0ed2840738737a1607), [`712b864`](https://github.com/mastra-ai/mastra/commit/712b864aa1ed12b14c54390ec17b69de163c37f7), [`85e4fb5`](https://github.com/mastra-ai/mastra/commit/85e4fb50087a81c74df3a762f53b56373db0b912), [`0c0e8d7`](https://github.com/mastra-ai/mastra/commit/0c0e8d7becd4d1445c656b78d5d845f606c1ff9d), [`53df41b`](https://github.com/mastra-ai/mastra/commit/53df41ba8b00438ebe5daee1b04613aa4239a5b2), [`72e437c`](https://github.com/mastra-ai/mastra/commit/72e437c515942c80b9def5b026e0bdee61b469d9), [`8f7a5de`](https://github.com/mastra-ai/mastra/commit/8f7a5dedc246cdc938bb65516703cf9b27b03756), [`11f6cd9`](https://github.com/mastra-ai/mastra/commit/11f6cd96fe42582403416608beb212cc1a2cc79e), [`ef03c0c`](https://github.com/mastra-ai/mastra/commit/ef03c0cfc62367a458e4cc56462e2148b35681c5), [`4fb4d88`](https://github.com/mastra-ai/mastra/commit/4fb4d881bc107acee13890ad4d78661016c510ed), [`eac4537`](https://github.com/mastra-ai/mastra/commit/eac453795531df0d5fe3729d80e93a91f8c1bc91), [`c328769`](https://github.com/mastra-ai/mastra/commit/c3287698ff8ef98dba86d415faa566fa3e5f4d56), [`9f7c67a`](https://github.com/mastra-ai/mastra/commit/9f7c67abeeb52c41c51a9b5edee60b62afe7cd8d), [`3b65e68`](https://github.com/mastra-ai/mastra/commit/3b65e68d7f1c771c7a70eea42d83fefdd28cad88), [`4eba27a`](https://github.com/mastra-ai/mastra/commit/4eba27adcf60f991df0e62f94b3e75b4e67f3b4b), [`c701be3`](https://github.com/mastra-ai/mastra/commit/c701be32d7d9aa94a66da8c6cc38dcac6856f464), [`b4b7ea8`](https://github.com/mastra-ai/mastra/commit/b4b7ea8733f033fc441ea47ed03f6afb17ec2248), [`db650ce`](https://github.com/mastra-ai/mastra/commit/db650ce490348914e85b93651d83acdf8f2a4c31), [`232fcbc`](https://github.com/mastra-ai/mastra/commit/232fcbc14fce625dd672ba043329c0b732c62be2), [`6354eeb`](https://github.com/mastra-ai/mastra/commit/6354eeb32efa9f5f68f51dda394e90e2ee76f1fb), [`a8799bb`](https://github.com/mastra-ai/mastra/commit/a8799bb8e44f4a60d01e4e2acd3448ff80bf14f8), [`e3868e2`](https://github.com/mastra-ai/mastra/commit/e3868e22babfffd0133771669ca724501c2dd58e), [`3491666`](https://github.com/mastra-ai/mastra/commit/34916663c4fdd43b48c21f4ab2d5fb6dcccc94f9), [`c0bec73`](https://github.com/mastra-ai/mastra/commit/c0bec732c93d1a22ae5e51ed66cf8cacca8bd6a6)]:
58
+ - @mastra/core@0.0.0-monorepo-flexibility-20260722142608
59
+ - @mastra/deployer@0.0.0-monorepo-flexibility-20260722142608
60
+
61
+ ## 0.1.0-alpha.0
62
+
63
+ ### Minor Changes
64
+
65
+ - New package: deploy a full Mastra server (including Studio) into any workspace sandbox that supports networking, and get a live public URL in seconds. Works with `@mastra/vercel`, `@mastra/e2b`, and `@mastra/daytona` sandboxes. Built for ephemeral environments: instant previews, PR/CI smoke deploys, agent-built app verification, and multi-tenant untrusted instances. ([#19577](https://github.com/mastra-ai/mastra/pull/19577))
66
+
67
+ **Deploy from your Mastra config**
68
+
69
+ ```typescript
70
+ import { Mastra } from '@mastra/core/mastra';
71
+ import { SandboxDeployer } from '@mastra/deployer-sandbox';
72
+ import { VercelSandbox } from '@mastra/vercel';
73
+
74
+ export const mastra = new Mastra({
75
+ deployer: new SandboxDeployer({
76
+ sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }),
77
+ }),
78
+ });
79
+ ```
80
+
81
+ Then run `mastra build` — it bundles the project and deploys it into the sandbox in one step. Redeploys reuse the same sandbox and skip dependency installs when the install inputs (`package.json`, bundled lockfiles, and the install command) are unchanged.
82
+
83
+ **Manage the deployment**
84
+
85
+ The sandbox name is the identity — `getDeployment()` retrieves the deployment from any process or codebase, without importing the Mastra project:
86
+
87
+ ```typescript
88
+ import { getDeployment } from '@mastra/deployer-sandbox/client';
89
+ import { VercelSandbox } from '@mastra/vercel';
90
+
91
+ const dep = await getDeployment({
92
+ sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }),
93
+ }); // never wakes a stopped sandbox
94
+ await dep.stop(); // snapshot-stop (resumable)
95
+ await dep.destroy(); // permanent delete
96
+ ```
97
+
98
+ **Deploy programmatically (CI / agents)**
99
+
100
+ ```typescript
101
+ import { deployToSandbox } from '@mastra/deployer-sandbox';
102
+ import { VercelSandbox } from '@mastra/vercel';
103
+
104
+ const sandbox = new VercelSandbox({ sandboxName: 'ci-preview', ports: [4111] });
105
+ const deployment = await deployToSandbox({ sandbox, dir: '.mastra/output' });
106
+ console.info(deployment.url);
107
+ ```
108
+
109
+ **Resolve and route at runtime**
110
+
111
+ The server-only `@mastra/deployer-sandbox/client` export includes `getDeployment()` to resolve the current URL and manage the deployment (`stop()`, `destroy()`, `logs()`, with optional wake-on-demand), plus `createSandboxHandler()` and `createSandboxProxy()` helpers to serve a sandbox behind a stable URL on your own domain.
112
+
113
+ ### Patch Changes
114
+
115
+ - Updated dependencies [[`ec857fc`](https://github.com/mastra-ai/mastra/commit/ec857fc79c264b53b38e16478c789b7177f2ad59), [`e1f2fae`](https://github.com/mastra-ai/mastra/commit/e1f2faebaf048c3d4c2e2c01d293767c195d5794), [`63aa799`](https://github.com/mastra-ai/mastra/commit/63aa799c6b44eacc7806cda6846b7c5bbee06b37), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`76b7181`](https://github.com/mastra-ai/mastra/commit/76b71810366e6d90b9d3973149d1c7ba3659ffb9), [`0c0e8d7`](https://github.com/mastra-ai/mastra/commit/0c0e8d7becd4d1445c656b78d5d845f606c1ff9d), [`9f7c67a`](https://github.com/mastra-ai/mastra/commit/9f7c67abeeb52c41c51a9b5edee60b62afe7cd8d), [`3b65e68`](https://github.com/mastra-ai/mastra/commit/3b65e68d7f1c771c7a70eea42d83fefdd28cad88), [`e3868e2`](https://github.com/mastra-ai/mastra/commit/e3868e22babfffd0133771669ca724501c2dd58e)]:
116
+ - @mastra/core@1.52.0-alpha.5
117
+ - @mastra/deployer@1.52.0-alpha.5
package/LICENSE.md ADDED
@@ -0,0 +1,30 @@
1
+ Portions of this software are licensed as follows:
2
+
3
+ - All content that resides under any directory named "ee/" within this
4
+ repository, including but not limited to:
5
+ - `packages/core/src/auth/ee/`
6
+ - `packages/server/src/server/auth/ee/`
7
+ is licensed under the license defined in `ee/LICENSE`.
8
+
9
+ - All third-party components incorporated into the Mastra Software are
10
+ licensed under the original license provided by the owner of the
11
+ applicable component.
12
+
13
+ - Content outside of the above-mentioned directories or restrictions is
14
+ available under the "Apache License 2.0" as defined below.
15
+
16
+ # Apache License 2.0
17
+
18
+ Copyright (c) 2025 Kepler Software, Inc.
19
+
20
+ Licensed under the Apache License, Version 2.0 (the "License");
21
+ you may not use this file except in compliance with the License.
22
+ You may obtain a copy of the License at
23
+
24
+ http://www.apache.org/licenses/LICENSE-2.0
25
+
26
+ Unless required by applicable law or agreed to in writing, software
27
+ distributed under the License is distributed on an "AS IS" BASIS,
28
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29
+ See the License for the specific language governing permissions and
30
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @mastra/deployer-sandbox
2
+
3
+ Deploy a full Mastra server into any workspace sandbox that supports networking — and get a live public URL in seconds.
4
+
5
+ Works with any `WorkspaceSandbox` provider that implements the core `networking` capability (Vercel Sandbox, E2B, Daytona, ...). Positioning: **ephemeral environments** — instant previews, PR/CI smoke deploys, agent-built-app verification, multi-tenant untrusted instances. Not production hosting.
6
+
7
+ ## Usage
8
+
9
+ ```typescript
10
+ // src/mastra/index.ts
11
+ import { Mastra } from '@mastra/core/mastra';
12
+ import { SandboxDeployer } from '@mastra/deployer-sandbox';
13
+ import { VercelSandbox } from '@mastra/vercel';
14
+
15
+ const deployer = new SandboxDeployer({
16
+ sandbox: new VercelSandbox({
17
+ sandboxName: 'my-preview', // identity: redeploys resume this sandbox
18
+ timeout: 3_600_000,
19
+ ports: [4111],
20
+ }),
21
+ });
22
+
23
+ export const mastra = new Mastra({
24
+ // ...
25
+ deployer,
26
+ });
27
+ ```
28
+
29
+ ```bash
30
+ mastra build
31
+ ```
32
+
33
+ `mastra build` bundles the project and deploys it into the sandbox in one step, printing the live API and Studio URLs.
34
+
35
+ Manage the deployment afterward with `getDeployment()` from the server-only `client` export — the sandbox name is the identity, so this works from any process or codebase:
36
+
37
+ ```typescript
38
+ import { getDeployment } from '@mastra/deployer-sandbox/client';
39
+ import { VercelSandbox } from '@mastra/vercel';
40
+
41
+ const dep = await getDeployment({
42
+ sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }),
43
+ }); // never wakes a stopped sandbox
44
+ console.log(dep.status, dep.url);
45
+ await dep.stop(); // snapshot-stop (resumable)
46
+ await dep.destroy(); // permanent delete
47
+ ```
48
+
49
+ Provider tooling works too (for example `vercel sandbox ls|stop|rm`).
50
+
51
+ One-shot programmatic deploy (CI / agents), no bundler — takes a prebuilt output dir:
52
+
53
+ ```typescript
54
+ import { deployToSandbox } from '@mastra/deployer-sandbox';
55
+ import { VercelSandbox } from '@mastra/vercel';
56
+
57
+ const sandbox = new VercelSandbox({ sandboxName: 'ci-preview', ports: [4111] });
58
+ const deployment = await deployToSandbox({ sandbox, dir: '.mastra/output', port: 4111 });
59
+ console.log(deployment.url);
60
+ ```
61
+
62
+ Pass `wake: true` to resume a stopped sandbox before returning — useful in a route handler that fronts the sandbox. If the server isn't healthy after the resume (some providers restore the filesystem but not processes), the wake relaunches it:
63
+
64
+ ```typescript
65
+ import { getDeployment } from '@mastra/deployer-sandbox/client';
66
+ import { VercelSandbox } from '@mastra/vercel';
67
+
68
+ const sandbox = new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] });
69
+ const dep = await getDeployment({ sandbox, wake: true });
70
+ ```
71
+
72
+ See the Mastra docs for lifecycle, routing tiers, and security notes.
@@ -0,0 +1,10 @@
1
+ import type { SandboxAliasOptions } from './types.js';
2
+ /**
3
+ * Upsert a Vercel Edge Config item so a stable key always points at the
4
+ * current sandbox URL. Used for Tier 3 routing: apps read the key from Edge
5
+ * Config (e.g. in middleware) instead of hardcoding the rotating sandbox URL.
6
+ */
7
+ export declare function updateEdgeConfigAlias(options: SandboxAliasOptions & {
8
+ url: string;
9
+ }): Promise<void>;
10
+ //# sourceMappingURL=alias.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias.d.ts","sourceRoot":"","sources":["../src/alias.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,mBAAmB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BzG"}
@@ -0,0 +1,115 @@
1
+ 'use strict';
2
+
3
+ // src/shared.ts
4
+ var REMOTE_DIR_NAME = "mastra-app";
5
+ var DEFAULT_PORT = 4111;
6
+ var SERVER_SCRIPT = ".mastra-server.sh";
7
+ var SERVER_PIDFILE = ".mastra-server.pid";
8
+ var SERVER_LOGFILE = ".mastra-server.log";
9
+ var INSTALL_MARKER = ".mastra-install-hash";
10
+ async function getInfoSafe(sandbox) {
11
+ try {
12
+ return await sandbox.getInfo?.();
13
+ } catch {
14
+ return void 0;
15
+ }
16
+ }
17
+ async function resolveRemoteDir(sandbox, remoteDir) {
18
+ if (remoteDir) return remoteDir;
19
+ const result = await runInSandbox(sandbox, `printf %s "\${HOME:-$(pwd)}"`, { allowFailure: true });
20
+ const base = result.stdout.trim();
21
+ if (!base) {
22
+ throw new Error("Could not resolve the sandbox home directory. Pass `remoteDir` explicitly.");
23
+ }
24
+ return `${base}/${REMOTE_DIR_NAME}`;
25
+ }
26
+ function shellQuote(value) {
27
+ return `'${value.replace(/'/g, `'\\''`)}'`;
28
+ }
29
+ async function runInSandbox(sandbox, script, opts) {
30
+ if (!sandbox.executeCommand) {
31
+ throw new Error(
32
+ `Sandbox provider "${sandbox.provider}" does not support executeCommand, which is required for sandbox deploys.`
33
+ );
34
+ }
35
+ const result = await sandbox.executeCommand(
36
+ "sh",
37
+ ["-c", script],
38
+ opts?.timeout ? { timeout: opts.timeout } : void 0
39
+ );
40
+ if (!result.success && !opts?.allowFailure) {
41
+ const what = opts?.label ?? truncate(script, 120);
42
+ throw new Error(
43
+ `Command failed inside sandbox (exit ${result.exitCode}): ${what}
44
+ ${truncate(result.stderr || result.stdout, 4e3)}`
45
+ );
46
+ }
47
+ return { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode };
48
+ }
49
+ function truncate(value, max) {
50
+ return value.length > max ? `${value.slice(0, max)}\u2026 (truncated)` : value;
51
+ }
52
+ async function killPreviousServer(sandbox, remoteDir) {
53
+ const pidfile = shellQuote(`${remoteDir}/${SERVER_PIDFILE}`);
54
+ const script = [
55
+ `if [ -f ${pidfile} ]; then`,
56
+ ` pid="$(cat ${pidfile})"`,
57
+ ` kill "$pid" 2>/dev/null || true`,
58
+ // Wait up to ~5s for the old server to release the port, then force-kill.
59
+ ` i=0`,
60
+ ` while kill -0 "$pid" 2>/dev/null && [ "$i" -lt 50 ]; do sleep 0.1; i=$((i + 1)); done`,
61
+ ` kill -9 "$pid" 2>/dev/null || true`,
62
+ ` rm -f ${pidfile}`,
63
+ `fi`
64
+ ].join("\n");
65
+ await runInSandbox(sandbox, script, { allowFailure: true, timeout: 15e3 });
66
+ }
67
+ async function launchServer(sandbox, remoteDir) {
68
+ const script = `${remoteDir}/${SERVER_SCRIPT}`;
69
+ await runInSandbox(sandbox, `nohup sh ${shellQuote(script)} >/dev/null 2>&1 & echo launched`);
70
+ }
71
+ async function tailServerLog(sandbox, remoteDir, lines = 50) {
72
+ const logfile = `${remoteDir}/${SERVER_LOGFILE}`;
73
+ const result = await runInSandbox(
74
+ sandbox,
75
+ `tail -n ${Math.floor(lines)} ${shellQuote(logfile)} 2>/dev/null || true`,
76
+ {
77
+ allowFailure: true
78
+ }
79
+ );
80
+ return result.stdout;
81
+ }
82
+ async function waitForHealthy(url, opts = {}) {
83
+ const path = opts.path ?? "/api";
84
+ const timeoutMs = opts.timeoutMs ?? 6e4;
85
+ const intervalMs = opts.intervalMs ?? 1e3;
86
+ const deadline = Date.now() + timeoutMs;
87
+ while (Date.now() < deadline) {
88
+ try {
89
+ const res = await fetch(new URL(path, url), { signal: AbortSignal.timeout(intervalMs * 5) });
90
+ const providerError = res.status === 410 || res.headers.has("x-vercel-error");
91
+ if (res.status < 500 && !providerError) {
92
+ return true;
93
+ }
94
+ } catch {
95
+ }
96
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
97
+ }
98
+ return false;
99
+ }
100
+
101
+ exports.DEFAULT_PORT = DEFAULT_PORT;
102
+ exports.INSTALL_MARKER = INSTALL_MARKER;
103
+ exports.SERVER_LOGFILE = SERVER_LOGFILE;
104
+ exports.SERVER_PIDFILE = SERVER_PIDFILE;
105
+ exports.SERVER_SCRIPT = SERVER_SCRIPT;
106
+ exports.getInfoSafe = getInfoSafe;
107
+ exports.killPreviousServer = killPreviousServer;
108
+ exports.launchServer = launchServer;
109
+ exports.resolveRemoteDir = resolveRemoteDir;
110
+ exports.runInSandbox = runInSandbox;
111
+ exports.shellQuote = shellQuote;
112
+ exports.tailServerLog = tailServerLog;
113
+ exports.waitForHealthy = waitForHealthy;
114
+ //# sourceMappingURL=chunk-CSXC6CZL.cjs.map
115
+ //# sourceMappingURL=chunk-CSXC6CZL.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared.ts"],"names":[],"mappings":"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","file":"chunk-CSXC6CZL.cjs","sourcesContent":["import type { SandboxInfo, WorkspaceSandbox } from '@mastra/core/workspace';\n\n/** Directory name (under the sandbox user's home) that the app is deployed into by default. */\nexport const REMOTE_DIR_NAME = 'mastra-app';\n/** Default port the Mastra server listens on. */\nexport const DEFAULT_PORT = 4111;\n/** Launch script written into the remote dir. Re-running it restarts the server (e.g. after a wake). */\nexport const SERVER_SCRIPT = '.mastra-server.sh';\n/** Pidfile written by the launch script. */\nexport const SERVER_PIDFILE = '.mastra-server.pid';\n/** Server log file inside the remote dir. */\nexport const SERVER_LOGFILE = '.mastra-server.log';\n/** Marker recording the package.json hash of the last completed dependency install. */\nexport const INSTALL_MARKER = '.mastra-install-hash';\n\n/** getInfo may be sync or async, and may throw — normalize to `undefined` on failure. */\nexport async function getInfoSafe(sandbox: WorkspaceSandbox): Promise<SandboxInfo | undefined> {\n try {\n return await sandbox.getInfo?.();\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve the directory the app is (or will be) deployed into. Defaults to\n * `$HOME/mastra-app` resolved inside the sandbox — home directories persist\n * across snapshot stop/resume on providers that support it, unlike `/tmp`.\n * The sandbox must be running.\n */\nexport async function resolveRemoteDir(sandbox: WorkspaceSandbox, remoteDir?: string): Promise<string> {\n if (remoteDir) return remoteDir;\n const result = await runInSandbox(sandbox, `printf %s \"\\${HOME:-$(pwd)}\"`, { allowFailure: true });\n const base = result.stdout.trim();\n if (!base) {\n throw new Error('Could not resolve the sandbox home directory. Pass `remoteDir` explicitly.');\n }\n return `${base}/${REMOTE_DIR_NAME}`;\n}\n\n/** Single-quote a value for POSIX shells. */\nexport function shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\n/** Run a shell script string inside the sandbox and throw on failure. */\nexport async function runInSandbox(\n sandbox: WorkspaceSandbox,\n script: string,\n opts?: {\n allowFailure?: boolean;\n timeout?: number;\n /** Safe description used in error messages instead of the script itself. */\n label?: string;\n },\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n if (!sandbox.executeCommand) {\n throw new Error(\n `Sandbox provider \"${sandbox.provider}\" does not support executeCommand, which is required for sandbox deploys.`,\n );\n }\n // Run via `sh -c` (argv style): providers pass `command` straight to their\n // exec API as an executable, so a raw script string with spaces would fail.\n const result = await sandbox.executeCommand(\n 'sh',\n ['-c', script],\n opts?.timeout ? { timeout: opts.timeout } : undefined,\n );\n if (!result.success && !opts?.allowFailure) {\n // Never echo the full script back: it can contain secrets (env values)\n // or entire base64 upload chunks. Use the label or a bounded excerpt.\n const what = opts?.label ?? truncate(script, 120);\n throw new Error(\n `Command failed inside sandbox (exit ${result.exitCode}): ${what}\\n${truncate(result.stderr || result.stdout, 4_000)}`,\n );\n }\n return { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode };\n}\n\nfunction truncate(value: string, max: number): string {\n return value.length > max ? `${value.slice(0, max)}… (truncated)` : value;\n}\n\n/**\n * Kill the previously launched server (if any) using its pidfile, waiting for\n * the process to exit (bounded, then SIGKILL) so the replacement never races\n * the old server for the port. Safe when nothing is running.\n */\nexport async function killPreviousServer(sandbox: WorkspaceSandbox, remoteDir: string): Promise<void> {\n const pidfile = shellQuote(`${remoteDir}/${SERVER_PIDFILE}`);\n const script = [\n `if [ -f ${pidfile} ]; then`,\n ` pid=\"$(cat ${pidfile})\"`,\n ` kill \"$pid\" 2>/dev/null || true`,\n // Wait up to ~5s for the old server to release the port, then force-kill.\n ` i=0`,\n ` while kill -0 \"$pid\" 2>/dev/null && [ \"$i\" -lt 50 ]; do sleep 0.1; i=$((i + 1)); done`,\n ` kill -9 \"$pid\" 2>/dev/null || true`,\n ` rm -f ${pidfile}`,\n `fi`,\n ].join('\\n');\n await runInSandbox(sandbox, script, { allowFailure: true, timeout: 15_000 });\n}\n\n/**\n * Launch (or relaunch) the server by running the recorded launch script,\n * detached via nohup. Deliberately NOT `processes.spawn()`: provider process\n * handles follow the command's log stream, which would keep the calling\n * process's event loop alive for as long as the server runs. The server's\n * lifecycle is managed through its pidfile instead.\n */\nexport async function launchServer(sandbox: WorkspaceSandbox, remoteDir: string): Promise<void> {\n const script = `${remoteDir}/${SERVER_SCRIPT}`;\n await runInSandbox(sandbox, `nohup sh ${shellQuote(script)} >/dev/null 2>&1 & echo launched`);\n}\n\n/** Tail the server log from inside the sandbox. */\nexport async function tailServerLog(sandbox: WorkspaceSandbox, remoteDir: string, lines = 50): Promise<string> {\n const logfile = `${remoteDir}/${SERVER_LOGFILE}`;\n const result = await runInSandbox(\n sandbox,\n `tail -n ${Math.floor(lines)} ${shellQuote(logfile)} 2>/dev/null || true`,\n {\n allowFailure: true,\n },\n );\n return result.stdout;\n}\n\n/**\n * Poll `${url}${path}` until the server responds. Any HTTP status below 500\n * counts as \"the server is up\" — gateway errors (502/503) mean nothing is\n * listening on the port, and 410 is what some providers (e.g. Vercel) return\n * from their edge when the sandbox itself is stopped.\n */\nexport async function waitForHealthy(\n url: string,\n opts: { path?: string; timeoutMs?: number; intervalMs?: number } = {},\n): Promise<boolean> {\n const path = opts.path ?? '/api';\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const intervalMs = opts.intervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n try {\n const res = await fetch(new URL(path, url), { signal: AbortSignal.timeout(intervalMs * 5) });\n // A provider-edge error header means the response came from the sandbox\n // infrastructure (stopped/unreachable VM), not from the Mastra server.\n const providerError = res.status === 410 || res.headers.has('x-vercel-error');\n if (res.status < 500 && !providerError) {\n return true;\n }\n } catch {\n // Not reachable yet.\n }\n await new Promise(resolve => setTimeout(resolve, intervalMs));\n }\n return false;\n}\n"]}
@@ -0,0 +1,101 @@
1
+ // src/shared.ts
2
+ var REMOTE_DIR_NAME = "mastra-app";
3
+ var DEFAULT_PORT = 4111;
4
+ var SERVER_SCRIPT = ".mastra-server.sh";
5
+ var SERVER_PIDFILE = ".mastra-server.pid";
6
+ var SERVER_LOGFILE = ".mastra-server.log";
7
+ var INSTALL_MARKER = ".mastra-install-hash";
8
+ async function getInfoSafe(sandbox) {
9
+ try {
10
+ return await sandbox.getInfo?.();
11
+ } catch {
12
+ return void 0;
13
+ }
14
+ }
15
+ async function resolveRemoteDir(sandbox, remoteDir) {
16
+ if (remoteDir) return remoteDir;
17
+ const result = await runInSandbox(sandbox, `printf %s "\${HOME:-$(pwd)}"`, { allowFailure: true });
18
+ const base = result.stdout.trim();
19
+ if (!base) {
20
+ throw new Error("Could not resolve the sandbox home directory. Pass `remoteDir` explicitly.");
21
+ }
22
+ return `${base}/${REMOTE_DIR_NAME}`;
23
+ }
24
+ function shellQuote(value) {
25
+ return `'${value.replace(/'/g, `'\\''`)}'`;
26
+ }
27
+ async function runInSandbox(sandbox, script, opts) {
28
+ if (!sandbox.executeCommand) {
29
+ throw new Error(
30
+ `Sandbox provider "${sandbox.provider}" does not support executeCommand, which is required for sandbox deploys.`
31
+ );
32
+ }
33
+ const result = await sandbox.executeCommand(
34
+ "sh",
35
+ ["-c", script],
36
+ opts?.timeout ? { timeout: opts.timeout } : void 0
37
+ );
38
+ if (!result.success && !opts?.allowFailure) {
39
+ const what = opts?.label ?? truncate(script, 120);
40
+ throw new Error(
41
+ `Command failed inside sandbox (exit ${result.exitCode}): ${what}
42
+ ${truncate(result.stderr || result.stdout, 4e3)}`
43
+ );
44
+ }
45
+ return { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode };
46
+ }
47
+ function truncate(value, max) {
48
+ return value.length > max ? `${value.slice(0, max)}\u2026 (truncated)` : value;
49
+ }
50
+ async function killPreviousServer(sandbox, remoteDir) {
51
+ const pidfile = shellQuote(`${remoteDir}/${SERVER_PIDFILE}`);
52
+ const script = [
53
+ `if [ -f ${pidfile} ]; then`,
54
+ ` pid="$(cat ${pidfile})"`,
55
+ ` kill "$pid" 2>/dev/null || true`,
56
+ // Wait up to ~5s for the old server to release the port, then force-kill.
57
+ ` i=0`,
58
+ ` while kill -0 "$pid" 2>/dev/null && [ "$i" -lt 50 ]; do sleep 0.1; i=$((i + 1)); done`,
59
+ ` kill -9 "$pid" 2>/dev/null || true`,
60
+ ` rm -f ${pidfile}`,
61
+ `fi`
62
+ ].join("\n");
63
+ await runInSandbox(sandbox, script, { allowFailure: true, timeout: 15e3 });
64
+ }
65
+ async function launchServer(sandbox, remoteDir) {
66
+ const script = `${remoteDir}/${SERVER_SCRIPT}`;
67
+ await runInSandbox(sandbox, `nohup sh ${shellQuote(script)} >/dev/null 2>&1 & echo launched`);
68
+ }
69
+ async function tailServerLog(sandbox, remoteDir, lines = 50) {
70
+ const logfile = `${remoteDir}/${SERVER_LOGFILE}`;
71
+ const result = await runInSandbox(
72
+ sandbox,
73
+ `tail -n ${Math.floor(lines)} ${shellQuote(logfile)} 2>/dev/null || true`,
74
+ {
75
+ allowFailure: true
76
+ }
77
+ );
78
+ return result.stdout;
79
+ }
80
+ async function waitForHealthy(url, opts = {}) {
81
+ const path = opts.path ?? "/api";
82
+ const timeoutMs = opts.timeoutMs ?? 6e4;
83
+ const intervalMs = opts.intervalMs ?? 1e3;
84
+ const deadline = Date.now() + timeoutMs;
85
+ while (Date.now() < deadline) {
86
+ try {
87
+ const res = await fetch(new URL(path, url), { signal: AbortSignal.timeout(intervalMs * 5) });
88
+ const providerError = res.status === 410 || res.headers.has("x-vercel-error");
89
+ if (res.status < 500 && !providerError) {
90
+ return true;
91
+ }
92
+ } catch {
93
+ }
94
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
95
+ }
96
+ return false;
97
+ }
98
+
99
+ export { DEFAULT_PORT, INSTALL_MARKER, SERVER_LOGFILE, SERVER_PIDFILE, SERVER_SCRIPT, getInfoSafe, killPreviousServer, launchServer, resolveRemoteDir, runInSandbox, shellQuote, tailServerLog, waitForHealthy };
100
+ //# sourceMappingURL=chunk-Z636GNUQ.js.map
101
+ //# sourceMappingURL=chunk-Z636GNUQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared.ts"],"names":[],"mappings":"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","file":"chunk-Z636GNUQ.js","sourcesContent":["import type { SandboxInfo, WorkspaceSandbox } from '@mastra/core/workspace';\n\n/** Directory name (under the sandbox user's home) that the app is deployed into by default. */\nexport const REMOTE_DIR_NAME = 'mastra-app';\n/** Default port the Mastra server listens on. */\nexport const DEFAULT_PORT = 4111;\n/** Launch script written into the remote dir. Re-running it restarts the server (e.g. after a wake). */\nexport const SERVER_SCRIPT = '.mastra-server.sh';\n/** Pidfile written by the launch script. */\nexport const SERVER_PIDFILE = '.mastra-server.pid';\n/** Server log file inside the remote dir. */\nexport const SERVER_LOGFILE = '.mastra-server.log';\n/** Marker recording the package.json hash of the last completed dependency install. */\nexport const INSTALL_MARKER = '.mastra-install-hash';\n\n/** getInfo may be sync or async, and may throw — normalize to `undefined` on failure. */\nexport async function getInfoSafe(sandbox: WorkspaceSandbox): Promise<SandboxInfo | undefined> {\n try {\n return await sandbox.getInfo?.();\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve the directory the app is (or will be) deployed into. Defaults to\n * `$HOME/mastra-app` resolved inside the sandbox — home directories persist\n * across snapshot stop/resume on providers that support it, unlike `/tmp`.\n * The sandbox must be running.\n */\nexport async function resolveRemoteDir(sandbox: WorkspaceSandbox, remoteDir?: string): Promise<string> {\n if (remoteDir) return remoteDir;\n const result = await runInSandbox(sandbox, `printf %s \"\\${HOME:-$(pwd)}\"`, { allowFailure: true });\n const base = result.stdout.trim();\n if (!base) {\n throw new Error('Could not resolve the sandbox home directory. Pass `remoteDir` explicitly.');\n }\n return `${base}/${REMOTE_DIR_NAME}`;\n}\n\n/** Single-quote a value for POSIX shells. */\nexport function shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\n/** Run a shell script string inside the sandbox and throw on failure. */\nexport async function runInSandbox(\n sandbox: WorkspaceSandbox,\n script: string,\n opts?: {\n allowFailure?: boolean;\n timeout?: number;\n /** Safe description used in error messages instead of the script itself. */\n label?: string;\n },\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n if (!sandbox.executeCommand) {\n throw new Error(\n `Sandbox provider \"${sandbox.provider}\" does not support executeCommand, which is required for sandbox deploys.`,\n );\n }\n // Run via `sh -c` (argv style): providers pass `command` straight to their\n // exec API as an executable, so a raw script string with spaces would fail.\n const result = await sandbox.executeCommand(\n 'sh',\n ['-c', script],\n opts?.timeout ? { timeout: opts.timeout } : undefined,\n );\n if (!result.success && !opts?.allowFailure) {\n // Never echo the full script back: it can contain secrets (env values)\n // or entire base64 upload chunks. Use the label or a bounded excerpt.\n const what = opts?.label ?? truncate(script, 120);\n throw new Error(\n `Command failed inside sandbox (exit ${result.exitCode}): ${what}\\n${truncate(result.stderr || result.stdout, 4_000)}`,\n );\n }\n return { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode };\n}\n\nfunction truncate(value: string, max: number): string {\n return value.length > max ? `${value.slice(0, max)}… (truncated)` : value;\n}\n\n/**\n * Kill the previously launched server (if any) using its pidfile, waiting for\n * the process to exit (bounded, then SIGKILL) so the replacement never races\n * the old server for the port. Safe when nothing is running.\n */\nexport async function killPreviousServer(sandbox: WorkspaceSandbox, remoteDir: string): Promise<void> {\n const pidfile = shellQuote(`${remoteDir}/${SERVER_PIDFILE}`);\n const script = [\n `if [ -f ${pidfile} ]; then`,\n ` pid=\"$(cat ${pidfile})\"`,\n ` kill \"$pid\" 2>/dev/null || true`,\n // Wait up to ~5s for the old server to release the port, then force-kill.\n ` i=0`,\n ` while kill -0 \"$pid\" 2>/dev/null && [ \"$i\" -lt 50 ]; do sleep 0.1; i=$((i + 1)); done`,\n ` kill -9 \"$pid\" 2>/dev/null || true`,\n ` rm -f ${pidfile}`,\n `fi`,\n ].join('\\n');\n await runInSandbox(sandbox, script, { allowFailure: true, timeout: 15_000 });\n}\n\n/**\n * Launch (or relaunch) the server by running the recorded launch script,\n * detached via nohup. Deliberately NOT `processes.spawn()`: provider process\n * handles follow the command's log stream, which would keep the calling\n * process's event loop alive for as long as the server runs. The server's\n * lifecycle is managed through its pidfile instead.\n */\nexport async function launchServer(sandbox: WorkspaceSandbox, remoteDir: string): Promise<void> {\n const script = `${remoteDir}/${SERVER_SCRIPT}`;\n await runInSandbox(sandbox, `nohup sh ${shellQuote(script)} >/dev/null 2>&1 & echo launched`);\n}\n\n/** Tail the server log from inside the sandbox. */\nexport async function tailServerLog(sandbox: WorkspaceSandbox, remoteDir: string, lines = 50): Promise<string> {\n const logfile = `${remoteDir}/${SERVER_LOGFILE}`;\n const result = await runInSandbox(\n sandbox,\n `tail -n ${Math.floor(lines)} ${shellQuote(logfile)} 2>/dev/null || true`,\n {\n allowFailure: true,\n },\n );\n return result.stdout;\n}\n\n/**\n * Poll `${url}${path}` until the server responds. Any HTTP status below 500\n * counts as \"the server is up\" — gateway errors (502/503) mean nothing is\n * listening on the port, and 410 is what some providers (e.g. Vercel) return\n * from their edge when the sandbox itself is stopped.\n */\nexport async function waitForHealthy(\n url: string,\n opts: { path?: string; timeoutMs?: number; intervalMs?: number } = {},\n): Promise<boolean> {\n const path = opts.path ?? '/api';\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const intervalMs = opts.intervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n try {\n const res = await fetch(new URL(path, url), { signal: AbortSignal.timeout(intervalMs * 5) });\n // A provider-edge error header means the response came from the sandbox\n // infrastructure (stopped/unreachable VM), not from the Mastra server.\n const providerError = res.status === 410 || res.headers.has('x-vercel-error');\n if (res.status < 500 && !providerError) {\n return true;\n }\n } catch {\n // Not reachable yet.\n }\n await new Promise(resolve => setTimeout(resolve, intervalMs));\n }\n return false;\n}\n"]}