From d338010648e430686800019fc212d59712e143fb Mon Sep 17 00:00:00 2001 From: ekeith <55766816+evanmkeith@users.noreply.github.com> Date: Fri, 11 Sep 2026 16:51:21 -0700 Subject: [PATCH] Fix JS push bundles externalizing Braintrust SDK ## Summary Fixes the JS SDK CLI push bundle path so uploaded function bundles inline Braintrust SDK packages by default again. The regression came from passing `plugins: []` into `buildOpts()`, which still allowed the built-in known-package externalization plugin to mark `braintrust`, `autoevals`, and `@braintrust/*` external. Hosted function runtime then failed at load time with `Cannot find module 'braintrust'`. This change disables only that known-package externalization plugin for final uploaded bundles, while keeping it enabled for local discovery builds. ## Testing - `cd js && pnpm vitest src/cli/auto-instrumentation.test.ts src/cli/util/external-packages-plugin.test.ts` - `./node_modules/.bin/prettier --write js/src/cli/index.ts js/src/cli/auto-instrumentation.test.ts` --- js/src/cli/auto-instrumentation.test.ts | 49 +++++++++++++++++++++++++ js/src/cli/index.ts | 9 ++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/js/src/cli/auto-instrumentation.test.ts b/js/src/cli/auto-instrumentation.test.ts index 0b9f41495..2aa10990d 100644 --- a/js/src/cli/auto-instrumentation.test.ts +++ b/js/src/cli/auto-instrumentation.test.ts @@ -139,6 +139,41 @@ describe("eval auto-instrumentation", () => { expect(output).toContain(googleGenAIChannel); }); + it("inlines the Braintrust SDK in the final uploaded bundle", async () => { + const sourceFile = path.join(fixtureDir, "braintrust-scorer.ts"); + await fs.writeFile( + sourceFile, + `import { marker } from "braintrust"; + export const value = marker;`, + ); + + handles = await initializeHandles({ files: [sourceFile], mode: "bundle" }); + await handles[sourceFile].bundle(); + const output = await fs.readFile(handles[sourceFile].bundleFile!, "utf8"); + + expect(output).toContain("bundled-braintrust"); + expect(output).not.toMatch(/require\(["']braintrust["']\)/); + }); + + it("keeps explicitly external packages external in the final uploaded bundle", async () => { + const sourceFile = path.join(fixtureDir, "external-package-scorer.ts"); + await fs.writeFile( + sourceFile, + `import { value } from "some-native-package"; + export const result = value;`, + ); + + handles = await initializeHandles({ + files: [sourceFile], + mode: "bundle", + externalPackages: ["some-native-package"], + }); + await handles[sourceFile].bundle(); + const output = await fs.readFile(handles[sourceFile].bundleFile!, "utf8"); + + expect(output).toMatch(/require\(["']some-native-package["']\)/); + }); + it.each([ ["instruments", undefined, ["start", "end", "asyncStart", "asyncEnd"]], ["respects opt-out for", "anthropic", []], @@ -231,6 +266,7 @@ process.stdout.write("loaded");`, }); async function writeFixturePackages(fixtureDir: string) { + const braintrustPackageDir = path.join(fixtureDir, "node_modules/braintrust"); const googlePackageDir = path.join(fixtureDir, "node_modules/@google/genai"); const indirectPackageDir = path.join( fixtureDir, @@ -240,6 +276,7 @@ async function writeFixturePackages(fixtureDir: string) { fixtureDir, "node_modules/@anthropic-ai/sdk", ); + await fs.mkdir(braintrustPackageDir, { recursive: true }); await fs.mkdir(path.join(googlePackageDir, "dist/node"), { recursive: true, }); @@ -249,6 +286,18 @@ async function writeFixturePackages(fixtureDir: string) { }); await Promise.all([ + fs.writeFile( + path.join(braintrustPackageDir, "package.json"), + JSON.stringify({ + name: "braintrust", + version: "1.0.0", + main: "./index.js", + }), + ), + fs.writeFile( + path.join(braintrustPackageDir, "index.js"), + `exports.marker = "bundled-braintrust";`, + ), fs.writeFile( path.join(googlePackageDir, "package.json"), JSON.stringify({ diff --git a/js/src/cli/index.ts b/js/src/cli/index.ts index eb5004555..b3ed92d13 100755 --- a/js/src/cli/index.ts +++ b/js/src/cli/index.ts @@ -381,8 +381,9 @@ async function initFile({ tsconfig, plugins: [], externalPackages, + markKnownPackagesExternal: false, }), - external: ["fsevents", "chokidar"], + external: ["fsevents", "chokidar", ...(externalPackages ?? [])], write: true, minify: true, sourcemap: true, @@ -820,17 +821,21 @@ function buildOpts({ tsconfig, plugins: argPlugins, externalPackages, + markKnownPackagesExternal = true, }: { fileName: string; outFile: string; tsconfig?: string; plugins?: PluginMaker[]; externalPackages?: string[]; + markKnownPackagesExternal?: boolean; }): esbuild.BuildOptions { const plugins = [ braintrustEsbuildPlugin(), nativeNodeModulesPlugin, - createMarkKnownPackagesExternalPlugin(externalPackages), + ...(markKnownPackagesExternal + ? [createMarkKnownPackagesExternalPlugin(externalPackages)] + : []), ...(argPlugins || []).map((fn) => fn(fileName)), ]; return {