Files
vue-tui/.agents/docs/api-contract.md
T
Yunfei He f847e17c81 docs(runtime): finish the useWindowSize rename in docs; tidy contract guards (#164)
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>
2026-06-14 02:04:16 +08:00

46 lines
2.7 KiB
Markdown

# 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.ts` snapshots 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 (`tsc` for
TSX, `vue-tsc` for 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]].