Problem
packages/loopover-miner/lib/** is 117 plain .js files, each with a hand-maintained .d.ts
sibling providing its types to consumers. Nothing actually verifies these stay in sync: the root
tsconfig.json's include is ["src", "test", ...] -- it never includes
packages/loopover-miner/lib itself, so the .js implementation is never compiled against its own
.d.ts. Type drift is only ever caught by luck, if some test/unit/miner-*.test.ts file's usage
happens to exercise the exact mismatched signature -- not by the compiler, which is the entire
point of having types. This is double the maintenance burden (every signature change means editing
two files by hand, in sync, with nothing enforcing it) for none of TypeScript's actual safety
guarantee.
Why plain .js was chosen (context, not a defense of the current gap)
packages/loopover-miner's own build script is literally node --check on every file -- no
tsc compilation step. This is a deliberate, real tradeoff: the package ships as directly-runnable
Node.js (npm install -g @loopover/miner then loopover-miner ... works with no build/transpile
step), which is genuinely valuable for a CLI tool. That property is worth preserving. What's NOT
worth preserving is losing compiler-verified types to get it -- tsc's own output can be plain,
directly-runnable JS (strip types, keep the code), so a proper TypeScript source with a real build
step does not have to sacrifice the zero-transpile-at-runtime property; it just needs the build
step to happen once, ahead of publish, instead of never.
Proposal
Convert packages/loopover-miner/lib/** (and bin/**) from .js + hand-maintained .d.ts to
real .ts source, compiled via tsc into the published package's actual JS output (mirroring how
packages/loopover-engine's src/ is already 100% real TypeScript with zero hand-maintained
.d.ts files anywhere in it -- the proven precedent in this same monorepo). The compiled output
stays a directly-runnable node bin/loopover-miner.js-shaped artifact; only the source changes,
not the distribution shape.
Deliberately NOT scoped as one PR. 117 files is too large and too risky for a single change --
this is a large, multi-phase migration, not a mechanical one-shot. Recommended phasing, smallest
and most-isolated first (matching the incremental discipline already proven tonight for the
storage-seam migration):
- Build tooling: add a real
tsc build step to packages/loopover-miner's own package.json
(build/typecheck scripts), a packages/loopover-miner/tsconfig.json, and CI wiring -- with
zero source files converted yet, just proving the build pipeline itself works end-to-end
(compiles, the CLI still runs, the package still publishes correctly) against a trivial single
converted file as a smoke test.
- Convert the leaf-most, lowest-fan-in modules first (small, standalone stores/utilities with few
internal dependents) -- lower risk, faster to review, builds momentum and catches build-tooling
issues on small blast-radius changes before tackling anything foundational.
- Convert the CLI command files (
*-cli.js) and bin/*.js entry points.
- Convert the foundational/most-depended-on modules last (
local-store.js, store-db-adapter.js,
event-ledger.js, and anything else many other files import) -- highest blast radius, do this
once the pattern is fully proven on everything else.
- Remove every now-redundant hand-maintained
.d.ts file as its .js sibling converts (a .ts
file's types ARE the implementation -- no separate declaration file needed once converted).
Each phase should be filed as its own follow-up issue once the prior phase lands, sized to a
reviewable PR (a handful of files, not all-at-once) -- do not attempt to enumerate all 117 files
into sub-issues up front; let the phasing above guide real-time scoping as work progresses.
Deliverables
Test Coverage Requirements
No behavior should change from this migration alone -- it's a source-representation change, not a
logic change. Existing tests must continue to pass unmodified (only import paths/build output
shape might need adjustment). packages/loopover-miner/lib/** remains under Codecov's normal
99% patch-coverage gate for any genuinely new code introduced alongside a conversion PR.
Expected Outcome
packages/loopover-miner's source is real, compiler-verified TypeScript with the same
zero-transpile-at-runtime distribution shape it has today, and the current double-maintenance,
drift-prone .js + hand-authored .d.ts pattern is gone.
Links & Resources
packages/loopover-engine/src/** -- the proven, already-100%-TypeScript precedent in this same
monorepo
packages/loopover-miner/package.json's build script -- the current node --check-only build
- Root
tsconfig.json -- confirms packages/loopover-miner/lib is not in include today
Problem
packages/loopover-miner/lib/**is 117 plain.jsfiles, each with a hand-maintained.d.tssibling providing its types to consumers. Nothing actually verifies these stay in sync: the root
tsconfig.json'sincludeis["src", "test", ...]-- it never includespackages/loopover-miner/libitself, so the.jsimplementation is never compiled against its own.d.ts. Type drift is only ever caught by luck, if sometest/unit/miner-*.test.tsfile's usagehappens to exercise the exact mismatched signature -- not by the compiler, which is the entire
point of having types. This is double the maintenance burden (every signature change means editing
two files by hand, in sync, with nothing enforcing it) for none of TypeScript's actual safety
guarantee.
Why plain
.jswas chosen (context, not a defense of the current gap)packages/loopover-miner's ownbuildscript is literallynode --checkon every file -- notsccompilation step. This is a deliberate, real tradeoff: the package ships as directly-runnableNode.js (
npm install -g @loopover/minerthenloopover-miner ...works with no build/transpilestep), which is genuinely valuable for a CLI tool. That property is worth preserving. What's NOT
worth preserving is losing compiler-verified types to get it --
tsc's own output can be plain,directly-runnable JS (strip types, keep the code), so a proper TypeScript source with a real build
step does not have to sacrifice the zero-transpile-at-runtime property; it just needs the build
step to happen once, ahead of publish, instead of never.
Proposal
Convert
packages/loopover-miner/lib/**(andbin/**) from.js+ hand-maintained.d.tstoreal
.tssource, compiled viatscinto the published package's actual JS output (mirroring howpackages/loopover-engine'ssrc/is already 100% real TypeScript with zero hand-maintained.d.tsfiles anywhere in it -- the proven precedent in this same monorepo). The compiled outputstays a directly-runnable
node bin/loopover-miner.js-shaped artifact; only the source changes,not the distribution shape.
Deliberately NOT scoped as one PR. 117 files is too large and too risky for a single change --
this is a large, multi-phase migration, not a mechanical one-shot. Recommended phasing, smallest
and most-isolated first (matching the incremental discipline already proven tonight for the
storage-seam migration):
tscbuild step topackages/loopover-miner's ownpackage.json(
build/typecheckscripts), apackages/loopover-miner/tsconfig.json, and CI wiring -- withzero source files converted yet, just proving the build pipeline itself works end-to-end
(compiles, the CLI still runs, the package still publishes correctly) against a trivial single
converted file as a smoke test.
internal dependents) -- lower risk, faster to review, builds momentum and catches build-tooling
issues on small blast-radius changes before tackling anything foundational.
*-cli.js) andbin/*.jsentry points.local-store.js,store-db-adapter.js,event-ledger.js, and anything else many other files import) -- highest blast radius, do thisonce the pattern is fully proven on everything else.
.d.tsfile as its.jssibling converts (a.tsfile's types ARE the implementation -- no separate declaration file needed once converted).
Each phase should be filed as its own follow-up issue once the prior phase lands, sized to a
reviewable PR (a handful of files, not all-at-once) -- do not attempt to enumerate all 117 files
into sub-issues up front; let the phasing above guide real-time scoping as work progresses.
Deliverables
tscbuild pipeline wired forpackages/loopover-miner, proven against oneconverted file
follow-up issues, not enumerated here)
.d.tsremoved once its.jssibling convertstsconfig.json(or the package's own) actually type-checks the converted source againstits own implementation, closing the drift gap this issue exists to fix
Test Coverage Requirements
No behavior should change from this migration alone -- it's a source-representation change, not a
logic change. Existing tests must continue to pass unmodified (only import paths/build output
shape might need adjustment).
packages/loopover-miner/lib/**remains under Codecov's normal99% patch-coverage gate for any genuinely new code introduced alongside a conversion PR.
Expected Outcome
packages/loopover-miner's source is real, compiler-verified TypeScript with the samezero-transpile-at-runtime distribution shape it has today, and the current double-maintenance,
drift-prone
.js+ hand-authored.d.tspattern is gone.Links & Resources
packages/loopover-engine/src/**-- the proven, already-100%-TypeScript precedent in this samemonorepo
packages/loopover-miner/package.json'sbuildscript -- the currentnode --check-only buildtsconfig.json-- confirmspackages/loopover-miner/libis not inincludetoday