Skip to content

Commit 0f7c5a9

Browse files
build(audience): make @imtbl/audience publishable as an npm tarball
Makes @imtbl/audience installable from npm (unblocks SDK-66) and picks it up by the monorepo's publish workflow (unblocks the first publish). Changes to packages/audience/sdk only: - tsup.config.js: local config that extends the monorepo defaults and sets noExternal: [/^@imtbl\//] so runtime JS inlines audience-core and its transitive metrics dep. - rollup.dts.config.js + rollup-plugin-dts: post-typegen step that rolls up the generated declaration file with respectExternal so public types are self-contained. - scripts/prepack.mjs + scripts/postpack.mjs: strip 'workspace:*' deps from the published package.json before pack, restore afterwards so the developer working tree stays on workspace form. - package.json: add 'pack:root' script matching every other shipped @imtbl/* package so the root 'pack-npm-packages' recursive invocation actually packs @imtbl/audience. Without this the publish workflow silently skipped the package. - .eslintignore: exempt the new tsup.config.js / rollup.dts.config.js from project-based eslint (mirrors existing pattern for build-time configs). Verified locally: - dist/node/*.js, dist/node/*.cjs, dist/browser/*.js contain no bare @imtbl/* imports - dist/types/index.d.ts contains no @imtbl/* re-exports - Installing the produced tarball into a fresh /tmp directory via 'npm install' resolves both the runtime require and the types - 'pnpm --filter @imtbl/audience pack:root' produces imtbl-audience-0.0.0.tgz at the repo root — same location pattern as passport, checkout, etc. Refs: SDK-66, SDK-63 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 01a67ef commit 0f7c5a9

7 files changed

Lines changed: 410 additions & 155 deletions

File tree

.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ packages/internal/generated-clients/src/
2121

2222
# put module specific ignore paths here
2323
packages/game-bridge/scripts/**/*.js
24+
packages/audience/sdk/rollup.dts.config.js
25+
packages/audience/sdk/tsup.config.js

