@spectrum-ts/imessage 8.1.0 → 8.1.1
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 +104 -56
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -204,8 +204,9 @@ const spaceSchema = z.object({
|
|
|
204
204
|
const spaceParamsSchema = z.object({ phone: z.string().optional() });
|
|
205
205
|
/**
|
|
206
206
|
* iMessage-specific per-message metadata surfaced on `IMessageMessage`.
|
|
207
|
-
* - `partIndex`:
|
|
208
|
-
*
|
|
207
|
+
* - `partIndex`: ordered part index within a multi-part message. Text and
|
|
208
|
+
* attachment parts both consume an index (0 for bare or single-part
|
|
209
|
+
* messages; 0..N-1 for a group's sub-items).
|
|
209
210
|
* - `parentId`: guid of the parent message for a group sub-item. Undefined
|
|
210
211
|
* when the message itself is the parent.
|
|
211
212
|
*/
|
|
@@ -445,6 +446,43 @@ const getPollCache = (owner) => {
|
|
|
445
446
|
}
|
|
446
447
|
return cache;
|
|
447
448
|
};
|
|
449
|
+
const addTextPart = (parts, text) => {
|
|
450
|
+
const trimmed = text?.trim();
|
|
451
|
+
if (trimmed) parts.push({
|
|
452
|
+
type: "text",
|
|
453
|
+
text: trimmed
|
|
454
|
+
});
|
|
455
|
+
};
|
|
456
|
+
const hasUsableTextPart = (text) => text?.split("").some((segment) => segment.trim()) ?? false;
|
|
457
|
+
const addAttachmentParts = (parts, attachments) => {
|
|
458
|
+
for (const attachment of attachments) if (attachment) parts.push({
|
|
459
|
+
type: "attachment",
|
|
460
|
+
attachment
|
|
461
|
+
});
|
|
462
|
+
};
|
|
463
|
+
const toOrderedParts = (text, attachments) => {
|
|
464
|
+
const parts = [];
|
|
465
|
+
if (!text) {
|
|
466
|
+
addAttachmentParts(parts, attachments);
|
|
467
|
+
return parts;
|
|
468
|
+
}
|
|
469
|
+
if (!text.includes("")) {
|
|
470
|
+
addAttachmentParts(parts, attachments);
|
|
471
|
+
addTextPart(parts, text);
|
|
472
|
+
return parts;
|
|
473
|
+
}
|
|
474
|
+
const textSegments = text.split("");
|
|
475
|
+
for (let i = 0; i < attachments.length; i++) {
|
|
476
|
+
addTextPart(parts, textSegments[i]);
|
|
477
|
+
const attachment = attachments[i];
|
|
478
|
+
if (attachment) parts.push({
|
|
479
|
+
type: "attachment",
|
|
480
|
+
attachment
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
addTextPart(parts, textSegments.slice(attachments.length).join(""));
|
|
484
|
+
return parts;
|
|
485
|
+
};
|
|
448
486
|
//#endregion
|
|
449
487
|
//#region src/shared/vcard.ts
|
|
450
488
|
const VCARD_MIME_TYPES = new Set([
|
|
@@ -487,11 +525,10 @@ const toVCardContent$1 = async (att) => {
|
|
|
487
525
|
const localAttachmentContent = async (att) => isVCardAttachment(att.mimeType, att.fileName) ? await toVCardContent$1(att) : toAttachmentContent$1(att);
|
|
488
526
|
//#endregion
|
|
489
527
|
//#region src/local/inbound.ts
|
|
490
|
-
const ATTACHMENT_PLACEHOLDER = "";
|
|
491
528
|
const ATTACHMENT_JOIN_RETRY_DELAY_MS = 250;
|
|
492
529
|
const ATTACHMENT_JOIN_RETRY_LIMIT = 8;
|
|
493
530
|
const ATTACHMENT_JOIN_FETCH_LIMIT = 10;
|
|
494
|
-
const hasAttachmentPlaceholder = (message) => message.text?.includes(
|
|
531
|
+
const hasAttachmentPlaceholder = (message) => message.text?.includes("") ?? false;
|
|
495
532
|
const isPendingAttachmentJoin = (message) => message.attachments.length === 0 && (message.hasAttachments || hasAttachmentPlaceholder(message));
|
|
496
533
|
const refetchUntilAttachmentsSettle = async (client, message) => {
|
|
497
534
|
if (!message.chatId) return message;
|
|
@@ -529,11 +566,31 @@ const toMessages = async (message) => {
|
|
|
529
566
|
},
|
|
530
567
|
timestamp: message.createdAt
|
|
531
568
|
};
|
|
532
|
-
if (message.attachments.length > 0)
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
569
|
+
if (message.attachments.length > 0) {
|
|
570
|
+
if (!hasUsableTextPart(message.text)) return Promise.all(message.attachments.map(async (att) => ({
|
|
571
|
+
...base,
|
|
572
|
+
id: `${message.id}:${att.id}`,
|
|
573
|
+
content: await localAttachmentContent(att)
|
|
574
|
+
})));
|
|
575
|
+
const parts = toOrderedParts(message.text, message.attachments);
|
|
576
|
+
const messages = [];
|
|
577
|
+
for (let i = 0; i < parts.length; i++) {
|
|
578
|
+
const part = parts[i];
|
|
579
|
+
if (!part) continue;
|
|
580
|
+
messages.push(part.type === "text" ? {
|
|
581
|
+
...base,
|
|
582
|
+
id: `${message.id}:text:${i}`,
|
|
583
|
+
content: asText(part.text),
|
|
584
|
+
partIndex: i
|
|
585
|
+
} : {
|
|
586
|
+
...base,
|
|
587
|
+
id: `${message.id}:${part.attachment.id}`,
|
|
588
|
+
content: await localAttachmentContent(part.attachment),
|
|
589
|
+
partIndex: i
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
return messages;
|
|
593
|
+
}
|
|
537
594
|
return [{
|
|
538
595
|
...base,
|
|
539
596
|
id: message.id,
|
|
@@ -868,35 +925,54 @@ const buildAttachmentMessage = async (client, base, info, id, partIndex, parentI
|
|
|
868
925
|
if (parentId !== void 0) msg.parentId = parentId;
|
|
869
926
|
return msg;
|
|
870
927
|
};
|
|
871
|
-
const
|
|
872
|
-
const
|
|
873
|
-
|
|
928
|
+
const buildTextMessage = (base, text, id, partIndex, parentId) => {
|
|
929
|
+
const msg = {
|
|
930
|
+
...base,
|
|
931
|
+
id,
|
|
932
|
+
content: asText(text),
|
|
933
|
+
partIndex
|
|
934
|
+
};
|
|
935
|
+
if (parentId !== void 0) msg.parentId = parentId;
|
|
936
|
+
return msg;
|
|
937
|
+
};
|
|
938
|
+
const buildOrderedPartMessage = async (client, base, part, id, partIndex, parentId) => part.type === "text" ? buildTextMessage(base, part.text, id, partIndex, parentId) : await buildAttachmentMessage(client, base, part.attachment, id, partIndex, parentId);
|
|
939
|
+
const buildContentMessage = async (client, base, message, messageGuidStr) => {
|
|
874
940
|
const attachments = messageAttachments(message);
|
|
875
|
-
if (attachments.length ===
|
|
876
|
-
const
|
|
877
|
-
if (!info) throw new Error("Unreachable: attachments.length === 1 but no element");
|
|
878
|
-
return buildAttachmentMessage(client, base, info, messageGuidStr, 0);
|
|
879
|
-
}
|
|
880
|
-
if (attachments.length > 1) {
|
|
881
|
-
const items = [];
|
|
882
|
-
for (let i = 0; i < attachments.length; i++) {
|
|
883
|
-
const info = attachments[i];
|
|
884
|
-
if (!info) continue;
|
|
885
|
-
items.push(await buildAttachmentMessage(client, base, info, formatChildId(i, messageGuidStr), i, messageGuidStr));
|
|
886
|
-
}
|
|
941
|
+
if (attachments.length === 0) {
|
|
942
|
+
const text = message.content.text;
|
|
887
943
|
return {
|
|
888
944
|
...base,
|
|
889
945
|
id: messageGuidStr,
|
|
890
|
-
content:
|
|
946
|
+
content: text ? asText(text) : asCustom(message)
|
|
891
947
|
};
|
|
892
948
|
}
|
|
893
|
-
const
|
|
949
|
+
const parts = toOrderedParts(message.content.text, attachments);
|
|
950
|
+
if (parts.length === 0) return {
|
|
951
|
+
...base,
|
|
952
|
+
id: messageGuidStr,
|
|
953
|
+
content: asCustom(message)
|
|
954
|
+
};
|
|
955
|
+
if (parts.length === 1) {
|
|
956
|
+
const part = parts[0];
|
|
957
|
+
if (!part) throw new Error("Unreachable: parts.length === 1 but no element");
|
|
958
|
+
return buildOrderedPartMessage(client, base, part, messageGuidStr, 0);
|
|
959
|
+
}
|
|
960
|
+
const items = [];
|
|
961
|
+
for (let i = 0; i < parts.length; i++) {
|
|
962
|
+
const part = parts[i];
|
|
963
|
+
if (!part) continue;
|
|
964
|
+
items.push(await buildOrderedPartMessage(client, base, part, formatChildId(i, messageGuidStr), i, messageGuidStr));
|
|
965
|
+
}
|
|
894
966
|
return {
|
|
895
967
|
...base,
|
|
896
968
|
id: messageGuidStr,
|
|
897
|
-
content:
|
|
969
|
+
content: asProviderGroup(items)
|
|
898
970
|
};
|
|
899
971
|
};
|
|
972
|
+
const rebuildFromAppleMessage = async (client, message, phone, chatGuidHint) => {
|
|
973
|
+
const messageGuidStr = message.guid;
|
|
974
|
+
return buildContentMessage(client, buildMessageBase(message, chatGuidHint, message.dateCreated ?? /* @__PURE__ */ new Date(), phone), message, messageGuidStr);
|
|
975
|
+
};
|
|
900
976
|
const cacheMessage = (cache, message) => {
|
|
901
977
|
cache.set(message.id, message);
|
|
902
978
|
if (message.content.type === "group") {
|
|
@@ -906,35 +982,7 @@ const cacheMessage = (cache, message) => {
|
|
|
906
982
|
const toInboundMessages = async (client, cache, event, phone) => {
|
|
907
983
|
const base = buildMessageBase(event.message, event.chatGuid, event.occurredAt, phone);
|
|
908
984
|
const messageGuidStr = event.message.guid;
|
|
909
|
-
const
|
|
910
|
-
if (attachments.length === 1) {
|
|
911
|
-
const info = attachments[0];
|
|
912
|
-
if (!info) throw new Error("Unreachable: attachments.length === 1 but no element");
|
|
913
|
-
const msg = await buildAttachmentMessage(client, base, info, messageGuidStr, 0);
|
|
914
|
-
cacheMessage(cache, msg);
|
|
915
|
-
return [msg];
|
|
916
|
-
}
|
|
917
|
-
if (attachments.length > 1) {
|
|
918
|
-
const items = [];
|
|
919
|
-
for (let i = 0; i < attachments.length; i++) {
|
|
920
|
-
const info = attachments[i];
|
|
921
|
-
if (!info) continue;
|
|
922
|
-
items.push(await buildAttachmentMessage(client, base, info, formatChildId(i, messageGuidStr), i, messageGuidStr));
|
|
923
|
-
}
|
|
924
|
-
const parent = {
|
|
925
|
-
...base,
|
|
926
|
-
id: messageGuidStr,
|
|
927
|
-
content: asProviderGroup(items)
|
|
928
|
-
};
|
|
929
|
-
cacheMessage(cache, parent);
|
|
930
|
-
return [parent];
|
|
931
|
-
}
|
|
932
|
-
const text = event.message.content.text;
|
|
933
|
-
const msg = {
|
|
934
|
-
...base,
|
|
935
|
-
id: messageGuidStr,
|
|
936
|
-
content: text ? asText(text) : asCustom(event.message)
|
|
937
|
-
};
|
|
985
|
+
const msg = await buildContentMessage(client, base, event.message, messageGuidStr);
|
|
938
986
|
cacheMessage(cache, msg);
|
|
939
987
|
return [msg];
|
|
940
988
|
};
|