feat: move TypeScript client codegen into the SDK module#9
Draft
TomChv wants to merge 1 commit into
Draft
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
Member
Author
|
PR needs dagger/dagger#13646 merged and released in order to load |
Member
Author
Once dagger/dagger#13663 is merge, the typescript client codegen will work :D |
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. 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 20, 2026 10:34
5f38891 to
d9835de
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.