@agentunion/fastaun-browser 0.5.8 → 0.5.9
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 +30 -0
- package/_packed_docs/CHANGELOG.md +30 -0
- package/_packed_docs/agent.md/examples//347/276/244/347/273/204-/345/274/200/345/217/221/345/233/242/351/230/237.md +21 -0
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +1 -0
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts.map +1 -1
- package/dist/aid-store.js +1 -3
- package/dist/aid-store.js.map +1 -1
- package/dist/bundle.js +454 -83
- package/dist/client/delivery.d.ts +7 -0
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +140 -19
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +2 -2
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.d.ts.map +1 -1
- package/dist/client/lifecycle.js +15 -4
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +8 -0
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +149 -34
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +50 -12
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +105 -13
- package/dist/client.js.map +1 -1
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +7 -3
- package/dist/facades.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/_packed_docs//345/217/221/345/270/203/346/212/245/345/221/212-0.5.6.md +0 -260
package/dist/bundle.js
CHANGED
|
@@ -460,7 +460,7 @@ var init_indexeddb_store = __esm({
|
|
|
460
460
|
});
|
|
461
461
|
|
|
462
462
|
// src/version.ts
|
|
463
|
-
var VERSION = "0.5.
|
|
463
|
+
var VERSION = "0.5.9";
|
|
464
464
|
|
|
465
465
|
// src/types.ts
|
|
466
466
|
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
@@ -4511,6 +4511,9 @@ var MessageDeliveryEngine = class {
|
|
|
4511
4511
|
__publicField(this, "realtimeSyncing", null);
|
|
4512
4512
|
__publicField(this, "pendingP2pPullUpper", null);
|
|
4513
4513
|
__publicField(this, "pendingGroupPullUpper", null);
|
|
4514
|
+
__publicField(this, "pendingPullNoProgressAcks", null);
|
|
4515
|
+
__publicField(this, "onlineUnreadHintTargets", null);
|
|
4516
|
+
__publicField(this, "onlineUnreadHintOwners", null);
|
|
4514
4517
|
__publicField(this, "realtimeAcking", null);
|
|
4515
4518
|
__publicField(this, "pendingP2PInlineAcks", null);
|
|
4516
4519
|
__publicField(this, "pendingGroupInlineAcks", null);
|
|
@@ -4523,9 +4526,13 @@ var MessageDeliveryEngine = class {
|
|
|
4523
4526
|
}
|
|
4524
4527
|
resetInlineAckState() {
|
|
4525
4528
|
this.inlineGeneration += 1;
|
|
4529
|
+
void this.runtime.client._rpcPipeline?.invalidatePulls?.();
|
|
4526
4530
|
this.realtimeSyncing = null;
|
|
4527
4531
|
this.pendingP2pPullUpper = null;
|
|
4528
4532
|
this.pendingGroupPullUpper = null;
|
|
4533
|
+
this.pendingPullNoProgressAcks = null;
|
|
4534
|
+
this.onlineUnreadHintTargets = null;
|
|
4535
|
+
this.onlineUnreadHintOwners = null;
|
|
4529
4536
|
this.realtimeTailResults = null;
|
|
4530
4537
|
this.realtimeAcking = null;
|
|
4531
4538
|
this.pendingP2PInlineAcks = null;
|
|
@@ -4535,6 +4542,16 @@ var MessageDeliveryEngine = class {
|
|
|
4535
4542
|
isInlineGenerationCurrent(generation) {
|
|
4536
4543
|
return generation === this.inlineGeneration;
|
|
4537
4544
|
}
|
|
4545
|
+
isPullOperationCurrent() {
|
|
4546
|
+
const client = this.runtime.client;
|
|
4547
|
+
const generation = client._pullOperationGeneration;
|
|
4548
|
+
if (generation === void 0) return true;
|
|
4549
|
+
const pipeline = client._rpcPipeline;
|
|
4550
|
+
return typeof pipeline?.isPullGenerationCurrent === "function" ? pipeline.isPullGenerationCurrent(generation) : true;
|
|
4551
|
+
}
|
|
4552
|
+
ensurePullOperationCurrent() {
|
|
4553
|
+
if (!this.isPullOperationCurrent()) throw new Error("pull invalidated");
|
|
4554
|
+
}
|
|
4538
4555
|
captureInlineGeneration() {
|
|
4539
4556
|
return this.inlineGeneration;
|
|
4540
4557
|
}
|
|
@@ -4565,7 +4582,15 @@ var MessageDeliveryEngine = class {
|
|
|
4565
4582
|
}
|
|
4566
4583
|
consumePendingPull(ns, throughSeq) {
|
|
4567
4584
|
const pending = ns.startsWith("p2p:") ? this.pendingP2pPullUpper : this.pendingGroupPullUpper;
|
|
4568
|
-
if ((pending?.get(ns) ?? 0) <= throughSeq)
|
|
4585
|
+
if ((pending?.get(ns) ?? 0) <= throughSeq) {
|
|
4586
|
+
pending?.delete(ns);
|
|
4587
|
+
this.pendingPullNoProgressAcks?.delete(ns);
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
markPendingPullNoProgress(ns, ack) {
|
|
4591
|
+
const blocked = this.pendingPullNoProgressAcks ?? /* @__PURE__ */ new Map();
|
|
4592
|
+
this.pendingPullNoProgressAcks = blocked;
|
|
4593
|
+
blocked.set(ns, ack);
|
|
4569
4594
|
}
|
|
4570
4595
|
schedulePendingPullIfNeeded(ns, reason) {
|
|
4571
4596
|
const pending = ns.startsWith("p2p:") ? this.pendingP2pPullUpper : this.pendingGroupPullUpper;
|
|
@@ -4573,15 +4598,20 @@ var MessageDeliveryEngine = class {
|
|
|
4573
4598
|
const upper = pending.get(ns) ?? 0;
|
|
4574
4599
|
if (upper <= 0) {
|
|
4575
4600
|
pending.delete(ns);
|
|
4601
|
+
this.pendingPullNoProgressAcks?.delete(ns);
|
|
4576
4602
|
return false;
|
|
4577
4603
|
}
|
|
4578
4604
|
const client = this.runtime.client;
|
|
4579
4605
|
const contiguous = client._seqTracker.getContiguousSeq(ns);
|
|
4580
4606
|
if (upper <= contiguous) {
|
|
4581
4607
|
pending.delete(ns);
|
|
4608
|
+
this.pendingPullNoProgressAcks?.delete(ns);
|
|
4582
4609
|
client._clientLog?.debug(`pending pull upper already covered: ns=${ns}, upper_seq=${upper}, contiguous=${contiguous}, reason=${reason}`);
|
|
4583
4610
|
return false;
|
|
4584
4611
|
}
|
|
4612
|
+
const blockedAck = this.pendingPullNoProgressAcks?.get(ns);
|
|
4613
|
+
if (blockedAck !== void 0 && contiguous <= blockedAck) return false;
|
|
4614
|
+
this.pendingPullNoProgressAcks?.delete(ns);
|
|
4585
4615
|
if (client.state !== "ready" /* READY */ || client._closing || this.realtimeSyncing?.has(ns) || client._rpcPipeline?.hasPullActivity?.(ns, false)) return false;
|
|
4586
4616
|
pending.delete(ns);
|
|
4587
4617
|
client._clientLog?.debug(`pending push follow-up pull scheduled: ns=${ns}, upper_seq=${upper}, reason=${reason}`);
|
|
@@ -4947,6 +4977,15 @@ var MessageDeliveryEngine = class {
|
|
|
4947
4977
|
value = row.effective_ack_seq;
|
|
4948
4978
|
} else if (Object.prototype.hasOwnProperty.call(row, "ack_seq")) {
|
|
4949
4979
|
value = row.ack_seq;
|
|
4980
|
+
} else if (Object.prototype.hasOwnProperty.call(row, "cursor")) {
|
|
4981
|
+
const cursor = row.cursor;
|
|
4982
|
+
const cursorRow = isJsonObject(cursor) ? cursor : null;
|
|
4983
|
+
if (cursorRow) {
|
|
4984
|
+
if (!Object.prototype.hasOwnProperty.call(cursorRow, "current_seq")) return 0;
|
|
4985
|
+
value = cursorRow.current_seq;
|
|
4986
|
+
} else {
|
|
4987
|
+
value = cursor;
|
|
4988
|
+
}
|
|
4950
4989
|
} else {
|
|
4951
4990
|
return requestedSeq;
|
|
4952
4991
|
}
|
|
@@ -4961,6 +5000,7 @@ var MessageDeliveryEngine = class {
|
|
|
4961
5000
|
}
|
|
4962
5001
|
async confirmPlainForwardAck(ns, method, ackSeq, groupId = "") {
|
|
4963
5002
|
const client = this.runtime.client;
|
|
5003
|
+
this.ensurePullOperationCurrent();
|
|
4964
5004
|
const coordinator = this.forwardCoordinator();
|
|
4965
5005
|
const generation = this.captureInlineGeneration();
|
|
4966
5006
|
coordinator.recordForwardAck(ns, ackSeq);
|
|
@@ -4977,6 +5017,7 @@ var MessageDeliveryEngine = class {
|
|
|
4977
5017
|
_rpc_background: true
|
|
4978
5018
|
};
|
|
4979
5019
|
const result = await client._rpcPipeline.rawCall(method, params2, { background: true });
|
|
5020
|
+
this.ensurePullOperationCurrent();
|
|
4980
5021
|
const actualAckSeq = this.resolveForwardAckSeq(result, ackSeq);
|
|
4981
5022
|
if (actualAckSeq < ackSeq) {
|
|
4982
5023
|
throw new Error(`${method} server ACK watermark ${actualAckSeq} is below requested ${ackSeq}`);
|
|
@@ -4993,6 +5034,7 @@ var MessageDeliveryEngine = class {
|
|
|
4993
5034
|
throw new Error(`${method} response must be an object`);
|
|
4994
5035
|
}
|
|
4995
5036
|
const client = this.runtime.client;
|
|
5037
|
+
this.ensurePullOperationCurrent();
|
|
4996
5038
|
const response = result;
|
|
4997
5039
|
const messages = deduplicatePlainForwardPageMessages(response.messages, afterSeq);
|
|
4998
5040
|
const coordinator = this.forwardCoordinator();
|
|
@@ -5020,24 +5062,29 @@ var MessageDeliveryEngine = class {
|
|
|
5020
5062
|
let committed = false;
|
|
5021
5063
|
try {
|
|
5022
5064
|
for (const rawMessage of messages) {
|
|
5065
|
+
this.ensurePullOperationCurrent();
|
|
5023
5066
|
const seq2 = positiveSafeSequenceHint(rawMessage.seq);
|
|
5024
5067
|
if (method === "message.pull") {
|
|
5025
5068
|
const appEvent = p2pAppEventFromPlainPullMessage(rawMessage);
|
|
5026
5069
|
if (await this.publishPulledMessage(appEvent.event, ns, seq2, appEvent.payload, false)) {
|
|
5027
5070
|
publishedCount += 1;
|
|
5028
5071
|
}
|
|
5072
|
+
this.ensurePullOperationCurrent();
|
|
5029
5073
|
continue;
|
|
5030
5074
|
}
|
|
5031
5075
|
const message = normalizeGroupMentionMode(rawMessage);
|
|
5032
5076
|
if (this.recallEventFromGroupMessage(message)) {
|
|
5033
5077
|
if (await this.publishGroupRecallTombstone(groupId, seq2, message)) {
|
|
5078
|
+
this.ensurePullOperationCurrent();
|
|
5034
5079
|
this.markPublishedSeq(ns, seq2);
|
|
5035
5080
|
publishedCount += 1;
|
|
5036
5081
|
}
|
|
5037
5082
|
} else if (await this.publishPulledMessage("group.message_created", ns, seq2, message, false)) {
|
|
5083
|
+
this.ensurePullOperationCurrent();
|
|
5038
5084
|
publishedCount += 1;
|
|
5039
5085
|
}
|
|
5040
5086
|
}
|
|
5087
|
+
this.ensurePullOperationCurrent();
|
|
5041
5088
|
if (messages.length > 0) client._seqTracker.onPullResult(ns, messages, afterSeq);
|
|
5042
5089
|
const commitTarget = Math.max(
|
|
5043
5090
|
client._seqTracker.getContiguousSeq(ns),
|
|
@@ -5049,17 +5096,20 @@ var MessageDeliveryEngine = class {
|
|
|
5049
5096
|
client._seqTracker.forceContiguousSeq(ns, commitTarget);
|
|
5050
5097
|
}
|
|
5051
5098
|
if (client._seqTracker.getContiguousSeq(ns) !== pageContigBefore) {
|
|
5099
|
+
this.ensurePullOperationCurrent();
|
|
5052
5100
|
await this.drainOrderedMessages(ns, void 0, false, false);
|
|
5101
|
+
this.ensurePullOperationCurrent();
|
|
5053
5102
|
await client._commitSeqTrackerState(ns);
|
|
5054
5103
|
}
|
|
5055
5104
|
committed = true;
|
|
5056
5105
|
} catch (exc) {
|
|
5057
|
-
if (!committed && typeof client._seqTracker.restoreNamespaceSnapshot === "function") {
|
|
5106
|
+
if (this.isPullOperationCurrent() && !committed && typeof client._seqTracker.restoreNamespaceSnapshot === "function") {
|
|
5058
5107
|
client._seqTracker.restoreNamespaceSnapshot(ns, pageTrackerSnapshot);
|
|
5059
5108
|
this.dropSeqTrackerPending(ns);
|
|
5060
5109
|
}
|
|
5061
5110
|
throw exc;
|
|
5062
5111
|
}
|
|
5112
|
+
this.ensurePullOperationCurrent();
|
|
5063
5113
|
const committedAck = client._seqTracker.getContiguousSeq(ns);
|
|
5064
5114
|
if (deferredServerCursor > 0 && committedAck >= deferredServerCursor) {
|
|
5065
5115
|
coordinator.clearForwardCursor(ns, committedAck);
|
|
@@ -5092,6 +5142,7 @@ var MessageDeliveryEngine = class {
|
|
|
5092
5142
|
if (clampedAckSeq < pendingAckSeq) {
|
|
5093
5143
|
throw new Error(`${ackMethod} cannot confirm pending Forward watermark ${pendingAckSeq}`);
|
|
5094
5144
|
}
|
|
5145
|
+
this.ensurePullOperationCurrent();
|
|
5095
5146
|
await this.confirmPlainForwardAck(ns, ackMethod, pendingAckSeq, groupId);
|
|
5096
5147
|
}
|
|
5097
5148
|
return { rawCount: messages.length, publishedCount };
|
|
@@ -6234,9 +6285,30 @@ var MessageDeliveryEngine = class {
|
|
|
6234
6285
|
const groupId = String(data.group_id ?? "").trim();
|
|
6235
6286
|
if (!groupId) return;
|
|
6236
6287
|
const ns = `group:${groupId}`;
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6288
|
+
const targets = this.onlineUnreadHintTargets ?? /* @__PURE__ */ new Map();
|
|
6289
|
+
const owners = this.onlineUnreadHintOwners ?? /* @__PURE__ */ new Set();
|
|
6290
|
+
this.onlineUnreadHintTargets = targets;
|
|
6291
|
+
this.onlineUnreadHintOwners = owners;
|
|
6292
|
+
targets.set(ns, Math.max(targets.get(ns) ?? 0, positiveSafeSequenceHint(data.seq)));
|
|
6293
|
+
if (owners.has(ns)) return;
|
|
6294
|
+
owners.add(ns);
|
|
6295
|
+
client._safeAsync((async () => {
|
|
6296
|
+
try {
|
|
6297
|
+
while (true) {
|
|
6298
|
+
const throughSeq = targets.get(ns) ?? 0;
|
|
6299
|
+
const ackBefore = this.syncState(ns).ack;
|
|
6300
|
+
await this.runGroupForwardRecovery(groupId, ns, 50, true, throughSeq);
|
|
6301
|
+
const ackAfter = this.syncState(ns).ack;
|
|
6302
|
+
const target = targets.get(ns) ?? 0;
|
|
6303
|
+
if (ackAfter >= target || ackAfter <= ackBefore) return;
|
|
6304
|
+
}
|
|
6305
|
+
} catch (exc) {
|
|
6306
|
+
client._clientLog?.debug(`online unread hint background Forward failed: ns=${ns} err=${formatDeliveryError(exc)}`);
|
|
6307
|
+
} finally {
|
|
6308
|
+
if (this.onlineUnreadHintTargets === targets) targets.delete(ns);
|
|
6309
|
+
if (this.onlineUnreadHintOwners === owners) owners.delete(ns);
|
|
6310
|
+
}
|
|
6311
|
+
})());
|
|
6240
6312
|
}
|
|
6241
6313
|
enqueueOnlineUnreadEventHint(data) {
|
|
6242
6314
|
const client = this.runtime.client;
|
|
@@ -6266,17 +6338,19 @@ var MessageDeliveryEngine = class {
|
|
|
6266
6338
|
const key = pipeline.pullGateKeyForCall("message.pull", request);
|
|
6267
6339
|
return await pipeline.runPullSerialized(key, invoke, background);
|
|
6268
6340
|
}
|
|
6269
|
-
async runGroupForwardRecovery(groupId, ns, pageLimit, background = false) {
|
|
6341
|
+
async runGroupForwardRecovery(groupId, ns, pageLimit, background = false, throughSeq = 0) {
|
|
6270
6342
|
const client = this.runtime.client;
|
|
6343
|
+
const state = this.syncState(ns);
|
|
6344
|
+
const maxPages = this.forwardMaxPages(state.ack, throughSeq, pageLimit);
|
|
6271
6345
|
const request = {
|
|
6272
6346
|
group_id: groupId,
|
|
6273
|
-
after_seq:
|
|
6347
|
+
after_seq: state.ack,
|
|
6274
6348
|
limit: pageLimit,
|
|
6275
|
-
max_pages:
|
|
6349
|
+
max_pages: maxPages
|
|
6276
6350
|
};
|
|
6277
6351
|
const invoke = async () => {
|
|
6278
6352
|
const after = this.syncState(ns).ack;
|
|
6279
|
-
const messages = await client._pullGroupV2(groupId, after, pageLimit, { gateLocked: true, maxPages
|
|
6353
|
+
const messages = await client._pullGroupV2(groupId, after, pageLimit, { gateLocked: true, maxPages });
|
|
6280
6354
|
return { messages, raw_count: messages.length };
|
|
6281
6355
|
};
|
|
6282
6356
|
const pipeline = client._rpcPipeline;
|
|
@@ -6290,6 +6364,10 @@ var MessageDeliveryEngine = class {
|
|
|
6290
6364
|
const ack = Number(tracker.getContiguousSeq(ns) || 0);
|
|
6291
6365
|
return { ack, tail: ack, head: Math.max(ack, Number(tracker.getMaxSeenSeq?.(ns) || 0)) };
|
|
6292
6366
|
}
|
|
6367
|
+
forwardMaxPages(ack, throughSeq, pageLimit) {
|
|
6368
|
+
const limit = Number.isSafeInteger(pageLimit) && pageLimit > 0 ? pageLimit : 1;
|
|
6369
|
+
return Math.max(1, Math.ceil(Math.max(0, throughSeq - ack) / limit));
|
|
6370
|
+
}
|
|
6293
6371
|
inlineMessage(data) {
|
|
6294
6372
|
if (!isJsonObject(data)) return null;
|
|
6295
6373
|
const inline = data.inline_message;
|
|
@@ -6621,17 +6699,28 @@ var MessageDeliveryEngine = class {
|
|
|
6621
6699
|
if (forceTail || order[0] === "tail") result = await run(true, false, void 0, false, forceTail);
|
|
6622
6700
|
const state = this.syncState(ns);
|
|
6623
6701
|
const tailMissedDuringPull = tailCompleted && Number(client._seqTracker.getMaxSeenSeq(ns) || 0) > state.head;
|
|
6624
|
-
const
|
|
6702
|
+
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
6703
|
+
const pendingThroughSeq = tailMissedDuringPull ? maxSeen : 0;
|
|
6625
6704
|
const tailForward = tailCompleted && (state.ack < state.tail - 1 || tailMissedDuringPull);
|
|
6626
6705
|
const backgroundWindowForward = order[0] === "forward" && !headForward;
|
|
6627
6706
|
if (headForward || tailForward || client._sessionOptions?.background_sync !== false && backgroundWindowForward) {
|
|
6707
|
+
const forwardTarget = Math.max(
|
|
6708
|
+
headForward ? Math.max(pushSeq, maxSeen) : 0,
|
|
6709
|
+
tailForward || backgroundWindowForward ? state.tail - 1 : 0,
|
|
6710
|
+
tailMissedDuringPull ? maxSeen : 0
|
|
6711
|
+
);
|
|
6712
|
+
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
6628
6713
|
result = await run(
|
|
6629
6714
|
false,
|
|
6630
6715
|
!(headForward || tailForward),
|
|
6631
|
-
|
|
6716
|
+
forwardMaxPages,
|
|
6632
6717
|
headForward || tailMissedDuringPull
|
|
6633
6718
|
);
|
|
6634
|
-
if (pendingThroughSeq > 0)
|
|
6719
|
+
if (pendingThroughSeq > 0) {
|
|
6720
|
+
const committedAck = this.syncState(ns).ack;
|
|
6721
|
+
if (committedAck >= pendingThroughSeq) this.consumePendingPull(ns, pendingThroughSeq);
|
|
6722
|
+
else if (committedAck <= state.ack) this.markPendingPullNoProgress(ns, committedAck);
|
|
6723
|
+
}
|
|
6635
6724
|
}
|
|
6636
6725
|
const finalState = this.syncState(ns);
|
|
6637
6726
|
if (tailCompleted && finalState.ack < finalState.tail - 1) {
|
|
@@ -6678,17 +6767,28 @@ var MessageDeliveryEngine = class {
|
|
|
6678
6767
|
if (forceTail || order[0] === "tail") result = await run(true, false, void 0, false, forceTail);
|
|
6679
6768
|
const state = this.syncState(ns);
|
|
6680
6769
|
const tailMissedDuringPull = tailCompleted && Number(client._seqTracker.getMaxSeenSeq(ns) || 0) > state.head;
|
|
6681
|
-
const
|
|
6770
|
+
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
6771
|
+
const pendingThroughSeq = tailMissedDuringPull ? maxSeen : 0;
|
|
6682
6772
|
const tailForward = tailCompleted && (state.ack < state.tail - 1 || tailMissedDuringPull);
|
|
6683
6773
|
const backgroundWindowForward = order[0] === "forward" && !headForward;
|
|
6684
6774
|
if (headForward || tailForward || client._sessionOptions?.background_sync !== false && backgroundWindowForward) {
|
|
6775
|
+
const forwardTarget = Math.max(
|
|
6776
|
+
headForward ? Math.max(pushSeq, maxSeen) : 0,
|
|
6777
|
+
tailForward || backgroundWindowForward ? state.tail - 1 : 0,
|
|
6778
|
+
tailMissedDuringPull ? maxSeen : 0
|
|
6779
|
+
);
|
|
6780
|
+
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
6685
6781
|
result = await run(
|
|
6686
6782
|
false,
|
|
6687
6783
|
!(headForward || tailForward),
|
|
6688
|
-
|
|
6784
|
+
forwardMaxPages,
|
|
6689
6785
|
headForward || tailMissedDuringPull
|
|
6690
6786
|
);
|
|
6691
|
-
if (pendingThroughSeq > 0)
|
|
6787
|
+
if (pendingThroughSeq > 0) {
|
|
6788
|
+
const committedAck = this.syncState(ns).ack;
|
|
6789
|
+
if (committedAck >= pendingThroughSeq) this.consumePendingPull(ns, pendingThroughSeq);
|
|
6790
|
+
else if (committedAck <= state.ack) this.markPendingPullNoProgress(ns, committedAck);
|
|
6791
|
+
}
|
|
6692
6792
|
}
|
|
6693
6793
|
const finalState = this.syncState(ns);
|
|
6694
6794
|
if (tailCompleted && finalState.ack < finalState.tail - 1) {
|
|
@@ -7245,22 +7345,28 @@ var MessageDeliveryEngine = class {
|
|
|
7245
7345
|
}
|
|
7246
7346
|
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true) {
|
|
7247
7347
|
const client = this.runtime.client;
|
|
7348
|
+
this.ensurePullOperationCurrent();
|
|
7248
7349
|
const queue = client._pendingOrderedMsgs.get(ns);
|
|
7249
7350
|
if (!queue || queue.size === 0) return;
|
|
7250
7351
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
7251
7352
|
const ready = [...queue.keys()].filter((seq2) => seq2 <= contig && (beforeSeq === void 0 || seq2 < beforeSeq)).sort((a, b) => a - b);
|
|
7252
7353
|
let delivered = false;
|
|
7253
7354
|
for (const seq2 of ready) {
|
|
7355
|
+
this.ensurePullOperationCurrent();
|
|
7254
7356
|
const item = queue.get(seq2);
|
|
7255
7357
|
queue.delete(seq2);
|
|
7256
7358
|
if (!item || client._pushedSeqs.get(ns)?.has(seq2)) continue;
|
|
7257
7359
|
await this.publishOrderedQueueItem(ns, item.event, seq2, item.payload, pullResponse);
|
|
7360
|
+
this.ensurePullOperationCurrent();
|
|
7258
7361
|
this.markPublishedSeq(ns, seq2);
|
|
7259
7362
|
delivered = true;
|
|
7260
7363
|
}
|
|
7261
7364
|
if (queue.size === 0) {
|
|
7262
7365
|
client._pendingOrderedMsgs.delete(ns);
|
|
7263
|
-
if (delivered && persist)
|
|
7366
|
+
if (delivered && persist) {
|
|
7367
|
+
this.ensurePullOperationCurrent();
|
|
7368
|
+
await this.saveSeqTrackerState();
|
|
7369
|
+
}
|
|
7264
7370
|
}
|
|
7265
7371
|
}
|
|
7266
7372
|
async publishOrderedMessage(event, ns, seq2, payload) {
|
|
@@ -7294,15 +7400,19 @@ var MessageDeliveryEngine = class {
|
|
|
7294
7400
|
}
|
|
7295
7401
|
async publishPulledMessage(event, ns, seq2, payload, persist = true) {
|
|
7296
7402
|
const client = this.runtime.client;
|
|
7403
|
+
this.ensurePullOperationCurrent();
|
|
7297
7404
|
const seqNum = Number(seq2);
|
|
7298
7405
|
if (!Number.isFinite(seqNum) || !Number.isInteger(seqNum) || seqNum <= 0 || !ns) {
|
|
7299
7406
|
if (event === "message.recalled") {
|
|
7300
|
-
|
|
7407
|
+
const published = await client._withPullResponseProcessing(
|
|
7301
7408
|
ns,
|
|
7302
7409
|
() => this.publishMessageRecallTombstone(seq2, payload)
|
|
7303
7410
|
);
|
|
7411
|
+
this.ensurePullOperationCurrent();
|
|
7412
|
+
return published;
|
|
7304
7413
|
}
|
|
7305
7414
|
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload));
|
|
7415
|
+
this.ensurePullOperationCurrent();
|
|
7306
7416
|
return true;
|
|
7307
7417
|
}
|
|
7308
7418
|
const queue = client._pendingOrderedMsgs.get(ns);
|
|
@@ -7312,6 +7422,7 @@ var MessageDeliveryEngine = class {
|
|
|
7312
7422
|
return false;
|
|
7313
7423
|
}
|
|
7314
7424
|
await this.drainOrderedMessages(ns, seqNum, false, persist);
|
|
7425
|
+
this.ensurePullOperationCurrent();
|
|
7315
7426
|
queue?.delete(seqNum);
|
|
7316
7427
|
if (queue && queue.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
7317
7428
|
if (event === "message.recalled") {
|
|
@@ -7319,10 +7430,12 @@ var MessageDeliveryEngine = class {
|
|
|
7319
7430
|
ns,
|
|
7320
7431
|
() => this.publishMessageRecallTombstone(seqNum, payload)
|
|
7321
7432
|
);
|
|
7433
|
+
this.ensurePullOperationCurrent();
|
|
7322
7434
|
this.markPublishedSeq(ns, seqNum);
|
|
7323
7435
|
return published;
|
|
7324
7436
|
}
|
|
7325
7437
|
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload));
|
|
7438
|
+
this.ensurePullOperationCurrent();
|
|
7326
7439
|
this.markPublishedSeq(ns, seqNum);
|
|
7327
7440
|
return true;
|
|
7328
7441
|
}
|
|
@@ -7884,11 +7997,14 @@ var LifecycleController = class {
|
|
|
7884
7997
|
return;
|
|
7885
7998
|
}
|
|
7886
7999
|
client._delivery.resetInlineAckState();
|
|
8000
|
+
const pullInvalidation = client._rpcPipeline?.invalidatePulls?.();
|
|
8001
|
+
client._rpcPipeline?.stopPullGateWatchdogs?.();
|
|
8002
|
+
await client._transport.close();
|
|
8003
|
+
await pullInvalidation;
|
|
7887
8004
|
await client._cancelReconnectAndWait();
|
|
7888
8005
|
await this.cancelConnectionAttemptAndWait();
|
|
7889
8006
|
await client._saveSeqTrackerState();
|
|
7890
8007
|
client._stopBackgroundTasks();
|
|
7891
|
-
await client._transport.close();
|
|
7892
8008
|
if (client._closing) return;
|
|
7893
8009
|
this.runtime.lifecycle.resetForDisconnect("standby");
|
|
7894
8010
|
await this.publishLifecycleStopEvent({ state: client._publicState(client._state) });
|
|
@@ -7909,22 +8025,30 @@ var LifecycleController = class {
|
|
|
7909
8025
|
return;
|
|
7910
8026
|
}
|
|
7911
8027
|
return this.withLifecycleStop(async () => {
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
await client._saveSeqTrackerState();
|
|
8028
|
+
const pullInvalidation = client._rpcPipeline?.invalidatePulls?.();
|
|
8029
|
+
client._rpcPipeline?.stopPullGateWatchdogs?.();
|
|
7915
8030
|
client._stopBackgroundTasks();
|
|
7916
8031
|
if (client._state === "idle" || client._state === "closed") {
|
|
8032
|
+
const reconnectCancellation2 = client._cancelReconnectAndWait();
|
|
8033
|
+
const connectionCancellation2 = this.cancelConnectionAttemptAndWait();
|
|
8034
|
+
await Promise.all([reconnectCancellation2, connectionCancellation2]);
|
|
8035
|
+
await pullInvalidation;
|
|
8036
|
+
await client._saveSeqTrackerState();
|
|
7917
8037
|
this.runtime.lifecycle.setState("closed");
|
|
7918
8038
|
client._resetSeqTrackingState();
|
|
7919
8039
|
client._clientLog.debug(`close exit: elapsed=${Date.now() - tStart}ms reason=already_idle`);
|
|
7920
8040
|
return;
|
|
7921
8041
|
}
|
|
8042
|
+
const reconnectCancellation = client._cancelReconnectAndWait();
|
|
8043
|
+
const connectionCancellation = this.cancelConnectionAttemptAndWait();
|
|
7922
8044
|
try {
|
|
7923
8045
|
await client._transport.call("auth.logout", {});
|
|
7924
8046
|
} catch (err) {
|
|
7925
8047
|
client._clientLog.warn(`auth.logout during close failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
7926
8048
|
}
|
|
7927
8049
|
await client._transport.close();
|
|
8050
|
+
await Promise.all([pullInvalidation, reconnectCancellation, connectionCancellation]);
|
|
8051
|
+
await client._saveSeqTrackerState();
|
|
7928
8052
|
this.runtime.lifecycle.setState("closed");
|
|
7929
8053
|
await this.publishLifecycleStopEvent({ state: client._publicState(client._state) });
|
|
7930
8054
|
client._resetSeqTrackingState();
|
|
@@ -14829,6 +14953,7 @@ var SIGNED_METHODS = /* @__PURE__ */ new Set([
|
|
|
14829
14953
|
"group.resume"
|
|
14830
14954
|
]);
|
|
14831
14955
|
var SIGNING_KEY_CACHE_MAX = 32;
|
|
14956
|
+
var IDENTITY_ADMISSION_RETRY_DELAYS_MS = [0, 50, 100, 200];
|
|
14832
14957
|
var signingKeyCache = /* @__PURE__ */ new Map();
|
|
14833
14958
|
var certFingerprintCache = /* @__PURE__ */ new Map();
|
|
14834
14959
|
function cacheGet(cache, key) {
|
|
@@ -14883,6 +15008,13 @@ async function signingCertFingerprint(certPem) {
|
|
|
14883
15008
|
}
|
|
14884
15009
|
var PULL_GATE_STALE_MS = 3e4;
|
|
14885
15010
|
var PULL_GATE_OPERATION_TIMEOUT_MS = 3e3;
|
|
15011
|
+
function sameIdentityAdmissionRejection(error, original) {
|
|
15012
|
+
const errorCode2 = Number(error?.code);
|
|
15013
|
+
const originalCode = Number(original?.code);
|
|
15014
|
+
const errorMessage3 = String(error instanceof Error ? error.message : error?.message ?? "").trim().toLowerCase();
|
|
15015
|
+
const originalMessage = String(original instanceof Error ? original.message : original?.message ?? "").trim().toLowerCase();
|
|
15016
|
+
return errorCode2 === -32003 && originalCode === -32003 && errorMessage3 === originalMessage;
|
|
15017
|
+
}
|
|
14886
15018
|
var NON_IDEMPOTENT_TIMEOUT = 35;
|
|
14887
15019
|
var NON_IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
|
|
14888
15020
|
"message.send",
|
|
@@ -14979,6 +15111,8 @@ var RpcPipeline = class {
|
|
|
14979
15111
|
__publicField(this, "runtime");
|
|
14980
15112
|
__publicField(this, "pullGateStates", /* @__PURE__ */ new Map());
|
|
14981
15113
|
__publicField(this, "inlineRealtimeScopes", /* @__PURE__ */ new Set());
|
|
15114
|
+
__publicField(this, "pullGeneration", 0);
|
|
15115
|
+
__publicField(this, "pullInvalidationWait", null);
|
|
14982
15116
|
this.runtime = runtime;
|
|
14983
15117
|
}
|
|
14984
15118
|
async call(method, params2) {
|
|
@@ -15348,19 +15482,21 @@ var RpcPipeline = class {
|
|
|
15348
15482
|
if (method === "message.pull" || method === "message.v2.pull" || method === "message.history") {
|
|
15349
15483
|
if (!client._aid) return "";
|
|
15350
15484
|
const mode = method === "message.history" ? "history" : params2.window_mode === "tail" ? "tail" : "forward";
|
|
15351
|
-
const cursor = mode === "history" ? `before=${String(params2.before_seq)}` : `after=${String(params2.after_seq ?? 0)}
|
|
15352
|
-
return `p2p:${client._aid}
|
|
15485
|
+
const cursor = mode === "history" ? `before=${String(params2.before_seq)}` : `after=${String(params2.after_seq ?? 0)}`;
|
|
15486
|
+
return `p2p:${client._aid}|mode=${mode}|cursor=${cursor}|force=${String(Boolean(params2.force))}|limit=${String(params2.limit)}`;
|
|
15353
15487
|
}
|
|
15354
15488
|
if (method === "group.pull" || method === "group.v2.pull" || method === "group.history") {
|
|
15355
15489
|
const gid = String(params2.group_id ?? params2.group_aid ?? "").trim();
|
|
15356
15490
|
if (!gid) return "";
|
|
15357
15491
|
const mode = method === "group.history" ? "history" : params2.window_mode === "tail" ? "tail" : "forward";
|
|
15358
|
-
const cursor = mode === "history" ? `before=${String(params2.before_seq)}` : `after=${String(params2.after_seq ?? params2.after_message_seq ?? 0)}
|
|
15359
|
-
|
|
15492
|
+
const cursor = mode === "history" ? `before=${String(params2.before_seq)}` : `after=${String(params2.after_seq ?? params2.after_message_seq ?? 0)}`;
|
|
15493
|
+
const explicitCursor = this.explicitGroupCursorParams(params2);
|
|
15494
|
+
const cursorSuffix = Object.keys(explicitCursor).length > 0 ? `|cursor_params=${stableStringify(explicitCursor)}` : "";
|
|
15495
|
+
return `group:${gid}|mode=${mode}|cursor=${cursor}${cursorSuffix}|force=${String(Boolean(params2.force))}|limit=${String(params2.limit)}`;
|
|
15360
15496
|
}
|
|
15361
15497
|
if (method === "group.pull_events") {
|
|
15362
15498
|
const gid = String(params2.group_id ?? params2.group_aid ?? "").trim();
|
|
15363
|
-
return gid ? `group_event:${gid}|forward|after=${String(params2.after_event_seq ?? 0)}|limit=${String(params2.limit)}` : "";
|
|
15499
|
+
return gid ? `group_event:${gid}|mode=forward|cursor=after=${String(params2.after_event_seq ?? 0)}|force=${String(Boolean(params2.force))}|limit=${String(params2.limit)}` : "";
|
|
15364
15500
|
}
|
|
15365
15501
|
return "";
|
|
15366
15502
|
}
|
|
@@ -15380,8 +15516,8 @@ var RpcPipeline = class {
|
|
|
15380
15516
|
if (!state) {
|
|
15381
15517
|
state = { active: null, foreground: [], background: [], byKey: /* @__PURE__ */ new Map(), lifecycle: /* @__PURE__ */ new Map(), watchdog: null };
|
|
15382
15518
|
this.pullGateStates.set(name, state);
|
|
15383
|
-
this.startPullGateWatchdog(state, name);
|
|
15384
15519
|
}
|
|
15520
|
+
this.startPullGateWatchdog(state, name);
|
|
15385
15521
|
return state;
|
|
15386
15522
|
}
|
|
15387
15523
|
pullGateOperationTimeoutMs() {
|
|
@@ -15398,6 +15534,13 @@ var RpcPipeline = class {
|
|
|
15398
15534
|
state.watchdog = timer;
|
|
15399
15535
|
timer.unref?.();
|
|
15400
15536
|
}
|
|
15537
|
+
stopPullGateWatchdogs() {
|
|
15538
|
+
for (const state of this.pullGateStates.values()) {
|
|
15539
|
+
if (state.watchdog === null) continue;
|
|
15540
|
+
clearInterval(state.watchdog);
|
|
15541
|
+
state.watchdog = null;
|
|
15542
|
+
}
|
|
15543
|
+
}
|
|
15401
15544
|
checkPullGate(state, name) {
|
|
15402
15545
|
const active = state.active;
|
|
15403
15546
|
if (!active) {
|
|
@@ -15407,17 +15550,12 @@ var RpcPipeline = class {
|
|
|
15407
15550
|
if (!active.pullingStartedAt || Date.now() - active.pullingStartedAt < this.pullGateOperationTimeoutMs()) return;
|
|
15408
15551
|
if (active.timedOut) return;
|
|
15409
15552
|
active.timedOut = true;
|
|
15553
|
+
active.invalidated = true;
|
|
15554
|
+
this.pullGeneration += 1;
|
|
15410
15555
|
active.cancel?.();
|
|
15411
15556
|
const err = new TimeoutError(`pull gate timeout: ${active.namespace}`, { retryable: true });
|
|
15412
15557
|
this.runtime.client._clientLog?.warn(`pull gate watchdog timeout: gate=${name} key=${active.key}`);
|
|
15413
|
-
state.lifecycle.set(active.namespace, "idle");
|
|
15414
|
-
if (state.active === active) state.active = null;
|
|
15415
|
-
if (state.byKey.get(active.key) === active) state.byKey.delete(active.key);
|
|
15416
|
-
active.resolve = () => {
|
|
15417
|
-
};
|
|
15418
15558
|
active.reject(err);
|
|
15419
|
-
this.drainPullGate(state);
|
|
15420
|
-
this.runtime.client._delivery?.onPullGateIdle?.(active.namespace);
|
|
15421
15559
|
}
|
|
15422
15560
|
realtimePullNamespace(key) {
|
|
15423
15561
|
for (const marker of ["|tail|", "|forward|"]) {
|
|
@@ -15436,7 +15574,7 @@ var RpcPipeline = class {
|
|
|
15436
15574
|
if (typeof cancel !== "function" || !key) return request;
|
|
15437
15575
|
const state = this.pullGateStates.get(this.pullGateName(key));
|
|
15438
15576
|
const active = state?.active;
|
|
15439
|
-
if (!active || active.
|
|
15577
|
+
if (!active || active.key !== key || active.timedOut || active.invalidated) return request;
|
|
15440
15578
|
const boundCancel = () => cancel.call(request);
|
|
15441
15579
|
active.cancel = boundCancel;
|
|
15442
15580
|
return request.finally(() => {
|
|
@@ -15522,7 +15660,10 @@ var RpcPipeline = class {
|
|
|
15522
15660
|
resumeResolve: null,
|
|
15523
15661
|
pullingStartedAt: 0,
|
|
15524
15662
|
timedOut: false,
|
|
15525
|
-
|
|
15663
|
+
invalidated: false,
|
|
15664
|
+
cancel: null,
|
|
15665
|
+
settled: Promise.resolve(),
|
|
15666
|
+
settledResolve: null
|
|
15526
15667
|
};
|
|
15527
15668
|
this.inlineRealtimeScopes.add(normalized);
|
|
15528
15669
|
try {
|
|
@@ -15562,14 +15703,59 @@ var RpcPipeline = class {
|
|
|
15562
15703
|
gate.inflight = false;
|
|
15563
15704
|
gate.startedAt = 0;
|
|
15564
15705
|
}
|
|
15706
|
+
isPullGenerationCurrent(generation) {
|
|
15707
|
+
return generation === this.pullGeneration;
|
|
15708
|
+
}
|
|
15709
|
+
invalidatePulls() {
|
|
15710
|
+
if (this.pullInvalidationWait) return this.pullInvalidationWait;
|
|
15711
|
+
this.pullGeneration += 1;
|
|
15712
|
+
const error = new Error("pull invalidated");
|
|
15713
|
+
const waits = [];
|
|
15714
|
+
for (const state of this.pullGateStates.values()) {
|
|
15715
|
+
const jobs = /* @__PURE__ */ new Set();
|
|
15716
|
+
if (state.active) jobs.add(state.active);
|
|
15717
|
+
for (const job of state.foreground) jobs.add(job);
|
|
15718
|
+
for (const job of state.background) jobs.add(job);
|
|
15719
|
+
for (const job of jobs) {
|
|
15720
|
+
job.invalidated = true;
|
|
15721
|
+
if (!job.timedOut) job.reject(error);
|
|
15722
|
+
job.cancel?.();
|
|
15723
|
+
job.resumeResolve?.();
|
|
15724
|
+
job.resumeResolve = null;
|
|
15725
|
+
if (job.running) {
|
|
15726
|
+
waits.push(job.settled);
|
|
15727
|
+
} else {
|
|
15728
|
+
job.settledResolve?.();
|
|
15729
|
+
job.settledResolve = null;
|
|
15730
|
+
}
|
|
15731
|
+
}
|
|
15732
|
+
state.foreground = state.foreground.filter((job) => !jobs.has(job));
|
|
15733
|
+
state.background = state.background.filter((job) => !jobs.has(job));
|
|
15734
|
+
for (const [key, job] of state.byKey.entries()) {
|
|
15735
|
+
if (jobs.has(job) && !job.running) state.byKey.delete(key);
|
|
15736
|
+
}
|
|
15737
|
+
this.drainPullGate(state);
|
|
15738
|
+
}
|
|
15739
|
+
const wait = Promise.all(waits).then(() => void 0);
|
|
15740
|
+
let tracked;
|
|
15741
|
+
tracked = wait.finally(() => {
|
|
15742
|
+
if (this.pullInvalidationWait === tracked) this.pullInvalidationWait = null;
|
|
15743
|
+
});
|
|
15744
|
+
this.pullInvalidationWait = tracked;
|
|
15745
|
+
return tracked;
|
|
15746
|
+
}
|
|
15747
|
+
pullInvalidationInProgress() {
|
|
15748
|
+
return this.pullInvalidationWait !== null;
|
|
15749
|
+
}
|
|
15565
15750
|
async runPullSerialized(key, operation, background = false) {
|
|
15751
|
+
if (this.pullInvalidationInProgress()) {
|
|
15752
|
+
throw new Error("pull invalidated");
|
|
15753
|
+
}
|
|
15566
15754
|
if (!key) return await this.executePullOperation(operation, background);
|
|
15567
15755
|
const state = this.pullGateState(key);
|
|
15568
15756
|
const namespace = this.pullScopeKey(key);
|
|
15569
|
-
const
|
|
15570
|
-
const
|
|
15571
|
-
const queuedBackground = state.background.find((job2) => job2.namespace === namespace);
|
|
15572
|
-
const existing = background ? active ?? queuedForeground ?? queuedBackground : queuedForeground ?? (active && !active.background ? active : null) ?? queuedBackground;
|
|
15757
|
+
const candidate = state.byKey.get(key);
|
|
15758
|
+
const existing = candidate && !candidate.timedOut && !candidate.invalidated ? candidate : null;
|
|
15573
15759
|
if (existing) {
|
|
15574
15760
|
if (!background && existing.background && existing !== state.active) {
|
|
15575
15761
|
const index = state.background.indexOf(existing);
|
|
@@ -15581,10 +15767,14 @@ var RpcPipeline = class {
|
|
|
15581
15767
|
}
|
|
15582
15768
|
let resolve;
|
|
15583
15769
|
let reject;
|
|
15770
|
+
let settledResolve;
|
|
15584
15771
|
const promise = new Promise((res, rej) => {
|
|
15585
15772
|
resolve = res;
|
|
15586
15773
|
reject = rej;
|
|
15587
15774
|
});
|
|
15775
|
+
const settled = new Promise((resolveSettled) => {
|
|
15776
|
+
settledResolve = resolveSettled;
|
|
15777
|
+
});
|
|
15588
15778
|
void promise.catch(() => {
|
|
15589
15779
|
});
|
|
15590
15780
|
const job = {
|
|
@@ -15602,7 +15792,10 @@ var RpcPipeline = class {
|
|
|
15602
15792
|
resumeResolve: null,
|
|
15603
15793
|
pullingStartedAt: 0,
|
|
15604
15794
|
timedOut: false,
|
|
15605
|
-
|
|
15795
|
+
invalidated: false,
|
|
15796
|
+
cancel: null,
|
|
15797
|
+
settled,
|
|
15798
|
+
settledResolve
|
|
15606
15799
|
};
|
|
15607
15800
|
(background ? state.background : state.foreground).push(job);
|
|
15608
15801
|
state.byKey.set(key, job);
|
|
@@ -15611,14 +15804,30 @@ var RpcPipeline = class {
|
|
|
15611
15804
|
return await promise;
|
|
15612
15805
|
}
|
|
15613
15806
|
async executePullOperation(operation, background) {
|
|
15614
|
-
|
|
15615
|
-
|
|
15807
|
+
const client = this.runtime.client;
|
|
15808
|
+
const hadPrevious = Object.prototype.hasOwnProperty.call(client, "_pullOperationGeneration");
|
|
15809
|
+
const previous = client._pullOperationGeneration;
|
|
15810
|
+
client._pullOperationGeneration = this.pullGeneration;
|
|
15811
|
+
try {
|
|
15812
|
+
if (background) return await client._withBackgroundRpc(operation);
|
|
15813
|
+
return await operation();
|
|
15814
|
+
} finally {
|
|
15815
|
+
if (hadPrevious) client._pullOperationGeneration = previous;
|
|
15816
|
+
else delete client._pullOperationGeneration;
|
|
15817
|
+
}
|
|
15818
|
+
}
|
|
15819
|
+
pullOperationIsCurrent() {
|
|
15820
|
+
const generation = this.runtime.client._pullOperationGeneration;
|
|
15821
|
+
return generation === void 0 || this.isPullGenerationCurrent(generation);
|
|
15822
|
+
}
|
|
15823
|
+
throwIfPullInvalidated() {
|
|
15824
|
+
if (!this.pullOperationIsCurrent()) throw new Error("pull invalidated");
|
|
15616
15825
|
}
|
|
15617
15826
|
async yieldPullGate(key, nextKey, background) {
|
|
15618
15827
|
if (!key) return;
|
|
15619
15828
|
const state = this.pullGateState(key);
|
|
15620
15829
|
const namespace = this.pullScopeKey(key);
|
|
15621
|
-
const job = state.active?.
|
|
15830
|
+
const job = state.active?.key === key ? state.active : null;
|
|
15622
15831
|
if (!job || state.active !== job) return;
|
|
15623
15832
|
const replacementKey = String(nextKey || key);
|
|
15624
15833
|
if (state.byKey.get(job.key) === job) state.byKey.delete(job.key);
|
|
@@ -15634,7 +15843,10 @@ var RpcPipeline = class {
|
|
|
15634
15843
|
state.active = null;
|
|
15635
15844
|
(job.background ? state.background : state.foreground).push(job);
|
|
15636
15845
|
this.drainPullGate(state);
|
|
15637
|
-
if (job.resume)
|
|
15846
|
+
if (job.resume) {
|
|
15847
|
+
await job.resume;
|
|
15848
|
+
if (job.invalidated) throw new Error("pull invalidated");
|
|
15849
|
+
}
|
|
15638
15850
|
}
|
|
15639
15851
|
getPullLifecycle(namespace) {
|
|
15640
15852
|
const ns = this.pullScopeKey(namespace);
|
|
@@ -15670,13 +15882,21 @@ var RpcPipeline = class {
|
|
|
15670
15882
|
return;
|
|
15671
15883
|
}
|
|
15672
15884
|
job.running = true;
|
|
15673
|
-
void this.executePullOperation(job.operation, job.background).then(
|
|
15674
|
-
|
|
15885
|
+
void this.executePullOperation(job.operation, job.background).then(
|
|
15886
|
+
(value) => {
|
|
15887
|
+
if (!job.timedOut && !job.invalidated) job.resolve(value);
|
|
15888
|
+
},
|
|
15889
|
+
(error) => {
|
|
15890
|
+
if (!job.timedOut && !job.invalidated) job.reject(error);
|
|
15891
|
+
}
|
|
15892
|
+
).finally(() => {
|
|
15675
15893
|
state.lifecycle.set(job.namespace, "idle");
|
|
15676
15894
|
if (state.active === job) state.active = null;
|
|
15677
15895
|
if (state.byKey.get(job.key) === job) state.byKey.delete(job.key);
|
|
15678
15896
|
this.drainPullGate(state);
|
|
15679
|
-
|
|
15897
|
+
job.settledResolve?.();
|
|
15898
|
+
job.settledResolve = null;
|
|
15899
|
+
if (!job.invalidated) this.runtime.client._delivery?.onPullGateIdle?.(job.namespace);
|
|
15680
15900
|
});
|
|
15681
15901
|
}
|
|
15682
15902
|
armQueuedPullTimers(_state) {
|
|
@@ -15699,7 +15919,9 @@ var RpcPipeline = class {
|
|
|
15699
15919
|
else request = client._transport.call(method, payload);
|
|
15700
15920
|
return this.bindActivePullCancellation(method, payload, request);
|
|
15701
15921
|
};
|
|
15702
|
-
|
|
15922
|
+
const result = await this.transportCallWithIdentityRecovery(invokeTransport, method, payload);
|
|
15923
|
+
this.throwIfPullInvalidated();
|
|
15924
|
+
return result;
|
|
15703
15925
|
}
|
|
15704
15926
|
async transportCallWithIdentityRecovery(operation, method, params2) {
|
|
15705
15927
|
try {
|
|
@@ -15707,11 +15929,22 @@ var RpcPipeline = class {
|
|
|
15707
15929
|
} catch (err) {
|
|
15708
15930
|
const recover = this.runtime.client._recoverIdentityAdmission;
|
|
15709
15931
|
if (typeof recover !== "function" || !await recover.call(this.runtime.client, err, method, params2)) throw err;
|
|
15710
|
-
|
|
15932
|
+
let lastError = err;
|
|
15933
|
+
for (const delay of IDENTITY_ADMISSION_RETRY_DELAYS_MS) {
|
|
15934
|
+
if (delay > 0) await new Promise((resolve) => setTimeout(resolve, delay));
|
|
15935
|
+
try {
|
|
15936
|
+
return await operation();
|
|
15937
|
+
} catch (retryError) {
|
|
15938
|
+
if (!sameIdentityAdmissionRejection(retryError, err)) throw retryError;
|
|
15939
|
+
lastError = retryError;
|
|
15940
|
+
}
|
|
15941
|
+
}
|
|
15942
|
+
throw lastError;
|
|
15711
15943
|
}
|
|
15712
15944
|
}
|
|
15713
15945
|
async postprocessResult(method, params2, result, options = {}) {
|
|
15714
15946
|
const client = this.runtime.client;
|
|
15947
|
+
this.throwIfPullInvalidated();
|
|
15715
15948
|
let next = result;
|
|
15716
15949
|
if ((method === "group.send" || method === "group.v2.send") && isJsonObject(next)) {
|
|
15717
15950
|
next = normalizeGroupMentionMode(next);
|
|
@@ -17412,17 +17645,21 @@ var GroupFacade = class extends RpcFacade {
|
|
|
17412
17645
|
}
|
|
17413
17646
|
create(params2) {
|
|
17414
17647
|
const split = splitAidStore(params2);
|
|
17415
|
-
if (
|
|
17648
|
+
if (split.params.group_name === void 0 && split.params.groupName !== void 0) {
|
|
17649
|
+
split.params.group_name = split.params.groupName;
|
|
17650
|
+
delete split.params.groupName;
|
|
17651
|
+
}
|
|
17652
|
+
if (split.aidStore && typeof this.client.createGroup === "function") {
|
|
17416
17653
|
return this.client.createGroup(split.params, { aidStore: split.aidStore });
|
|
17417
17654
|
}
|
|
17418
17655
|
return this.call("group.create", split.params);
|
|
17419
17656
|
}
|
|
17420
17657
|
bindAid(params2) {
|
|
17421
|
-
return this.
|
|
17658
|
+
return this.call("group.bind_aid", splitAidStore(params2).params);
|
|
17422
17659
|
}
|
|
17423
17660
|
bindGroupAid(params2) {
|
|
17424
17661
|
const split = splitAidStore(params2);
|
|
17425
|
-
if (typeof this.client.bindGroupAid === "function") {
|
|
17662
|
+
if (split.aidStore && typeof this.client.bindGroupAid === "function") {
|
|
17426
17663
|
return this.client.bindGroupAid(split.params, { aidStore: split.aidStore });
|
|
17427
17664
|
}
|
|
17428
17665
|
return this.call("group.bind_group_aid", split.params);
|
|
@@ -22795,6 +23032,10 @@ var V2Session = class {
|
|
|
22795
23032
|
};
|
|
22796
23033
|
|
|
22797
23034
|
// src/client/v2-e2ee.ts
|
|
23035
|
+
function pullGateKeyForClient(client, method, params2, fallback) {
|
|
23036
|
+
const key = client._rpcPipeline?.pullGateKeyForCall?.(method, params2);
|
|
23037
|
+
return typeof key === "string" && key ? key : fallback;
|
|
23038
|
+
}
|
|
22798
23039
|
var V2_BOOTSTRAP_TTL_MS = 60 * 60 * 1e3;
|
|
22799
23040
|
var V2_RETRYABLE_CODES = /* @__PURE__ */ new Set([-33011, -33012, -33050, -33052, -33054]);
|
|
22800
23041
|
var V2_GROUP_STALE_BOOTSTRAP_CODE = -33054;
|
|
@@ -23854,7 +24095,11 @@ var V2E2EECoordinator = class {
|
|
|
23854
24095
|
const ns = client._aid ? `p2p:${client._aid}` : "";
|
|
23855
24096
|
if (opts?.windowMode === "tail") {
|
|
23856
24097
|
if (!opts.gateLocked) {
|
|
23857
|
-
const key =
|
|
24098
|
+
const key = pullGateKeyForClient(client, "message.v2.pull", {
|
|
24099
|
+
window_mode: "tail",
|
|
24100
|
+
after_seq: afterSeq,
|
|
24101
|
+
limit
|
|
24102
|
+
}, `${ns}|tail|after=${afterSeq}|limit=${limit}`);
|
|
23858
24103
|
return await client._runPullSerialized(key, () => this.pullV2(afterSeq, limit, {
|
|
23859
24104
|
...opts ?? {},
|
|
23860
24105
|
gateLocked: true
|
|
@@ -23864,7 +24109,11 @@ var V2E2EECoordinator = class {
|
|
|
23864
24109
|
return Array.isArray(result.messages) ? result.messages : [];
|
|
23865
24110
|
}
|
|
23866
24111
|
if (ns && !opts?.gateLocked) {
|
|
23867
|
-
const key =
|
|
24112
|
+
const key = pullGateKeyForClient(client, "message.v2.pull", {
|
|
24113
|
+
after_seq: afterSeq,
|
|
24114
|
+
force: opts?.force === true,
|
|
24115
|
+
limit
|
|
24116
|
+
}, `${ns}|forward|after=${afterSeq}|force=${String(Boolean(opts?.force))}|limit=${limit}`);
|
|
23868
24117
|
return await client._runPullSerialized(key, () => this.pullV2(afterSeq, limit, {
|
|
23869
24118
|
...opts ?? {},
|
|
23870
24119
|
gateLocked: true
|
|
@@ -23872,7 +24121,11 @@ var V2E2EECoordinator = class {
|
|
|
23872
24121
|
}
|
|
23873
24122
|
const decrypted = [];
|
|
23874
24123
|
let nextAfterSeq = opts?.force ? afterSeq : afterSeq || (ns ? client._seqTracker.getContiguousSeq(ns) : 0);
|
|
23875
|
-
let pullGateKey = ns ?
|
|
24124
|
+
let pullGateKey = ns ? pullGateKeyForClient(client, "message.v2.pull", {
|
|
24125
|
+
after_seq: afterSeq,
|
|
24126
|
+
force: opts?.force === true,
|
|
24127
|
+
limit
|
|
24128
|
+
}, `${ns}|forward|after=${afterSeq}|force=${String(Boolean(opts?.force))}|limit=${limit}`) : "";
|
|
23876
24129
|
const deferredServerCursor = ns ? this.pendingForwardCursor(ns, client._seqTracker.getContiguousSeq(ns)) : 0;
|
|
23877
24130
|
const deferredForwardAck = ns ? this.pendingForwardAck(ns, client._seqTracker.getContiguousSeq(ns)) : 0;
|
|
23878
24131
|
let pageCount = 0;
|
|
@@ -23917,6 +24170,7 @@ var V2E2EECoordinator = class {
|
|
|
23917
24170
|
const pageTrackerSnapshot = ns && typeof client._seqTracker.snapshotNamespace === "function" ? client._seqTracker.snapshotNamespace(ns) : null;
|
|
23918
24171
|
const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
|
|
23919
24172
|
const deferredKeyFetches = /* @__PURE__ */ new Map();
|
|
24173
|
+
let blockedSeq = 0;
|
|
23920
24174
|
for (const msg of messages) {
|
|
23921
24175
|
const seq2 = Number(msg.seq ?? 0);
|
|
23922
24176
|
if (!Number.isFinite(seq2) || seq2 <= 0) continue;
|
|
@@ -23956,6 +24210,9 @@ var V2E2EECoordinator = class {
|
|
|
23956
24210
|
}
|
|
23957
24211
|
const deferStatus = {};
|
|
23958
24212
|
const plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true);
|
|
24213
|
+
if (deferStatus.deferred) {
|
|
24214
|
+
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq2) : seq2;
|
|
24215
|
+
}
|
|
23959
24216
|
if (deferStatus.deferred && deferStatus.fromAid) {
|
|
23960
24217
|
const key = `${deferStatus.fromAid}\0${deferStatus.senderDeviceId ?? ""}\0${deferStatus.groupId ?? ""}`;
|
|
23961
24218
|
deferredKeyFetches.set(key, {
|
|
@@ -23978,7 +24235,7 @@ var V2E2EECoordinator = class {
|
|
|
23978
24235
|
const serverAckSeq = parsedServerAckSeq ?? 0;
|
|
23979
24236
|
const retentionFloor = Math.max(0, Number(result.retention_floor_seq ?? 0));
|
|
23980
24237
|
if (ns) {
|
|
23981
|
-
const commitTarget = Math.max(
|
|
24238
|
+
const commitTarget = blockedSeq > 0 ? pageContigBefore : Math.max(
|
|
23982
24239
|
pageContigBefore,
|
|
23983
24240
|
Number.isFinite(retentionFloor) ? retentionFloor : 0,
|
|
23984
24241
|
pageCount === 1 ? deferredServerCursor : 0,
|
|
@@ -24020,7 +24277,7 @@ var V2E2EECoordinator = class {
|
|
|
24020
24277
|
this.recordForwardCursor(ns, serverAckSeq, ackSeq);
|
|
24021
24278
|
}
|
|
24022
24279
|
const knownServerAckSeq = hasServerAckSeq ? serverAckSeq : pageCount === 1 ? deferredServerCursor : 0;
|
|
24023
|
-
const ackNeeded = ackSeq > 0 && ackSeq > lastAutoAckSeq && (hasServerAckSeq && ackSeq > serverAckSeq || contigAdvanced && ackSeq > knownServerAckSeq);
|
|
24280
|
+
const ackNeeded = blockedSeq <= 0 && ackSeq > 0 && ackSeq > lastAutoAckSeq && (hasServerAckSeq && ackSeq > serverAckSeq || contigAdvanced && ackSeq > knownServerAckSeq);
|
|
24024
24281
|
if (ackNeeded) {
|
|
24025
24282
|
this.recordForwardAck(ns, ackSeq);
|
|
24026
24283
|
const nextAfter2 = Math.max(pageMaxSeq, nextAfterSeq);
|
|
@@ -24036,6 +24293,7 @@ var V2E2EECoordinator = class {
|
|
|
24036
24293
|
}
|
|
24037
24294
|
const nextAfter = Math.max(pageMaxSeq, nextAfterSeq);
|
|
24038
24295
|
const rawCount = messages.length;
|
|
24296
|
+
if (blockedSeq > 0) break;
|
|
24039
24297
|
const shouldContinue = shouldContinueForwardPage({
|
|
24040
24298
|
rawCount,
|
|
24041
24299
|
nextAfterSeq,
|
|
@@ -24048,7 +24306,11 @@ var V2E2EECoordinator = class {
|
|
|
24048
24306
|
});
|
|
24049
24307
|
if (!shouldContinue) break;
|
|
24050
24308
|
if (pullGateKey && opts?.gateLocked && client._rpcPipeline?.yieldPullGate) {
|
|
24051
|
-
const nextKey =
|
|
24309
|
+
const nextKey = pullGateKeyForClient(client, "message.v2.pull", {
|
|
24310
|
+
after_seq: nextAfter,
|
|
24311
|
+
force: opts?.force === true,
|
|
24312
|
+
limit
|
|
24313
|
+
}, `${ns}|forward|after=${nextAfter}|force=${String(Boolean(opts?.force))}|limit=${limit}`);
|
|
24052
24314
|
await client._rpcPipeline.yieldPullGate(pullGateKey, nextKey, true);
|
|
24053
24315
|
pullGateKey = nextKey;
|
|
24054
24316
|
}
|
|
@@ -24268,7 +24530,13 @@ var V2E2EECoordinator = class {
|
|
|
24268
24530
|
const ns = `group:${gid}`;
|
|
24269
24531
|
if (opts?.windowMode === "tail") {
|
|
24270
24532
|
if (!opts.gateLocked) {
|
|
24271
|
-
const key =
|
|
24533
|
+
const key = pullGateKeyForClient(client, "group.v2.pull", {
|
|
24534
|
+
group_id: gid,
|
|
24535
|
+
window_mode: "tail",
|
|
24536
|
+
after_seq: afterSeq,
|
|
24537
|
+
limit,
|
|
24538
|
+
_group_cursor_params: opts?.cursorParams
|
|
24539
|
+
}, `${ns}|tail|after=${afterSeq}|limit=${limit}`);
|
|
24272
24540
|
return await client._runPullSerialized(key, () => this.pullGroupV2(gid, afterSeq, limit, {
|
|
24273
24541
|
...opts ?? {},
|
|
24274
24542
|
gateLocked: true
|
|
@@ -24284,7 +24552,13 @@ var V2E2EECoordinator = class {
|
|
|
24284
24552
|
return Array.isArray(result.messages) ? result.messages : [];
|
|
24285
24553
|
}
|
|
24286
24554
|
if (!opts?.gateLocked) {
|
|
24287
|
-
const key =
|
|
24555
|
+
const key = pullGateKeyForClient(client, "group.v2.pull", {
|
|
24556
|
+
group_id: gid,
|
|
24557
|
+
after_seq: afterSeq,
|
|
24558
|
+
force: opts?.force === true,
|
|
24559
|
+
limit,
|
|
24560
|
+
_group_cursor_params: opts?.cursorParams
|
|
24561
|
+
}, `${ns}|forward|after=${afterSeq}|force=${String(Boolean(opts?.force))}|limit=${limit}`);
|
|
24288
24562
|
return await client._runPullSerialized(key, () => this.pullGroupV2(gid, afterSeq, limit, {
|
|
24289
24563
|
...opts ?? {},
|
|
24290
24564
|
gateLocked: true
|
|
@@ -24294,7 +24568,13 @@ var V2E2EECoordinator = class {
|
|
|
24294
24568
|
const wireGroupId = String(opts?.wireGroupId ?? groupId ?? "").trim() || gid;
|
|
24295
24569
|
const cursorParams = opts?.cursorParams ?? {};
|
|
24296
24570
|
const ownsCursor = opts?.ownsCursor !== false;
|
|
24297
|
-
let pullGateKey = ownsCursor ?
|
|
24571
|
+
let pullGateKey = ownsCursor ? pullGateKeyForClient(client, "group.v2.pull", {
|
|
24572
|
+
group_id: gid,
|
|
24573
|
+
after_seq: afterSeq,
|
|
24574
|
+
force: opts?.force === true,
|
|
24575
|
+
limit,
|
|
24576
|
+
_group_cursor_params: cursorParams
|
|
24577
|
+
}, `${ns}|forward|after=${afterSeq}|force=${String(Boolean(opts?.force))}|limit=${limit}`) : "";
|
|
24298
24578
|
let nextAfterSeq = opts?.explicitAfterSeq || opts?.force ? afterSeq : afterSeq || client._seqTracker.getContiguousSeq(ns);
|
|
24299
24579
|
const deferredServerCursor = ownsCursor ? this.pendingForwardCursor(ns, client._seqTracker.getContiguousSeq(ns)) : 0;
|
|
24300
24580
|
const deferredForwardAck = ownsCursor ? this.pendingForwardAck(ns, client._seqTracker.getContiguousSeq(ns)) : 0;
|
|
@@ -24347,6 +24627,7 @@ var V2E2EECoordinator = class {
|
|
|
24347
24627
|
const pageTrackerSnapshot = typeof client._seqTracker.snapshotNamespace === "function" ? client._seqTracker.snapshotNamespace(ns) : null;
|
|
24348
24628
|
const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
|
|
24349
24629
|
const deferredKeyFetches = /* @__PURE__ */ new Map();
|
|
24630
|
+
let blockedSeq = 0;
|
|
24350
24631
|
for (const msg of messages) {
|
|
24351
24632
|
const seq2 = Number(msg.seq ?? 0);
|
|
24352
24633
|
if (!Number.isFinite(seq2) || seq2 <= 0) continue;
|
|
@@ -24411,6 +24692,9 @@ var V2E2EECoordinator = class {
|
|
|
24411
24692
|
}
|
|
24412
24693
|
const deferStatus = {};
|
|
24413
24694
|
let plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true);
|
|
24695
|
+
if (deferStatus.deferred) {
|
|
24696
|
+
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq2) : seq2;
|
|
24697
|
+
}
|
|
24414
24698
|
if (deferStatus.deferred && deferStatus.fromAid) {
|
|
24415
24699
|
const key = `${deferStatus.fromAid}\0${deferStatus.senderDeviceId ?? ""}\0${deferStatus.groupId ?? ""}`;
|
|
24416
24700
|
deferredKeyFetches.set(key, {
|
|
@@ -24439,7 +24723,7 @@ var V2E2EECoordinator = class {
|
|
|
24439
24723
|
Number(cursor?.join_seq ?? 0)
|
|
24440
24724
|
);
|
|
24441
24725
|
const effectiveFloor = Math.max(retentionFloor, visibilityFloor);
|
|
24442
|
-
const commitTarget = Math.max(
|
|
24726
|
+
const commitTarget = blockedSeq > 0 ? pageContigBefore : Math.max(
|
|
24443
24727
|
pageContigBefore,
|
|
24444
24728
|
Number.isFinite(effectiveFloor) ? effectiveFloor : 0,
|
|
24445
24729
|
ownsCursor && pageCount === 1 ? deferredServerCursor : 0,
|
|
@@ -24483,7 +24767,7 @@ var V2E2EECoordinator = class {
|
|
|
24483
24767
|
this.recordForwardCursor(ns, cursorCurrentSeq, ackSeq);
|
|
24484
24768
|
}
|
|
24485
24769
|
const knownServerCursorSeq = hasServerCursor ? cursorCurrentSeq : ownsCursor && pageCount === 1 ? deferredServerCursor : 0;
|
|
24486
|
-
const ackNeeded = ackSeq > 0 && ackSeq > lastAutoAckSeq && ownsCursor && (hasServerCursor && ackSeq > cursorCurrentSeq || contigAdvanced && ackSeq > knownServerCursorSeq);
|
|
24770
|
+
const ackNeeded = blockedSeq <= 0 && ackSeq > 0 && ackSeq > lastAutoAckSeq && ownsCursor && (hasServerCursor && ackSeq > cursorCurrentSeq || contigAdvanced && ackSeq > knownServerCursorSeq);
|
|
24487
24771
|
if (ackNeeded) {
|
|
24488
24772
|
this.recordForwardAck(ns, ackSeq);
|
|
24489
24773
|
const nextAfter2 = Math.max(pageMaxSeq, nextAfterSeq);
|
|
@@ -24499,6 +24783,7 @@ var V2E2EECoordinator = class {
|
|
|
24499
24783
|
const nextAfter = Math.max(pageMaxSeq, nextAfterSeq);
|
|
24500
24784
|
if (!ownsCursor) break;
|
|
24501
24785
|
const rawCount = messages.length;
|
|
24786
|
+
if (blockedSeq > 0) break;
|
|
24502
24787
|
const shouldContinue = shouldContinueForwardPage({
|
|
24503
24788
|
rawCount,
|
|
24504
24789
|
nextAfterSeq,
|
|
@@ -24511,7 +24796,13 @@ var V2E2EECoordinator = class {
|
|
|
24511
24796
|
});
|
|
24512
24797
|
if (!shouldContinue) break;
|
|
24513
24798
|
if (pullGateKey && opts?.gateLocked && client._rpcPipeline?.yieldPullGate) {
|
|
24514
|
-
const nextKey =
|
|
24799
|
+
const nextKey = pullGateKeyForClient(client, "group.v2.pull", {
|
|
24800
|
+
group_id: gid,
|
|
24801
|
+
after_seq: nextAfter,
|
|
24802
|
+
force: opts?.force === true,
|
|
24803
|
+
limit,
|
|
24804
|
+
_group_cursor_params: cursorParams
|
|
24805
|
+
}, `${ns}|forward|after=${nextAfter}|force=${String(Boolean(opts?.force))}|limit=${limit}`);
|
|
24515
24806
|
await client._rpcPipeline.yieldPullGate(pullGateKey, nextKey, true);
|
|
24516
24807
|
pullGateKey = nextKey;
|
|
24517
24808
|
}
|
|
@@ -26084,7 +26375,7 @@ var GroupStateCoordinator = class {
|
|
|
26084
26375
|
const proposalId = isJsonObject(proposeResult) ? String(proposeResult.proposal_id ?? "").trim() : "";
|
|
26085
26376
|
if (proposalId) {
|
|
26086
26377
|
try {
|
|
26087
|
-
await client.call("group.v2.confirm_state", { proposal_id: proposalId });
|
|
26378
|
+
await client.call("group.v2.confirm_state", { proposal_id: proposalId, group_id: groupId });
|
|
26088
26379
|
client._v2AutoProposeLastSnapshot.set(groupId, membershipSnapshot);
|
|
26089
26380
|
client._clientLog.debug(`V2 auto confirm_state: group=${groupId} proposal=${proposalId}`);
|
|
26090
26381
|
} catch (confirmExc) {
|
|
@@ -26137,7 +26428,7 @@ var GroupStateCoordinator = class {
|
|
|
26137
26428
|
return false;
|
|
26138
26429
|
}
|
|
26139
26430
|
if (!await this.verifyPendingProposalAgainstBase(groupId, proposal, stateResp)) return false;
|
|
26140
|
-
await client.call("group.v2.confirm_state", { proposal_id: proposalId });
|
|
26431
|
+
await client.call("group.v2.confirm_state", { proposal_id: proposalId, group_id: groupId });
|
|
26141
26432
|
client._clientLog.info(`V2 confirmed pending proposal: group=${groupId} proposal=${proposalId}`);
|
|
26142
26433
|
return true;
|
|
26143
26434
|
}
|
|
@@ -27400,6 +27691,7 @@ var AgentMdManager = class _AgentMdManager {
|
|
|
27400
27691
|
if (content !== void 0 && content !== null) {
|
|
27401
27692
|
const text3 = String(content ?? "");
|
|
27402
27693
|
if (text3.length === 0) throw new ValidationError("uploadAgentMd requires non-empty content");
|
|
27694
|
+
validateAgentMdDocument(text3, { expectedAid: target });
|
|
27403
27695
|
await this.saveRecord(target, {
|
|
27404
27696
|
content: text3,
|
|
27405
27697
|
local_etag: await _AgentMdManager.contentEtag(text3),
|
|
@@ -28877,6 +29169,7 @@ var _AUNClient = class _AUNClient {
|
|
|
28877
29169
|
this._peerCache.clear();
|
|
28878
29170
|
this._certCache.clear();
|
|
28879
29171
|
this._gatewayUrl = null;
|
|
29172
|
+
this._gatewayCandidates = [];
|
|
28880
29173
|
this._deviceId = aid.deviceId || getDeviceId();
|
|
28881
29174
|
this._slotId = aid.slotId || "default";
|
|
28882
29175
|
this._logger = new AUNLogger({ debug: aid.debug, aunPath: nextConfig.aunPath });
|
|
@@ -29056,7 +29349,7 @@ var _AUNClient = class _AUNClient {
|
|
|
29056
29349
|
if (!message.toLowerCase().startsWith(agentPrefix)) return false;
|
|
29057
29350
|
const target = message.slice(agentPrefix.length).trim();
|
|
29058
29351
|
if (!target || target.toLowerCase() !== String(this._aid ?? "").trim().toLowerCase()) return false;
|
|
29059
|
-
await this._agentMdManager.upload(buildDefaultAgentMd(target));
|
|
29352
|
+
await this._agentMdManager.upload(await this._agentMdManager.readContent(target) ?? buildDefaultAgentMd(target));
|
|
29060
29353
|
return true;
|
|
29061
29354
|
}
|
|
29062
29355
|
async _runGroupIdentityOperation(groupId, operation) {
|
|
@@ -29085,6 +29378,10 @@ var _AUNClient = class _AUNClient {
|
|
|
29085
29378
|
}
|
|
29086
29379
|
this._aidStore = store;
|
|
29087
29380
|
const payload = { ...params2 };
|
|
29381
|
+
if (payload.group_name === void 0 && payload.groupName !== void 0) {
|
|
29382
|
+
payload.group_name = payload.groupName;
|
|
29383
|
+
delete payload.groupName;
|
|
29384
|
+
}
|
|
29088
29385
|
const isNamed = Boolean(String(payload.group_name ?? "").trim());
|
|
29089
29386
|
payload._defer_group_ready_postprocess = true;
|
|
29090
29387
|
if (!isNamed) {
|
|
@@ -29112,7 +29409,24 @@ var _AUNClient = class _AUNClient {
|
|
|
29112
29409
|
delete postprocessParams2._defer_group_ready_postprocess;
|
|
29113
29410
|
return await this._groupState.postprocessResult("group.create", postprocessParams2, result2);
|
|
29114
29411
|
}
|
|
29115
|
-
const
|
|
29412
|
+
const pendingKey = `create:${String(payload.group_name).trim().toLowerCase()}`;
|
|
29413
|
+
const keystore = store._keystore;
|
|
29414
|
+
let keyPair = null;
|
|
29415
|
+
if (keystore && typeof keystore.loadPendingGroupBind === "function") {
|
|
29416
|
+
keyPair = await keystore.loadPendingGroupBind(pendingKey);
|
|
29417
|
+
}
|
|
29418
|
+
if (!keyPair || !keyPair.public_key_der_b64 || !keyPair.private_key_pem) {
|
|
29419
|
+
const generated = await new CryptoProvider().generateIdentity();
|
|
29420
|
+
keyPair = {
|
|
29421
|
+
private_key_pem: generated.private_key_pem,
|
|
29422
|
+
public_key_der_b64: generated.public_key_der_b64,
|
|
29423
|
+
curve: generated.curve
|
|
29424
|
+
};
|
|
29425
|
+
if (keystore && typeof keystore.savePendingGroupBind === "function") {
|
|
29426
|
+
await keystore.savePendingGroupBind(pendingKey, keyPair);
|
|
29427
|
+
}
|
|
29428
|
+
}
|
|
29429
|
+
if (!keyPair) throw new ValidationError("createGroup: failed to generate or load key pair");
|
|
29116
29430
|
payload.public_key = keyPair.public_key_der_b64;
|
|
29117
29431
|
payload.curve = keyPair.curve;
|
|
29118
29432
|
const result = await this.call("group.create", payload);
|
|
@@ -29138,6 +29452,9 @@ var _AUNClient = class _AUNClient {
|
|
|
29138
29452
|
throw new ValidationError("createGroup requires current owner AID for group agent.md upload");
|
|
29139
29453
|
}
|
|
29140
29454
|
await this._uploadGroupAgentMd(store, groupAid, payload, group, uploaderAid);
|
|
29455
|
+
if (keystore && typeof keystore.clearPendingGroupBind === "function") {
|
|
29456
|
+
await keystore.clearPendingGroupBind(pendingKey);
|
|
29457
|
+
}
|
|
29141
29458
|
const postprocessParams = { ...payload };
|
|
29142
29459
|
delete postprocessParams._defer_group_ready_postprocess;
|
|
29143
29460
|
return await this._groupState.postprocessResult("group.create", postprocessParams, result);
|
|
@@ -29195,10 +29512,14 @@ var _AUNClient = class _AUNClient {
|
|
|
29195
29512
|
}
|
|
29196
29513
|
this._aidStore = store;
|
|
29197
29514
|
const groupId = String(params2.group_id ?? params2.group_aid ?? "").trim();
|
|
29515
|
+
const pendingKey = `bind:${groupId}`;
|
|
29198
29516
|
const keystore = store._keystore;
|
|
29199
29517
|
let keyPair = null;
|
|
29200
29518
|
if (groupId && keystore && typeof keystore.loadPendingGroupBind === "function") {
|
|
29201
|
-
keyPair = await keystore.loadPendingGroupBind(
|
|
29519
|
+
keyPair = await keystore.loadPendingGroupBind(pendingKey);
|
|
29520
|
+
if (!keyPair || !keyPair.public_key_der_b64 || !keyPair.private_key_pem) {
|
|
29521
|
+
keyPair = await keystore.loadPendingGroupBind(groupId);
|
|
29522
|
+
}
|
|
29202
29523
|
}
|
|
29203
29524
|
if (!keyPair || !keyPair.public_key_der_b64 || !keyPair.private_key_pem) {
|
|
29204
29525
|
const generated = await new CryptoProvider().generateIdentity();
|
|
@@ -29208,7 +29529,7 @@ var _AUNClient = class _AUNClient {
|
|
|
29208
29529
|
curve: generated.curve
|
|
29209
29530
|
};
|
|
29210
29531
|
if (groupId && keystore && typeof keystore.savePendingGroupBind === "function") {
|
|
29211
|
-
await keystore.savePendingGroupBind(
|
|
29532
|
+
await keystore.savePendingGroupBind(pendingKey, keyPair);
|
|
29212
29533
|
}
|
|
29213
29534
|
}
|
|
29214
29535
|
if (!keyPair) {
|
|
@@ -29244,6 +29565,7 @@ var _AUNClient = class _AUNClient {
|
|
|
29244
29565
|
}
|
|
29245
29566
|
await this._uploadGroupAgentMd(store, groupAid, payload, group, uploaderAid);
|
|
29246
29567
|
if (groupId && keystore && typeof keystore.clearPendingGroupBind === "function") {
|
|
29568
|
+
await keystore.clearPendingGroupBind(pendingKey);
|
|
29247
29569
|
await keystore.clearPendingGroupBind(groupId);
|
|
29248
29570
|
}
|
|
29249
29571
|
return result;
|
|
@@ -29280,7 +29602,24 @@ var _AUNClient = class _AUNClient {
|
|
|
29280
29602
|
if (!oldPublicKey) {
|
|
29281
29603
|
throw new ValidationError(`renewGroupAid: cannot determine old public key for ${groupAid}`);
|
|
29282
29604
|
}
|
|
29283
|
-
const
|
|
29605
|
+
const keystore = store._keystore;
|
|
29606
|
+
const pendingKey = `renew:${groupId}`;
|
|
29607
|
+
let newKeyPair = null;
|
|
29608
|
+
if (keystore && typeof keystore.loadPendingGroupBind === "function") {
|
|
29609
|
+
newKeyPair = await keystore.loadPendingGroupBind(pendingKey);
|
|
29610
|
+
}
|
|
29611
|
+
if (!newKeyPair || !newKeyPair.public_key_der_b64 || !newKeyPair.private_key_pem) {
|
|
29612
|
+
const generated = await new CryptoProvider().generateIdentity();
|
|
29613
|
+
newKeyPair = {
|
|
29614
|
+
private_key_pem: generated.private_key_pem,
|
|
29615
|
+
public_key_der_b64: generated.public_key_der_b64,
|
|
29616
|
+
curve: generated.curve
|
|
29617
|
+
};
|
|
29618
|
+
if (keystore && typeof keystore.savePendingGroupBind === "function") {
|
|
29619
|
+
await keystore.savePendingGroupBind(pendingKey, newKeyPair);
|
|
29620
|
+
}
|
|
29621
|
+
}
|
|
29622
|
+
if (!newKeyPair) throw new ValidationError("renewGroupAid: failed to generate or load key pair");
|
|
29284
29623
|
const newPublicKey = newKeyPair.public_key_der_b64;
|
|
29285
29624
|
const newPrivateKey = newKeyPair.private_key_pem;
|
|
29286
29625
|
const curve = newKeyPair.curve || "P-256";
|
|
@@ -29336,6 +29675,9 @@ var _AUNClient = class _AUNClient {
|
|
|
29336
29675
|
throw new ValidationError("renewGroupAid requires current owner AID for group agent.md upload");
|
|
29337
29676
|
}
|
|
29338
29677
|
await this._uploadGroupAgentMd(store, returnedGroupAid, payload, group, uploaderAid);
|
|
29678
|
+
if (keystore && typeof keystore.clearPendingGroupBind === "function") {
|
|
29679
|
+
await keystore.clearPendingGroupBind(pendingKey);
|
|
29680
|
+
}
|
|
29339
29681
|
return result;
|
|
29340
29682
|
}
|
|
29341
29683
|
async startGroupTransfer(params2 = {}, options = {}) {
|
|
@@ -29393,12 +29735,12 @@ var _AUNClient = class _AUNClient {
|
|
|
29393
29735
|
if (!store) {
|
|
29394
29736
|
throw new ValidationError("completeGroupTransfer requires aidStore");
|
|
29395
29737
|
}
|
|
29396
|
-
const keyPair = await new CryptoProvider().generateIdentity();
|
|
29397
29738
|
const payload = { ...params2 };
|
|
29398
29739
|
const groupId = String(params2.group_id ?? "").trim();
|
|
29399
29740
|
if (!groupId) {
|
|
29400
29741
|
throw new ValidationError("completeGroupTransfer requires group_id");
|
|
29401
29742
|
}
|
|
29743
|
+
const pendingKey = `complete:${groupId}`;
|
|
29402
29744
|
let groupAid = String(params2.group_aid ?? "").trim();
|
|
29403
29745
|
if (!groupAid) {
|
|
29404
29746
|
const info = await this.call("group.get_info", { group_id: groupId, required: ["member"] });
|
|
@@ -29407,6 +29749,23 @@ var _AUNClient = class _AUNClient {
|
|
|
29407
29749
|
if (!groupAid) {
|
|
29408
29750
|
throw new ValidationError("completeGroupTransfer: unable to determine group_aid");
|
|
29409
29751
|
}
|
|
29752
|
+
const keystore = store._keystore;
|
|
29753
|
+
let keyPair = null;
|
|
29754
|
+
if (keystore && typeof keystore.loadPendingGroupBind === "function") {
|
|
29755
|
+
keyPair = await keystore.loadPendingGroupBind(pendingKey);
|
|
29756
|
+
}
|
|
29757
|
+
if (!keyPair || !keyPair.public_key_der_b64 || !keyPair.private_key_pem) {
|
|
29758
|
+
const generated = await new CryptoProvider().generateIdentity();
|
|
29759
|
+
keyPair = {
|
|
29760
|
+
private_key_pem: generated.private_key_pem,
|
|
29761
|
+
public_key_der_b64: generated.public_key_der_b64,
|
|
29762
|
+
curve: generated.curve
|
|
29763
|
+
};
|
|
29764
|
+
if (keystore && typeof keystore.savePendingGroupBind === "function") {
|
|
29765
|
+
await keystore.savePendingGroupBind(pendingKey, keyPair);
|
|
29766
|
+
}
|
|
29767
|
+
}
|
|
29768
|
+
if (!keyPair) throw new ValidationError("completeGroupTransfer: failed to generate or load key pair");
|
|
29410
29769
|
const current = this.currentAid;
|
|
29411
29770
|
const newOwner = String(current?.aid ?? "").trim();
|
|
29412
29771
|
if (!current || !newOwner || !current.isPrivateKeyValid()) {
|
|
@@ -29460,6 +29819,9 @@ var _AUNClient = class _AUNClient {
|
|
|
29460
29819
|
throw new ValidationError("completeGroupTransfer requires current owner AID for group agent.md upload");
|
|
29461
29820
|
}
|
|
29462
29821
|
await this._uploadGroupAgentMd(store, returnedGroupAid, payload, group, uploaderAid);
|
|
29822
|
+
if (keystore && typeof keystore.clearPendingGroupBind === "function") {
|
|
29823
|
+
await keystore.clearPendingGroupBind(pendingKey);
|
|
29824
|
+
}
|
|
29463
29825
|
return result;
|
|
29464
29826
|
}
|
|
29465
29827
|
static _notifyParamsSizeOk(params2) {
|
|
@@ -30040,16 +30402,21 @@ var _AUNClient = class _AUNClient {
|
|
|
30040
30402
|
async _resolveGatewayCandidatesForAid(aid) {
|
|
30041
30403
|
const target = String(aid ?? this._aid ?? "").trim();
|
|
30042
30404
|
if (!target) throw new StateError("gateway discovery requires a loaded AID");
|
|
30405
|
+
const discovery = this._discovery;
|
|
30406
|
+
const tokenStore = this._tokenStore;
|
|
30407
|
+
const discoveryIsCurrent = () => this._discovery === discovery && this._tokenStore === tokenStore && !this._closing;
|
|
30043
30408
|
if (this._gatewayCandidates.length > 0) return [...this._gatewayCandidates];
|
|
30044
30409
|
if (this._gatewayUrl) {
|
|
30045
30410
|
this._gatewayCandidates = [this._gatewayUrl];
|
|
30046
30411
|
return [...this._gatewayCandidates];
|
|
30047
30412
|
}
|
|
30048
30413
|
try {
|
|
30049
|
-
const getMetadata =
|
|
30050
|
-
const rawList = typeof getMetadata === "function" ? String(await getMetadata.call(
|
|
30414
|
+
const getMetadata = tokenStore.getMetadata;
|
|
30415
|
+
const rawList = typeof getMetadata === "function" ? String(await getMetadata.call(tokenStore, target, "gateway_urls") ?? "").trim() : "";
|
|
30416
|
+
if (!discoveryIsCurrent()) throw new StateError("gateway discovery superseded by identity change");
|
|
30051
30417
|
const cachedList = rawList ? JSON.parse(rawList) : [];
|
|
30052
|
-
const raw = typeof getMetadata === "function" ? String(await getMetadata.call(
|
|
30418
|
+
const raw = typeof getMetadata === "function" ? String(await getMetadata.call(tokenStore, target, "gateway_url") ?? "").trim() : "";
|
|
30419
|
+
if (!discoveryIsCurrent()) throw new StateError("gateway discovery superseded by identity change");
|
|
30053
30420
|
const candidates2 = Array.isArray(cachedList) ? cachedList.map((item) => String(item ?? "").trim()).filter(Boolean) : [];
|
|
30054
30421
|
const gateway = candidates2[0] ?? (raw.startsWith('"') && raw.endsWith('"') ? String(JSON.parse(raw)).trim() : raw);
|
|
30055
30422
|
if (gateway) {
|
|
@@ -30058,6 +30425,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30058
30425
|
return [...this._gatewayCandidates];
|
|
30059
30426
|
}
|
|
30060
30427
|
} catch {
|
|
30428
|
+
if (!discoveryIsCurrent()) throw new StateError("gateway discovery superseded by identity change");
|
|
30061
30429
|
}
|
|
30062
30430
|
const dotIdx = target.indexOf(".");
|
|
30063
30431
|
const issuerDomain = dotIdx >= 0 ? target.slice(dotIdx + 1) : target;
|
|
@@ -30069,22 +30437,26 @@ var _AUNClient = class _AUNClient {
|
|
|
30069
30437
|
let lastError = null;
|
|
30070
30438
|
for (const url of candidates) {
|
|
30071
30439
|
try {
|
|
30072
|
-
const discovered = await
|
|
30440
|
+
const discovered = await discovery.discoverAll(url);
|
|
30441
|
+
if (!discoveryIsCurrent()) throw new StateError("gateway discovery superseded by identity change");
|
|
30073
30442
|
const gatewayUrls = [...new Set(discovered.map((item) => String(item ?? "").trim()).filter(Boolean))];
|
|
30074
30443
|
if (gatewayUrls.length === 0) throw new ValidationError("gateway discovery returned no candidates");
|
|
30075
30444
|
const gateway = gatewayUrls[0];
|
|
30076
30445
|
this._gatewayCandidates = gatewayUrls;
|
|
30077
30446
|
this._gatewayUrl = gateway;
|
|
30078
30447
|
try {
|
|
30079
|
-
const setMetadata =
|
|
30448
|
+
const setMetadata = tokenStore.setMetadata;
|
|
30080
30449
|
if (typeof setMetadata === "function") {
|
|
30081
|
-
await setMetadata.call(
|
|
30082
|
-
|
|
30450
|
+
await setMetadata.call(tokenStore, target, "gateway_url", gateway);
|
|
30451
|
+
if (!discoveryIsCurrent()) throw new StateError("gateway discovery superseded by identity change");
|
|
30452
|
+
await setMetadata.call(tokenStore, target, "gateway_urls", JSON.stringify(gatewayUrls));
|
|
30453
|
+
if (!discoveryIsCurrent()) throw new StateError("gateway discovery superseded by identity change");
|
|
30083
30454
|
}
|
|
30084
30455
|
} catch {
|
|
30085
30456
|
}
|
|
30086
30457
|
return [...gatewayUrls];
|
|
30087
30458
|
} catch (err) {
|
|
30459
|
+
if (!discoveryIsCurrent()) throw new StateError("gateway discovery superseded by identity change");
|
|
30088
30460
|
lastError = err;
|
|
30089
30461
|
}
|
|
30090
30462
|
}
|
|
@@ -32600,8 +32972,7 @@ var AIDStore = class {
|
|
|
32600
32972
|
});
|
|
32601
32973
|
}
|
|
32602
32974
|
await this._persistGatewayUrl(target, gatewayUrl);
|
|
32603
|
-
|
|
32604
|
-
if (!uploaded.ok) return uploaded;
|
|
32975
|
+
await this.uploadAgentMd(target, buildDefaultAgentMd(target));
|
|
32605
32976
|
return resultOk({ registered: true });
|
|
32606
32977
|
} catch (exc) {
|
|
32607
32978
|
if (exc instanceof IdentityConflictError) {
|