Repository navigation
Keep the test and snapshot harness out of production installs (0.4.0) - #72
Merged
Merged
Conversation
`pgstencil/database` now imports testcontainers when it starts or reattaches local services and node-pg-migrate when `migrate` runs, so reading migration sources or migrating a persistent database no longer loads the Docker client. `pgstencil/snapshots` loads cheerio and turndown at import. Each goes through `importPeer`, which names the missing package and the entry point that needs it, ready for these packages to become optional peers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
testcontainers, node-pg-migrate, cheerio and turndown move from pgstencil's dependencies to optional peerDependencies, so an application that imports only the runtime entry points no longer installs the Docker client stack, the migration runner or the HTML-to-Markdown converter. pg stays a dependency: `pgstencil/postgres` uses it at request time. The workspace keeps them as pgstencil devDependencies, the examples that start local databases declare the two they load, and the packed consumer in `packages:verify` installs the optional peers (and node-pg-migrate's pg peer) as devDependencies, the way a tooling user would. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`scripts/runtime-deps.test.mjs` (in `pnpm test:scripts`) fails if any package lists testcontainers, node-pg-migrate, cheerio or turndown in dependencies or optionalDependencies, if pgstencil stops declaring them optional peers, or if any published entry point reaches one by a static import, through workspace or third-party code. It bundles each entry with esbuild and also requires that each tooling package is still seen dynamically, so it cannot pass vacuously. `packages:verify` now also installs the packed archives with `--prod` into a runtime-only consumer, with peers auto-installed, and fails if an optional peer lands there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PACKAGES.md gains a "Tooling peers" section: the peers `pgstencil/database`, `pgstencil/testing` and `pgstencil/snapshots` load, when each loads, the one install line, and that migrating a persistent database needs node-pg-migrate but not testcontainers. The package README and the root README point at it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Minor bump: an application that uses `pgstencil/database`, `pgstencil/testing` or `pgstencil/snapshots` must now install testcontainers, node-pg-migrate, cheerio and turndown itself (PACKAGES.md -> Tooling peers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
pgstencil0.3.0 listspg,node-pg-migrate,testcontainers,cheerioandturndownindependencies. Onlypgis used at request time. The rest belong to the Docker test-database harness, the migration runner and the HTML-to-Markdown snapshot lens. So any application that imports only the runtime entry points still installs the Docker client stack (dockerode,docker-modem,ssh2, ...), Cheerio and Turndown in production. Dormouse generates its supply-chain disclosure from the lockfile graph, so its Hosted section lists 323 packages while its Workers bundle about 33.Design
I followed the import graph:
pgstencil,pgstencil/postgresandpgstencil/diagnostics, plus every@pgstencil/authand@pgstencil/stripeexport. None of them imports a tooling package.pgstencil/databaseusestestcontainersandnode-pg-migrate.pgstencil/testinguses both throughdatabase.pgstencil/snapshotsusescheerioandturndown.node-pg-migrateis tooling.migrateis a release step, never something a deployed server runs. The docs already say to "apply migrations as a separate release step", the workspace runs it frompnpm db:migrate, and Dormouse runs it fromtsx server/db.ts.pgstays runtime.pgstencil/postgresuses it at request time.What changed:
Optional peers. The four tooling packages move to
peerDependencies, each markedoptionalinpeerDependenciesMeta. They keep the same ranges, so the floor is still the version CI tests. pnpm and npm do not install optional peers automatically, so a production install leaves them out. The workspace keeps them aspgstencildevDependencies, the same pattern askysely.Loaded on first use, with a clear error. Each tooling package is loaded through a new internal
importPeerhelper, using dynamicimport():testcontainersloads whenensureServicesruns.node-pg-migrateloads whenmigrateruns.snapshotsloadscheerioandturndownwith a top-level await, sohtmlToMarkdownstays synchronous.If a peer is missing, the error names the peer and the entry point that needs it, for example:
pgstencil/database needs the optional peer dependency "testcontainers". Add it to your project, for example: pnpm add -D testcontainers.One side effect helps: migrating a persistent database, or only reading migration sources, no longer loads the Docker client.
I did not split out a separate package. Optional peers fix the install graph without changing the published API.
@pgstencil/authand@pgstencil/stripewere checked and do not have this problem. Auth'sbetter-auth,joseandopenid-clientare all used at runtime, and Stripe has no dependencies. Neither package changed beyond the version.Consumer changes
No API change. Every export has the same names and signatures. The
.d.tsfiles do not reference the tooling packages.Install change, so this is a minor bump to 0.4.0. An application that imports
pgstencil/database,pgstencil/testingorpgstencil/snapshotsmust now add the peers it uses, usually as devDependencies:PACKAGES.md→ "Tooling peers" lists which entry point loads which peer, and when. If a release step runsmigratefrom a production install, it needsnode-pg-migrate, which peers onpg, as a regular dependency. It does not needtestcontainers.Dormouse Hosted, when it adopts the release, needs
testcontainersandnode-pg-migrateas devDependencies, forpgstencil/testingin its tests anddevelopmentDatabaseinserver/dev.ts. Itsdb:migratestep needs onlynode-pg-migrate. Nothing in its Workers changes.Consumer package count
I packed the archives and ran
pnpm install --prodon them in a scratch project, counting distinct packages innode_modules/.pnpm:kysely,hono,stripepgstencil+@pgstencil/auth+kysely,honoAfter the change, none of
testcontainers,node-pg-migrate,cheerio,turndown,dockerode,docker-modemorssh2is installed. In that same production install:pgstencil,/postgres,/diagnostics,@pgstencil/auth/better-auth-workersand@pgstencil/stripeall import.pgstencil/databaseimports, andreadMigrationsworks.migrate(),ensureServices()andimport('pgstencil/snapshots')each fail with the clear message.Regression check
scripts/runtime-deps.test.mjs(run bypnpm test:scripts) fails if:dependenciesoroptionalDependencies;pgstencilstops declaring one as an optional peer;It bundles each export with esbuild and records each place a tooling package is imported, and how. It also requires that each tooling package is still seen as a dynamic import, so the test cannot pass vacuously. The list lives in
scripts/tooling-peers.json.pnpm packages:verifynow also installs the packed archives with--prod, with peers auto-installed, into a separate runtime-only consumer. It fails if any of the listed packages lands there. The existing full consumer now installs the tooling peers as devDependencies and still runs the login and billing flow end to end.Mutation results (each reverted afterwards):
testcontainersmoved back todependenciespackages:verify("A production install of the packages includes testcontainers")node-pg-migrateimport inmigrations.ts, re-exported frompostgres.tspgstencil/postgres,pgstencil/database,pgstencil/testingand three auth entries that reach it throughpgstencil/postgresimport 'cheerio'indiagnostics.tspgstencil/diagnosticsand three auth entriescheeriodynamic import turned non-literalTest results
All of these ran locally on Node 26 with Docker running, and all passed:
pnpm check: format, typecheck, 30 script tests, and 24 Vitest files / 187 tests, including the Docker integration suitepnpm db:verifypnpm --filter @pgstencil/example-workers buildpnpm packages:verifyCI runs Node 24.
Release
The last commit raises all three packages to 0.4.0, the same way #54 cut 0.3.0. After merge,
release.ymlstages the packages, and a human approves them with 2FA. Nothing has been published or tagged.🤖 Generated with Claude Code