@agentunion/fastaun 0.5.9 → 0.5.11
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 +64 -0
- package/_packed_docs/CHANGELOG.md +64 -0
- package/_packed_docs/INDEX.md +3 -3
- package/_packed_docs/KITE_DOCS_GUIDE.md +1 -1
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +6 -5
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +102 -8
- package/_packed_docs/sdk/09-group-rpc-manual.md +18 -3
- package/_packed_docs/sdk/09-message-rpc-manual.md +34 -10
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +3 -2
- package/_packed_docs/sdk/INDEX.md +2 -1
- package/dist/agent-md.js +5 -1
- package/dist/agent-md.js.map +1 -1
- package/dist/auth.d.ts +2 -1
- package/dist/auth.js +30 -44
- package/dist/auth.js.map +1 -1
- package/dist/client/delivery.d.ts +39 -9
- package/dist/client/delivery.js +407 -73
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +6 -6
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.js +5 -14
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +4 -0
- package/dist/client/rpc-pipeline.js +51 -5
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +3 -0
- package/dist/client/v2-e2ee.js +236 -59
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.js +84 -30
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +23 -8
- package/dist/events.js +120 -26
- package/dist/events.js.map +1 -1
- package/dist/register-flow.js +15 -111
- package/dist/register-flow.js.map +1 -1
- package/dist/transport.d.ts +36 -3
- package/dist/transport.js +855 -33
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/client/delivery.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { slotIsolationKey } from '../config.js';
|
|
2
2
|
import { ConnectionState, isJsonObject } from '../types.js';
|
|
3
|
+
import { validateGroupAIDFormat } from '../validators.js';
|
|
3
4
|
import { hasGroupMentionModeField, normalizeGroupMentionMode } from './mention-mode.js';
|
|
4
5
|
const PUSHED_SEQS_LIMIT = 50_000;
|
|
5
6
|
const PENDING_ORDERED_LIMIT = 50_000;
|
|
6
7
|
const MESSAGE_RECALL_SEEN_LIMIT = 10_000;
|
|
7
8
|
const GROUP_RECALL_SEEN_LIMIT = 10_000;
|
|
8
9
|
const SEQ_TRACKER_PERSIST_FLUSH_DELAY_MS = 200;
|
|
10
|
+
const DELIVERY_CHANGED_MESSAGE_EVENTS = new Set([
|
|
11
|
+
'message.received',
|
|
12
|
+
'group.message_created',
|
|
13
|
+
]);
|
|
9
14
|
const MAX_INLINE_PENDING_ACK_NAMESPACES = 4096;
|
|
10
15
|
const APP_MESSAGE_ENVELOPE_KEYS = [
|
|
11
16
|
'module_id', 'message_type', 'type', 'kind', 'version',
|
|
@@ -73,6 +78,10 @@ export class MessageDeliveryEngine {
|
|
|
73
78
|
pendingGroupInlineAcks = null;
|
|
74
79
|
pendingGroupInlineAckNamespaces = null;
|
|
75
80
|
inlineAckGeneration = 0;
|
|
81
|
+
pendingDeliveryChanges = null;
|
|
82
|
+
deliveryChangedGeneration = 0;
|
|
83
|
+
syncRun = 0;
|
|
84
|
+
syncSessions = null;
|
|
76
85
|
// 同一实例的 tracker 写入必须串行,避免旧的延迟 flush 覆盖新的 Forward 提交。
|
|
77
86
|
seqTrackerWriteChain = Promise.resolve();
|
|
78
87
|
constructor(runtime) {
|
|
@@ -145,6 +154,7 @@ export class MessageDeliveryEngine {
|
|
|
145
154
|
}
|
|
146
155
|
const client = this.runtime.client;
|
|
147
156
|
this.ensurePullOperationCurrent();
|
|
157
|
+
this.syncStarted(ns);
|
|
148
158
|
const response = result;
|
|
149
159
|
const messages = deduplicatePlainForwardPageMessages(response.messages, afterSeq);
|
|
150
160
|
const coordinator = this.forwardCoordinator();
|
|
@@ -187,7 +197,7 @@ export class MessageDeliveryEngine {
|
|
|
187
197
|
}
|
|
188
198
|
const message = normalizeGroupMentionMode(rawMessage);
|
|
189
199
|
if (this.recallEventFromGroupMessage(message)) {
|
|
190
|
-
if (await this.publishGroupRecallTombstone(groupId, seq, message)) {
|
|
200
|
+
if (await this.publishGroupRecallTombstone(groupId, seq, message, 'pull')) {
|
|
191
201
|
this.ensurePullOperationCurrent();
|
|
192
202
|
this.markPublishedSeq(ns, seq);
|
|
193
203
|
publishedCount += 1;
|
|
@@ -207,7 +217,7 @@ export class MessageDeliveryEngine {
|
|
|
207
217
|
}
|
|
208
218
|
if (client._seqTracker.getContiguousSeq(ns) !== pageContigBefore) {
|
|
209
219
|
this.ensurePullOperationCurrent();
|
|
210
|
-
await this.drainOrderedMessages(ns, undefined, false, false);
|
|
220
|
+
await this.drainOrderedMessages(ns, undefined, false, false, 'pull');
|
|
211
221
|
this.ensurePullOperationCurrent();
|
|
212
222
|
await client._commitSeqTrackerState(ns);
|
|
213
223
|
}
|
|
@@ -254,9 +264,19 @@ export class MessageDeliveryEngine {
|
|
|
254
264
|
this.ensurePullOperationCurrent();
|
|
255
265
|
await this.confirmPlainForwardAck(ns, ackMethod, pendingAckSeq, groupId);
|
|
256
266
|
}
|
|
267
|
+
this.syncProgress(ns, {
|
|
268
|
+
rawCount: messages.length,
|
|
269
|
+
pulledCount: publishedCount,
|
|
270
|
+
remaining: response.remaining,
|
|
271
|
+
hasMore: typeof response.has_more === 'boolean' ? response.has_more : undefined,
|
|
272
|
+
currentSeq: client._seqTracker.getContiguousSeq(ns),
|
|
273
|
+
});
|
|
257
274
|
return { rawCount: messages.length, publishedCount };
|
|
258
275
|
}
|
|
259
276
|
resetInlineAckState() {
|
|
277
|
+
this.syncStopped('aborted');
|
|
278
|
+
this.deliveryChangedGeneration += 1;
|
|
279
|
+
this.pendingDeliveryChanges = null;
|
|
260
280
|
this.inlineAckGeneration += 1;
|
|
261
281
|
void this.runtime.client._rpcPipeline?.invalidatePulls?.();
|
|
262
282
|
this.pendingP2PInlineAcks = null;
|
|
@@ -267,6 +287,225 @@ export class MessageDeliveryEngine {
|
|
|
267
287
|
this.onlineUnreadHintTargets = null;
|
|
268
288
|
this.onlineUnreadHintTasks = null;
|
|
269
289
|
this.realtimeTailHeads = null;
|
|
290
|
+
this.syncSessions = null;
|
|
291
|
+
}
|
|
292
|
+
deliveryChangedNamespace(event, payload) {
|
|
293
|
+
if (event === 'group.message_created' && isJsonObject(payload)) {
|
|
294
|
+
const aid = String(this.runtime.client._aid ?? '').trim();
|
|
295
|
+
const dot = aid.indexOf('.');
|
|
296
|
+
try {
|
|
297
|
+
const groupAid = validateGroupAIDFormat(payload.group_aid ?? payload.group_id, { localIssuer: dot >= 0 ? aid.slice(dot + 1) : '' });
|
|
298
|
+
return groupAid.includes('.') ? `group:${groupAid}` : '';
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
return '';
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return 'p2p';
|
|
305
|
+
}
|
|
306
|
+
isDeliveryChangedMessage(event, payload) {
|
|
307
|
+
if (!DELIVERY_CHANGED_MESSAGE_EVENTS.has(event)
|
|
308
|
+
|| !isJsonObject(payload))
|
|
309
|
+
return false;
|
|
310
|
+
const messageId = payload.message_id;
|
|
311
|
+
const seq = payload.seq;
|
|
312
|
+
return (typeof messageId === 'string' && messageId.trim().length > 0)
|
|
313
|
+
|| (typeof seq === 'number' && Number.isSafeInteger(seq) && seq > 0);
|
|
314
|
+
}
|
|
315
|
+
deliveryChangedTrigger(source) {
|
|
316
|
+
if (source === 'inline-push' || source === 'inline_push')
|
|
317
|
+
return 'inline_push';
|
|
318
|
+
if (source === 'pull' || source === 'tail' || source === 'pending-retry' || source === 'pending_retry')
|
|
319
|
+
return 'pull_drained';
|
|
320
|
+
if (source === 'push' || source === 'group-push' || source === 'ordered')
|
|
321
|
+
return 'push';
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
noteDeliveryChanged(event, payload, source, context) {
|
|
325
|
+
if (!this.isDeliveryChangedMessage(event, payload))
|
|
326
|
+
return;
|
|
327
|
+
const trigger = this.deliveryChangedTrigger(source);
|
|
328
|
+
const namespace = this.deliveryChangedNamespace(event, payload);
|
|
329
|
+
if (!trigger || !namespace)
|
|
330
|
+
return;
|
|
331
|
+
const pending = trigger === 'pull_drained'
|
|
332
|
+
? this.pendingDeliveryChanges ?? new Map()
|
|
333
|
+
: context?.changes ?? this.pendingDeliveryChanges ?? new Map();
|
|
334
|
+
if (trigger === 'pull_drained' || !context)
|
|
335
|
+
this.pendingDeliveryChanges = pending;
|
|
336
|
+
pending.set(namespace, (pending.get(namespace) ?? 0) + 1);
|
|
337
|
+
if (!context && trigger !== 'pull_drained')
|
|
338
|
+
this.flushDeliveryChanged(trigger);
|
|
339
|
+
}
|
|
340
|
+
flushDeliveryChanged(trigger) {
|
|
341
|
+
const pending = this.pendingDeliveryChanges;
|
|
342
|
+
if (!pending || pending.size === 0)
|
|
343
|
+
return;
|
|
344
|
+
const changes = [...pending.entries()]
|
|
345
|
+
.filter(([, deliveredCount]) => deliveredCount > 0)
|
|
346
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
347
|
+
.map(([namespace, deliveredCount]) => ({ namespace, delivered_count: deliveredCount }));
|
|
348
|
+
pending.clear();
|
|
349
|
+
if (changes.length === 0)
|
|
350
|
+
return;
|
|
351
|
+
const payload = { source: trigger === 'pull_drained' ? 'pull' : trigger, trigger, changes };
|
|
352
|
+
const dispatcher = this.runtime.client._dispatcher;
|
|
353
|
+
const published = typeof dispatcher.enqueue === 'function'
|
|
354
|
+
? (dispatcher.enqueue('delivery.changed', payload), undefined)
|
|
355
|
+
: typeof dispatcher.publishSyncAware === 'function'
|
|
356
|
+
? dispatcher.publishSyncAware('delivery.changed', payload)
|
|
357
|
+
: dispatcher.publish?.('delivery.changed', payload);
|
|
358
|
+
if (isPromiseLike(published))
|
|
359
|
+
void Promise.resolve(published).catch((exc) => {
|
|
360
|
+
this.runtime.client._clientLog.warn(`delivery.changed handler failed: ${formatDeliveryError(exc)}`);
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
publishSyncLifecycle(event, payload) {
|
|
364
|
+
const dispatcher = this.runtime.client._dispatcher;
|
|
365
|
+
const published = typeof dispatcher.enqueue === 'function'
|
|
366
|
+
? (dispatcher.enqueue(event, payload), undefined)
|
|
367
|
+
: typeof dispatcher.publishSyncAware === 'function'
|
|
368
|
+
? dispatcher.publishSyncAware(event, payload)
|
|
369
|
+
: dispatcher.publish?.(event, payload);
|
|
370
|
+
if (isPromiseLike(published))
|
|
371
|
+
void Promise.resolve(published).catch((exc) => {
|
|
372
|
+
this.runtime.client._clientLog.warn(`${event} handler failed: ${formatDeliveryError(exc)}`);
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
syncStarted(ns) {
|
|
376
|
+
const namespace = String(ns ?? '').trim();
|
|
377
|
+
if (!namespace)
|
|
378
|
+
return;
|
|
379
|
+
const sessions = this.syncSessions ?? new Map();
|
|
380
|
+
this.syncSessions = sessions;
|
|
381
|
+
if (sessions.has(namespace))
|
|
382
|
+
return;
|
|
383
|
+
if (sessions.size === 0) {
|
|
384
|
+
this.syncRun += 1;
|
|
385
|
+
this.publishSyncLifecycle('sync.started', {
|
|
386
|
+
run_id: this.syncRun,
|
|
387
|
+
source: 'pull',
|
|
388
|
+
syncing: true,
|
|
389
|
+
namespaces_pending: 1,
|
|
390
|
+
received_total: 0,
|
|
391
|
+
namespace,
|
|
392
|
+
started_at: Date.now(),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
const session = { pages: 0, pulled: 0, startedAt: Date.now() };
|
|
396
|
+
sessions.set(namespace, session);
|
|
397
|
+
}
|
|
398
|
+
syncProgress(ns, progress = {}) {
|
|
399
|
+
const namespace = String(ns ?? '').trim();
|
|
400
|
+
if (!namespace)
|
|
401
|
+
return;
|
|
402
|
+
this.syncStarted(namespace);
|
|
403
|
+
const session = this.syncSessions?.get(namespace);
|
|
404
|
+
if (!session)
|
|
405
|
+
return;
|
|
406
|
+
const pulledCount = Math.max(0, Number(progress.pulledCount ?? progress.rawCount ?? 0) || 0);
|
|
407
|
+
const rawCount = Math.max(0, Number(progress.rawCount ?? pulledCount) || 0);
|
|
408
|
+
session.pages += 1;
|
|
409
|
+
session.pulled += pulledCount;
|
|
410
|
+
const payload = {
|
|
411
|
+
run_id: this.syncRun,
|
|
412
|
+
source: 'pull',
|
|
413
|
+
namespace,
|
|
414
|
+
page: session.pages,
|
|
415
|
+
page_pulled_count: pulledCount,
|
|
416
|
+
page_raw_count: rawCount,
|
|
417
|
+
pulled_count: session.pulled,
|
|
418
|
+
received_total: session.pulled,
|
|
419
|
+
batch_size: pulledCount,
|
|
420
|
+
};
|
|
421
|
+
if (typeof progress.remaining === 'number'
|
|
422
|
+
&& Number.isSafeInteger(progress.remaining) && progress.remaining >= 0) {
|
|
423
|
+
payload.remaining = progress.remaining;
|
|
424
|
+
payload.estimated_remaining = payload.remaining;
|
|
425
|
+
}
|
|
426
|
+
if (progress.hasMore !== undefined) {
|
|
427
|
+
payload.has_more = Boolean(progress.hasMore);
|
|
428
|
+
if (progress.remaining === undefined || progress.remaining === null) {
|
|
429
|
+
payload.estimated_remaining = progress.hasMore ? undefined : 0;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (progress.currentSeq !== undefined && Number.isFinite(Number(progress.currentSeq))) {
|
|
433
|
+
payload.current_seq = Math.max(0, Number(progress.currentSeq));
|
|
434
|
+
}
|
|
435
|
+
if (progress.targetSeq !== undefined && Number.isFinite(Number(progress.targetSeq))) {
|
|
436
|
+
payload.target_seq = Math.max(0, Number(progress.targetSeq));
|
|
437
|
+
}
|
|
438
|
+
this.publishSyncLifecycle('sync.progress', payload);
|
|
439
|
+
}
|
|
440
|
+
onPullDrained() {
|
|
441
|
+
this.flushDeliveryChanged('pull_drained');
|
|
442
|
+
this.syncStopped('pull_drained');
|
|
443
|
+
}
|
|
444
|
+
onPullAborted() {
|
|
445
|
+
this.syncStopped('aborted');
|
|
446
|
+
}
|
|
447
|
+
syncStopped(reason = 'completed') {
|
|
448
|
+
const sessions = this.syncSessions;
|
|
449
|
+
if (!sessions || sessions.size === 0)
|
|
450
|
+
return;
|
|
451
|
+
const entries = [...sessions.entries()];
|
|
452
|
+
const receivedTotal = entries.reduce((total, [, session]) => total + session.pulled, 0);
|
|
453
|
+
const payload = {
|
|
454
|
+
run_id: this.syncRun,
|
|
455
|
+
source: 'pull',
|
|
456
|
+
syncing: false,
|
|
457
|
+
namespaces_pending: 0,
|
|
458
|
+
received_total: receivedTotal,
|
|
459
|
+
reason,
|
|
460
|
+
stopped_at: Date.now(),
|
|
461
|
+
};
|
|
462
|
+
if (entries.length === 1) {
|
|
463
|
+
const [namespace, session] = entries[0];
|
|
464
|
+
payload.namespace = namespace;
|
|
465
|
+
payload.pages = session.pages;
|
|
466
|
+
payload.pulled_count = session.pulled;
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
payload.namespaces = entries.map(([namespace]) => namespace);
|
|
470
|
+
payload.pages = entries.reduce((total, [, session]) => total + session.pages, 0);
|
|
471
|
+
payload.pulled_count = receivedTotal;
|
|
472
|
+
}
|
|
473
|
+
sessions.clear();
|
|
474
|
+
this.syncSessions = null;
|
|
475
|
+
this.publishSyncLifecycle('sync.stopped', payload);
|
|
476
|
+
}
|
|
477
|
+
flushDeliveryChangedContext(context, trigger) {
|
|
478
|
+
if (context.generation !== this.deliveryChangedGeneration || context.changes.size === 0)
|
|
479
|
+
return;
|
|
480
|
+
const pending = this.pendingDeliveryChanges;
|
|
481
|
+
if (pending) {
|
|
482
|
+
for (const [namespace, count] of pending) {
|
|
483
|
+
context.changes.set(namespace, (context.changes.get(namespace) ?? 0) + count);
|
|
484
|
+
}
|
|
485
|
+
pending.clear();
|
|
486
|
+
}
|
|
487
|
+
const changes = [...context.changes.entries()]
|
|
488
|
+
.filter(([, count]) => count > 0)
|
|
489
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
490
|
+
.map(([namespace, delivered_count]) => ({ namespace, delivered_count }));
|
|
491
|
+
context.changes.clear();
|
|
492
|
+
if (changes.length === 0)
|
|
493
|
+
return;
|
|
494
|
+
const dispatcher = this.runtime.client._dispatcher;
|
|
495
|
+
const payload = { trigger, source: trigger, changes };
|
|
496
|
+
const published = typeof dispatcher.enqueue === 'function'
|
|
497
|
+
? (dispatcher.enqueue('delivery.changed', payload), undefined)
|
|
498
|
+
: typeof dispatcher.publishSyncAware === 'function'
|
|
499
|
+
? dispatcher.publishSyncAware('delivery.changed', payload)
|
|
500
|
+
: dispatcher.publish?.('delivery.changed', payload);
|
|
501
|
+
if (isPromiseLike(published))
|
|
502
|
+
void Promise.resolve(published).catch((exc) => {
|
|
503
|
+
this.runtime.client._clientLog.warn(`delivery.changed handler failed: ${formatDeliveryError(exc)}`);
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
invalidateDeliveryChanges() {
|
|
507
|
+
this.deliveryChangedGeneration += 1;
|
|
508
|
+
this.pendingDeliveryChanges = null;
|
|
270
509
|
}
|
|
271
510
|
inlineGenerationIsCurrent(generation) {
|
|
272
511
|
return this.inlineAckGeneration === generation;
|
|
@@ -310,10 +549,17 @@ export class MessageDeliveryEngine {
|
|
|
310
549
|
}
|
|
311
550
|
endRealtimeSync(ns) {
|
|
312
551
|
this.realtimeSyncing?.delete(ns);
|
|
552
|
+
this.runtime.client._rpcPipeline?.requestPullDrainedCheck?.();
|
|
313
553
|
}
|
|
314
554
|
hasPendingPull(ns) {
|
|
315
555
|
return (this.pendingGroupPullUpper?.get(ns) ?? 0) > 0;
|
|
316
556
|
}
|
|
557
|
+
hasAnyPendingPull() {
|
|
558
|
+
return [...(this.pendingGroupPullUpper?.values() ?? [])].some((seq) => seq > 0)
|
|
559
|
+
|| Boolean(this.onlineUnreadHintTasks?.size)
|
|
560
|
+
|| Boolean(this.realtimeSyncing?.size)
|
|
561
|
+
|| Boolean(this.runtime.client._v2E2EE?.hasPendingSenderIKWork?.());
|
|
562
|
+
}
|
|
317
563
|
onPullGateIdle(ns) {
|
|
318
564
|
if (!ns)
|
|
319
565
|
return;
|
|
@@ -378,14 +624,14 @@ export class MessageDeliveryEngine {
|
|
|
378
624
|
client._pushedSeqs.set(ns, new Set(keep));
|
|
379
625
|
}
|
|
380
626
|
}
|
|
381
|
-
enqueueOrderedMessage(ns, event, seq, payload) {
|
|
627
|
+
enqueueOrderedMessage(ns, event, seq, payload, source = 'push') {
|
|
382
628
|
const client = this.runtime.client;
|
|
383
629
|
let queue = client._pendingOrderedMsgs.get(ns);
|
|
384
630
|
if (!queue) {
|
|
385
631
|
queue = new Map();
|
|
386
632
|
client._pendingOrderedMsgs.set(ns, queue);
|
|
387
633
|
}
|
|
388
|
-
queue.set(seq, { event, payload });
|
|
634
|
+
queue.set(seq, { event, payload, source });
|
|
389
635
|
if (queue.size > PENDING_ORDERED_LIMIT) {
|
|
390
636
|
const drop = [...queue.keys()].sort((a, b) => a - b).slice(0, queue.size - PENDING_ORDERED_LIMIT);
|
|
391
637
|
for (const oldSeq of drop)
|
|
@@ -395,7 +641,7 @@ export class MessageDeliveryEngine {
|
|
|
395
641
|
isGroupEventNamespace(ns) {
|
|
396
642
|
return ns.startsWith('group_event:');
|
|
397
643
|
}
|
|
398
|
-
async publishOrderedQueueItem(ns, event, seq, payload, source, pullResponse = false) {
|
|
644
|
+
async publishOrderedQueueItem(ns, event, seq, payload, source, pullResponse = false, deliveryContext) {
|
|
399
645
|
const client = this.runtime.client;
|
|
400
646
|
this.ensurePullOperationCurrent();
|
|
401
647
|
if (event === 'group.changed' && this.isGroupEventNamespace(ns)) {
|
|
@@ -404,17 +650,17 @@ export class MessageDeliveryEngine {
|
|
|
404
650
|
return;
|
|
405
651
|
}
|
|
406
652
|
if (event === 'message.recalled') {
|
|
407
|
-
await this.publishMessageRecallTombstone(seq, payload);
|
|
653
|
+
await this.publishMessageRecallTombstone(seq, payload, source);
|
|
408
654
|
this.ensurePullOperationCurrent();
|
|
409
655
|
return;
|
|
410
656
|
}
|
|
411
657
|
if (pullResponse) {
|
|
412
|
-
const published = client._withPullResponseProcessing(ns, () =>
|
|
658
|
+
const published = client._withPullResponseProcessing(ns, () => this.publishAppEvent(event, payload, source, deliveryContext));
|
|
413
659
|
if (isPromiseLike(published))
|
|
414
660
|
await published;
|
|
415
661
|
}
|
|
416
662
|
else {
|
|
417
|
-
const published =
|
|
663
|
+
const published = this.publishAppEvent(event, payload, source, deliveryContext);
|
|
418
664
|
if (isPromiseLike(published))
|
|
419
665
|
await published;
|
|
420
666
|
}
|
|
@@ -457,17 +703,27 @@ export class MessageDeliveryEngine {
|
|
|
457
703
|
}
|
|
458
704
|
return result;
|
|
459
705
|
}
|
|
460
|
-
normalizePublishedMessagePayload(event, payload) {
|
|
706
|
+
normalizePublishedMessagePayload(event, payload, source = 'direct') {
|
|
461
707
|
payload = this.stripInlineInternalFields(payload);
|
|
708
|
+
let normalized;
|
|
462
709
|
if (this.isInstanceScopedMessageEvent(event)) {
|
|
463
710
|
if (event === 'group.message_created')
|
|
464
711
|
payload = normalizeGroupMentionMode(payload);
|
|
465
|
-
|
|
712
|
+
normalized = this.attachAppMessageEnvelope(this.stripInternalSenderDeviceFields(this.attachCurrentInstanceContext(payload)));
|
|
466
713
|
}
|
|
467
|
-
if (this.isGroupScopedEvent(event)) {
|
|
468
|
-
|
|
714
|
+
else if (this.isGroupScopedEvent(event)) {
|
|
715
|
+
normalized = this.attachAppGroupEventEnvelope(this.attachCurrentInstanceContext(payload));
|
|
469
716
|
}
|
|
470
|
-
|
|
717
|
+
else {
|
|
718
|
+
normalized = payload;
|
|
719
|
+
}
|
|
720
|
+
if (source === 'direct' || !isJsonObject(normalized))
|
|
721
|
+
return normalized;
|
|
722
|
+
const canonicalSource = source === 'group-push' || source === 'ordered' || source === 'legacy' || source === 'tail'
|
|
723
|
+
? (source === 'tail' ? 'pull' : 'push')
|
|
724
|
+
: source === 'inline-push' || source === 'inline_push' ? 'inline_push'
|
|
725
|
+
: source === 'pending-retry' || source === 'pending_retry' ? 'pending_retry' : source;
|
|
726
|
+
return { ...normalized, source: canonicalSource };
|
|
471
727
|
}
|
|
472
728
|
stripInlineInternalFields(payload) {
|
|
473
729
|
if (!isJsonObject(payload))
|
|
@@ -737,7 +993,7 @@ export class MessageDeliveryEngine {
|
|
|
737
993
|
return `p2p|tombstone:${tombstoneId}`;
|
|
738
994
|
return `p2p|unknown:${Date.now()}:${Math.random()}`;
|
|
739
995
|
}
|
|
740
|
-
async publishMessageRecallTombstone(seq, message) {
|
|
996
|
+
async publishMessageRecallTombstone(seq, message, source = 'push') {
|
|
741
997
|
const client = this.runtime.client;
|
|
742
998
|
const eventPayload = this.recallEventFromMessage(message);
|
|
743
999
|
if (!eventPayload)
|
|
@@ -758,7 +1014,7 @@ export class MessageDeliveryEngine {
|
|
|
758
1014
|
for (const [oldKey] of drop)
|
|
759
1015
|
seen.delete(oldKey);
|
|
760
1016
|
}
|
|
761
|
-
await client._publishAppEvent('message.recalled', eventPayload,
|
|
1017
|
+
await client._publishAppEvent('message.recalled', eventPayload, source);
|
|
762
1018
|
client._clientLog.debug(`message.recalled published: seq=${String(seq)} ids=${JSON.stringify(eventPayload.message_ids)}`);
|
|
763
1019
|
return true;
|
|
764
1020
|
}
|
|
@@ -841,7 +1097,7 @@ export class MessageDeliveryEngine {
|
|
|
841
1097
|
return `${normalizedGroupId}|tombstone:${tombstoneId}`;
|
|
842
1098
|
return `${normalizedGroupId}|unknown:${Date.now()}:${Math.random()}`;
|
|
843
1099
|
}
|
|
844
|
-
async publishGroupRecallTombstone(groupId, seq, message) {
|
|
1100
|
+
async publishGroupRecallTombstone(groupId, seq, message, source = 'push') {
|
|
845
1101
|
const client = this.runtime.client;
|
|
846
1102
|
const eventPayload = this.recallEventFromGroupMessage(message);
|
|
847
1103
|
if (!eventPayload)
|
|
@@ -864,7 +1120,7 @@ export class MessageDeliveryEngine {
|
|
|
864
1120
|
for (const [oldKey] of drop)
|
|
865
1121
|
seen.delete(oldKey);
|
|
866
1122
|
}
|
|
867
|
-
await client._publishAppEvent('group.message_recalled', eventPayload,
|
|
1123
|
+
await client._publishAppEvent('group.message_recalled', eventPayload, source);
|
|
868
1124
|
client._clientLog.debug(`group.message_recalled published: group=${groupId} seq=${String(seq)} ids=${JSON.stringify(eventPayload.message_ids)}`);
|
|
869
1125
|
return true;
|
|
870
1126
|
}
|
|
@@ -934,7 +1190,7 @@ export class MessageDeliveryEngine {
|
|
|
934
1190
|
if (contig !== contigBefore)
|
|
935
1191
|
this.persistSeq(ns);
|
|
936
1192
|
}
|
|
937
|
-
publishAppEvent(event, payload, source = 'direct') {
|
|
1193
|
+
publishAppEvent(event, payload, source = 'direct', deliveryContext) {
|
|
938
1194
|
const client = this.runtime.client;
|
|
939
1195
|
if ((event === 'message.received' || event === 'group.message_created') && isJsonObject(payload)) {
|
|
940
1196
|
client._maybeAppendEchoTraceReceive(payload);
|
|
@@ -954,7 +1210,23 @@ export class MessageDeliveryEngine {
|
|
|
954
1210
|
client._clientLog.debug(`agent_md etag inject skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
955
1211
|
}
|
|
956
1212
|
}
|
|
957
|
-
|
|
1213
|
+
const generation = this.deliveryChangedGeneration;
|
|
1214
|
+
const normalized = this.normalizePublishedMessagePayload(event, payload, source);
|
|
1215
|
+
const dispatcher = client._dispatcher;
|
|
1216
|
+
const result = typeof dispatcher.enqueue === 'function'
|
|
1217
|
+
? (dispatcher.enqueue(event, normalized), undefined)
|
|
1218
|
+
: typeof dispatcher.publishSyncAware === 'function'
|
|
1219
|
+
? dispatcher.publishSyncAware(event, normalized)
|
|
1220
|
+
: dispatcher.publish?.(event, normalized);
|
|
1221
|
+
const note = () => {
|
|
1222
|
+
if (generation === this.deliveryChangedGeneration) {
|
|
1223
|
+
this.noteDeliveryChanged(event, payload, source, deliveryContext);
|
|
1224
|
+
}
|
|
1225
|
+
};
|
|
1226
|
+
if (isPromiseLike(result))
|
|
1227
|
+
return Promise.resolve(result).then(note);
|
|
1228
|
+
note();
|
|
1229
|
+
return result;
|
|
958
1230
|
}
|
|
959
1231
|
messagePayloadForDebug(message) {
|
|
960
1232
|
if (!isJsonObject(message))
|
|
@@ -1140,7 +1412,7 @@ export class MessageDeliveryEngine {
|
|
|
1140
1412
|
_decrypt_error: String(exc),
|
|
1141
1413
|
};
|
|
1142
1414
|
client._attachV2EnvelopeMetadataFromSource(safeEvent, data);
|
|
1143
|
-
Promise.resolve(client._publishAppEvent('message.undecryptable', safeEvent)).catch(() => { });
|
|
1415
|
+
Promise.resolve(client._publishAppEvent('message.undecryptable', safeEvent, 'push')).catch(() => { });
|
|
1144
1416
|
}
|
|
1145
1417
|
});
|
|
1146
1418
|
client._clientLog.debug(`_onRawMessageReceived exit: elapsed=${Date.now() - tStart}ms (handler dispatched)`);
|
|
@@ -1272,7 +1544,7 @@ export class MessageDeliveryEngine {
|
|
|
1272
1544
|
_decrypt_error: String(exc),
|
|
1273
1545
|
};
|
|
1274
1546
|
client._attachV2EnvelopeMetadataFromSource(safeEvent, data);
|
|
1275
|
-
Promise.resolve(client._publishAppEvent('group.message_undecryptable', safeEvent)).catch(() => { });
|
|
1547
|
+
Promise.resolve(client._publishAppEvent('group.message_undecryptable', safeEvent, 'push')).catch(() => { });
|
|
1276
1548
|
}
|
|
1277
1549
|
});
|
|
1278
1550
|
client._clientLog.debug(`_onRawGroupMessageCreated exit: elapsed=${Date.now() - tStart}ms (handler dispatched)`);
|
|
@@ -1368,7 +1640,7 @@ export class MessageDeliveryEngine {
|
|
|
1368
1640
|
const client = this.runtime.client;
|
|
1369
1641
|
let groupId = String(notification.group_id ?? '').trim();
|
|
1370
1642
|
if (!groupId) {
|
|
1371
|
-
await client._publishAppEvent('group.message_created', notification);
|
|
1643
|
+
await client._publishAppEvent('group.message_created', notification, 'push');
|
|
1372
1644
|
return;
|
|
1373
1645
|
}
|
|
1374
1646
|
if (client._sessionOptions?.background_sync === false) {
|
|
@@ -1518,8 +1790,10 @@ export class MessageDeliveryEngine {
|
|
|
1518
1790
|
}
|
|
1519
1791
|
}
|
|
1520
1792
|
client._gapFillDone.set(dedupKey, Date.now());
|
|
1793
|
+
this.syncStarted(ns);
|
|
1521
1794
|
let filled = 0;
|
|
1522
1795
|
let continuationAfterSeq = 0;
|
|
1796
|
+
let failed = false;
|
|
1523
1797
|
try {
|
|
1524
1798
|
let nextAfterSeq = afterSeq;
|
|
1525
1799
|
const maxPages = singlePage ? 1 : 100;
|
|
@@ -1571,6 +1845,7 @@ export class MessageDeliveryEngine {
|
|
|
1571
1845
|
}
|
|
1572
1846
|
const eventSeqs = [];
|
|
1573
1847
|
let hasDissolvedEvent = false;
|
|
1848
|
+
let publishedEventCount = 0;
|
|
1574
1849
|
for (const evt of eventObjects) {
|
|
1575
1850
|
const eventSeq = Number(evt.event_seq ?? 0);
|
|
1576
1851
|
if (Number.isFinite(eventSeq) && eventSeq > 0)
|
|
@@ -1590,10 +1865,12 @@ export class MessageDeliveryEngine {
|
|
|
1590
1865
|
}
|
|
1591
1866
|
}
|
|
1592
1867
|
if (Number.isFinite(eventSeq) && eventSeq > 0 && !client._pushedSeqs.get(ns)?.has(eventSeq)) {
|
|
1593
|
-
this.enqueueOrderedMessage(ns, 'group.changed', eventSeq, evt);
|
|
1868
|
+
this.enqueueOrderedMessage(ns, 'group.changed', eventSeq, evt, 'pull');
|
|
1869
|
+
publishedEventCount += 1;
|
|
1594
1870
|
}
|
|
1595
1871
|
}
|
|
1596
|
-
|
|
1872
|
+
if (et !== 'group.message_created')
|
|
1873
|
+
filled += 1;
|
|
1597
1874
|
}
|
|
1598
1875
|
const ackContig = client._seqTracker.getContiguousSeq(ns);
|
|
1599
1876
|
await this.drainOrderedMessages(ns);
|
|
@@ -1620,6 +1897,15 @@ export class MessageDeliveryEngine {
|
|
|
1620
1897
|
client._clientLog.debug(`group event auto-ack failed: group=${groupId} ${formatDeliveryError(e)}`);
|
|
1621
1898
|
}
|
|
1622
1899
|
}
|
|
1900
|
+
this.syncProgress(ns, {
|
|
1901
|
+
rawCount: eventObjects.length,
|
|
1902
|
+
pulledCount: publishedEventCount,
|
|
1903
|
+
remaining: result.remaining,
|
|
1904
|
+
hasMore: typeof result.has_more === 'boolean'
|
|
1905
|
+
? Boolean(result.has_more) : undefined,
|
|
1906
|
+
currentSeq: ackContig,
|
|
1907
|
+
targetSeq: Math.max(Number(cursor?.latest_seq ?? 0), Number(result.latest_event_seq ?? 0)),
|
|
1908
|
+
});
|
|
1623
1909
|
const nextAfter = Math.max(eventSeqs.length > 0 ? Math.max(...eventSeqs) : nextAfterSeq, nextAfterSeq);
|
|
1624
1910
|
if (singlePage && result.has_more === true && nextAfter > nextAfterSeq) {
|
|
1625
1911
|
continuationAfterSeq = nextAfter;
|
|
@@ -1634,6 +1920,7 @@ export class MessageDeliveryEngine {
|
|
|
1634
1920
|
client._clientLog.debug(`group event gap fill done: group=${groupId}, after_seq=${afterSeq}, filled=${filled}`);
|
|
1635
1921
|
}
|
|
1636
1922
|
catch (exc) {
|
|
1923
|
+
failed = true;
|
|
1637
1924
|
client._clientLog.warn(`group event gap fill failed: ${formatDeliveryError(exc)}`);
|
|
1638
1925
|
}
|
|
1639
1926
|
finally {
|
|
@@ -1650,6 +1937,8 @@ export class MessageDeliveryEngine {
|
|
|
1650
1937
|
else if (!singlePage && filled > 0 && client._seqTracker.getContiguousSeq(ns) > afterSeq) {
|
|
1651
1938
|
void this.fillGroupEventGap(groupId);
|
|
1652
1939
|
}
|
|
1940
|
+
if (!client._rpcPipeline)
|
|
1941
|
+
this.syncStopped(failed ? 'aborted' : 'pull_drained');
|
|
1653
1942
|
}
|
|
1654
1943
|
}
|
|
1655
1944
|
enqueueOnlineUnreadEventHint(data) {
|
|
@@ -2845,6 +3134,7 @@ export class MessageDeliveryEngine {
|
|
|
2845
3134
|
targets.delete(ns);
|
|
2846
3135
|
if (tasks.get(ns) === task)
|
|
2847
3136
|
tasks.delete(ns);
|
|
3137
|
+
client._rpcPipeline?.requestPullDrainedCheck?.();
|
|
2848
3138
|
}
|
|
2849
3139
|
});
|
|
2850
3140
|
tasks.set(ns, task);
|
|
@@ -2975,13 +3265,13 @@ export class MessageDeliveryEngine {
|
|
|
2975
3265
|
catch (exc) {
|
|
2976
3266
|
const error = formatDeliveryError(exc);
|
|
2977
3267
|
client._clientLog.warn(`restore SeqTracker state failed: ${error}`);
|
|
2978
|
-
client._dispatcher.
|
|
3268
|
+
client._dispatcher.enqueue('seq_tracker.persist_error', {
|
|
2979
3269
|
phase: 'restore',
|
|
2980
3270
|
aid: client._aid,
|
|
2981
3271
|
device_id: client._deviceId,
|
|
2982
3272
|
slot_id: client._slotId,
|
|
2983
3273
|
error: String(error),
|
|
2984
|
-
})
|
|
3274
|
+
});
|
|
2985
3275
|
}
|
|
2986
3276
|
}
|
|
2987
3277
|
migrateSeqStateGroupIds(state) {
|
|
@@ -3200,13 +3490,13 @@ export class MessageDeliveryEngine {
|
|
|
3200
3490
|
catch (exc) {
|
|
3201
3491
|
const error = formatDeliveryError(exc);
|
|
3202
3492
|
client._clientLog.warn(`save SeqTracker state failed: ${error}`);
|
|
3203
|
-
client._dispatcher.
|
|
3493
|
+
client._dispatcher.enqueue('seq_tracker.persist_error', {
|
|
3204
3494
|
phase: 'save',
|
|
3205
3495
|
aid,
|
|
3206
3496
|
device_id: deviceId,
|
|
3207
3497
|
slot_id: slotId,
|
|
3208
3498
|
error: String(error),
|
|
3209
|
-
})
|
|
3499
|
+
});
|
|
3210
3500
|
if (throwOnError)
|
|
3211
3501
|
throw exc;
|
|
3212
3502
|
}
|
|
@@ -3324,45 +3614,67 @@ export class MessageDeliveryEngine {
|
|
|
3324
3614
|
}
|
|
3325
3615
|
return params;
|
|
3326
3616
|
}
|
|
3327
|
-
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true) {
|
|
3617
|
+
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true, source = 'push', context) {
|
|
3328
3618
|
const client = this.runtime.client;
|
|
3329
3619
|
this.ensurePullOperationCurrent();
|
|
3330
3620
|
const queue = client._pendingOrderedMsgs.get(ns);
|
|
3331
3621
|
if (!queue || queue.size === 0)
|
|
3332
3622
|
return;
|
|
3333
3623
|
let delivered = false;
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
.
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3624
|
+
const rootTrigger = this.deliveryChangedTrigger(source);
|
|
3625
|
+
const drainContexts = new Map();
|
|
3626
|
+
try {
|
|
3627
|
+
while (true) {
|
|
3628
|
+
this.ensurePullOperationCurrent();
|
|
3629
|
+
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
3630
|
+
const ready = [...queue.keys()]
|
|
3631
|
+
.filter((seq) => seq <= contig && (beforeSeq === undefined || seq < beforeSeq))
|
|
3632
|
+
.sort((a, b) => a - b);
|
|
3633
|
+
let seq = ready[0];
|
|
3634
|
+
if (seq === undefined) {
|
|
3635
|
+
const nextSeq = contig + 1;
|
|
3636
|
+
if (beforeSeq !== undefined && nextSeq >= beforeSeq)
|
|
3637
|
+
break;
|
|
3638
|
+
if (!queue.has(nextSeq))
|
|
3639
|
+
break;
|
|
3640
|
+
seq = nextSeq;
|
|
3641
|
+
}
|
|
3642
|
+
if (seq === undefined)
|
|
3643
|
+
continue;
|
|
3644
|
+
const item = queue.get(seq);
|
|
3645
|
+
queue.delete(seq);
|
|
3646
|
+
if (!item)
|
|
3647
|
+
continue;
|
|
3648
|
+
if (client._pushedSeqs.get(ns)?.has(seq)) {
|
|
3649
|
+
client._clientLog.debug(`publish ordered drain skipped duplicate: ns=${ns}, seq=${seq}, event=${item.event}`);
|
|
3650
|
+
client._markOrderedSeqDelivered(ns, seq);
|
|
3651
|
+
continue;
|
|
3652
|
+
}
|
|
3653
|
+
const itemSource = item.source ?? source;
|
|
3654
|
+
const itemTrigger = this.deliveryChangedTrigger(itemSource);
|
|
3655
|
+
let itemContext = itemTrigger === rootTrigger ? context : undefined;
|
|
3656
|
+
if (itemTrigger === 'push' || itemTrigger === 'inline_push') {
|
|
3657
|
+
if (!itemContext) {
|
|
3658
|
+
itemContext = drainContexts.get(itemTrigger);
|
|
3659
|
+
if (!itemContext) {
|
|
3660
|
+
itemContext = { generation: this.deliveryChangedGeneration, changes: new Map() };
|
|
3661
|
+
drainContexts.set(itemTrigger, itemContext);
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
await this.publishOrderedQueueItem(ns, item.event, seq, item.payload, itemSource, pullResponse, itemContext);
|
|
3666
|
+
this.ensurePullOperationCurrent();
|
|
3667
|
+
this.markPublishedSeq(ns, seq);
|
|
3357
3668
|
client._markOrderedSeqDelivered(ns, seq);
|
|
3358
|
-
|
|
3669
|
+
delivered = true;
|
|
3670
|
+
client._clientLog.debug(`publish ordered drain delivered: ns=${ns}, seq=${seq}, event=${item.event}`);
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
finally {
|
|
3674
|
+
for (const [trigger, drainContext] of drainContexts) {
|
|
3675
|
+
if (drainContext !== context)
|
|
3676
|
+
this.flushDeliveryChangedContext(drainContext, trigger);
|
|
3359
3677
|
}
|
|
3360
|
-
await this.publishOrderedQueueItem(ns, item.event, seq, item.payload, 'ordered-drain', pullResponse);
|
|
3361
|
-
this.ensurePullOperationCurrent();
|
|
3362
|
-
this.markPublishedSeq(ns, seq);
|
|
3363
|
-
client._markOrderedSeqDelivered(ns, seq);
|
|
3364
|
-
delivered = true;
|
|
3365
|
-
client._clientLog.debug(`publish ordered drain delivered: ns=${ns}, seq=${seq}, event=${item.event}`);
|
|
3366
3678
|
}
|
|
3367
3679
|
if (queue.size === 0) {
|
|
3368
3680
|
client._pendingOrderedMsgs.delete(ns);
|
|
@@ -3372,13 +3684,35 @@ export class MessageDeliveryEngine {
|
|
|
3372
3684
|
}
|
|
3373
3685
|
}
|
|
3374
3686
|
}
|
|
3375
|
-
async publishOrderedMessage(event, ns, seq, payload) {
|
|
3687
|
+
async publishOrderedMessage(event, ns, seq, payload, source = 'push') {
|
|
3688
|
+
const context = {
|
|
3689
|
+
generation: this.deliveryChangedGeneration,
|
|
3690
|
+
changes: new Map(),
|
|
3691
|
+
};
|
|
3692
|
+
try {
|
|
3693
|
+
return await this.publishOrderedMessageInternal(event, ns, seq, payload, source, context);
|
|
3694
|
+
}
|
|
3695
|
+
finally {
|
|
3696
|
+
const trigger = this.deliveryChangedTrigger(source);
|
|
3697
|
+
if (trigger === 'pull_drained' && context.generation === this.deliveryChangedGeneration) {
|
|
3698
|
+
const pending = this.pendingDeliveryChanges ?? new Map();
|
|
3699
|
+
this.pendingDeliveryChanges = pending;
|
|
3700
|
+
for (const [namespace, count] of context.changes) {
|
|
3701
|
+
pending.set(namespace, (pending.get(namespace) ?? 0) + count);
|
|
3702
|
+
}
|
|
3703
|
+
}
|
|
3704
|
+
else if (trigger && trigger !== 'pull_drained') {
|
|
3705
|
+
this.flushDeliveryChangedContext(context, trigger);
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
async publishOrderedMessageInternal(event, ns, seq, payload, source, context) {
|
|
3376
3710
|
const client = this.runtime.client;
|
|
3377
3711
|
this.ensurePullOperationCurrent();
|
|
3378
3712
|
const seqNum = Number(seq);
|
|
3379
3713
|
if (!Number.isFinite(seqNum) || !Number.isInteger(seqNum) || seqNum <= 0) {
|
|
3380
3714
|
client._clientLog.debug(`publish ordered direct(no-seq): event=${event}, ns=${ns || '<none>'}, seq=${String(seq)}`);
|
|
3381
|
-
await this.publishOrderedQueueItem(ns, event, seqNum, payload,
|
|
3715
|
+
await this.publishOrderedQueueItem(ns, event, seqNum, payload, source, false, context);
|
|
3382
3716
|
this.ensurePullOperationCurrent();
|
|
3383
3717
|
return true;
|
|
3384
3718
|
}
|
|
@@ -3393,10 +3727,10 @@ export class MessageDeliveryEngine {
|
|
|
3393
3727
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
3394
3728
|
if (seqNum > contig && seqNum !== contig + 1) {
|
|
3395
3729
|
client._clientLog.debug(`publish ordered enqueue(gap): event=${event}, ns=${ns}, seq=${seqNum}, contiguous=${contig}`);
|
|
3396
|
-
this.enqueueOrderedMessage(ns, event, seqNum, payload);
|
|
3730
|
+
this.enqueueOrderedMessage(ns, event, seqNum, payload, source);
|
|
3397
3731
|
return false;
|
|
3398
3732
|
}
|
|
3399
|
-
await this.drainOrderedMessages(ns, seqNum);
|
|
3733
|
+
await this.drainOrderedMessages(ns, seqNum, false, true, source, context);
|
|
3400
3734
|
this.ensurePullOperationCurrent();
|
|
3401
3735
|
if (client._pushedSeqs.get(ns)?.has(seqNum)) {
|
|
3402
3736
|
client._clientLog.debug(`publish ordered skipped after-drain duplicate: event=${event}, ns=${ns}, seq=${seqNum}`);
|
|
@@ -3406,12 +3740,12 @@ export class MessageDeliveryEngine {
|
|
|
3406
3740
|
queue?.delete(seqNum);
|
|
3407
3741
|
if (queue && queue.size === 0)
|
|
3408
3742
|
client._pendingOrderedMsgs.delete(ns);
|
|
3409
|
-
await this.publishOrderedQueueItem(ns, event, seqNum, payload,
|
|
3743
|
+
await this.publishOrderedQueueItem(ns, event, seqNum, payload, source, false, context);
|
|
3410
3744
|
this.ensurePullOperationCurrent();
|
|
3411
3745
|
this.markPublishedSeq(ns, seqNum);
|
|
3412
3746
|
client._markOrderedSeqDelivered(ns, seqNum);
|
|
3413
3747
|
client._clientLog.debug(`publish ordered delivered: event=${event}, ns=${ns}, seq=${seqNum}`);
|
|
3414
|
-
await this.drainOrderedMessages(ns);
|
|
3748
|
+
await this.drainOrderedMessages(ns, undefined, false, true, source, context);
|
|
3415
3749
|
if (!client._pendingOrderedMsgs.get(ns)) {
|
|
3416
3750
|
this.ensurePullOperationCurrent();
|
|
3417
3751
|
await this.saveSeqTrackerState();
|
|
@@ -3444,18 +3778,18 @@ export class MessageDeliveryEngine {
|
|
|
3444
3778
|
}
|
|
3445
3779
|
return true;
|
|
3446
3780
|
}
|
|
3447
|
-
async publishPulledMessage(event, ns, seq, payload, persist = true) {
|
|
3781
|
+
async publishPulledMessage(event, ns, seq, payload, persist = true, source = 'pull') {
|
|
3448
3782
|
const client = this.runtime.client;
|
|
3449
3783
|
this.ensurePullOperationCurrent();
|
|
3450
3784
|
const seqNum = Number(seq);
|
|
3451
3785
|
if (!Number.isFinite(seqNum) || !Number.isInteger(seqNum) || seqNum <= 0 || !ns) {
|
|
3452
3786
|
client._clientLog.debug(`publish pulled direct(no-seq): event=${event}, ns=${ns || '<none>'}, seq=${String(seq)}`);
|
|
3453
3787
|
if (event === 'message.recalled') {
|
|
3454
|
-
const published = await this.publishMessageRecallTombstone(seq, payload);
|
|
3788
|
+
const published = await this.publishMessageRecallTombstone(seq, payload, source);
|
|
3455
3789
|
this.ensurePullOperationCurrent();
|
|
3456
3790
|
return published;
|
|
3457
3791
|
}
|
|
3458
|
-
const published = client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload,
|
|
3792
|
+
const published = client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source));
|
|
3459
3793
|
if (isPromiseLike(published))
|
|
3460
3794
|
await published;
|
|
3461
3795
|
this.ensurePullOperationCurrent();
|
|
@@ -3469,27 +3803,27 @@ export class MessageDeliveryEngine {
|
|
|
3469
3803
|
client._pendingOrderedMsgs.delete(ns);
|
|
3470
3804
|
return false;
|
|
3471
3805
|
}
|
|
3472
|
-
await this.drainOrderedMessages(ns, seqNum, true, persist);
|
|
3806
|
+
await this.drainOrderedMessages(ns, seqNum, true, persist, source);
|
|
3473
3807
|
this.ensurePullOperationCurrent();
|
|
3474
3808
|
queue?.delete(seqNum);
|
|
3475
3809
|
if (queue && queue.size === 0)
|
|
3476
3810
|
client._pendingOrderedMsgs.delete(ns);
|
|
3477
3811
|
if (event === 'message.recalled') {
|
|
3478
|
-
const recallPublished = await this.publishMessageRecallTombstone(seqNum, payload);
|
|
3812
|
+
const recallPublished = await this.publishMessageRecallTombstone(seqNum, payload, source);
|
|
3479
3813
|
this.ensurePullOperationCurrent();
|
|
3480
3814
|
this.markPublishedSeq(ns, seqNum);
|
|
3481
3815
|
client._clientLog.debug(`publish pulled delivered: event=${event}, ns=${ns}, seq=${seqNum}`);
|
|
3482
|
-
await this.drainOrderedMessages(ns, undefined, true, persist);
|
|
3816
|
+
await this.drainOrderedMessages(ns, undefined, true, persist, source);
|
|
3483
3817
|
this.ensurePullOperationCurrent();
|
|
3484
3818
|
return recallPublished;
|
|
3485
3819
|
}
|
|
3486
|
-
const published = client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload,
|
|
3820
|
+
const published = client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source));
|
|
3487
3821
|
if (isPromiseLike(published))
|
|
3488
3822
|
await published;
|
|
3489
3823
|
this.ensurePullOperationCurrent();
|
|
3490
3824
|
this.markPublishedSeq(ns, seqNum);
|
|
3491
3825
|
client._clientLog.debug(`publish pulled delivered: event=${event}, ns=${ns}, seq=${seqNum}`);
|
|
3492
|
-
await this.drainOrderedMessages(ns, undefined, true, persist);
|
|
3826
|
+
await this.drainOrderedMessages(ns, undefined, true, persist, source);
|
|
3493
3827
|
this.ensurePullOperationCurrent();
|
|
3494
3828
|
return true;
|
|
3495
3829
|
}
|