@blockcast/mmt-container 0.5.0-main.ed11aec88d91 → 0.5.0
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/dist/browser-runtime.js +150 -21
- package/dist/browser-runtime.js.map +2 -2
- package/dist/fec-manager.d.ts.map +1 -1
- package/dist/fec-manager.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +2 -2
- package/dist/mmtp-container-parser.d.ts +10 -0
- package/dist/mmtp-container-parser.d.ts.map +1 -1
- package/dist/mmtp-container-parser.js +31 -1
- package/dist/mmtp-container-parser.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +31 -1
- package/dist/mmtp-container-parser.no-modules.js.map +2 -2
- package/dist/mmtp-decode-pipeline.js +31 -1
- package/dist/mmtp-decode-pipeline.js.map +2 -2
- package/dist/mmtp-router.d.ts +11 -0
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +54 -1
- package/dist/mmtp-router.js.map +2 -2
- package/dist/multicast-manager.d.ts +25 -1
- package/dist/multicast-manager.d.ts.map +1 -1
- package/dist/multicast-manager.js +92 -2
- package/dist/multicast-manager.js.map +2 -2
- package/dist/no-modules.js +31 -1
- package/dist/no-modules.js.map +2 -2
- package/dist/repair-fetch.d.ts +41 -10
- package/dist/repair-fetch.d.ts.map +1 -1
- package/dist/repair-fetch.js +58 -19
- package/dist/repair-fetch.js.map +2 -2
- package/dist/wasm-mmtp-container-parser.js +31 -1
- package/dist/wasm-mmtp-container-parser.js.map +2 -2
- package/package.json +7 -6
- package/src/fec-manager.ts +3 -0
- package/src/index.ts +1 -0
- package/src/mmtp-container-parser.ts +48 -0
- package/src/mmtp-router.ts +27 -0
- package/src/multicast-manager.ts +68 -0
- package/src/repair-fetch.ts +131 -31
- package/test-vectors/catalog/negative/multicast-auth-padded-key.json +0 -1
- package/test-vectors/catalog/negative/multicast-auth-reused-track-format.json +0 -1
- package/test-vectors/catalog/negative/multicast-auth-root-dotted-key.json +0 -1
- package/test-vectors/catalog/negative/multicast-auth-trailing-pad-bits.json +0 -1
- package/test-vectors/repair-policy-v1.json +113 -0
package/dist/browser-runtime.js
CHANGED
|
@@ -17655,6 +17655,9 @@ function authoredGap(before, after) {
|
|
|
17655
17655
|
if (!a || !b || a.mediaTimescale !== b.mediaTimescale) return false;
|
|
17656
17656
|
return b.decodeTime > a.decodeTime + BigInt(a.durationTicks);
|
|
17657
17657
|
}
|
|
17658
|
+
function ssIdAfter(a, b) {
|
|
17659
|
+
return (a - b | 0) > 0;
|
|
17660
|
+
}
|
|
17658
17661
|
var FecReleaseSequencer = class {
|
|
17659
17662
|
#streams = /* @__PURE__ */ new Map();
|
|
17660
17663
|
#gate;
|
|
@@ -17716,11 +17719,17 @@ var FecReleaseSequencer = class {
|
|
|
17716
17719
|
stream.last = null;
|
|
17717
17720
|
stream.lastSbn = void 0;
|
|
17718
17721
|
stream.discontinuity = false;
|
|
17722
|
+
stream.rapSsId = void 0;
|
|
17719
17723
|
}
|
|
17720
17724
|
if (stream.last !== null && compareFrameOrder(frame, stream.last) <= 0) {
|
|
17721
17725
|
this.#recordStat("droppedStale");
|
|
17722
17726
|
return;
|
|
17723
17727
|
}
|
|
17728
|
+
const ssId = meta.fecSbn;
|
|
17729
|
+
if (meta.trackType === "video" && ssId !== void 0 && this.#gate.isRap?.(data, meta) === true) {
|
|
17730
|
+
if (stream.rapSsId === void 0 || ssIdAfter(ssId, stream.rapSsId)) stream.rapSsId = ssId;
|
|
17731
|
+
this.#gate.onRap?.(stream.packetId, stream.catalogTrackName, ssId);
|
|
17732
|
+
}
|
|
17724
17733
|
if (stream.last === null) {
|
|
17725
17734
|
if (meta.trackType === "video" && !meta.keyframe) {
|
|
17726
17735
|
this.#recordStat("droppedBeforeStartupKeyframe");
|
|
@@ -17756,6 +17765,22 @@ var FecReleaseSequencer = class {
|
|
|
17756
17765
|
}
|
|
17757
17766
|
return earliest;
|
|
17758
17767
|
}
|
|
17768
|
+
/**
|
|
17769
|
+
* Whether a complete RAP above SS_ID `ssId` entered the gate of a stream of
|
|
17770
|
+
* `packetId` (draft-ramadan-moq-fec 11.4.2: repair of a block below it is
|
|
17771
|
+
* moot). Its SS_ID is the one its frame completed in; a frame's packets
|
|
17772
|
+
* hold consecutive SS_IDs in authored order, so a complete RAP with a
|
|
17773
|
+
* packet above `ssId` has every packet of it at or above the first SS_ID
|
|
17774
|
+
* any loss at or below `ssId` could have taken.
|
|
17775
|
+
*/
|
|
17776
|
+
rapAbove(packetId, catalogTrackName, ssId) {
|
|
17777
|
+
for (const stream of this.#streams.values()) {
|
|
17778
|
+
if (stream.packetId !== packetId) continue;
|
|
17779
|
+
if (catalogTrackName !== void 0 && stream.catalogTrackName !== catalogTrackName) continue;
|
|
17780
|
+
if (stream.rapSsId !== void 0 && ssIdAfter(stream.rapSsId, ssId)) return true;
|
|
17781
|
+
}
|
|
17782
|
+
return false;
|
|
17783
|
+
}
|
|
17759
17784
|
/** Re-evaluate held gaps after FEC state changed. */
|
|
17760
17785
|
poke(streamKey) {
|
|
17761
17786
|
if (streamKey !== void 0) {
|
|
@@ -17846,7 +17871,8 @@ var FecReleaseSequencer = class {
|
|
|
17846
17871
|
buf: [],
|
|
17847
17872
|
last: null,
|
|
17848
17873
|
lastSbn: void 0,
|
|
17849
|
-
discontinuity: false
|
|
17874
|
+
discontinuity: false,
|
|
17875
|
+
rapSsId: void 0
|
|
17850
17876
|
};
|
|
17851
17877
|
this.#streams.set(streamKey, stream);
|
|
17852
17878
|
}
|
|
@@ -18209,6 +18235,10 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
18209
18235
|
fecReleaseEarliestHeldAtMs(packetId, catalogTrackName) {
|
|
18210
18236
|
return this.#fecSequencer?.earliestHeldArrivalMs(packetId, catalogTrackName);
|
|
18211
18237
|
}
|
|
18238
|
+
/** See FecReleaseSequencer.rapAbove; false when no stream is FEC-gated. */
|
|
18239
|
+
fecReleaseRapAbove(packetId, catalogTrackName, ssId) {
|
|
18240
|
+
return this.#fecSequencer?.rapAbove(packetId, catalogTrackName, ssId) ?? false;
|
|
18241
|
+
}
|
|
18212
18242
|
/** Re-evaluate held gaps after FEC block state changed. */
|
|
18213
18243
|
pokeFecRelease(packetId, catalogTrackName) {
|
|
18214
18244
|
if (!this.#fecSequencer) return;
|
|
@@ -19605,6 +19635,7 @@ var MmtpRouter = class {
|
|
|
19605
19635
|
#onBlockFailed = null;
|
|
19606
19636
|
/** Typed observer of every gap decision the release gate makes. */
|
|
19607
19637
|
#onFrameGap;
|
|
19638
|
+
#fecRapObservers = /* @__PURE__ */ new Set();
|
|
19608
19639
|
// Pokes requested while a packet is being processed are deferred to its
|
|
19609
19640
|
// end: a synchronous recovery completes its block BEFORE routing the
|
|
19610
19641
|
// recovered frames, and releasing a held gap in between would strand them.
|
|
@@ -21263,6 +21294,24 @@ var MmtpRouter = class {
|
|
|
21263
21294
|
fecReleaseEarliestHeldAtMs(packetId, catalogTrackName) {
|
|
21264
21295
|
return this.#parser.fecReleaseEarliestHeldAtMs(packetId, catalogTrackName);
|
|
21265
21296
|
}
|
|
21297
|
+
/**
|
|
21298
|
+
* Whether a complete RAP above SS_ID `ssId` entered this stream's FEC
|
|
21299
|
+
* release gate (see FecReleaseSequencer.rapAbove).
|
|
21300
|
+
*/
|
|
21301
|
+
fecReleaseRapAbove(packetId, catalogTrackName, ssId) {
|
|
21302
|
+
return this.#parser.fecReleaseRapAbove(packetId, catalogTrackName, ssId);
|
|
21303
|
+
}
|
|
21304
|
+
/**
|
|
21305
|
+
* Observe each complete RAP entering an FEC release gate, with the SS_ID
|
|
21306
|
+
* its frame completed in. Called synchronously from the frame push: an
|
|
21307
|
+
* observer that drives FEC state must defer that work.
|
|
21308
|
+
*/
|
|
21309
|
+
addFecRapObserver(observer) {
|
|
21310
|
+
this.#fecRapObservers.add(observer);
|
|
21311
|
+
return () => {
|
|
21312
|
+
this.#fecRapObservers.delete(observer);
|
|
21313
|
+
};
|
|
21314
|
+
}
|
|
21266
21315
|
#requestFecPoke(packetId, catalogTrackName) {
|
|
21267
21316
|
if (this.#disposed) return;
|
|
21268
21317
|
if (this.#fecPokeDepth > 0) {
|
|
@@ -21308,6 +21357,10 @@ var MmtpRouter = class {
|
|
|
21308
21357
|
this.#onFrameGap?.(decision);
|
|
21309
21358
|
return decision;
|
|
21310
21359
|
},
|
|
21360
|
+
isRap: (data, meta) => this.#isRapForGap(data, meta),
|
|
21361
|
+
onRap: (packetId, catalogTrackName, ssId) => {
|
|
21362
|
+
for (const observer of this.#fecRapObservers) observer(packetId, catalogTrackName, ssId);
|
|
21363
|
+
},
|
|
21311
21364
|
onReleased: (data, meta) => {
|
|
21312
21365
|
if (meta.trackType !== "video" || meta.mpuSequenceNumber === void 0) return;
|
|
21313
21366
|
const timing = meta.authoredTiming;
|
|
@@ -26756,6 +26809,8 @@ function newBlockPolicyStats(packetId, catalogTrackName, epoch) {
|
|
|
26756
26809
|
repairsSkippedPresentationDelayUnavailable: 0,
|
|
26757
26810
|
repairsSkippedRangeNoAnchor: 0,
|
|
26758
26811
|
repairsSkippedGroupCannotComplete: 0,
|
|
26812
|
+
repairsSkippedMootRap: 0,
|
|
26813
|
+
repairStops: { preempted: 0, reprioritized: 0, expired: 0, resolved: 0, reset: 0, disposed: 0, moot: 0 },
|
|
26759
26814
|
lastRepairSkip: null,
|
|
26760
26815
|
keyframeRepairFetchesSent: 0,
|
|
26761
26816
|
rangeRepairFetchesSent: 0,
|
|
@@ -26842,7 +26897,17 @@ var REPAIR_SKIP_REASONS = /* @__PURE__ */ new Set([
|
|
|
26842
26897
|
"rtt-exceeds-budget",
|
|
26843
26898
|
"presentation-delay-unavailable",
|
|
26844
26899
|
"range-no-anchor",
|
|
26845
|
-
"group-cannot-complete"
|
|
26900
|
+
"group-cannot-complete",
|
|
26901
|
+
"moot-rap"
|
|
26902
|
+
]);
|
|
26903
|
+
var REPAIR_STOP_REASONS = /* @__PURE__ */ new Set([
|
|
26904
|
+
"preempted",
|
|
26905
|
+
"reprioritized",
|
|
26906
|
+
"expired",
|
|
26907
|
+
"resolved",
|
|
26908
|
+
"reset",
|
|
26909
|
+
"disposed",
|
|
26910
|
+
"moot"
|
|
26846
26911
|
]);
|
|
26847
26912
|
var REPAIR_DEADLINE_BOUNDS = /* @__PURE__ */ new Set(["wait", "presentation", "keyframe", "retention"]);
|
|
26848
26913
|
var GAP_REASONS = {
|
|
@@ -26901,6 +26966,8 @@ function isRepairLifecycleEvent(value) {
|
|
|
26901
26966
|
]) && isRepairBlockIdentity(block) && (value["priority"] === 0 || value["priority"] === 1 || value["priority"] === 2) && isFiniteNumber(value["rttMs"]) && value["rttMs"] > 0 && isFiniteNumber(value["budgetMs"]) && value["budgetMs"] > value["rttMs"] && isNullableNonNegative(value["delayMs"]) && isNullableNonNegative(value["blockAgeMs"]) && value["delayMs"] === null === (value["blockAgeMs"] === null) && REPAIR_DEADLINE_BOUNDS.has(value["bound"]);
|
|
26902
26967
|
case "repair-skipped":
|
|
26903
26968
|
return hasExactKeys(value, ["version", "type", "block", "reason", "rttMs", "budgetMs"]) && isRepairBlockIdentity(block) && REPAIR_SKIP_REASONS.has(value["reason"]) && isNullableNonNegative(value["rttMs"]) && isFiniteNumber(value["budgetMs"]);
|
|
26969
|
+
case "repair-stopped":
|
|
26970
|
+
return hasExactKeys(value, ["version", "type", "block", "reason"]) && isRepairBlockIdentity(block) && REPAIR_STOP_REASONS.has(value["reason"]);
|
|
26904
26971
|
case "repair-priority": {
|
|
26905
26972
|
const blockClass = value["blockClass"];
|
|
26906
26973
|
const action = value["action"];
|
|
@@ -28491,6 +28558,7 @@ var MulticastManager = class {
|
|
|
28491
28558
|
else if (reason === "rtt-exceeds-budget") stats.repairsSkippedRttExceedsBudget++;
|
|
28492
28559
|
else if (reason === "range-no-anchor") stats.repairsSkippedRangeNoAnchor++;
|
|
28493
28560
|
else if (reason === "group-cannot-complete") stats.repairsSkippedGroupCannotComplete++;
|
|
28561
|
+
else if (reason === "moot-rap") stats.repairsSkippedMootRap++;
|
|
28494
28562
|
else stats.repairsSkippedPresentationDelayUnavailable++;
|
|
28495
28563
|
stats.lastRepairSkip = {
|
|
28496
28564
|
reason,
|
|
@@ -28551,6 +28619,27 @@ var MulticastManager = class {
|
|
|
28551
28619
|
block: repairBlockIdentity(packetId, sbn, catalogTrackName)
|
|
28552
28620
|
});
|
|
28553
28621
|
}
|
|
28622
|
+
/** Record a running repair FETCH the scheduler stopped, and why. */
|
|
28623
|
+
noteRepairStopped(reason, sbn, packetId, catalogTrackName) {
|
|
28624
|
+
this.#statsFor(packetId, catalogTrackName).repairStops[reason]++;
|
|
28625
|
+
this.#emitRepairLifecycle({
|
|
28626
|
+
version: 2,
|
|
28627
|
+
type: "repair-stopped",
|
|
28628
|
+
block: repairBlockIdentity(packetId, sbn, catalogTrackName),
|
|
28629
|
+
reason
|
|
28630
|
+
});
|
|
28631
|
+
}
|
|
28632
|
+
/**
|
|
28633
|
+
* Whether a complete RAP above SS_ID `ssId` reached the stream's in-order
|
|
28634
|
+
* release gate (draft-ramadan-moq-fec 11.4.2: repair below it is moot).
|
|
28635
|
+
*/
|
|
28636
|
+
rapCompleteAbove(packetId, catalogTrackName, ssId) {
|
|
28637
|
+
return this.#router.fecReleaseRapAbove(packetId, catalogTrackName, ssId);
|
|
28638
|
+
}
|
|
28639
|
+
/** Observe each complete RAP reaching a release gate (synchronous: defer FEC work). */
|
|
28640
|
+
addRapCompleteObserver(observer) {
|
|
28641
|
+
return this.#router.addFecRapObserver(observer);
|
|
28642
|
+
}
|
|
28554
28643
|
/** Catalog/reset epoch of a packet's streams; gap decisions carry it. */
|
|
28555
28644
|
epochFor(packetId) {
|
|
28556
28645
|
return this.#fec.epochFor(packetId);
|
|
@@ -28566,6 +28655,7 @@ var MulticastManager = class {
|
|
|
28566
28655
|
if (stats.epoch !== this.#fec.epochFor(stats.packetId)) continue;
|
|
28567
28656
|
out[key] = {
|
|
28568
28657
|
...stats,
|
|
28658
|
+
repairStops: { ...stats.repairStops },
|
|
28569
28659
|
lastRepairSkip: stats.lastRepairSkip === null ? null : { ...stats.lastRepairSkip }
|
|
28570
28660
|
};
|
|
28571
28661
|
}
|
|
@@ -30929,6 +31019,34 @@ function wireRepairFetch(mc, opts) {
|
|
|
30929
31019
|
run.stopped = reason;
|
|
30930
31020
|
run.controller.abort();
|
|
30931
31021
|
if (reason === "preempted") releaseHold(entry);
|
|
31022
|
+
mc.noteRepairStopped?.(reason, entry.sbn, entry.packetId, entry.catalogTrackName);
|
|
31023
|
+
};
|
|
31024
|
+
const lastSsId = (entry) => {
|
|
31025
|
+
if (entry.range) return entry.sbn + entry.range.holeLength - 1;
|
|
31026
|
+
const length = symbolCounts(entry.sbn, entry.packetId, entry.catalogTrackName)?.authoredLength;
|
|
31027
|
+
return length === void 0 ? void 0 : entry.sbn + length - 1;
|
|
31028
|
+
};
|
|
31029
|
+
const moot = (entry) => {
|
|
31030
|
+
if (entry.priority !== 0) return false;
|
|
31031
|
+
const last = lastSsId(entry);
|
|
31032
|
+
if (last === void 0) return false;
|
|
31033
|
+
try {
|
|
31034
|
+
return mc.rapCompleteAbove?.(entry.packetId, entry.catalogTrackName, last) === true;
|
|
31035
|
+
} catch {
|
|
31036
|
+
return false;
|
|
31037
|
+
}
|
|
31038
|
+
};
|
|
31039
|
+
const skip = (entry, reason, rttMs, budgetMs) => {
|
|
31040
|
+
retire(entry);
|
|
31041
|
+
releaseHold(entry);
|
|
31042
|
+
clearEntry(entry);
|
|
31043
|
+
mc.noteRepairSkipped(
|
|
31044
|
+
reason,
|
|
31045
|
+
{ rttMs, budgetMs, priority: entry.priority },
|
|
31046
|
+
entry.sbn,
|
|
31047
|
+
entry.packetId,
|
|
31048
|
+
entry.catalogTrackName
|
|
31049
|
+
);
|
|
30932
31050
|
};
|
|
30933
31051
|
const readKeyframeBudget = (packetId, catalogTrackName) => {
|
|
30934
31052
|
const reader = opts.keyframeRepairBudgetMs;
|
|
@@ -30953,31 +31071,22 @@ function wireRepairFetch(mc, opts) {
|
|
|
30953
31071
|
const rttMs = readRtt();
|
|
30954
31072
|
const reason = !entry.range && !groupCanComplete(entry.sbn, entry.packetId, entry.catalogTrackName) ? "group-cannot-complete" : rttMs === null ? "rtt-unmeasured" : rttMs < budgetMs ? null : "rtt-exceeds-budget";
|
|
30955
31073
|
if (reason === null) return rttMs;
|
|
30956
|
-
|
|
30957
|
-
releaseHold(entry);
|
|
30958
|
-
clearEntry(entry);
|
|
30959
|
-
mc.noteRepairSkipped(
|
|
30960
|
-
reason,
|
|
30961
|
-
{ rttMs, budgetMs, priority: entry.priority },
|
|
30962
|
-
entry.sbn,
|
|
30963
|
-
entry.packetId,
|
|
30964
|
-
entry.catalogTrackName
|
|
30965
|
-
);
|
|
31074
|
+
skip(entry, reason, rttMs, budgetMs);
|
|
30966
31075
|
return null;
|
|
30967
31076
|
};
|
|
30968
31077
|
const retire = (entry) => {
|
|
30969
31078
|
if (entries.get(entry.key) === entry) entries.delete(entry.key);
|
|
30970
31079
|
if (entry.expiry !== void 0) clearTimeout(entry.expiry);
|
|
30971
31080
|
};
|
|
30972
|
-
const
|
|
31081
|
+
const outstandingBelow = (priority) => {
|
|
30973
31082
|
for (const entry of entries.values()) {
|
|
30974
|
-
if (entry.priority <
|
|
31083
|
+
if (entry.priority < priority) return true;
|
|
30975
31084
|
}
|
|
30976
31085
|
return false;
|
|
30977
31086
|
};
|
|
30978
|
-
const
|
|
31087
|
+
const preemptBestEffort = () => {
|
|
30979
31088
|
for (const entry of entries.values()) {
|
|
30980
|
-
if (entry.priority
|
|
31089
|
+
if (entry.priority === 0 || !entry.running) continue;
|
|
30981
31090
|
stop(entry, "preempted");
|
|
30982
31091
|
note("repair-preempted", entry);
|
|
30983
31092
|
}
|
|
@@ -30997,8 +31106,13 @@ function wireRepairFetch(mc, opts) {
|
|
|
30997
31106
|
};
|
|
30998
31107
|
const start = (entry, counted = true) => {
|
|
30999
31108
|
const now = performance.now();
|
|
31109
|
+
if (moot(entry)) {
|
|
31110
|
+
skip(entry, "moot-rap", readRtt(), entry.deadlineAt - now);
|
|
31111
|
+
return;
|
|
31112
|
+
}
|
|
31000
31113
|
const rttMs = admit(entry, now);
|
|
31001
31114
|
if (rttMs === null) return;
|
|
31115
|
+
if (entry.priority === 0) preemptBestEffort();
|
|
31002
31116
|
if (counted) entry.attempts++;
|
|
31003
31117
|
mc.noteRepairFetchSent?.(entry.priority, entry.sbn, entry.packetId, entry.catalogTrackName, {
|
|
31004
31118
|
rttMs,
|
|
@@ -31042,9 +31156,13 @@ function wireRepairFetch(mc, opts) {
|
|
|
31042
31156
|
queued.push(entry);
|
|
31043
31157
|
}
|
|
31044
31158
|
for (const entry of queued) {
|
|
31045
|
-
if (entry.priority
|
|
31159
|
+
if (entry.priority === 0) start(entry);
|
|
31160
|
+
}
|
|
31161
|
+
if (outstandingBelow(1)) return;
|
|
31162
|
+
for (const entry of queued) {
|
|
31163
|
+
if (entry.priority === 1) start(entry);
|
|
31046
31164
|
}
|
|
31047
|
-
if (
|
|
31165
|
+
if (outstandingBelow(2)) return;
|
|
31048
31166
|
queued.filter((entry) => entry.priority === 2).sort((a, b) => a.deadlineAt - b.deadlineAt || a.order - b.order).forEach((entry) => start(entry));
|
|
31049
31167
|
};
|
|
31050
31168
|
const symbolCounts = (sbn, packetId, catalogTrackName) => {
|
|
@@ -31172,7 +31290,6 @@ function wireRepairFetch(mc, opts) {
|
|
|
31172
31290
|
stop(entry2, "reprioritized");
|
|
31173
31291
|
start(entry2, false);
|
|
31174
31292
|
}
|
|
31175
|
-
preemptDeltas();
|
|
31176
31293
|
dispatch();
|
|
31177
31294
|
return;
|
|
31178
31295
|
}
|
|
@@ -31304,7 +31421,6 @@ function wireRepairFetch(mc, opts) {
|
|
|
31304
31421
|
};
|
|
31305
31422
|
entries.set(key, entry);
|
|
31306
31423
|
noteBudget(entry, deadline.extensionMs);
|
|
31307
|
-
if (entry.priority < 2) preemptDeltas();
|
|
31308
31424
|
dispatch();
|
|
31309
31425
|
});
|
|
31310
31426
|
const rangeFor = (loss, repairTrack) => {
|
|
@@ -31380,15 +31496,28 @@ function wireRepairFetch(mc, opts) {
|
|
|
31380
31496
|
}
|
|
31381
31497
|
entries.set(entry.key, entry);
|
|
31382
31498
|
entry.expiry = setTimeout(dispatch, Math.max(0, entry.deadlineAt - performance.now()) + 1);
|
|
31383
|
-
preemptDeltas();
|
|
31384
31499
|
dispatch();
|
|
31385
31500
|
});
|
|
31386
31501
|
}
|
|
31502
|
+
const removeRapObserver = mc.addRapCompleteObserver?.((packetId) => {
|
|
31503
|
+
queueMicrotask(() => {
|
|
31504
|
+
if (disposed) return;
|
|
31505
|
+
for (const entry of [...entries.values()]) {
|
|
31506
|
+
if (entry.packetId !== packetId || !entry.running || !moot(entry)) continue;
|
|
31507
|
+
stop(entry, "moot");
|
|
31508
|
+
retire(entry);
|
|
31509
|
+
releaseHold(entry);
|
|
31510
|
+
clearEntry(entry);
|
|
31511
|
+
}
|
|
31512
|
+
dispatch();
|
|
31513
|
+
});
|
|
31514
|
+
});
|
|
31387
31515
|
return () => {
|
|
31388
31516
|
disposed = true;
|
|
31389
31517
|
mc.setUnicastRepair?.(false);
|
|
31390
31518
|
removeResetObserver();
|
|
31391
31519
|
removeLifecycleObserver();
|
|
31520
|
+
removeRapObserver?.();
|
|
31392
31521
|
for (const entry of [...entries.values()]) {
|
|
31393
31522
|
clearEntry(entry);
|
|
31394
31523
|
if (entry.running) releaseHold(entry);
|