@peerbit/shared-log 13.2.33 → 13.2.34

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.
@@ -4,6 +4,7 @@ type LegacyReplicationInfoMessage = AllReplicatingSegmentsMessage | AddedReplica
4
4
  export type ReplicationInfoV2ReceivePhase = "awaiting-full" | "active" | "resync";
5
5
  type LocalCapabilityReady = {
6
6
  peerHash: string;
7
+ receiveEpoch: object | null;
7
8
  receiverTransportSession: bigint;
8
9
  /**
9
10
  * The local capability envelope and the later RequestV2 envelope use the
@@ -11,6 +12,41 @@ type LocalCapabilityReady = {
11
12
  * be strictly newer, so never construct it in this captured millisecond.
12
13
  */
13
14
  requestNotBeforeMs: number;
15
+ advertisement?: ReplicationInfoV2LocalCapabilityAdvertisement;
16
+ };
17
+ type LocalCapabilityReadyProperties = {
18
+ peerHash: string;
19
+ peerSession: object;
20
+ receiveEpoch: object | null;
21
+ receiverTransportSession: bigint;
22
+ requestNotBeforeMs: number;
23
+ };
24
+ export type ReplicationInfoV2LocalCapabilityAdvertisementHandle = {
25
+ firstAttempt: Promise<void>;
26
+ releaseLegacyBarrier(): void;
27
+ };
28
+ export type ReplicationInfoV2LocalCapabilityContext = {
29
+ peerHash: string;
30
+ target: PublicSignKey;
31
+ lifecycleSignal: AbortSignal;
32
+ legacyBarrierReleased: boolean;
33
+ };
34
+ export type ReplicationInfoV2LocalCapabilityAdvertisement = {
35
+ peerHash: string;
36
+ target: PublicSignKey;
37
+ peerSession: object;
38
+ receiveEpoch: object | null;
39
+ lifecycleSignal: AbortSignal;
40
+ onLifecycleAbort: () => void;
41
+ controller: AbortController;
42
+ context: ReplicationInfoV2LocalCapabilityContext;
43
+ attempts: number;
44
+ ready: boolean;
45
+ acknowledgedReady?: LocalCapabilityReady;
46
+ receiverTransportSession?: bigint;
47
+ timer?: ReturnType<typeof setTimeout>;
48
+ inFlight?: Promise<void>;
49
+ firstAttempt?: Promise<void>;
14
50
  };
