spectrum-ts 0.6.0 → 0.6.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/providers/imessage/index.js +58 -51
- package/package.json +2 -2
|
@@ -107,21 +107,14 @@ async function disposeCloudAuth(clients) {
|
|
|
107
107
|
|
|
108
108
|
// src/providers/imessage/local.ts
|
|
109
109
|
import { createReadStream } from "fs";
|
|
110
|
-
import { mkdtemp, rm, writeFile } from "fs/promises";
|
|
110
|
+
import { mkdtemp, readFile, rm, writeFile } from "fs/promises";
|
|
111
111
|
import { tmpdir } from "os";
|
|
112
112
|
import { basename, join } from "path";
|
|
113
113
|
import { Readable } from "stream";
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (!result.message?.id) {
|
|
119
|
-
throw new Error(
|
|
120
|
-
"iMessage local send did not return a message id \u2014 track upstream in @photon-ai/imessage-kit"
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
return { id: result.message.id, timestamp: result.sentAt };
|
|
124
|
-
};
|
|
114
|
+
var synthSendResult = () => ({
|
|
115
|
+
id: crypto.randomUUID(),
|
|
116
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
117
|
+
});
|
|
125
118
|
var DEFAULT_ATTACHMENT_NAME = "attachment";
|
|
126
119
|
var VCARD_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
127
120
|
"text/vcard",
|
|
@@ -137,17 +130,21 @@ var isVCardAttachment = (mimeType, fileName) => {
|
|
|
137
130
|
}
|
|
138
131
|
return Boolean(fileName?.toLowerCase().endsWith(".vcf"));
|
|
139
132
|
};
|
|
140
|
-
var
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
133
|
+
var readLocalAttachment = async (att) => {
|
|
134
|
+
if (!att.localPath) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`iMessage attachment ${att.id} has no local file available on disk`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
return readFile(att.localPath);
|
|
140
|
+
};
|
|
144
141
|
var toAttachmentContent = (att) => {
|
|
145
142
|
const { localPath } = att;
|
|
146
143
|
return asAttachment({
|
|
147
144
|
name: att.fileName ?? DEFAULT_ATTACHMENT_NAME,
|
|
148
145
|
mimeType: att.mimeType,
|
|
149
146
|
size: att.sizeBytes,
|
|
150
|
-
read: () =>
|
|
147
|
+
read: () => readLocalAttachment(att),
|
|
151
148
|
stream: localPath ? async () => Readable.toWeb(
|
|
152
149
|
createReadStream(localPath)
|
|
153
150
|
) : void 0
|
|
@@ -155,16 +152,23 @@ var toAttachmentContent = (att) => {
|
|
|
155
152
|
};
|
|
156
153
|
var toVCardContent = async (att) => {
|
|
157
154
|
try {
|
|
158
|
-
const buf = await
|
|
155
|
+
const buf = await readLocalAttachment(att);
|
|
159
156
|
return asContact(fromVCard(buf.toString("utf8")));
|
|
160
157
|
} catch {
|
|
161
158
|
return toAttachmentContent(att);
|
|
162
159
|
}
|
|
163
160
|
};
|
|
164
161
|
var toMessages = async (message) => {
|
|
162
|
+
const { chatId, chatKind } = message;
|
|
163
|
+
if (!chatId || chatKind === "unknown") {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
if (message.reaction !== null || message.kind !== "text" || message.retractedAt !== null) {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
165
169
|
const base = {
|
|
166
170
|
sender: { id: message.participant ?? "" },
|
|
167
|
-
space:
|
|
171
|
+
space: { id: chatId, type: chatKind === "group" ? "group" : "dm" },
|
|
168
172
|
timestamp: message.createdAt
|
|
169
173
|
};
|
|
170
174
|
if (message.attachments.length > 0) {
|
|
@@ -186,19 +190,23 @@ var toMessages = async (message) => {
|
|
|
186
190
|
};
|
|
187
191
|
var messages = (client) => stream((emit, end) => {
|
|
188
192
|
let lastPromise = Promise.resolve();
|
|
189
|
-
client.startWatching({
|
|
190
|
-
|
|
191
|
-
if (message.isFromMe) {
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
193
|
+
const startPromise = client.startWatching({
|
|
194
|
+
onIncomingMessage: (message) => {
|
|
194
195
|
lastPromise = lastPromise.then(() => toMessages(message)).then((ms) => {
|
|
195
196
|
for (const m of ms) {
|
|
196
197
|
emit(m);
|
|
197
198
|
}
|
|
198
|
-
}).catch(
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
}).catch(end);
|
|
200
|
+
},
|
|
201
|
+
onError: end
|
|
202
|
+
}).catch(end);
|
|
203
|
+
return async () => {
|
|
204
|
+
await startPromise.catch(() => {
|
|
205
|
+
});
|
|
206
|
+
await client.stopWatching();
|
|
207
|
+
await lastPromise.catch(() => {
|
|
208
|
+
});
|
|
209
|
+
};
|
|
202
210
|
});
|
|
203
211
|
var vcardFileName = (content) => {
|
|
204
212
|
const base = content.name?.formatted ?? content.user?.id ?? "contact";
|
|
@@ -210,7 +218,7 @@ var sendTempFile = async (client, spaceId, name, data) => {
|
|
|
210
218
|
const tmp = join(dir, safeName);
|
|
211
219
|
await writeFile(tmp, data);
|
|
212
220
|
try {
|
|
213
|
-
|
|
221
|
+
await client.send({ to: spaceId, attachments: [tmp] });
|
|
214
222
|
} finally {
|
|
215
223
|
await rm(dir, { recursive: true, force: true }).catch(() => {
|
|
216
224
|
});
|
|
@@ -219,21 +227,20 @@ var sendTempFile = async (client, spaceId, name, data) => {
|
|
|
219
227
|
var send = async (client, spaceId, content) => {
|
|
220
228
|
switch (content.type) {
|
|
221
229
|
case "text":
|
|
222
|
-
|
|
230
|
+
await client.send({ to: spaceId, text: content.text });
|
|
231
|
+
return synthSendResult();
|
|
223
232
|
case "attachment":
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
);
|
|
233
|
+
await sendTempFile(client, spaceId, content.name, await content.read());
|
|
234
|
+
return synthSendResult();
|
|
227
235
|
case "contact": {
|
|
228
236
|
const vcf = await toVCard(content);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
Buffer.from(vcf, "utf8")
|
|
235
|
-
)
|
|
237
|
+
await sendTempFile(
|
|
238
|
+
client,
|
|
239
|
+
spaceId,
|
|
240
|
+
vcardFileName(content),
|
|
241
|
+
Buffer.from(vcf, "utf8")
|
|
236
242
|
);
|
|
243
|
+
return synthSendResult();
|
|
237
244
|
}
|
|
238
245
|
default:
|
|
239
246
|
throw new Error(
|
|
@@ -251,7 +258,7 @@ import {
|
|
|
251
258
|
|
|
252
259
|
// src/utils/audio.ts
|
|
253
260
|
import { spawn } from "child_process";
|
|
254
|
-
import { mkdtemp as mkdtemp2, readFile, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
261
|
+
import { mkdtemp as mkdtemp2, readFile as readFile2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
255
262
|
import { tmpdir as tmpdir2 } from "os";
|
|
256
263
|
import { join as join2 } from "path";
|
|
257
264
|
var M4A_BRANDS = /* @__PURE__ */ new Set([
|
|
@@ -358,7 +365,7 @@ var transcodeToM4a = async (buffer) => {
|
|
|
358
365
|
if (code !== 0) {
|
|
359
366
|
throw new Error(`ffmpeg conversion failed (exit ${code}): ${stderr}`);
|
|
360
367
|
}
|
|
361
|
-
const out = await
|
|
368
|
+
const out = await readFile2(outPath);
|
|
362
369
|
return { buffer: out, duration: parseDuration(stderr) };
|
|
363
370
|
} finally {
|
|
364
371
|
await rm2(dir, { recursive: true, force: true }).catch(() => {
|
|
@@ -373,7 +380,7 @@ var ensureM4a = async (buffer, mimeType) => {
|
|
|
373
380
|
};
|
|
374
381
|
|
|
375
382
|
// src/providers/imessage/remote.ts
|
|
376
|
-
var
|
|
383
|
+
var toSendResult = (receipt) => ({
|
|
377
384
|
id: receipt.guid,
|
|
378
385
|
timestamp: /* @__PURE__ */ new Date()
|
|
379
386
|
});
|
|
@@ -495,14 +502,14 @@ var send2 = async (clients, spaceId, content) => {
|
|
|
495
502
|
const chat = chatGuid(spaceId);
|
|
496
503
|
switch (content.type) {
|
|
497
504
|
case "text":
|
|
498
|
-
return
|
|
505
|
+
return toSendResult(await remote.messages.send(chat, content.text));
|
|
499
506
|
case "attachment": {
|
|
500
507
|
const attachment = await remote.attachments.upload({
|
|
501
508
|
data: await content.read(),
|
|
502
509
|
fileName: content.name,
|
|
503
510
|
mimeType: content.mimeType
|
|
504
511
|
});
|
|
505
|
-
return
|
|
512
|
+
return toSendResult(
|
|
506
513
|
await remote.messages.send(chat, "", {
|
|
507
514
|
attachment: attachment.guid
|
|
508
515
|
})
|
|
@@ -510,7 +517,7 @@ var send2 = async (clients, spaceId, content) => {
|
|
|
510
517
|
}
|
|
511
518
|
case "contact": {
|
|
512
519
|
const attachment = await sendContactAttachment(remote, content);
|
|
513
|
-
return
|
|
520
|
+
return toSendResult(await remote.messages.send(chat, "", { attachment }));
|
|
514
521
|
}
|
|
515
522
|
case "voice": {
|
|
516
523
|
const { buffer } = await ensureM4a(
|
|
@@ -522,7 +529,7 @@ var send2 = async (clients, spaceId, content) => {
|
|
|
522
529
|
fileName: content.name ?? "voice.m4a",
|
|
523
530
|
mimeType: "audio/x-m4a"
|
|
524
531
|
});
|
|
525
|
-
return
|
|
532
|
+
return toSendResult(
|
|
526
533
|
await remote.messages.send(chat, "", {
|
|
527
534
|
attachment: attachment.guid,
|
|
528
535
|
audioMessage: true
|
|
@@ -542,7 +549,7 @@ var replyToMessage = async (clients, spaceId, msgId, content) => {
|
|
|
542
549
|
const replyTo = messageGuid(msgId);
|
|
543
550
|
switch (content.type) {
|
|
544
551
|
case "text":
|
|
545
|
-
return
|
|
552
|
+
return toSendResult(
|
|
546
553
|
await remote.messages.send(chat, content.text, { replyTo })
|
|
547
554
|
);
|
|
548
555
|
case "attachment": {
|
|
@@ -551,7 +558,7 @@ var replyToMessage = async (clients, spaceId, msgId, content) => {
|
|
|
551
558
|
fileName: content.name,
|
|
552
559
|
mimeType: content.mimeType
|
|
553
560
|
});
|
|
554
|
-
return
|
|
561
|
+
return toSendResult(
|
|
555
562
|
await remote.messages.send(chat, "", {
|
|
556
563
|
attachment: attachment.guid,
|
|
557
564
|
replyTo
|
|
@@ -560,7 +567,7 @@ var replyToMessage = async (clients, spaceId, msgId, content) => {
|
|
|
560
567
|
}
|
|
561
568
|
case "contact": {
|
|
562
569
|
const attachment = await sendContactAttachment(remote, content);
|
|
563
|
-
return
|
|
570
|
+
return toSendResult(
|
|
564
571
|
await remote.messages.send(chat, "", { attachment, replyTo })
|
|
565
572
|
);
|
|
566
573
|
}
|
|
@@ -574,7 +581,7 @@ var replyToMessage = async (clients, spaceId, msgId, content) => {
|
|
|
574
581
|
fileName: content.name ?? "voice.m4a",
|
|
575
582
|
mimeType: "audio/x-m4a"
|
|
576
583
|
});
|
|
577
|
-
return
|
|
584
|
+
return toSendResult(
|
|
578
585
|
await remote.messages.send(chat, "", {
|
|
579
586
|
attachment: attachment.guid,
|
|
580
587
|
audioMessage: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spectrum-ts",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@photon-ai/advanced-imessage": "^0.4.3",
|
|
23
|
-
"@photon-ai/imessage-kit": "^3.0.0
|
|
23
|
+
"@photon-ai/imessage-kit": "^3.0.0",
|
|
24
24
|
"@photon-ai/whatsapp-business": "^0.1.1",
|
|
25
25
|
"@repeaterjs/repeater": "^3.0.6",
|
|
26
26
|
"better-grpc": "^0.3.2",
|