chore(js-sdk,cli): modernize tsconfig and adopt TypeScript 7 (side-by-side) - #1536
Conversation
|
PR SummaryMedium Risk Overview Reviewed by Cursor Bugbot for commit 443f089. Bugbot is set up for automated code reviews on this repo. Configure here. |
Package ArtifactsBuilt from 247c106. Download artifacts from this workflow run. JS SDK ( npm install ./e2b-2.32.1-mishushakov-bump-typescript-7.0.tgzCLI ( npm install ./e2b-cli-2.13.2-mishushakov-bump-typescript-7.0.tgzPython SDK ( pip install ./e2b-2.31.0+mishushakov.bump.typescript.7-py3-none-any.whl |
7af632c to
a4aac95
Compare
…-side) Adopt TypeScript 7 for both packages. TypeScript 7.0's native compiler ships no programmatic API yet (that lands in 7.1), so it is installed side-by-side with TypeScript 6.0 per the official guidance: - `@typescript/native` (npm:typescript@^7.0.2) provides the native `tsc` used for type-checking (`tsc --noEmit`) - `typescript` resolves to `@typescript/typescript6@^6.0.2`, which keeps the compiler API available for tooling that needs it — tsdown's `.d.ts` generation and the codegen scripts (openapi-typescript, json2ts), which crash on TS 7.0's API-less native build Now that tsdown owns the build emit and `tsc` is type-check only, the compiler options are also modernized: - js-sdk: target/lib `es6`->`es2022`, add `module: esnext`, `moduleResolution` `node`->`bundler`; drop `allowJs` (no JS sources) and `allowSyntheticDefaultImports` (implied by `esModuleInterop`) - js-sdk: pin `useDefineForClassFields: false`. `target: es2022` would default it to `true`, changing class-field emit and shifting stack frames, which breaks the template builder's fixed-depth caller resolution (getCallerDirectory / per-step stack traces) and fails the template build/stacktrace tests - cli: `moduleResolution` `node`->`bundler`; drop strict-implied flags (strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, alwaysStrict); drop `downlevelIteration` and `baseUrl` (both removed in TS 7), replacing `baseUrl` with explicit `paths` for the existing `src/...` import style - cli: drop `outDir` (unused under `tsc --noEmit`) and add an explicit `exclude` for `dist`/`node_modules` so the built bundle is never type-checked Target stays at es2022 (engines still allow Node 20). No public API or runtime change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
a4aac95 to
bfa0af5
Compare
The codegen image was left at Node 20.19.5 while `.tool-versions` moved to 22.18.0, so the "pinned to match .tool-versions" comment was stale. Sync it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This PR only touches dev/build tooling (tsconfig, TypeScript devDependencies, codegen Dockerfile) — nothing in the published package (dist/README/package.json runtime surface) changes, so no version bump/release is warranted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…solution emit-invariant (#1539) 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>
Supersedes #1516 (same modernization at TypeScript 6.0). Rebased onto
mainnow that the build runs on tsdown (#1515).What & why
Adopt TypeScript 7 for both packages and modernize the compiler config.
TypeScript 7.0's native compiler ships no programmatic API yet (it lands in 7.1), so anything built on the TS compiler API breaks on it — here that's tsdown's
.d.tsgeneration and the codegen scripts (openapi-typescript,json-schema-to-typescript). Per the official guidance, TS 7 is installed side-by-side with TS 6:tsc --noEmit(typecheck) → native TypeScript 7.0.2 (verified:tsc --version→ 7.0.2)import 'typescript'→ TypeScript 6.0 with the compiler API → tsdown dts + codegen keep workingInternal build-config change only — no public API or runtime behavior changes.
Compiler options: before → after
packages/js-sdk/tsconfig.jsontargetes6es2022lib["dom","ESNext"]["dom","es2022"]moduleesnextmoduleResolutionnodebundlerallowJstrue.jssources)allowSyntheticDefaultImportstrueesModuleInterop)useDefineForClassFieldsfalse(now explicit) — see notepackages/cli/tsconfig.jsonmoduleResolutionnodebundlerstrictNullChecks,strictFunctionTypes,strictBindCallApply,strictPropertyInitialization,noImplicitThis,alwaysStricttruestrict)downlevelIterationtruees2022)baseUrl"."paths{ e2b }{ src, "src/*", e2b }(replacesbaseUrlfor the existingsrc/...import style)outDir"dist"tsc --noEmit)exclude["dist","node_modules"](so the built bundle is never type-checked)target/libfor the CLI were alreadyes2022.Notes / decisions
typescript@7bump: TS 7.0 is the native (Go) compiler rewrite — feature-identical to 6.0 for type-checking, no programmatic API until 7.1. A plain bump crashed both codegen tools (Cannot read properties of undefined (reading 'createKeywordTypeNode')). Side-by-side gives native-TS-7 checking while keeping the TS-6 API for tooling. Once 7.1 ships the API and the tools update, this collapses back to a singletypescript@7dep.useDefineForClassFields: falseis pinned explicitly. Raising js-sdk'stargettoes2022flips this default totrue, changing class-field emit and shifting stack frames. The template builder resolves the caller's directory and per-step traces via fixed-depth stack walking (getCallerDirectoryinsrc/template/index.ts), so the extra frames threw it off by one — resolving.copy('folder/*', …)against the wrong base dir and mis-attributing build steps (tests/template/build.test.ts+stacktrace.test.ts). Pinningfalsekeeps the exact pre-existing field semantics (es6 already impliedfalse); adoptingdefinesemantics should be a separate, deliberately tested change.es2022, notes2023.enginesstill allow Node 20 (>=20.18.1 <21 || >=22).moduleResolution: "bundler"typechecks + builds cleanly in both packages. The CLI'sbaseUrl-based bare imports (from 'src/user',from 'src') are preserved viapaths; the bundled output still resolves them (build verified, binary smoke-tested).Not done (intentionally)
verbatimModuleSyntax— ~177import typeconversions; left as a follow-up.tsconfig.base.json— the two configs diverge too much to factor out cleanly.Verification
pnpm run typecheck✅ both packages, on native TS 7.0.2pnpm run build✅ both packages (js-sdk ESM + CJS + DTS; cli CJS; binary smoke-tested)openapi-typescript+json2tsrun and produce identical output (idempotent)pnpm run lint✅ both packagespnpm run test—template/build+template/stacktracenow pass (stacktraceverified locally 30/30); remaining local failures are allE2B_API_KEY-gated live tests, unaffected by this change🤖 Generated with Claude Code