Follow-up to #76 (closed #75), filed against my own gate.
#76 turned on declaration emission and added a check that every declared types target is present in the tarball. That check asserts the file exists. It does not assert the file resolves — which is the only thing a consumer experiences.
A peer caught the consequence in d2f8b96: src/sdk-server.ts:12 does
import type { McpSdkServerConfigWithInstance } from "@anthropic-ai/claude-agent-sdk";
and that package is an optional peer dependency:
"peerDependencies": { "@anthropic-ai/claude-agent-sdk": ">=0.3.0" },
"peerDependenciesMeta": { "@anthropic-ai/claude-agent-sdk": { "optional": true } }
While dts: false meant nothing was emitted, that type reference never reached anyone. Now that sdk-server.d.ts is real, a consumer who installs @wave-av/mcp-server without the optional peer and type-checks @wave-av/mcp-server/sdk-server will fail to resolve McpSdkServerConfigWithInstance.
This is a general point about the change, not a regression: turning a dormant code path on is a behaviour change, and everything inside it becomes reachable for the first time.
What the gate should do instead
Add a smoke arm that type-checks the installed tarball from the consumer's side, without optional peers present — which is exactly the install shape the existing smoke already creates:
- In the throwaway project the smoke already builds, write a tiny
.ts that imports both the root and ./sdk-server.
- Run
tsc --noEmit against it with a minimal tsconfig.
- Fail on unresolved types.
That converts existsSync into a real assertion. It would have caught this before merge.
Open question worth deciding first
Which behaviour do we actually want?
- (a) Accept it — the
./sdk-server subpath is documented as requiring the peer, so failing to type-check without it is correct. Then the smoke arm should install the peer before checking that subpath, and check the root without it.
- (b) Make the types self-contained — inline or re-declare the config type so
sdk-server.d.ts has no hard reference to an optional package. Costs a duplicated type, buys a package that type-checks standalone.
I lean (a): the peer is genuinely required to use that entry point, so requiring it to type-check that entry point is honest. But it should be a decision, not an accident, and the CHANGELOG note from d2f8b96 should say which one we chose.
Related: #75, #76.
Follow-up to #76 (closed #75), filed against my own gate.
#76 turned on declaration emission and added a check that every declared
typestarget is present in the tarball. That check asserts the file exists. It does not assert the file resolves — which is the only thing a consumer experiences.A peer caught the consequence in
d2f8b96:src/sdk-server.ts:12doesand that package is an optional peer dependency:
While
dts: falsemeant nothing was emitted, that type reference never reached anyone. Now thatsdk-server.d.tsis real, a consumer who installs@wave-av/mcp-serverwithout the optional peer and type-checks@wave-av/mcp-server/sdk-serverwill fail to resolveMcpSdkServerConfigWithInstance.This is a general point about the change, not a regression: turning a dormant code path on is a behaviour change, and everything inside it becomes reachable for the first time.
What the gate should do instead
Add a smoke arm that type-checks the installed tarball from the consumer's side, without optional peers present — which is exactly the install shape the existing smoke already creates:
.tsthat imports both the root and./sdk-server.tsc --noEmitagainst it with a minimal tsconfig.That converts
existsSyncinto a real assertion. It would have caught this before merge.Open question worth deciding first
Which behaviour do we actually want?
./sdk-serversubpath is documented as requiring the peer, so failing to type-check without it is correct. Then the smoke arm should install the peer before checking that subpath, and check the root without it.sdk-server.d.tshas no hard reference to an optional package. Costs a duplicated type, buys a package that type-checks standalone.I lean (a): the peer is genuinely required to use that entry point, so requiring it to type-check that entry point is honest. But it should be a decision, not an accident, and the CHANGELOG note from
d2f8b96should say which one we chose.Related: #75, #76.