@mastra/factory 0.2.1 → 0.2.2-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.
Files changed (59) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/auth.d.ts +2 -2
  3. package/dist/auth.d.ts.map +1 -1
  4. package/dist/auth.js +22 -2
  5. package/dist/auth.js.map +1 -1
  6. package/dist/factory.d.ts.map +1 -1
  7. package/dist/factory.js +411 -244
  8. package/dist/factory.js.map +1 -1
  9. package/dist/index.js +411 -244
  10. package/dist/index.js.map +1 -1
  11. package/dist/integrations/github/integration.js +85 -37
  12. package/dist/integrations/github/integration.js.map +1 -1
  13. package/dist/integrations/github/routes.d.ts.map +1 -1
  14. package/dist/integrations/github/routes.js +85 -37
  15. package/dist/integrations/github/routes.js.map +1 -1
  16. package/dist/integrations/github/sandbox.d.ts +2 -0
  17. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  18. package/dist/integrations/github/sandbox.js +28 -8
  19. package/dist/integrations/github/sandbox.js.map +1 -1
  20. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  21. package/dist/integrations/platform/github/integration.js +119 -39
  22. package/dist/integrations/platform/github/integration.js.map +1 -1
  23. package/dist/routes/config.d.ts.map +1 -1
  24. package/dist/routes/config.js +1 -4
  25. package/dist/routes/config.js.map +1 -1
  26. package/dist/routes/surface.js +1 -4
  27. package/dist/routes/surface.js.map +1 -1
  28. package/dist/routes/work-items.js.map +1 -1
  29. package/dist/rules/binding-context.js.map +1 -1
  30. package/dist/rules/dispatcher.d.ts.map +1 -1
  31. package/dist/rules/dispatcher.js +7 -1
  32. package/dist/rules/dispatcher.js.map +1 -1
  33. package/dist/rules/processor.js.map +1 -1
  34. package/dist/rules/tools.js.map +1 -1
  35. package/dist/spa-static.d.ts.map +1 -1
  36. package/dist/spa-static.js +1 -0
  37. package/dist/spa-static.js.map +1 -1
  38. package/dist/storage/domains/source-control/base.d.ts +9 -0
  39. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  40. package/dist/storage/domains/source-control/base.js +4 -0
  41. package/dist/storage/domains/source-control/base.js.map +1 -1
  42. package/dist/storage/domains/source-control/inmemory.d.ts +4 -0
  43. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  44. package/dist/storage/domains/source-control/inmemory.js +4 -0
  45. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  46. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  47. package/dist/storage/domains/work-items/base.js +20 -4
  48. package/dist/storage/domains/work-items/base.js.map +1 -1
  49. package/dist/storage/domains/work-items/metrics.js.map +1 -1
  50. package/dist/timing.d.ts +15 -0
  51. package/dist/timing.d.ts.map +1 -0
  52. package/dist/timing.js +27 -0
  53. package/dist/timing.js.map +1 -0
  54. package/dist/workspace.d.ts +2 -3
  55. package/dist/workspace.d.ts.map +1 -1
  56. package/dist/workspace.js +104 -65
  57. package/dist/workspace.js.map +1 -1
  58. package/factory-skills/factory-review/SKILL.md +9 -2
  59. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -24558,6 +24558,31 @@ import {
24558
24558
  isSessionProvider,
24559
24559
  isSSOProvider
24560
24560
  } from "@mastra/core/server";
