@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/dist/index.js CHANGED
@@ -7,6 +7,23 @@ import { promisify } from "util";
7
7
  import { createHash } from "crypto";
8
8
  //#region src/client.ts
9
9
  const DEFAULT_PROXY_URL = "https://workspaces.mastra.ai";
10
+ const REGIONAL_PROXY_URLS = {
11
+ us: "https://workspaces.us.mastra.ai",
12
+ eu: "https://workspaces.eu.mastra.ai"
13
+ };
14
+ /**
15
+ * Resolves the workspace proxy URL, preferring an explicit
16
+ * `MASTRA_WORKSPACE_PROXY_URL` override, then a regional replica selected by
17
+ * `MASTRA_PLATFORM_REGION` (case-insensitive `us` or `eu`), then the global
18
+ * default. Unknown region values fall through to the global default.
19
+ */
20
+ function resolveProxyUrl() {
21
+ const override = process.env.MASTRA_WORKSPACE_PROXY_URL?.trim();
22
+ if (override) return override;
23
+ const region = process.env.MASTRA_PLATFORM_REGION?.trim().toLowerCase();
24
+ if (region === "us" || region === "eu") return REGIONAL_PROXY_URLS[region];
25
+ return DEFAULT_PROXY_URL;
26
+ }
10
27
  /**
11
28
  * Default per-request timeout for calls to the workspace proxy. Applied only
12
29
  * when the caller doesn't already pass an `AbortSignal`. Long-running routes
@@ -29,7 +46,7 @@ function resolvePlatformOptions(options) {
29
46
  accessToken: requireOption(options.accessToken ?? process.env.MASTRA_PLATFORM_ACCESS_TOKEN, "accessToken"),
30
47
  projectId: requireOption(options.projectId ?? process.env.MASTRA_PROJECT_ID, "projectId"),
31
48
  actingUserId: options.actingUserId?.trim() || void 0,
32
- proxyUrl: (process.env.MASTRA_WORKSPACE_PROXY_URL ?? DEFAULT_PROXY_URL).replace(/\/$/, ""),
49
+ proxyUrl: resolveProxyUrl().replace(/\/$/, ""),
33
50
  sandboxProvider: resolveSandboxProvider(configuredSandboxProvider),
34
51
  sessionId: options.sessionId,
35
52
  threadId: options.threadId,
@@ -1991,6 +2008,14 @@ const BUILD_TOKEN_ENV = "MASTRA_REPOSITORY_ACCESS_TOKEN";
1991
2008
  const CLONE_URL_ALLOWED_CHARS = /^[a-z0-9:/._-]+$/i;
1992
2009
  const CLONE_URL_HOST_PATTERN = /^[a-z0-9.-]+$/i;
1993
2010
  const CLONE_URL_SEGMENT_PATTERN = /^[\w.-]+$/;
2011
+ /** Last default-branch head resolved per clone URL, shared across resolvers in this process. */
2012
+ const lastKnownHeads = /* @__PURE__ */ new Map();
2013
+ const MAX_LAST_KNOWN_HEADS = 1e3;
2014
+ function rememberHead(cloneUrl, sha) {
2015
+ lastKnownHeads.delete(cloneUrl);
2016
+ lastKnownHeads.set(cloneUrl, sha);
2017
+ if (lastKnownHeads.size > MAX_LAST_KNOWN_HEADS) lastKnownHeads.delete(lastKnownHeads.keys().next().value);
2018
+ }
1994
2019
  /**
1995
2020
  * Create a lazy repository template definition for PlatformSandbox, mirroring
1996
2021
  * `@mastra/e2b`'s `createRepoTemplate`: pass the sandbox context through and a
@@ -2001,8 +2026,10 @@ const CLONE_URL_SEGMENT_PATTERN = /^[\w.-]+$/;
2001
2026
  * what gets cloned and what the template is identified by can't drift — and
2002
2027
  * pins repositories to their current default-branch commit. Private repository
2003
2028
  * credentials are used for head resolution and sent to the provider as
2004
- * transient build envs; they never enter the serialized definition. If the
2005
- * repository or its head cannot be resolved, the resolver keeps `cpuCount` and
2029
+ * transient build envs; they never enter the serialized definition. A failed
2030
+ * head lookup reuses the last head resolved for the same clone URL in this
2031
+ * process. If the repository cannot be resolved, or no head has been resolved
2032
+ * yet, the resolver keeps `cpuCount` and
2006
2033
  * `memoryMB` in a resources-only template so the sandbox still boots at the
2007
2034
  * requested size, and the caller's runtime setup materializes the checkout.
2008
2035
  */
@@ -2033,16 +2060,30 @@ function createRepoTemplate(options) {
2033
2060
  }
2034
2061
  const token = access.authorization?.token;
2035
2062
  let headError;
2036
- const sha = await (token ? resolveHead(cloneUrl, token) : resolveHead(cloneUrl)).catch((error) => {
2063
+ const resolved = await (token ? resolveHead(cloneUrl, token) : resolveHead(cloneUrl)).catch((error) => {
2037
2064
  headError = error;
2038
2065
  });
2039
- if (!sha || !SHA_PATTERN.test(sha)) {
2040
- console.warn("[platform-workspace] repo template skipped: could not resolve default-branch head", {
2066
+ let sha;
2067
+ if (resolved && SHA_PATTERN.test(resolved)) {
2068
+ sha = resolved;
2069
+ rememberHead(cloneUrl, sha);
2070
+ } else {
2071
+ const lastKnown = lastKnownHeads.get(cloneUrl);
2072
+ if (!lastKnown) {
2073
+ console.warn("[platform-workspace] repo template skipped: could not resolve default-branch head", {
2074
+ cloneUrl,
2075
+ sha: resolved,
2076
+ error: redactSecrets(headError)
2077
+ });
2078
+ return resourcesOnly();
2079
+ }
2080
+ console.warn("[platform-workspace] repo template pinned to the last known default-branch head", {
2041
2081
  cloneUrl,
2042
- sha,
2082
+ sha: lastKnown,
2083
+ resolved,
2043
2084
  error: redactSecrets(headError)
2044
2085
  });
2045
- return resourcesOnly();
2086
+ sha = lastKnown;
2046
2087
  }
2047
2088
  const workingDirectory = options.workingDirectory === void 0 ? void 0 : trimTrailingSlashes(assertWorkingDirectory(options.workingDirectory));
2048
2089
  const repoDir = repoDirName(cloneUrl);