Follow-up cleanup for the 7 confirmed findings from a review of #163. The dominant theme: #163 hard-renamed the public composable useTerminalSize -> useWindowSize (no alias) but left stale references to the dead name in user-facing docs. - README.md + packages/runtime/README.md: the composable tables named the removed `useTerminalSize()` (root README even framed the sole real export `useWindowSize` as an "Ink-compat alias" — now inverted). Point both at `useWindowSize()`. - .agents/docs/ink-divergences.md: two vue-tui-side references to `useTerminalSize` (the shallowRef "object of refs" example and the "composables throw outside a render tree" list) -> `useWindowSize`. The Ink-side `useWindowSize -> WindowSize` naming example is left unchanged. - .agents/docs/accessibility-api.md: the intro cited three "blessed entries" but only aria-camelCase is one; `renderToString` layout-only and the `useWindowSize` name are now Ink parity, not divergences. Reword. - .agents/docs/api-contract.md: tighten the `/internal` wording — the test does assert one tripwire on `/internal`, so "not covered by public-api.test.ts" was imprecise. - public-api.test.ts / render-to-string.test.tsx: the public renderToString dropped the `isScreenReaderEnabled` option but (unlike the sibling `ScreenReaderOptions` type) had no compile-time guard. Replace an obscure, fmt-fragile type-indexing guard with a readable call-site `@ts-expect-error` in render-to-string.test.tsx; re-adding the option to the public RenderToStringOptions makes the directive unused and fails `tsc --noEmit`. - Rename terminal-size.test.tsx / .sequential.test.tsx -> window-size.test.tsx / .sequential.test.tsx to match the migrated symbol. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.7 KiB
Public API contract & surface
What is — and isn't — part of @vue-tui/runtime's public contract, and how the contract is
tested. (Behavioral divergences from Ink live in ink-divergences; this file is about the
SHAPE of the public surface itself.)
The contract = public exports and their user-consumable types
The public API is everything exported from the main barrel (@vue-tui/runtime): components,
composables, entry points — and their TYPES (component prop types, composable return/options
types, and named types such as AriaRole, WindowSize, BoxProps, UseXReturn / UseXOptions).
A type is as much a part of the contract as runtime behavior. If user code can name a type and annotate with it, renaming or removing it breaks that code at COMPILE time — exactly as severe as a runtime break. So a type rename/removal is a breaking change, and the type surface is the most important part of the contract to get right.
Because it is contract, it is tested, not merely shipped:
public-api.test.tssnapshots the exact public value-export set — adding, removing, or renaming any runtime export fails it, so every surface change must be a deliberate edit there. Specific internal-only members (measureText, the screen-reader linearizer) are additionally tripwired, and internal-only types (e.g.ScreenReaderOptions) are guarded with a compile-time@ts-expect-error. Type-only exports are erased at runtime, so the type surface is guarded individually rather than exhaustively snapshotted.- Type-safety behavior is established by RUNNING the type-checker against real usage (
tscfor TSX,vue-tscfor templates), never assumed. See accessibility-api for a worked example — which aria spellings the compiler does and does not catch, proven with both tools.
/internal is NOT the contract
@vue-tui/runtime/internal is an explicitly internal / advanced surface — host-node types
(TuiNode, …), test-only helpers (renderToStringWithScreenReader), dev/HMR types (DevState,
DevErrorInfo), kitty-controller internals, etc. It carries no stability guarantee: its
surface is not snapshotted by public-api.test.ts (a member may be tripwired there to prove it is
internal, but the surface itself carries no contract), and may change freely between releases.
Placement rule for any export:
- A user-facing contract → the main barrel (and it is tested).
- Needed only by tests or advanced integrators →
/internal, never the main barrel.
Packaging/build internals (the exports field shape, .mjs paths, dist layout) are likewise
not part of the behavioral/type contract and are not aligned to Ink — see the alignment-scope
note in ink-divergences.