24561
+
24562
+ // src/timing.ts
24563
+ async function timedPhase(phase, fn) {
24564
+ const start = performance.now();
24565
+ try {
24566
+ return await fn();
24567
+ } finally {
24568
+ process.stderr.write(`[factory:timing] ${phase} ${Math.round(performance.now() - start)}ms
24569
+ `);
24570
+ }
24571
+ }
24572
+ async function timedAboveThreshold(phase, thresholdMs, fn) {
24573
+ const start = performance.now();
24574
+ try {
24575
+ return await fn();
24576
+ } finally {
24577
+ const elapsed = performance.now() - start;
24578
+ if (elapsed > thresholdMs) {
24579
+ process.stderr.write(`[factory:timing] slow ${phase} ${Math.round(elapsed)}ms
24580
+ `);
24581
+ }
24582
+ }
24583
+ }
24584
+
24585
+ // src/auth.ts
24561
24586
  function sanitizeReturnTo(raw) {
24562
24587
  if (!raw) return "/";
24563
24588
  if (!raw.startsWith("/")) return "/";
@@ -24846,11 +24871,15 @@ function createFactoryAuthGate(provider) {
24846
24871
  if (c.req.method === "POST" && path3 === "/web/github/webhook") {
24847
24872
  return next();
24848
24873
  }
24849
- if (path3 === "/signin" || path3.startsWith("/assets/")) {
24874
+ if (path3 === "/signin" || path3.startsWith("/assets/") || path3 === "/manifest.webmanifest" || path3 === "/mastra.svg") {
24850
24875
  return next();
24851
24876
  }
24852
24877
  const token = getBearerToken(c.req.header("Authorization"));
24853
- const user = await authenticateRequest(provider, token, c.req.raw);
24878
+ const user = await timedAboveThreshold(
24879
+ "auth.gate.authenticate",
24880
+ 1e3,
24881
+ () => authenticateRequest(provider, token, c.req.raw)
24882
+ );
24854
24883
  if (user) {
24855
24884
  await ensureUserOrg(provider, user);
24856
24885
  c.set(FACTORY_AUTH_USER_KEY, user);
@@ -25532,8 +25561,23 @@ async function teardownProjectSandbox(options) {
25532
25561
  function shellQuote(value) {
25533
25562
  return `'` + value.split(`'`).join(`'\\''`) + `'`;
25534
25563
  }
25535
- async function sh(sandbox, script) {
25536
- return sandbox.executeCommand("sh", ["-c", script]);
25564
+ var DEFAULT_COMMAND_TIMEOUT_MS = 15 * 6e4;
25565
+ var CHECKOUT_COMMAND_TIMEOUT_MS = 5 * 6e4;
25566
+ async function sh(sandbox, script, options = {}) {
25567
+ const timeoutMs = options.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS;
25568
+ let timer;
25569
+ const hangGuard = new Promise((_, reject) => {
25570
+ timer = setTimeout(() => {
25571
+ const phase = options.phase ? ` during ${options.phase}` : "";
25572
+ reject(new Error(`Sandbox command timed out after ${Math.round(timeoutMs / 1e3)}s${phase}.`));
25573
+ }, timeoutMs);
25574
+ timer.unref?.();
25575
+ });
25576
+ try {
25577
+ return await Promise.race([sandbox.executeCommand("sh", ["-c", script], { timeout: timeoutMs }), hangGuard]);
25578
+ } finally {
25579
+ clearTimeout(timer);
25580
+ }
25537
25581
  }
25538
25582
  var MaterializeError = class extends Error {
25539
25583
  constructor(message, code) {
@@ -25570,7 +25614,8 @@ async function materializeRepo(options) {
25570
25614
  );
25571
25615
  }
25572
25616
  const authUrl = tokenUrl(repo, token);
25573
- const alreadyMaterialized = Boolean(sandboxRow.materializedAt) || await hasExistingCheckout(sandbox, workdir, repo);
25617
+ const alreadyMaterialized = await hasExistingCheckout(sandbox, workdir, repo);
25618
+ let succeeded = false;
25574
25619
  try {
25575
25620
  if (!alreadyMaterialized) {
25576
25621
  reportProgress(onProgress, {
@@ -25579,7 +25624,8 @@ async function materializeRepo(options) {
25579
25624
  });
25580
25625
  const clone = await sh(
25581
25626
  sandbox,
25582
- `git clone --depth=1 --single-branch --branch ${shellQuote(repoInfo.defaultBranch)} ${shellQuote(authUrl)} ${shellQuote(workdir)}`
25627
+ `git clone --depth=1 --single-branch --branch ${shellQuote(repoInfo.defaultBranch)} ${shellQuote(authUrl)} ${shellQuote(workdir)}`,
25628
+ { phase: "repository clone" }
25583
25629
  );
25584
25630
  if (clone.exitCode !== 0) {
25585
25631
  throw classifyGitFailure(clone, "clone-failed");
@@ -25590,13 +25636,14 @@ async function materializeRepo(options) {
25590
25636
  if (setUrl.exitCode !== 0) {
25591
25637
  throw new MaterializeError(`Failed to set git remote: ${setUrl.stderr}`, "pull-failed");
25592
25638
  }
25593
- const pull = await sh(sandbox, `git -C ${shellQuote(workdir)} pull --ff-only`);
25639
+ const pull = await sh(sandbox, `git -C ${shellQuote(workdir)} pull --ff-only`, { phase: "repository pull" });
25594
25640
  if (pull.exitCode !== 0) {
25595
25641
  throw classifyGitFailure(pull, "pull-failed");
25596
25642
  }
25597
25643
  }
25644
+ succeeded = true;
25598
25645
  } finally {
25599
- await scrubRemote(sandbox, workdir, repo, alreadyMaterialized);
25646
+ await scrubRemote(sandbox, workdir, repo, succeeded);
25600
25647
  }
25601
25648
  reportProgress(onProgress, { phase: "finalizing", message: "Finalizing workspace\u2026" });
25602
25649
  await storage.markMaterialized({ id: sandboxRow.id });
@@ -25627,7 +25674,8 @@ async function checkoutSessionBranch(sandbox, workdir, {
25627
25674
  if (setUrl.exitCode !== 0) throw classifyGitFailure(setUrl, "pull-failed");
25628
25675
  const fetch2 = await sh(
25629
25676
  sandbox,
25630
- `git -C ${shellQuote(workdir)} fetch origin ${shellQuote(baseBranch)} && git -C ${shellQuote(workdir)} checkout -b ${shellQuote(branch)} FETCH_HEAD`
25677
+ `git -C ${shellQuote(workdir)} fetch origin ${shellQuote(baseBranch)} && git -C ${shellQuote(workdir)} checkout -b ${shellQuote(branch)} FETCH_HEAD`,
25678
+ { timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS, phase: "branch checkout" }
25631
25679
  );
25632
25680
  if (fetch2.exitCode !== 0) throw classifyGitFailure(fetch2, "clone-failed");
25633
25681
  } finally {
@@ -25751,7 +25799,7 @@ function computeWorktreePath(repoWorkdir, branch) {
25751
25799
  }
25752
25800
  async function runWorktreeSetup(sandbox, worktreePath, command) {
25753
25801
  const result = await sh(sandbox, `cd ${shellQuote(worktreePath)} && { ${command}
25754
- }`);
25802
+ }`, { phase: "worktree setup" });
25755
25803
  if (result.exitCode !== 0) {
25756
25804
  const detail = (result.stderr.trim() || result.stdout.trim()).slice(-2e3);
25757
25805
  throw new WorktreeError(`Setup command failed (exit ${result.exitCode}): ${detail}`, "setup-failed");
@@ -26484,43 +26532,56 @@ function buildGithubRoutes(options) {
26484
26532
  handler: async (c) => {
26485
26533
  const resolved = await resolveOrgTenant(loose(c), auth);
26486
26534
  if ("response" in resolved) return resolved.response;
26487
- const installs = await github.sourceControlStorage.installations.list({ orgId: resolved.tenant.orgId });
26535
+ const orgId = resolved.tenant.orgId;
26536
+ const installs = await github.sourceControlStorage.installations.list({ orgId });
26488
26537
  const query = (c.req.query("q") ?? "").toLowerCase();
26489
- const repos = [];
26538
+ const listed = await Promise.all(
26539
+ installs.map(async (inst) => {
26540
+ try {
26541
+ return { inst, list: await github.listInstallationRepos(Number(inst.externalId)) };
26542
+ } catch (err) {
26543
+ if (err.status !== 404) throw err;
26544
+ console.error(`[Mastra Factory] pruning stale GitHub installation ${inst.externalId} (404 from GitHub)`);
26545
+ await github.sourceControlStorage.installations.delete({ orgId, id: inst.id });
26546
+ return { inst, list: [] };
26547
+ }
26548
+ })
26549
+ );
26550
+ const matches = [];
26490
26551
  const seenRepositoryIds = /* @__PURE__ */ new Set();
26491
- for (const inst of installs) {
26492
- let list;
26493
- try {
26494
- list = await github.listInstallationRepos(Number(inst.externalId));
26495
- } catch (err) {
26496
- if (err.status !== 404) throw err;
26497
- console.error(`[Mastra Factory] pruning stale GitHub installation ${inst.externalId} (404 from GitHub)`);
26498
- await github.sourceControlStorage.installations.delete({ orgId: resolved.tenant.orgId, id: inst.id });
26499
- continue;
26500
- }
26552
+ for (const { inst, list } of listed) {
26501
26553
  for (const repo of list) {
26502
26554
  if (query && !repo.fullName.toLowerCase().includes(query)) continue;
26503
26555
  if (seenRepositoryIds.has(repo.id)) continue;
26504
26556
  seenRepositoryIds.add(repo.id);
26505
- const repository = await github.sourceControlStorage.repositories.upsert({
26506
- orgId: resolved.tenant.orgId,
26507
- input: {
26508
- installationId: inst.id,
26509
- externalId: repo.id.toString(),
26510
- slug: repo.fullName,
26511
- defaultBranch: isValidGitRef2(repo.defaultBranch) ? repo.defaultBranch : "main",
26512
- providerMetadata: { private: repo.private, owner: repo.owner }
26513
- }
26514
- });
26515
- repos.push({
26516
- ...repo,
26517
- installationStorageId: inst.id,
26518
- repositoryStorageId: repository.id,
26519
- sandboxProvider: fleet.provider,
26520
- sandboxWorkdir: fleet.computeWorkdir(repo.fullName)
26521
- });
26557
+ matches.push({ inst, repo });
26522
26558
  }
26523
26559
  }
26560
+ const repos = new Array(matches.length);
26561
+ const upsertConcurrency = 10;
26562
+ for (let start = 0; start < matches.length; start += upsertConcurrency) {
26563
+ await Promise.all(
26564
+ matches.slice(start, start + upsertConcurrency).map(async ({ inst, repo }, offset) => {
26565
+ const repository = await github.sourceControlStorage.repositories.upsert({
26566
+ orgId,
26567
+ input: {
26568
+ installationId: inst.id,
26569
+ externalId: repo.id.toString(),
26570
+ slug: repo.fullName,
26571
+ defaultBranch: isValidGitRef2(repo.defaultBranch) ? repo.defaultBranch : "main",
26572
+ providerMetadata: { private: repo.private, owner: repo.owner }
26573
+ }
26574
+ });
26575
+ repos[start + offset] = {
26576
+ ...repo,
26577
+ installationStorageId: inst.id,
26578
+ repositoryStorageId: repository.id,
26579
+ sandboxProvider: fleet.provider,
26580
+ sandboxWorkdir: fleet.computeWorkdir(repo.fullName)
26581
+ };
26582
+ })
26583
+ );
26584
+ }
26524
26585
  return c.json({ repos });
26525
26586
  }
26526
26587
  })
@@ -26851,8 +26912,25 @@ async function loadOrCreateSandboxRow(github, project, userId) {
26851
26912
  return github.sourceControlStorage.sandboxes.getOrCreate({ projectRepository: project, userId });
26852
26913
  }
26853
26914
  async function prepareProject(options) {
26854
- const { github, fleet, project, userId, onProgress } = options;
26855
- const sandboxRow = await loadOrCreateSandboxRow(github, project, userId);
26915
+ const { github, fleet, userId, onProgress } = options;
26916
+ let project = options.project;
26917
+ if (project.sandboxProvider !== fleet.provider) {
26918
+ const sandboxWorkdir = fleet.computeWorkdir(project.repository.slug);
26919
+ await github.sourceControlStorage.projectRepositories.update({
26920
+ orgId: project.installation.orgId,
26921
+ id: project.id,
26922
+ input: { sandboxProvider: fleet.provider, sandboxWorkdir }
26923
+ });
26924
+ project = { ...project, sandboxProvider: fleet.provider, sandboxWorkdir };
26925
+ }
26926
+ let sandboxRow = await loadOrCreateSandboxRow(github, project, userId);
26927
+ if (sandboxRow.sandboxWorkdir !== project.sandboxWorkdir) {
26928
+ await github.sourceControlStorage.sandboxes.setWorkdir({
26929
+ id: sandboxRow.id,
26930
+ sandboxWorkdir: project.sandboxWorkdir
26931
+ });
26932
+ sandboxRow = { ...sandboxRow, sandboxWorkdir: project.sandboxWorkdir, materializedAt: null };
26933
+ }
26856
26934
  const access = await github.versionControl.getRepositoryAccess({
26857
26935
  orgId: project.installation.orgId,
26858
26936
  repositoryId: project.repository.id
@@ -28326,6 +28404,17 @@ function retryDelay(error, fallbackMs) {
28326
28404
  // src/integrations/platform/github/integration.ts
28327
28405
  var PAGE_SIZE = 30;
28328
28406
  var API_PREFIX2 = "/v1/server";
28407
+ var INSTALLATION_REPOS_CACHE_TTL_MS = 3e4;
28408
+ var REPOSITORY_ACCESS_CACHE_TTL_MS = 5 * 6e4;
28409
+ var MAX_CACHE_ENTRIES = 1e3;
28410
+ function setBounded(cache, key, value) {
28411
+ cache.delete(key);
28412
+ cache.set(key, value);
28413
+ if (cache.size > MAX_CACHE_ENTRIES) {
28414
+ const oldest = cache.keys().next().value;
28415
+ if (oldest !== void 0) cache.delete(oldest);
28416
+ }
28417
+ }
28329
28418
  var REPOSITORY_TOKEN_PERMISSIONS = {
28330
28419
  contents: "write",
28331
28420
  issues: "write",
@@ -28345,6 +28434,10 @@ var PlatformGithubIntegration = class {
28345
28434
  #pollingIntervalMs;
28346
28435
  #storage;
28347
28436
  #integrationStorage;
28437
+ /** installationId → cached repository listing (TTL-bounded). */
28438
+ #installationReposCache = /* @__PURE__ */ new Map();
28439
+ /** `orgId:repositoryId` → cached repository access (TTL-bounded). */
28440
+ #repositoryAccessCache = /* @__PURE__ */ new Map();
28348
28441
  intake = {
28349
28442
  resolveIntakeDispatch: (input) => this.#resolveIntakeDispatch(input),
28350
28443
  listSources: async ({ orgId, userId }) => {
@@ -28475,6 +28568,10 @@ var PlatformGithubIntegration = class {
28475
28568
  )
28476
28569
  ),
28477
28570
  getRepositoryAccess: async ({ orgId, repositoryId }) => {
28571
+ const cacheKey = `${orgId}:${repositoryId}`;
28572
+ const cached = this.#repositoryAccessCache.get(cacheKey);
28573
+ if (cached && cached.expiresAt > Date.now()) return cached.access;
28574
+ this.#repositoryAccessCache.delete(cacheKey);
28478
28575
  const repository = await this.storage.repositories.get({ orgId, id: repositoryId });
28479
28576
  if (!repository) throw new Error("Version-control repository not found.");
28480
28577
  const cloneUrl = `https://github.com/${repository.slug}.git`;
@@ -28488,10 +28585,15 @@ var PlatformGithubIntegration = class {
28488
28585
  `${API_PREFIX2}/github-app/installations/${installationId}/token`,
28489
28586
  { repositories: [repositoryName], permissions: REPOSITORY_TOKEN_PERMISSIONS }
28490
28587
  );
28491
- return {
28588
+ const access = {
28492
28589
  cloneUrl,
28493
28590
  authorization: { scheme: "bearer", token: token.token }
28494
28591
  };
28592
+ setBounded(this.#repositoryAccessCache, cacheKey, {
28593
+ access,
28594
+ expiresAt: Date.now() + REPOSITORY_ACCESS_CACHE_TTL_MS
28595
+ });
28596
+ return access;
28495
28597
  },
28496
28598
  listPullRequests: (input) => this.#listPullRequests(input),
28497
28599
  getPullRequest: (input) => this.#getPullRequest(input),
@@ -28786,8 +28888,16 @@ var PlatformGithubIntegration = class {
28786
28888
  }
28787
28889
  }
28788
28890
  async listInstallationRepos(installationId) {
28891
+ const cached = this.#installationReposCache.get(installationId);
28892
+ if (cached && cached.expiresAt > Date.now()) return cached.repos;
28893
+ this.#installationReposCache.delete(installationId);
28789
28894
  const result = await this.#client.request("GET", `${API_PREFIX2}/github-app/installations/${installationId}/repositories`);
28790
- return result.repositories.map((repository) => ({ ...repository, installationId }));
28895
+ const repos = result.repositories.map((repository) => ({ ...repository, installationId }));
28896
+ setBounded(this.#installationReposCache, installationId, {
28897
+ repos,
28898
+ expiresAt: Date.now() + INSTALLATION_REPOS_CACHE_TTL_MS
28899
+ });
28900
+ return repos;
28791
28901
  }
28792
28902
  async mintInstallationToken(installationId) {
28793
28903
  const repositories = await this.listInstallationRepos(installationId);
@@ -31922,7 +32032,7 @@ var ConfigRoutes = class extends Route {
31922
32032
  const record = await context.storage.get({ orgId: context.orgId, userId: context.userId });
31923
32033
  if (!resourceId) return c.json({ config: readStoredOMConfig(record) });
31924
32034
  const session = await controller.getSessionByResource?.(resourceId, scope);
31925
- if (!session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
32035
+ if (!session) return c.json({ config: readStoredOMConfig(record) });
31926
32036
  await hydrateSessionMemorySettings(session, record);
31927
32037
  return c.json({ config: readOMConfig(session) });
31928
32038
  } catch (error) {
@@ -31956,7 +32066,6 @@ var ConfigRoutes = class extends Route {
31956
32066
  if ("response" in context) return context.response;
31957
32067
  try {
31958
32068
  const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : void 0;
31959
- if (resourceId && !session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
31960
32069
  const otherRole = session ? role === "observer" ? session.om.reflector : session.om.observer : void 0;
31961
32070
  const otherRoleCurrentModelId = otherRole?.modelId() ?? null;
31962
32071
  await session?.om[role].switchModel({ modelId });
@@ -31998,7 +32107,6 @@ var ConfigRoutes = class extends Route {
31998
32107
  if ("response" in context) return context.response;
31999
32108
  try {
32000
32109
  const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : void 0;
32001
- if (resourceId && !session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
32002
32110
  if (observation !== void 0 && session) {
32003
32111
  await session.state.set({ observationThreshold: observation });
32004
32112
  await session.thread.setSetting({ key: "observationThreshold", value: observation });
@@ -32043,7 +32151,6 @@ var ConfigRoutes = class extends Route {
32043
32151
  if ("response" in context) return context.response;
32044
32152
  try {
32045
32153
  const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : void 0;
32046
- if (resourceId && !session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
32047
32154
  if (session) {
32048
32155
  await session.state.set({ observeAttachments: value });
32049
32156
  await session.thread.setSetting({ key: "observeAttachments", value });
@@ -33827,7 +33934,8 @@ var FACTORY_GOVERNANCE_SCHEMAS = [
33827
33934
  name: "factory_deferred_decisions_tenant_key_unique",
33828
33935
  columns: ["org_id", "factory_project_id", "idempotency_key"]
33829
33936
  }
33830
- ]
33937
+ ],
33938
+ indexes: [{ name: "factory_deferred_decisions_claim_idx", columns: ["status", "created_at"] }]
33831
33939
  },
33832
33940
  {
33833
33941
  name: "factory_run_bindings",
@@ -33844,7 +33952,17 @@ var FACTORY_GOVERNANCE_SCHEMAS = [
33844
33952
  status: { type: "text" },
33845
33953
  created_at: { type: "timestamp" },
33846
33954
  revoked_at: { type: "timestamp", nullable: true }
33847
- }
33955
+ },
33956
+ indexes: [
33957
+ // Exact-address lookups run on every processor message; status filter is
33958
+ // applied on top of the address columns.
33959
+ {
33960
+ name: "factory_run_bindings_session_idx",
33961
+ columns: ["factory_project_id", "thread_id", "resource_id", "session_id"]
33962
+ },
33963
+ // Restart reconciler enumerates active bindings across all tenants.
33964
+ { name: "factory_run_bindings_status_idx", columns: ["status"] }
33965
+ ]
33848
33966
  },
33849
33967
  {
33850
33968
  name: "factory_tool_result_cursors",
@@ -33881,7 +33999,8 @@ var FACTORY_GOVERNANCE_SCHEMAS = [
33881
33999
  name: "factory_pending_starts_tenant_kickoff_unique",
33882
34000
  columns: ["org_id", "factory_project_id", "kickoff_key"]
33883
34001
  }
33884
- ]
34002
+ ],
34003
+ indexes: [{ name: "factory_pending_starts_claim_idx", columns: ["status", "created_at"] }]
33885
34004
  }
33886
34005
  ];
33887
34006
  function toBinding(row) {
@@ -33962,7 +34081,11 @@ var WorkItemsStorage = class extends FactoryStorageDomain3 {
33962
34081
  }
33963
34082
  async #claimLeases(table, input, map) {
33964
34083
  const claim = () => this.storage.withTransaction(async (ops) => {
33965
- const candidates = await ops.findMany(table, {}, { orderBy: [["created_at", "asc"]] });
34084
+ const candidates = await ops.findMany(
34085
+ table,
34086
+ { status: { in: ["pending", "retry", "leased"] } },
34087
+ { orderBy: [["created_at", "asc"]], limit: Math.max(input.limit * 5, 50) }
34088
+ );
33966
34089
  const claimed = [];
33967
34090
  for (const candidate of candidates) {
33968
34091
  if (claimed.length >= input.limit) break;
@@ -36448,6 +36571,12 @@ var FactoryDecisionDispatcher = class {
36448
36571
  (candidate) => candidate.id === record.bindingId && candidate.status === "active"
36449
36572
  );
36450
36573
  if (!binding) throw new Error("Prepared Factory binding is unavailable or revoked.");
36574
+ const item = await this.#storage.get({ orgId: record.orgId, id: binding.workItemId });
36575
+ const startedBy = item?.sessions[binding.role]?.startedBy;
36576
+ if (!startedBy) throw new Error(`Factory binding ${binding.id} has no authenticated session owner.`);
36577
+ await this.#primeCredentials?.({ orgId: record.orgId, userId: startedBy });
36578
+ const requestContext = new RequestContext2();
36579
+ requestContext.set("user", { workosId: startedBy, organizationId: record.orgId });
36451
36580
  const session = await this.#requireSession(binding);
36452
36581
  await awaitNotification(
36453
36582
  await session.sendNotificationSignal(
@@ -36460,7 +36589,7 @@ var FactoryDecisionDispatcher = class {
36460
36589
  sourceId: record.id,
36461
36590
  dedupeKey: `factory-kickoff:${record.kickoffKey}`
36462
36591
  },
36463
- { ifActive: { behavior: "deliver" }, ifIdle: { behavior: "wake" } }
36592
+ { ifActive: { behavior: "deliver" }, ifIdle: { behavior: "wake" }, requestContext }
36464
36593
  ),
36465
36594
  true
36466
36595
  );
@@ -36941,6 +37070,7 @@ var MIME = {
36941
37070
  ".mjs": "text/javascript; charset=utf-8",
36942
37071
  ".css": "text/css; charset=utf-8",
36943
37072
  ".json": "application/json",
37073
+ ".webmanifest": "application/manifest+json",
36944
37074
  ".map": "application/json",
36945
37075
  ".svg": "image/svg+xml",
36946
37076
  ".png": "image/png",
@@ -38714,6 +38844,10 @@ var SourceControlStorage = class extends FactoryStorageDomain11 {
38714
38844
  }
38715
38845
  },
38716
38846
  getById: ({ id }) => getSandbox(id),
38847
+ setWorkdir: async ({ id, sandboxWorkdir }) => {
38848
+ await requireSandbox(id);
38849
+ await db().updateMany(SANDBOXES, { id }, { sandbox_workdir: sandboxWorkdir, materialized_at: null });
38850
+ },
38717
38851
  setSandboxId: async ({ id, sandboxId }) => {
38718
38852
  await requireSandbox(id);
38719
38853
  await db().updateMany(SANDBOXES, { id }, { sandbox_id: sandboxId });
@@ -38924,6 +39058,7 @@ function createWorkspaceFactory(options = {}) {
38924
39058
  const { sandbox: sandboxConfig, github, fleet, workItems } = options;
38925
39059
  const isLocalSandbox = sandboxConfig?.machine instanceof LocalSandbox;
38926
39060
  const githubTokenInjectors = /* @__PURE__ */ new Map();
39061
+ const inflightMaterializations = /* @__PURE__ */ new Map();
38927
39062
  return async ({ requestContext, mastra, skillExtension }) => {
38928
39063
  const effectiveSkillExtension = skillExtension ?? factorySkillExtension;
38929
39064
  const ctx = requestContext.get("controller");
@@ -38991,65 +39126,84 @@ function createWorkspaceFactory(options = {}) {
38991
39126
  }
38992
39127
  } catch {
38993
39128
  }
38994
- const access = await github.versionControl.getRepositoryAccess({
38995
- orgId: session.orgId,
38996
- repositoryId: repository.id
38997
- });
38998
- const token = access.authorization?.token;
38999
- if (!token) throw new Error("Repository access did not include a bearer token for the Factory session");
39000
- let patKind = "default";
39001
- if (workItems) {
39002
- try {
39003
- const address = getFactorySessionAddress(requestContext);
39004
- const runBinding = address ? await workItems.findRunBindingBySession(address) : null;
39005
- if (runBinding?.role === "review" && runBinding.orgId === session.orgId) patKind = "reviewer";
39006
- } catch {
39007
- }
39008
- }
39009
- const ghCliToken = await getGithubPat(() => github.integrationStorage, session.orgId, patKind) ?? token;
39010
- const sandbox = await fleet.ensureSandbox(
39011
- binding,
39012
- { GH_TOKEN: ghCliToken },
39013
- void 0,
39014
- isLocalSandbox ? { workingDirectory: workdir } : {}
39015
- );
39016
- await materializeRepo({
39017
- row: { id: session.id, sandboxWorkdir: workdir, materializedAt: session.materializedAt },
39018
- repoInfo: { repoFullName, defaultBranch: repository.defaultBranch },
39019
- sandbox,
39020
- token,
39021
- storage: storage.sessions
39022
- });
39023
- await checkoutSessionBranch(sandbox, workdir, {
39024
- branch: session.branch,
39025
- baseBranch: session.baseBranch || projectRepository.branch || repository.defaultBranch,
39026
- token,
39027
- repoFullName
39028
- });
39029
- if (projectRepository.setupCommand) await runWorktreeSetup(sandbox, workdir, projectRepository.setupCommand);
39030
- const injectGithubToken2 = (freshToken) => {
39031
- if (!sandbox.setEnvironmentVariable) {
39032
- throw new Error("The active sandbox provider does not support runtime GitHub token refresh.");
39129
+ const materialize = async () => {
39130
+ const access = await github.versionControl.getRepositoryAccess({
39131
+ orgId: session.orgId,
39132
+ repositoryId: repository.id
39133
+ });
39134
+ const token = access.authorization?.token;
39135
+ if (!token) throw new Error("Repository access did not include a bearer token for the Factory session");
39136
+ let patKind = "default";
39137
+ if (workItems) {
39138
+ try {
39139
+ const address = getFactorySessionAddress(requestContext);
39140
+ const runBinding = address ? await workItems.findRunBindingBySession(address) : null;
39141
+ if (runBinding?.role === "review" && runBinding.orgId === session.orgId) patKind = "reviewer";
39142
+ } catch {
39143
+ }
39033
39144
  }
39034
- sandbox.setEnvironmentVariable("GH_TOKEN", freshToken);
39035
- const registered = githubTokenInjectors.get(workspaceId);
39036
- if (registered) registered.ghToken = freshToken;
39145
+ const ghCliToken = await getGithubPat(() => github.integrationStorage, session.orgId, patKind) ?? token;
39146
+ const sandbox = await fleet.ensureSandbox(
39147
+ binding,
39148
+ { GH_TOKEN: ghCliToken },
39149
+ void 0,
39150
+ isLocalSandbox ? { workingDirectory: workdir } : {}
39151
+ );
39152
+ await materializeRepo({
39153
+ row: { id: session.id, sandboxWorkdir: workdir, materializedAt: session.materializedAt },
39154
+ repoInfo: { repoFullName, defaultBranch: repository.defaultBranch },
39155
+ sandbox,
39156
+ token,
39157
+ storage: storage.sessions
39158
+ });
39159
+ await checkoutSessionBranch(sandbox, workdir, {
39160
+ branch: session.branch,
39161
+ baseBranch: session.baseBranch || projectRepository.branch || repository.defaultBranch,
39162
+ token,
39163
+ repoFullName
39164
+ });
39165
+ if (projectRepository.setupCommand) await runWorktreeSetup(sandbox, workdir, projectRepository.setupCommand);
39166
+ const injectGithubToken2 = (freshToken) => {
39167
+ if (!sandbox.setEnvironmentVariable) {
39168
+ throw new Error("The active sandbox provider does not support runtime GitHub token refresh.");
39169
+ }
39170
+ sandbox.setEnvironmentVariable("GH_TOKEN", freshToken);
39171
+ const registered = githubTokenInjectors.get(workspaceId);
39172
+ if (registered) registered.ghToken = freshToken;
39173
+ };
39174
+ githubTokenInjectors.set(workspaceId, { inject: injectGithubToken2, patKind, ghToken: ghCliToken });
39175
+ registerGithubTokenInjector(requestContext, injectGithubToken2);
39176
+ registerGithubPatKind(requestContext, patKind);
39177
+ const filesystem = new SandboxFilesystem2({ sandbox, workdir });
39178
+ const projectSkillPaths = [path2.join(configDir, "skills"), ".claude/skills", ".agents/skills"];
39179
+ const skillPaths = [...effectiveSkillExtension?.paths ?? [], ...projectSkillPaths];
39180
+ return new Workspace({
39181
+ id: workspaceId,
39182
+ name: "Mastra Code Factory Session Workspace",
39183
+ filesystem,
39184
+ sandbox,
39185
+ tools: MASTRACODE_WORKSPACE_TOOLS,
39186
+ skills: skillPaths,
39187
+ skillSource: effectiveSkillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem
39188
+ });
39037
39189
  };
39038
- githubTokenInjectors.set(workspaceId, { inject: injectGithubToken2, patKind, ghToken: ghCliToken });
39039
- registerGithubTokenInjector(requestContext, injectGithubToken2);
39040
- registerGithubPatKind(requestContext, patKind);
39041
- const filesystem = new SandboxFilesystem2({ sandbox, workdir });
39042
- const projectSkillPaths = [path2.join(configDir, "skills"), ".claude/skills", ".agents/skills"];
39043
- const skillPaths = [...effectiveSkillExtension?.paths ?? [], ...projectSkillPaths];
39044
- return new Workspace({
39045
- id: workspaceId,
39046
- name: "Mastra Code Factory Session Workspace",
39047
- filesystem,
39048
- sandbox,
39049
- tools: MASTRACODE_WORKSPACE_TOOLS,
39050
- skills: skillPaths,
39051
- skillSource: effectiveSkillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem
39052
- });
39190
+ const inflight = inflightMaterializations.get(workspaceId);
39191
+ if (inflight) {
39192
+ const workspace = await inflight;
39193
+ const registered = githubTokenInjectors.get(workspaceId);
39194
+ if (registered) {
39195
+ registerGithubTokenInjector(requestContext, registered.inject);
39196
+ registerGithubPatKind(requestContext, registered.patKind);
39197
+ }
39198
+ return workspace;
39199
+ }
39200
+ const materialization = materialize();
39201
+ inflightMaterializations.set(workspaceId, materialization);
39202
+ try {
39203
+ return await materialization;
39204
+ } finally {
39205
+ inflightMaterializations.delete(workspaceId);
39206
+ }
39053
39207
  };
39054
39208
  }
39055
39209
  var getFactoryWorkspace = createWorkspaceFactory();
@@ -39194,9 +39348,12 @@ var MastraFactory = class {
39194
39348
  registerSandboxReattach(fleet);
39195
39349
  const stateSigner = createStateSigner(this.#config.stateSecret);
39196
39350
  if (auth && hasAuthInit(auth)) {
39197
- await auth.init({ database: storage.authDatabase?.(), publicUrl: publicOrigin, allowedOrigins });
39351
+ await timedPhase(
39352
+ "prepare.auth.init",
39353
+ () => auth.init({ database: storage.authDatabase?.(), publicUrl: publicOrigin, allowedOrigins })
39354
+ );
39198
39355
  }
39199
- await storage.init();
39356
+ await timedPhase("prepare.storage.init", () => storage.init());
39200
39357
  if (auth) {
39201
39358
  registerTenantCredentialResolver(modelCredentialsStorage);
39202
39359
  }
@@ -39264,153 +39421,160 @@ var MastraFactory = class {
39264
39421
  const toolIntegrations = integrationRegistrations.filter(
39265
39422
  ({ integration }) => integration.agentTools || integration.sessionTools
39266
39423
  );
39267
- const prepared = await prepareAgentControllerMount({
39268
- controllerId: CONTROLLER_ID,
39269
- workspace: createWorkspaceFactory({
39270
- ...this.#config.sandbox ? { sandbox: this.#config.sandbox } : {},
39271
- ...githubIntegration ? { github: githubIntegration } : {},
39272
- ...workItemsStorage ? { workItems: workItemsStorage } : {},
39273
- fleet
39274
- }),
39275
- disableGithubSignals: true,
39276
- // Memory settings live in the factory's `memory-settings` app table (per
39277
- // org/user), so the host machine's TUI settings.json must not seed them.
39278
- disableSettingsOmSeed: true,
39279
- storage: storage.getMastraStorage(),
39280
- ...mastraStorageBackend ? { storageBackend: mastraStorageBackend } : {},
39281
- ...factoryProcessor ? { inputProcessors: [factoryProcessor] } : {},
39282
- ...vector ? { vector } : {},
39283
- ...toolIntegrations.length > 0 || workItemsStorage && transitionService ? {
39284
- extraTools: async ({ requestContext }) => {
39285
- const tools = {};
39286
- const toolOwners = /* @__PURE__ */ new Map();
39287
- const mergeTools = (ownerId, contributed) => {
39288
- for (const [name, tool] of Object.entries(contributed)) {
39289
- const owner = toolOwners.get(name);
39290
- if (owner) {
39291
- throw new Error(
39292
- `MastraFactory: integration tool '${name}' from '${ownerId}' conflicts with '${owner}'.`
39293
- );
39424
+ const prepared = await timedPhase(
39425
+ "prepare.controllerMount",
39426
+ () => prepareAgentControllerMount({
39427
+ controllerId: CONTROLLER_ID,
39428
+ workspace: createWorkspaceFactory({
39429
+ ...this.#config.sandbox ? { sandbox: this.#config.sandbox } : {},
39430
+ ...githubIntegration ? { github: githubIntegration } : {},
39431
+ ...workItemsStorage ? { workItems: workItemsStorage } : {},
39432
+ fleet
39433
+ }),
39434
+ disableGithubSignals: true,
39435
+ // Memory settings live in the factory's `memory-settings` app table (per
39436
+ // org/user), so the host machine's TUI settings.json must not seed them.
39437
+ disableSettingsOmSeed: true,
39438
+ storage: storage.getMastraStorage(),
39439
+ ...mastraStorageBackend ? { storageBackend: mastraStorageBackend } : {},
39440
+ ...factoryProcessor ? { inputProcessors: [factoryProcessor] } : {},
39441
+ ...vector ? { vector } : {},
39442
+ ...toolIntegrations.length > 0 || workItemsStorage && transitionService ? {
39443
+ extraTools: async ({ requestContext }) => {
39444
+ const tools = {};
39445
+ const toolOwners = /* @__PURE__ */ new Map();
39446
+ const mergeTools = (ownerId, contributed) => {
39447
+ for (const [name, tool] of Object.entries(contributed)) {
39448
+ const owner = toolOwners.get(name);
39449
+ if (owner) {
39450
+ throw new Error(
39451
+ `MastraFactory: integration tool '${name}' from '${ownerId}' conflicts with '${owner}'.`
39452
+ );
39453
+ }
39454
+ toolOwners.set(name, ownerId);
39455
+ tools[name] = tool;
39294
39456
  }
39295
- toolOwners.set(name, ownerId);
39296
- tools[name] = tool;
39457
+ };
39458
+ if (workItemsStorage && transitionService) {
39459
+ mergeTools(
39460
+ "factory",
39461
+ await createFactoryTransitionTools({
39462
+ requestContext,
39463
+ storage: workItemsStorage,
39464
+ transitionService
39465
+ })
39466
+ );
39297
39467
  }
39298
- };
39299
- if (workItemsStorage && transitionService) {
39300
- mergeTools(
39301
- "factory",
39302
- await createFactoryTransitionTools({ requestContext, storage: workItemsStorage, transitionService })
39303
- );
39304
- }
39305
- for (const { integration, ready, ensureReady } of toolIntegrations) {
39306
- if (!ready && ensureReady) {
39307
- try {
39308
- await ensureReady();
39309
- } catch {
39310
- continue;
39468
+ for (const { integration, ready, ensureReady } of toolIntegrations) {
39469
+ if (!ready && ensureReady) {
39470
+ try {
39471
+ await ensureReady();
39472
+ } catch {
39473
+ continue;
39474
+ }
39475
+ }
39476
+ if (integration.agentTools) {
39477
+ mergeTools(integration.id, await integration.agentTools({ requestContext }));
39478
+ }
39479
+ if (integration.sessionTools) {
39480
+ mergeTools(integration.id, integration.sessionTools({ requestContext }));
39311
39481
  }
39312
39482
  }
39313
- if (integration.agentTools) {
39314
- mergeTools(integration.id, await integration.agentTools({ requestContext }));
39315
- }
39316
- if (integration.sessionTools) {
39317
- mergeTools(integration.id, integration.sessionTools({ requestContext }));
39318
- }
39483
+ return tools;
39484
+ }
39485
+ } : {},
39486
+ postToolObserver: async (toolContext) => {
39487
+ const requestContext = toolContext.context?.requestContext;
39488
+ if (requestContext) {
39489
+ await observeAgentGitAction({
39490
+ audit: auditDomain,
39491
+ toolContext: { ...toolContext, context: requestContext }
39492
+ });
39319
39493
  }
39320
- return tools;
39321
- }
39322
- } : {},
39323
- postToolObserver: async (toolContext) => {
39324
- const requestContext = toolContext.context?.requestContext;
39325
- if (requestContext) {
39326
- await observeAgentGitAction({
39494
+ await Promise.all(
39495
+ integrations.map(async (integration) => {
39496
+ if (!integration.postToolObserver) return;
39497
+ try {
39498
+ await integration.postToolObserver({ toolContext, requestContext });
39499
+ } catch (error) {
39500
+ console.warn(`[factory] Integration '${integration.id}' post-tool observer failed:`, error);
39501
+ }
39502
+ })
39503
+ );
39504
+ },
39505
+ ...pubsub ? { pubsub, crossProcessPubSub: true } : {},
39506
+ buildApiRoutes: ({ controller, authStorage }) => [
39507
+ // Public `/auth/*` routes (login/callback/logout/me). Folded in as
39508
+ // `apiRoutes` (not plain Hono routes) because the entry can't touch the
39509
+ // Hono app the deployer generates. `requiresAuth: false`; the gate
39510
+ // skips `/auth/*`.
39511
+ ...auth ? buildAuthRoutes(auth, { publicUrl: publicOrigin }) : [],
39512
+ // Custom `/web/*` routes (fs / config / integrations / factory / audit).
39513
+ ...assembleFactoryApiRoutes({
39514
+ controllerId: CONTROLLER_ID,
39515
+ controller,
39516
+ auth: routeAuth,
39517
+ authStorage,
39327
39518
  audit: auditDomain,
39328
- toolContext: { ...toolContext, context: requestContext }
39329
- });
39330
- }
39331
- await Promise.all(
39332
- integrations.map(async (integration) => {
39333
- if (!integration.postToolObserver) return;
39334
- try {
39335
- await integration.postToolObserver({ toolContext, requestContext });
39336
- } catch (error) {
39337
- console.warn(`[factory] Integration '${integration.id}' post-tool observer failed:`, error);
39519
+ publicOrigin,
39520
+ stateSigner,
39521
+ fleet,
39522
+ factoryStorage: storage,
39523
+ integrationStorage,
39524
+ sourceControlStorage,
39525
+ domains,
39526
+ integrations: integrationRegistrations,
39527
+ intakeReady,
39528
+ factoryReady,
39529
+ rules,
39530
+ factoryTransitionService: transitionService,
39531
+ onFactoryRuntime: ({ transitionService: runtimeTransitionService, prepareBinding }) => {
39532
+ this.#dispatcher ??= new FactoryDecisionDispatcher({
39533
+ controller,
39534
+ transitionService: runtimeTransitionService,
39535
+ storage: storage.getDomain("work-items"),
39536
+ reconcileToolResults: () => factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve(),
39537
+ prepareBinding,
39538
+ primeCredentials: (tenant) => primeTenantCredentials({ tenant, credentials: modelCredentialsStorage })
39539
+ });
39338
39540
  }
39339
- })
39340
- );
39341
- },
39342
- ...pubsub ? { pubsub, crossProcessPubSub: true } : {},
39343
- buildApiRoutes: ({ controller, authStorage }) => [
39344
- // Public `/auth/*` routes (login/callback/logout/me). Folded in as
39345
- // `apiRoutes` (not plain Hono routes) because the entry can't touch the
39346
- // Hono app the deployer generates. `requiresAuth: false`; the gate
39347
- // skips `/auth/*`.
39348
- ...auth ? buildAuthRoutes(auth, { publicUrl: publicOrigin }) : [],
39349
- // Custom `/web/*` routes (fs / config / integrations / factory / audit).
39350
- ...assembleFactoryApiRoutes({
39351
- controllerId: CONTROLLER_ID,
39352
- controller,
39353
- auth: routeAuth,
39354
- authStorage,
39355
- audit: auditDomain,
39356
- publicOrigin,
39357
- stateSigner,
39358
- fleet,
39359
- factoryStorage: storage,
39360
- integrationStorage,
39361
- sourceControlStorage,
39362
- domains,
39363
- integrations: integrationRegistrations,
39364
- intakeReady,
39365
- factoryReady,
39366
- rules,
39367
- factoryTransitionService: transitionService,
39368
- onFactoryRuntime: ({ transitionService: runtimeTransitionService, prepareBinding }) => {
39369
- this.#dispatcher ??= new FactoryDecisionDispatcher({
39370
- controller,
39371
- transitionService: runtimeTransitionService,
39372
- storage: storage.getDomain("work-items"),
39373
- reconcileToolResults: () => factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve(),
39374
- prepareBinding,
39375
- primeCredentials: (tenant) => primeTenantCredentials({ tenant, credentials: modelCredentialsStorage })
39376
- });
39541
+ }),
39542
+ ...projectRoutes.routes(),
39543
+ ...auditDomain.routes()
39544
+ ],
39545
+ buildServerConfig: () => {
39546
+ const cors = allowedOrigins.length ? { cors: { origin: allowedOrigins, credentials: true } } : {};
39547
+ const onError = { onError: handleServerError };
39548
+ const uiDist = resolveUiDistDir();
39549
+ const spa = uiDist ? [createSpaStaticMiddleware(uiDist)] : [];
39550
+ if (!auth) {
39551
+ return {
39552
+ middleware: [
39553
+ createCustomProvidersPrimer({ auth: routeAuth, storage: customProvidersStorage, authEnabled: false }),
39554
+ ...spa
39555
+ ],
39556
+ ...cors,
39557
+ ...onError
39558
+ };
39377
39559
  }
39378
- }),
39379
- ...projectRoutes.routes(),
39380
- ...auditDomain.routes()
39381
- ],
39382
- buildServerConfig: () => {
39383
- const cors = allowedOrigins.length ? { cors: { origin: allowedOrigins, credentials: true } } : {};
39384
- const onError = { onError: handleServerError };
39385
- const uiDist = resolveUiDistDir();
39386
- const spa = uiDist ? [createSpaStaticMiddleware(uiDist)] : [];
39387
- if (!auth) {
39388
39560
  return {
39561
+ auth,
39389
39562
  middleware: [
39390
- createCustomProvidersPrimer({ auth: routeAuth, storage: customProvidersStorage, authEnabled: false }),
39563
+ createFactoryAuthGate(auth),
39564
+ createTenantCredentialPrimer({ auth: routeAuth, credentials: modelCredentialsStorage }),
39565
+ createCustomProvidersPrimer({
39566
+ auth: routeAuth,
39567
+ storage: customProvidersStorage,
39568
+ authEnabled: Boolean(auth)
39569
+ }),
39391
39570
  ...spa
39392
39571
  ],
39393
39572
  ...cors,
39394
39573
  ...onError
39395
39574
  };
39396
39575
  }
39397
- return {
39398
- auth,
39399
- middleware: [
39400
- createFactoryAuthGate(auth),
39401
- createTenantCredentialPrimer({ auth: routeAuth, credentials: modelCredentialsStorage }),
39402
- createCustomProvidersPrimer({
39403
- auth: routeAuth,
39404
- storage: customProvidersStorage,
39405
- authEnabled: Boolean(auth)
39406
- }),
39407
- ...spa
39408
- ],
39409
- ...cors,
39410
- ...onError
39411
- };
39412
- }
39413
- });
39576
+ })
39577
+ );
39414
39578
  this.#prepared = prepared;
39415
39579
  this.#factoryProcessor = factoryProcessor;
39416
39580
  const integrationWorkers = integrationRegistrations.filter(({ integration, ready }) => ready && integration.workers).flatMap(
@@ -39451,8 +39615,11 @@ var MastraFactory = class {
39451
39615
  if (!this.#prepared) {
39452
39616
  throw new Error("MastraFactory.finalize() called before prepare()");
39453
39617
  }
39454
- await this.#prepared.finalize();
39455
- await this.#factoryProcessor?.reconcileAllBoundThreads();
39618
+ await timedPhase("finalize.controller", () => this.#prepared.finalize());
39619
+ await timedPhase(
39620
+ "finalize.reconcileBoundThreads",
39621
+ () => this.#factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve()
39622
+ );
39456
39623
  this.#dispatcher?.start();
39457
39624
  }
39458
39625
  /** Stop Factory-owned background dispatch before the host process shuts down. */