spectrum-ts 1.2.1 → 1.3.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.
- package/dist/{chunk-K3CTEGCZ.js → chunk-66GJ45ZZ.js} +1 -1
- package/dist/{chunk-I7EKZS5C.js → chunk-B4MHPWPZ.js} +1 -1
- package/dist/{chunk-UQPIWAHH.js → chunk-LH4YEBG3.js} +30 -17
- package/dist/index.d.ts +16 -12
- package/dist/index.js +79 -15
- package/dist/providers/imessage/index.d.ts +20 -3
- package/dist/providers/imessage/index.js +227 -143
- package/dist/providers/terminal/index.d.ts +89 -4
- package/dist/providers/terminal/index.js +30 -40
- package/dist/providers/whatsapp-business/index.d.ts +2 -1
- package/dist/providers/whatsapp-business/index.js +26 -36
- package/dist/{types-Dvp0I86h.d.ts → types-BcCLW2VO.d.ts} +58 -20
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
asGroup,
|
|
3
3
|
asRichlink,
|
|
4
4
|
groupSchema
|
|
5
|
-
} from "../../chunk-
|
|
5
|
+
} from "../../chunk-66GJ45ZZ.js";
|
|
6
6
|
import {
|
|
7
7
|
asPoll,
|
|
8
8
|
asPollOption,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
text,
|
|
24
24
|
textSchema,
|
|
25
25
|
toVCard
|
|
26
|
-
} from "../../chunk-
|
|
26
|
+
} from "../../chunk-LH4YEBG3.js";
|
|
27
27
|
|
|
28
28
|
// src/providers/imessage/index.ts
|
|
29
29
|
import {
|
|
@@ -77,18 +77,36 @@ function effect(input, messageEffect) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// src/providers/imessage/auth.ts
|
|
80
|
-
import {
|
|
81
|
-
createClient
|
|
82
|
-
} from "@photon-ai/advanced-imessage";
|
|
80
|
+
import { createClient } from "@photon-ai/advanced-imessage";
|
|
83
81
|
var RENEWAL_RATIO = 0.8;
|
|
84
82
|
var EXPIRY_BUFFER_MS = 3e4;
|
|
85
83
|
var RETRY_DELAY_MS = 3e4;
|
|
86
84
|
var cloudAuthState = /* @__PURE__ */ new WeakMap();
|
|
85
|
+
var requirePhone = (data, instanceId) => {
|
|
86
|
+
const phone = data.numbers?.[instanceId];
|
|
87
|
+
if (!phone) {
|
|
88
|
+
throw new Error(`iMessage instance ${instanceId} has no phone assigned`);
|
|
89
|
+
}
|
|
90
|
+
return phone;
|
|
91
|
+
};
|
|
87
92
|
async function createCloudClients(projectId, projectSecret) {
|
|
88
93
|
let tokenData = await cloud.issueImessageTokens(projectId, projectSecret);
|
|
89
94
|
let tokenExpiresAt = Date.now() + tokenData.expiresIn * 1e3;
|
|
90
95
|
let disposed = false;
|
|
91
96
|
let renewalTimer;
|
|
97
|
+
if (tokenData.type === "shared") {
|
|
98
|
+
throw UnsupportedError.action(
|
|
99
|
+
"multi-phone",
|
|
100
|
+
"iMessage shared mode",
|
|
101
|
+
"use dedicated-token cloud mode"
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const records = [];
|
|
105
|
+
const syncPhones = (data) => {
|
|
106
|
+
for (const { entry, instanceId } of records) {
|
|
107
|
+
entry.phone = requirePhone(data, instanceId);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
92
110
|
const scheduleRenewal = () => {
|
|
93
111
|
if (disposed) {
|
|
94
112
|
return;
|
|
@@ -98,7 +116,15 @@ async function createCloudClients(projectId, projectSecret) {
|
|
|
98
116
|
renewalTimer = setTimeout(async () => {
|
|
99
117
|
try {
|
|
100
118
|
tokenData = await cloud.issueImessageTokens(projectId, projectSecret);
|
|
119
|
+
if (tokenData.type === "shared") {
|
|
120
|
+
throw UnsupportedError.action(
|
|
121
|
+
"multi-phone",
|
|
122
|
+
"iMessage shared mode",
|
|
123
|
+
"use dedicated-token cloud mode"
|
|
124
|
+
);
|
|
125
|
+
}
|
|
101
126
|
tokenExpiresAt = Date.now() + tokenData.expiresIn * 1e3;
|
|
127
|
+
syncPhones(tokenData);
|
|
102
128
|
scheduleRenewal();
|
|
103
129
|
} catch {
|
|
104
130
|
renewalTimer = setTimeout(() => scheduleRenewal(), RETRY_DELAY_MS);
|
|
@@ -113,25 +139,22 @@ async function createCloudClients(projectId, projectSecret) {
|
|
|
113
139
|
return;
|
|
114
140
|
}
|
|
115
141
|
tokenData = await cloud.issueImessageTokens(projectId, projectSecret);
|
|
142
|
+
if (tokenData.type === "shared") {
|
|
143
|
+
throw UnsupportedError.action(
|
|
144
|
+
"multi-phone",
|
|
145
|
+
"iMessage shared mode",
|
|
146
|
+
"use dedicated-token cloud mode"
|
|
147
|
+
);
|
|
148
|
+
}
|
|
116
149
|
tokenExpiresAt = Date.now() + tokenData.expiresIn * 1e3;
|
|
150
|
+
syncPhones(tokenData);
|
|
117
151
|
scheduleRenewal();
|
|
118
152
|
};
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
address,
|
|
125
|
-
tls: true,
|
|
126
|
-
token: async () => {
|
|
127
|
-
await refreshIfNeeded();
|
|
128
|
-
return tokenData.token;
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
];
|
|
132
|
-
}
|
|
133
|
-
return Object.entries(tokenData.auth).map(
|
|
134
|
-
([instanceId, token]) => createClient({
|
|
153
|
+
const dedicated = tokenData;
|
|
154
|
+
for (const [instanceId, token] of Object.entries(dedicated.auth)) {
|
|
155
|
+
const entry = {
|
|
156
|
+
phone: requirePhone(dedicated, instanceId),
|
|
157
|
+
client: createClient({
|
|
135
158
|
address: `${instanceId}.imsg.photon.codes:443`,
|
|
136
159
|
tls: true,
|
|
137
160
|
token: async () => {
|
|
@@ -140,10 +163,11 @@ async function createCloudClients(projectId, projectSecret) {
|
|
|
140
163
|
return data.auth[instanceId] ?? token;
|
|
141
164
|
}
|
|
142
165
|
})
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
166
|
+
};
|
|
167
|
+
records.push({ entry, instanceId });
|
|
168
|
+
}
|
|
169
|
+
const entries = records.map((r) => r.entry);
|
|
170
|
+
cloudAuthState.set(entries, {
|
|
147
171
|
dispose: () => {
|
|
148
172
|
disposed = true;
|
|
149
173
|
if (renewalTimer !== void 0) {
|
|
@@ -152,7 +176,7 @@ async function createCloudClients(projectId, projectSecret) {
|
|
|
152
176
|
}
|
|
153
177
|
}
|
|
154
178
|
});
|
|
155
|
-
return
|
|
179
|
+
return entries;
|
|
156
180
|
}
|
|
157
181
|
async function disposeCloudAuth(clients) {
|
|
158
182
|
const auth = cloudAuthState.get(clients);
|
|
@@ -230,7 +254,12 @@ var toMessages = async (message) => {
|
|
|
230
254
|
}
|
|
231
255
|
const base = {
|
|
232
256
|
sender: { id: message.participant ?? "" },
|
|
233
|
-
|
|
257
|
+
// Local mode has no concept of "which-of-my-phones"; phone is empty.
|
|
258
|
+
space: {
|
|
259
|
+
id: chatId,
|
|
260
|
+
type: chatKind === "group" ? "group" : "dm",
|
|
261
|
+
phone: ""
|
|
262
|
+
},
|
|
234
263
|
timestamp: message.createdAt
|
|
235
264
|
};
|
|
236
265
|
if (message.attachments.length > 0) {
|
|
@@ -337,17 +366,6 @@ var messages2 = (client) => messages(client);
|
|
|
337
366
|
var send2 = async (client, spaceId, content) => send(client, spaceId, content);
|
|
338
367
|
var getMessage2 = async (client, id) => getMessage(client, id);
|
|
339
368
|
|
|
340
|
-
// src/providers/imessage/remote/client.ts
|
|
341
|
-
var REMOTE_CLIENT_MISSING = "No remote iMessage client available";
|
|
342
|
-
var firstRemoteClient = (clients) => clients[0];
|
|
343
|
-
var primaryRemoteClient = (clients) => {
|
|
344
|
-
const remote = firstRemoteClient(clients);
|
|
345
|
-
if (!remote) {
|
|
346
|
-
throw new Error(REMOTE_CLIENT_MISSING);
|
|
347
|
-
}
|
|
348
|
-
return remote;
|
|
349
|
-
};
|
|
350
|
-
|
|
351
369
|
// src/providers/imessage/remote/inbound.ts
|
|
352
370
|
import {
|
|
353
371
|
messageGuid,
|
|
@@ -520,13 +538,14 @@ var isIMessageMessage = (value) => {
|
|
|
520
538
|
return typeof record.id === "string" && record.id.length > 0 && typeof record.content === "object" && record.content !== null && typeof record.sender === "object" && record.sender !== null && typeof record.space === "object" && record.space !== null;
|
|
521
539
|
};
|
|
522
540
|
var asProviderGroup = (items) => groupSchema.parse({ type: "group", items });
|
|
523
|
-
var buildMessageBase = (message, chatGuidHint, timestamp) => {
|
|
541
|
+
var buildMessageBase = (message, chatGuidHint, timestamp, phone) => {
|
|
524
542
|
const chat = resolveChatGuid(message, chatGuidHint);
|
|
525
543
|
return {
|
|
526
544
|
sender: { id: resolveSenderId(message) },
|
|
527
545
|
space: {
|
|
528
546
|
id: chat,
|
|
529
|
-
type: chat.includes(";+;") ? "group" : "dm"
|
|
547
|
+
type: chat.includes(";+;") ? "group" : "dm",
|
|
548
|
+
phone
|
|
530
549
|
},
|
|
531
550
|
timestamp
|
|
532
551
|
};
|
|
@@ -581,10 +600,10 @@ var toRichlinkMessage = (message, base, id) => {
|
|
|
581
600
|
};
|
|
582
601
|
}
|
|
583
602
|
};
|
|
584
|
-
var rebuildFromAppleMessage = async (client, message, chatGuidHint) => {
|
|
603
|
+
var rebuildFromAppleMessage = async (client, message, phone, chatGuidHint) => {
|
|
585
604
|
const messageGuidStr = message.guid;
|
|
586
605
|
const timestamp = message.dateCreated ?? /* @__PURE__ */ new Date();
|
|
587
|
-
const base = buildMessageBase(message, chatGuidHint, timestamp);
|
|
606
|
+
const base = buildMessageBase(message, chatGuidHint, timestamp, phone);
|
|
588
607
|
if (message.attachments.length === 1) {
|
|
589
608
|
const info = message.attachments[0];
|
|
590
609
|
if (!info) {
|
|
@@ -636,8 +655,13 @@ var cacheMessage = (cache, message) => {
|
|
|
636
655
|
}
|
|
637
656
|
}
|
|
638
657
|
};
|
|
639
|
-
var toInboundMessages = async (client, cache, event) => {
|
|
640
|
-
const base = buildMessageBase(
|
|
658
|
+
var toInboundMessages = async (client, cache, event, phone) => {
|
|
659
|
+
const base = buildMessageBase(
|
|
660
|
+
event.message,
|
|
661
|
+
event.chatGuid,
|
|
662
|
+
event.timestamp,
|
|
663
|
+
phone
|
|
664
|
+
);
|
|
641
665
|
const messageGuidStr = event.message.guid;
|
|
642
666
|
if (getBalloonBundleId(event.message) === URL_BALLOON_BUNDLE_ID) {
|
|
643
667
|
const msg2 = toRichlinkMessage(event.message, base, messageGuidStr);
|
|
@@ -694,7 +718,7 @@ var toInboundMessages = async (client, cache, event) => {
|
|
|
694
718
|
cacheMessage(cache, msg);
|
|
695
719
|
return [msg];
|
|
696
720
|
};
|
|
697
|
-
var getMessage3 = async (remote, spaceId, msgId) => {
|
|
721
|
+
var getMessage3 = async (remote, spaceId, msgId, phone) => {
|
|
698
722
|
const cache = getMessageCache(remote);
|
|
699
723
|
const cached = cache.get(msgId);
|
|
700
724
|
if (cached) {
|
|
@@ -706,7 +730,12 @@ var getMessage3 = async (remote, spaceId, msgId) => {
|
|
|
706
730
|
const fetched = await remote.messages.get(
|
|
707
731
|
messageGuid(childRef.parentGuid)
|
|
708
732
|
);
|
|
709
|
-
const parent = await rebuildFromAppleMessage(
|
|
733
|
+
const parent = await rebuildFromAppleMessage(
|
|
734
|
+
remote,
|
|
735
|
+
fetched,
|
|
736
|
+
phone,
|
|
737
|
+
spaceId
|
|
738
|
+
);
|
|
710
739
|
cacheMessage(cache, parent);
|
|
711
740
|
if (parent.content.type !== "group") {
|
|
712
741
|
return;
|
|
@@ -722,7 +751,12 @@ var getMessage3 = async (remote, spaceId, msgId) => {
|
|
|
722
751
|
}
|
|
723
752
|
try {
|
|
724
753
|
const fetched = await remote.messages.get(messageGuid(msgId));
|
|
725
|
-
const rebuilt = await rebuildFromAppleMessage(
|
|
754
|
+
const rebuilt = await rebuildFromAppleMessage(
|
|
755
|
+
remote,
|
|
756
|
+
fetched,
|
|
757
|
+
phone,
|
|
758
|
+
spaceId
|
|
759
|
+
);
|
|
726
760
|
cacheMessage(cache, rebuilt);
|
|
727
761
|
return rebuilt;
|
|
728
762
|
} catch (err) {
|
|
@@ -785,12 +819,12 @@ var asProviderReaction = (emoji, target) => reactionSchema.parse({
|
|
|
785
819
|
target,
|
|
786
820
|
type: "reaction"
|
|
787
821
|
});
|
|
788
|
-
var resolveReactionTarget = async (client, cache, strippedGuid, partIndex) => {
|
|
822
|
+
var resolveReactionTarget = async (client, cache, strippedGuid, partIndex, phone) => {
|
|
789
823
|
let candidate = cache.get(strippedGuid);
|
|
790
824
|
if (!candidate) {
|
|
791
825
|
try {
|
|
792
826
|
const fetched = await client.messages.get(messageGuid2(strippedGuid));
|
|
793
|
-
candidate = await rebuildFromAppleMessage(client, fetched);
|
|
827
|
+
candidate = await rebuildFromAppleMessage(client, fetched, phone);
|
|
794
828
|
cacheMessage(cache, candidate);
|
|
795
829
|
} catch {
|
|
796
830
|
return;
|
|
@@ -806,7 +840,7 @@ var resolveReactionTarget = async (client, cache, strippedGuid, partIndex) => {
|
|
|
806
840
|
}
|
|
807
841
|
return candidate;
|
|
808
842
|
};
|
|
809
|
-
var toReactionMessages = async (client, cache, event, target) => {
|
|
843
|
+
var toReactionMessages = async (client, cache, event, target, phone) => {
|
|
810
844
|
const type = getAssociatedMessageType(event.message);
|
|
811
845
|
if (type && isTapbackRemoval(type)) {
|
|
812
846
|
return [];
|
|
@@ -823,7 +857,8 @@ var toReactionMessages = async (client, cache, event, target) => {
|
|
|
823
857
|
client,
|
|
824
858
|
cache,
|
|
825
859
|
strippedGuid,
|
|
826
|
-
partIndex
|
|
860
|
+
partIndex,
|
|
861
|
+
phone
|
|
827
862
|
);
|
|
828
863
|
if (!resolved) {
|
|
829
864
|
return [];
|
|
@@ -832,7 +867,12 @@ var toReactionMessages = async (client, cache, event, target) => {
|
|
|
832
867
|
if (typeof messageId !== "string" || messageId.length === 0) {
|
|
833
868
|
return [];
|
|
834
869
|
}
|
|
835
|
-
const base = buildMessageBase(
|
|
870
|
+
const base = buildMessageBase(
|
|
871
|
+
event.message,
|
|
872
|
+
event.chatGuid,
|
|
873
|
+
event.timestamp,
|
|
874
|
+
phone
|
|
875
|
+
);
|
|
836
876
|
return [
|
|
837
877
|
{
|
|
838
878
|
...base,
|
|
@@ -1545,7 +1585,8 @@ var buildPollOptionMessage = (input) => {
|
|
|
1545
1585
|
sender: { id: input.senderAddress },
|
|
1546
1586
|
space: {
|
|
1547
1587
|
id: input.chatGuid,
|
|
1548
|
-
type: input.chatGuid.includes(";+;") ? "group" : "dm"
|
|
1588
|
+
type: input.chatGuid.includes(";+;") ? "group" : "dm",
|
|
1589
|
+
phone: input.phone
|
|
1549
1590
|
},
|
|
1550
1591
|
timestamp: input.event.at,
|
|
1551
1592
|
content: asPollOption({
|
|
@@ -1563,6 +1604,7 @@ var buildPollOptionMessages = (input) => {
|
|
|
1563
1604
|
chatGuid: input.chatGuid,
|
|
1564
1605
|
event: input.event,
|
|
1565
1606
|
optionId: delta.optionId,
|
|
1607
|
+
phone: input.phone,
|
|
1566
1608
|
selected: delta.selected,
|
|
1567
1609
|
senderAddress: input.senderAddress
|
|
1568
1610
|
});
|
|
@@ -1587,7 +1629,7 @@ var refreshPollMetadata = async (client, pollCache, event, fallbackOptionIds) =>
|
|
|
1587
1629
|
poll: refreshed
|
|
1588
1630
|
};
|
|
1589
1631
|
};
|
|
1590
|
-
var toPollVoteMessages = async (client, pollCache, event) => {
|
|
1632
|
+
var toPollVoteMessages = async (client, pollCache, event, phone) => {
|
|
1591
1633
|
const senderAddress = event.actor.address;
|
|
1592
1634
|
if (!senderAddress) {
|
|
1593
1635
|
return [];
|
|
@@ -1630,6 +1672,7 @@ var toPollVoteMessages = async (client, pollCache, event) => {
|
|
|
1630
1672
|
chatGuid: chatGuidStr,
|
|
1631
1673
|
deltas,
|
|
1632
1674
|
event,
|
|
1675
|
+
phone,
|
|
1633
1676
|
senderAddress
|
|
1634
1677
|
});
|
|
1635
1678
|
pollCache.commitActorSelection(
|
|
@@ -1640,7 +1683,7 @@ var toPollVoteMessages = async (client, pollCache, event) => {
|
|
|
1640
1683
|
);
|
|
1641
1684
|
return messages5;
|
|
1642
1685
|
};
|
|
1643
|
-
var toPollUnvoteMessages = async (client, pollCache, event) => {
|
|
1686
|
+
var toPollUnvoteMessages = async (client, pollCache, event, phone) => {
|
|
1644
1687
|
const senderAddress = event.actor.address;
|
|
1645
1688
|
if (!senderAddress) {
|
|
1646
1689
|
return [];
|
|
@@ -1660,17 +1703,18 @@ var toPollUnvoteMessages = async (client, pollCache, event) => {
|
|
|
1660
1703
|
chatGuid: chatGuidStr,
|
|
1661
1704
|
deltas,
|
|
1662
1705
|
event,
|
|
1706
|
+
phone,
|
|
1663
1707
|
senderAddress
|
|
1664
1708
|
});
|
|
1665
1709
|
pollCache.commitActorSelection(pollId, senderAddress, [], event.at);
|
|
1666
1710
|
return messages5;
|
|
1667
1711
|
};
|
|
1668
|
-
var toPollDeltaMessages = async (client, pollCache, event) => {
|
|
1712
|
+
var toPollDeltaMessages = async (client, pollCache, event, phone) => {
|
|
1669
1713
|
if (isVotedPollEvent(event)) {
|
|
1670
|
-
return toPollVoteMessages(client, pollCache, event);
|
|
1714
|
+
return toPollVoteMessages(client, pollCache, event, phone);
|
|
1671
1715
|
}
|
|
1672
1716
|
if (isUnvotedPollEvent(event)) {
|
|
1673
|
-
return toPollUnvoteMessages(client, pollCache, event);
|
|
1717
|
+
return toPollUnvoteMessages(client, pollCache, event, phone);
|
|
1674
1718
|
}
|
|
1675
1719
|
return [];
|
|
1676
1720
|
};
|
|
@@ -1686,43 +1730,43 @@ var isRetryableIMessageStreamError = (error) => {
|
|
|
1686
1730
|
}
|
|
1687
1731
|
return false;
|
|
1688
1732
|
};
|
|
1689
|
-
var toMessageItem = async (client, event, cursor) => {
|
|
1733
|
+
var toMessageItem = async (client, event, phone, cursor) => {
|
|
1690
1734
|
const id = event.message.guid;
|
|
1691
1735
|
if (event.message.isFromMe) {
|
|
1692
1736
|
return { cursor, id, values: [] };
|
|
1693
1737
|
}
|
|
1694
1738
|
const cache = getMessageCache(client);
|
|
1695
1739
|
const target = event.message.associatedMessageGuid;
|
|
1696
|
-
const values = target ? await toReactionMessages(client, cache, event, target) : await toInboundMessages(client, cache, event);
|
|
1740
|
+
const values = target ? await toReactionMessages(client, cache, event, target, phone) : await toInboundMessages(client, cache, event, phone);
|
|
1697
1741
|
return { cursor, id, values };
|
|
1698
1742
|
};
|
|
1699
|
-
var messageStream = (client) => resumableOrderedStream({
|
|
1743
|
+
var messageStream = (client, phone) => resumableOrderedStream({
|
|
1700
1744
|
fetchMissed: (cursor, { limit }) => client.messages.fetchMissed(cursor, { limit }),
|
|
1701
1745
|
isRetryableError: isRetryableIMessageStreamError,
|
|
1702
|
-
processLive: (event) => toMessageItem(client, event, event.cursor),
|
|
1703
|
-
processMissed: (message) => toMessageItem(client, receivedEventFromMessage(message)),
|
|
1746
|
+
processLive: (event) => toMessageItem(client, event, phone, event.cursor),
|
|
1747
|
+
processMissed: (message) => toMessageItem(client, receivedEventFromMessage(message), phone),
|
|
1704
1748
|
subscribeLive: () => client.messages.subscribe("message.received")
|
|
1705
1749
|
});
|
|
1706
1750
|
var logPollStreamError = (error) => {
|
|
1707
1751
|
console.error("[spectrum-ts][imessage][poll] stream failed", error);
|
|
1708
1752
|
};
|
|
1709
|
-
var emitPollMessages = async (client, pollCache, event, emit) => {
|
|
1753
|
+
var emitPollMessages = async (client, pollCache, event, phone, emit) => {
|
|
1710
1754
|
cachePollEvent(pollCache, event);
|
|
1711
1755
|
if (event.actor.isFromMe) {
|
|
1712
1756
|
return;
|
|
1713
1757
|
}
|
|
1714
|
-
const messages5 = await toPollDeltaMessages(client, pollCache, event);
|
|
1758
|
+
const messages5 = await toPollDeltaMessages(client, pollCache, event, phone);
|
|
1715
1759
|
for (const vote of messages5) {
|
|
1716
1760
|
await emit(vote);
|
|
1717
1761
|
}
|
|
1718
1762
|
};
|
|
1719
|
-
var runPollSubscription = async (client, pollCache, subscription, emit, onEvent) => {
|
|
1763
|
+
var runPollSubscription = async (client, pollCache, subscription, phone, emit, onEvent) => {
|
|
1720
1764
|
for await (const event of subscription) {
|
|
1721
1765
|
onEvent();
|
|
1722
|
-
await emitPollMessages(client, pollCache, event, emit);
|
|
1766
|
+
await emitPollMessages(client, pollCache, event, phone, emit);
|
|
1723
1767
|
}
|
|
1724
1768
|
};
|
|
1725
|
-
var pollStream = (client, pollCache) => stream((emit, end) => {
|
|
1769
|
+
var pollStream = (client, pollCache, phone) => stream((emit, end) => {
|
|
1726
1770
|
let active = client.polls.subscribe();
|
|
1727
1771
|
let closed = false;
|
|
1728
1772
|
let retryDelayMs = RECONNECT_INITIAL_DELAY_MS;
|
|
@@ -1750,9 +1794,16 @@ var pollStream = (client, pollCache) => stream((emit, end) => {
|
|
|
1750
1794
|
const pump = (async () => {
|
|
1751
1795
|
while (!closed) {
|
|
1752
1796
|
try {
|
|
1753
|
-
await runPollSubscription(
|
|
1754
|
-
|
|
1755
|
-
|
|
1797
|
+
await runPollSubscription(
|
|
1798
|
+
client,
|
|
1799
|
+
pollCache,
|
|
1800
|
+
active,
|
|
1801
|
+
phone,
|
|
1802
|
+
emit,
|
|
1803
|
+
() => {
|
|
1804
|
+
retryDelayMs = RECONNECT_INITIAL_DELAY_MS;
|
|
1805
|
+
}
|
|
1806
|
+
);
|
|
1756
1807
|
} catch (e) {
|
|
1757
1808
|
if (!closed) {
|
|
1758
1809
|
logPollStreamError(e);
|
|
@@ -1775,12 +1826,17 @@ var pollStream = (client, pollCache) => stream((emit, end) => {
|
|
|
1775
1826
|
await pump;
|
|
1776
1827
|
};
|
|
1777
1828
|
});
|
|
1778
|
-
var clientStream = (client, pollCache) => {
|
|
1779
|
-
return mergeStreams([
|
|
1829
|
+
var clientStream = (client, pollCache, phone) => {
|
|
1830
|
+
return mergeStreams([
|
|
1831
|
+
messageStream(client, phone),
|
|
1832
|
+
pollStream(client, pollCache, phone)
|
|
1833
|
+
]);
|
|
1780
1834
|
};
|
|
1781
1835
|
var messages3 = (clients) => {
|
|
1782
1836
|
const pollCache = getPollCache(clients);
|
|
1783
|
-
return mergeStreams(
|
|
1837
|
+
return mergeStreams(
|
|
1838
|
+
clients.map((entry) => clientStream(entry.client, pollCache, entry.phone))
|
|
1839
|
+
);
|
|
1784
1840
|
};
|
|
1785
1841
|
|
|
1786
1842
|
// src/providers/imessage/remote/typing.ts
|
|
@@ -1794,43 +1850,52 @@ var stopTyping = async (remote, spaceId) => {
|
|
|
1794
1850
|
|
|
1795
1851
|
// src/providers/imessage/remote/api.ts
|
|
1796
1852
|
var messages4 = (clients) => messages3(clients);
|
|
1797
|
-
var startTyping2 = async (
|
|
1798
|
-
const remote = firstRemoteClient(clients);
|
|
1799
|
-
if (!remote) {
|
|
1800
|
-
return;
|
|
1801
|
-
}
|
|
1853
|
+
var startTyping2 = async (remote, spaceId) => {
|
|
1802
1854
|
await startTyping(remote, spaceId);
|
|
1803
1855
|
};
|
|
1804
|
-
var stopTyping2 = async (
|
|
1805
|
-
const remote = firstRemoteClient(clients);
|
|
1806
|
-
if (!remote) {
|
|
1807
|
-
return;
|
|
1808
|
-
}
|
|
1856
|
+
var stopTyping2 = async (remote, spaceId) => {
|
|
1809
1857
|
await stopTyping(remote, spaceId);
|
|
1810
1858
|
};
|
|
1811
|
-
var send4 = async (
|
|
1812
|
-
var replyToMessage2 = async (
|
|
1813
|
-
var editMessage2 = async (
|
|
1814
|
-
var reactToMessage2 = async (
|
|
1815
|
-
const remote = firstRemoteClient(clients);
|
|
1816
|
-
if (!remote) {
|
|
1817
|
-
return;
|
|
1818
|
-
}
|
|
1859
|
+
var send4 = async (remote, spaceId, content) => send3(remote, spaceId, content);
|
|
1860
|
+
var replyToMessage2 = async (remote, spaceId, msgId, content) => replyToMessage(remote, spaceId, msgId, content);
|
|
1861
|
+
var editMessage2 = async (remote, spaceId, msgId, content) => editMessage(remote, spaceId, msgId, content);
|
|
1862
|
+
var reactToMessage2 = async (remote, spaceId, target, reaction) => {
|
|
1819
1863
|
await reactToMessage(remote, spaceId, target, reaction);
|
|
1820
1864
|
};
|
|
1821
|
-
var getMessage4 = async (
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1865
|
+
var getMessage4 = async (remote, spaceId, msgId, phone) => getMessage3(remote, spaceId, msgId, phone);
|
|
1866
|
+
|
|
1867
|
+
// src/providers/imessage/remote/client.ts
|
|
1868
|
+
var availablePhones = (clients) => clients.map((c) => c.phone);
|
|
1869
|
+
var clientForPhone = (clients, phone) => {
|
|
1870
|
+
const entry = clients.find((c) => c.phone === phone);
|
|
1871
|
+
if (!entry) {
|
|
1872
|
+
const list = availablePhones(clients).join(", ") || "<none>";
|
|
1873
|
+
throw new Error(
|
|
1874
|
+
`No iMessage client serves phone ${phone}. Available: ${list}`
|
|
1875
|
+
);
|
|
1825
1876
|
}
|
|
1826
|
-
return
|
|
1877
|
+
return entry.client;
|
|
1878
|
+
};
|
|
1879
|
+
var randomPhone = (clients) => {
|
|
1880
|
+
if (clients.length === 0) {
|
|
1881
|
+
throw new Error("No iMessage phones configured for this account");
|
|
1882
|
+
}
|
|
1883
|
+
const entry = clients[Math.floor(Math.random() * clients.length)];
|
|
1884
|
+
if (!entry) {
|
|
1885
|
+
throw new Error("No iMessage phones configured for this account");
|
|
1886
|
+
}
|
|
1887
|
+
return entry.phone;
|
|
1827
1888
|
};
|
|
1828
1889
|
|
|
1829
1890
|
// src/providers/imessage/types.ts
|
|
1830
1891
|
import { IMessageSDK } from "@photon-ai/imessage-kit";
|
|
1831
1892
|
import z2 from "zod";
|
|
1832
1893
|
var isLocal = (client) => client instanceof IMessageSDK;
|
|
1833
|
-
var clientEntry = z2.object({
|
|
1894
|
+
var clientEntry = z2.object({
|
|
1895
|
+
address: z2.string(),
|
|
1896
|
+
token: z2.string(),
|
|
1897
|
+
phone: z2.string()
|
|
1898
|
+
});
|
|
1834
1899
|
var configSchema = z2.union([
|
|
1835
1900
|
z2.object({ local: z2.literal(true) }),
|
|
1836
1901
|
z2.object({
|
|
@@ -1841,7 +1906,11 @@ var configSchema = z2.union([
|
|
|
1841
1906
|
var userSchema = z2.object({});
|
|
1842
1907
|
var spaceSchema = z2.object({
|
|
1843
1908
|
id: z2.string(),
|
|
1844
|
-
type: z2.enum(["dm", "group"])
|
|
1909
|
+
type: z2.enum(["dm", "group"]),
|
|
1910
|
+
phone: z2.string()
|
|
1911
|
+
});
|
|
1912
|
+
var spaceParamsSchema = z2.object({
|
|
1913
|
+
phone: z2.string().optional()
|
|
1845
1914
|
});
|
|
1846
1915
|
var messageSchema = z2.object({
|
|
1847
1916
|
partIndex: z2.number().int().nonnegative().optional(),
|
|
@@ -1857,11 +1926,48 @@ var imessage = definePlatform("iMessage", {
|
|
|
1857
1926
|
message: MessageEffect2
|
|
1858
1927
|
}
|
|
1859
1928
|
},
|
|
1929
|
+
lifecycle: {
|
|
1930
|
+
createClient: async ({
|
|
1931
|
+
config,
|
|
1932
|
+
projectId,
|
|
1933
|
+
projectSecret
|
|
1934
|
+
}) => {
|
|
1935
|
+
if (config.local) {
|
|
1936
|
+
return new IMessageSDK2();
|
|
1937
|
+
}
|
|
1938
|
+
if (config.clients) {
|
|
1939
|
+
const entries = Array.isArray(config.clients) ? config.clients : [config.clients];
|
|
1940
|
+
return entries.map((e) => ({
|
|
1941
|
+
phone: e.phone,
|
|
1942
|
+
client: createClient2({
|
|
1943
|
+
address: e.address,
|
|
1944
|
+
tls: true,
|
|
1945
|
+
token: e.token
|
|
1946
|
+
})
|
|
1947
|
+
}));
|
|
1948
|
+
}
|
|
1949
|
+
if (!(projectId && projectSecret)) {
|
|
1950
|
+
throw new Error(
|
|
1951
|
+
"iMessage requires projectId and projectSecret. Either pass credentials to Spectrum(), use local mode: imessage.config({ local: true }), or provide explicit client config: imessage.config({ clients: [...] })"
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
return await createCloudClients(projectId, projectSecret);
|
|
1955
|
+
},
|
|
1956
|
+
destroyClient: async ({ client }) => {
|
|
1957
|
+
if (isLocal(client)) {
|
|
1958
|
+
await client.close();
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1961
|
+
await disposeCloudAuth(client);
|
|
1962
|
+
await Promise.all(client.map((entry) => entry.client.close()));
|
|
1963
|
+
}
|
|
1964
|
+
},
|
|
1860
1965
|
user: {
|
|
1861
1966
|
resolve: async ({ input }) => ({ id: input.userID })
|
|
1862
1967
|
},
|
|
1863
1968
|
space: {
|
|
1864
1969
|
schema: spaceSchema,
|
|
1970
|
+
params: spaceParamsSchema,
|
|
1865
1971
|
resolve: async ({ input, client }) => {
|
|
1866
1972
|
if (isLocal(client)) {
|
|
1867
1973
|
throw UnsupportedError.action(
|
|
@@ -1873,55 +1979,26 @@ var imessage = definePlatform("iMessage", {
|
|
|
1873
1979
|
if (input.users.length === 0) {
|
|
1874
1980
|
throw new Error("iMessage space creation requires at least one user");
|
|
1875
1981
|
}
|
|
1982
|
+
if (client.length === 0) {
|
|
1983
|
+
throw new Error("No iMessage clients configured");
|
|
1984
|
+
}
|
|
1985
|
+
const phone = input.params?.phone ?? randomPhone(client);
|
|
1986
|
+
const remote = clientForPhone(client, phone);
|
|
1876
1987
|
const addresses = input.users.map((u) => u.id);
|
|
1877
1988
|
if (input.users.length === 1) {
|
|
1878
1989
|
return {
|
|
1879
1990
|
id: directChat(addresses[0] ?? ""),
|
|
1880
|
-
type: "dm"
|
|
1991
|
+
type: "dm",
|
|
1992
|
+
phone
|
|
1881
1993
|
};
|
|
1882
1994
|
}
|
|
1883
|
-
const remote = client[0];
|
|
1884
|
-
if (!remote) {
|
|
1885
|
-
throw new Error("No remote iMessage client available");
|
|
1886
|
-
}
|
|
1887
1995
|
const { chat } = await remote.chats.create(addresses);
|
|
1888
|
-
return { id: chat.guid, type: "group" };
|
|
1996
|
+
return { id: chat.guid, type: "group", phone };
|
|
1889
1997
|
}
|
|
1890
1998
|
},
|
|
1891
1999
|
message: {
|
|
1892
2000
|
schema: messageSchema
|
|
1893
2001
|
},
|
|
1894
|
-
lifecycle: {
|
|
1895
|
-
createClient: async ({
|
|
1896
|
-
config,
|
|
1897
|
-
projectId,
|
|
1898
|
-
projectSecret
|
|
1899
|
-
}) => {
|
|
1900
|
-
if (config.local) {
|
|
1901
|
-
return new IMessageSDK2();
|
|
1902
|
-
}
|
|
1903
|
-
if (config.clients) {
|
|
1904
|
-
const entries = Array.isArray(config.clients) ? config.clients : [config.clients];
|
|
1905
|
-
return entries.map(
|
|
1906
|
-
(e) => createClient2({ address: e.address, tls: true, token: e.token })
|
|
1907
|
-
);
|
|
1908
|
-
}
|
|
1909
|
-
if (!(projectId && projectSecret)) {
|
|
1910
|
-
throw new Error(
|
|
1911
|
-
"iMessage requires projectId and projectSecret. Either pass credentials to Spectrum(), use local mode: imessage.config({ local: true }), or provide explicit client config: imessage.config({ clients: [...] })"
|
|
1912
|
-
);
|
|
1913
|
-
}
|
|
1914
|
-
return await createCloudClients(projectId, projectSecret);
|
|
1915
|
-
},
|
|
1916
|
-
destroyClient: async ({ client }) => {
|
|
1917
|
-
if (isLocal(client)) {
|
|
1918
|
-
await client.close();
|
|
1919
|
-
return;
|
|
1920
|
-
}
|
|
1921
|
-
await disposeCloudAuth(client);
|
|
1922
|
-
await Promise.all(client.map((c) => c.close()));
|
|
1923
|
-
}
|
|
1924
|
-
},
|
|
1925
2002
|
events: {
|
|
1926
2003
|
messages: ({ client }) => isLocal(client) ? messages2(client) : messages4(client)
|
|
1927
2004
|
},
|
|
@@ -1930,19 +2007,22 @@ var imessage = definePlatform("iMessage", {
|
|
|
1930
2007
|
if (isLocal(client)) {
|
|
1931
2008
|
return await send2(client, space.id, content);
|
|
1932
2009
|
}
|
|
1933
|
-
|
|
2010
|
+
const remote = clientForPhone(client, space.phone);
|
|
2011
|
+
return await send4(remote, space.id, content);
|
|
1934
2012
|
},
|
|
1935
2013
|
startTyping: async ({ space, client }) => {
|
|
1936
2014
|
if (isLocal(client)) {
|
|
1937
2015
|
return;
|
|
1938
2016
|
}
|
|
1939
|
-
|
|
2017
|
+
const remote = clientForPhone(client, space.phone);
|
|
2018
|
+
await startTyping2(remote, space.id);
|
|
1940
2019
|
},
|
|
1941
2020
|
stopTyping: async ({ space, client }) => {
|
|
1942
2021
|
if (isLocal(client)) {
|
|
1943
2022
|
return;
|
|
1944
2023
|
}
|
|
1945
|
-
|
|
2024
|
+
const remote = clientForPhone(client, space.phone);
|
|
2025
|
+
await stopTyping2(remote, space.id);
|
|
1946
2026
|
},
|
|
1947
2027
|
reactToMessage: async ({ space, target, reaction, client }) => {
|
|
1948
2028
|
if (isLocal(client)) {
|
|
@@ -1955,8 +2035,9 @@ var imessage = definePlatform("iMessage", {
|
|
|
1955
2035
|
"iMessage polls do not support reactions"
|
|
1956
2036
|
);
|
|
1957
2037
|
}
|
|
2038
|
+
const remote = clientForPhone(client, space.phone);
|
|
1958
2039
|
await reactToMessage2(
|
|
1959
|
-
|
|
2040
|
+
remote,
|
|
1960
2041
|
space.id,
|
|
1961
2042
|
target,
|
|
1962
2043
|
reaction
|
|
@@ -1973,19 +2054,22 @@ var imessage = definePlatform("iMessage", {
|
|
|
1973
2054
|
"iMessage polls do not support replies"
|
|
1974
2055
|
);
|
|
1975
2056
|
}
|
|
1976
|
-
|
|
2057
|
+
const remote = clientForPhone(client, space.phone);
|
|
2058
|
+
return await replyToMessage2(remote, space.id, messageId, content);
|
|
1977
2059
|
},
|
|
1978
2060
|
editMessage: async ({ space, messageId, content, client }) => {
|
|
1979
2061
|
if (isLocal(client)) {
|
|
1980
2062
|
throw UnsupportedError.action("edit", "iMessage (local mode)");
|
|
1981
2063
|
}
|
|
1982
|
-
|
|
2064
|
+
const remote = clientForPhone(client, space.phone);
|
|
2065
|
+
await editMessage2(remote, space.id, messageId, content);
|
|
1983
2066
|
},
|
|
1984
2067
|
getMessage: async ({ space, messageId, client }) => {
|
|
1985
2068
|
if (isLocal(client)) {
|
|
1986
2069
|
return getMessage2(client, messageId);
|
|
1987
2070
|
}
|
|
1988
|
-
|
|
2071
|
+
const remote = clientForPhone(client, space.phone);
|
|
2072
|
+
return getMessage4(remote, space.id, messageId, space.phone);
|
|
1989
2073
|
}
|
|
1990
2074
|
}
|
|
1991
2075
|
});
|