@photon-ai/advanced-imessage-kit 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/index.d.ts CHANGED
@@ -148,6 +148,7 @@ type MessageResponse = {
148
148
  partCount?: number | null;
149
149
  payloadData?: NodeJS.Dict<any>[];
150
150
  hasPayloadData?: boolean;
151
+ isPoll?: boolean;
151
152
  wasDeliveredQuietly?: boolean;
152
153
  didNotifyRecipient?: boolean;
153
154
  shareStatus?: number | null;
@@ -326,11 +327,59 @@ interface TypedEventEmitter {
326
327
  removeListener(event: string | symbol, listener: (...args: unknown[]) => void): this;
327
328
  }
328
329
 
330
+ interface CreatePollOptions {
331
+ chatGuid: string;
332
+ title?: string;
333
+ options: string[];
334
+ }
335
+ interface VotePollOptions {
336
+ chatGuid: string;
337
+ pollMessageGuid: string;
338
+ optionIdentifier: string;
339
+ }
340
+ interface AddPollOptionOptions {
341
+ chatGuid: string;
342
+ pollMessageGuid: string;
343
+ optionText: string;
344
+ }
345
+ interface PollOption {
346
+ optionIdentifier: string;
347
+ text: string;
348
+ attributedText: string;
349
+ creatorHandle: string;
350
+ canBeEdited: boolean;
351
+ }
352
+ interface PollVote {
353
+ voteOptionIdentifier: string;
354
+ participantHandle: string;
355
+ serverVoteTime?: number;
356
+ }
357
+ interface PollDefinition {
358
+ version: number;
359
+ item: {
360
+ title: string;
361
+ orderedPollOptions: PollOption[];
362
+ creatorHandle: string;
363
+ };
364
+ }
365
+ interface PollVoteResponse {
366
+ version: number;
367
+ item: {
368
+ votes: PollVote[];
369
+ };
370
+ }
371
+ type PollMessageResponse = MessageResponse;
372
+
329
373
  interface SendStickerOptions {
330
374
  chatGuid: string;
331
375
  filePath: string;
332
376
  fileName?: string;
333
377
  selectedMessageGuid?: string;
378
+ stickerX?: number;
379
+ stickerY?: number;
380
+ stickerScale?: number;
381
+ stickerRotation?: number;
382
+ stickerWidth?: number;
334
383
  }
335
384
 
336
385
  type ValidTapback = "love" | "like" | "dislike" | "laugh" | "emphasize" | "question";
@@ -387,7 +436,6 @@ declare class ChatModule {
387
436
  }): Promise<ChatResponse>;
388
437
  deleteChat(guid: string): Promise<void>;
389
438
  markChatRead(guid: string): Promise<void>;
390
- markChatUnread(guid: string): Promise<void>;
391
439
  leaveChat(guid: string): Promise<void>;
392
440
  addParticipant(chatGuid: string, address: string): Promise<ChatResponse>;
393
441
  removeParticipant(chatGuid: string, address: string): Promise<ChatResponse>;
@@ -528,6 +576,15 @@ declare class MessageModule {
528
576
  }): Promise<MessageResponse[]>;
529
577
  }
530
578
 
