Uh oh!
There was an error while loading. Please reload this page.
Publish JSDoc-derived type declarations (icebird-style, no copy) - #184
Publish JSDoc-derived type declarations (icebird-style, no copy)#184platypii wants to merge 2 commits into
Conversation
Consumers of the package got real types only for the two entry points that
happened to have a hand-written sibling .d.ts (`.`/`./core` and `./integration`);
the other four (`./core/observability`, `./core/sinks`, `./core/query`, `./tui`)
resolved to implicit `any`, because TypeScript does not read JSDoc out of an
installed package's `.js` and there was no declaration build.
Add a declaration build modeled on icebird: `tsconfig.build.json` emits `.d.ts`
(+ maps) from JSDoc with `rootDir: src` -> `outDir: types`, run via
`build:types` and wired to `prepare` so it runs before pack/publish. `types/` is
gitignored and shipped through the `files` allowlist; `exports` gains a `types`
condition per entry (generated `types/...` for JSDoc-only entries, the
hand-written `src/...d.ts` for the barrel entries).
The icebird mechanism needs every type-import specifier to resolve identically
from both `src/<P>/x.js` and the parallel generated `types/<P>/x.d.ts`. Anchor
all 159 such specifiers to repo-root `.js` paths (e.g. `../../src/core/types.js`)
so tsc keeps them verbatim and they resolve from both trees. Documented as the
project convention in AGENTS.md.
Three targeted fixes remove the only hand-written-.d.ts -> JSDoc-module
couplings that the two-tree split cannot bridge:
- cli/types.d.ts: use the named `KernelRuntime` instead of
`ReturnType<typeof createKernelRuntime>` (drops the activation.js dependency).
- observability/types.d.ts: declare `ObservabilityHandle` as an explicit
interface instead of deriving it from `typeof installObservability`; the
precise provider types still reach consumers via the generated `index.d.ts`.
- observability/tracer.js: `@import { Span }` so the emitted tracer declaration
resolves `Span` from its sibling generated `runtime.d.ts`.
One dynamic `hypaware-core` import in core_commands.js is indirected through a
variable so the declaration build (rootDir: src) does not pull that module under
src's emit root (TS6059).
Verified with an external-consumer probe (strict, nodenext) importing all six
entry points: types resolve for every entry (negative control errors as
expected). typecheck, lint (423 files), and npm test (1473 pass) all green.platypii
commented
Jun 28, 2026
Validation against the real packed tarballBuilt the tarball via Tarball ships the types: 226 generated Types resolve as real (not
Runtime importability — Minor pre-existing note (not introduced here): |
The hand-written cli/integration.d.ts exposed the instance fields but no
constructor, so consumers (resolving the public ./integration entry) inherited
Error's (message, options) signature and could not construct the error with its
{code, stdout, stderr, json} detail under types. Declare the real constructor so
the public type matches integration.js. Validated against the packed tarball: a
clean consumer can now construct it with typed detail and mistyped detail is
rejected.platypii
commented
Jun 28, 2026
Follow-up: declared the |
Publish real types to consumers
Today consumers get real types only for the two entries with a hand-written sibling
.d.ts(././core,./integration); the other four (./core/observability,./core/sinks,./core/query,./tui) resolve to implicitany, because TypeScript does not read JSDoc out of an installed package's.jsand there is no declaration build.Approach (icebird-style, no copy)
tsconfig.build.jsonemits.d.ts(+ maps) from JSDoc withrootDir: src→outDir: types, run viabuild:typesand wired toprepare.types/is gitignored and shipped through thefilesallowlist.exportsgains atypescondition per entry: generatedtypes/...for JSDoc-only entries, the hand-writtensrc/...d.tsfor the barrel entries..jspath (e.g.../../src/core/types.js) so the same import resolves identically from bothsrc/<P>/x.jsand the generatedtypes/<P>/x.d.ts. Documented as the project convention in AGENTS.md.Targeted fixes (the only hand-written-
.d.ts→ JSDoc-module couplings the split can't bridge)cli/types.d.ts: use the namedKernelRuntimeinstead ofReturnType<typeof createKernelRuntime>.observability/types.d.ts: declareObservabilityHandleas an explicit interface (precise provider types still reach consumers via the generatedindex.d.ts).observability/tracer.js:@import { Span }so the emitted declaration resolvesSpanfrom its sibling generatedruntime.d.ts.hypaware-coreimport incore_commands.jsis indirected through a variable so the build (rootDir: src) does not pull it under src's emit root (TS6059).Verification
External-consumer probe (strict, nodenext) importing all six entry points: types resolve for every entry; negative control errors as expected.
typecheck,lint(423 files), andnpm test(1473 pass) all green.Notes
types/) avoids the convention but reintroduces a copy step.