Skip to content

build(ts-sdk): publish @pod-network/trade-sdk to npm on a ts-sdk-scoped tag - #258

Merged
poszu merged 2 commits into
mainfrom
publish-ts-sdk
Jul 30, 2026
Merged

build(ts-sdk): publish @pod-network/trade-sdk to npm on a ts-sdk-scoped tag#258
poszu merged 2 commits into
mainfrom
publish-ts-sdk

Conversation

@poszu

@poszu poszu commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

ts-sdk has never been published, so consumers link it from a sibling checkout with file:../pod-sdk/ts-sdk. That carries no version, and a consumer checking this repo out with no ref compiles against whatever the default branch happens to be — builds aren't reproducible, and an SDK change reaches users with nothing in the consumer's history recording which SDK shipped.

That isn't hypothetical. buildSubmitOrder defaulted ioc to false while the CLOB rejects any market order that isn't immediate-or-cancel, so every market order the trading frontend built was refused and positions couldn't be closed. The fix reached the deployed app with no frontend commit at all — a regression would have travelled exactly as silently.

Release flow

Publishing is driven by a ts-sdk-v* tag. That's deliberately distinct from the repo-wide v* tag release.yml already uses to zip every SDK into a GitHub Release, so a TypeScript patch doesn't drag rust-sdk along, and the two globs never fire for the same tag.

The job resolves the version, then runs npm citypecheckbuildnpm publish --provenance, authenticating with the NPM_TOKEN secret.

Two guards, each covering a mistake that can't be undone:

  • Tag vs manifest. The tag triggers the release but package.json is the source of truth, so tagging ts-sdk-v0.1.0 against a manifest reading 0.0.0 fails instead of publishing a mislabelled version. An npm version can never be reused.
  • Prerelease dist-tag. npm publish applies latest even to a semver prerelease, which would make a release candidate the default install for every consumer. Hyphenated versions go to rc instead, so a rehearsal is harmless.

Manifest

version 0.0.00.1.0, plus publishConfig.access: public (scoped packages default to restricted, so the first publish would otherwise fail or land private), repository/homepage/bugs, and prepublishOnly so a manual publish can't ship a stale dist/dist is gitignored and absent from a fresh checkout.

Access is set only via publishConfig, not an --access flag, so it holds for every publish path rather than just this workflow.

Closing a CI gap

Adds a ts-sdk job to test.yml. Until now no CI anywhere touched the TypeScript — test.yml, lint.yml and format.yml are all cargo and Foundry — so a broken SDK only surfaced when a downstream image build failed. The same job gates the release, so a publish can't ship code that doesn't compile.

typecheck and build both run and are not redundant: tsconfig.build.json excludes **/*.test.ts and examples, so typecheck covers a strict superset.

Verified

npm ci, npm run typecheck and npm run build all pass. npm publish --dry-run resolves to @pod-network/trade-sdk@0.1.0, 102 files, 111.3 kB, reporting public access without the --access flag. The npm pack tarball contains all four exports targets — dist/index.js, dist/index.d.ts, dist/write/index.js, dist/write/index.d.ts — so the package imports rather than merely installing, and the packaged dist/write/index.js carries the immediate-or-cancel fix.

One redundancy is kept knowingly: prepublishOnly and the explicit Build step mean tsc runs twice. Removing the explicit step would make a correct publish depend on prepublishOnly firing, and if that were ever wrong the package would publish empty to a version npm will never let us reuse. A few seconds of compile is cheap insurance against a one-way failure.

After merging

Nothing is published by this PR. Merge first so a tag on main picks up the workflow, then rehearse with 0.1.0-rc.0 (manifest + ts-sdk-v0.1.0-rc.0) and confirm it lands under rc with latest untouched, before tagging ts-sdk-v0.1.0.

The frontend switchover is a separate follow-up, since it can't depend on ^0.1.0 until that version exists. It keeps its commit pin until then, and that pin plus the whole second checkout step get deleted in the same change that adopts the npm dependency.

poszu added 2 commits July 30, 2026 09:28
ts-sdk has never been published, so consumers link it from a sibling checkout
with `file:../pod-sdk/ts-sdk`. That carries no version, and a consumer checking
this repo out with no ref compiled against whatever the default branch happened
to be — builds were not reproducible, and an SDK change reached users with
nothing in the consumer's history recording which SDK shipped. The
immediate-or-cancel default landed in a deployed app that way; a regression
would travel just as silently.

Publish on a `ts-sdk-v*` tag, which does not match the `v*` glob release.yml uses
to zip every SDK, so TypeScript releases keep their own cadence. The job checks
the tag against package.json before publishing, because an npm version can never
be reused and a mislabelled one is permanent. It routes hyphenated versions to
the `rc` dist-tag, since npm otherwise applies `latest` to a prerelease and would
make a release candidate the default install.

package.json gains publishConfig.access (scoped packages default to restricted,
so the first publish would otherwise fail or land private), repository/homepage/
bugs, and prepublishOnly so a manual publish cannot ship a stale dist — dist is
gitignored and absent from a fresh checkout.

Also add a ts-sdk job to test.yml. No CI anywhere touched the TypeScript, so a
broken SDK surfaced only when a downstream image build failed; the same job gates
the release.
…access

publishConfig.access already makes the package public, so the --access flag on
the publish command was a second source for one setting — and the weaker one,
since it only applies to this workflow while publishConfig applies to any
publish. Verified with a dry run: npm still reports public access without it.

Document the release flow in the ts-sdk README. The repo now has two tag
conventions — `v*` zips every SDK into a GitHub Release, `ts-sdk-v*` publishes
this package to npm — and nothing said so, leaving the workflow file as the only
place to discover the tag shape. Also record the prerelease rc dist-tag
behaviour and the npm link loop for working on the SDK and a consumer together.
@poszu
poszu merged commit 6447812 into main Jul 30, 2026
10 checks passed
@poszu
poszu deleted the publish-ts-sdk branch July 30, 2026 09: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.

2 participants