15
51
  export type ReplicationInfoV2LocalCapabilityRefresh = {
16
52
  receiverTransportSession: bigint;
@@ -67,6 +103,8 @@ export type ReplicationInfoV2ReceiveDeps = {
67
103
  getSelfKey: () => PublicSignKey;
68
104
  getReceiverTransportSession: () => bigint;
69
105
  isClosed: () => boolean;
106
+ isPeerSessionCurrent: (peerHash: string, peerSession: object) => boolean;
107
+ isReceiveEpochCurrent: (peerHash: string, receiveEpoch: object | null) => boolean;
70
108
  isPeerStateCurrent: (peerHash: string, peerSession: object, receiveEpoch: object | null) => boolean;
71
109
  isSenderTransportSessionCurrent: (peerHash: string, senderTransportSession: bigint) => boolean;
72
110
  sendRequest: (request: RequestReplicationInfoV2Message, target: PublicSignKey, signal: AbortSignal) => Promise<void>;
@@ -78,6 +116,7 @@ export type ReplicationInfoV2ReceiveDeps = {
78
116
  signal: AbortSignal;
79
117
  }) => Promise<ReplicationInfoV2LocalCapabilityRefresh | undefined>;
80
118
  onRequestError?: (error: unknown) => void;
119
+ onLocalCapabilityError?: (error: unknown) => void;
81
120
  now?: () => number;
82
121
  requestRetryMs?: number;
83
122
  maxRequestRetryMs?: number;
@@ -94,6 +133,8 @@ export declare class ReplicationInfoV2ReceiveCoordinator {
94
133
  _receiveStates: Map<string, ReplicationInfoV2ReceiveState>;
95
134
  _cutoverPeerSessions: WeakSet<object>;
96
135
  _localCapabilityReadyBySession: WeakMap<object, LocalCapabilityReady>;
136
+ _localCapabilityContextBySession: WeakMap<object, ReplicationInfoV2LocalCapabilityContext>;
137
+ _localCapabilityAdvertisementsByPeer: Map<string, ReplicationInfoV2LocalCapabilityAdvertisement>;
97
138
  _reservedAdmissionsByPeer: Map<string, ReplicationInfoV2ReceiveAdmission>;
98
139
  private readonly now;
99
140
  private readonly requestRetryMs;
@@ -107,14 +148,42 @@ export declare class ReplicationInfoV2ReceiveCoordinator {
107
148
  /** Revoke an unauthenticated or downgraded capability generation. */
108
149
  revokePeerCapability(peerHash: string, reopenLegacy?: boolean): void;
109
150
  private clearState;
110
- /** Record success of this session's ACKed local APPLY advertisement. */
111
- markLocalCapabilityReady(properties: {
151
+ private clearLocalCapabilityAdvertisement;
152
+ private isLocalCapabilityAdvertisementOwnerCurrent;
153
+ private isLocalCapabilityAdvertisementGenerationCurrent;
154
+ private isLocalCapabilityAdvertisementReadyOpen;
155
+ private localCapabilityRetryDelay;
156
+ private armLocalCapabilityAdvertisement;
157
+ private runLocalCapabilityAdvertisement;
158
+ /**
159
+ * Start local authenticated-apply advertisement independently of the legacy
160
+ * join path. ACK and legacy publication are a two-phase barrier: the first
161
+ * attempt always settles independently, while readiness is promoted only
162
+ * after the host releases the legacy barrier. Failed attempts leave one
163
+ * exact-session worker retrying with capped exponential backoff.
164
+ */
165
+ advertiseLocalCapability(properties: {
166
+ target: PublicSignKey;
167
+ peerSession: object;
168
+ receiveEpoch: object | null;
169
+ signal: AbortSignal;
170
+ }): ReplicationInfoV2LocalCapabilityAdvertisementHandle;
171
+ private releaseLocalCapabilityLegacyBarrier;
172
+ private promoteLocalCapabilityAdvertisement;
173
+ /**
174
+ * Re-advertise one exact current recovery epoch from the stable membership
175
+ * context captured during opening. The opening handle owns barrier release;
176
+ * recovery never bypasses a legacy snapshot or role publication still in
177
+ * progress.
178
+ */
179
+ reAdvertiseLocalCapabilityForRecovery(properties: {
112
180
  peerHash: string;
113
181
  peerSession: object;
114
182
  receiveEpoch: object | null;
115
- receiverTransportSession: bigint;
116
- requestNotBeforeMs: number;
117
183
  }): boolean;
184
+ /** Record success of this session's ACKed local APPLY advertisement. */
185
+ markLocalCapabilityReady(properties: LocalCapabilityReadyProperties): boolean;
186
+ private recordLocalCapabilityReady;
118
187
  /**
119
188
  * Promote one signed capability generation after the opening barrier has
120
189
  * committed. Repeated same-session advertisements refresh freshness only;
@@ -1 +1 @@
1
- {"version":3,"file":"replication-info-v2-receive.d.ts","sourceRoot":"","sources":["../../src/replication-info-v2-receive.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replication-info-v2-receive.d.ts","sourceRoot":"","sources":["../../src/replication-info-v2-receive.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ const DEFAULT_MAX_REQUEST_RETRY_MS = 30_000;
10
10
  const DEFAULT_REQUEST_MAX_ATTEMPTS = 7;
11
11
  const DEFAULT_LEGACY_FALLBACK_DELAY_MS = 5_000;
12
12
  const MAX_U64 = (1n << 64n) - 1n;
13
+ const MAX_BACKOFF_EXPONENT = 20;
13
14
  const bytesEqual = (left, right) => {
14
15
  if (left.byteLength !== right.byteLength) {
15
16
  return false;
@@ -41,6 +42,8 @@ export class ReplicationInfoV2ReceiveCoordinator {
41
42
  _receiveStates;
42
43
  _cutoverPeerSessions;
43
44
  _localCapabilityReadyBySession;
45
+ _localCapabilityContextBySession;
46
+ _localCapabilityAdvertisementsByPeer;
44
47
  _reservedAdmissionsByPeer;
45
48
  now;
46
49
  requestRetryMs;
@@ -57,6 +60,8 @@ export class ReplicationInfoV2ReceiveCoordinator {
57
60
  this._receiveStates = new Map();
58
61
  this._cutoverPeerSessions = new WeakSet();
59
62
  this._localCapabilityReadyBySession = new WeakMap();
63
+ this._localCapabilityContextBySession = new WeakMap();
64
+ this._localCapabilityAdvertisementsByPeer = new Map();
60
65
  this._reservedAdmissionsByPeer = new Map();
61
66
  }
62
67
  resetForOpen() {
@@ -64,25 +69,41 @@ export class ReplicationInfoV2ReceiveCoordinator {
64
69
  this._receiveStates = new Map();
65
70
  this._cutoverPeerSessions = new WeakSet();
66
71
  this._localCapabilityReadyBySession = new WeakMap();
72
+ this._localCapabilityContextBySession = new WeakMap();
73
+ this._localCapabilityAdvertisementsByPeer = new Map();
67
74
  this._reservedAdmissionsByPeer = new Map();
68
75
  }
69
76
  clearForClose() {
77
+ for (const advertisement of [
78
+ ...(this._localCapabilityAdvertisementsByPeer?.values() ?? []),
79
+ ]) {
80
+ this.clearLocalCapabilityAdvertisement(advertisement);
81
+ }
82
+ this._localCapabilityAdvertisementsByPeer?.clear();
70
83
  for (const state of this._receiveStates?.values() ?? []) {
71
84
  this.clearState(state);
72
85
  }
73
86
  this._receiveStates?.clear();
74
87
  this._cutoverPeerSessions = new WeakSet();
75
88
  this._localCapabilityReadyBySession = new WeakMap();
89
+ this._localCapabilityContextBySession = new WeakMap();
76
90
  }
77
91
  clearPeer(peerHash, expectedSession) {
92
+ const advertisement = this._localCapabilityAdvertisementsByPeer.get(peerHash);
93
+ if (advertisement &&
94
+ (!expectedSession || advertisement.peerSession === expectedSession)) {
95
+ this.clearLocalCapabilityAdvertisement(advertisement);
96
+ }
78
97
  const state = this._receiveStates.get(peerHash);
79
98
  if (state && (!expectedSession || state.peerSession === expectedSession)) {
80
99
  this.clearState(state);
81
100
  this._localCapabilityReadyBySession.delete(state.peerSession);
101
+ this._localCapabilityContextBySession.delete(state.peerSession);
82
102
  this._cutoverPeerSessions.delete(state.peerSession);
83
103
  }
84
104
  if (expectedSession) {
85
105
  this._localCapabilityReadyBySession.delete(expectedSession);
106
+ this._localCapabilityContextBySession.delete(expectedSession);
86
107
  this._cutoverPeerSessions.delete(expectedSession);
87
108
  }
88
109
  }
@@ -112,8 +133,345 @@ export class ReplicationInfoV2ReceiveCoordinator {
112
133
  this._receiveStates.delete(state.peerHash);
113
134
  }
114
135
  }
136
+ clearLocalCapabilityAdvertisement(state, options) {
137
+ if (state.timer) {
138
+ clearTimeout(state.timer);
139
+ state.timer = undefined;
140
+ }
141
+ state.lifecycleSignal.removeEventListener("abort", state.onLifecycleAbort);
142
+ state.controller.abort();
143
+ const wasMapped = this._localCapabilityAdvertisementsByPeer.get(state.peerHash) === state;
144
+ if (wasMapped) {
145
+ this._localCapabilityAdvertisementsByPeer.delete(state.peerHash);
146
+ }
147
+ const ready = this._localCapabilityReadyBySession.get(state.peerSession);
148
+ if (ready?.advertisement === state) {
149
+ this._localCapabilityReadyBySession.delete(state.peerSession);
150
+ }
151
+ if (wasMapped &&
152
+ !options?.preserveContext &&
153
+ this._localCapabilityContextBySession.get(state.peerSession) ===
154
+ state.context) {
155
+ this._localCapabilityContextBySession.delete(state.peerSession);
156
+ }
157
+ }
158
+ isLocalCapabilityAdvertisementOwnerCurrent(state) {
159
+ return (this._localCapabilityAdvertisementsByPeer.get(state.peerHash) === state &&
160
+ this._localCapabilityContextBySession.get(state.peerSession) ===
161
+ state.context &&
162
+ state.context.peerHash === state.peerHash &&
163
+ state.context.lifecycleSignal === state.lifecycleSignal &&
164
+ state.context.target.equals(state.target) &&
165
+ !state.controller.signal.aborted &&
166
+ !state.lifecycleSignal.aborted &&
167
+ !this.deps.isClosed() &&
168
+ this.deps.isPeerSessionCurrent(state.peerHash, state.peerSession) &&
169
+ (state.receiverTransportSession === undefined ||
170
+ this.deps.getReceiverTransportSession() ===
171
+ state.receiverTransportSession));
172
+ }
173
+ isLocalCapabilityAdvertisementGenerationCurrent(state) {
174
+ return (this.isLocalCapabilityAdvertisementOwnerCurrent(state) &&
175
+ this.deps.isReceiveEpochCurrent(state.peerHash, state.receiveEpoch));
176
+ }
177
+ isLocalCapabilityAdvertisementReadyOpen(state) {
178
+ return (this.isLocalCapabilityAdvertisementGenerationCurrent(state) &&
179
+ this.deps.isPeerStateCurrent(state.peerHash, state.peerSession, state.receiveEpoch));
180
+ }
181
+ localCapabilityRetryDelay(state) {
182
+ const exponent = Math.max(0, state.attempts - 1);
183
+ return Math.min(this.maxRequestRetryMs, this.requestRetryMs * 2 ** Math.min(exponent, MAX_BACKOFF_EXPONENT));
184
+ }
185
+ armLocalCapabilityAdvertisement(state) {
186
+ if (state.timer || state.inFlight || state.ready) {
187
+ return;
188
+ }
189
+ if (state.acknowledgedReady && !state.context.legacyBarrierReleased) {
190
+ return;
191
+ }
192
+ if (!this.isLocalCapabilityAdvertisementOwnerCurrent(state)) {
193
+ this.clearLocalCapabilityAdvertisement(state);
194
+ return;
195
+ }
196
+ if (!this.isLocalCapabilityAdvertisementGenerationCurrent(state)) {
197
+ return;
198
+ }
199
+ state.timer = setTimeout(() => {
200
+ state.timer = undefined;
201
+ if (!this.isLocalCapabilityAdvertisementOwnerCurrent(state)) {
202
+ this.clearLocalCapabilityAdvertisement(state);
203
+ return;
204
+ }
205
+ if (!this.isLocalCapabilityAdvertisementGenerationCurrent(state)) {
206
+ return;
207
+ }
208
+ if (!this.isLocalCapabilityAdvertisementReadyOpen(state)) {
209
+ this.armLocalCapabilityAdvertisement(state);
210
+ return;
211
+ }
212
+ void this.runLocalCapabilityAdvertisement(state);
213
+ }, this.localCapabilityRetryDelay(state));
214
+ state.timer.unref?.();
215
+ }
216
+ async runLocalCapabilityAdvertisement(state) {
217
+ if (state.inFlight) {
218
+ await state.inFlight;
219
+ return;
220
+ }
221
+ if (state.ready) {
222
+ return;
223
+ }
224
+ if (!this.isLocalCapabilityAdvertisementOwnerCurrent(state)) {
225
+ this.clearLocalCapabilityAdvertisement(state);
226
+ return;
227
+ }
228
+ if (!this.isLocalCapabilityAdvertisementGenerationCurrent(state)) {
229
+ return;
230
+ }
231
+ if (state.acknowledgedReady) {
232
+ if (state.context.legacyBarrierReleased) {
233
+ this.promoteLocalCapabilityAdvertisement(state);
234
+ }
235
+ return;
236
+ }
237
+ if (!this.isLocalCapabilityAdvertisementReadyOpen(state)) {
238
+ this.armLocalCapabilityAdvertisement(state);
239
+ return;
240
+ }
241
+ state.attempts = Math.min(state.attempts + 1, MAX_BACKOFF_EXPONENT + 1);
242
+ let operation;
243
+ operation = (async () => {
244
+ const refreshed = await this.deps.refreshLocalCapability({
245
+ peerHash: state.peerHash,
246
+ target: state.target,
247
+ peerSession: state.peerSession,
248
+ receiveEpoch: state.receiveEpoch,
249
+ signal: AbortSignal.any([
250
+ state.controller.signal,
251
+ state.lifecycleSignal,
252
+ ]),
253
+ });
254
+ if (!refreshed ||
255
+ !this.isLocalCapabilityAdvertisementGenerationCurrent(state) ||
256
+ this.deps.getReceiverTransportSession() !==
257
+ refreshed.receiverTransportSession) {
258
+ return;
259
+ }
260
+ state.receiverTransportSession = refreshed.receiverTransportSession;
261
+ state.acknowledgedReady = {
262
+ peerHash: state.peerHash,
263
+ receiveEpoch: state.receiveEpoch,
264
+ receiverTransportSession: refreshed.receiverTransportSession,
265
+ requestNotBeforeMs: refreshed.requestNotBeforeMs,
266
+ advertisement: state,
267
+ };
268
+ state.attempts = 0;
269
+ this.promoteLocalCapabilityAdvertisement(state);
270
+ })()
271
+ .catch((error) => {
272
+ if (!state.controller.signal.aborted &&
273
+ !state.lifecycleSignal.aborted &&
274
+ !this.deps.isClosed()) {
275
+ this.deps.onLocalCapabilityError?.(error);
276
+ }
277
+ })
278
+ .finally(() => {
279
+ if (state.inFlight === operation) {
280
+ state.inFlight = undefined;
281
+ }
282
+ if (!this.isLocalCapabilityAdvertisementOwnerCurrent(state)) {
283
+ this.clearLocalCapabilityAdvertisement(state);
284
+ }
285
+ else if (this.isLocalCapabilityAdvertisementGenerationCurrent(state) &&
286
+ !state.ready) {
287
+ if (!state.acknowledgedReady || state.context.legacyBarrierReleased) {
288
+ this.armLocalCapabilityAdvertisement(state);
289
+ }
290
+ }
291
+ });
292
+ state.inFlight = operation;
293
+ await operation;
294
+ }
295
+ /**
296
+ * Start local authenticated-apply advertisement independently of the legacy
297
+ * join path. ACK and legacy publication are a two-phase barrier: the first
298
+ * attempt always settles independently, while readiness is promoted only
299
+ * after the host releases the legacy barrier. Failed attempts leave one
300
+ * exact-session worker retrying with capped exponential backoff.
301
+ */
302
+ advertiseLocalCapability(properties) {
303
+ const peerHash = properties.target.hashcode();
304
+ if (properties.signal.aborted ||
305
+ this.deps.isClosed() ||
306
+ !this.deps.isPeerSessionCurrent(peerHash, properties.peerSession) ||
307
+ !this.deps.isReceiveEpochCurrent(peerHash, properties.receiveEpoch)) {
308
+ return {
309
+ firstAttempt: Promise.resolve(),
310
+ releaseLegacyBarrier: () => { },
311
+ };
312
+ }
313
+ let context = this._localCapabilityContextBySession.get(properties.peerSession);
314
+ if (context &&
315
+ (context.peerHash !== peerHash ||
316
+ !context.target.equals(properties.target) ||
317
+ context.lifecycleSignal !== properties.signal)) {
318
+ return {
319
+ firstAttempt: Promise.resolve(),
320
+ releaseLegacyBarrier: () => { },
321
+ };
322
+ }
323
+ if (!context) {
324
+ context = {
325
+ peerHash,
326
+ target: properties.target,
327
+ lifecycleSignal: properties.signal,
328
+ legacyBarrierReleased: false,
329
+ };
330
+ this._localCapabilityContextBySession.set(properties.peerSession, context);
331
+ }
332
+ let state = this._localCapabilityAdvertisementsByPeer.get(peerHash);
333
+ if (state &&
334
+ (state.peerSession !== properties.peerSession ||
335
+ state.context !== context ||
336
+ state.lifecycleSignal !== properties.signal ||
337
+ !state.target.equals(properties.target))) {
338
+ this.clearLocalCapabilityAdvertisement(state);
339
+ state = undefined;
340
+ }
341
+ if (state && state.receiveEpoch !== properties.receiveEpoch) {
342
+ this.clearLocalCapabilityAdvertisement(state, { preserveContext: true });
343
+ state = undefined;
344
+ }
345
+ if (state && !this.isLocalCapabilityAdvertisementOwnerCurrent(state)) {
346
+ this.clearLocalCapabilityAdvertisement(state);
347
+ state = undefined;
348
+ }
349
+ if (this._localCapabilityContextBySession.get(properties.peerSession) !==
350
+ context) {
351
+ return {
352
+ firstAttempt: Promise.resolve(),
353
+ releaseLegacyBarrier: () => { },
354
+ };
355
+ }
356
+ if (!state) {
357
+ const controller = new AbortController();
358
+ const advertisement = {
359
+ peerHash,
360
+ target: properties.target,
361
+ peerSession: properties.peerSession,
362
+ receiveEpoch: properties.receiveEpoch,
363
+ lifecycleSignal: properties.signal,
364
+ onLifecycleAbort: () => { },
365
+ controller,
366
+ context,
367
+ attempts: 0,
368
+ ready: false,
369
+ receiverTransportSession: this.deps.getReceiverTransportSession(),
370
+ };
371
+ advertisement.onLifecycleAbort = () => this.clearLocalCapabilityAdvertisement(advertisement);
372
+ properties.signal.addEventListener("abort", advertisement.onLifecycleAbort, {
373
+ once: true,
374
+ });
375
+ this._localCapabilityAdvertisementsByPeer.set(peerHash, advertisement);
376
+ state = advertisement;
377
+ }
378
+ const firstAttempt = state.firstAttempt ??
379
+ (state.firstAttempt = this.runLocalCapabilityAdvertisement(state));
380
+ const advertisement = state;
381
+ return {
382
+ firstAttempt,
383
+ releaseLegacyBarrier: () => this.releaseLocalCapabilityLegacyBarrier(advertisement.peerSession, context),
384
+ };
385
+ }
386
+ releaseLocalCapabilityLegacyBarrier(peerSession, context) {
387
+ if (context.legacyBarrierReleased) {
388
+ return;
389
+ }
390
+ if (this._localCapabilityContextBySession.get(peerSession) !== context ||
391
+ context.lifecycleSignal.aborted ||
392
+ this.deps.isClosed() ||
393
+ !this.deps.isPeerSessionCurrent(context.peerHash, peerSession)) {
394
+ return;
395
+ }
396
+ context.legacyBarrierReleased = true;
397
+ const state = this._localCapabilityAdvertisementsByPeer.get(context.peerHash);
398
+ if (state?.peerSession === peerSession && state.context === context) {
399
+ if (!this.isLocalCapabilityAdvertisementOwnerCurrent(state)) {
400
+ this.clearLocalCapabilityAdvertisement(state);
401
+ return;
402
+ }
403
+ this.promoteLocalCapabilityAdvertisement(state);
404
+ }
405
+ }
406
+ promoteLocalCapabilityAdvertisement(state) {
407
+ const ready = state.acknowledgedReady;
408
+ if (state.ready ||
409
+ !state.context.legacyBarrierReleased ||
410
+ !ready ||
411
+ ready.receiveEpoch !== state.receiveEpoch ||
412
+ ready.advertisement !== state ||
413
+ !this.isLocalCapabilityAdvertisementOwnerCurrent(state) ||
414
+ !this.isLocalCapabilityAdvertisementGenerationCurrent(state) ||
415
+ this.deps.getReceiverTransportSession() !== ready.receiverTransportSession) {
416
+ return state.ready;
417
+ }
418
+ if (!this.isLocalCapabilityAdvertisementReadyOpen(state)) {
419
+ this.armLocalCapabilityAdvertisement(state);
420
+ return false;
421
+ }
422
+ if (!this.recordLocalCapabilityReady({
423
+ peerHash: state.peerHash,
424
+ peerSession: state.peerSession,
425
+ receiveEpoch: state.receiveEpoch,
426
+ receiverTransportSession: ready.receiverTransportSession,
427
+ requestNotBeforeMs: ready.requestNotBeforeMs,
428
+ }, state)) {
429
+ return false;
430
+ }
431
+ state.ready = true;
432
+ return true;
433
+ }
434
+ /**
435
+ * Re-advertise one exact current recovery epoch from the stable membership
436
+ * context captured during opening. The opening handle owns barrier release;
437
+ * recovery never bypasses a legacy snapshot or role publication still in
438
+ * progress.
439
+ */
440
+ reAdvertiseLocalCapabilityForRecovery(properties) {
441
+ const context = this._localCapabilityContextBySession.get(properties.peerSession);
442
+ if (!context ||
443
+ context.peerHash !== properties.peerHash ||
444
+ context.lifecycleSignal.aborted ||
445
+ this.deps.isClosed() ||
446
+ !this.deps.isPeerSessionCurrent(properties.peerHash, properties.peerSession) ||
447
+ !this.deps.isReceiveEpochCurrent(properties.peerHash, properties.receiveEpoch)) {
448
+ return false;
449
+ }
450
+ const state = this._receiveStates.get(properties.peerHash);
451
+ if (state?.peerSession === properties.peerSession &&
452
+ state.receiveEpoch === properties.receiveEpoch &&
453
+ state.receiverBinding !== undefined) {
454
+ return false;
455
+ }
456
+ const ready = this._localCapabilityReadyBySession.get(properties.peerSession);
457
+ if (ready?.peerHash === properties.peerHash &&
458
+ ready.receiveEpoch === properties.receiveEpoch &&
459
+ ready.receiverTransportSession === this.deps.getReceiverTransportSession()) {
460
+ return false;
461
+ }
462
+ this.advertiseLocalCapability({
463
+ target: context.target,
464
+ peerSession: properties.peerSession,
465
+ receiveEpoch: properties.receiveEpoch,
466
+ signal: context.lifecycleSignal,
467
+ });
468
+ return true;
469
+ }
115
470
  /** Record success of this session's ACKed local APPLY advertisement. */
116
471
  markLocalCapabilityReady(properties) {
472
+ return this.recordLocalCapabilityReady(properties);
473
+ }
474
+ recordLocalCapabilityReady(properties, advertisement) {
117
475
  const { peerHash, peerSession, receiverTransportSession } = properties;
118
476
  const state = this._receiveStates.get(peerHash);
119
477
  if (this.deps.isClosed() ||
@@ -123,8 +481,10 @@ export class ReplicationInfoV2ReceiveCoordinator {
123
481
  }
124
482
  const ready = {
125
483
  peerHash,
484
+ receiveEpoch: properties.receiveEpoch,
126
485
  receiverTransportSession,
127
486
  requestNotBeforeMs: properties.requestNotBeforeMs,
487
+ advertisement,
128
488
  };
129
489
  this._localCapabilityReadyBySession.set(peerSession, ready);
130
490
  if (state?.peerSession === peerSession &&
@@ -198,7 +558,9 @@ export class ReplicationInfoV2ReceiveCoordinator {
198
558
  });
199
559
  }
200
560
  const ready = this._localCapabilityReadyBySession.get(peerSession);
201
- if (ready?.peerHash === peerHash && state.receiverBinding === undefined) {
561
+ if (ready?.peerHash === peerHash &&
562
+ ready.receiveEpoch === receiveEpoch &&
563
+ state.receiverBinding === undefined) {
202
564
  this.bindLocalCapability(state, ready);
203
565
  }
204
566
  if (state.phase !== "active") {
@@ -231,7 +593,7 @@ export class ReplicationInfoV2ReceiveCoordinator {
231
593
  };
232
594
  this._receiveStates.set(peerHash, state);
233
595
  const ready = this._localCapabilityReadyBySession.get(peerSession);
234
- if (ready?.peerHash === peerHash) {
596
+ if (ready?.peerHash === peerHash && ready.receiveEpoch === receiveEpoch) {
235
597
  this.bindLocalCapability(state, ready);
236
598
  this.armRequest(state, 0);
237
599
  }
@@ -629,6 +991,7 @@ export class ReplicationInfoV2ReceiveCoordinator {
629
991
  }
630
992
  const ready = {
631
993
  peerHash: state.peerHash,
994
+ receiveEpoch: state.receiveEpoch,
632
995
  receiverTransportSession: refreshed.receiverTransportSession,
633
996
  requestNotBeforeMs: refreshed.requestNotBeforeMs,
634
997
  };
@@ -673,6 +1036,7 @@ export class ReplicationInfoV2ReceiveCoordinator {
673
1036
  const ready = this._localCapabilityReadyBySession.get(state.peerSession);
674
1037
  if (!ready ||
675
1038
  ready.peerHash !== state.peerHash ||
1039
+ ready.receiveEpoch !== state.receiveEpoch ||
676
1040
  ready.receiverTransportSession !== state.receiverTransportSession) {
677
1041
  return;
678
1042
  }