@spectrum-ts/imessage 9.0.0 → 9.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
@@ -141,6 +141,7 @@ declare const customizedMiniAppSchema: z.ZodObject<{
141
141
  imageSubtitle: z.ZodOptional<z.ZodString>;
142
142
  summary: z.ZodOptional<z.ZodString>;
143
143
  }, z.core.$strip>;
144
+ live: z.ZodOptional<z.ZodBoolean>;
144
145
  teamId: z.ZodString;
145
146
  url: z.ZodURL;
146
147
  }, z.core.$strip>;
@@ -155,7 +156,8 @@ type CustomizedMiniAppInput = Omit<CustomizedMiniApp, "type" | "__platform">;
155
156
  * the recipient taps the card; the server constructs the matching
156
157
  * `MSMessageExtensionBalloonPlugin` plugin id from these values. `appStoreId`
157
158
  * is optional and only points recipients without the extension at its App
158
- * Store entry.
159
+ * Store entry. `live` is optional; when omitted, the remote server keeps the
160
+ * static layout preview visible.
159
161
  *
160
162
  * `space.send(customizedMiniApp(...))` is the canonical form.
161
163
  *
@@ -193,8 +195,25 @@ declare const spaceSchema: z.ZodObject<{
193
195
  }>;
194
196
  phone: z.ZodString;
195
197
  }, z.core.$strip>;
198
+ declare const miniAppCardSessionSchema: z.ZodObject<{
199
+ chatGuid: z.ZodString;
200
+ messageGuid: z.ZodString;
201
+ sessionId: z.ZodString;
202
+ targetMessageGuid: z.ZodString;
203
+ }, z.core.$strip>;
204
+ /**
205
+ * iMessage-specific per-message metadata surfaced on `IMessageMessage`.
206
+ * - `partIndex`: ordered part index within a multi-part message. Text and
207
+ * attachment parts both consume an index (0 for bare or single-part
208
+ * messages; 0..N-1 for a group's sub-items).
209
+ * - `parentId`: guid of the parent message for a group sub-item. Undefined
210
+ * when the message itself is the parent.
211
+ * - `miniAppCardSession`: stable handle returned by mini-app card sends and
212
+ * updates. It is required to update the card in place later.
213
+ */
196
214
  type IMessageMessage = SchemaMessage<typeof userSchema, typeof spaceSchema> & {
197
215
  direction?: "inbound" | "outbound";
216
+ miniAppCardSession?: z.infer<typeof miniAppCardSessionSchema>;
198
217
  partIndex?: number;
199
218
  parentId?: string;
200
219
  };
@@ -238,6 +257,12 @@ declare const imessage: import("@spectrum-ts/core").Platform<import("@spectrum-t
238
257
  type: "dm" | "group";
239
258
  phone: string;
240
259
  }, import("zod").ZodObject<{
260
+ miniAppCardSession: import("zod").ZodOptional<import("zod").ZodObject<{
261
+ chatGuid: import("zod").ZodString;
262
+ messageGuid: import("zod").ZodString;
263
+ sessionId: import("zod").ZodString;
264
+ targetMessageGuid: import("zod").ZodString;
265
+ }, import("zod/v4/core").$strip>>;
241
266
  partIndex: import("zod").ZodOptional<import("zod").ZodNumber>;
242
267
  parentId: import("zod").ZodOptional<import("zod").ZodString>;
243
268
  }, import("zod/v4/core").$strip>, IMessageMessage, undefined, {
@@ -327,6 +352,33 @@ declare const imessage: import("@spectrum-ts/core").Platform<import("@spectrum-t
327
352
  id: string;
328
353
  __platform: string;
329
354
  }) => Promise<import("@spectrum-ts/core").AvatarData | undefined>;
