@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/dist/index.js CHANGED
@@ -740,6 +740,8 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
740
740
  // the same message content with different GUIDs due to unstable Socket.IO connections.
741
741
  // This is especially problematic when the polling transport causes connection issues.
742
742
  __publicField(this, "processedMessages", /* @__PURE__ */ new Set());
743
+ // Last message timestamp for reconnect recovery
744
+ __publicField(this, "lastMessageTime", 0);
743
745
  // Send queue for sequential message delivery
744
746
  //
745
747
  // Purpose: Ensure all outgoing messages (text, attachments, stickers, etc.) from
@@ -750,6 +752,12 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
750
752
  // Purpose: Prevent duplicate 'ready' events when both legacy mode (no API key)
751
753
  // and auth-ok events occur, which would cause user callbacks to fire twice.
752
754
  __publicField(this, "readyEmitted", false);
755
+ // Flag to track if socket event listeners have been attached
756
+ //
757
+ // Purpose: Prevent duplicate event listeners when connect() is called multiple times
758
+ // or after close(). Without this, each connect() call would add new listeners,
759
+ // causing events to fire multiple times.
760
+ __publicField(this, "listenersAttached", false);
753
761
  this.config = {
754
762
  serverUrl: "http://localhost:1234",
755
763
  logLevel: "info",
@@ -781,8 +789,18 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
781
789
  // Only WebSocket - polling disabled to prevent message duplication
782
790
  timeout: 1e4,
783
791
  // 10 second timeout to avoid overly frequent reconnections
784
- forceNew: true
792
+ forceNew: true,
785
793
  // Force new connection to avoid connection state pollution
794
+ reconnection: true,
795
+ // Enable auto-reconnection (default, but explicit for clarity)
796
+ reconnectionAttempts: Number.POSITIVE_INFINITY,
797
+ // Never give up
798
+ reconnectionDelay: 100,
799
+ // Start with 100ms delay (fast initial reconnect)
800
+ reconnectionDelayMax: 2e3,
801
+ // Max 2 seconds between attempts
802
+ randomizationFactor: 0.1
803
+ // Low randomization for more consistent reconnect timing
786
804
  });
787
805
  const enqueueSend = this.enqueueSend.bind(this);
788
806
  this.attachments = new AttachmentModule(this.http, enqueueSend);
@@ -822,6 +840,17 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
822
840
  return super.removeListener(event, listener);
823
841
  }
824
842
  async connect() {
843
+ if (!this.listenersAttached) {
844
+ this.listenersAttached = true;
845
+ this.attachSocketListeners();
846
+ }
847
+ if (this.socket.connected) {
848
+ this.logger.info("Already connected to iMessage server");
849
+ return;
850
+ }
851
+ this.socket.connect();
852
+ }
853
+ attachSocketListeners() {
825
854
  const serverEvents = [
826
855
  "new-message",
827
856
  "message-updated",
@@ -850,6 +879,9 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
850
879
  return;
851
880
  }
852
881
  this.processedMessages.add(message.guid);
882
+ if (message.dateCreated && message.dateCreated > this.lastMessageTime) {
883
+ this.lastMessageTime = message.dateCreated;
884
+ }
853
885
  }
854
886
  }
855
887
  if (args.length > 0) {
@@ -859,15 +891,32 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
859
891
  }
860
892
  });
861
893
  }
862
- this.socket.on("disconnect", () => {
863
- this.logger.info("Disconnected from iMessage server");
894
+ this.socket.on("disconnect", (reason) => {
895
+ this.logger.info(`Disconnected from iMessage server (reason: ${reason})`);
864
896
  this.readyEmitted = false;
865
897
  this.emit("disconnect");
898
+ if (reason === "io server disconnect") {
899
+ this.logger.info("Server disconnected, manually triggering reconnect...");
900
+ this.socket.connect();
901
+ }
902
+ });
903
+ this.socket.io.on("reconnect_attempt", (attempt) => {
904
+ this.logger.info(`Reconnection attempt #${attempt}...`);
905
+ });
906
+ this.socket.io.on("reconnect", (attempt) => {
907
+ this.logger.info(`Reconnected successfully after ${attempt} attempt(s)`);
866
908
  });
867
- this.socket.on("auth-ok", () => {
909
+ this.socket.io.on("reconnect_error", (error) => {
910
+ this.logger.warn(`Reconnection error: ${error.message}`);
911
+ });
912
+ this.socket.io.on("reconnect_failed", () => {
913
+ this.logger.error("All reconnection attempts failed");
914
+ });
915
+ this.socket.on("auth-ok", async () => {
868
916
  this.logger.info("Authentication successful");
869
917
  if (!this.readyEmitted) {
870
918
  this.readyEmitted = true;
919
+ await this.recoverMissedMessages();
871
920
  this.emit("ready");
872
921
  }
873
922
  });
@@ -875,27 +924,51 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
875
924
  this.logger.error(`Authentication failed: ${error.message} ${error.reason ? `(${error.reason})` : ""}`);
876
925
  this.emit("error", new Error(`Authentication failed: ${error.message}`));
877
926
  });
878
- if (this.socket.connected) {
879
- this.logger.info("Already connected to iMessage server");
880
- return;
881
- }
882
- this.socket.once("connect", () => {
927
+ this.socket.on("connect", async () => {
883
928
  this.logger.info("Connected to iMessage server, waiting for authentication...");
884
929
  if (!this.config.apiKey) {
885
930
  this.logger.info("No API key provided, skipping authentication (legacy server mode)");
886
931
  if (!this.readyEmitted) {
887
932
  this.readyEmitted = true;
933
+ await this.recoverMissedMessages();
888
934
  this.emit("ready");
889
935
  }
890
936
  }
891
937
  });
892
- if (!this.socket.connected) {
893
- this.socket.connect();
894
- }
938
+ this.socket.on("connect_error", (error) => {
939
+ this.logger.warn(`Connection error: ${error.message}`);
940
+ });
895
941
  }
896
942
  async close() {
897
943
  this.socket.disconnect();
898
944
  }
945
+ async recoverMissedMessages() {
946
+ if (this.lastMessageTime <= 0) return;
947
+ try {
948
+ const after = this.lastMessageTime;
949
+ const messages = await this.messages.getMessages({
950
+ after,
951
+ sort: "ASC",
952
+ limit: 100
953
+ });
954
+ if (messages.length === 0) {
955
+ this.logger.debug("No missed messages to recover");
956
+ return;
957
+ }
958
+ this.logger.info(`Recovering ${messages.length} missed message(s)`);
959
+ for (const msg of messages) {
960
+ if (msg.guid && !this.processedMessages.has(msg.guid)) {
961
+ this.processedMessages.add(msg.guid);
962
+ if (msg.dateCreated && msg.dateCreated > this.lastMessageTime) {
963
+ this.lastMessageTime = msg.dateCreated;
964
+ }
965
+ super.emit("new-message", msg);
966
+ }
967
+ }
968
+ } catch (e) {
969
+ this.logger.warn(`Failed to recover missed messages: ${e}`);
970
+ }
971
+ }
899
972
  /**
900
973
  * Clear processed message records (prevent memory leaks)
901
974
  * @param maxSize Maximum number of messages to retain, default 1000