@photon-ai/advanced-imessage-kit 1.2.0 → 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/README.md +536 -554
- package/dist/index.cjs +291 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -4
- package/dist/index.d.ts +76 -4
- package/dist/index.js +286 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -202,15 +202,23 @@ var AttachmentModule = class {
|
|
|
202
202
|
const fileName = options.fileName || path__namespace.default.basename(options.filePath);
|
|
203
203
|
const form = new FormData__default.default();
|
|
204
204
|
form.append("attachment", await promises.readFile(options.filePath), fileName);
|
|
205
|
-
|
|
205
|
+
form.append("name", fileName);
|
|
206
|
+
form.append("chatGuid", options.chatGuid);
|
|
207
|
+
form.append("isSticker", "true");
|
|
208
|
+
form.append("method", "private-api");
|
|
209
|
+
if (options.selectedMessageGuid) {
|
|
210
|
+
form.append("selectedMessageGuid", options.selectedMessageGuid);
|
|
211
|
+
form.append("partIndex", "0");
|
|
212
|
+
}
|
|
213
|
+
form.append("stickerX", String(options.stickerX ?? 0.5));
|
|
214
|
+
form.append("stickerY", String(options.stickerY ?? 0.5));
|
|
215
|
+
form.append("stickerScale", String(options.stickerScale ?? 0.75));
|
|
216
|
+
form.append("stickerRotation", String(options.stickerRotation ?? 0));
|
|
217
|
+
form.append("stickerWidth", String(options.stickerWidth ?? 300));
|
|
218
|
+
const { data } = await this.http.post("/api/v1/message/attachment", form, {
|
|
206
219
|
headers: form.getHeaders()
|
|
207
220
|
});
|
|
208
|
-
|
|
209
|
-
chatGuid: options.chatGuid,
|
|
210
|
-
selectedMessageGuid: options.selectedMessageGuid,
|
|
211
|
-
parts: [{ partIndex: 0, attachment: data.data.path, name: fileName }]
|
|
212
|
-
});
|
|
213
|
-
return response.data.data;
|
|
221
|
+
return data.data;
|
|
214
222
|
});
|
|
215
223
|
}
|
|
216
224
|
};
|
|
@@ -227,35 +235,32 @@ var ChatModule = class {
|
|
|
227
235
|
return response.data.data;
|
|
228
236
|
}
|
|
229
237
|
async getChat(guid, options) {
|
|
230
|
-
const response = await this.http.get(`/api/v1/chat/${guid}`, {
|
|
238
|
+
const response = await this.http.get(`/api/v1/chat/${encodeURIComponent(guid)}`, {
|
|
231
239
|
params: options?.with ? { with: options.with.join(",") } : {}
|
|
232
240
|
});
|
|
233
241
|
return response.data.data;
|
|
234
242
|
}
|
|
235
243
|
async updateChat(guid, options) {
|
|
236
|
-
const response = await this.http.put(`/api/v1/chat/${guid}`, options);
|
|
244
|
+
const response = await this.http.put(`/api/v1/chat/${encodeURIComponent(guid)}`, options);
|
|
237
245
|
return response.data.data;
|
|
238
246
|
}
|
|
239
247
|
async deleteChat(guid) {
|
|
240
|
-
await this.http.delete(`/api/v1/chat/${guid}`);
|
|
248
|
+
await this.http.delete(`/api/v1/chat/${encodeURIComponent(guid)}`);
|
|
241
249
|
}
|
|
242
250
|
async markChatRead(guid) {
|
|
243
|
-
await this.http.post(`/api/v1/chat/${guid}/read`);
|
|
244
|
-
}
|
|
245
|
-
async markChatUnread(guid) {
|
|
246
|
-
await this.http.post(`/api/v1/chat/${guid}/unread`);
|
|
251
|
+
await this.http.post(`/api/v1/chat/${encodeURIComponent(guid)}/read`);
|
|
247
252
|
}
|
|
248
253
|
async leaveChat(guid) {
|
|
249
|
-
await this.http.post(`/api/v1/chat/${guid}/leave`);
|
|
254
|
+
await this.http.post(`/api/v1/chat/${encodeURIComponent(guid)}/leave`);
|
|
250
255
|
}
|
|
251
256
|
async addParticipant(chatGuid, address) {
|
|
252
|
-
const response = await this.http.post(`/api/v1/chat/${chatGuid}/participant`, {
|
|
257
|
+
const response = await this.http.post(`/api/v1/chat/${encodeURIComponent(chatGuid)}/participant`, {
|
|
253
258
|
address
|
|
254
259
|
});
|
|
255
260
|
return response.data.data;
|
|
256
261
|
}
|
|
257
262
|
async removeParticipant(chatGuid, address) {
|
|
258
|
-
const response = await this.http.delete(`/api/v1/chat/${chatGuid}/participant`, {
|
|
263
|
+
const response = await this.http.delete(`/api/v1/chat/${encodeURIComponent(chatGuid)}/participant`, {
|
|
259
264
|
data: { address }
|
|
260
265
|
});
|
|
261
266
|
return response.data.data;
|
|
@@ -268,7 +273,7 @@ var ChatModule = class {
|
|
|
268
273
|
if (options?.before !== void 0) params.before = options.before;
|
|
269
274
|
if (options?.after !== void 0) params.after = options.after;
|
|
270
275
|
if (options?.with) params.with = options.with.join(",");
|
|
271
|
-
const response = await this.http.get(`/api/v1/chat/${chatGuid}/message`, {
|
|
276
|
+
const response = await this.http.get(`/api/v1/chat/${encodeURIComponent(chatGuid)}/message`, {
|
|
272
277
|
params
|
|
273
278
|
});
|
|
274
279
|
return response.data.data;
|
|
@@ -278,15 +283,15 @@ var ChatModule = class {
|
|
|
278
283
|
const fileName = path__namespace.default.basename(filePath);
|
|
279
284
|
const form = new FormData__default.default();
|
|
280
285
|
form.append("icon", fileBuffer, fileName);
|
|
281
|
-
await this.http.post(`/api/v1/chat/${chatGuid}/icon`, form, {
|
|
286
|
+
await this.http.post(`/api/v1/chat/${encodeURIComponent(chatGuid)}/icon`, form, {
|
|
282
287
|
headers: form.getHeaders()
|
|
283
288
|
});
|
|
284
289
|
}
|
|
285
290
|
async removeGroupIcon(chatGuid) {
|
|
286
|
-
await this.http.delete(`/api/v1/chat/${chatGuid}/icon`);
|
|
291
|
+
await this.http.delete(`/api/v1/chat/${encodeURIComponent(chatGuid)}/icon`);
|
|
287
292
|
}
|
|
288
293
|
async getGroupIcon(chatGuid) {
|
|
289
|
-
const response = await this.http.get(`/api/v1/chat/${chatGuid}/icon`, {
|
|
294
|
+
const response = await this.http.get(`/api/v1/chat/${encodeURIComponent(chatGuid)}/icon`, {
|
|
290
295
|
responseType: "arraybuffer"
|
|
291
296
|
});
|
|
292
297
|
return Buffer.from(response.data);
|
|
@@ -298,10 +303,10 @@ var ChatModule = class {
|
|
|
298
303
|
return response.data.data;
|
|
299
304
|
}
|
|
300
305
|
async startTyping(chatGuid) {
|
|
301
|
-
await this.http.post(`/api/v1/chat/${chatGuid}/typing`);
|
|
306
|
+
await this.http.post(`/api/v1/chat/${encodeURIComponent(chatGuid)}/typing`);
|
|
302
307
|
}
|
|
303
308
|
async stopTyping(chatGuid) {
|
|
304
|
-
await this.http.delete(`/api/v1/chat/${chatGuid}/typing`);
|
|
309
|
+
await this.http.delete(`/api/v1/chat/${encodeURIComponent(chatGuid)}/typing`);
|
|
305
310
|
}
|
|
306
311
|
};
|
|
307
312
|
|
|
@@ -321,10 +326,10 @@ var ContactModule = class {
|
|
|
321
326
|
return response.data.data;
|
|
322
327
|
}
|
|
323
328
|
async shareContactCard(chatGuid) {
|
|
324
|
-
await this.http.post(`/api/v1/chat/${chatGuid}/share/contact`);
|
|
329
|
+
await this.http.post(`/api/v1/chat/${encodeURIComponent(chatGuid)}/share/contact`);
|
|
325
330
|
}
|
|
326
331
|
async shouldShareContact(chatGuid) {
|
|
327
|
-
const response = await this.http.get(`/api/v1/chat/${chatGuid}/share/contact/status`);
|
|
332
|
+
const response = await this.http.get(`/api/v1/chat/${encodeURIComponent(chatGuid)}/share/contact/status`);
|
|
328
333
|
return response.data.data;
|
|
329
334
|
}
|
|
330
335
|
};
|
|
@@ -390,6 +395,40 @@ var ICloudModule = class {
|
|
|
390
395
|
await this.http.post("/api/v1/icloud/findmy/friends/refresh");
|
|
391
396
|
}
|
|
392
397
|
};
|
|
398
|
+
|
|
399
|
+
// lib/auto-create-chat.ts
|
|
400
|
+
function isChatNotExistError(error) {
|
|
401
|
+
const axiosError = error;
|
|
402
|
+
const errorMsg = axiosError?.response?.data?.error?.message || axiosError?.response?.data?.message || "";
|
|
403
|
+
const lowerMsg = errorMsg.toLowerCase();
|
|
404
|
+
return lowerMsg.includes("chat does not exist") || lowerMsg.includes("chat not found");
|
|
405
|
+
}
|
|
406
|
+
function extractAddress(chatGuid) {
|
|
407
|
+
const parts = chatGuid.split(";-;");
|
|
408
|
+
if (parts.length !== 2 || !parts[1]) {
|
|
409
|
+
return void 0;
|
|
410
|
+
}
|
|
411
|
+
return parts[1];
|
|
412
|
+
}
|
|
413
|
+
async function createChatWithMessage(options) {
|
|
414
|
+
const { http, address, message, tempGuid, subject, effectId } = options;
|
|
415
|
+
try {
|
|
416
|
+
const response = await http.post("/api/v1/chat/new", {
|
|
417
|
+
addresses: [address],
|
|
418
|
+
message,
|
|
419
|
+
tempGuid,
|
|
420
|
+
subject,
|
|
421
|
+
effectId
|
|
422
|
+
});
|
|
423
|
+
return response.data.data?.guid;
|
|
424
|
+
} catch (error) {
|
|
425
|
+
throw new Error(
|
|
426
|
+
`Failed to create chat with address "${address}": ${error instanceof Error ? error.message : String(error)}`
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// modules/message.ts
|
|
393
432
|
var MessageModule = class {
|
|
394
433
|
constructor(http, enqueueSend = (task) => task()) {
|
|
395
434
|
this.http = http;
|
|
@@ -397,12 +436,25 @@ var MessageModule = class {
|
|
|
397
436
|
}
|
|
398
437
|
async sendMessage(options) {
|
|
399
438
|
return this.enqueueSend(async () => {
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
439
|
+
const tempGuid = options.tempGuid || crypto.randomUUID();
|
|
440
|
+
const payload = { ...options, tempGuid };
|
|
441
|
+
try {
|
|
442
|
+
const response = await this.http.post("/api/v1/message/text", payload);
|
|
443
|
+
return response.data.data;
|
|
444
|
+
} catch (error) {
|
|
445
|
+
if (!isChatNotExistError(error)) throw error;
|
|
446
|
+
const address = extractAddress(options.chatGuid);
|
|
447
|
+
if (!address) throw error;
|
|
448
|
+
await createChatWithMessage({
|
|
449
|
+
http: this.http,
|
|
450
|
+
address,
|
|
451
|
+
message: options.message,
|
|
452
|
+
tempGuid,
|
|
453
|
+
subject: options.subject,
|
|
454
|
+
effectId: options.effectId
|
|
455
|
+
});
|
|
456
|
+
return { guid: tempGuid, text: options.message, dateCreated: Date.now() };
|
|
457
|
+
}
|
|
406
458
|
});
|
|
407
459
|
}
|
|
408
460
|
async getMessage(guid, options) {
|
|
@@ -491,6 +543,51 @@ var MessageModule = class {
|
|
|
491
543
|
}
|
|
492
544
|
};
|
|
493
545
|
|
|
546
|
+
// modules/poll.ts
|
|
547
|
+
var PollModule = class {
|
|
548
|
+
constructor(http) {
|
|
549
|
+
this.http = http;
|
|
550
|
+
}
|
|
551
|
+
async create(options) {
|
|
552
|
+
if (options.options.length < 2) {
|
|
553
|
+
throw new Error("Poll must have at least 2 options");
|
|
554
|
+
}
|
|
555
|
+
const { data } = await this.http.post("/api/v1/poll/create", {
|
|
556
|
+
chatGuid: options.chatGuid,
|
|
557
|
+
title: options.title ?? "",
|
|
558
|
+
options: options.options
|
|
559
|
+
});
|
|
560
|
+
return data.data;
|
|
561
|
+
}
|
|
562
|
+
async vote(options) {
|
|
563
|
+
const { data } = await this.http.post("/api/v1/poll/vote", {
|
|
564
|
+
chatGuid: options.chatGuid,
|
|
565
|
+
pollMessageGuid: options.pollMessageGuid,
|
|
566
|
+
optionIdentifier: options.optionIdentifier
|
|
567
|
+
});
|
|
568
|
+
return data.data;
|
|
569
|
+
}
|
|
570
|
+
async unvote(options) {
|
|
571
|
+
const { data } = await this.http.post("/api/v1/poll/unvote", {
|
|
572
|
+
chatGuid: options.chatGuid,
|
|
573
|
+
pollMessageGuid: options.pollMessageGuid,
|
|
574
|
+
optionIdentifier: options.optionIdentifier
|
|
575
|
+
});
|
|
576
|
+
return data.data;
|
|
577
|
+
}
|
|
578
|
+
async addOption(options) {
|
|
579
|
+
if (!options.optionText || options.optionText.trim().length === 0) {
|
|
580
|
+
throw new Error("Option text cannot be empty");
|
|
581
|
+
}
|
|
582
|
+
const { data } = await this.http.post("/api/v1/poll/option", {
|
|
583
|
+
chatGuid: options.chatGuid,
|
|
584
|
+
pollMessageGuid: options.pollMessageGuid,
|
|
585
|
+
optionText: options.optionText
|
|
586
|
+
});
|
|
587
|
+
return data.data;
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
|
|
494
591
|
// modules/scheduled.ts
|
|
495
592
|
var ScheduledMessageModule = class {
|
|
496
593
|
constructor(http) {
|
|
@@ -532,14 +629,6 @@ var ServerModule = class {
|
|
|
532
629
|
});
|
|
533
630
|
return response.data.data;
|
|
534
631
|
}
|
|
535
|
-
async getAlerts() {
|
|
536
|
-
const response = await this.http.get("/api/v1/server/alert");
|
|
537
|
-
return response.data.data;
|
|
538
|
-
}
|
|
539
|
-
async markAlertAsRead(ids) {
|
|
540
|
-
const response = await this.http.post("/api/v1/server/alert/read", { ids });
|
|
541
|
-
return response.data.data;
|
|
542
|
-
}
|
|
543
632
|
async getMediaStatistics(options) {
|
|
544
633
|
const params = {};
|
|
545
634
|
if (options?.only) params.only = options.only.join(",");
|
|
@@ -574,6 +663,7 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
574
663
|
__publicField(this, "handles");
|
|
575
664
|
__publicField(this, "facetime");
|
|
576
665
|
__publicField(this, "icloud");
|
|
666
|
+
__publicField(this, "polls");
|
|
577
667
|
__publicField(this, "scheduledMessages");
|
|
578
668
|
__publicField(this, "server");
|
|
579
669
|
// Message deduplication feature
|
|
@@ -587,6 +677,11 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
587
677
|
// Purpose: Ensure all outgoing messages (text, attachments, stickers, etc.) from
|
|
588
678
|
// a single user/SDK instance are sent in strict order, preventing race conditions.
|
|
589
679
|
__publicField(this, "sendQueue", Promise.resolve());
|
|
680
|
+
// Flag to track if 'ready' event has been emitted
|
|
681
|
+
//
|
|
682
|
+
// Purpose: Prevent duplicate 'ready' events when both legacy mode (no API key)
|
|
683
|
+
// and auth-ok events occur, which would cause user callbacks to fire twice.
|
|
684
|
+
__publicField(this, "readyEmitted", false);
|
|
590
685
|
this.config = {
|
|
591
686
|
serverUrl: "http://localhost:1234",
|
|
592
687
|
logLevel: "info",
|
|
@@ -629,6 +724,7 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
629
724
|
this.handles = new HandleModule(this.http);
|
|
630
725
|
this.facetime = new FaceTimeModule(this.http);
|
|
631
726
|
this.icloud = new ICloudModule(this.http);
|
|
727
|
+
this.polls = new PollModule(this.http);
|
|
632
728
|
this.scheduledMessages = new ScheduledMessageModule(this.http);
|
|
633
729
|
this.server = new ServerModule(this.http);
|
|
634
730
|
}
|
|
@@ -697,11 +793,15 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
697
793
|
}
|
|
698
794
|
this.socket.on("disconnect", () => {
|
|
699
795
|
this.logger.info("Disconnected from iMessage server");
|
|
796
|
+
this.readyEmitted = false;
|
|
700
797
|
this.emit("disconnect");
|
|
701
798
|
});
|
|
702
799
|
this.socket.on("auth-ok", () => {
|
|
703
800
|
this.logger.info("Authentication successful");
|
|
704
|
-
this.
|
|
801
|
+
if (!this.readyEmitted) {
|
|
802
|
+
this.readyEmitted = true;
|
|
803
|
+
this.emit("ready");
|
|
804
|
+
}
|
|
705
805
|
});
|
|
706
806
|
this.socket.on("auth-error", (error) => {
|
|
707
807
|
this.logger.error(`Authentication failed: ${error.message} ${error.reason ? `(${error.reason})` : ""}`);
|
|
@@ -713,6 +813,13 @@ var _AdvancedIMessageKit = class _AdvancedIMessageKit extends EventEmitter.Event
|
|
|
713
813
|
}
|
|
714
814
|
this.socket.once("connect", () => {
|
|
715
815
|
this.logger.info("Connected to iMessage server, waiting for authentication...");
|
|
816
|
+
if (!this.config.apiKey) {
|
|
817
|
+
this.logger.info("No API key provided, skipping authentication (legacy server mode)");
|
|
818
|
+
if (!this.readyEmitted) {
|
|
819
|
+
this.readyEmitted = true;
|
|
820
|
+
this.emit("ready");
|
|
821
|
+
}
|
|
822
|
+
}
|
|
716
823
|
});
|
|
717
824
|
if (!this.socket.connected) {
|
|
718
825
|
this.socket.connect();
|
|
@@ -795,6 +902,144 @@ var IMESSAGE_ALIASES_REMOVED = "imessage-aliases-removed";
|
|
|
795
902
|
var FT_CALL_STATUS_CHANGED = "ft-call-status-changed";
|
|
796
903
|
var NEW_FINDMY_LOCATION = "new-findmy-location";
|
|
797
904
|
|
|
905
|
+
// lib/poll-utils.ts
|
|
906
|
+
var POLL_BALLOON_BUNDLE_ID = "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.messages.Polls";
|
|
907
|
+
var pollCache = /* @__PURE__ */ new Map();
|
|
908
|
+
function cachePoll(messageGuid, poll) {
|
|
909
|
+
pollCache.set(messageGuid, poll);
|
|
910
|
+
}
|
|
911
|
+
function getOptionTextById(optionId) {
|
|
912
|
+
for (const poll of pollCache.values()) {
|
|
913
|
+
const option = poll.options.find((o) => o.optionIdentifier === optionId);
|
|
914
|
+
if (option) return option.text;
|
|
915
|
+
}
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
function isPollMessage(message) {
|
|
919
|
+
return message.balloonBundleId === POLL_BALLOON_BUNDLE_ID;
|
|
920
|
+
}
|
|
921
|
+
function isPollVote(message) {
|
|
922
|
+
return isPollMessage(message) && message.associatedMessageType === "4000";
|
|
923
|
+
}
|
|
924
|
+
function extractDataUrl(payloadData) {
|
|
925
|
+
if (!payloadData || payloadData.length === 0) return null;
|
|
926
|
+
const payload = payloadData[0];
|
|
927
|
+
if (!payload) return null;
|
|
928
|
+
if (payload.URL && typeof payload.URL === "string") {
|
|
929
|
+
return payload.URL;
|
|
930
|
+
}
|
|
931
|
+
const objects = payload.$objects;
|
|
932
|
+
if (Array.isArray(objects)) {
|
|
933
|
+
for (const obj of objects) {
|
|
934
|
+
if (typeof obj === "object" && obj !== null) {
|
|
935
|
+
if (obj["NS.relative"] && typeof obj["NS.relative"] === "object") {
|
|
936
|
+
const relativeObj = objects[obj["NS.relative"].UID];
|
|
937
|
+
if (typeof relativeObj === "string" && relativeObj.startsWith("data:,")) {
|
|
938
|
+
return relativeObj;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
if (typeof obj === "string" && obj.startsWith("data:,")) {
|
|
942
|
+
return obj;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
return null;
|
|
948
|
+
}
|
|
949
|
+
function parseDataUrl(dataUrl) {
|
|
950
|
+
try {
|
|
951
|
+
const prefix = "data:,";
|
|
952
|
+
if (!dataUrl.startsWith(prefix)) return null;
|
|
953
|
+
let data = dataUrl.slice(prefix.length);
|
|
954
|
+
const queryIndex = data.indexOf("?");
|
|
955
|
+
if (queryIndex !== -1) {
|
|
956
|
+
data = data.slice(0, queryIndex);
|
|
957
|
+
}
|
|
958
|
+
data = decodeURIComponent(data);
|
|
959
|
+
try {
|
|
960
|
+
return JSON.parse(data);
|
|
961
|
+
} catch {
|
|
962
|
+
const decoded = Buffer.from(data, "base64").toString("utf-8");
|
|
963
|
+
return JSON.parse(decoded);
|
|
964
|
+
}
|
|
965
|
+
} catch {
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
function parsePollDefinition(message) {
|
|
970
|
+
if (!isPollMessage(message)) return null;
|
|
971
|
+
if (isPollVote(message)) return null;
|
|
972
|
+
const dataUrl = extractDataUrl(message.payloadData);
|
|
973
|
+
if (!dataUrl) return null;
|
|
974
|
+
const data = parseDataUrl(dataUrl);
|
|
975
|
+
if (!data || !data.item) return null;
|
|
976
|
+
const parsed = {
|
|
977
|
+
title: data.item.title || "",
|
|
978
|
+
creatorHandle: data.item.creatorHandle || "",
|
|
979
|
+
options: data.item.orderedPollOptions || []
|
|
980
|
+
};
|
|
981
|
+
if (message.guid) {
|
|
982
|
+
cachePoll(message.guid, parsed);
|
|
983
|
+
}
|
|
984
|
+
return parsed;
|
|
985
|
+
}
|
|
986
|
+
function parsePollVotes(message) {
|
|
987
|
+
if (!isPollMessage(message)) return null;
|
|
988
|
+
if (!isPollVote(message)) return null;
|
|
989
|
+
const dataUrl = extractDataUrl(message.payloadData);
|
|
990
|
+
if (!dataUrl) return null;
|
|
991
|
+
const data = parseDataUrl(dataUrl);
|
|
992
|
+
if (!data || !data.item) return null;
|
|
993
|
+
return {
|
|
994
|
+
votes: data.item.votes || []
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
function getPollSummary(message) {
|
|
998
|
+
if (!isPollMessage(message)) {
|
|
999
|
+
return message.text || "(no text)";
|
|
1000
|
+
}
|
|
1001
|
+
if (isPollVote(message)) {
|
|
1002
|
+
const voteData = parsePollVotes(message);
|
|
1003
|
+
if (voteData && voteData.votes.length > 0) {
|
|
1004
|
+
const votes = voteData.votes.map((v) => {
|
|
1005
|
+
const optionText = getOptionTextById(v.voteOptionIdentifier);
|
|
1006
|
+
const optionDisplay = optionText ? `"${optionText}"` : `option ${v.voteOptionIdentifier}`;
|
|
1007
|
+
return `${v.participantHandle || "Someone"} voted ${optionDisplay}`;
|
|
1008
|
+
}).join(", ");
|
|
1009
|
+
return `[Poll Vote] ${votes}`;
|
|
1010
|
+
}
|
|
1011
|
+
return "[Poll Vote]";
|
|
1012
|
+
}
|
|
1013
|
+
const pollData = parsePollDefinition(message);
|
|
1014
|
+
if (pollData) {
|
|
1015
|
+
const title = pollData.title ? `"${pollData.title}"` : "(untitled poll)";
|
|
1016
|
+
const optionsList = pollData.options.map((opt, i) => ` ${i + 1}. ${opt.text}`).join("\n");
|
|
1017
|
+
return `[Poll] ${title}
|
|
1018
|
+
${optionsList}`;
|
|
1019
|
+
}
|
|
1020
|
+
return "[Poll] (unable to parse)";
|
|
1021
|
+
}
|
|
1022
|
+
function getPollOneLiner(message) {
|
|
1023
|
+
if (!isPollMessage(message)) {
|
|
1024
|
+
return message.text || "(no text)";
|
|
1025
|
+
}
|
|
1026
|
+
if (isPollVote(message)) {
|
|
1027
|
+
const voteData = parsePollVotes(message);
|
|
1028
|
+
if (voteData && voteData.votes.length > 0) {
|
|
1029
|
+
return `[Poll Vote] ${voteData.votes.length} vote(s)`;
|
|
1030
|
+
}
|
|
1031
|
+
return "[Poll Vote]";
|
|
1032
|
+
}
|
|
1033
|
+
const pollData = parsePollDefinition(message);
|
|
1034
|
+
if (pollData) {
|
|
1035
|
+
const title = pollData.title || "Poll";
|
|
1036
|
+
const optionsPreview = pollData.options.slice(0, 2).map((o) => o.text).join(", ");
|
|
1037
|
+
const moreOptions = pollData.options.length > 2 ? `, +${pollData.options.length - 2} more` : "";
|
|
1038
|
+
return `[${title}] ${optionsPreview}${moreOptions}`;
|
|
1039
|
+
}
|
|
1040
|
+
return "[Poll]";
|
|
1041
|
+
}
|
|
1042
|
+
|
|
798
1043
|
exports.AdvancedIMessageKit = AdvancedIMessageKit;
|
|
799
1044
|
exports.CHAT_READ_STATUS_CHANGED = CHAT_READ_STATUS_CHANGED;
|
|
800
1045
|
exports.FT_CALL_STATUS_CHANGED = FT_CALL_STATUS_CHANGED;
|
|
@@ -829,6 +1074,12 @@ exports.THEME_BACKUP_DELETED = THEME_BACKUP_DELETED;
|
|
|
829
1074
|
exports.THEME_BACKUP_UPDATED = THEME_BACKUP_UPDATED;
|
|
830
1075
|
exports.TYPING_INDICATOR = TYPING_INDICATOR;
|
|
831
1076
|
exports.getLogger = getLogger;
|
|
1077
|
+
exports.getPollOneLiner = getPollOneLiner;
|
|
1078
|
+
exports.getPollSummary = getPollSummary;
|
|
1079
|
+
exports.isPollMessage = isPollMessage;
|
|
1080
|
+
exports.isPollVote = isPollVote;
|
|
1081
|
+
exports.parsePollDefinition = parsePollDefinition;
|
|
1082
|
+
exports.parsePollVotes = parsePollVotes;
|
|
832
1083
|
exports.setGlobalLogLevel = setGlobalLogLevel;
|
|
833
1084
|
//# sourceMappingURL=index.cjs.map
|
|
834
1085
|
//# sourceMappingURL=index.cjs.map
|