355
+ getDisplayName: ({
356
+ client
357
+ }: {
358
+ client: IMessageClient;
359
+ config: {
360
+ local: true;
361
+ } | {
362
+ local: false;
363
+ clients?: {
364
+ address: string;
365
+ token: string;
366
+ phone: string;
367
+ } | {
368
+ address: string;
369
+ token: string;
370
+ phone: string;
371
+ }[] | undefined;
372
+ };
373
+ store: import("@spectrum-ts/core").Store;
374
+ }, space: {
375
+ id: string;
376
+ type: "dm" | "group";
377
+ phone: string;
378
+ } & {
379
+ id: string;
380
+ __platform: string;
381
+ }) => Promise<string | undefined>;
330
382
  getAttachment: ({
331
383
  client
332
384
  }: {
package/dist/index.js CHANGED
@@ -124,6 +124,7 @@ const customizedMiniAppSchema = z.object({
124
124
  appStoreId: z.number().int().positive().optional(),
125
125
  extensionBundleId: z.string().nonempty(),
126
126
  layout: layoutSchema,
127
+ live: z.boolean().optional(),
127
128
  teamId: z.string(),
128
129
  url: z.url()
129
130
  });
@@ -141,7 +142,8 @@ const asCustomizedMiniApp = (input) => customizedMiniAppSchema.parse({
141
142
  * the recipient taps the card; the server constructs the matching
142
143
  * `MSMessageExtensionBalloonPlugin` plugin id from these values. `appStoreId`
143
144
  * is optional and only points recipients without the extension at its App
144
- * Store entry.
145
+ * Store entry. `live` is optional; when omitted, the remote server keeps the
146
+ * static layout preview visible.
145
147
  *
146
148
  * `space.send(customizedMiniApp(...))` is the canonical form.
147
149
  *
@@ -202,6 +204,12 @@ const spaceSchema = z.object({
202
204
  phone: z.string()
203
205
  });
204
206
  const spaceParamsSchema = z.object({ phone: z.string().optional() });
207
+ const miniAppCardSessionSchema = z.object({
208
+ chatGuid: z.string(),
209
+ messageGuid: z.string(),
210
+ sessionId: z.string(),
211
+ targetMessageGuid: z.string()
212
+ });
205
213
  /**
206
214
  * iMessage-specific per-message metadata surfaced on `IMessageMessage`.
207
215
  * - `partIndex`: ordered part index within a multi-part message. Text and
@@ -209,8 +217,11 @@ const spaceParamsSchema = z.object({ phone: z.string().optional() });
209
217
  * messages; 0..N-1 for a group's sub-items).
210
218
  * - `parentId`: guid of the parent message for a group sub-item. Undefined
211
219
  * when the message itself is the parent.
220
+ * - `miniAppCardSession`: stable handle returned by mini-app card sends and
221
+ * updates. It is required to update the card in place later.
212
222
  */
213
223
  const messageSchema = z.object({
224
+ miniAppCardSession: miniAppCardSessionSchema.optional(),
214
225
  partIndex: z.number().int().nonnegative().optional(),
215
226
  parentId: z.string().optional()
216
227
  });
@@ -789,6 +800,14 @@ const shareContactCard$1 = async (remote, spaceId) => {
789
800
  };
790
801
  //#endregion
791
802
  //#region src/remote/customized-mini-app.ts
803
+ const toProviderRecord = (result, content, spaceId) => ({
804
+ id: result.guid,
805
+ content,
806
+ direction: "outbound",
807
+ miniAppCardSession: result.miniAppCardSession,
808
+ space: { id: spaceId },
809
+ timestamp: result.dateCreated
810
+ });
792
811
  /**
793
812
  * Send a `CustomizedMiniApp` card to a remote iMessage chat.
794
813
  *
@@ -800,14 +819,10 @@ const shareContactCard$1 = async (remote, spaceId) => {
800
819
  */
801
820
  const sendCustomizedMiniApp$1 = async (remote, spaceId, content) => {
802
821
  const chat = toChatGuid(spaceId);
803
- const message = await remote.messages.sendCustomizedMiniApp(chat, content);
804
- return {
805
- id: message.guid,
806
- content,
807
- direction: "outbound",
808
- space: { id: spaceId },
809
- timestamp: message.dateCreated
810
- };
822
+ return toProviderRecord(await remote.messages.sendCustomizedMiniApp(chat, content), content, spaceId);
823
+ };
824
+ const updateCustomizedMiniApp$1 = async (remote, spaceId, session, content) => {
825
+ return toProviderRecord(await remote.messages.updateCustomizedMiniApp(session, content), content, spaceId);
811
826
  };
812
827
  //#endregion
813
828
  //#region src/remote/attachments.ts
@@ -1248,6 +1263,15 @@ const markRead$1 = async (remote, spaceId) => {
1248
1263
  const setDisplayName$1 = async (remote, spaceId, content) => {
1249
1264
  await remote.groups.setDisplayName(toChatGuid(spaceId), content.displayName);
1250
1265
  };
1266
+ /**
1267
+ * Read a remote iMessage group chat's title. The SDK returns an empty
1268
+ * `Chat.displayName` for an unnamed group; normalized to `undefined`. The
1269
+ * group-only guard lives at the action layer (see `remoteGroupClient`).
1270
+ */
1271
+ const getDisplayName$1 = async (remote, spaceId) => {
1272
+ const { displayName } = await remote.chats.get(toChatGuid(spaceId));
1273
+ return displayName || void 0;
1274
+ };
1251
1275
  //#endregion
1252
1276
  //#region src/remote/markdown.ts
1253
1277
  const markdownLexer = new Marked();
@@ -2154,7 +2178,9 @@ const stopTyping$1 = async (remote, spaceId) => {
2154
2178
  const messages = (clients, projectConfig) => messages$1(clients, projectConfig);
2155
2179
  const setBackground = async (remote, spaceId, content) => setBackground$1(remote, spaceId, content);
2156
2180
  const sendCustomizedMiniApp = async (remote, spaceId, content) => sendCustomizedMiniApp$1(remote, spaceId, content);
2181
+ const updateCustomizedMiniApp = async (remote, spaceId, session, content) => updateCustomizedMiniApp$1(remote, spaceId, session, content);
2157
2182
  const setDisplayName = async (remote, spaceId, content) => setDisplayName$1(remote, spaceId, content);
2183
+ const getDisplayName = async (remote, spaceId) => getDisplayName$1(remote, spaceId);
2158
2184
  const addParticipants = async (remote, spaceId, content) => addParticipants$1(remote, spaceId, content);
2159
2185
  const removeParticipants = async (remote, spaceId, content) => removeParticipants$1(remote, spaceId, content);
2160
2186
  const leaveGroup = async (remote, spaceId) => leaveGroup$1(remote, spaceId);
@@ -2198,13 +2224,14 @@ const SPECTRUM_MINI_APP = {
2198
2224
  };
2199
2225
  /**
2200
2226
  * Build the iMessage mini-app card for an `app` content: Spectrum's fixed
2201
- * identity plus the per-message `url` and the `layout` already derived from the
2202
- * URL's link metadata.
2227
+ * identity plus the per-message `url`, optional live-rendering hint, and the
2228
+ * `layout` already derived from the URL's link metadata.
2203
2229
  */
2204
- const toSpectrumMiniApp = (url, layout) => asCustomizedMiniApp({
2230
+ const toSpectrumMiniApp = (url, layout, live) => asCustomizedMiniApp({
2205
2231
  ...SPECTRUM_MINI_APP,
2206
2232
  url,
2207
- layout
2233
+ layout,
2234
+ ...live === void 0 ? {} : { live }
2208
2235
  });
2209
2236
  //#endregion
2210
2237
  //#region src/remote/client.ts
@@ -2249,6 +2276,25 @@ const cacheRemoteOutbound = (remote, space, record) => {
2249
2276
  };
2250
2277
  const handleEdit = async (client, space, content) => {
2251
2278
  if (isLocal(client)) throw UnsupportedError.action("edit", "iMessage (local mode)");
2279
+ const miniAppCardSession = content.target.miniAppCardSession;
2280
+ const updateMiniAppCardSession = (record) => {
2281
+ const nextSession = record?.miniAppCardSession;
2282
+ if (nextSession) content.target.miniAppCardSession = nextSession;
2283
+ };
2284
+ if (content.content.type === "app") {
2285
+ if (!miniAppCardSession) throw UnsupportedError.content("edit", "iMessage", "mini app card edits require a miniAppCardSession from the original send");
2286
+ const url = await content.content.url();
2287
+ const layout = await content.content.layout();
2288
+ const remote = clientForPhone(client, space.phone);
2289
+ updateMiniAppCardSession(cacheRemoteOutbound(remote, space, await updateCustomizedMiniApp(remote, space.id, miniAppCardSession, toSpectrumMiniApp(url, layout, content.content.live))));
2290
+ return;
2291
+ }
2292
+ if (isCustomizedMiniApp(content.content)) {
2293
+ if (!miniAppCardSession) throw UnsupportedError.content("edit", "iMessage", "customized mini app card edits require a miniAppCardSession from the original send");
2294
+ const remote = clientForPhone(client, space.phone);
2295
+ updateMiniAppCardSession(cacheRemoteOutbound(remote, space, await updateCustomizedMiniApp(remote, space.id, miniAppCardSession, content.content)));
2296
+ return;
2297
+ }
2252
2298
  if (content.content.type !== "text") throw UnsupportedError.content("edit", "iMessage", `only text content can be edited (got "${content.content.type}")`);
2253
2299
  await editMessage(clientForPhone(client, space.phone), space.id, content.target.id, content.content);
2254
2300
  };
@@ -2288,7 +2334,7 @@ const handleApp = async (client, space, content) => {
2288
2334
  if (isLocal(client)) return await send$2(client, space.id, await text(url).build());
2289
2335
  const layout = await content.layout();
2290
2336
  const remote = clientForPhone(client, space.phone);
2291
- return cacheRemoteOutbound(remote, space, await sendCustomizedMiniApp(remote, space.id, toSpectrumMiniApp(url, layout)));
2337
+ return cacheRemoteOutbound(remote, space, await sendCustomizedMiniApp(remote, space.id, toSpectrumMiniApp(url, layout, content.live)));
2292
2338
  };
2293
2339
  const handleRead = async (client, space) => {
2294
2340
  if (isLocal(client)) throw UnsupportedError.action("read", "iMessage (local mode)", "marking chats as read requires remote iMessage");
@@ -2530,6 +2576,12 @@ const imessage = definePlatform("iMessage", {
2530
2576
  local: "fetching group avatars requires remote iMessage"
2531
2577
  }), space.id);
2532
2578
  },
2579
+ getDisplayName: async ({ client }, space) => {
2580
+ return await getDisplayName(remoteGroupClient(client, space, "getDisplayName", {
2581
+ dm: "only group chats have display names (this space is a DM)",
2582
+ local: "reading chat display names requires remote iMessage"
2583
+ }), space.id);
2584
+ },
2533
2585
  getAttachment: async ({ client }, guid, phone) => {
2534
2586
  if (isLocal(client)) throw UnsupportedError.action("getAttachment", "iMessage (local mode)", "fetching attachments by GUID requires remote iMessage");
2535
2587
  if (client.length === 0) throw new Error("No iMessage clients configured");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectrum-ts/imessage",
3
- "version": "9.0.0",
3
+ "version": "9.3.0",
4
4
  "description": "iMessage provider for spectrum-ts — local and remote (advanced) modes.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,7 +31,7 @@
31
31
  "label": "iMessage"
32
32
  },
33
33
  "dependencies": {
34
- "@photon-ai/advanced-imessage": "^0.12.0",
34
+ "@photon-ai/advanced-imessage": "^1.0.0",
35
35
  "@photon-ai/imessage-kit": "^3.0.0",
36
36
  "@photon-ai/otel": "^3.1.0",
37
37
  "lru-cache": "^11.0.0",