64e9bc02b6
Follow-up to #1536, which pinned `useDefineForClassFields: false` in the js-sdk tsconfig because raising `target` to `es2022` flips the default to `true`, and that broke the template builder. This PR fixes the root cause and removes the pin, so the SDK now compiles with the standard es2022 `[[Define]]` class-field semantics. ## Root cause `TemplateBase` resolved its default `fileContextPath` in a **class field initializer**: ```ts private fileContextPath: PathLike = runtime === 'browser' ? '.' : (getCallerDirectory(STACK_TRACE_DEPTH) ?? '.') ``` With native class fields (define semantics), V8 evaluates field initializers in an extra `<instance_members_initializer>` stack frame: ``` at getCallerDirectory (utils.ts) at <instance_members_initializer> (index.ts) ← extra frame under define semantics at new TemplateBase (index.ts) at Template (index.ts) at user code ← fixed-depth walk lands one frame short ``` `getCallerDirectory` walks the stack at a fixed depth, so it landed on the SDK's own `src/template` directory instead of the caller's — `.copy('folder/*', …)` then globbed against the wrong base dir (`Error: No files found in .../src/template/...`), and the resulting client-side failure mis-attributed build-step stack traces (the two `stacktrace.test.ts` failures were cascades of this one bug). ## Fix Move the default resolution into the constructor body, where the stack shape is identical under both emits: ```ts constructor(options?: TemplateOptions) { this.fileContextPath = options?.fileContextPath ?? (runtime === 'browser' ? '.' : (getCallerDirectory(STACK_TRACE_DEPTH) ?? '.')) ``` The call is now emit-invariant (same `STACK_TRACE_DEPTH`), so the tsconfig pin is removed. The method-level `getCallerFrame` call sites were never affected — method bodies don't change shape with class-field semantics. Only the js-sdk is touched: the Python SDKs resolve the caller via `inspect` and don't have this failure mode, and the CLI bundle doesn't include `TemplateBase`. ## Usage example Fixes relative-path resolution for SDK consumers whose toolchain emits native class fields (e.g. esbuild/vitest with `target: es2022+`): ```ts // user-project/scripts/template.ts const template = Template() .fromBaseImage() .copy('assets/*', '/app/assets') // now resolves against user-project/scripts/, // not the SDK's own directory ``` ## Verification - `tests/template/stacktrace.test.ts` — 30/30 pass with the flag defaulted (`true`), and still 30/30 when explicitly set back to `false` (emit-invariance) - `tests/template/build.test.ts` — 4/4 pass against the real backend (real `.copy` glob + build) - Smoke-tested built `dist/index.mjs` and `dist/index.js` from an external directory: `fileContextPath` resolves to the importing script's directory in both - Unit project A/B: identical results with and without this change (remaining failures are pre-existing `E2B_API_KEY`-gated live tests) - `pnpm run typecheck`, `lint`, `format` ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
What is E2B?
E2B is an open-source infrastructure that allows you to run AI-generated code in secure isolated sandboxes in the cloud. To start and control sandboxes, use our JavaScript SDK or Python SDK.
Run your first Sandbox
1. Install SDK
npm i e2b
2. Get your E2B API key
E2B_API_KEY=e2b_***
3. Start a sandbox and run commands
import Sandbox from 'e2b'
const sandbox = await Sandbox.create()
const result = await sandbox.commands.run('echo "Hello from E2B!"')
console.log(result.stdout) // Hello from E2B!
4. Code execution with Code Interpreter
If you need runCode(), install the Code Interpreter SDK:
npm i @e2b/code-interpreter
import { Sandbox } from '@e2b/code-interpreter'
const sandbox = await Sandbox.create()
const execution = await sandbox.runCode('x = 1; x += 1; x')
console.log(execution.text) // outputs 2
5. Check docs
Visit E2B documentation.
6. E2B cookbook
Visit our Cookbook to get inspired by examples with different LLMs and AI frameworks.
