@photon-ai/advanced-imessage-kit 1.11.0 → 1.11.2
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 +72 -41
- package/dist/index.cjs +85 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +85 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,37 +18,39 @@ Advanced iMessage Kit is a full-featured iMessage SDK for **reading**, **sending
|
|
|
18
18
|
|
|
19
19
|
## Features
|
|
20
20
|
|
|
21
|
-
| Feature | Description | Method
|
|
22
|
-
| ---------------------------------------------------------- | --------------------------------------------- |
|
|
23
|
-
| [Send Messages](#send-messages) | Send text messages to any contact | `messages.sendMessage()`
|
|
24
|
-
| [Reply to Messages](#send-messages) | Reply inline to a specific message | `messages.sendMessage()`
|
|
25
|
-
| [Message Effects](#send-messages) | Send with effects (confetti, fireworks, etc.) | `messages.sendMessage()`
|
|
21
|
+
| Feature | Description | Method | Example |
|
|
22
|
+
| ---------------------------------------------------------- | --------------------------------------------- | -------------------------------------------- | ----------------------------------------------------------------- |
|
|
23
|
+
| [Send Messages](#send-messages) | Send text messages to any contact | `messages.sendMessage()` | [message-send.ts](./examples/message-send.ts) |
|
|
24
|
+
| [Reply to Messages](#send-messages) | Reply inline to a specific message | `messages.sendMessage()` | [message-reply.ts](./examples/message-reply.ts) |
|
|
25
|
+
| [Message Effects](#send-messages) | Send with effects (confetti, fireworks, etc.) | `messages.sendMessage()` | [message-effects.ts](./examples/message-effects.ts) |
|
|
26
26
|
| [Schedule Messages](#scheduled-messages) | Send once or on a recurring schedule | `scheduledMessages.createScheduledMessage()` | [scheduled-message-once.ts](./examples/scheduled-message-once.ts) |
|
|
27
|
-
| [Unsend Messages](#unsend-messages) | Retract a sent message | `messages.unsendMessage()`
|
|
28
|
-
| [Edit Messages](#edit-messages) | Edit a sent message | `messages.editMessage()`
|
|
29
|
-
| [Send Tapbacks](#send-tapbacks) | React with ❤️ 👍 👎 😂 ‼️ ❓ | `messages.sendReaction()`
|
|
30
|
-
| [Query Messages](#query-messages) | Search and filter message history | `messages.getMessages()`
|
|
31
|
-
| [Message History](#get-chat-messages) | View messages, reactions, polls, stickers | `chats.getChatMessages()`
|
|
32
|
-
| [Send Attachments](#send-attachments) | Send images, files, documents | `attachments.sendAttachment()`
|
|
33
|
-
| [Send Audio Messages](#send-audio-messages) | Send voice messages | `attachments.sendAttachment()`
|
|
34
|
-
| [Send Stickers](#send-stickers) | Send sticker as standalone message | `attachments.sendSticker()`
|
|
35
|
-
| [Reply Stickers](#send-stickers) | Attach sticker to a message bubble | `attachments.sendSticker()`
|
|
36
|
-
| [Download Attachments](#download-attachments) | Download received files and media | `attachments.downloadAttachment()`
|
|
37
|
-
| [Get Chats](#get-chats) | List all conversations | `chats.getChats()`
|
|
38
|
-
| [Get Chat Participants](#get-chat-participants) | View group chat participants | `chats.getChat()`
|
|
39
|
-
| [Manage Group Chats](#manage-group-chats) | Add/remove members, rename groups | `chats.addParticipant()`
|
|
40
|
-
| [Typing Indicators](#typing-indicators) | Show "typing..." status | `chats.startTyping()`
|
|
41
|
-
| [Get Contacts](#get-contacts) | Fetch device contacts | `contacts.getContacts()`
|
|
42
|
-
| [Share Contact Card](#share-contact-card) | Share your contact info in chat | `contacts.shareContactCard()`
|
|
43
|
-
| [Check iMessage Availability](#check-service-availability) | Verify if contact uses iMessage | `handles.getHandleAvailability()`
|
|
44
|
-
| [Server Info](#get-server-info) | Get server status and config | `server.getServerInfo()`
|
|
45
|
-
| [Message Statistics](#message-statistics) | Get message counts and analytics | `server.getMessageStats()`
|
|
46
|
-
| [Create Polls](#create-polls) | Create interactive polls in chat | `polls.create()`
|
|
47
|
-
| [Vote on Polls](#vote-on-polls) | Vote or unvote on poll options | `polls.vote()`
|
|
48
|
-
| [Add Poll Options](#add-poll-options) | Add options to existing polls | `polls.addOption()`
|
|
49
|
-
| [Find My Friends](#find-my-friends) | Get friends' locations | `icloud.refreshFindMyFriends()`
|
|
50
|
-
| [
|
|
51
|
-
| [
|
|
27
|
+
| [Unsend Messages](#unsend-messages) | Retract a sent message | `messages.unsendMessage()` | [message-unsend.ts](./examples/message-unsend.ts) |
|
|
28
|
+
| [Edit Messages](#edit-messages) | Edit a sent message | `messages.editMessage()` | [message-edit.ts](./examples/message-edit.ts) |
|
|
29
|
+
| [Send Tapbacks](#send-tapbacks) | React with ❤️ 👍 👎 😂 ‼️ ❓ | `messages.sendReaction()` | [message-reaction.ts](./examples/message-reaction.ts) |
|
|
30
|
+
| [Query Messages](#query-messages) | Search and filter message history | `messages.getMessages()` | [message-search.ts](./examples/message-search.ts) |
|
|
31
|
+
| [Message History](#get-chat-messages) | View messages, reactions, polls, stickers | `chats.getChatMessages()` | [message-history.ts](./examples/message-history.ts) |
|
|
32
|
+
| [Send Attachments](#send-attachments) | Send images, files, documents | `attachments.sendAttachment()` | [message-attachment.ts](./examples/message-attachment.ts) |
|
|
33
|
+
| [Send Audio Messages](#send-audio-messages) | Send voice messages | `attachments.sendAttachment()` | [message-audio.ts](./examples/message-audio.ts) |
|
|
34
|
+
| [Send Stickers](#send-stickers) | Send sticker as standalone message | `attachments.sendSticker()` | [message-sticker.ts](./examples/message-sticker.ts) |
|
|
35
|
+
| [Reply Stickers](#send-stickers) | Attach sticker to a message bubble | `attachments.sendSticker()` | [message-reply-sticker.ts](./examples/message-reply-sticker.ts) |
|
|
36
|
+
| [Download Attachments](#download-attachments) | Download received files and media | `attachments.downloadAttachment()` | [attachment-download.ts](./examples/attachment-download.ts) |
|
|
37
|
+
| [Get Chats](#get-chats) | List all conversations | `chats.getChats()` | [chat-fetch.ts](./examples/chat-fetch.ts) |
|
|
38
|
+
| [Get Chat Participants](#get-chat-participants) | View group chat participants | `chats.getChat()` | [chat-participants.ts](./examples/chat-participants.ts) |
|
|
39
|
+
| [Manage Group Chats](#manage-group-chats) | Add/remove members, rename groups | `chats.addParticipant()` | [chat-group.ts](./examples/chat-group.ts) |
|
|
40
|
+
| [Typing Indicators](#typing-indicators) | Show "typing..." status | `chats.startTyping()` | [message-typing.ts](./examples/message-typing.ts) |
|
|
41
|
+
| [Get Contacts](#get-contacts) | Fetch device contacts | `contacts.getContacts()` | [contact-list.ts](./examples/contact-list.ts) |
|
|
42
|
+
| [Share Contact Card](#share-contact-card) | Share your contact info in chat | `contacts.shareContactCard()` | [message-contact-card.ts](./examples/message-contact-card.ts) |
|
|
43
|
+
| [Check iMessage Availability](#check-service-availability) | Verify if contact uses iMessage | `handles.getHandleAvailability()` | [service-check.ts](./examples/service-check.ts) |
|
|
44
|
+
| [Server Info](#get-server-info) | Get server status and config | `server.getServerInfo()` | [server-info.ts](./examples/server-info.ts) |
|
|
45
|
+
| [Message Statistics](#message-statistics) | Get message counts and analytics | `server.getMessageStats()` | [message-stats.ts](./examples/message-stats.ts) |
|
|
46
|
+
| [Create Polls](#create-polls) | Create interactive polls in chat | `polls.create()` | [poll-create.ts](./examples/poll-create.ts) |
|
|
47
|
+
| [Vote on Polls](#vote-on-polls) | Vote or unvote on poll options | `polls.vote()` | [poll-vote.ts](./examples/poll-vote.ts) |
|
|
48
|
+
| [Add Poll Options](#add-poll-options) | Add options to existing polls | `polls.addOption()` | [poll-add-option.ts](./examples/poll-add-option.ts) |
|
|
49
|
+
| [Find My Friends](#find-my-friends) | Get friends' locations | `icloud.refreshFindMyFriends()` | [findmy-friends.ts](./examples/findmy-friends.ts) |
|
|
50
|
+
| [Set Chat Background](#chat-background) | Set custom background image for chat | `chats.setBackground()` | [background-set.ts](./examples/background-set.ts) |
|
|
51
|
+
| [Remove Chat Background](#chat-background) | Remove background from chat | `chats.removeBackground()` | [background-remove.ts](./examples/background-remove.ts) |
|
|
52
|
+
| [Real-time Events](#real-time-events) | Listen for new messages, typing, etc. | `sdk.on()` | [listen-simple.ts](./examples/listen-simple.ts) |
|
|
53
|
+
| [Auto Reply](#real-time-events) | Build automated reply bots | `sdk.on()` | [auto-reply-hey.ts](./examples/auto-reply-hey.ts) |
|
|
52
54
|
|
|
53
55
|
---
|
|
54
56
|
|
|
@@ -314,16 +316,19 @@ const daily = await sdk.scheduledMessages.createScheduledMessage({
|
|
|
314
316
|
```typescript
|
|
315
317
|
const scheduledMessages = await sdk.scheduledMessages.getScheduledMessages();
|
|
316
318
|
|
|
317
|
-
const updated = await sdk.scheduledMessages.updateScheduledMessage(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
319
|
+
const updated = await sdk.scheduledMessages.updateScheduledMessage(
|
|
320
|
+
"scheduled-id",
|
|
321
|
+
{
|
|
322
|
+
type: "send-message",
|
|
323
|
+
payload: {
|
|
324
|
+
chatGuid: "any;-;+1234567890",
|
|
325
|
+
message: "Updated message!",
|
|
326
|
+
method: "apple-script",
|
|
327
|
+
},
|
|
328
|
+
scheduledFor: Date.now() + 10 * 60 * 1000,
|
|
329
|
+
schedule: { type: "once" },
|
|
330
|
+
}
|
|
331
|
+
);
|
|
327
332
|
|
|
328
333
|
await sdk.scheduledMessages.deleteScheduledMessage("scheduled-id");
|
|
329
334
|
```
|
|
@@ -332,7 +337,7 @@ await sdk.scheduledMessages.deleteScheduledMessage("scheduled-id");
|
|
|
332
337
|
|
|
333
338
|
## Chats
|
|
334
339
|
|
|
335
|
-
> Examples: [chat-fetch.ts](./examples/chat-fetch.ts) | [chat-group.ts](./examples/chat-group.ts) | [message-typing.ts](./examples/message-typing.ts)
|
|
340
|
+
> Examples: [chat-fetch.ts](./examples/chat-fetch.ts) | [chat-group.ts](./examples/chat-group.ts) | [message-typing.ts](./examples/message-typing.ts) | [background-set.ts](./examples/background-set.ts) | [background-remove.ts](./examples/background-remove.ts)
|
|
336
341
|
|
|
337
342
|
### Get Chats
|
|
338
343
|
|
|
@@ -466,6 +471,30 @@ await sdk.chats.removeGroupIcon("chat-guid");
|
|
|
466
471
|
|
|
467
472
|
> Example: [chat-group.ts](./examples/chat-group.ts)
|
|
468
473
|
|
|
474
|
+
### Chat Background
|
|
475
|
+
|
|
476
|
+
Set, get, or remove custom background images for individual chats:
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
// Get current background info
|
|
480
|
+
const bgInfo = await sdk.chats.getBackground("chat-guid");
|
|
481
|
+
console.log(`Has background: ${bgInfo.hasBackground}`);
|
|
482
|
+
if (bgInfo.hasBackground) {
|
|
483
|
+
console.log(`Background ID: ${bgInfo.backgroundId}`);
|
|
484
|
+
console.log(`Image URL: ${bgInfo.imageUrl}`);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Set a background image
|
|
488
|
+
await sdk.chats.setBackground("chat-guid", {
|
|
489
|
+
filePath: "/path/to/image.png",
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// Remove background
|
|
493
|
+
await sdk.chats.removeBackground("chat-guid");
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
> Examples: [background-set.ts](./examples/background-set.ts) | [background-remove.ts](./examples/background-remove.ts)
|
|
497
|
+
|
|
469
498
|
---
|
|
470
499
|
|
|
471
500
|
## Attachments
|
|
@@ -1049,6 +1078,8 @@ bun run examples/<filename>.ts
|
|
|
1049
1078
|
| [chat-participants.ts](./examples/chat-participants.ts) | Get group participants |
|
|
1050
1079
|
| [chat-group.ts](./examples/chat-group.ts) | Manage groups |
|
|
1051
1080
|
| [message-typing.ts](./examples/message-typing.ts) | Typing indicators |
|
|
1081
|
+
| [background-set.ts](./examples/background-set.ts) | Set chat background |
|
|
1082
|
+
| [background-remove.ts](./examples/background-remove.ts) | Remove chat background |
|
|
1052
1083
|
|
|
1053
1084
|
### Contacts & Services
|
|
1054
1085
|
|
package/dist/index.cjs
CHANGED
|
@@ -769,6 +769,8 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
769
769
|
// the same message content with different GUIDs due to unstable Socket.IO connections.
|
|
770
770
|
// This is especially problematic when the polling transport causes connection issues.
|
|
771
771
|
__publicField(this, "processedMessages", /* @__PURE__ */ new Set());
|
|
772
|
+
// Last message timestamp for reconnect recovery
|
|
773
|
+
__publicField(this, "lastMessageTime", 0);
|
|
772
774
|
// Send queue for sequential message delivery
|
|
773
775
|
//
|
|
774
776
|
// Purpose: Ensure all outgoing messages (text, attachments, stickers, etc.) from
|
|
@@ -779,6 +781,12 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
779
781
|
// Purpose: Prevent duplicate 'ready' events when both legacy mode (no API key)
|
|
780
782
|
// and auth-ok events occur, which would cause user callbacks to fire twice.
|
|
781
783
|
__publicField(this, "readyEmitted", false);
|
|
784
|
+
// Flag to track if socket event listeners have been attached
|
|
785
|
+
//
|
|
786
|
+
// Purpose: Prevent duplicate event listeners when connect() is called multiple times
|
|
787
|
+
// or after close(). Without this, each connect() call would add new listeners,
|
|
788
|
+
// causing events to fire multiple times.
|
|
789
|
+
__publicField(this, "listenersAttached", false);
|
|
782
790
|
this.config = {
|
|
783
791
|
serverUrl: "http://localhost:1234",
|
|
784
792
|
logLevel: "info",
|
|
@@ -810,8 +818,18 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
810
818
|
// Only WebSocket - polling disabled to prevent message duplication
|
|
811
819
|
timeout: 1e4,
|
|
812
820
|
// 10 second timeout to avoid overly frequent reconnections
|
|
813
|
-
forceNew: true
|
|
821
|
+
forceNew: true,
|
|
814
822
|
// Force new connection to avoid connection state pollution
|
|
823
|
+
reconnection: true,
|
|
824
|
+
// Enable auto-reconnection (default, but explicit for clarity)
|
|
825
|
+
reconnectionAttempts: Number.POSITIVE_INFINITY,
|
|
826
|
+
// Never give up
|
|
827
|
+
reconnectionDelay: 100,
|
|
828
|
+
// Start with 100ms delay (fast initial reconnect)
|
|
829
|
+
reconnectionDelayMax: 2e3,
|
|
830
|
+
// Max 2 seconds between attempts
|
|
831
|
+
randomizationFactor: 0.1
|
|
832
|
+
// Low randomization for more consistent reconnect timing
|
|
815
833
|
});
|
|
816
834
|
const enqueueSend = this.enqueueSend.bind(this);
|
|
817
835
|
this.attachments = new AttachmentModule(this.http, enqueueSend);
|
|
@@ -851,6 +869,17 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
851
869
|
return super.removeListener(event, listener);
|
|
852
870
|
}
|
|
853
871
|
async connect() {
|
|
872
|
+
if (!this.listenersAttached) {
|
|
873
|
+
this.listenersAttached = true;
|
|
874
|
+
this.attachSocketListeners();
|
|
875
|
+
}
|
|
876
|
+
if (this.socket.connected) {
|
|
877
|
+
this.logger.info("Already connected to iMessage server");
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
this.socket.connect();
|
|
881
|
+
}
|
|
882
|
+
attachSocketListeners() {
|
|
854
883
|
const serverEvents = [
|
|
855
884
|
"new-message",
|
|
856
885
|
"message-updated",
|
|
@@ -879,6 +908,9 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
879
908
|
return;
|
|
880
909
|
}
|
|
881
910
|
this.processedMessages.add(message.guid);
|
|
911
|
+
if (message.dateCreated && message.dateCreated > this.lastMessageTime) {
|
|
912
|
+
this.lastMessageTime = message.dateCreated;
|
|
913
|
+
}
|
|
882
914
|
}
|
|
883
915
|
}
|
|
884
916
|
if (args.length > 0) {
|
|
@@ -888,15 +920,32 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
888
920
|
}
|
|
889
921
|
});
|
|
890
922
|
}
|
|
891
|
-
this.socket.on("disconnect", () => {
|
|
892
|
-
this.logger.info(
|
|
923
|
+
this.socket.on("disconnect", (reason) => {
|
|
924
|
+
this.logger.info(`Disconnected from iMessage server (reason: ${reason})`);
|
|
893
925
|
this.readyEmitted = false;
|
|
894
926
|
this.emit("disconnect");
|
|
927
|
+
if (reason === "io server disconnect") {
|
|
928
|
+
this.logger.info("Server disconnected, manually triggering reconnect...");
|
|
929
|
+
this.socket.connect();
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
this.socket.io.on("reconnect_attempt", (attempt) => {
|
|
933
|
+
this.logger.info(`Reconnection attempt #${attempt}...`);
|
|
934
|
+
});
|
|
935
|
+
this.socket.io.on("reconnect", (attempt) => {
|
|
936
|
+
this.logger.info(`Reconnected successfully after ${attempt} attempt(s)`);
|
|
895
937
|
});
|
|
896
|
-
this.socket.on("
|
|
938
|
+
this.socket.io.on("reconnect_error", (error) => {
|
|
939
|
+
this.logger.warn(`Reconnection error: ${error.message}`);
|
|
940
|
+
});
|
|
941
|
+
this.socket.io.on("reconnect_failed", () => {
|
|
942
|
+
this.logger.error("All reconnection attempts failed");
|
|
943
|
+
});
|
|
944
|
+
this.socket.on("auth-ok", async () => {
|
|
897
945
|
this.logger.info("Authentication successful");
|
|
898
946
|
if (!this.readyEmitted) {
|
|
899
947
|
this.readyEmitted = true;
|
|
948
|
+
await this.recoverMissedMessages();
|
|
900
949
|
this.emit("ready");
|
|
901
950
|
}
|
|
902
951
|
});
|
|
@@ -904,27 +953,51 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
904
953
|
this.logger.error(`Authentication failed: ${error.message} ${error.reason ? `(${error.reason})` : ""}`);
|
|
905
954
|
this.emit("error", new Error(`Authentication failed: ${error.message}`));
|
|
906
955
|
});
|
|
907
|
-
|
|
908
|
-
this.logger.info("Already connected to iMessage server");
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
this.socket.once("connect", () => {
|
|
956
|
+
this.socket.on("connect", async () => {
|
|
912
957
|
this.logger.info("Connected to iMessage server, waiting for authentication...");
|
|
913
958
|
if (!this.config.apiKey) {
|
|
914
959
|
this.logger.info("No API key provided, skipping authentication (legacy server mode)");
|
|
915
960
|
if (!this.readyEmitted) {
|
|
916
961
|
this.readyEmitted = true;
|
|
962
|
+
await this.recoverMissedMessages();
|
|
917
963
|
this.emit("ready");
|
|
918
964
|
}
|
|
919
965
|
}
|
|
920
966
|
});
|
|
921
|
-
|
|
922
|
-
this.
|
|
923
|
-
}
|
|
967
|
+
this.socket.on("connect_error", (error) => {
|
|
968
|
+
this.logger.warn(`Connection error: ${error.message}`);
|
|
969
|
+
});
|
|
924
970
|
}
|
|
925
971
|
async close() {
|
|
926
972
|
this.socket.disconnect();
|
|
927
973
|
}
|
|
974
|
+
async recoverMissedMessages() {
|
|
975
|
+
if (this.lastMessageTime <= 0) return;
|
|
976
|
+
try {
|
|
977
|
+
const after = this.lastMessageTime;
|
|
978
|
+
const messages = await this.messages.getMessages({
|
|
979
|
+
after,
|
|
980
|
+
sort: "ASC",
|
|
981
|
+
limit: 100
|
|
982
|
+
});
|
|
983
|
+
if (messages.length === 0) {
|
|
984
|
+
this.logger.debug("No missed messages to recover");
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
this.logger.info(`Recovering ${messages.length} missed message(s)`);
|
|
988
|
+
for (const msg of messages) {
|
|
989
|
+
if (msg.guid && !this.processedMessages.has(msg.guid)) {
|
|
990
|
+
this.processedMessages.add(msg.guid);
|
|
991
|
+
if (msg.dateCreated && msg.dateCreated > this.lastMessageTime) {
|
|
992
|
+
this.lastMessageTime = msg.dateCreated;
|
|
993
|
+
}
|
|
994
|
+
super.emit("new-message", msg);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
} catch (e) {
|
|
998
|
+
this.logger.warn(`Failed to recover missed messages: ${e}`);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
928
1001
|
/**
|
|
929
1002
|
* Clear processed message records (prevent memory leaks)
|
|
930
1003
|
* @param maxSize Maximum number of messages to retain, default 1000
|