@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.
@@ -511,11 +511,15 @@ function readEntry(treeMap, id) {
511
511
  var OutboxWatcher = class {
512
512
  constructor(opts) {
513
513
  this.inFlight = /* @__PURE__ */ new Set();
514
- this.handled = /* @__PURE__ */ new Set();
515
514
  this.observer = null;
516
515
  this.treeMap = null;
517
516
  this.rootDoc = null;
518
517
  this.txHandler = null;
518
+ this.subdocsHandler = null;
519
+ this.updateHandler = null;
520
+ this.reconnectedHandler = null;
521
+ this.reconnectProvider = null;
522
+ this.subdocHandlers = /* @__PURE__ */ new Map();
519
523
  this.server = opts.server;
520
524
  this.sender = opts.sender;
521
525
  this.bootstrap = opts.bootstrap;
@@ -548,23 +552,57 @@ var OutboxWatcher = class {
548
552
  rootDoc.on("afterTransaction", onTx);
549
553
  this.txHandler = onTx;
550
554
  const onSubdocs = (changes) => {
551
- console.error(`[abracadabra-resend] subdocs: added=${changes.added.size} loaded=${changes.loaded.size}`);
552
- for (const sub of [...changes.added, ...changes.loaded]) sub.on("afterTransaction", (tx) => {
553
- console.error(`[abracadabra-resend] subdoc afterTransaction (guid=${sub.guid}, local=${tx.local})`);
554
- this.scan("subdoc");
555
- });
555
+ console.error(`[abracadabra-resend] subdocs: added=${changes.added.size} loaded=${changes.loaded.size} removed=${changes.removed.size}`);
556
+ for (const sub of changes.removed) {
557
+ const handler = this.subdocHandlers.get(sub);
558
+ if (handler) {
559
+ sub.off("afterTransaction", handler);
560
+ this.subdocHandlers.delete(sub);
561
+ }
562
+ }
563
+ for (const sub of [...changes.added, ...changes.loaded]) {
564
+ if (this.subdocHandlers.has(sub)) continue;
565
+ const handler = (tx) => {
566
+ console.error(`[abracadabra-resend] subdoc afterTransaction (guid=${sub.guid}, local=${tx.local})`);
567
+ this.scan("subdoc");
568
+ };
569
+ sub.on("afterTransaction", handler);
570
+ this.subdocHandlers.set(sub, handler);
571
+ }
556
572
  };
557
573
  rootDoc.on("subdocs", onSubdocs);
558
- rootDoc.on("update", (_update, origin) => {
574
+ this.subdocsHandler = onSubdocs;
575
+ const onUpdate = (_update, origin) => {
559
576
  console.error(`[abracadabra-resend] root update applied (origin=${String(origin)})`);
560
577
  this.scan("update");
561
- });
578
+ };
579
+ rootDoc.on("update", onUpdate);
580
+ this.updateHandler = onUpdate;
581
+ const provider = this.server.rootProvider;
582
+ if (provider && typeof provider.on === "function") {
583
+ const onReconnected = () => {
584
+ console.error("[abracadabra-resend] provider reconnected — re-scanning");
585
+ this.scan("reconnected");
586
+ };
587
+ provider.on("reconnected", onReconnected);
588
+ this.reconnectedHandler = onReconnected;
589
+ this.reconnectProvider = provider;
590
+ }
562
591
  console.error(`[abracadabra-resend] Outbox watcher attached (ready column ${this.bootstrap.columns.Ready})`);
563
592
  }
564
593
  stop() {
565
594
  if (this.rootDoc && this.txHandler) this.rootDoc.off("afterTransaction", this.txHandler);
595
+ if (this.rootDoc && this.subdocsHandler) this.rootDoc.off("subdocs", this.subdocsHandler);
596
+ if (this.rootDoc && this.updateHandler) this.rootDoc.off("update", this.updateHandler);
597
+ for (const [sub, handler] of this.subdocHandlers) sub.off("afterTransaction", handler);
598
+ this.subdocHandlers.clear();
566
599
  if (this.treeMap && this.observer) this.treeMap.unobserveDeep(this.observer);
600
+ if (this.reconnectProvider && this.reconnectedHandler) this.reconnectProvider.off("reconnected", this.reconnectedHandler);
567
601
  this.txHandler = null;
602
+ this.subdocsHandler = null;
603
+ this.updateHandler = null;
604
+ this.reconnectedHandler = null;
605
+ this.reconnectProvider = null;
568
606
  this.rootDoc = null;
569
607
  this.observer = null;
570
608
  this.treeMap = null;
@@ -591,9 +629,8 @@ var OutboxWatcher = class {
591
629
  });
592
630
  if (e.parentId !== readyColId) return;
593
631
  inReadyCount++;
594
- if (this.inFlight.has(id) || this.handled.has(id)) return;
632
+ if (this.inFlight.has(id)) return;
595
633
  if (typeof e.meta.resendId === "string" && e.meta.resendId.length > 0) {
596
- this.handled.add(id);
597
634
  this.moveTo(id, this.bootstrap.columns.Sent);
598
635
  return;
599
636
  }
@@ -613,7 +650,6 @@ var OutboxWatcher = class {
613
650
  const payload = await renderEmail(this.server, id, this.defaultFrom);
614
651
  console.error(`[abracadabra-resend] sending "${payload.subject}" → ${payload.to.join(", ")} (doc=${id})`);
615
652
  const { id: resendId } = await this.sender.send(payload, { "X-Abra-Doc-Id": id });
616
- this.handled.add(id);
617
653
  this.patchMeta(id, {
618
654
  resendId,
619
655
  sentAt: Date.now(),
@@ -622,7 +658,6 @@ var OutboxWatcher = class {
622
658
  this.moveTo(id, this.bootstrap.columns.Sent);
623
659
  console.error(`[abracadabra-resend] sent "${payload.subject}" (resend=${resendId}, doc=${id})`);
624
660
  } catch (err) {
625
- this.handled.add(id);
626
661
  const message = err instanceof RenderError ? err.message : err?.message ? String(err.message) : String(err);
627
662
  console.error(`[abracadabra-resend] send failed for "${label}" (${id}): ${message}`);
628
663
  this.patchMeta(id, {
@@ -1336,6 +1371,7 @@ var AbracadabraResendServer = class {
1336
1371
  this._connection = null;
1337
1372
  this.childCache = /* @__PURE__ */ new Map();
1338
1373
  this.evictionTimer = null;
1374
+ this.heartbeatTimer = null;
1339
1375
  this._userId = null;
1340
1376
  this._signFn = null;
1341
1377
  this._reconnecting = null;
@@ -1403,6 +1439,9 @@ var AbracadabraResendServer = class {
1403
1439
  await this._connectToSpace(targetId);
1404
1440
  console.error("[abracadabra-resend] Space doc synced");
1405
1441
  this.evictionTimer = setInterval(() => this.evictIdle(), 6e4);
1442
+ this.heartbeatTimer = setInterval(() => {
1443
+ this.ensureConnected();
1444
+ }, 3e4);
1406
1445
  }
1407
1446
  async _connectToSpace(docId) {
1408
1447
  if (!this.client.isTokenValid() && this._signFn && this._userId) {
@@ -1456,20 +1495,13 @@ var AbracadabraResendServer = class {
1456
1495
  await waitForSync(conn.provider, 6e3);
1457
1496
  } catch {}
1458
1497
  if (this._wsConnected(conn.provider)) return;
1459
- console.error("[abracadabra-resend] Active connection dead — rebuilding…");
1460
- const docId = conn.docId;
1498
+ console.error("[abracadabra-resend] Socket dead — forcing reconnect on the same doc…");
1499
+ conn.provider.reconnect();
1461
1500
  try {
1462
- conn.provider.destroy();
1463
- } catch {}
1464
- for (const [, cached] of this.childCache) try {
1465
- cached.provider.destroy();
1466
- } catch {}
1467
- this.childCache.clear();
1468
- try {
1469
- await this._connectToSpace(docId);
1470
- console.error("[abracadabra-resend] Space provider rebuilt + synced");
1501
+ await waitForSync(conn.provider, 1e4);
1502
+ console.error("[abracadabra-resend] Reconnected + re-synced");
1471
1503
  } catch (e) {
1472
- console.error("[abracadabra-resend] Connection rebuild failed:", e);
1504
+ console.error("[abracadabra-resend] Reconnect did not re-sync in time:", e);
1473
1505
  }
1474
1506
  } finally {
1475
1507
  this._reconnecting = null;
@@ -1517,6 +1549,10 @@ var AbracadabraResendServer = class {
1517
1549
  clearInterval(this.evictionTimer);
1518
1550
  this.evictionTimer = null;
1519
1551
  }
1552
+ if (this.heartbeatTimer) {
1553
+ clearInterval(this.heartbeatTimer);
1554
+ this.heartbeatTimer = null;
1555
+ }
1520
1556
  for (const [, cached] of this.childCache) try {
1521
1557
  cached.provider.destroy();
1522
1558
  } catch {}