packages/audience/sdk/package.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
"eslint": "^8.56.0",
1616
"jest": "^29.7.0",
1717
"jest-environment-jsdom": "^29.4.3",
18+
"rollup": "^4.22.4",
19+
"rollup-plugin-dts": "^6.4.1",
1820
"ts-jest": "^29.1.0",
1921
"tsup": "^8.3.0",
2022
"typescript": "^5.6.2"
@@ -36,7 +38,9 @@
3638
"default": "./dist/node/index.js"
3739
}
3840
},
39-
"files": ["dist"],
41+
"files": [
42+
"dist"
43+
],
4044
"homepage": "https://github.com/immutable/ts-immutable-sdk#readme",
4145
"main": "dist/node/index.cjs",
4246
"module": "dist/node/index.js",
@@ -47,9 +51,12 @@
4751
"repository": "immutable/ts-immutable-sdk.git",
4852
"scripts": {
4953
"build": "pnpm transpile && pnpm typegen",
50-
"transpile": "tsup src/index.ts --config ../../../tsup.config.js",
51-
"typegen": "tsc --customConditions default --emitDeclarationOnly --outDir dist/types",
54+
"transpile": "tsup --config tsup.config.js",
55+
"typegen": "tsc --customConditions default --emitDeclarationOnly --outDir dist/types && rollup -c rollup.dts.config.js",
5256
"lint": "eslint ./src --ext .ts,.jsx,.tsx --max-warnings=0",
57+
"pack:root": "pnpm pack --pack-destination $(dirname $(pnpm root -w))",
58+
"prepack": "node scripts/prepack.mjs",
59+
"postpack": "node scripts/postpack.mjs",
5360
"test": "jest --passWithNoTests",
5461
"test:watch": "jest --watch",
5562
"typecheck": "tsc --customConditions development --noEmit --jsx preserve"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Roll up the generated .d.ts files so that type re-exports from
2+
// `@imtbl/audience-core` (and its transitive `@imtbl/metrics`) are inlined
3+
// into a single self-contained declaration file. Without this, consumers of
4+
// the published tarball would get unresolved type references, because the
5+
// @imtbl/* packages are bundled into dist/ but not published alongside.
6+
import { dts } from 'rollup-plugin-dts';
7+
8+
// By default, rollup treats every non-relative import as external — so
9+
// `@imtbl/audience-core` type re-exports would stay as bare imports in the
10+
// output. Pass `respectExternal: true` so the plugin walks through node
11+
// resolution to `.d.ts` files for @imtbl/* workspace packages and inlines
12+
// them into the rolled-up declaration file.
13+
export default {
14+
input: 'dist/types/index.d.ts',
15+
output: { file: 'dist/types/index.d.ts', format: 'es' },
16+
plugins: [dts({ respectExternal: true })],
17+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env node
2+
/*
3+
* postpack: restore the package.json that prepack.mjs backed up.
4+
*
5+
* Runs after `npm pack` / `npm publish` finishes, so the developer's working
6+
* tree goes back to referencing `@imtbl/audience-core: workspace:*` for
7+
* local monorepo development.
8+
*/
9+
import { existsSync, copyFileSync, unlinkSync } from 'node:fs';
10+
11+
const pkgPath = new URL('../package.json', import.meta.url);
12+
const backupPath = new URL('../package.json.prepack-backup', import.meta.url);
13+
14+
if (existsSync(backupPath)) {
15+
copyFileSync(backupPath, pkgPath);
16+
unlinkSync(backupPath);
17+
console.log('[postpack] restored original package.json');
18+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env node
2+
/*
3+
* prepack: strip workspace-protocol deps from package.json before `npm pack`.
4+
*
5+
* The runtime JS (dist/node, dist/browser) and the bundled .d.ts already
6+
* inline `@imtbl/audience-core` and its transitive `@imtbl/metrics` dep, so
7+
* they don't need to be listed as runtime deps in the published package. If
8+
* we left them, npm would choke on the `workspace:*` protocol at install.
9+
*
10+
* A sibling postpack.mjs restores the original package.json after the tarball
11+
* is written, so the developer's working tree is never left modified.
12+
*/
13+
import { readFileSync, writeFileSync, copyFileSync } from 'node:fs';
14+
15+
const pkgPath = new URL('../package.json', import.meta.url);
16+
const backupPath = new URL('../package.json.prepack-backup', import.meta.url);
17+
18+
copyFileSync(pkgPath, backupPath);
19+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
20+
21+
// Deps bundled into dist/: remove from published metadata.
22+
const bundledWorkspaceDeps = ['@imtbl/audience-core', '@imtbl/metrics'];
23+
for (const name of bundledWorkspaceDeps) {
24+
if (pkg.dependencies) delete pkg.dependencies[name];
25+
}
26+
// Clean up empty dependencies object.
27+
if (pkg.dependencies && Object.keys(pkg.dependencies).length === 0) {
28+
delete pkg.dependencies;
29+
}
30+
31+
writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
32+
console.log('[prepack] stripped bundled workspace deps from package.json');
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// @ts-check
2+
// Local tsup config for @imtbl/audience.
3+
//
4+
// Extends the monorepo's root tsup config but overrides `noExternal` so that
5+
// every `@imtbl/*` workspace dep (audience-core, its transitive metrics dep)
6+
// is inlined into the built bundle. This makes the package installable as a
7+
// standalone tarball without the pnpm `workspace:*` protocol.
8+
import { defineConfig } from 'tsup';
9+
import { nodeModulesPolyfillPlugin } from 'esbuild-plugins-node-modules-polyfill';
10+
import { replace } from 'esbuild-plugin-replace';
11+
import pkg from './package.json' assert { type: 'json' };
12+
13+
const IMTBL_WORKSPACE = /^@imtbl\//;
14+
15+
export default defineConfig((options) => {
16+
if (options.watch) {
17+
return {
18+
entry: ['src/index.ts'],
19+
outDir: 'dist/browser',
20+
format: 'esm',
21+
target: 'es2022',
22+
platform: 'browser',
23+
bundle: true,
24+
noExternal: [IMTBL_WORKSPACE],
25+
esbuildPlugins: [
26+
nodeModulesPolyfillPlugin({
27+
globals: { Buffer: true, process: true },
28+
modules: ['crypto', 'buffer', 'process'],
29+
}),
30+
replace({
31+
__SDK_VERSION__: pkg.version === '0.0.0' ? '2.0.0' : pkg.version,
32+
}),
33+
],
34+
};
35+
}
36+
37+
return [
38+
// Browser ESM bundle
39+
{
40+
entry: ['src/index.ts'],
41+
outDir: 'dist/browser',
42+
platform: 'browser',
43+
format: 'esm',
44+
target: 'es2022',
45+
minify: true,
46+
bundle: true,
47+
noExternal: [IMTBL_WORKSPACE, '@uniswap/swap-router-contracts'],
48+
treeshake: true,
49+
esbuildPlugins: [
50+
nodeModulesPolyfillPlugin({
51+
globals: { Buffer: true, process: true },
52+
modules: ['crypto', 'buffer', 'process'],
53+
}),
54+
replace({ __SDK_VERSION__: pkg.version }),
55+
],
56+
},
57+
58+
// Node CJS + ESM bundle
59+
{
60+
entry: ['src/index.ts'],
61+
outDir: 'dist/node',
62+
platform: 'node',
63+
format: ['esm', 'cjs'],
64+
target: 'es2022',
65+
minify: true,
66+
bundle: true,
67+
noExternal: [IMTBL_WORKSPACE, '@uniswap/swap-router-contracts'],
68+
treeshake: true,
69+
esbuildPlugins: [
70+
replace({ __SDK_VERSION__: pkg.version }),
71+
],
72+
},
73+
];
74+
});

0 commit comments

Comments
 (0)