cross-tab-worker-databus 0.21.25 → 0.21.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/dist/centrifuge.js +1 -1
- package/dist/{chunk-ORGPJ2CX.js → chunk-WKCHJMIV.js} +15 -7
- package/dist/chunk-WKCHJMIV.js.map +7 -0
- package/dist/cjs/centrifuge.cjs +14 -6
- package/dist/cjs/centrifuge.cjs.map +2 -2
- package/dist/cjs/index.cjs +14 -6
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/replay-manager.d.ts +13 -5
- package/dist/core/replay-manager.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/docs/roadmap.md +15 -1
- package/docs/zh/roadmap.md +15 -1
- package/package.json +1 -1
- package/dist/chunk-ORGPJ2CX.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,50 @@
|
|
|
1
|
+
## [0.21.27] - 2026-09-25
|
|
2
|
+
|
|
3
|
+
Three shipped sentences about lifecycle windows were re-checked against the code and the runner: one held and is now backed by a measurement, one was false about *why* the code is safe, and one quoted a number that had already rotted.
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **`reconcile()`'s REGISTRY leg was unreachable for a different reason than its comment gave.** The note said the span between `pause()` clearing `started` and `pause()` removing the message listener holds "a boolean assignment and two `heartbeatHandle` writes, with no call that can hand the stack to consumer code". The middle of those three statements is `this.environment.clearInterval(this.heartbeatHandle)` — a call into adapter code, which this same file's `activate()` comment treats as consumer-supplied and untrusted. So the absence of calls was never what closed the window; the `if (!this.started) return` guard at the top of `reconcile()` is. The comment now says that, which also strengthens the case for keeping a guard that the old phrasing made look redundant.
|
|
8
|
+
- **The activation window's provenance is measured rather than argued.** `pause()`'s null-`heartbeatHandle` branch is a covered arm whose *origin* was a claim: that only the two "abandons activation…" tests reach it. Instrumenting the branch and running the whole suite printed exactly two lines and no third — one from the adapter's `createChannel`, one from the storage-less self-SUBSCRIBE's `handlers.onControl` — and the two test names are now quoted at the site, so a third origin is something a future reader can notice rather than something they have to re-derive.
|
|
9
|
+
- **A quoted call count became a lookup.** `reopenTransport()`'s note had carried "0 of 5041 calls" since `b0354e4`; the same function count on this tree reads 5046. The number was only ever there to say *hot method, cold arms*, and that reading survives any drift — which is precisely why a stale figure is dangerous: it looks like evidence. The sentence now names where to take the count from instead of preserving one.
|
|
10
|
+
|
|
11
|
+
### Tests
|
|
12
|
+
|
|
13
|
+
- **None added or changed, and the ledger is quoted rather than assumed.** `pnpm check` 0 with **936** tests and 5/5 perf gates, `pnpm lint` 0, `pnpm test:coverage` 0 with **46** zero-count branch arms of **1963** and aggregate 99.02 / 97.65 / 99.27 / 99.69 — unchanged, as it must be for a diff that contains no code. `git diff -U0 src/` with every comment line filtered out returns nothing.
|
|
14
|
+
|
|
15
|
+
### Documentation
|
|
16
|
+
|
|
17
|
+
- **`AGENTS.md` gained the decay rule for quoted numbers.** A count in a comment contradicts nothing when it drifts, so either name the lookup that re-derives it or drop the figure; the pair that carries the argument (this leg runs thousands of times, these arms read zero) is the part worth keeping. This is the same failure mode as quoting a sweep total as a per-seed cost — the reader cannot tell a stale measurement from a current one, and a stale one calibrates them.
|
|
18
|
+
- **And the shipped-surface rule got its position half, measured rather than inherited.** The existing note says a src comment ships through the declarations *and* the JS, which is true in aggregate and misleading per sentence: this release's three corrections all sit in **statement slots inside method bodies**, and grepping one built tree shows they reach the published package only through the `.js.map` files' embedded sources (`files: ["dist"]` does publish those). A **class-member JSDoc** — `0.21.26`'s `stop()` note is the control — does appear in `dist/core/replay-manager.d.ts`, in the shared ESM chunk and in both CJS bundles. The control that keeps this from reading as a regression is a comment that predates both releases: `cluster.ts`'s "Order matters: release local subscriptions…" is equally absent from the bundles. So "does this comment ship?" is asked per artifact — what a consumer's editor shows, what a sourcemap step recovers, what a bundle read surfaces — not once for the tree.
|
|
19
|
+
- **Nothing consumer-facing moved**, so no `docs/` page was rewritten: these are maintainer-facing comments about internal methods, corrected in place.
|
|
20
|
+
|
|
21
|
+
### Compatibility
|
|
22
|
+
|
|
23
|
+
Comment-only. No export, frame, option, default or storage key moved; `verify:compat`, `verify:types` and `verify:pack` pass against `v0.21.26`.
|
|
24
|
+
|
|
25
|
+
## [0.21.26] - 2026-09-25
|
|
26
|
+
|
|
27
|
+
One false sentence about who cancels a persistence retry, corrected everywhere it had been written — found by an audit pass whose own scheduling step was wrong, which is the part worth reading.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **`retryGeneration` has exactly one writer, and it is not `stop()`.** Four comments in `replay-manager.ts` described the cancellation generation as bumped "on suspend/stop". This class defines *both* of those methods, and only `suspend()` increments the field — `stop()` clears the retention-sweep timer and cancels nothing in flight. A maintainer auditing "what supersedes an in-flight retry" who read `stop()` first would have found no bump and had to conclude either that the comment was right and the code was broken, or that the pair meant something else. `ReplayManager` appears nowhere in the barrel, so no consumer can reach the wrong model; the class's own callers can, and `stop()`'s only caller in `src/` is `suspend()`.
|
|
32
|
+
- **The half that was true is now stated at the level it is true at.** `CrossTabDataBus` has no `suspend()` method at all: it reaches the bump from two sites, the cluster's `onSuspend` handler and `beginStop()`. So a hidden *tab* and a stopped *bus* both do cancel their queued durable appends — through `ReplayManager.suspend()` — and that is exactly why the shorthand stayed plausible: the test that covers the behavior is named "cancels a pending persistence retry when the bus stops", and it passes whatever this class's `stop()` does. Nor was the sentence a stale remnant of code that once behaved that way — checked against `0cb8572`, the commit that split this file out, `stop()` has never touched the field; the pair has been false since the day it was written.
|
|
33
|
+
- **One corrected claim about the corrected claims, caught before it shipped.** The pass began with a scan that decided which zero-count branch arms still lacked a verdict at their site by reading the line above each one. It reported 21 unvisited legs on a ledger of 46 in which **every** arm already carries one, because those verdicts run five to fifteen lines and state the measurement that closes the arm. Reading the reported sites with a window is what turned the pass into a one-defect pass instead of a re-do of closed work.
|
|
34
|
+
|
|
35
|
+
### Tests
|
|
36
|
+
|
|
37
|
+
- **None added, and that is the honest classification.** Nothing here moves behavior: the diff is comment lines only (`git diff -U0 src/` with every non-comment line filtered out returns nothing), the suite is unchanged at 936 tests, the perf gates at 5/5, and the branch-arm ledger at **46 zero-count arms of 1963** with aggregate 99.02 / 97.65 / 99.27 / 99.69 — byte-identical to `0.21.25`'s. A test asserting that `ReplayManager.stop()` cancels nothing would characterize an internal method with one caller rather than pin a contract, and this repository's rule is to name that difference instead of banking the green.
|
|
38
|
+
|
|
39
|
+
### Documentation
|
|
40
|
+
|
|
41
|
+
- **`AGENTS.md` gained the scoping rule.** A scan is a probe, so it needs the control the probe rules already demand: run it on a site you know is answered and check it reports "present" before its output becomes a task list — a scan that cannot distinguish *absent* from *not looked at* schedules rework over closed ground, and that rework looks like progress. The second half of the rule is the pair-shorthand itself: when a comment names two methods as doing the same thing, check each name in the class that owns the thing, because the pair can be accurate about callers and false about callees while every test passes.
|
|
42
|
+
- **The shipped surface for a comment is wider than the declarations.** Verified rather than assumed: the corrected sentences appear in `dist/core/replay-manager.d.ts`, in the ESM chunk `dist/chunk-WKOCDMCH.js`, and in both CJS bundles (`dist/cjs/index.cjs`, `dist/cjs/centrifuge.cjs`) — esbuild preserves comments in the JS, and all of those paths are in `package.json` `files`.
|
|
43
|
+
|
|
44
|
+
### Compatibility
|
|
45
|
+
|
|
46
|
+
Comment-only. No export, frame, option, default or storage key moved; `verify:compat`, `verify:types` and `verify:pack` pass against `v0.21.25`.
|
|
47
|
+
|
|
1
48
|
## [0.21.25] - 2026-09-25
|
|
2
49
|
|
|
3
50
|
A publication's fan-out set is now fixed when its delivery begins, which closes a shape that did not terminate: a handler that registers a fresh closure for its own topic made the message that triggered the registration keep delivering to the handlers it created.
|
package/dist/centrifuge.js
CHANGED
|
@@ -1996,7 +1996,9 @@ var ReplayManager = class {
|
|
|
1996
1996
|
trace;
|
|
1997
1997
|
onPersistenceError;
|
|
1998
1998
|
onDispatchError;
|
|
1999
|
-
/** Bumped
|
|
1999
|
+
/** Bumped by exactly one statement, in `suspend()` below — which is where the
|
|
2000
|
+
* `generation !== this.retryGeneration` tests throughout this file look for a
|
|
2001
|
+
* cancellation. This class's own `stop()` does not touch the field. */
|
|
2000
2002
|
retryGeneration = 0;
|
|
2001
2003
|
pendingReplayPersistence = [];
|
|
2002
2004
|
persistenceFlushScheduled = false;
|
|
@@ -2155,13 +2157,19 @@ var ReplayManager = class {
|
|
|
2155
2157
|
this.scheduleRetentionCleanup(this.now() - this.retentionMs);
|
|
2156
2158
|
}, this.retentionSweepMs);
|
|
2157
2159
|
}
|
|
2158
|
-
/** Stop the periodic retention sweep.
|
|
2160
|
+
/** Stop the periodic retention sweep. Its only caller in `src/` is `suspend()`,
|
|
2161
|
+
* which chains it at its end — the class is internal (`ReplayManager` appears
|
|
2162
|
+
* nowhere in the barrel), so no consumer reaches this method directly. It
|
|
2163
|
+
* cancels no in-flight work: that is the `retryGeneration` bump in `suspend()`. */
|
|
2159
2164
|
stop() {
|
|
2160
2165
|
if (this.retentionTimer) clearInterval(this.retentionTimer);
|
|
2161
2166
|
this.retentionTimer = null;
|
|
2162
2167
|
}
|
|
2163
|
-
/**
|
|
2164
|
-
* or stopped bus does not keep hammering the store
|
|
2168
|
+
/** Cancel in-flight persistence retries by superseding their generation, so a
|
|
2169
|
+
* hidden tab or a stopped bus does not keep hammering the store. This is the
|
|
2170
|
+
* field's only writer; the bus reaches it from its two `replayManager.suspend()`
|
|
2171
|
+
* call sites (the cluster's `onSuspend` handler, and `beginStop()`), and this
|
|
2172
|
+
* class's own `stop()` only clears the sweep timer. */
|
|
2165
2173
|
suspend() {
|
|
2166
2174
|
this.retryGeneration += 1;
|
|
2167
2175
|
if (this.hydration) {
|
|
@@ -2335,7 +2343,7 @@ var ReplayManager = class {
|
|
|
2335
2343
|
});
|
|
2336
2344
|
}
|
|
2337
2345
|
/** Run a persistence operation with exponential backoff on transient failure.
|
|
2338
|
-
*
|
|
2346
|
+
* The `suspend()` bump of `retryGeneration` cancels the loop early; a
|
|
2339
2347
|
* structurally failing operation throws after `persistenceRetryMaxAttempts`,
|
|
2340
2348
|
* leaving the ring buffer intact so the bus keeps working. */
|
|
2341
2349
|
async withPersistenceRetry(persistenceOperation, operation) {
|
|
@@ -2491,7 +2499,7 @@ var SDK_VERSION = (
|
|
|
2491
2499
|
// declaration's type is `string | undefined` and the export's is `string`
|
|
2492
2500
|
// (dropping the conditional is TS2322, measured). Recorded here so the leg reads
|
|
2493
2501
|
// as a shape the harness cannot reach rather than as a case nobody exercised.
|
|
2494
|
-
true ? "0.21.
|
|
2502
|
+
true ? "0.21.27" : ""
|
|
2495
2503
|
);
|
|
2496
2504
|
|
|
2497
2505
|
// src/core/data-bus.ts
|
|
@@ -3731,4 +3739,4 @@ export {
|
|
|
3731
3739
|
parseDataBusPublication,
|
|
3732
3740
|
selectWorkerBackend
|
|
3733
3741
|
};
|
|
3734
|
-
//# sourceMappingURL=chunk-
|
|
3742
|
+
//# sourceMappingURL=chunk-WKCHJMIV.js.map
|