From 4e90424670a5bd93d5692da4aec41d0f0788c826 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 23 Jul 2026 14:07:42 -0400 Subject: [PATCH 1/9] start server processes with node inspector --- packages/core/src/cli/index.ts | 94 ++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/packages/core/src/cli/index.ts b/packages/core/src/cli/index.ts index 9a66dfeb9e..d77f24e03a 100644 --- a/packages/core/src/cli/index.ts +++ b/packages/core/src/cli/index.ts @@ -272,6 +272,31 @@ function findViteBin(): string { return findBinUpwards("vite") ?? "vite"; } +/** + * Resolve Vite's JS entry so it can be run as `node `. The + * `node_modules/.bin/vite` shim is a shell script on POSIX (pnpm) and a `.CMD` + * on Windows — neither is directly executable by `node` — so the inspect path + * needs the real JS file. Vite's `exports` map blocks resolving `./bin/vite.js` + * directly, so resolve `vite/package.json` (which is exported) and read its + * `bin` field. Returns null if it cannot be resolved, in which case callers + * fall back to spawning the shim without the debugger. + */ +function findViteJsEntry(): string | null { + try { + const require = createRequire(path.join(process.cwd(), "package.json")); + const pkgJsonPath = require.resolve("vite/package.json"); + const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")) as { + bin?: string | Record; + }; + const rel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.vite; + if (!rel) return null; + const entry = path.join(path.dirname(pkgJsonPath), rel); + return fs.existsSync(entry) ? entry : null; + } catch { + return null; + } +} + function findTsxBin(): string { const localTsx = path.resolve("node_modules/.bin/tsx"); if (fs.existsSync(localTsx)) return localTsx; @@ -382,15 +407,38 @@ function isWorkspaceRoot(): boolean { } } +/** + * Pull a Node `--inspect` / `--inspect-brk` flag (with optional `=[host:]port`) + * out of a dev arg list. Vite does not understand it, so it is stripped from the + * args and instead applied to the Vite child's `NODE_OPTIONS`. Setting it only + * on the child avoids the parent `pnpm`/`agent-native` Node processes grabbing + * the inspector port first. + */ +function extractNodeInspectFlag(args: string[]): { + inspectFlag: string | null; + rest: string[]; +} { + const rest: string[] = []; + let inspectFlag: string | null = null; + for (const arg of args) { + if (/^--inspect(-brk)?(=.+)?$/.test(arg)) { + inspectFlag = arg; + continue; + } + rest.push(arg); + } + return { inspectFlag, rest }; +} + function run( cmd: string, cmdArgs: string[], - opts?: { stdio?: "inherit" | "pipe" }, + opts?: { stdio?: "inherit" | "pipe"; env?: NodeJS.ProcessEnv }, ) { const child = spawn(cmd, cmdArgs, { stdio: opts?.stdio ?? "inherit", shell: process.platform === "win32", - env: process.env, + env: opts?.env ?? process.env, }); child.on("exit", (code) => process.exit(code ?? 0)); // Forward signals to child so Cmd+C doesn't leave zombie processes holding ports @@ -541,7 +589,47 @@ switch (command) { break; } const vite = findViteBin(); - run(vite, args); + const { inspectFlag, rest } = extractNodeInspectFlag(args); + if (!inspectFlag) { + run(vite, rest); + break; + } + const viteJsEntry = findViteJsEntry(); + if (!viteJsEntry) { + console.warn( + "[agent-native] Could not resolve Vite's JS entry; starting dev " + + "server without the debugger.", + ); + run(vite, rest); + break; + } + // API route handlers do NOT run in the Vite process — Nitro runs them in a + // separate process spawned by env-runner's node-process runner. To make + // exactly that process (and nothing else in the pnpm/CLI/Vite chain) + // inspectable on a single known port, we: + // 1. select the node-process dev runner (so the server is a real, + // attachable process rather than a worker thread), and + // 2. inject NODE_OPTIONS via a preload that runs INSIDE Vite before its + // main module. Vite itself booted without --inspect so it never opens + // an inspector, but the server process it later forks inherits the + // flag and opens the only inspector — on . + const parsed = inspectFlag.match(/^--(inspect(?:-brk)?)(?:=(.+))?$/); + const kind = parsed?.[1] ?? "inspect"; + const target = parsed?.[2] ?? "9229"; + const directive = `--${kind}=${target}`; + const preload = + "data:text/javascript," + + encodeURIComponent( + `process.env.NODE_OPTIONS=((process.env.NODE_OPTIONS??"")+" ${directive}").trim();`, + ); + const env = { + ...process.env, + NITRO_DEV_RUNNER: process.env.NITRO_DEV_RUNNER ?? "node-process", + }; + console.log( + `[agent-native] API server debugger listening on ${target}`, + ); + run(process.execPath, ["--import", preload, viteJsEntry, ...rest], { env }); break; } From e9623c07493ea567d76ee82a9d7628b682a241a7 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 23 Jul 2026 14:14:03 -0400 Subject: [PATCH 2/9] update package.json --- .changeset/dev-inspect-flag.md | 11 +++++++++++ packages/core/src/templates/default/package.json | 2 +- .../core/src/templates/workspace-root/package.json | 2 +- templates/assets/package.json | 2 +- templates/brain/package.json | 2 +- templates/calendar/package.json | 2 +- templates/clips/package.json | 2 +- templates/content/package.json | 2 +- templates/design/package.json | 2 +- templates/dispatch/package.json | 2 +- templates/forms/package.json | 2 +- templates/macros/package.json | 2 +- templates/mail/package.json | 2 +- templates/slides/package.json | 2 +- 14 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 .changeset/dev-inspect-flag.md diff --git a/.changeset/dev-inspect-flag.md b/.changeset/dev-inspect-flag.md new file mode 100644 index 0000000000..332e928513 --- /dev/null +++ b/.changeset/dev-inspect-flag.md @@ -0,0 +1,11 @@ +--- +"@agent-native/core": minor +--- + +`agent-native dev --inspect` (and `--inspect-brk`, optionally `=`) now +attaches the Node inspector to **only** the Nitro API-server process, on a +single known port (default 9229). It selects Nitro's `node-process` dev runner +so the server is a real, attachable process, and injects `NODE_OPTIONS` through +a Vite preload that runs before Vite's own startup — so Vite, pnpm, and the CLI +are never inspected and there is exactly one debugger target. Set +`NITRO_DEV_RUNNER` yourself to override the runner. diff --git a/packages/core/src/templates/default/package.json b/packages/core/src/templates/default/package.json index 6fea0d66b7..25a72935f4 100644 --- a/packages/core/src/templates/default/package.json +++ b/packages/core/src/templates/default/package.json @@ -3,7 +3,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "typecheck": "agent-native typecheck", diff --git a/packages/core/src/templates/workspace-root/package.json b/packages/core/src/templates/workspace-root/package.json index 9cf353ac62..c6e6a5dc57 100644 --- a/packages/core/src/templates/workspace-root/package.json +++ b/packages/core/src/templates/workspace-root/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "pnpm -r build", "typecheck": "pnpm -r typecheck", "repair:workspace-org": "tsx scripts/repair-workspace-org.ts", diff --git a/templates/assets/package.json b/templates/assets/package.json index dc169d1d3d..0d1e188d02 100644 --- a/templates/assets/package.json +++ b/templates/assets/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "test": "vitest --run", diff --git a/templates/brain/package.json b/templates/brain/package.json index b14b4fa674..0cf647d0cf 100644 --- a/templates/brain/package.json +++ b/templates/brain/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "test": "vitest --run --config vitest.config.ts", diff --git a/templates/calendar/package.json b/templates/calendar/package.json index aecaaa40fa..69c4369e60 100644 --- a/templates/calendar/package.json +++ b/templates/calendar/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "test": "vitest --run", diff --git a/templates/clips/package.json b/templates/clips/package.json index 8af9abd568..f89223487b 100644 --- a/templates/clips/package.json +++ b/templates/clips/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "typecheck": "agent-native typecheck", diff --git a/templates/content/package.json b/templates/content/package.json index 4aa5f45f29..e41368ded3 100644 --- a/templates/content/package.json +++ b/templates/content/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "dev:database": "node scripts/check-native-deps.mjs && node scripts/dev-database.mjs", "build": "agent-native build", "start": "agent-native start", diff --git a/templates/design/package.json b/templates/design/package.json index 9f7ef4ce10..5a4d01920a 100644 --- a/templates/design/package.json +++ b/templates/design/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "test": "vitest --run", diff --git a/templates/dispatch/package.json b/templates/dispatch/package.json index af045f516b..c56e31d037 100644 --- a/templates/dispatch/package.json +++ b/templates/dispatch/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "typecheck": "agent-native typecheck", diff --git a/templates/forms/package.json b/templates/forms/package.json index 332404ed27..ee63c47829 100644 --- a/templates/forms/package.json +++ b/templates/forms/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "format.fix": "oxfmt --write .", diff --git a/templates/macros/package.json b/templates/macros/package.json index a4c4cb3188..f0ad991fd4 100644 --- a/templates/macros/package.json +++ b/templates/macros/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "test": "vitest --run --passWithNoTests", diff --git a/templates/mail/package.json b/templates/mail/package.json index 431bef10d5..8b20f82f57 100644 --- a/templates/mail/package.json +++ b/templates/mail/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "test": "vitest --run", diff --git a/templates/slides/package.json b/templates/slides/package.json index 89d6548962..b2c5dcad5d 100644 --- a/templates/slides/package.json +++ b/templates/slides/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "agent-native dev", + "dev": "agent-native dev --inspect", "build": "agent-native build", "start": "agent-native start", "test": "vitest --run", From 8851e3eb49ee854aab063e4d21f6065d9c4a7f48 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 23 Jul 2026 14:16:30 -0400 Subject: [PATCH 3/9] why say many word when few do trick --- packages/core/src/cli/index.ts | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/packages/core/src/cli/index.ts b/packages/core/src/cli/index.ts index d77f24e03a..f562fd5e0d 100644 --- a/packages/core/src/cli/index.ts +++ b/packages/core/src/cli/index.ts @@ -272,15 +272,6 @@ function findViteBin(): string { return findBinUpwards("vite") ?? "vite"; } -/** - * Resolve Vite's JS entry so it can be run as `node `. The - * `node_modules/.bin/vite` shim is a shell script on POSIX (pnpm) and a `.CMD` - * on Windows — neither is directly executable by `node` — so the inspect path - * needs the real JS file. Vite's `exports` map blocks resolving `./bin/vite.js` - * directly, so resolve `vite/package.json` (which is exported) and read its - * `bin` field. Returns null if it cannot be resolved, in which case callers - * fall back to spawning the shim without the debugger. - */ function findViteJsEntry(): string | null { try { const require = createRequire(path.join(process.cwd(), "package.json")); @@ -407,13 +398,6 @@ function isWorkspaceRoot(): boolean { } } -/** - * Pull a Node `--inspect` / `--inspect-brk` flag (with optional `=[host:]port`) - * out of a dev arg list. Vite does not understand it, so it is stripped from the - * args and instead applied to the Vite child's `NODE_OPTIONS`. Setting it only - * on the child avoids the parent `pnpm`/`agent-native` Node processes grabbing - * the inspector port first. - */ function extractNodeInspectFlag(args: string[]): { inspectFlag: string | null; rest: string[]; @@ -603,16 +587,7 @@ switch (command) { run(vite, rest); break; } - // API route handlers do NOT run in the Vite process — Nitro runs them in a - // separate process spawned by env-runner's node-process runner. To make - // exactly that process (and nothing else in the pnpm/CLI/Vite chain) - // inspectable on a single known port, we: - // 1. select the node-process dev runner (so the server is a real, - // attachable process rather than a worker thread), and - // 2. inject NODE_OPTIONS via a preload that runs INSIDE Vite before its - // main module. Vite itself booted without --inspect so it never opens - // an inspector, but the server process it later forks inherits the - // flag and opens the only inspector — on . + // Attach inspect flag to server process (not Vite or Nitro process) const parsed = inspectFlag.match(/^--(inspect(?:-brk)?)(?:=(.+))?$/); const kind = parsed?.[1] ?? "inspect"; const target = parsed?.[2] ?? "9229"; From 6d7811562e797bfefa8864052939a342aa7df181 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 23 Jul 2026 14:16:53 -0400 Subject: [PATCH 4/9] no changeset --- .changeset/dev-inspect-flag.md | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 .changeset/dev-inspect-flag.md diff --git a/.changeset/dev-inspect-flag.md b/.changeset/dev-inspect-flag.md deleted file mode 100644 index 332e928513..0000000000 --- a/.changeset/dev-inspect-flag.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@agent-native/core": minor ---- - -`agent-native dev --inspect` (and `--inspect-brk`, optionally `=`) now -attaches the Node inspector to **only** the Nitro API-server process, on a -single known port (default 9229). It selects Nitro's `node-process` dev runner -so the server is a real, attachable process, and injects `NODE_OPTIONS` through -a Vite preload that runs before Vite's own startup — so Vite, pnpm, and the CLI -are never inspected and there is exactly one debugger target. Set -`NITRO_DEV_RUNNER` yourself to override the runner. From 0bfcae023f7ee02f0c6fcffcea1b781b3accd06e Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 23 Jul 2026 14:21:21 -0400 Subject: [PATCH 5/9] lint --- packages/core/src/cli/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/core/src/cli/index.ts b/packages/core/src/cli/index.ts index d2c0cd21e8..7aa9e0d3aa 100644 --- a/packages/core/src/cli/index.ts +++ b/packages/core/src/cli/index.ts @@ -605,9 +605,7 @@ switch (command) { ...process.env, NITRO_DEV_RUNNER: process.env.NITRO_DEV_RUNNER ?? "node-process", }; - console.log( - `[agent-native] API server debugger listening on ${target}`, - ); + console.log(`[agent-native] API server debugger listening on ${target}`); run(process.execPath, ["--import", preload, viteJsEntry, ...rest], { env }); break; } From 666f5a124260cc6df4c08661fceb8d32733a1176 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 23 Jul 2026 15:08:21 -0400 Subject: [PATCH 6/9] clean up --- packages/core/src/templates/workspace-root/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/templates/workspace-root/package.json b/packages/core/src/templates/workspace-root/package.json index c6e6a5dc57..9cf353ac62 100644 --- a/packages/core/src/templates/workspace-root/package.json +++ b/packages/core/src/templates/workspace-root/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "scripts": { - "dev": "agent-native dev --inspect", + "dev": "agent-native dev", "build": "pnpm -r build", "typecheck": "pnpm -r typecheck", "repair:workspace-org": "tsx scripts/repair-workspace-org.ts", From 008ec8344389ddc96fc97eecdd1c8c01ef3c87c7 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 23 Jul 2026 15:12:45 -0400 Subject: [PATCH 7/9] Revert "no changeset" This reverts commit 6d7811562e797bfefa8864052939a342aa7df181. --- .changeset/dev-inspect-flag.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/dev-inspect-flag.md diff --git a/.changeset/dev-inspect-flag.md b/.changeset/dev-inspect-flag.md new file mode 100644 index 0000000000..332e928513 --- /dev/null +++ b/.changeset/dev-inspect-flag.md @@ -0,0 +1,11 @@ +--- +"@agent-native/core": minor +--- + +`agent-native dev --inspect` (and `--inspect-brk`, optionally `=`) now +attaches the Node inspector to **only** the Nitro API-server process, on a +single known port (default 9229). It selects Nitro's `node-process` dev runner +so the server is a real, attachable process, and injects `NODE_OPTIONS` through +a Vite preload that runs before Vite's own startup — so Vite, pnpm, and the CLI +are never inspected and there is exactly one debugger target. Set +`NITRO_DEV_RUNNER` yourself to override the runner. From bd48e020736174759089a51ffe66356e86633141 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 23 Jul 2026 15:51:57 -0400 Subject: [PATCH 8/9] fix: DS indexing now runs with correct context --- .../index-design-system-with-builder.test.ts | 2 + .../index-design-system-with-builder.ts | 48 ++++++++++-------- .../index-design-system-with-builder.test.ts | 8 +++ .../index-design-system-with-builder.ts | 49 +++++++++++-------- 4 files changed, 65 insertions(+), 42 deletions(-) diff --git a/templates/design/server/handlers/index-design-system-with-builder.test.ts b/templates/design/server/handlers/index-design-system-with-builder.test.ts index a16dfdc3a9..c729a863c5 100644 --- a/templates/design/server/handlers/index-design-system-with-builder.test.ts +++ b/templates/design/server/handlers/index-design-system-with-builder.test.ts @@ -7,12 +7,14 @@ const mocks = vi.hoisted(() => ({ setResponseStatus: vi.fn(), startBuilderDesignSystemIndex: vi.fn(), upsertBuilderProxyDesignSystem: vi.fn(), + runWithRequestContext: vi.fn((_ctx, fn) => fn()), })); vi.mock("@agent-native/core/server", () => ({ FeatureNotConfiguredError: class FeatureNotConfiguredError extends Error {}, getSession: mocks.getSession, startBuilderDesignSystemIndex: mocks.startBuilderDesignSystemIndex, + runWithRequestContext: mocks.runWithRequestContext, })); vi.mock("h3", () => ({ diff --git a/templates/design/server/handlers/index-design-system-with-builder.ts b/templates/design/server/handlers/index-design-system-with-builder.ts index 5ae12784cb..3924343f7b 100644 --- a/templates/design/server/handlers/index-design-system-with-builder.ts +++ b/templates/design/server/handlers/index-design-system-with-builder.ts @@ -1,6 +1,7 @@ import { FeatureNotConfiguredError, getSession, + runWithRequestContext, startBuilderDesignSystemIndex, } from "@agent-native/core/server"; import { @@ -90,27 +91,32 @@ export const indexDesignSystemWithBuilder = defineEventHandler( .trim() || "Imported brand"; try { - const result = await startBuilderDesignSystemIndex({ - projectName: suggestedTitle, - files: [ - { - name: filename, - data: part.data, - mimeType: "application/octet-stream", - }, - ], - }); - const proxy = await upsertBuilderProxyDesignSystem({ - result, - ownerEmail: session.email, - orgId: session.orgId ?? null, - projectName: suggestedTitle, - }); - return { - ...result, - ...proxy, - uploadedFileCount: 1, - }; + return await runWithRequestContext( + { userEmail: session.email, orgId: session.orgId }, + async () => { + const result = await startBuilderDesignSystemIndex({ + projectName: suggestedTitle, + files: [ + { + name: filename, + data: part.data, + mimeType: "application/octet-stream", + }, + ], + }); + const proxy = await upsertBuilderProxyDesignSystem({ + result, + ownerEmail: session.email, + orgId: session.orgId ?? null, + projectName: suggestedTitle, + }); + return { + ...result, + ...proxy, + uploadedFileCount: 1, + }; + }, + ); } catch (err) { if (err instanceof FeatureNotConfiguredError) { setResponseStatus(event, 412); diff --git a/templates/slides/server/handlers/index-design-system-with-builder.test.ts b/templates/slides/server/handlers/index-design-system-with-builder.test.ts index dac59d270b..5c2271d216 100644 --- a/templates/slides/server/handlers/index-design-system-with-builder.test.ts +++ b/templates/slides/server/handlers/index-design-system-with-builder.test.ts @@ -39,6 +39,14 @@ vi.mock("../lib/builder-design-system-proxy.js", () => ({ mockUpsertBuilderProxyDesignSystem(...args), })); +vi.mock("./request-auth-context.js", () => ({ + withSlidesRequestContext: ( + _event: unknown, + fn: (ctx: { email?: string; orgId?: string }) => unknown, + preResolvedContext: { email?: string; orgId?: string }, + ) => fn(preResolvedContext), +})); + import { indexDesignSystemWithBuilder } from "./index-design-system-with-builder"; describe("indexDesignSystemWithBuilder", () => { diff --git a/templates/slides/server/handlers/index-design-system-with-builder.ts b/templates/slides/server/handlers/index-design-system-with-builder.ts index e99175ab62..19b5f0f06f 100644 --- a/templates/slides/server/handlers/index-design-system-with-builder.ts +++ b/templates/slides/server/handlers/index-design-system-with-builder.ts @@ -11,6 +11,7 @@ import { } from "h3"; import { upsertBuilderProxyDesignSystem } from "../lib/builder-design-system-proxy.js"; +import { withSlidesRequestContext } from "./request-auth-context.js"; const MAX_FIG_BYTES = 200 * 1024 * 1024; const MULTIPART_OVERHEAD_BYTES = 1024 * 1024; @@ -72,27 +73,33 @@ export const indexDesignSystemWithBuilder = defineEventHandler( .trim() || "Imported brand"; try { - const result = await startBuilderDesignSystemIndex({ - projectName: suggestedTitle, - files: [ - { - name: part.filename || "brand.fig", - data: part.data, - mimeType: "application/octet-stream", - }, - ], - }); - const proxy = await upsertBuilderProxyDesignSystem({ - result, - ownerEmail: session.email, - orgId: session.orgId ?? null, - projectName: suggestedTitle, - }); - return { - ...result, - ...proxy, - uploadedFileCount: 1, - }; + return await withSlidesRequestContext( + event, + async ({ orgId }) => { + const result = await startBuilderDesignSystemIndex({ + projectName: suggestedTitle, + files: [ + { + name: part.filename || "brand.fig", + data: part.data, + mimeType: "application/octet-stream", + }, + ], + }); + const proxy = await upsertBuilderProxyDesignSystem({ + result, + ownerEmail: session.email, + orgId: orgId ?? null, + projectName: suggestedTitle, + }); + return { + ...result, + ...proxy, + uploadedFileCount: 1, + }; + }, + { email: session.email, orgId: session.orgId ?? undefined }, + ); } catch (err) { if (err instanceof FeatureNotConfiguredError) { setResponseStatus(event, 412); From 876fbe4c55d4738313eee2b4fe784811c05e3dd5 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Thu, 23 Jul 2026 20:17:59 +0000 Subject: [PATCH 9/9] fix: resolve live active org before Builder design-system indexing context - Slides: stop passing session.orgId as preResolvedContext, which bypassed resolveSlidesRequestAuthContext's live org-switch resolution. - Design: resolve the live org via getOrgContext (with a session.orgId fallback) before establishing the request context and persisting the proxy record, matching the pattern used elsewhere in the app. --- .../index-design-system-with-builder.test.ts | 6 +++ .../index-design-system-with-builder.ts | 15 +++++- .../index-design-system-with-builder.test.ts | 10 ++-- .../index-design-system-with-builder.ts | 50 +++++++++---------- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/templates/design/server/handlers/index-design-system-with-builder.test.ts b/templates/design/server/handlers/index-design-system-with-builder.test.ts index c729a863c5..df087eb36c 100644 --- a/templates/design/server/handlers/index-design-system-with-builder.test.ts +++ b/templates/design/server/handlers/index-design-system-with-builder.test.ts @@ -1,6 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const mocks = vi.hoisted(() => ({ + getOrgContext: vi.fn(), getRequestHeader: vi.fn(), getSession: vi.fn(), readMultipartFormData: vi.fn(), @@ -10,6 +11,10 @@ const mocks = vi.hoisted(() => ({ runWithRequestContext: vi.fn((_ctx, fn) => fn()), })); +vi.mock("@agent-native/core/org", () => ({ + getOrgContext: mocks.getOrgContext, +})); + vi.mock("@agent-native/core/server", () => ({ FeatureNotConfiguredError: class FeatureNotConfiguredError extends Error {}, getSession: mocks.getSession, @@ -37,6 +42,7 @@ describe("Builder .fig multipart preflight", () => { email: "designer@example.com", orgId: null, }); + mocks.getOrgContext.mockResolvedValue({ orgId: "org-1" }); mocks.getRequestHeader.mockReturnValue("1024"); mocks.readMultipartFormData.mockResolvedValue([ { diff --git a/templates/design/server/handlers/index-design-system-with-builder.ts b/templates/design/server/handlers/index-design-system-with-builder.ts index 3924343f7b..61e5a2c16f 100644 --- a/templates/design/server/handlers/index-design-system-with-builder.ts +++ b/templates/design/server/handlers/index-design-system-with-builder.ts @@ -1,3 +1,4 @@ +import { getOrgContext } from "@agent-native/core/org"; import { FeatureNotConfiguredError, getSession, @@ -90,9 +91,19 @@ export const indexDesignSystemWithBuilder = defineEventHandler( .replace(/[-_]+/g, " ") .trim() || "Imported brand"; + // `session.orgId` is set at sign-in and not refreshed when the user + // switches orgs; `getOrgContext` resolves the live active-org setting. + let orgId: string | undefined; + try { + orgId = (await getOrgContext(event)).orgId ?? undefined; + } catch { + // Org tables can be unavailable during first boot; fall back below. + } + orgId ??= session.orgId ?? undefined; + try { return await runWithRequestContext( - { userEmail: session.email, orgId: session.orgId }, + { userEmail: session.email, orgId }, async () => { const result = await startBuilderDesignSystemIndex({ projectName: suggestedTitle, @@ -107,7 +118,7 @@ export const indexDesignSystemWithBuilder = defineEventHandler( const proxy = await upsertBuilderProxyDesignSystem({ result, ownerEmail: session.email, - orgId: session.orgId ?? null, + orgId: orgId ?? null, projectName: suggestedTitle, }); return { diff --git a/templates/slides/server/handlers/index-design-system-with-builder.test.ts b/templates/slides/server/handlers/index-design-system-with-builder.test.ts index 5c2271d216..9344a54113 100644 --- a/templates/slides/server/handlers/index-design-system-with-builder.test.ts +++ b/templates/slides/server/handlers/index-design-system-with-builder.test.ts @@ -40,11 +40,13 @@ vi.mock("../lib/builder-design-system-proxy.js", () => ({ })); vi.mock("./request-auth-context.js", () => ({ - withSlidesRequestContext: ( - _event: unknown, + withSlidesRequestContext: async ( + event: unknown, fn: (ctx: { email?: string; orgId?: string }) => unknown, - preResolvedContext: { email?: string; orgId?: string }, - ) => fn(preResolvedContext), + ) => { + const session = await mockGetSession(event); + return fn({ email: session?.email, orgId: session?.orgId }); + }, })); import { indexDesignSystemWithBuilder } from "./index-design-system-with-builder"; diff --git a/templates/slides/server/handlers/index-design-system-with-builder.ts b/templates/slides/server/handlers/index-design-system-with-builder.ts index 19b5f0f06f..5411b5cceb 100644 --- a/templates/slides/server/handlers/index-design-system-with-builder.ts +++ b/templates/slides/server/handlers/index-design-system-with-builder.ts @@ -73,33 +73,29 @@ export const indexDesignSystemWithBuilder = defineEventHandler( .trim() || "Imported brand"; try { - return await withSlidesRequestContext( - event, - async ({ orgId }) => { - const result = await startBuilderDesignSystemIndex({ - projectName: suggestedTitle, - files: [ - { - name: part.filename || "brand.fig", - data: part.data, - mimeType: "application/octet-stream", - }, - ], - }); - const proxy = await upsertBuilderProxyDesignSystem({ - result, - ownerEmail: session.email, - orgId: orgId ?? null, - projectName: suggestedTitle, - }); - return { - ...result, - ...proxy, - uploadedFileCount: 1, - }; - }, - { email: session.email, orgId: session.orgId ?? undefined }, - ); + return await withSlidesRequestContext(event, async ({ orgId }) => { + const result = await startBuilderDesignSystemIndex({ + projectName: suggestedTitle, + files: [ + { + name: part.filename || "brand.fig", + data: part.data, + mimeType: "application/octet-stream", + }, + ], + }); + const proxy = await upsertBuilderProxyDesignSystem({ + result, + ownerEmail: session.email, + orgId: orgId ?? null, + projectName: suggestedTitle, + }); + return { + ...result, + ...proxy, + uploadedFileCount: 1, + }; + }); } catch (err) { if (err instanceof FeatureNotConfiguredError) { setResponseStatus(event, 412);