From 70777e4a450eb1f4be3e512e3af086afb5f9034a Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Wed, 19 Aug 2026 15:45:09 +0530 Subject: [PATCH] fix(compiler): reserve api as a runtime binding to avoid client-scope collision Co-Authored-By: Claude Opus 5 --- packages/compiler/src/client-codegen.ts | 1 + .../compiler/test/api-block-codegen.test.ts | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/packages/compiler/src/client-codegen.ts b/packages/compiler/src/client-codegen.ts index 066b7b5d..7d476288 100644 --- a/packages/compiler/src/client-codegen.ts +++ b/packages/compiler/src/client-codegen.ts @@ -61,6 +61,7 @@ const RUNTIME_BINDINGS = new Set([ "server", "props", "refs", + "api", "event", "payload", ]); diff --git a/packages/compiler/test/api-block-codegen.test.ts b/packages/compiler/test/api-block-codegen.test.ts index d1f07da2..fa18f11e 100644 --- a/packages/compiler/test/api-block-codegen.test.ts +++ b/packages/compiler/test/api-block-codegen.test.ts @@ -80,3 +80,31 @@ test("a block without an error section still emits its response body", () => { expect(generated).toContain("plainUsers"); expect(generated).toContain("data.users"); }); + +test("a state field named api does not collide with the emitted api object", () => { + const generated = generateTargets( + parse(`page Repro { + state { + api = "" + } + + client { +${BLOCK} + } + + functions { + client async function run(): Promise { + const users = await api.searchUsers({ name: "Ajay" }) + console.log(users) + } + } + + view {
} +} +`), + ).browser; + + expect(() => { + new Function(generated.replace(/^\s*import[^\n]*$/gm, "").replace(/\bexport\s+/g, "")); + }).not.toThrow(); +});