@photon-ai/advanced-imessage-kit 1.14.3 → 1.16.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 +128 -3
- package/dist/index.cjs +71 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -3
- package/dist/index.d.ts +56 -3
- package/dist/index.js +71 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,23 @@
|
|
|
14
14
|
|
|
15
15
|
Advanced iMessage Kit is a full-featured iMessage SDK for **reading**, **sending**, and **automating** iMessage conversations on macOS. Perfect for building **AI agents**, **automation tools**, and **chat applications**.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## Enterprise
|
|
18
|
+
|
|
19
|
+
**Advanced iMessage Kit** is the **enterprise edition** provided by **[Photon](https://photon.codes)**.
|
|
20
|
+
|
|
21
|
+
- **Provisioned iMessage Numbers** – Dedicated numbers ready for production use
|
|
22
|
+
- **Managed Hosting** – Fully managed infrastructure for reliability and scale
|
|
23
|
+
- **DevOps & Deployment Support** – Production setup, monitoring, and scaling
|
|
24
|
+
- **Enterprise Support** – Direct support and custom integrations
|
|
25
|
+
|
|
26
|
+
📩 **Enterprise inquiries:**
|
|
27
|
+
Contact **daniel@photon.codes**
|
|
28
|
+
|
|
29
|
+
🌐 **Book a Demo:**
|
|
30
|
+
https://photon.codes
|
|
31
|
+
|
|
32
|
+
If you're looking for the **free/open-source version**, please use **[iMessage Kit](https://github.com/photon-hq/imessage-kit)** instead.
|
|
33
|
+
|
|
18
34
|
|
|
19
35
|
## Features
|
|
20
36
|
|
|
@@ -23,6 +39,8 @@ Advanced iMessage Kit is a full-featured iMessage SDK for **reading**, **sending
|
|
|
23
39
|
| [Send Messages](#send-messages) | Send text messages to any contact | `messages.sendMessage()` | [message-send.ts](./examples/message-send.ts) |
|
|
24
40
|
| [Reply to Messages](#send-messages) | Reply inline to a specific message | `messages.sendMessage()` | [message-reply.ts](./examples/message-reply.ts) |
|
|
25
41
|
| [Message Effects](#send-messages) | Send with effects (confetti, fireworks, etc.) | `messages.sendMessage()` | [message-effects.ts](./examples/message-effects.ts) |
|
|
42
|
+
| [Text Styles](#text-styles--animations) | Bold, italic, underline, strikethrough | `messages.sendMessage()` | [message-styled.ts](./examples/message-styled.ts) |
|
|
43
|
+
| [Text Animations](#text-styles--animations) | Per-character animations (shake, ripple, etc.)| `messages.sendMessage()` | [message-styled.ts](./examples/message-styled.ts) |
|
|
26
44
|
| [Send Rich Links](#send-messages) | Send URLs with rich link previews | `messages.sendMessage()` | [message-rich-link.ts](./examples/message-rich-link.ts) |
|
|
27
45
|
| [Schedule Messages](#scheduled-messages) | Send once or on a recurring schedule | `scheduledMessages.createScheduledMessage()` | [scheduled-message-once.ts](./examples/scheduled-message-once.ts) |
|
|
28
46
|
| [Unsend Messages](#unsend-messages) | Retract a sent message | `messages.unsendMessage()` | [message-unsend.ts](./examples/message-unsend.ts) |
|
|
@@ -101,6 +119,15 @@ interface ClientConfig {
|
|
|
101
119
|
}
|
|
102
120
|
```
|
|
103
121
|
|
|
122
|
+
### Remote Server Setup
|
|
123
|
+
|
|
124
|
+
If your SDK code runs on a different machine than the iMessage server:
|
|
125
|
+
|
|
126
|
+
- `serverUrl` points to the server machine
|
|
127
|
+
- `filePath` points to the SDK machine
|
|
128
|
+
|
|
129
|
+
The SDK reads local files first, then uploads the file bytes to the server.
|
|
130
|
+
|
|
104
131
|
---
|
|
105
132
|
|
|
106
133
|
## Core Concepts
|
|
@@ -191,6 +218,71 @@ await sdk.messages.sendMessage({
|
|
|
191
218
|
|
|
192
219
|
> Example: [message-effects.ts](./examples/message-effects.ts)
|
|
193
220
|
|
|
221
|
+
### Text Styles & Animations
|
|
222
|
+
|
|
223
|
+
Apply per-range text formatting and whole-message character animations (requires Private API):
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// Bold a portion of text
|
|
227
|
+
await sdk.messages.sendMessage({
|
|
228
|
+
chatGuid: "iMessage;-;+1234567890",
|
|
229
|
+
message: "This is bold text",
|
|
230
|
+
textStyles: [{ start: 8, end: 12, bold: true }],
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Multiple styles in one message
|
|
234
|
+
await sdk.messages.sendMessage({
|
|
235
|
+
chatGuid: "iMessage;-;+1234567890",
|
|
236
|
+
message: "Bold here, italic there",
|
|
237
|
+
textStyles: [
|
|
238
|
+
{ start: 0, end: 9, bold: true },
|
|
239
|
+
{ start: 11, end: 23, italic: true },
|
|
240
|
+
],
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Character animation (applies to whole message)
|
|
244
|
+
await sdk.messages.sendMessage({
|
|
245
|
+
chatGuid: "iMessage;-;+1234567890",
|
|
246
|
+
message: "Ripple wave!",
|
|
247
|
+
textAnimation: "ripple",
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Combine all three layers
|
|
251
|
+
await sdk.messages.sendMessage({
|
|
252
|
+
chatGuid: "iMessage;-;+1234567890",
|
|
253
|
+
message: "Bold shaking fireworks!",
|
|
254
|
+
textStyles: [{ start: 0, end: 4, bold: true }],
|
|
255
|
+
textAnimation: "shake",
|
|
256
|
+
effectId: "com.apple.messages.effect.CKFireworksEffect",
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Text Style Properties** (per range):
|
|
261
|
+
|
|
262
|
+
| Property | Type | Description |
|
|
263
|
+
| --------------- | ------- | -------------- |
|
|
264
|
+
| `start` | number | Start index |
|
|
265
|
+
| `end` | number | End index |
|
|
266
|
+
| `bold` | boolean | Bold |
|
|
267
|
+
| `italic` | boolean | Italic |
|
|
268
|
+
| `underline` | boolean | Underline |
|
|
269
|
+
| `strikethrough` | boolean | Strikethrough |
|
|
270
|
+
|
|
271
|
+
**Text Animations** (whole message):
|
|
272
|
+
|
|
273
|
+
| `textAnimation` | Description |
|
|
274
|
+
| --------------- | ----------- |
|
|
275
|
+
| `"big"` | Big |
|
|
276
|
+
| `"small"` | Small |
|
|
277
|
+
| `"shake"` | Shake |
|
|
278
|
+
| `"nod"` | Nod |
|
|
279
|
+
| `"explode"` | Explode |
|
|
280
|
+
| `"ripple"` | Ripple |
|
|
281
|
+
| `"bloom"` | Bloom |
|
|
282
|
+
| `"jitter"` | Jitter |
|
|
283
|
+
|
|
284
|
+
> Example: [message-styled.ts](./examples/message-styled.ts)
|
|
285
|
+
|
|
194
286
|
### Query Messages
|
|
195
287
|
|
|
196
288
|
```typescript
|
|
@@ -529,6 +621,38 @@ const message = await sdk.attachments.sendAttachment({
|
|
|
529
621
|
});
|
|
530
622
|
```
|
|
531
623
|
|
|
624
|
+
### Send Multiple Images In One Request
|
|
625
|
+
|
|
626
|
+
Use `sendMultipartMessage()` when you want to send multiple images together as one multipart iMessage request:
|
|
627
|
+
|
|
628
|
+
```typescript
|
|
629
|
+
const message = await sdk.messages.sendMultipartMessage({
|
|
630
|
+
chatGuid: "iMessage;+;chat123456789",
|
|
631
|
+
parts: [
|
|
632
|
+
{
|
|
633
|
+
partIndex: 0,
|
|
634
|
+
filePath: "/path/to/image-1.jpg",
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
partIndex: 1,
|
|
638
|
+
filePath: "/path/to/image-2.jpg",
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
partIndex: 2,
|
|
642
|
+
filePath: "/path/to/image-3.jpg",
|
|
643
|
+
},
|
|
644
|
+
],
|
|
645
|
+
});
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
Notes:
|
|
649
|
+
- `sendMultipartMessage()` uploads each file first, then sends all parts together in a single `/api/v1/message/multipart` request.
|
|
650
|
+
- This requires the Private API path on the server.
|
|
651
|
+
- The target `chatGuid` must already exist. If you only have a phone number/email, create or fetch the chat first.
|
|
652
|
+
- If the SDK and server are on different machines, each `filePath` must exist on the SDK machine. The SDK uploads the file bytes to the server before sending.
|
|
653
|
+
|
|
654
|
+
> Example: [message-multipart-images.ts](./examples/message-multipart-images.ts)
|
|
655
|
+
|
|
532
656
|
### Send Audio Messages
|
|
533
657
|
|
|
534
658
|
```typescript
|
|
@@ -1114,8 +1238,9 @@ bun run examples/<filename>.ts
|
|
|
1114
1238
|
| [message-unsend.ts](./examples/message-unsend.ts) | Unsend messages |
|
|
1115
1239
|
| [message-edit.ts](./examples/message-edit.ts) | Edit messages |
|
|
1116
1240
|
| [message-reaction.ts](./examples/message-reaction.ts) | Send Tapbacks |
|
|
1117
|
-
| [message-effects.ts](./examples/message-effects.ts) | Message effects
|
|
1118
|
-
| [message-
|
|
1241
|
+
| [message-effects.ts](./examples/message-effects.ts) | Message effects |
|
|
1242
|
+
| [message-styled.ts](./examples/message-styled.ts) | Text styles & animations |
|
|
1243
|
+
| [message-search.ts](./examples/message-search.ts) | Search messages |
|
|
1119
1244
|
| [message-history.ts](./examples/message-history.ts) | Message history |
|
|
1120
1245
|
| [message-destination-caller-id.ts](./examples/message-destination-caller-id.ts) | Destination caller ID |
|
|
1121
1246
|
|
package/dist/index.cjs
CHANGED
|
@@ -164,14 +164,16 @@ function extractService(chatGuid) {
|
|
|
164
164
|
return void 0;
|
|
165
165
|
}
|
|
166
166
|
async function createChatWithMessage(options) {
|
|
167
|
-
const { http, address, message, tempGuid, subject,
|
|
167
|
+
const { http, address, message, tempGuid, subject, bubbleEffect, textStyles, textAnimation, service } = options;
|
|
168
168
|
try {
|
|
169
169
|
const response = await http.post("/api/v1/chat/new", {
|
|
170
170
|
addresses: [address],
|
|
171
171
|
message,
|
|
172
172
|
tempGuid,
|
|
173
173
|
subject,
|
|
174
|
-
|
|
174
|
+
bubbleEffect,
|
|
175
|
+
textStyles,
|
|
176
|
+
textAnimation,
|
|
175
177
|
...service && { service }
|
|
176
178
|
});
|
|
177
179
|
return response.data.data?.guid;
|
|
@@ -529,6 +531,15 @@ var MessageModule = class {
|
|
|
529
531
|
this.http = http;
|
|
530
532
|
this.enqueueSend = enqueueSend;
|
|
531
533
|
}
|
|
534
|
+
async uploadMultipartAttachment(part, fileName = part.fileName || path__namespace.default.basename(part.filePath)) {
|
|
535
|
+
const fileBuffer = await promises.readFile(part.filePath);
|
|
536
|
+
const form = new FormData__default.default();
|
|
537
|
+
form.append("attachment", fileBuffer, fileName);
|
|
538
|
+
const response = await this.http.post("/api/v1/attachment/upload", form, {
|
|
539
|
+
headers: form.getHeaders()
|
|
540
|
+
});
|
|
541
|
+
return response.data.data.path;
|
|
542
|
+
}
|
|
532
543
|
async sendMessage(options) {
|
|
533
544
|
return this.enqueueSend(async () => {
|
|
534
545
|
const tempGuid = options.tempGuid || crypto.randomUUID();
|
|
@@ -547,13 +558,70 @@ var MessageModule = class {
|
|
|
547
558
|
message: options.message,
|
|
548
559
|
tempGuid,
|
|
549
560
|
subject: options.subject,
|
|
550
|
-
|
|
561
|
+
bubbleEffect: options.bubbleEffect,
|
|
562
|
+
textStyles: options.textStyles,
|
|
563
|
+
textAnimation: options.textAnimation,
|
|
551
564
|
service
|
|
552
565
|
});
|
|
553
566
|
return { guid: tempGuid, text: options.message, dateCreated: Date.now() };
|
|
554
567
|
}
|
|
555
568
|
});
|
|
556
569
|
}
|
|
570
|
+
async sendMultipartMessage(options) {
|
|
571
|
+
return this.enqueueSend(async () => {
|
|
572
|
+
const tempGuid = options.tempGuid || crypto.randomUUID();
|
|
573
|
+
const buildPayloadPart = async (part, index) => {
|
|
574
|
+
const resolvedPartIndex = part.partIndex ?? index;
|
|
575
|
+
if ("text" in part) {
|
|
576
|
+
return {
|
|
577
|
+
partIndex: resolvedPartIndex,
|
|
578
|
+
text: part.text,
|
|
579
|
+
...part.mention ? { mention: part.mention } : {}
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
const fileName = part.fileName || path__namespace.default.basename(part.filePath);
|
|
583
|
+
const uploadedPath = await this.uploadMultipartAttachment(part, fileName);
|
|
584
|
+
return {
|
|
585
|
+
partIndex: resolvedPartIndex,
|
|
586
|
+
attachment: uploadedPath,
|
|
587
|
+
name: fileName
|
|
588
|
+
};
|
|
589
|
+
};
|
|
590
|
+
const uploadParts = async () => {
|
|
591
|
+
const parts = [];
|
|
592
|
+
for (const [index, part] of options.parts.entries()) {
|
|
593
|
+
parts.push(await buildPayloadPart(part, index));
|
|
594
|
+
}
|
|
595
|
+
return parts;
|
|
596
|
+
};
|
|
597
|
+
const send = async (chatGuid) => {
|
|
598
|
+
const parts = await uploadParts();
|
|
599
|
+
const payload = {
|
|
600
|
+
chatGuid,
|
|
601
|
+
tempGuid,
|
|
602
|
+
parts,
|
|
603
|
+
subject: options.subject,
|
|
604
|
+
effectId: options.effectId,
|
|
605
|
+
selectedMessageGuid: options.selectedMessageGuid,
|
|
606
|
+
partIndex: options.partIndex ?? 0,
|
|
607
|
+
ddScan: options.ddScan ?? false,
|
|
608
|
+
attributedBody: options.attributedBody
|
|
609
|
+
};
|
|
610
|
+
const response = await this.http.post("/api/v1/message/multipart", payload);
|
|
611
|
+
return response.data.data;
|
|
612
|
+
};
|
|
613
|
+
try {
|
|
614
|
+
return await send(options.chatGuid);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
if (isChatNotExistError(error)) {
|
|
617
|
+
throw new Error(
|
|
618
|
+
"Chat does not exist for multipart send. Use an existing chatGuid, or create the chat first before calling sendMultipartMessage()."
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
throw error;
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
}
|
|
557
625
|
async getMessage(guid, options) {
|
|
558
626
|
const response = await this.http.get(`/api/v1/message/${encodeURIComponent(guid)}`, {
|
|
559
627
|
params: options?.with ? { with: options.with.join(",") } : {}
|