@spectrum-ts/imessage 5.2.0 → 6.0.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.
Files changed (2) hide show
  1. package/dist/index.js +27 -15
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1508,9 +1508,12 @@ const log$1 = createLogger("spectrum.imessage.contact");
1508
1508
  const SHARE_TTL_MS = 1440 * 60 * 1e3;
1509
1509
  const MAX_TRACKED_CHATS = 1e4;
1510
1510
  /**
1511
- * Tracks which chats this bot has already proactively pushed its contact card
1512
- * to, so `im.chats.shareContactInfo` is fired at most once per chat per 24h
1513
- * per iMessage provider instance.
1511
+ * Tracks which chats this bot's line has already proactively pushed its contact
1512
+ * card to, so `im.chats.shareContactInfo` is fired at most once per chat per
1513
+ * line per 24h. One tracker is created per `AdvancedIMessage` client (see
1514
+ * `getContactShareTracker`), so the dedupe is naturally scoped to the line: a
1515
+ * DM `chatGuid` encodes the peer, not the receiving bot line, so the same guid
1516
+ * arriving on a different line shares independently.
1514
1517
  *
1515
1518
  * Backed by `lru-cache` for TTL + bounded memory. `ttlAutopurge: false`
1516
1519
  * keeps eviction lazy (on access) — there is no background timer to leak
@@ -1522,6 +1525,10 @@ var ContactShareTracker = class {
1522
1525
  ttl: SHARE_TTL_MS,
1523
1526
  ttlAutopurge: false
1524
1527
  });
1528
+ client;
1529
+ constructor(client) {
1530
+ this.client = client;
1531
+ }
1525
1532
  /**
1526
1533
  * Best-effort share. The cache is set eagerly so that a burst of inbound
1527
1534
  * messages for the same chat coalesces to a single API call. On failure the
@@ -1529,11 +1536,11 @@ var ContactShareTracker = class {
1529
1536
  * permanently mute the feature for a chat. Never awaits and never throws:
1530
1537
  * the receive stream must not crash on share failures.
1531
1538
  */
1532
- maybeShare(client, chatGuid) {
1539
+ maybeShare(chatGuid) {
1533
1540
  if (this.cache.has(chatGuid)) return;
1534
1541
  this.cache.set(chatGuid, true);
1535
1542
  const safeChatGuid = sanitizeErrorMessage(chatGuid);
1536
- client.chats.shareContactInfo(chatGuid).then(() => {
1543
+ this.client.chats.shareContactInfo(chatGuid).then(() => {
1537
1544
  log$1.info("shared contact card", { "spectrum.imessage.contact.chat": safeChatGuid });
1538
1545
  }).catch((error) => {
1539
1546
  this.cache.delete(chatGuid);
@@ -1546,16 +1553,18 @@ var ContactShareTracker = class {
1546
1553
  };
1547
1554
  const trackers = /* @__PURE__ */ new WeakMap();
1548
1555
  /**
1549
- * Returns a per-owner tracker. Mirrors `getMessageCache`/`getPollCache` in
1550
- * ../cache.ts keyed by an object (the `RemoteClient[]` array for remote
1551
- * mode), so each iMessage provider instance has its own tracker and multiple
1552
- * providers don't share state accidentally.
1556
+ * Returns a per-line tracker. Mirrors `getMessageCache` in ../cache.ts — keyed
1557
+ * by the individual `AdvancedIMessage` client, so each line has its own dedupe
1558
+ * state and multiple lines/providers don't share state accidentally. The
1559
+ * WeakMap holds the client weakly, so a torn-down line's tracker is collected
1560
+ * with its client (the tracker's own reference back to the client doesn't pin
1561
+ * it — the entry is a collectible cycle).
1553
1562
  */
1554
- const getContactShareTracker = (owner) => {
1555
- let tracker = trackers.get(owner);
1563
+ const getContactShareTracker = (client) => {
1564
+ let tracker = trackers.get(client);
1556
1565
  if (!tracker) {
1557
- tracker = new ContactShareTracker();
1558
- trackers.set(owner, tracker);
1566
+ tracker = new ContactShareTracker(client);
1567
+ trackers.set(client, tracker);
1559
1568
  }
1560
1569
  return tracker;
1561
1570
  };
@@ -1786,8 +1795,11 @@ const pollStream = (client, pollCache, phone) => resumableOrderedStream({
1786
1795
  const clientStream = (client, pollCache, phone, onInbound) => mergeStreams([messageStream(client, phone, onInbound), pollStream(client, pollCache, phone)]);
1787
1796
  const messages$1 = (clients, projectConfig) => {
1788
1797
  const pollCache = getPollCache(clients);
1789
- const tracker = projectConfig?.profile?.imessageSynced === true ? getContactShareTracker(clients) : void 0;
1790
- return mergeStreams(clients.map((entry) => clientStream(entry.client, pollCache, entry.phone, tracker ? (chatGuid) => tracker.maybeShare(entry.client, chatGuid) : void 0)));
1798
+ const shareEnabled = projectConfig?.profile?.imessageSynced === true;
1799
+ return mergeStreams(clients.map((entry) => {
1800
+ const tracker = shareEnabled ? getContactShareTracker(entry.client) : void 0;
1801
+ return clientStream(entry.client, pollCache, entry.phone, tracker ? (chatGuid) => tracker.maybeShare(chatGuid) : void 0);
1802
+ }));
1791
1803
  };
1792
1804
  //#endregion
1793
1805
  //#region src/remote/stream-text.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectrum-ts/imessage",
3
- "version": "5.2.0",
3
+ "version": "6.0.0",
4
4
  "description": "iMessage provider for spectrum-ts — local and remote (advanced) modes.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,7 +39,7 @@
39
39
  "zod": "^4.2.1"
40
40
  },
41
41
  "peerDependencies": {
42
- "@spectrum-ts/core": "^5.0.0",
42
+ "@spectrum-ts/core": "^6.0.0",
43
43
  "typescript": "^5 || ^6.0.0"
44
44
  },
45
45
  "license": "MIT"