Conversation
Build/structure: - Replace Rollup + Jest with @b9g/libuild; tests via @b9g/libuild/test - Flatten packages/* into single package with subpath entry points: repeater/core (class only), repeater/static (race/merge/zip/latest as named fns), repeater/timers, repeater/limiters. Default `repeater` re-exports the full class with statics attached (no breaking change). - Deprecate pubsub (removed) and react-hooks (already gone) - Switch to npm lockfile; TypeScript 5.x with isolatedModules API: - Add Symbol.asyncDispose / Symbol.dispose (ES2025) with runtime guards - Rename aux exports: delay->createDelay, interval->createInterval, timeout->createTimeout, semaphore->createSemaphore, throttler->createThrottle - createStop uses Object.assign; push() float-detection uses Object.create(nextP) Fixes: - index.ts re-exported type-only names as runtime bindings, crashing ESM imports; split into export/export type. isolatedModules now guards this. Tests: 163/163 green on both node and bun. Refs #81 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address code review (two P2s): - Add root exports map for ./core, ./static, ./timers, ./limiters so subpaths resolve for file:/npm link/git installs, not just the registry tarball (which ships dist/package.json). - Add `prepare` script so dist/ is built on install for those same non-registry modes, since dist/ is gitignored. Verified: `npm run prepare` builds all 5 entry points from clean; a link-style install resolves every subpath via the root exports map. Refs #81 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Also normalize repository.url to git+https form to silence npm warning. Refs #81 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reconstruct core.ts from the original repeater.ts so the file keeps its explanatory JSDoc/rationale (buffer docs, state enum, RepeaterRecord fields, stop-vs-finish, the AsyncGenerator/implements note, the r.err rationale, the #49 executor-settle TODO) and the <T, TReturn, TNext> generics on the internal helpers, rather than the comment-stripped, any-typed extraction. Intentional deltas preserved: Object.create(nextP) float detection, Object.assign in createStop (+ onstop arity wrap), disposal symbols. tsc clean; 163/163 on node and bun; build emits with type-only names erased. Refs #81 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brainkim
commented
Jun 3, 2026
brainkim
left a comment
Member
Author
There was a problem hiding this comment.
Some general thoughts
- Rename src/static.ts -> src/combinators.ts (subpath becomes @repeaterjs/repeater/combinators); update index/limiters imports and regenerate the exports map. - Drop the custom rejection() test helper in favor of the built-in `expect(p).rejects` matcher, which works on bun for native promises (the helper was an over-correction; only the .resolves cases needed plain-await). tsc clean; 163/163 on node and bun. Refs #81 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a dependency-free internal util module aligned with crank's src/_utils.ts (isPromiseLike, isIteratorLike, safeRace) so the memory-safe race implementation stays in sync across bikeshaving packages. The underscore prefix keeps it out of libuild's entry points, so it bundles into importers rather than becoming a public subpath. Swap the two remaining raw Promise.race sites — limiters' stop/leak race and combinators' loser-cleanup — for safeRace, closing the last memory-leak vectors. (The advance/advances hack in combinators stays for now; a safeRace-based rewrite of race() is a separate, higher-risk pass.) tsc clean; 163/163 on node and bun; safeRace inlines into the combinators and limiters bundles. Refs #81 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the hand-rolled advance/advances deferred coordination in race, merge, zip, and latest with safeRace([work, stop]). Since stop resolves to undefined, a safeRace result of undefined doubles as the stop signal, which lets us drop every stopped flag and stop.then fan-out. merge/zip/latest are clean structural swaps (one pending next() per loop, no multi-pending). race keeps a per-next() done-observer so that any contender finishing still stops the race and records its return value even when it never wins a value turn — preserving the exact sample-fastest / stop-on-any-finish semantics. (A naive safeRace-winner rewrite loses the finisher's return value to a stranded next(); see the analysis in the PR.) Verified: 163/163 across 5x node + 3x bun stress runs. Refs #81 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New coverage for two features this release that had none: - src/test/dispose.ts: Symbol.asyncDispose / Symbol.dispose, `using` and `await using`, and that combinator results are disposable. - src/test/utils.ts: safeRace (first-settle, rejection, non-thenable and already-settled contenders, never-settling, shared promise, undefined sentinel) plus isPromiseLike / isIteratorLike. The dispose tests surfaced a real gap: the disposal methods were installed on the prototype at runtime but never declared on the Repeater type, so `await using r = new Repeater(...)` was a type error for consumers. Added an interface merge declaring [Symbol.asyncDispose]/[Symbol.dispose] so it type checks, while keeping the feature-detection guards for old runtimes. 178/178 on node and bun. Refs #81 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Property-based tests (fast-check) for race/merge/zip/latest covering value-completeness, column/width invariants, sub-multiset output, and early-break disposal across randomized async interleavings. Add a node-oriented GitHub Actions workflow (typecheck/build/test on Node 20/22/24, plus a bun-target job) and a `typecheck` npm script. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
timers and limiters pulled Repeater/buffers from ./index.js, which is the Repeater subclass carrying the static combinators — so every timers bundle dragged in race/merge/zip/latest. Point them at ./core.js instead; the timers bundle no longer includes the combinators. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three small tests take every source file to 100% line + function coverage: - latest() rejects when a contender throws on its first pull (the one combinator error branch nothing hit) - createSemaphore / createThrottle throw RangeError for limit < 1 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Build/structure:
repeaterre-exports the full class with statics attached (no breaking change).API:
Fixes:
Tests: 163/163 green on both node and bun.
Refs #81