build(ts-sdk): publish @pod-network/trade-sdk to npm on a ts-sdk-scoped tag - #258
Merged
Conversation
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.
ogabrielides
approved these changes
Jul 30, 2026
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.
ts-sdkhas never been published, so consumers link it from a sibling checkout withfile:../pod-sdk/ts-sdk. That carries no version, and a consumer checking this repo out with norefcompiles 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.
buildSubmitOrderdefaultedioctofalsewhile 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-widev*tagrelease.ymlalready uses to zip every SDK into a GitHub Release, so a TypeScript patch doesn't dragrust-sdkalong, and the two globs never fire for the same tag.The job resolves the version, then runs
npm ci→typecheck→build→npm publish --provenance, authenticating with theNPM_TOKENsecret.Two guards, each covering a mistake that can't be undone:
package.jsonis the source of truth, so taggingts-sdk-v0.1.0against a manifest reading0.0.0fails instead of publishing a mislabelled version. An npm version can never be reused.npm publishapplieslatesteven to a semver prerelease, which would make a release candidate the default install for every consumer. Hyphenated versions go torcinstead, so a rehearsal is harmless.Manifest
version0.0.0→0.1.0, pluspublishConfig.access: public(scoped packages default to restricted, so the first publish would otherwise fail or land private),repository/homepage/bugs, andprepublishOnlyso a manual publish can't ship a staledist/—distis gitignored and absent from a fresh checkout.Access is set only via
publishConfig, not an--accessflag, so it holds for every publish path rather than just this workflow.Closing a CI gap
Adds a
ts-sdkjob totest.yml. Until now no CI anywhere touched the TypeScript —test.yml,lint.ymlandformat.ymlare 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.typecheckandbuildboth run and are not redundant:tsconfig.build.jsonexcludes**/*.test.tsandexamples, sotypecheckcovers a strict superset.Verified
npm ci,npm run typecheckandnpm run buildall pass.npm publish --dry-runresolves to@pod-network/trade-sdk@0.1.0, 102 files, 111.3 kB, reporting public access without the--accessflag. Thenpm packtarball contains all fourexportstargets —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 packageddist/write/index.jscarries the immediate-or-cancel fix.One redundancy is kept knowingly:
prepublishOnlyand the explicit Build step meantscruns twice. Removing the explicit step would make a correct publish depend onprepublishOnlyfiring, 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
mainpicks up the workflow, then rehearse with0.1.0-rc.0(manifest +ts-sdk-v0.1.0-rc.0) and confirm it lands underrcwithlatestuntouched, before taggingts-sdk-v0.1.0.The frontend switchover is a separate follow-up, since it can't depend on
^0.1.0until 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.