@mastra/platform-workspace 1.5.0 → 1.6.0-alpha.1

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/README.md CHANGED
@@ -8,6 +8,23 @@ Mastra Platform workspace provider. It gives agents environment-scoped sandbox e
8
8
  npm install @mastra/platform-workspace
9
9
  ```
10
10
 
11
+ ## Configuration
12
+
13
+ All options can be passed to the constructor or read from environment variables:
14
+
15
+ | Option | Env var | Required |
16
+ | ----------------- | ------------------------------ | ------------------------------- |
17
+ | `accessToken` | `MASTRA_PLATFORM_ACCESS_TOKEN` | Yes |
18
+ | `projectId` | `MASTRA_PROJECT_ID` | Yes |
19
+ | `environmentId` | `MASTRA_ENVIRONMENT_ID` | Yes (sandbox) |
20
+ | `actingUserId` | — | No (sandbox) |
21
+ | `sandboxProvider` | `SANDBOX_PROVIDER` | No (sandbox, defaults to `e2b`) |
22
+ | `bucketName` | `MASTRA_PLATFORM_BUCKET_NAME` | Yes (filesystem) |
23
+
24
+ The proxy URL defaults to `https://workspaces.mastra.ai`. Set `MASTRA_PLATFORM_REGION` to `us` or `eu` (case-insensitive) to route to the regional replica at `https://workspaces.us.mastra.ai` or `https://workspaces.eu.mastra.ai`. An explicit `MASTRA_WORKSPACE_PROXY_URL` (useful for staging) overrides both.
25
+
26
+ Requests to the proxy are authenticated with `Authorization: Bearer <accessToken>`. For sandbox requests authenticated with a project access token, set `actingUserId` to the stable opaque user subject from your authentication system. It is sent as `x-acting-user-id` for token partitioning and attribution; it is not an authorization claim.
27
+
11
28
  ## Usage
12
29
 
