@abraca/resend 2.16.0 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -541,11 +541,15 @@ function readEntry(treeMap, id) {
541
541
  var OutboxWatcher = class {
542
542
  constructor(opts) {
543
543
  this.inFlight = /* @__PURE__ */ new Set();
544
- this.handled = /* @__PURE__ */ new Set();
545
544
  this.observer = null;
546
545
  this.treeMap = null;
547
546
  this.rootDoc = null;
548
547
  this.txHandler = null;
548
+ this.subdocsHandler = null;
549
+ this.updateHandler = null;
550
+ this.reconnectedHandler = null;
551
+ this.reconnectProvider = null;
552
+ this.subdocHandlers = /* @__PURE__ */ new Map();
549
553
  this.server = opts.server;
550
554
  this.sender = opts.sender;
551
555
  this.bootstrap = opts.bootstrap;
@@ -578,23 +582,57 @@ var OutboxWatcher = class {
578
582
  rootDoc.on("afterTransaction", onTx);
579
583
  this.txHandler = onTx;
580
584
  const onSubdocs = (changes) => {
581
- console.error(`[abracadabra-resend] subdocs: added=${changes.added.size} loaded=${changes.loaded.size}`);
582
- for (const sub of [...changes.added, ...changes.loaded]) sub.on("afterTransaction", (tx) => {
583
- console.error(`[abracadabra-resend] subdoc afterTransaction (guid=${sub.guid}, local=${tx.local})`);
584
- this.scan("subdoc");
585
- });
585
+ console.error(`[abracadabra-resend] subdocs: added=${changes.added.size} loaded=${changes.loaded.size} removed=${changes.removed.size}`);
586
+ for (const sub of changes.removed) {
587
+ const handler = this.subdocHandlers.get(sub);
588
+ if (handler) {
589
+ sub.off("afterTransaction", handler);
590
+ this.subdocHandlers.delete(sub);
591
+ }
592
+ }
593
+ for (const sub of [...changes.added, ...changes.loaded]) {
594
+ if (this.subdocHandlers.has(sub)) continue;
595
+ const handler = (tx) => {
596
+ console.error(`[abracadabra-resend] subdoc afterTransaction (guid=${sub.guid}, local=${tx.local})`);
597
+ this.scan("subdoc");
598
+ };
599
+ sub.on("afterTransaction", handler);
600
+ this.subdocHandlers.set(sub, handler);
601
+ }
586
602
  };
587
603
  rootDoc.on("subdocs", onSubdocs);
588
- rootDoc.on("update", (_update, origin) => {
604
+ this.subdocsHandler = onSubdocs;
605
+ const onUpdate = (_update, origin) => {
589
606
  console.error(`[abracadabra-resend] root update applied (origin=${String(origin)})`);
590
607
  this.scan("update");
591
- });
608
+ };
609
+ rootDoc.on("update", onUpdate);
610
+ this.updateHandler = onUpdate;
611
+ const provider = this.server.rootProvider;
612
+ if (provider && typeof provider.on === "function") {
613
+ const onReconnected = () => {
614
+ console.error("[abracadabra-resend] provider reconnected — re-scanning");
615
+ this.scan("reconnected");
616
+ };
617
+ provider.on("reconnected", onReconnected);
618
+ this.reconnectedHandler = onReconnected;
619
+ this.reconnectProvider = provider;
620
+ }
592
621
  console.error(`[abracadabra-resend] Outbox watcher attached (ready column ${this.bootstrap.columns.Ready})`);
593
622
  }
594
623
  stop() {
595
624
  if (this.rootDoc && this.txHandler) this.rootDoc.off("afterTransaction", this.txHandler);
625
+ if (this.rootDoc && this.subdocsHandler) this.rootDoc.off("subdocs", this.subdocsHandler);
626
+ if (this.rootDoc && this.updateHandler) this.rootDoc.off("update", this.updateHandler);
627
+ for (const [sub, handler] of this.subdocHandlers) sub.off("afterTransaction", handler);
628
+ this.subdocHandlers.clear();
596
629
  if (this.treeMap && this.observer) this.treeMap.unobserveDeep(this.observer);
630
+ if (this.reconnectProvider && this.reconnectedHandler) this.reconnectProvider.off("reconnected", this.reconnectedHandler);
597
631
  this.txHandler = null;
632
+ this.subdocsHandler = null;
633
+ this.updateHandler = null;
634
+ this.reconnectedHandler = null;
635
+ this.reconnectProvider = null;
598
636
  this.rootDoc = null;
599
637
  this.observer = null;
600
638
  this.treeMap = null;
@@ -621,9 +659,8 @@ var OutboxWatcher = class {
621
659
  });
622
660
  if (e.parentId !== readyColId) return;
623
661
  inReadyCount++;
624
- if (this.inFlight.has(id) || this.handled.has(id)) return;
662
+ if (this.inFlight.has(id)) return;
625
663
  if (typeof e.meta.resendId === "string" && e.meta.resendId.length > 0) {
626
- this.handled.add(id);
627
664
  this.moveTo(id, this.bootstrap.columns.Sent);
628
665
  return;
629
666
  }
@@ -643,7 +680,6 @@ var OutboxWatcher = class {
643
680
  const payload = await renderEmail(this.server, id, this.defaultFrom);
644
681
  console.error(`[abracadabra-resend] sending "${payload.subject}" → ${payload.to.join(", ")} (doc=${id})`);
645
682
  const { id: resendId } = await this.sender.send(payload, { "X-Abra-Doc-Id": id });
646
- this.handled.add(id);
647
683
  this.patchMeta(id, {
648
684
  resendId,
649
685
  sentAt: Date.now(),
@@ -652,7 +688,6 @@ var OutboxWatcher = class {
652
688
  this.moveTo(id, this.bootstrap.columns.Sent);
653
689
  console.error(`[abracadabra-resend] sent "${payload.subject}" (resend=${resendId}, doc=${id})`);
654
690
  } catch (err) {
655
- this.handled.add(id);
656
691
  const message = err instanceof RenderError ? err.message : err?.message ? String(err.message) : String(err);
657
692
  console.error(`[abracadabra-resend] send failed for "${label}" (${id}): ${message}`);
658
693
  this.patchMeta(id, {
@@ -1366,6 +1401,7 @@ var AbracadabraResendServer = class {
1366
1401
  this._connection = null;
1367
1402
  this.childCache = /* @__PURE__ */ new Map();
1368
1403
  this.evictionTimer = null;
1404
+ this.heartbeatTimer = null;
1369
1405
  this._userId = null;
1370
1406
  this._signFn = null;
1371
1407
  this._reconnecting = null;
@@ -1433,6 +1469,9 @@ var AbracadabraResendServer = class {
1433
1469
  await this._connectToSpace(targetId);
1434
1470
  console.error("[abracadabra-resend] Space doc synced");
1435
1471
  this.evictionTimer = setInterval(() => this.evictIdle(), 6e4);
1472
+ this.heartbeatTimer = setInterval(() => {
1473
+ this.ensureConnected();
1474
+ }, 3e4);
1436
1475
  }
1437
1476
  async _connectToSpace(docId) {
1438
1477
  if (!this.client.isTokenValid() && this._signFn && this._userId) {
@@ -1486,20 +1525,13 @@ var AbracadabraResendServer = class {
1486
1525
  await waitForSync(conn.provider, 6e3);
1487
1526
  } catch {}
1488
1527
  if (this._wsConnected(conn.provider)) return;
1489
- console.error("[abracadabra-resend] Active connection dead — rebuilding…");
1490
- const docId = conn.docId;
1528
+ console.error("[abracadabra-resend] Socket dead — forcing reconnect on the same doc…");
1529
+ conn.provider.reconnect();
1491
1530
  try {
1492
- conn.provider.destroy();
1493
- } catch {}
1494
- for (const [, cached] of this.childCache) try {
1495
- cached.provider.destroy();
1496
- } catch {}
1497
- this.childCache.clear();
1498
- try {
1499
- await this._connectToSpace(docId);
1500
- console.error("[abracadabra-resend] Space provider rebuilt + synced");
1531
+ await waitForSync(conn.provider, 1e4);
1532
+ console.error("[abracadabra-resend] Reconnected + re-synced");
1501
1533
  } catch (e) {
1502
- console.error("[abracadabra-resend] Connection rebuild failed:", e);
1534
+ console.error("[abracadabra-resend] Reconnect did not re-sync in time:", e);
1503
1535
  }
1504
1536
  } finally {
1505
1537
  this._reconnecting = null;
@@ -1547,6 +1579,10 @@ var AbracadabraResendServer = class {
1547
1579
  clearInterval(this.evictionTimer);
1548
1580
  this.evictionTimer = null;
1549
1581
  }
1582
+ if (this.heartbeatTimer) {
1583
+ clearInterval(this.heartbeatTimer);
1584
+ this.heartbeatTimer = null;
1585
+ }
1550
1586
  for (const [, cached] of this.childCache) try {
1551
1587
  cached.provider.destroy();
1552
1588
  } catch {}