feat: move TypeScript client codegen into the SDK module#9
Open
TomChv wants to merge 1 commit into
Open
Conversation
TomChv
force-pushed
the
feat/extract-client-codegen-in-typescript-sdk
branch
2 times, most recently
from
July 15, 2026 14:44
71b3bbb to
8d31ef1
Compare
This comment was marked as outdated.
This comment was marked as outdated.
Member
Author
Once dagger/dagger#13663 is merge, the typescript client codegen will work :D |
TomChv
force-pushed
the
feat/extract-client-codegen-in-typescript-sdk
branch
from
July 20, 2026 10:34
5f38891 to
d9835de
Compare
TomChv
force-pushed
the
feat/extract-client-codegen-in-typescript-sdk
branch
from
July 21, 2026 13:13
d9835de to
c310703
Compare
TomChv
marked this pull request as ready for review
July 21, 2026 13:15
TomChv
force-pushed
the
feat/extract-client-codegen-in-typescript-sdk
branch
6 times, most recently
from
July 21, 2026 18:24
1e08ca1 to
5bec371
Compare
grouville
self-requested a review
July 21, 2026 19:32
grouville
approved these changes
Jul 21, 2026
Client generation used to run inside dagger/dagger's engine runtime, which
opened a nested engine session and coupled client bindings to engine
internals. Moving it into this SDK module makes generation ordinary codegen in
a plain container: the engine hands over the client-facing schema and the
bound module's metadata as data, with no nested session.
A generated client now binds exactly one module and ships as a self-contained,
scoped npm package. At runtime it serves that single module through
Workspace.moduleSource, so the bindings resolve from any plain client session
rather than only from a module runtime.
Client generation overlays the freshly generated files on the existing client
dir, so user-authored files there (e.g. a hand-written main.ts) survive
regeneration from any cwd. Local bound modules are resolved fresh from the
workspace (a cached module source can miss live edits), while pinned/immutable
git modules keep their canonical ref. Module refs are resolved
workspace-root-relative ("/" + ref) so generation works from any cwd.
Read the SDK's managed modules and clients from the passed workspace
(ws.sdk(name: currentModule.name)) instead of the ambient current workspace.
Module SDKs can no longer read the ambient workspace (dagger/dagger#13659), and
it was never populated during dagger.cloud @check execution -- which is why the
discovery and generate-all checks failed only in CI. The auto-injected
Workspace argument is always loaded, so the four affected checks now pass there
too.
Split the e2e module by concern into per-group files (utils, runtime, module,
client, init, config), each a small `type` exposed from E2e as a sub-object so
`dagger check` discovers its checks under `e-2-e:<group>:<check>`.
Requires the engine client-codegen primitives released in v1.0.0-beta.7
(dagger/dagger#13646 and #13663).
Signed-off-by: Tom Chauveau <tom@dagger.io>
TomChv
force-pushed
the
feat/extract-client-codegen-in-typescript-sdk
branch
from
July 21, 2026 20:10
5bec371 to
eb8c037
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Move TypeScript client codegen into the SDK module
Moves TypeScript client generation out of
dagger/dagger's engine runtime and into this.dangSDK module. The module now generates a typed client for a bound module itself — receiving the schema + module metadata from the engine as plain data and running codegen in an ordinary container, with no nested engine session.Important
Depends on two engine PRs, both gated
v1.0.0-0:ModuleSource.clientSchemaIntrospectionJSON(the client-facing schema: core + the bound module only) andCurrentModuleAsSDKClient.moduleSource(resolves the bound module at generation time, honoring pin/remote refs).Workspace.moduleSource(path), the runtime field the generated client calls to serve its bound module from a plainconnect()session (design:hack/designs/generated-client-module-loading.md).This PR requires an engine that ships both.
What's in it
helpers/codegen— the TypeScript client generator ported fromdagger/dagger'scmd/codegenas a standalone, engine-free Go module (nodagger.io/daggerdependency). Reads a pre-computed introspection schema + ameta.json(module name, engine version, bound module) and emits the client bindings. The upstream live-engine query is replaced by themeta.jsoninput. Upstream golden tests ported to guard fidelity.helpers/config-updator— new client config writers producing a scoped npm package:package.json(@dagger.io/<module>-clientname,@dagger.io/daggerpinned to the engine version,type:module,typescript), plustsconfig.json/deno.json.typescript-sdk.dang— the dang wiring:generateClient(ws, module, path)— the workspace analogue ofmod(ws, path).generate(ws).generateAllClient(ws) @generate— regenerates every registered client (currentModule.asSDK.clients), resolving each bound module viaclient.moduleSourceand generating fromclientSchemaIntrospectionJSON.generateAll→generateAllModulefor symmetry.codegenBuilder/configUpdatorBuildercontainer builders (compiled like the existing helpers).e2e —
generateClientCheck,generateAllClientCheck,generateClientRespectsExistingCheck,generateClientCompilesCheck, andhelperTestsCheck(runs the Go helper tests insidedagger check), plus dependency-bearing fixtures (client/app→client/dep).Client output layout
A generated client is a scoped package:
dagger.gen.ts— core Dagger types (named to match the Go SDK'sdagger.gen.go)<module>.gen.ts— one per module: the bound module (e.g.hello.gen.ts) and each dependency; each carries its own types plus the prototype augmentations it contributes toQuery/Client/Binding/Env.Key design decisions
@dagger.io/dagger; no TypeScript library bundle is vendored here.serveBoundModulebootstrap serves exactly that module (no dependency loop, noincludeDependencies). ALOCAL_SOURCE/DIR_SOURCEmodule is resolved against the workspace by its workspace-root-relative path (dag.currentWorkspace().moduleSource(path)) — cwd-independent, so it works anywhere in the project tree; aGIT_SOURCEmodule serves from its canonical ref + pin (dag.moduleSource(ref, { refPin })), which resolves from anywhere. A local-bound client shipped away from the project tree is unservable by design (remote-only) — seehack/designs/generated-client-module-loading.md.Full rationale in
design/client-gen.md.Testing
go test ./...in each helper (also run insidedagger checkviahelperTestsCheck), including a golden test for theserveBoundModulebootstrap (local path vs. git ref + pin).generateClientCompilesCheck, which additionally requires #13663: it type-checks the generateddag.currentWorkspace().moduleSource(...)against the engine'sWorkspace.moduleSource, so it only passes once the engine ships that field.Known limitations / follow-ups
@dagger.io/daggerversion on a dev/unreleased engine isn't on npm.generateClientCompilesCheckbuilds it from a pinneddagger/daggercommit; the client'spackage.jsonrespects an existing local./sdkref (seedesign/client-bundle.md).config-updatorbut isn't wired intoclientDirectoryyet.