13
30
  ```typescript
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;CAC/D;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,KAAK,CAAC;AAWhD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7E;AAUD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,qBAAqB;IAKjE,WAAW;IACX,SAAS;IACT,YAAY;IACZ,QAAQ;IACR,eAAe;IACf,SAAS;IACT,QAAQ;IACR,KAAK;EAER;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,gGAAgG;IAChG,IAAI,EAAE,MAAM,CAAC;CACd;AAkBD,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2HAA2H;IAC3H,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,yGAAyG;IACzG,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1C,YAAY,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EASvC;CACF;AAED,qBAAa,cAAc;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,qFAAqF;IACrF,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC;IAE7B,YAAY,OAAO,EAAE,qBAAqB,EAUzC;IAEK,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,QAAQ,CAAC,CAEnF;IAEK,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,QAAQ,CAAC,CAE3F;YAEa,aAAa;CA2B5B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;CAC/D;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,KAAK,CAAC;AA6BhD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7E;AAUD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,qBAAqB;IAKjE,WAAW;IACX,SAAS;IACT,YAAY;IACZ,QAAQ;IACR,eAAe;IACf,SAAS;IACT,QAAQ;IACR,KAAK;EAER;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,gGAAgG;IAChG,IAAI,EAAE,MAAM,CAAC;CACd;AAkBD,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2HAA2H;IAC3H,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,yGAAyG;IACzG,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1C,YAAY,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EASvC;CACF;AAED,qBAAa,cAAc;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,qFAAqF;IACrF,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC;IAE7B,YAAY,OAAO,EAAE,qBAAqB,EAUzC;IAEK,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,QAAQ,CAAC,CAEnF;IAEK,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,QAAQ,CAAC,CAE3F;YAEa,aAAa;CA2B5B"}
package/dist/index.cjs CHANGED
@@ -31,6 +31,23 @@ let util = require("util");
31
31
  let crypto = require("crypto");
32
32
  //#region src/client.ts
33
33
  const DEFAULT_PROXY_URL = "https://workspaces.mastra.ai";
34
+ const REGIONAL_PROXY_URLS = {
35
+ us: "https://workspaces.us.mastra.ai",
36
+ eu: "https://workspaces.eu.mastra.ai"
37
+ };
38
+ /**
39
+ * Resolves the workspace proxy URL, preferring an explicit
40
+ * `MASTRA_WORKSPACE_PROXY_URL` override, then a regional replica selected by
41
+ * `MASTRA_PLATFORM_REGION` (case-insensitive `us` or `eu`), then the global
42
+ * default. Unknown region values fall through to the global default.
43
+ */
44
+ function resolveProxyUrl() {
45
+ const override = process.env.MASTRA_WORKSPACE_PROXY_URL?.trim();
46
+ if (override) return override;
47
+ const region = process.env.MASTRA_PLATFORM_REGION?.trim().toLowerCase();
48
+ if (region === "us" || region === "eu") return REGIONAL_PROXY_URLS[region];
49
+ return DEFAULT_PROXY_URL;
50
+ }
34
51
  /**
35
52
  * Default per-request timeout for calls to the workspace proxy. Applied only
36
53
  * when the caller doesn't already pass an `AbortSignal`. Long-running routes
@@ -53,7 +70,7 @@ function resolvePlatformOptions(options) {
53
70
  accessToken: requireOption(options.accessToken ?? process.env.MASTRA_PLATFORM_ACCESS_TOKEN, "accessToken"),
54
71
  projectId: requireOption(options.projectId ?? process.env.MASTRA_PROJECT_ID, "projectId"),
55
72
  actingUserId: options.actingUserId?.trim() || void 0,
56
- proxyUrl: (process.env.MASTRA_WORKSPACE_PROXY_URL ?? DEFAULT_PROXY_URL).replace(/\/$/, ""),
73
+ proxyUrl: resolveProxyUrl().replace(/\/$/, ""),
57
74
  sandboxProvider: resolveSandboxProvider(configuredSandboxProvider),
58
75
  sessionId: options.sessionId,
59
76
  threadId: options.threadId,
@@ -2015,6 +2032,14 @@ const BUILD_TOKEN_ENV = "MASTRA_REPOSITORY_ACCESS_TOKEN";
2015
2032
  const CLONE_URL_ALLOWED_CHARS = /^[a-z0-9:/._-]+$/i;
2016
2033
  const CLONE_URL_HOST_PATTERN = /^[a-z0-9.-]+$/i;
2017
2034
  const CLONE_URL_SEGMENT_PATTERN = /^[\w.-]+$/;
2035
+ /** Last default-branch head resolved per clone URL, shared across resolvers in this process. */
2036
+ const lastKnownHeads = /* @__PURE__ */ new Map();
2037
+ const MAX_LAST_KNOWN_HEADS = 1e3;
2038
+ function rememberHead(cloneUrl, sha) {
2039
+ lastKnownHeads.delete(cloneUrl);
2040
+ lastKnownHeads.set(cloneUrl, sha);
2041
+ if (lastKnownHeads.size > MAX_LAST_KNOWN_HEADS) lastKnownHeads.delete(lastKnownHeads.keys().next().value);
2042
+ }
2018
2043
  /**
2019
2044
  * Create a lazy repository template definition for PlatformSandbox, mirroring
2020
2045
  * `@mastra/e2b`'s `createRepoTemplate`: pass the sandbox context through and a
@@ -2025,8 +2050,10 @@ const CLONE_URL_SEGMENT_PATTERN = /^[\w.-]+$/;
2025
2050
  * what gets cloned and what the template is identified by can't drift — and
2026
2051
  * pins repositories to their current default-branch commit. Private repository
2027
2052
  * credentials are used for head resolution and sent to the provider as
2028
- * transient build envs; they never enter the serialized definition. If the
2029
- * repository or its head cannot be resolved, the resolver keeps `cpuCount` and
2053
+ * transient build envs; they never enter the serialized definition. A failed
2054
+ * head lookup reuses the last head resolved for the same clone URL in this
2055
+ * process. If the repository cannot be resolved, or no head has been resolved
2056
+ * yet, the resolver keeps `cpuCount` and
2030
2057
  * `memoryMB` in a resources-only template so the sandbox still boots at the
2031
2058
  * requested size, and the caller's runtime setup materializes the checkout.
2032
2059
  */
@@ -2057,16 +2084,30 @@ function createRepoTemplate(options) {
2057
2084
  }
2058
2085
  const token = access.authorization?.token;
2059
2086
  let headError;
2060
- const sha = await (token ? resolveHead(cloneUrl, token) : resolveHead(cloneUrl)).catch((error) => {
2087
+ const resolved = await (token ? resolveHead(cloneUrl, token) : resolveHead(cloneUrl)).catch((error) => {
2061
2088
  headError = error;
2062
2089
  });
2063
- if (!sha || !SHA_PATTERN.test(sha)) {
2064
- console.warn("[platform-workspace] repo template skipped: could not resolve default-branch head", {
2090
+ let sha;
2091
+ if (resolved && SHA_PATTERN.test(resolved)) {
2092
+ sha = resolved;
2093
+ rememberHead(cloneUrl, sha);
2094
+ } else {
2095
+ const lastKnown = lastKnownHeads.get(cloneUrl);
2096
+ if (!lastKnown) {
2097
+ console.warn("[platform-workspace] repo template skipped: could not resolve default-branch head", {
2098
+ cloneUrl,
2099
+ sha: resolved,
2100
+ error: redactSecrets(headError)
2101
+ });
2102
+ return resourcesOnly();
2103
+ }
2104
+ console.warn("[platform-workspace] repo template pinned to the last known default-branch head", {
2065
2105
  cloneUrl,
2066
- sha,
2106
+ sha: lastKnown,
2107
+ resolved,
2067
2108
  error: redactSecrets(headError)
2068
2109
  });
2069
- return resourcesOnly();
2110
+ sha = lastKnown;
2070
2111
  }
2071
2112
  const workingDirectory = options.workingDirectory === void 0 ? void 0 : trimTrailingSlashes(assertWorkingDirectory(options.workingDirectory));
2072
2113
  const repoDir = repoDirName(cloneUrl);