579
+ declare class PollModule {
580
+ private readonly http;
581
+ constructor(http: AxiosInstance);
582
+ create(options: CreatePollOptions): Promise<PollMessageResponse>;
583
+ vote(options: VotePollOptions): Promise<PollMessageResponse>;
584
+ unvote(options: VotePollOptions): Promise<PollMessageResponse>;
585
+ addOption(options: AddPollOptionOptions): Promise<PollMessageResponse>;
586
+ }
587
+
531
588
  declare class ScheduledMessageModule {
532
589
  private readonly http;
533
590
  constructor(http: AxiosInstance);
@@ -543,8 +600,6 @@ declare class ServerModule {
543
600
  getServerInfo(): Promise<any>;
544
601
  getMessageStats(): Promise<any>;
545
602
  getServerLogs(count?: number): Promise<string[]>;
546
- getAlerts(): Promise<any[]>;
547
- markAlertAsRead(ids: string[]): Promise<any>;
548
603
  getMediaStatistics(options?: {
549
604
  only?: string[];
550
605
  }): Promise<any>;
@@ -568,10 +623,12 @@ declare class AdvancedIMessageKit extends EventEmitter$1 implements TypedEventEm
568
623
  readonly handles: HandleModule;
569
624
  readonly facetime: FaceTimeModule;
570
625
  readonly icloud: ICloudModule;
626
+ readonly polls: PollModule;
571
627
  readonly scheduledMessages: ScheduledMessageModule;
572
628
  readonly server: ServerModule;
573
629
  private processedMessages;
574
630
  private sendQueue;
631
+ private readyEmitted;
575
632
  private constructor();
576
633
  emit<K extends keyof PhotonEventMap>(event: K, ...args: PhotonEventMap[K] extends undefined ? [] : [PhotonEventMap[K]]): boolean;
577
634
  on<K extends keyof PhotonEventMap>(event: K, listener: PhotonEventMap[K] extends undefined ? () => void : (data: PhotonEventMap[K]) => void): this;
@@ -636,4 +693,19 @@ declare const NEW_FINDMY_LOCATION = "new-findmy-location";
636
693
  declare const setGlobalLogLevel: (level: LogLevel) => void;
637
694
  declare const getLogger: (tag: string) => Logger;
638
695
 
639
- export { AdvancedIMessageKit, type Attachment, type AttachmentResponse, type BackupData, CHAT_READ_STATUS_CHANGED, type Chat, type ChatResponse, type ClientConfig, FT_CALL_STATUS_CHANGED, type FaceTimeStatusData, type FindMyLocationItem, GROUP_ICON_CHANGED, GROUP_ICON_REMOVED, GROUP_NAME_CHANGE, HELLO_WORLD, type Handle, type HandleResponse, IMESSAGE_ALIASES_REMOVED, INCOMING_FACETIME, MESSAGE_SEND_ERROR, MESSAGE_UPDATED, type Message, type MessageData, type MessageResponse, NEW_FINDMY_LOCATION, NEW_MESSAGE, NEW_SERVER, PARTICIPANT_ADDED, PARTICIPANT_LEFT, PARTICIPANT_REMOVED, type PhotonEventMap, type PhotonEventName, SCHEDULED_MESSAGE_CREATED, SCHEDULED_MESSAGE_DELETED, SCHEDULED_MESSAGE_ERROR, SCHEDULED_MESSAGE_SENT, SCHEDULED_MESSAGE_UPDATED, SDK, SERVER_UPDATE, SERVER_UPDATE_DOWNLOADING, SERVER_UPDATE_INSTALLING, SETTINGS_BACKUP_CREATED, SETTINGS_BACKUP_DELETED, SETTINGS_BACKUP_UPDATED, type ScheduledMessageData, type SendAttachmentOptions, type SendMessageOptions, type SendStickerOptions, type ServerMetadataResponse, type ServerUpdateData, THEME_BACKUP_CREATED, THEME_BACKUP_DELETED, THEME_BACKUP_UPDATED, TYPING_INDICATOR, type TypedEventEmitter, type ValidRemoveTapback, type ValidTapback, getLogger, setGlobalLogLevel };
696
+ declare function isPollMessage(message: MessageResponse): boolean;
697
+ declare function isPollVote(message: MessageResponse): boolean;
698
+ interface ParsedPoll {
699
+ title: string;
700
+ creatorHandle: string;
701
+ options: PollOption[];
702
+ }
703
+ interface ParsedPollVote {
704
+ votes: PollVote[];
705
+ }
706
+ declare function parsePollDefinition(message: MessageResponse): ParsedPoll | null;
707
+ declare function parsePollVotes(message: MessageResponse): ParsedPollVote | null;
708
+ declare function getPollSummary(message: MessageResponse): string;
709
+ declare function getPollOneLiner(message: MessageResponse): string;
710
+
711
+ export { type AddPollOptionOptions, AdvancedIMessageKit, type Attachment, type AttachmentResponse, type BackupData, CHAT_READ_STATUS_CHANGED, type Chat, type ChatResponse, type ClientConfig, type CreatePollOptions, FT_CALL_STATUS_CHANGED, type FaceTimeStatusData, type FindMyLocationItem, GROUP_ICON_CHANGED, GROUP_ICON_REMOVED, GROUP_NAME_CHANGE, HELLO_WORLD, type Handle, type HandleResponse, IMESSAGE_ALIASES_REMOVED, INCOMING_FACETIME, MESSAGE_SEND_ERROR, MESSAGE_UPDATED, type Message, type MessageData, type MessageResponse, NEW_FINDMY_LOCATION, NEW_MESSAGE, NEW_SERVER, PARTICIPANT_ADDED, PARTICIPANT_LEFT, PARTICIPANT_REMOVED, type ParsedPoll, type ParsedPollVote, type PhotonEventMap, type PhotonEventName, type PollDefinition, type PollMessageResponse, type PollOption, type PollVote, type PollVoteResponse, SCHEDULED_MESSAGE_CREATED, SCHEDULED_MESSAGE_DELETED, SCHEDULED_MESSAGE_ERROR, SCHEDULED_MESSAGE_SENT, SCHEDULED_MESSAGE_UPDATED, SDK, SERVER_UPDATE, SERVER_UPDATE_DOWNLOADING, SERVER_UPDATE_INSTALLING, SETTINGS_BACKUP_CREATED, SETTINGS_BACKUP_DELETED, SETTINGS_BACKUP_UPDATED, type ScheduledMessageData, type SendAttachmentOptions, type SendMessageOptions, type SendStickerOptions, type ServerMetadataResponse, type ServerUpdateData, THEME_BACKUP_CREATED, THEME_BACKUP_DELETED, THEME_BACKUP_UPDATED, TYPING_INDICATOR, type TypedEventEmitter, type ValidRemoveTapback, type ValidTapback, type VotePollOptions, getLogger, getPollOneLiner, getPollSummary, isPollMessage, isPollVote, parsePollDefinition, parsePollVotes, setGlobalLogLevel };
package/dist/index.js CHANGED
@@ -173,15 +173,23 @@ var AttachmentModule = class {
173
173
  const fileName = options.fileName || path__default.basename(options.filePath);
174
174
  const form = new FormData();
175
175
  form.append("attachment", await readFile(options.filePath), fileName);
176
- const { data } = await this.http.post("/api/v1/attachment/upload", form, {
176
+ form.append("name", fileName);
177
+ form.append("chatGuid", options.chatGuid);
178
+ form.append("isSticker", "true");
179
+ form.append("method", "private-api");
180
+ if (options.selectedMessageGuid) {
181
+ form.append("selectedMessageGuid", options.selectedMessageGuid);
182
+ form.append("partIndex", "0");
183
+ }
184
+ form.append("stickerX", String(options.stickerX ?? 0.5));
185
+ form.append("stickerY", String(options.stickerY ?? 0.5));
186
+ form.append("stickerScale", String(options.stickerScale ?? 0.75));
187
+ form.append("stickerRotation", String(options.stickerRotation ?? 0));
188
+ form.append("stickerWidth", String(options.stickerWidth ?? 300));
189
+ const { data } = await this.http.post("/api/v1/message/attachment", form, {
177
190
  headers: form.getHeaders()
178
191
  });
179
- const response = await this.http.post("/api/v1/message/multipart", {
180
- chatGuid: options.chatGuid,
181
- selectedMessageGuid: options.selectedMessageGuid,
182
- parts: [{ partIndex: 0, attachment: data.data.path, name: fileName }]
183
- });
184
- return response.data.data;
192
+ return data.data;
185
193
  });
186
194
  }
187
195
  };
@@ -198,35 +206,32 @@ var ChatModule = class {
198
206
  return response.data.data;
199
207
  }
200
208
  async getChat(guid, options) {
201
- const response = await this.http.get(`/api/v1/chat/${guid}`, {
209
+ const response = await this.http.get(`/api/v1/chat/${encodeURIComponent(guid)}`, {
202
210
  params: options?.with ? { with: options.with.join(",") } : {}
203
211
  });
204
212
  return response.data.data;
205
213
  }
206
214
  async updateChat(guid, options) {
207
- const response = await this.http.put(`/api/v1/chat/${guid}`, options);
215
+ const response = await this.http.put(`/api/v1/chat/${encodeURIComponent(guid)}`, options);
208
216
  return response.data.data;
209
217
  }
210
218
  async deleteChat(guid) {
211
- await this.http.delete(`/api/v1/chat/${guid}`);
219
+ await this.http.delete(`/api/v1/chat/${encodeURIComponent(guid)}`);
212
220
  }
213
221
  async markChatRead(guid) {
214
- await this.http.post(`/api/v1/chat/${guid}/read`);
215
- }
216
- async markChatUnread(guid) {
217
- await this.http.post(`/api/v1/chat/${guid}/unread`);
222
+ await this.http.post(`/api/v1/chat/${encodeURIComponent(guid)}/read`);
218
223
  }
219
224
  async leaveChat(guid) {
220
- await this.http.post(`/api/v1/chat/${guid}/leave`);
225
+ await this.http.post(`/api/v1/chat/${encodeURIComponent(guid)}/leave`);
221
226
  }
222
227
  async addParticipant(chatGuid, address) {
223
- const response = await this.http.post(`/api/v1/chat/${chatGuid}/participant`, {
228
+ const response = await this.http.post(`/api/v1/chat/${encodeURIComponent(chatGuid)}/participant`, {
224
229
  address
225
230
  });
226
231
  return response.data.data;
227
232
  }
228
233
  async removeParticipant(chatGuid, address) {
229
- const response = await this.http.delete(`/api/v1/chat/${chatGuid}/participant`, {
234
+ const response = await this.http.delete(`/api/v1/chat/${encodeURIComponent(chatGuid)}/participant`, {
230
235
  data: { address }
231
236
  });
232
237
  return response.data.data;
@@ -239,7 +244,7 @@ var ChatModule = class {
239
244
  if (options?.before !== void 0) params.before = options.before;
240
245
  if (options?.after !== void 0) params.after = options.after;
241
246
  if (options?.with) params.with = options.with.join(",");
242
- const response = await this.http.get(`/api/v1/chat/${chatGuid}/message`, {
247
+ const response = await this.http.get(`/api/v1/chat/${encodeURIComponent(chatGuid)}/message`, {
243
248
  params
244
249
  });
245
250
  return response.data.data;
@@ -249,15 +254,15 @@ var ChatModule = class {
249
254
  const fileName = path__default.basename(filePath);
250
255
  const form = new FormData();
251
256
  form.append("icon", fileBuffer, fileName);
252
- await this.http.post(`/api/v1/chat/${chatGuid}/icon`, form, {
257
+ await this.http.post(`/api/v1/chat/${encodeURIComponent(chatGuid)}/icon`, form, {
253
258
  headers: form.getHeaders()
254
259
  });
255
260
  }
256
261
  async removeGroupIcon(chatGuid) {
257
- await this.http.delete(`/api/v1/chat/${chatGuid}/icon`);
262
+ await this.http.delete(`/api/v1/chat/${encodeURIComponent(chatGuid)}/icon`);
258
263
  }
259
264
  async getGroupIcon(chatGuid) {
260
- const response = await this.http.get(`/api/v1/chat/${chatGuid}/icon`, {
265
+ const response = await this.http.get(`/api/v1/chat/${encodeURIComponent(chatGuid)}/icon`, {
261
266
  responseType: "arraybuffer"
262
267
  });
263
268
  return Buffer.from(response.data);
@@ -269,10 +274,10 @@ var ChatModule = class {
269
274
  return response.data.data;
270
275
  }
271
276
  async startTyping(chatGuid) {
272
- await this.http.post(`/api/v1/chat/${chatGuid}/typing`);
277
+ await this.http.post(`/api/v1/chat/${encodeURIComponent(chatGuid)}/typing`);
273
278
  }
274
279
  async stopTyping(chatGuid) {
275
- await this.http.delete(`/api/v1/chat/${chatGuid}/typing`);
280
+ await this.http.delete(`/api/v1/chat/${encodeURIComponent(chatGuid)}/typing`);
276
281
  }
277
282
  };
278
283
 
@@ -292,10 +297,10 @@ var ContactModule = class {
292
297
  return response.data.data;
293
298
  }
294
299
  async shareContactCard(chatGuid) {
295
- await this.http.post(`/api/v1/chat/${chatGuid}/share/contact`);
300
+ await this.http.post(`/api/v1/chat/${encodeURIComponent(chatGuid)}/share/contact`);
296
301
  }
297
302
  async shouldShareContact(chatGuid) {
298
- const response = await this.http.get(`/api/v1/chat/${chatGuid}/share/contact/status`);
303
+ const response = await this.http.get(`/api/v1/chat/${encodeURIComponent(chatGuid)}/share/contact/status`);
299
304
  return response.data.data;
300
305
  }
301
306
  };
@@ -509,6 +514,51 @@ var MessageModule = class {
509
514
  }
510
515
  };
511
516
 
517
+ // modules/poll.ts
518
+ var PollModule = class {
519
+ constructor(http) {
520
+ this.http = http;
521
+ }
522
+ async create(options) {
523
+ if (options.options.length < 2) {
524
+ throw new Error("Poll must have at least 2 options");
525
+ }
526
+ const { data } = await this.http.post("/api/v1/poll/create", {
527
+ chatGuid: options.chatGuid,
528
+ title: options.title ?? "",
529
+ options: options.options
530
+ });
531
+ return data.data;
532
+ }
533
+ async vote(options) {
534
+ const { data } = await this.http.post("/api/v1/poll/vote", {
535
+ chatGuid: options.chatGuid,
536
+ pollMessageGuid: options.pollMessageGuid,
537
+ optionIdentifier: options.optionIdentifier
538
+ });
539
+ return data.data;
540
+ }
541
+ async unvote(options) {
542
+ const { data } = await this.http.post("/api/v1/poll/unvote", {
543
+ chatGuid: options.chatGuid,
544
+ pollMessageGuid: options.pollMessageGuid,
545
+ optionIdentifier: options.optionIdentifier
546
+ });
547
+ return data.data;
548
+ }
549
+ async addOption(options) {
550
+ if (!options.optionText || options.optionText.trim().length === 0) {
551
+ throw new Error("Option text cannot be empty");
552
+ }
553
+ const { data } = await this.http.post("/api/v1/poll/option", {
554
+ chatGuid: options.chatGuid,
555
+ pollMessageGuid: options.pollMessageGuid,
556
+ optionText: options.optionText
557
+ });
558
+ return data.data;
559
+ }
560
+ };
561
+
512
562
  // modules/scheduled.ts
513
563
  var ScheduledMessageModule = class {
514
564
  constructor(http) {
@@ -550,14 +600,6 @@ var ServerModule = class {
550
600
  });
551
601
  return response.data.data;
552
602
  }
553
- async getAlerts() {
554
- const response = await this.http.get("/api/v1/server/alert");
555
- return response.data.data;
556
- }
557
- async markAlertAsRead(ids) {
558
- const response = await this.http.post("/api/v1/server/alert/read", { ids });
559
- return response.data.data;
560
- }
561
603
  async getMediaStatistics(options) {
562
604
  const params = {};
563
605
  if (options?.only) params.only = options.only.join(",");
@@ -592,6 +634,7 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
592
634
  __publicField(this, "handles");
593
635
  __publicField(this, "facetime");
594
636
  __publicField(this, "icloud");
637
+ __publicField(this, "polls");
595
638
  __publicField(this, "scheduledMessages");
596
639
  __publicField(this, "server");
597
640
  // Message deduplication feature
@@ -605,6 +648,11 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
605
648
  // Purpose: Ensure all outgoing messages (text, attachments, stickers, etc.) from
606
649
  // a single user/SDK instance are sent in strict order, preventing race conditions.
607
650
  __publicField(this, "sendQueue", Promise.resolve());
651
+ // Flag to track if 'ready' event has been emitted
652
+ //
653
+ // Purpose: Prevent duplicate 'ready' events when both legacy mode (no API key)
654
+ // and auth-ok events occur, which would cause user callbacks to fire twice.
655
+ __publicField(this, "readyEmitted", false);
608
656
  this.config = {
609
657
  serverUrl: "http://localhost:1234",
610
658
  logLevel: "info",
@@ -647,6 +695,7 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
647
695
  this.handles = new HandleModule(this.http);
648
696
  this.facetime = new FaceTimeModule(this.http);
649
697
  this.icloud = new ICloudModule(this.http);
698
+ this.polls = new PollModule(this.http);
650
699
  this.scheduledMessages = new ScheduledMessageModule(this.http);
651
700
  this.server = new ServerModule(this.http);
652
701
  }
@@ -715,11 +764,15 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
715
764
  }
716
765
  this.socket.on("disconnect", () => {
717
766
  this.logger.info("Disconnected from iMessage server");
767
+ this.readyEmitted = false;
718
768
  this.emit("disconnect");
719
769
  });
720
770
  this.socket.on("auth-ok", () => {
721
771
  this.logger.info("Authentication successful");
722
- this.emit("ready");
772
+ if (!this.readyEmitted) {
773
+ this.readyEmitted = true;
774
+ this.emit("ready");
775
+ }
723
776
  });
724
777
  this.socket.on("auth-error", (error) => {
725
778
  this.logger.error(`Authentication failed: ${error.message} ${error.reason ? `(${error.reason})` : ""}`);
@@ -733,7 +786,10 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter {
733
786
  this.logger.info("Connected to iMessage server, waiting for authentication...");
734
787
  if (!this.config.apiKey) {
735
788
  this.logger.info("No API key provided, skipping authentication (legacy server mode)");
736
- this.emit("ready");
789
+ if (!this.readyEmitted) {
790
+ this.readyEmitted = true;
791
+ this.emit("ready");
792
+ }
737
793
  }
738
794
  });
739
795
  if (!this.socket.connected) {
@@ -817,6 +873,144 @@ var IMESSAGE_ALIASES_REMOVED = "imessage-aliases-removed";
817
873
  var FT_CALL_STATUS_CHANGED = "ft-call-status-changed";
818
874
  var NEW_FINDMY_LOCATION = "new-findmy-location";
819
875
 
820
- export { AdvancedIMessageKit, CHAT_READ_STATUS_CHANGED, FT_CALL_STATUS_CHANGED, GROUP_ICON_CHANGED, GROUP_ICON_REMOVED, GROUP_NAME_CHANGE, HELLO_WORLD, IMESSAGE_ALIASES_REMOVED, INCOMING_FACETIME, MESSAGE_SEND_ERROR, MESSAGE_UPDATED, NEW_FINDMY_LOCATION, NEW_MESSAGE, NEW_SERVER, PARTICIPANT_ADDED, PARTICIPANT_LEFT, PARTICIPANT_REMOVED, SCHEDULED_MESSAGE_CREATED, SCHEDULED_MESSAGE_DELETED, SCHEDULED_MESSAGE_ERROR, SCHEDULED_MESSAGE_SENT, SCHEDULED_MESSAGE_UPDATED, SDK, SERVER_UPDATE, SERVER_UPDATE_DOWNLOADING, SERVER_UPDATE_INSTALLING, SETTINGS_BACKUP_CREATED, SETTINGS_BACKUP_DELETED, SETTINGS_BACKUP_UPDATED, THEME_BACKUP_CREATED, THEME_BACKUP_DELETED, THEME_BACKUP_UPDATED, TYPING_INDICATOR, getLogger, setGlobalLogLevel };
876
+ // lib/poll-utils.ts
877
+ var POLL_BALLOON_BUNDLE_ID = "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.messages.Polls";
878
+ var pollCache = /* @__PURE__ */ new Map();
879
+ function cachePoll(messageGuid, poll) {
880
+ pollCache.set(messageGuid, poll);
881
+ }
882
+ function getOptionTextById(optionId) {
883
+ for (const poll of pollCache.values()) {
884
+ const option = poll.options.find((o) => o.optionIdentifier === optionId);
885
+ if (option) return option.text;
886
+ }
887
+ return null;
888
+ }
889
+ function isPollMessage(message) {
890
+ return message.balloonBundleId === POLL_BALLOON_BUNDLE_ID;
891
+ }
892
+ function isPollVote(message) {
893
+ return isPollMessage(message) && message.associatedMessageType === "4000";
894
+ }
895
+ function extractDataUrl(payloadData) {
896
+ if (!payloadData || payloadData.length === 0) return null;
897
+ const payload = payloadData[0];
898
+ if (!payload) return null;
899
+ if (payload.URL && typeof payload.URL === "string") {
900
+ return payload.URL;
901
+ }
902
+ const objects = payload.$objects;
903
+ if (Array.isArray(objects)) {
904
+ for (const obj of objects) {
905
+ if (typeof obj === "object" && obj !== null) {
906
+ if (obj["NS.relative"] && typeof obj["NS.relative"] === "object") {
907
+ const relativeObj = objects[obj["NS.relative"].UID];
908
+ if (typeof relativeObj === "string" && relativeObj.startsWith("data:,")) {
909
+ return relativeObj;
910
+ }
911
+ }
912
+ if (typeof obj === "string" && obj.startsWith("data:,")) {
913
+ return obj;
914
+ }
915
+ }
916
+ }
917
+ }
918
+ return null;
919
+ }
920
+ function parseDataUrl(dataUrl) {
921
+ try {
922
+ const prefix = "data:,";
923
+ if (!dataUrl.startsWith(prefix)) return null;
924
+ let data = dataUrl.slice(prefix.length);
925
+ const queryIndex = data.indexOf("?");
926
+ if (queryIndex !== -1) {
927
+ data = data.slice(0, queryIndex);
928
+ }
929
+ data = decodeURIComponent(data);
930
+ try {
931
+ return JSON.parse(data);
932
+ } catch {
933
+ const decoded = Buffer.from(data, "base64").toString("utf-8");
934
+ return JSON.parse(decoded);
935
+ }
936
+ } catch {
937
+ return null;
938
+ }
939
+ }
940
+ function parsePollDefinition(message) {
941
+ if (!isPollMessage(message)) return null;
942
+ if (isPollVote(message)) return null;
943
+ const dataUrl = extractDataUrl(message.payloadData);
944
+ if (!dataUrl) return null;
945
+ const data = parseDataUrl(dataUrl);
946
+ if (!data || !data.item) return null;
947
+ const parsed = {
948
+ title: data.item.title || "",
949
+ creatorHandle: data.item.creatorHandle || "",
950
+ options: data.item.orderedPollOptions || []
951
+ };
952
+ if (message.guid) {
953
+ cachePoll(message.guid, parsed);
954
+ }
955
+ return parsed;
956
+ }
957
+ function parsePollVotes(message) {
958
+ if (!isPollMessage(message)) return null;
959
+ if (!isPollVote(message)) return null;
960
+ const dataUrl = extractDataUrl(message.payloadData);
961
+ if (!dataUrl) return null;
962
+ const data = parseDataUrl(dataUrl);
963
+ if (!data || !data.item) return null;
964
+ return {
965
+ votes: data.item.votes || []
966
+ };
967
+ }
968
+ function getPollSummary(message) {
969
+ if (!isPollMessage(message)) {
970
+ return message.text || "(no text)";
971
+ }
972
+ if (isPollVote(message)) {
973
+ const voteData = parsePollVotes(message);
974
+ if (voteData && voteData.votes.length > 0) {
975
+ const votes = voteData.votes.map((v) => {
976
+ const optionText = getOptionTextById(v.voteOptionIdentifier);
977
+ const optionDisplay = optionText ? `"${optionText}"` : `option ${v.voteOptionIdentifier}`;
978
+ return `${v.participantHandle || "Someone"} voted ${optionDisplay}`;
979
+ }).join(", ");
980
+ return `[Poll Vote] ${votes}`;
981
+ }
982
+ return "[Poll Vote]";
983
+ }
984
+ const pollData = parsePollDefinition(message);
985
+ if (pollData) {
986
+ const title = pollData.title ? `"${pollData.title}"` : "(untitled poll)";
987
+ const optionsList = pollData.options.map((opt, i) => ` ${i + 1}. ${opt.text}`).join("\n");
988
+ return `[Poll] ${title}
989
+ ${optionsList}`;
990
+ }
991
+ return "[Poll] (unable to parse)";
992
+ }
993
+ function getPollOneLiner(message) {
994
+ if (!isPollMessage(message)) {
995
+ return message.text || "(no text)";
996
+ }
997
+ if (isPollVote(message)) {
998
+ const voteData = parsePollVotes(message);
999
+ if (voteData && voteData.votes.length > 0) {
1000
+ return `[Poll Vote] ${voteData.votes.length} vote(s)`;
1001
+ }
1002
+ return "[Poll Vote]";
1003
+ }
1004
+ const pollData = parsePollDefinition(message);
1005
+ if (pollData) {
1006
+ const title = pollData.title || "Poll";
1007
+ const optionsPreview = pollData.options.slice(0, 2).map((o) => o.text).join(", ");
1008
+ const moreOptions = pollData.options.length > 2 ? `, +${pollData.options.length - 2} more` : "";
1009
+ return `[${title}] ${optionsPreview}${moreOptions}`;
1010
+ }
1011
+ return "[Poll]";
1012
+ }
1013
+
1014
+ export { AdvancedIMessageKit, CHAT_READ_STATUS_CHANGED, FT_CALL_STATUS_CHANGED, GROUP_ICON_CHANGED, GROUP_ICON_REMOVED, GROUP_NAME_CHANGE, HELLO_WORLD, IMESSAGE_ALIASES_REMOVED, INCOMING_FACETIME, MESSAGE_SEND_ERROR, MESSAGE_UPDATED, NEW_FINDMY_LOCATION, NEW_MESSAGE, NEW_SERVER, PARTICIPANT_ADDED, PARTICIPANT_LEFT, PARTICIPANT_REMOVED, SCHEDULED_MESSAGE_CREATED, SCHEDULED_MESSAGE_DELETED, SCHEDULED_MESSAGE_ERROR, SCHEDULED_MESSAGE_SENT, SCHEDULED_MESSAGE_UPDATED, SDK, SERVER_UPDATE, SERVER_UPDATE_DOWNLOADING, SERVER_UPDATE_INSTALLING, SETTINGS_BACKUP_CREATED, SETTINGS_BACKUP_DELETED, SETTINGS_BACKUP_UPDATED, THEME_BACKUP_CREATED, THEME_BACKUP_DELETED, THEME_BACKUP_UPDATED, TYPING_INDICATOR, getLogger, getPollOneLiner, getPollSummary, isPollMessage, isPollVote, parsePollDefinition, parsePollVotes, setGlobalLogLevel };
821
1015
  //# sourceMappingURL=index.js.map
822
1016
  //# sourceMappingURL=index.js.map