Visitar URL original
feat(sdk/typescript): publish @dagger.io/core as its own package by TomChv · Pull Request #15131 · dagger/dagger · GitHub
Skip to content

feat(sdk/typescript): publish @dagger.io/core as its own package - #15131

Open
TomChv wants to merge 4 commits into
mainfrom
feat/ts-core-package
Open

TomChv wants to merge 4 commits into
mainfrom
feat/ts-core-package

Conversation

@TomChv

@TomChv TomChv commented Nov 10, 2026

Copy link
Copy Markdown
Member

Adds @dagger.io/core — the generated Dagger bindings, dag, and the typed connect — as a real npm package, and a release path for it.

Nothing is moved or rewired. The pre-v1 tree at sdk/typescript/ is untouched, so this adds a package and breaks no build.

Why it ships from here

Its version is the engine release, not the SDK's. @dagger.io/session, @dagger.io/module, @dagger.io/telemetry and @dagger.io/connect are versioned on dagger/typescript-sdk's own cadence and published from there; core is the bindings for one engine, so the two move together.

Every .ts file is produced by typescript-sdk's packager against a running engine and copied verbatim. The README in the package says so, because client.gen.ts alone is 23k lines and a local edit would vanish on the next regeneration.

The release

releaseCore sits next to the SDK's own release, in the same shape: build, set the version, publish, with releaseCoreDryRun as a check. The prerelease channel in the tag decides the dist-tag, so a beta engine never moves latest.

@dagger.io/session is a published dependency, so npm install fetches it from the registry during the build. That is deliberate: it is the only step that proves the package boundary holds before a tarball exists.

Version is 1.0.0-beta.25.2

The layers moved to 1.0.0-beta.2 and core was still pinning beta.1, which puts two copies of session in any scope that resolves beta.2. Core cannot simply be republished — 1.0.0-beta.25 is taken — so this is a patch under that engine release.

The form matters. 1.0.0-beta.25-2 would sort above every future beta, because 25-2 is an alphanumeric prerelease identifier and alphanumeric outranks numeric, so semver puts it after 1.0.0-beta.26. 1.0.0-beta.25.2 sorts where it should:

1.0.0-beta.25  <  1.0.0-beta.25.2  <  1.0.0-beta.26  <  1.0.0-beta.25-2

The session pin is a range (^1.0.0-beta.2) rather than exact, so the next session release does not need another core patch there is no version for.

Verification

Against real npmjs: it installs @dagger.io/session@1.0.0-beta.2, tsc builds, the emitted dist/core.js keeps the @dagger.io/session specifier rather than a path out of its own tree, and release-core-dry-run passes. Published to a local registry and installed from there, it loads with 182 exports and a working dag.

Paired with dagger/typescript-sdk#133, which pins core by a bounded range so this patch is resolvable at all.

First slice of the package split on this side: @dagger.io/core as a real npm
package that depends on @dagger.io/session rather than reaching into a tree.

Its version is the **engine release** (1.0.0-beta.24), which is why it is
published from here and not from typescript-sdk, where session, module and
telemetry are versioned on their own cadence. session is pinned at the version
it was built against.

Every .ts file is produced by typescript-sdk's packager against a running
engine and is copied verbatim; the README says so, because client.gen.ts is
23k lines and a local edit would vanish on the next regeneration. Nothing is
moved or rewired: the pre-v1 tree at sdk/typescript/ is untouched, so this adds
a package and breaks no build.

Rehearsed against a local verdaccio, with session, module and telemetry
published there at 1.0.0-beta.1 by typescript-sdk's `packager:release`:

  - tsc builds clean against the *published* @dagger.io/session, which is the
    first time core has been compiled across the package boundary rather than
    against a workspace sibling
  - the emitted dist/core.js and dist/connect.js keep the `@dagger.io/session`
    specifier, so the tarball resolves it instead of a path out of its own tree
  - installing @dagger.io/core in a clean project pulls session transitively,
    and `dag.container().from(...).withExec(...)` chains

Not done here, and deliberately: the pre-v1 tree has not moved to
typescript-v0/, there is no facade, and nothing calls typescript-sdk's module
to regenerate these files or publishes core from the release pipeline.

Signed-off-by: Tom Chauveau <tom@dagger.io>
The package existed but nothing could ship it; it was built and published by
hand. This adds releaseCore alongside the SDK's own release, in the same shape:
build, set the version, publish, with a dry run as a check.

Its version is the **engine** release, so the tag is taken as-is rather than
through versionFromTag. The SDK is tagged sdk/typescript/vX and versioned on its
own cadence; core is the generated bindings for one engine, so the two move
together and nothing else here does.

@dagger.io/session is a published dependency now, so `npm install` fetches it
from the registry during the build. That is the point: it is the only step that
proves the package boundary holds before a tarball exists.

The prerelease channel decides the dist-tag, which is what keeps a beta engine
off `latest`. A non-semver tag falls back to "dev" because `npm version
prepatch` invents a prerelease and npm refuses to publish one under a name it
has never seen without a tag — which @dagger.io/core is, and which is why the
dry run failed until the fallback existed. The SDK's own release does not need
this: @dagger.io/dagger already exists, so npm does not ask.

Rehearsed against a local verdaccio: v1.0.0-beta.25 published under `beta`,
`latest` left where it was, session pinned at 1.0.0-beta.1, and the tarball
installs and loads with `dag` on it.

Signed-off-by: Tom Chauveau <tom@dagger.io>
core pinned @dagger.io/session at an exact version, which meant every session
release forced a core republish — and core's version is the engine's, so there
is often no version to republish it as.

Measured what the exact pin actually does. With core pinning 1.0.0-beta.1 and a
scope resolving session 1.0.0-beta.2, npm installs both:

  node_modules/@dagger.io/session                      -> 1.0.0-beta.2
  node_modules/@dagger.io/core/node_modules/@dagger.io/session -> 1.0.0-beta.1

That is not just a bigger tree. session carries ENGINE_VERSION and passes it as
--version when it starts a session, so core would keep announcing the older
engine while everything else announced the newer one — the bindings and the
served API drifting apart, which is the one thing the version coupling exists
to prevent.

With ^1.0.0-beta.1 the same install resolves to one copy. Verified both ways
against a local registry, and `^1.0.0-beta.1` matches 1.0.0-beta.2, 1.0.0 and
1.0.1 by semver.

Signed-off-by: Tom Chauveau <tom@dagger.io>
session, connect, module and telemetry are on 1.0.0-beta.2 now, and core was
still pinning beta.1 — which puts two copies of session in any scope that
resolves beta.2.

core cannot simply be republished: its version is the engine release and
1.0.0-beta.25 is taken. So this is a patch under that release, and the form
matters. `1.0.0-beta.25-2` would sort *above* every future beta, because
`25-2` is an alphanumeric prerelease identifier and alphanumeric outranks
numeric — semver puts it after 1.0.0-beta.26. `1.0.0-beta.25.2` sorts where it
should, between beta.25 and beta.26.

The session pin is a range now rather than exact, so the next session release
does not need another core patch.

Verified against real npmjs: it installs session 1.0.0-beta.2, tsc builds, and
the release dry run passes.

Signed-off-by: Tom Chauveau <tom@dagger.io>
@TomChv
TomChv requested a review from a team as a code owner November 10, 2026 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant