@spectrum-ts/imessage 5.0.0 → 5.2.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
@@ -161,7 +161,16 @@ interface RemoteClient {
161
161
  phone: string;
162
162
  }
163
163
  type IMessageClient = IMessageSDK | RemoteClient[];
164
- declare const userSchema: z.ZodObject<{}, z.core.$strip>;
164
+ declare const userSchema: z.ZodObject<{
165
+ address: z.ZodOptional<z.ZodString>;
166
+ country: z.ZodOptional<z.ZodString>;
167
+ service: z.ZodOptional<z.ZodEnum<{
168
+ iMessage: "iMessage";
169
+ unknown: "unknown";
170
+ SMS: "SMS";
171
+ RCS: "RCS";
172
+ }>>;
173
+ }, z.core.$strip>;
165
174
  declare const spaceSchema: z.ZodObject<{
166
175
  id: z.ZodString;
167
176
  type: z.ZodEnum<{
@@ -190,7 +199,16 @@ declare const imessage: import("@spectrum-ts/core").Platform<import("@spectrum-t
190
199
  token: import("zod").ZodString;
191
200
  phone: import("zod").ZodString;
192
201
  }, import("zod/v4/core").$strip>>]>>;
193
- }, import("zod/v4/core").$strip>]>, import("zod").ZodType<object, unknown, import("zod/v4/core").$ZodTypeInternals<object, unknown>> | undefined, import("zod").ZodObject<{
202
+ }, import("zod/v4/core").$strip>]>, import("zod").ZodObject<{
203
+ address: import("zod").ZodOptional<import("zod").ZodString>;
204
+ country: import("zod").ZodOptional<import("zod").ZodString>;
205
+ service: import("zod").ZodOptional<import("zod").ZodEnum<{
206
+ iMessage: "iMessage";
207
+ unknown: "unknown";
208
+ SMS: "SMS";
209
+ RCS: "RCS";
210
+ }>>;
211
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
194
212
  id: import("zod").ZodString;
195
213
  type: import("zod").ZodEnum<{
196
214
  dm: "dm";
package/dist/index.js CHANGED
@@ -186,7 +186,16 @@ const configSchema = z.union([z.object({ local: z.literal(true) }), z.object({
186
186
  local: z.literal(false).optional().default(false),
187
187
  clients: clientEntry.or(z.array(clientEntry)).optional()
188
188
  })]);
189
- z.object({});
189
+ const userSchema = z.object({
190
+ address: z.string().optional(),
191
+ country: z.string().optional(),
192
+ service: z.enum([
193
+ "iMessage",
194
+ "SMS",
195
+ "RCS",
196
+ "unknown"
197
+ ]).optional()
198
+ });
190
199
  const spaceSchema = z.object({
191
200
  id: z.string(),
192
201
  type: z.enum(["dm", "group"]),
@@ -480,7 +489,10 @@ const toMessages = async (message) => {
480
489
  if (message.reaction !== null || message.kind !== "text" || message.retractedAt !== null) return [];
481
490
  if (isPendingAttachmentJoin(message)) return [];
482
491
  const base = {
483
- sender: { id: message.participant ?? "" },
492
+ sender: {
493
+ id: message.participant ?? "",
494
+ ...message.participant ? { address: message.participant } : {}
495
+ },
484
496
  space: {
485
497
  id: chatId,
486
498
  type: chatKind === "group" ? "group" : "dm",
@@ -764,7 +776,18 @@ const resolveChatGuid = (message, hint) => {
764
776
  if (hint) return hint;
765
777
  return message.chatGuids?.[0] ?? "";
766
778
  };
767
- const resolveSenderId = (message) => message.sender?.address ?? "";
779
+ /**
780
+ * Normalize an Apple address (`message.sender` or an event `actor`) into the
781
+ * spectrum sender ref. `id` stays the cross-provider identity key (the
782
+ * address); `address`/`country`/`service` are surfaced when present so apps
783
+ * can tell iMessage from SMS/RCS. Empty fields are omitted.
784
+ */
785
+ const toSenderRef = (addr) => ({
786
+ id: addr?.address ?? "",
787
+ ...addr?.address ? { address: addr.address } : {},
788
+ ...addr?.country ? { country: addr.country } : {},
789
+ ...addr?.service ? { service: addr.service } : {}
790
+ });
768
791
  const isIMessageMessage = (value) => {
769
792
  if (typeof value !== "object" || value === null) return false;
770
793
  const record = value;
@@ -778,7 +801,7 @@ const buildMessageBase = (message, chatGuidHint, timestamp, phone) => {
778
801
  const chat = resolveChatGuid(message, chatGuidHint);
779
802
  return {
780
803
  direction: message.isFromMe ? "outbound" : "inbound",
781
- sender: { id: resolveSenderId(message) },
804
+ sender: toSenderRef(message.sender),
782
805
  space: {
783
806
  id: chat,
784
807
  type: chatTypeFromGuid(chat),
@@ -974,13 +997,12 @@ const resolveReactionTarget = async (client, cache, chat, targetGuid, partIndex,
974
997
  const toReactionMessages = async (client, cache, event, phone) => {
975
998
  const emoji = reactionEmoji(event.reaction);
976
999
  if (!emoji) return [];
977
- const senderAddress = event.actor?.address;
978
- if (!senderAddress) return [];
1000
+ if (!event.actor?.address) return [];
979
1001
  const resolved = await resolveReactionTarget(client, cache, event.chatGuid, event.messageGuid, event.targetPartIndex, phone);
980
1002
  if (!resolved) return [];
981
1003
  const partSuffix = typeof event.targetPartIndex === "number" ? `:${event.targetPartIndex}` : "";
982
1004
  return [{
983
- sender: { id: senderAddress },
1005
+ sender: toSenderRef(event.actor),
984
1006
  space: {
985
1007
  id: event.chatGuid,
986
1008
  type: chatTypeFromGuid(event.chatGuid),
@@ -1609,8 +1631,8 @@ const buildPollOptionMessage = (input) => {
1609
1631
  const action = input.selected ? "selected" : "deselected";
1610
1632
  const eventTime = input.event.occurredAt.getTime();
1611
1633
  return {
1612
- id: `${input.event.pollMessageGuid}:${input.senderAddress}:${input.optionId}:${action}:${eventTime}`,
1613
- sender: { id: input.senderAddress },
1634
+ id: `${input.event.pollMessageGuid}:${input.sender.id}:${input.optionId}:${action}:${eventTime}`,
1635
+ sender: input.sender,
1614
1636
  space: {
1615
1637
  id: input.chatGuid,
1616
1638
  type: chatTypeFromGuid(input.chatGuid),
@@ -1630,9 +1652,9 @@ const refreshPollMetadata = async (client, pollCache, event) => {
1630
1652
  return pollCache.get(info.pollMessageGuid);
1631
1653
  };
1632
1654
  const toPollOptionMessage = async (client, pollCache, event, phone) => {
1633
- const senderAddress = event.actor?.address;
1655
+ const sender = toSenderRef(event.actor);
1634
1656
  const optionId = event.delta.optionIdentifier;
1635
- if (!(senderAddress && optionId)) return [];
1657
+ if (!(sender.id && optionId)) return [];
1636
1658
  let cached = await resolvePoll(client, pollCache, event);
1637
1659
  if (!cached) return [];
1638
1660
  if (!cached.optionsByIdentifier.has(optionId)) {
@@ -1646,7 +1668,7 @@ const toPollOptionMessage = async (client, pollCache, event, phone) => {
1646
1668
  optionId,
1647
1669
  phone,
1648
1670
  selected: event.delta.type === "voted",
1649
- senderAddress
1671
+ sender
1650
1672
  });
1651
1673
  return message ? [message] : [];
1652
1674
  };
@@ -2038,7 +2060,10 @@ const imessage = definePlatform("iMessage", {
2038
2060
  await Promise.all(client.map((entry) => entry.client.close()));
2039
2061
  }
2040
2062
  },
2041
- user: { resolve: async ({ input }) => ({ id: input.userID }) },
2063
+ user: {
2064
+ schema: userSchema,
2065
+ resolve: async ({ input }) => ({ id: input.userID })
2066
+ },
2042
2067
  space: {
2043
2068
  schema: spaceSchema,
2044
2069
  params: spaceParamsSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectrum-ts/imessage",
3
- "version": "5.0.0",
3
+ "version": "5.2.0",
4
4
  "description": "iMessage provider for spectrum-ts — local and remote (advanced) modes.",
5
5
  "repository": {
6
6
  "type": "git",