|
| 1 | +# Design: TypeScript Types + Hosted API Reference |
| 2 | + |
| 3 | +Date: 2026-06-16 |
| 4 | +Issue: #44 — ship `.d.ts` types and generate an API reference with TypeDoc |
| 5 | +Branch: `44-ship-dts-types-and-generate-an-api-reference-with-typedoc` |
| 6 | + |
| 7 | +## Goal |
| 8 | + |
| 9 | +Guarantee that consumers of the `claudius-chat-widget` npm package get full |
| 10 | +TypeScript IntelliSense, and auto-generate a hosted API reference from |
| 11 | +TSDoc comments that is published under the existing docs domain. |
| 12 | + |
| 13 | +## Background (current state) |
| 14 | + |
| 15 | +- `widget` publishes as `claudius-chat-widget`. It already declares |
| 16 | + `types: "./dist/index.d.ts"` and ships declarations, but the build runs |
| 17 | + `tsc --emitDeclarationOnly`, which emits a **37-file tree** (including |
| 18 | + dev-only `main.d.ts`, `embed.d.ts`, and `test-utils/`) rather than one |
| 19 | + bundled entry. |
| 20 | +- The public surface is the barrel `widget/src/index.ts`: `ChatWidget` + |
| 21 | + `ChatWidgetProps`, `WidgetPosition`, translations API, locales API, |
| 22 | + `Trigger`/`TriggerAction`/`UrlPattern`, themes + theme token types, |
| 23 | + `ChatApiClient` + options, error classes, and the `Source`/`ChatMessage`/ |
| 24 | + `Chat*` request/response types. Only the `theme` prop currently has a |
| 25 | + TSDoc comment. |
| 26 | +- Docs are an Astro + Starlight site in `docs/`, deployed to the |
| 27 | + `claudius-docs` Cloudflare Pages project by `.github/workflows/docs.yml`. |
| 28 | + The sidebar already has an **API Reference** group, and there is an |
| 29 | + existing precedent for linking a sibling Pages site (Storybook, with |
| 30 | + `target: _blank` and a badge). |
| 31 | +- `ci.yml` runs the widget job: lint, format:check, typecheck, test, build. |
| 32 | + There is no TypeDoc and no doc-coverage gate yet. |
| 33 | + |
| 34 | +## Decisions (validated with user) |
| 35 | + |
| 36 | +1. **Type bundling:** single rolled-up `dist/index.d.ts` via |
| 37 | + `vite-plugin-dts` (`rollupTypes: true`), replacing `tsc --emitDeclarationOnly`. |
| 38 | +2. **API-reference hosting:** TypeDoc emits **HTML** to `widget/dist/api`; |
| 39 | + that HTML is copied into the Astro site and deployed with the existing |
| 40 | + `claudius-docs` Pages project at **`/api/`**. One domain, one deploy, |
| 41 | + one nav link, no new Pages project or secrets. |
| 42 | +3. **Export-correctness guarantee (beyond AC):** add `@arethetypeswrong/cli` |
| 43 | + + `publint` to prove ESM/CJS consumers resolve types correctly. |
| 44 | +4. **Visual verification (beyond AC):** screenshot the rendered `/api/` |
| 45 | + reference and the docs sidebar link as part of verification. |
| 46 | + |
| 47 | +## Components |
| 48 | + |
| 49 | +### 1. Single bundled `index.d.ts` |
| 50 | +- Add `vite-plugin-dts` to `widget`; configure in `vite.config.ts` (lib build |
| 51 | + only) with `rollupTypes: true`, `tsconfigPath: './tsconfig.json'`, |
| 52 | + `include: ['src']`, excluding tests and stories. |
| 53 | +- Remove `tsc --emitDeclarationOnly` from `build` / `build:lib`. Keep |
| 54 | + `typecheck: tsc --noEmit`. Simplify `tsconfig.json` emit options that the |
| 55 | + plugin now owns. |
| 56 | +- Outcome: one `dist/index.d.ts` containing only the public surface. |
| 57 | + |
| 58 | +### 2. TSDoc on every public export |
| 59 | +- Document each symbol reachable from `src/index.ts`, and each member of |
| 60 | + exported interfaces (props, theme inputs, client options, message/source |
| 61 | + types). Use `@param`, `@returns`, `@defaultValue`, `@example`, `@see`. |
| 62 | +- Mark genuinely-internal helpers `@internal` so they are excluded from both |
| 63 | + the generated docs and the coverage gate. |
| 64 | + |
| 65 | +### 3. TypeDoc generation — `pnpm docs:api` |
| 66 | +- Add `typedoc` to `widget`; `typedoc.json` with `entryPoints: ["src/index.ts"]`, |
| 67 | + `out: "dist/api"` (HTML), `excludeInternal/Private/Externals: true`, exclude |
| 68 | + tests/stories, `validation.notDocumented: true`, `treatWarningsAsErrors: true`. |
| 69 | +- Scripts: `docs:api` (full HTML) and `docs:api:check` (`typedoc --emit none`, |
| 70 | + fast validation-only). |
| 71 | + |
| 72 | +### 4. Host under the docs domain at `/api/` |
| 73 | +- `docs/scripts/copy-api.mjs` (run as docs `prebuild`): copy `../widget/dist/api` |
| 74 | + into `docs/public/api/` when present; warn and skip when absent so docs-only |
| 75 | + local builds still succeed. |
| 76 | +- `docs.yml`: add steps to install the widget and run `pnpm docs:api` before the |
| 77 | + docs build; add `widget/**` to the path triggers so the reference rebuilds |
| 78 | + when the public API changes. |
| 79 | +- Add a sidebar item to the existing **API Reference** group: |
| 80 | + `{ label: "Generated Reference (TypeDoc)", link: "/api/", attrs: { target: "_blank", rel: "noopener noreferrer" }, badge: { text: "typedoc" } }`. |
| 81 | +- `.gitignore`: add `docs/public/api/` (generated, not committed). |
| 82 | + |
| 83 | +### 5. CI doc-coverage gate |
| 84 | +- `treatWarningsAsErrors` + `validation.notDocumented` make `docs:api:check` |
| 85 | + exit non-zero on any undocumented public symbol or broken `@link`. |
| 86 | +- `ci.yml` widget job gains a **TSDoc coverage** step (`pnpm docs:api:check`) |
| 87 | + and an export-correctness step (`attw` + `publint`). The existing Build step |
| 88 | + now also exercises `vite-plugin-dts`. |
| 89 | + |
| 90 | +### 6. Verification (including visual) |
| 91 | +- After `pnpm build`: assert a single `dist/index.d.ts` with no leftover |
| 92 | + `dist/components/*.d.ts`; run `attw` + `publint` on the packed tarball. |
| 93 | +- Build docs, then screenshot the rendered `/api/` reference and the docs |
| 94 | + sidebar link to confirm rendering and wiring. |
| 95 | + |
| 96 | +## Acceptance-criteria mapping |
| 97 | + |
| 98 | +| Acceptance criterion | Component | |
| 99 | +|---|---| |
| 100 | +| Vite build emits a single `index.d.ts` bundle | 1 | |
| 101 | +| All public exports have TSDoc comments | 2, 5 (enforced) | |
| 102 | +| `pnpm docs:api` runs TypeDoc -> HTML in `dist/api` | 3 | |
| 103 | +| Generated reference published to Cloudflare Pages + linked from docs | 4 | |
| 104 | +| CI fails if any public export lacks a TSDoc summary | 5 | |
| 105 | + |
| 106 | +## Risks / notes |
| 107 | + |
| 108 | +- `rollupTypes` uses `@microsoft/api-extractor` under the hood; complex type |
| 109 | + constructs can produce warnings. The public types here are simple (string |
| 110 | + unions + interfaces), so risk is low. Verify the single-file output and |
| 111 | + consumer resolution with `attw`. |
| 112 | +- Hosting at bare `/api/` is collision-free with the existing `/api/rest` and |
| 113 | + `/api/widget` content routes (no shared file/route names). Confirmed. |
| 114 | +- Local docs `dev`/`build` without first generating the widget API will show |
| 115 | + no `/api/`; the tolerant copy script makes this a warning, not a failure. |
| 116 | + |
| 117 | +## Out of scope |
| 118 | + |
| 119 | +- Auto-generating Markdown prop tables into the hand-written docs (that was the |
| 120 | + "Markdown in Starlight" option, not chosen). The generated reference is the |
| 121 | + canonical source; hand-written pages may link to it. |
| 122 | +- Worker package API docs (the npm consumer surface is the widget). |
0 commit comments