Skip to content

feat(wire): startServerAsync exposes the resolved bound port#87

Merged
tangletools merged 1 commit into
mainfrom
feat/start-server-expose-bound-port
May 23, 2026
Merged

feat(wire): startServerAsync exposes the resolved bound port#87
tangletools merged 1 commit into
mainfrom
feat/start-server-expose-bound-port

Conversation

@tangletools
Copy link
Copy Markdown
Contributor

Summary

Adds `startServerAsync({ port: 0 })` that resolves with `{ server, port, host, close }` once the server is listening. Smoke tests + sidecars that need to dial back to the bound port can read it directly instead of guessing free ports.

Motivation

The four product ingestion-server smoke tests (tax/legal/creative/gtm) worked around this by picking `30000 + Math.floor(Math.random() * 10000)` — birthday-collides under N parallel vitest workers. Surfaced in the cross-product audit (legal #105 M1).

The original `startServer` returns a `ServerType` and only logs the bound port to console; the kernel-assigned port is invisible to callers.

Changes

  • `src/wire/server.ts`: new `StartedServer` interface (`{ server, port, host, close }`) + `startServerAsync()` resolves with the bound port; original `startServer` unchanged (CLI uses it).
  • `src/wire/index.ts`: re-export `StartedServer` + `startServerAsync`.
  • `tests/wire/server.test.ts`: 2 new tests — port-0 binds with healthz roundtrip, two concurrent servers receive distinct ports.

Verification

  • `pnpm typecheck` clean
  • `pnpm test` — 1319/1319 pass (135 files, +2 new tests)
  • `pnpm build` clean

Version

`0.34.1` → `0.35.0` (additive, no breaking changes).

Follow-up

Product repos consuming `startServer` in smoke tests can switch to `startServerAsync({ port: 0 })` for deterministic concurrent-test runs. Not blocking — non-zero ports still work as before.

Smoke tests (and any sidecar that registers with a parent) need the
actual port the kernel bound when `opts.port === 0`. `startServer`'s
callback fires it but doesn't surface it to the caller; smoke tests
across the four product repos worked around this with random-port-in-
range loops that birthday-collide under parallel vitest workers.

`startServerAsync({ port: 0 })` resolves with `{ server, port, host,
close }` once the server is listening. The original `startServer`
remains for the CLI entry that blocks-forever on SIGINT.

- src/wire/server.ts: new `StartedServer` interface + `startServerAsync`
- src/wire/index.ts: re-export `StartedServer` + `startServerAsync`
- tests/wire/server.test.ts: 2 tests — port-0 binds + concurrent servers
  get distinct ports

1319 tests pass. Bump to 0.35.0.
@tangletools tangletools merged commit b84a478 into main May 23, 2026
@tangletools tangletools deleted the feat/start-server-expose-bound-port branch May 23, 2026 23:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants