@photon-ai/advanced-imessage-kit 1.14.2 → 1.16.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/README.md +169 -12
- package/dist/index.cjs +72 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -3
- package/dist/index.d.ts +56 -3
- package/dist/index.js +72 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,23 @@
|
|
|
14
14
|
|
|
15
15
|
Advanced iMessage Kit is a full-featured iMessage SDK for **reading**, **sending**, and **automating** iMessage conversations on macOS. Perfect for building **AI agents**, **automation tools**, and **chat applications**.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## Enterprise
|
|
18
|
+
|
|
19
|
+
**Advanced iMessage Kit** is the **enterprise edition** provided by **[Photon](https://photon.codes)**.
|
|
20
|
+
|
|
21
|
+
- **Provisioned iMessage Numbers** – Dedicated numbers ready for production use
|
|
22
|
+
- **Managed Hosting** – Fully managed infrastructure for reliability and scale
|
|
23
|
+
- **DevOps & Deployment Support** – Production setup, monitoring, and scaling
|
|
24
|
+
- **Enterprise Support** – Direct support and custom integrations
|
|
25
|
+
|
|
26
|
+
📩 **Enterprise inquiries:**
|
|
27
|
+
Contact **daniel@photon.codes**
|
|
28
|
+
|
|
29
|
+
🌐 **Book a Demo:**
|
|
30
|
+
https://photon.codes
|
|
31
|
+
|
|
32
|
+
If you're looking for the **free/open-source version**, please use **[iMessage Kit](https://github.com/photon-hq/imessage-kit)** instead.
|
|
33
|
+
|
|
18
34
|
|
|
19
35
|
## Features
|
|
20
36
|
|
|
@@ -23,6 +39,8 @@ Advanced iMessage Kit is a full-featured iMessage SDK for **reading**, **sending
|
|
|
23
39
|
| [Send Messages](#send-messages) | Send text messages to any contact | `messages.sendMessage()` | [message-send.ts](./examples/message-send.ts) |
|
|
24
40
|
| [Reply to Messages](#send-messages) | Reply inline to a specific message | `messages.sendMessage()` | [message-reply.ts](./examples/message-reply.ts) |
|
|
25
41
|
| [Message Effects](#send-messages) | Send with effects (confetti, fireworks, etc.) | `messages.sendMessage()` | [message-effects.ts](./examples/message-effects.ts) |
|
|
42
|
+
| [Text Styles](#text-styles--animations) | Bold, italic, underline, strikethrough | `messages.sendMessage()` | [message-styled.ts](./examples/message-styled.ts) |
|
|
43
|
+
| [Text Animations](#text-styles--animations) | Per-character animations (shake, ripple, etc.)| `messages.sendMessage()` | [message-styled.ts](./examples/message-styled.ts) |
|
|
26
44
|
| [Send Rich Links](#send-messages) | Send URLs with rich link previews | `messages.sendMessage()` | [message-rich-link.ts](./examples/message-rich-link.ts) |
|
|
27
45
|
| [Schedule Messages](#scheduled-messages) | Send once or on a recurring schedule | `scheduledMessages.createScheduledMessage()` | [scheduled-message-once.ts](./examples/scheduled-message-once.ts) |
|
|
28
46
|
| [Unsend Messages](#unsend-messages) | Retract a sent message | `messages.unsendMessage()` | [message-unsend.ts](./examples/message-unsend.ts) |
|
|
@@ -49,6 +67,7 @@ Advanced iMessage Kit is a full-featured iMessage SDK for **reading**, **sending
|
|
|
49
67
|
| [Vote on Polls](#vote-on-polls) | Vote or unvote on poll options | `polls.vote()` | [poll-vote.ts](./examples/poll-vote.ts) |
|
|
50
68
|
| [Add Poll Options](#add-poll-options) | Add options to existing polls | `polls.addOption()` | [poll-add-option.ts](./examples/poll-add-option.ts) |
|
|
51
69
|
| [Find My Friends](#find-my-friends) | Get friends' locations | `icloud.refreshFindMyFriends()` | [findmy-friends.ts](./examples/findmy-friends.ts) |
|
|
70
|
+
| [Find My Watch](#find-my-watch) | Watch friends' location changes in real-time | `icloud.refreshFindMyFriends()` | [findmy-watch.ts](./examples/findmy-watch.ts) |
|
|
52
71
|
| [Set Chat Background](#chat-background) | Set custom background image for chat | `chats.setBackground()` | [background-set.ts](./examples/background-set.ts) |
|
|
53
72
|
| [Remove Chat Background](#chat-background) | Remove background from chat | `chats.removeBackground()` | [background-remove.ts](./examples/background-remove.ts) |
|
|
54
73
|
| [Real-time Events](#real-time-events) | Listen for new messages, typing, etc. | `sdk.on()` | [listen-simple.ts](./examples/listen-simple.ts) |
|
|
@@ -100,6 +119,15 @@ interface ClientConfig {
|
|
|
100
119
|
}
|
|
101
120
|
```
|
|
102
121
|
|
|
122
|
+
### Remote Server Setup
|
|
123
|
+
|
|
124
|
+
If your SDK code runs on a different machine than the iMessage server:
|
|
125
|
+
|
|
126
|
+
- `serverUrl` points to the server machine
|
|
127
|
+
- `filePath` points to the SDK machine
|
|
128
|
+
|
|
129
|
+
The SDK reads local files first, then uploads the file bytes to the server.
|
|
130
|
+
|
|
103
131
|
---
|
|
104
132
|
|
|
105
133
|
## Core Concepts
|
|
@@ -190,6 +218,71 @@ await sdk.messages.sendMessage({
|
|
|
190
218
|
|
|
191
219
|
> Example: [message-effects.ts](./examples/message-effects.ts)
|
|
192
220
|
|
|
221
|
+
### Text Styles & Animations
|
|
222
|
+
|
|
223
|
+
Apply per-range text formatting and whole-message character animations (requires Private API):
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// Bold a portion of text
|
|
227
|
+
await sdk.messages.sendMessage({
|
|
228
|
+
chatGuid: "iMessage;-;+1234567890",
|
|
229
|
+
message: "This is bold text",
|
|
230
|
+
textStyles: [{ start: 8, end: 12, bold: true }],
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Multiple styles in one message
|
|
234
|
+
await sdk.messages.sendMessage({
|
|
235
|
+
chatGuid: "iMessage;-;+1234567890",
|
|
236
|
+
message: "Bold here, italic there",
|
|
237
|
+
textStyles: [
|
|
238
|
+
{ start: 0, end: 9, bold: true },
|
|
239
|
+
{ start: 11, end: 23, italic: true },
|
|
240
|
+
],
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Character animation (applies to whole message)
|
|
244
|
+
await sdk.messages.sendMessage({
|
|
245
|
+
chatGuid: "iMessage;-;+1234567890",
|
|
246
|
+
message: "Ripple wave!",
|
|
247
|
+
textAnimation: "ripple",
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Combine all three layers
|
|
251
|
+
await sdk.messages.sendMessage({
|
|
252
|
+
chatGuid: "iMessage;-;+1234567890",
|
|
253
|
+
message: "Bold shaking fireworks!",
|
|
254
|
+
textStyles: [{ start: 0, end: 4, bold: true }],
|
|
255
|
+
textAnimation: "shake",
|
|
256
|
+
effectId: "com.apple.messages.effect.CKFireworksEffect",
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Text Style Properties** (per range):
|
|
261
|
+
|
|
262
|
+
| Property | Type | Description |
|
|
263
|
+
| --------------- | ------- | -------------- |
|
|
264
|
+
| `start` | number | Start index |
|
|
265
|
+
| `end` | number | End index |
|
|
266
|
+
| `bold` | boolean | Bold |
|
|
267
|
+
| `italic` | boolean | Italic |
|
|
268
|
+
| `underline` | boolean | Underline |
|
|
269
|
+
| `strikethrough` | boolean | Strikethrough |
|
|
270
|
+
|
|
271
|
+
**Text Animations** (whole message):
|
|
272
|
+
|
|
273
|
+
| `textAnimation` | Description |
|
|
274
|
+
| --------------- | ----------- |
|
|
275
|
+
| `"big"` | Big |
|
|
276
|
+
| `"small"` | Small |
|
|
277
|
+
| `"shake"` | Shake |
|
|
278
|
+
| `"nod"` | Nod |
|
|
279
|
+
| `"explode"` | Explode |
|
|
280
|
+
| `"ripple"` | Ripple |
|
|
281
|
+
| `"bloom"` | Bloom |
|
|
282
|
+
| `"jitter"` | Jitter |
|
|
283
|
+
|
|
284
|
+
> Example: [message-styled.ts](./examples/message-styled.ts)
|
|
285
|
+
|
|
193
286
|
### Query Messages
|
|
194
287
|
|
|
195
288
|
```typescript
|
|
@@ -337,7 +430,7 @@ const updated = await sdk.scheduledMessages.updateScheduledMessage(
|
|
|
337
430
|
},
|
|
338
431
|
scheduledFor: Date.now() + 10 * 60 * 1000,
|
|
339
432
|
schedule: { type: "once" },
|
|
340
|
-
}
|
|
433
|
+
},
|
|
341
434
|
);
|
|
342
435
|
|
|
343
436
|
await sdk.scheduledMessages.deleteScheduledMessage("scheduled-id");
|
|
@@ -528,6 +621,38 @@ const message = await sdk.attachments.sendAttachment({
|
|
|
528
621
|
});
|
|
529
622
|
```
|
|
530
623
|
|
|
624
|
+
### Send Multiple Images In One Request
|
|
625
|
+
|
|
626
|
+
Use `sendMultipartMessage()` when you want to send multiple images together as one multipart iMessage request:
|
|
627
|
+
|
|
628
|
+
```typescript
|
|
629
|
+
const message = await sdk.messages.sendMultipartMessage({
|
|
630
|
+
chatGuid: "iMessage;+;chat123456789",
|
|
631
|
+
parts: [
|
|
632
|
+
{
|
|
633
|
+
partIndex: 0,
|
|
634
|
+
filePath: "/path/to/image-1.jpg",
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
partIndex: 1,
|
|
638
|
+
filePath: "/path/to/image-2.jpg",
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
partIndex: 2,
|
|
642
|
+
filePath: "/path/to/image-3.jpg",
|
|
643
|
+
},
|
|
644
|
+
],
|
|
645
|
+
});
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
Notes:
|
|
649
|
+
- `sendMultipartMessage()` uploads each file first, then sends all parts together in a single `/api/v1/message/multipart` request.
|
|
650
|
+
- This requires the Private API path on the server.
|
|
651
|
+
- The target `chatGuid` must already exist. If you only have a phone number/email, create or fetch the chat first.
|
|
652
|
+
- If the SDK and server are on different machines, each `filePath` must exist on the SDK machine. The SDK uploads the file bytes to the server before sending.
|
|
653
|
+
|
|
654
|
+
> Example: [message-multipart-images.ts](./examples/message-multipart-images.ts)
|
|
655
|
+
|
|
531
656
|
### Send Audio Messages
|
|
532
657
|
|
|
533
658
|
```typescript
|
|
@@ -595,9 +720,8 @@ const buffer = await sdk.attachments.downloadAttachment("attachment-guid", {
|
|
|
595
720
|
});
|
|
596
721
|
|
|
597
722
|
// Download Live Photo video
|
|
598
|
-
const liveBuffer =
|
|
599
|
-
"attachment-guid"
|
|
600
|
-
);
|
|
723
|
+
const liveBuffer =
|
|
724
|
+
await sdk.attachments.downloadAttachmentLive("attachment-guid");
|
|
601
725
|
|
|
602
726
|
// Get blurhash (for placeholders)
|
|
603
727
|
const blurhash = await sdk.attachments.getAttachmentBlurhash("attachment-guid");
|
|
@@ -686,11 +810,11 @@ Check if a phone/email supports iMessage or FaceTime:
|
|
|
686
810
|
// First parameter is the address (phone or email), not handle guid
|
|
687
811
|
const hasIMessage = await sdk.handles.getHandleAvailability(
|
|
688
812
|
"+1234567890",
|
|
689
|
-
"imessage"
|
|
813
|
+
"imessage",
|
|
690
814
|
);
|
|
691
815
|
const hasFaceTime = await sdk.handles.getHandleAvailability(
|
|
692
816
|
"+1234567890",
|
|
693
|
-
"facetime"
|
|
817
|
+
"facetime",
|
|
694
818
|
);
|
|
695
819
|
|
|
696
820
|
// Choose service based on availability
|
|
@@ -852,7 +976,7 @@ sdk.on("new-message", (message) => {
|
|
|
852
976
|
|
|
853
977
|
## iCloud
|
|
854
978
|
|
|
855
|
-
>
|
|
979
|
+
> Examples: [findmy-friends.ts](./examples/findmy-friends.ts) | [findmy-watch.ts](./examples/findmy-watch.ts)
|
|
856
980
|
|
|
857
981
|
### Find My Friends
|
|
858
982
|
|
|
@@ -870,10 +994,10 @@ const locations = await sdk.icloud.refreshFindMyFriends();
|
|
|
870
994
|
const friend = locations.find((loc) => loc.handle === "+1234567890");
|
|
871
995
|
if (friend) {
|
|
872
996
|
console.log(
|
|
873
|
-
`Coordinates: ${friend.coordinates[0]}, ${friend.coordinates[1]}
|
|
997
|
+
`Coordinates: ${friend.coordinates[0]}, ${friend.coordinates[1]}`,
|
|
874
998
|
);
|
|
875
999
|
console.log(
|
|
876
|
-
`Maps: https://maps.google.com/?q=${friend.coordinates[0]},${friend.coordinates[1]}
|
|
1000
|
+
`Maps: https://maps.google.com/?q=${friend.coordinates[0]},${friend.coordinates[1]}`,
|
|
877
1001
|
);
|
|
878
1002
|
if (friend.long_address) console.log(`Address: ${friend.long_address}`);
|
|
879
1003
|
}
|
|
@@ -887,6 +1011,37 @@ for (const loc of locations) {
|
|
|
887
1011
|
|
|
888
1012
|
> Example: [findmy-friends.ts](./examples/findmy-friends.ts)
|
|
889
1013
|
|
|
1014
|
+
### Find My Watch
|
|
1015
|
+
|
|
1016
|
+
Watch friends' location changes in real-time. Fetches initial locations on connect, then listens for live updates via the `new-findmy-location` event (server auto-refreshes every 30s):
|
|
1017
|
+
|
|
1018
|
+
```typescript
|
|
1019
|
+
import type { FindMyLocationItem } from "@photon-ai/advanced-imessage-kit";
|
|
1020
|
+
|
|
1021
|
+
// Fetch initial locations on ready
|
|
1022
|
+
sdk.on("ready", async () => {
|
|
1023
|
+
const locations = await sdk.icloud.refreshFindMyFriends();
|
|
1024
|
+
for (const loc of locations) {
|
|
1025
|
+
console.log(`${loc.handle}`);
|
|
1026
|
+
console.log(` Coordinates: ${loc.coordinates[0]}, ${loc.coordinates[1]}`);
|
|
1027
|
+
console.log(
|
|
1028
|
+
` Maps: https://maps.google.com/?q=${loc.coordinates[0]},${loc.coordinates[1]}`,
|
|
1029
|
+
);
|
|
1030
|
+
if (loc.long_address) console.log(` Address: ${loc.long_address}`);
|
|
1031
|
+
}
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
// Listen for real-time location updates
|
|
1035
|
+
sdk.on("new-findmy-location", (location: FindMyLocationItem) => {
|
|
1036
|
+
console.log(`${location.handle} updated:`);
|
|
1037
|
+
console.log(
|
|
1038
|
+
` Coordinates: ${location.coordinates[0]}, ${location.coordinates[1]}`,
|
|
1039
|
+
);
|
|
1040
|
+
});
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
> Example: [findmy-watch.ts](./examples/findmy-watch.ts)
|
|
1044
|
+
|
|
890
1045
|
---
|
|
891
1046
|
|
|
892
1047
|
## Real-time Events
|
|
@@ -1083,8 +1238,9 @@ bun run examples/<filename>.ts
|
|
|
1083
1238
|
| [message-unsend.ts](./examples/message-unsend.ts) | Unsend messages |
|
|
1084
1239
|
| [message-edit.ts](./examples/message-edit.ts) | Edit messages |
|
|
1085
1240
|
| [message-reaction.ts](./examples/message-reaction.ts) | Send Tapbacks |
|
|
1086
|
-
| [message-effects.ts](./examples/message-effects.ts) | Message effects
|
|
1087
|
-
| [message-
|
|
1241
|
+
| [message-effects.ts](./examples/message-effects.ts) | Message effects |
|
|
1242
|
+
| [message-styled.ts](./examples/message-styled.ts) | Text styles & animations |
|
|
1243
|
+
| [message-search.ts](./examples/message-search.ts) | Search messages |
|
|
1088
1244
|
| [message-history.ts](./examples/message-history.ts) | Message history |
|
|
1089
1245
|
| [message-destination-caller-id.ts](./examples/message-destination-caller-id.ts) | Destination caller ID |
|
|
1090
1246
|
|
|
@@ -1132,6 +1288,7 @@ bun run examples/<filename>.ts
|
|
|
1132
1288
|
| [server-info.ts](./examples/server-info.ts) | Server info and logs |
|
|
1133
1289
|
| [message-stats.ts](./examples/message-stats.ts) | Message statistics |
|
|
1134
1290
|
| [findmy-friends.ts](./examples/findmy-friends.ts) | Find My Friends |
|
|
1291
|
+
| [findmy-watch.ts](./examples/findmy-watch.ts) | Find My Watch |
|
|
1135
1292
|
| [auto-reply-hey.ts](./examples/auto-reply-hey.ts) | Auto reply bot |
|
|
1136
1293
|
|
|
1137
1294
|
---
|
package/dist/index.cjs
CHANGED
|
@@ -164,14 +164,16 @@ function extractService(chatGuid) {
|
|
|
164
164
|
return void 0;
|
|
165
165
|
}
|
|
166
166
|
async function createChatWithMessage(options) {
|
|
167
|
-
const { http, address, message, tempGuid, subject,
|
|
167
|
+
const { http, address, message, tempGuid, subject, bubbleEffect, textStyles, textAnimation, service } = options;
|
|
168
168
|
try {
|
|
169
169
|
const response = await http.post("/api/v1/chat/new", {
|
|
170
170
|
addresses: [address],
|
|
171
171
|
message,
|
|
172
172
|
tempGuid,
|
|
173
173
|
subject,
|
|
174
|
-
|
|
174
|
+
bubbleEffect,
|
|
175
|
+
textStyles,
|
|
176
|
+
textAnimation,
|
|
175
177
|
...service && { service }
|
|
176
178
|
});
|
|
177
179
|
return response.data.data?.guid;
|
|
@@ -529,6 +531,15 @@ var MessageModule = class {
|
|
|
529
531
|
this.http = http;
|
|
530
532
|
this.enqueueSend = enqueueSend;
|
|
531
533
|
}
|
|
534
|
+
async uploadMultipartAttachment(part, fileName = part.fileName || path__namespace.default.basename(part.filePath)) {
|
|
535
|
+
const fileBuffer = await promises.readFile(part.filePath);
|
|
536
|
+
const form = new FormData__default.default();
|
|
537
|
+
form.append("attachment", fileBuffer, fileName);
|
|
538
|
+
const response = await this.http.post("/api/v1/attachment/upload", form, {
|
|
539
|
+
headers: form.getHeaders()
|
|
540
|
+
});
|
|
541
|
+
return response.data.data.path;
|
|
542
|
+
}
|
|
532
543
|
async sendMessage(options) {
|
|
533
544
|
return this.enqueueSend(async () => {
|
|
534
545
|
const tempGuid = options.tempGuid || crypto.randomUUID();
|
|
@@ -547,13 +558,70 @@ var MessageModule = class {
|
|
|
547
558
|
message: options.message,
|
|
548
559
|
tempGuid,
|
|
549
560
|
subject: options.subject,
|
|
550
|
-
|
|
561
|
+
bubbleEffect: options.bubbleEffect,
|
|
562
|
+
textStyles: options.textStyles,
|
|
563
|
+
textAnimation: options.textAnimation,
|
|
551
564
|
service
|
|
552
565
|
});
|
|
553
566
|
return { guid: tempGuid, text: options.message, dateCreated: Date.now() };
|
|
554
567
|
}
|
|
555
568
|
});
|
|
556
569
|
}
|
|
570
|
+
async sendMultipartMessage(options) {
|
|
571
|
+
return this.enqueueSend(async () => {
|
|
572
|
+
const tempGuid = options.tempGuid || crypto.randomUUID();
|
|
573
|
+
const buildPayloadPart = async (part, index) => {
|
|
574
|
+
const resolvedPartIndex = part.partIndex ?? index;
|
|
575
|
+
if ("text" in part) {
|
|
576
|
+
return {
|
|
577
|
+
partIndex: resolvedPartIndex,
|
|
578
|
+
text: part.text,
|
|
579
|
+
...part.mention ? { mention: part.mention } : {}
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
const fileName = part.fileName || path__namespace.default.basename(part.filePath);
|
|
583
|
+
const uploadedPath = await this.uploadMultipartAttachment(part, fileName);
|
|
584
|
+
return {
|
|
585
|
+
partIndex: resolvedPartIndex,
|
|
586
|
+
attachment: uploadedPath,
|
|
587
|
+
name: fileName
|
|
588
|
+
};
|
|
589
|
+
};
|
|
590
|
+
const uploadParts = async () => {
|
|
591
|
+
const parts = [];
|
|
592
|
+
for (const [index, part] of options.parts.entries()) {
|
|
593
|
+
parts.push(await buildPayloadPart(part, index));
|
|
594
|
+
}
|
|
595
|
+
return parts;
|
|
596
|
+
};
|
|
597
|
+
const send = async (chatGuid) => {
|
|
598
|
+
const parts = await uploadParts();
|
|
599
|
+
const payload = {
|
|
600
|
+
chatGuid,
|
|
601
|
+
tempGuid,
|
|
602
|
+
parts,
|
|
603
|
+
subject: options.subject,
|
|
604
|
+
effectId: options.effectId,
|
|
605
|
+
selectedMessageGuid: options.selectedMessageGuid,
|
|
606
|
+
partIndex: options.partIndex ?? 0,
|
|
607
|
+
ddScan: options.ddScan ?? false,
|
|
608
|
+
attributedBody: options.attributedBody
|
|
609
|
+
};
|
|
610
|
+
const response = await this.http.post("/api/v1/message/multipart", payload);
|
|
611
|
+
return response.data.data;
|
|
612
|
+
};
|
|
613
|
+
try {
|
|
614
|
+
return await send(options.chatGuid);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
if (isChatNotExistError(error)) {
|
|
617
|
+
throw new Error(
|
|
618
|
+
"Chat does not exist for multipart send. Use an existing chatGuid, or create the chat first before calling sendMultipartMessage()."
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
throw error;
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
}
|
|
557
625
|
async getMessage(guid, options) {
|
|
558
626
|
const response = await this.http.get(`/api/v1/message/${encodeURIComponent(guid)}`, {
|
|
559
627
|
params: options?.with ? { with: options.with.join(",") } : {}
|
|
@@ -919,6 +987,7 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
919
987
|
"new-server",
|
|
920
988
|
"incoming-facetime",
|
|
921
989
|
"ft-call-status-changed",
|
|
990
|
+
"new-findmy-location",
|
|
922
991
|
"hello-world"
|
|
923
992
|
];
|
|
924
993
|
for (const eventName of serverEvents) {
|