10 TypeScript files, 5 SDK artefacts: typed in Node and Deno Panth, who leads the software team at Oizom, built a single-build-script pipeline that compiles 10 TypeScript source files into five SDK artefacts for the open-source ticket-tracker project, producing a dependency-free client typed for Node, Deno, Bun and the browser. The 237-line sdk/build.mjs concatenates the modules, strips sibling imports and throws on any package import, then derives a flat sdk.d.ts via tsc and ESM bundles via esbuild, with a post-build check that imports each bundle and fails if the declaration file contains an import line. Files are hosted on Firebase with immutable caching for /lib/v1/, no-store for /lib/latest/, and a typescript content type for .ts files. Ten TypeScript files go in, five artefacts come out, and the client is typed in Node, Deno, Bun and the browser. One build script does it, and the SDK has no dependencies. The constraint: an orchestrator should be able to import the client straight from a URL and get types, and nothing I host may be a second copy of the code that drifts from the first. I'm Panth, and I lead the software team at Oizom. This is from ticket-tracker https://github.com/Panth977/ticket-tracker , my open-source board, where AI agents work tickets alongside people. Writing a client by hand for every orchestrator is the thing the app exists to avoid, so it ships one: @tm/sdk , hosted next to the API it talks to. /lib/v1/sdk.js ESM bundle, no dependencies browsers, Deno, Bun /lib/v1/sdk.min.js the same, minified /lib/v1/sdk.ts the whole SDK as ONE TypeScript file /lib/v1/sdk.d.ts one flat declaration file, no imports /lib/v1/tm-sdk-1.6.0.tgz and tm-sdk.tgz, for npm install /lib/v1/openapi.json OpenAPI 3.1 for /v1 /lib/v1/sdk.json version, byte sizes, SHA-256 of every file /lib/latest/… the same files, never cached The v1 is the API's wire version, not the package's. A breaking change to the wire format would get /lib/v2/ , and /lib/v1/ keeps working. A new SDK build for the same wire version replaces the files in place under a new tarball name. sdk/build.mjs is 237 lines. The order of the steps is the whole idea: sdk/src/ .ts ──concat, imports stripped──▶ dist/sdk.ts │ tsc --emitDeclarationOnly │ esbuild ▼ ▼ dist/sdk.d.ts dist/sdk.js + sdk.min.js │ npm pack ▼ dist/tm-sdk-