spectrum-ts 1.18.0 → 2.0.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 +11 -1
- package/dist/{attachment-DfWSZS5L.d.ts → attachment-B4nSrKVd.d.ts} +1 -1
- package/dist/{authoring-C9uDdZ2F.d.ts → authoring-BjE5BvlO.d.ts} +2 -2
- package/dist/authoring.d.ts +3 -3
- package/dist/authoring.js +6 -3
- package/dist/chunk-34FQGGD7.js +34 -0
- package/dist/chunk-3B4QH4JG.js +35 -0
- package/dist/chunk-3GEJYGZK.js +84 -0
- package/dist/chunk-5LT5J3NR.js +695 -0
- package/dist/{chunk-MC6ZKFSG.js → chunk-5XEFJBN2.js} +25 -103
- package/dist/{chunk-JQN6CRSC.js → chunk-6BI4PFTP.js} +10 -39
- package/dist/{chunk-QGJFZMD5.js → chunk-6UZFVXQF.js} +17 -101
- package/dist/{chunk-YN6WOTBF.js → chunk-ATNAE7OR.js} +77 -7
- package/dist/{chunk-IPOFBAIM.js → chunk-NGC4DJIX.js} +23 -19
- package/dist/{chunk-5TIF3FIE.js → chunk-Q537JPTG.js} +8 -6
- package/dist/{chunk-5BKZJMZV.js → chunk-U3LXXT3W.js} +61 -32
- package/dist/chunk-U7AWXDH6.js +91 -0
- package/dist/{chunk-3OTECDNH.js → chunk-WXY5QP3M.js} +5 -3
- package/dist/index.d.ts +69 -124
- package/dist/index.js +350 -90
- package/dist/manifest.json +6 -0
- package/dist/providers/imessage/index.d.ts +2 -2
- package/dist/providers/imessage/index.js +8 -5
- package/dist/providers/index.d.ts +5 -2
- package/dist/providers/index.js +16 -8
- package/dist/providers/slack/index.d.ts +1 -1
- package/dist/providers/slack/index.js +4 -3
- package/dist/providers/telegram/index.d.ts +47 -0
- package/dist/providers/telegram/index.js +13 -0
- package/dist/providers/terminal/index.d.ts +17 -419
- package/dist/providers/terminal/index.js +5 -3
- package/dist/providers/whatsapp-business/index.d.ts +1 -1
- package/dist/providers/whatsapp-business/index.js +6 -4
- package/dist/types-BD0-kKyv.d.ts +82 -0
- package/dist/{types-DcQ5a7PK.d.ts → types-Bje8aq1k.d.ts} +34 -4
- package/package.json +2 -1
|
@@ -1,83 +1,5 @@
|
|
|
1
1
|
import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
|
|
2
2
|
|
|
3
|
-
// src/utils/cloud.ts
|
|
4
|
-
var SPECTRUM_CLOUD_URL = process.env.SPECTRUM_CLOUD_URL ?? "https://spectrum.photon.codes";
|
|
5
|
-
var SpectrumCloudError = class extends Error {
|
|
6
|
-
status;
|
|
7
|
-
code;
|
|
8
|
-
constructor(status, code, message) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.name = "SpectrumCloudError";
|
|
11
|
-
this.status = status;
|
|
12
|
-
this.code = code;
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
var request = async (path, init) => {
|
|
16
|
-
const response = await fetch(`${SPECTRUM_CLOUD_URL}${path}`, init);
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
const body = await response.text().catch(() => "");
|
|
19
|
-
try {
|
|
20
|
-
const parsed = JSON.parse(body);
|
|
21
|
-
throw new SpectrumCloudError(
|
|
22
|
-
response.status,
|
|
23
|
-
parsed.code,
|
|
24
|
-
parsed.message
|
|
25
|
-
);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
if (error instanceof SpectrumCloudError) {
|
|
28
|
-
throw error;
|
|
29
|
-
}
|
|
30
|
-
throw new SpectrumCloudError(
|
|
31
|
-
response.status,
|
|
32
|
-
"UNKNOWN",
|
|
33
|
-
body || response.statusText
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
const json = await response.json();
|
|
38
|
-
if (!json.succeed) {
|
|
39
|
-
throw new SpectrumCloudError(
|
|
40
|
-
response.status,
|
|
41
|
-
"UNKNOWN",
|
|
42
|
-
"Server returned succeed=false"
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
return json.data;
|
|
46
|
-
};
|
|
47
|
-
var basicAuth = (projectId, projectSecret) => `Basic ${btoa(`${projectId}:${projectSecret}`)}`;
|
|
48
|
-
var cloud = {
|
|
49
|
-
getProject: (projectId, projectSecret) => request(`/projects/${projectId}/`, {
|
|
50
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
51
|
-
}),
|
|
52
|
-
getSubscription: (projectId) => request(`/projects/${projectId}/billing/subscription`),
|
|
53
|
-
issueImessageTokens: (projectId, projectSecret) => request(`/projects/${projectId}/imessage/tokens`, {
|
|
54
|
-
method: "POST",
|
|
55
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
56
|
-
}),
|
|
57
|
-
getImessageInfo: (projectId) => request(`/projects/${projectId}/imessage/`),
|
|
58
|
-
issueWhatsappBusinessTokens: (projectId, projectSecret) => request(`/projects/${projectId}/whatsapp-business/tokens`, {
|
|
59
|
-
method: "POST",
|
|
60
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
61
|
-
}),
|
|
62
|
-
issueSlackTokens: (projectId, projectSecret) => request(`/projects/${projectId}/slack/tokens`, {
|
|
63
|
-
method: "POST",
|
|
64
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
65
|
-
}),
|
|
66
|
-
issueFusorToken: (projectId, projectSecret) => request(`/projects/${projectId}/fusor/token`, {
|
|
67
|
-
method: "POST",
|
|
68
|
-
headers: { Authorization: basicAuth(projectId, projectSecret) }
|
|
69
|
-
}),
|
|
70
|
-
getPlatforms: (projectId) => request(`/projects/${projectId}/platforms/`),
|
|
71
|
-
togglePlatform: (projectId, projectSecret, platform, enabled) => request(`/projects/${projectId}/platforms/`, {
|
|
72
|
-
method: "PATCH",
|
|
73
|
-
headers: {
|
|
74
|
-
Authorization: basicAuth(projectId, projectSecret),
|
|
75
|
-
"Content-Type": "application/json"
|
|
76
|
-
},
|
|
77
|
-
body: JSON.stringify({ platform, enabled })
|
|
78
|
-
})
|
|
79
|
-
};
|
|
80
|
-
|
|
81
3
|
// src/utils/stream.ts
|
|
82
4
|
import { Repeater } from "@repeaterjs/repeater";
|
|
83
5
|
function createAsyncQueue() {
|
|
@@ -190,6 +112,16 @@ function broadcast(source) {
|
|
|
190
112
|
let terminalError;
|
|
191
113
|
let pumpPromise;
|
|
192
114
|
let closed = false;
|
|
115
|
+
const closeConsumers = (error) => {
|
|
116
|
+
if (consumers.size === 0) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const current = Array.from(consumers);
|
|
120
|
+
consumers.clear();
|
|
121
|
+
for (const consumer of current) {
|
|
122
|
+
consumer.end(error);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
193
125
|
const startPump = () => {
|
|
194
126
|
if (pumping || terminated) {
|
|
195
127
|
return;
|
|
@@ -198,35 +130,35 @@ function broadcast(source) {
|
|
|
198
130
|
pumpPromise = (async () => {
|
|
199
131
|
try {
|
|
200
132
|
for await (const value of source) {
|
|
201
|
-
|
|
133
|
+
if (terminated) {
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
for (const consumer of Array.from(consumers)) {
|
|
202
137
|
consumer.deliveries = consumer.deliveries.then(
|
|
203
138
|
() => consumer.emit(value).catch(() => {
|
|
204
139
|
})
|
|
205
140
|
);
|
|
206
141
|
}
|
|
207
142
|
}
|
|
143
|
+
if (terminated) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
208
146
|
terminated = true;
|
|
209
147
|
await Promise.allSettled(
|
|
210
148
|
Array.from(consumers, (consumer) => consumer.deliveries)
|
|
211
149
|
);
|
|
212
|
-
|
|
213
|
-
consumer.end();
|
|
214
|
-
}
|
|
215
|
-
consumers.clear();
|
|
150
|
+
closeConsumers();
|
|
216
151
|
} catch (error) {
|
|
217
152
|
terminated = true;
|
|
218
153
|
terminalError = error;
|
|
219
|
-
|
|
220
|
-
consumer.end(error);
|
|
221
|
-
}
|
|
222
|
-
consumers.clear();
|
|
154
|
+
closeConsumers(error);
|
|
223
155
|
}
|
|
224
156
|
})();
|
|
225
157
|
};
|
|
226
158
|
return {
|
|
227
159
|
subscribe() {
|
|
228
160
|
return stream((emit, end) => {
|
|
229
|
-
if (terminated) {
|
|
161
|
+
if (terminated || closed) {
|
|
230
162
|
end(terminalError);
|
|
231
163
|
return;
|
|
232
164
|
}
|
|
@@ -247,27 +179,17 @@ function broadcast(source) {
|
|
|
247
179
|
return;
|
|
248
180
|
}
|
|
249
181
|
closed = true;
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
} finally {
|
|
256
|
-
if (!terminated) {
|
|
257
|
-
terminated = true;
|
|
258
|
-
for (const consumer of consumers) {
|
|
259
|
-
consumer.end();
|
|
260
|
-
}
|
|
261
|
-
consumers.clear();
|
|
262
|
-
}
|
|
182
|
+
terminated = true;
|
|
183
|
+
closeConsumers();
|
|
184
|
+
await source.close().catch(ignoreCleanupError);
|
|
185
|
+
if (pumpPromise) {
|
|
186
|
+
await pumpPromise.catch(ignoreCleanupError);
|
|
263
187
|
}
|
|
264
188
|
}
|
|
265
189
|
};
|
|
266
190
|
}
|
|
267
191
|
|
|
268
192
|
export {
|
|
269
|
-
SpectrumCloudError,
|
|
270
|
-
cloud,
|
|
271
193
|
createAsyncQueue,
|
|
272
194
|
stream,
|
|
273
195
|
mergeStreams,
|
|
@@ -3,37 +3,11 @@ import {
|
|
|
3
3
|
bufferToStream,
|
|
4
4
|
fetchUrlBytes,
|
|
5
5
|
readSchema,
|
|
6
|
-
resolveContents,
|
|
7
6
|
streamSchema
|
|
8
7
|
} from "./chunk-2ILTJC35.js";
|
|
9
8
|
|
|
10
|
-
// src/content/group.ts
|
|
11
|
-
import z from "zod";
|
|
12
|
-
var isMessage = (v) => typeof v === "object" && v !== null && "id" in v && "content" in v;
|
|
13
|
-
var groupSchema = z.object({
|
|
14
|
-
type: z.literal("group"),
|
|
15
|
-
items: z.array(z.custom(isMessage)).min(2)
|
|
16
|
-
});
|
|
17
|
-
var asGroup = (input) => groupSchema.parse({ type: "group", items: input.items });
|
|
18
|
-
var stubOutboundMessage = (content) => ({ id: "", content });
|
|
19
|
-
function group(...items) {
|
|
20
|
-
return {
|
|
21
|
-
build: async () => {
|
|
22
|
-
const resolved = await resolveContents(items);
|
|
23
|
-
const members = [];
|
|
24
|
-
for (const item of resolved) {
|
|
25
|
-
if (item.type === "group" || item.type === "reaction") {
|
|
26
|
-
throw new Error(`group() cannot contain "${item.type}" items`);
|
|
27
|
-
}
|
|
28
|
-
members.push(stubOutboundMessage(item));
|
|
29
|
-
}
|
|
30
|
-
return asGroup({ items: members });
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
9
|
// src/content/richlink.ts
|
|
36
|
-
import
|
|
10
|
+
import z from "zod";
|
|
37
11
|
|
|
38
12
|
// src/utils/link-metadata.ts
|
|
39
13
|
import ogs from "open-graph-scraper";
|
|
@@ -90,22 +64,22 @@ var fetchImage = (url) => fetchUrlBytes(new URL(url), {
|
|
|
90
64
|
});
|
|
91
65
|
|
|
92
66
|
// src/content/richlink.ts
|
|
93
|
-
var richlinkCoverSchema =
|
|
94
|
-
mimeType:
|
|
67
|
+
var richlinkCoverSchema = z.object({
|
|
68
|
+
mimeType: z.string().min(1).optional(),
|
|
95
69
|
read: readSchema,
|
|
96
70
|
stream: streamSchema
|
|
97
71
|
});
|
|
98
|
-
var optionalStringAccessor =
|
|
72
|
+
var optionalStringAccessor = z.function({
|
|
99
73
|
input: [],
|
|
100
|
-
output:
|
|
74
|
+
output: z.promise(z.string().min(1).optional())
|
|
101
75
|
});
|
|
102
|
-
var coverAccessor =
|
|
76
|
+
var coverAccessor = z.function({
|
|
103
77
|
input: [],
|
|
104
|
-
output:
|
|
78
|
+
output: z.promise(richlinkCoverSchema.optional())
|
|
105
79
|
});
|
|
106
|
-
var richlinkSchema =
|
|
107
|
-
type:
|
|
108
|
-
url:
|
|
80
|
+
var richlinkSchema = z.object({
|
|
81
|
+
type: z.literal("richlink"),
|
|
82
|
+
url: z.url(),
|
|
109
83
|
title: optionalStringAccessor,
|
|
110
84
|
summary: optionalStringAccessor,
|
|
111
85
|
cover: coverAccessor
|
|
@@ -150,9 +124,6 @@ function richlink(url) {
|
|
|
150
124
|
}
|
|
151
125
|
|
|
152
126
|
export {
|
|
153
|
-
groupSchema,
|
|
154
|
-
asGroup,
|
|
155
|
-
group,
|
|
156
127
|
asRichlink,
|
|
157
128
|
richlink
|
|
158
129
|
};
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
readSchema
|
|
4
|
-
} from "./chunk-2ILTJC35.js";
|
|
5
2
|
|
|
6
3
|
// src/utils/vcard.ts
|
|
7
4
|
import vCard from "vcf";
|
|
@@ -350,109 +347,28 @@ var writePhoto = async (card, photo) => {
|
|
|
350
347
|
type: photoTypeParam(photo.mimeType)
|
|
351
348
|
});
|
|
352
349
|
};
|
|
353
|
-
var toVCard = async (
|
|
354
|
-
if (typeof
|
|
355
|
-
return
|
|
350
|
+
var toVCard = async (contact) => {
|
|
351
|
+
if (typeof contact.raw === "string" && contact.raw.startsWith("BEGIN:VCARD")) {
|
|
352
|
+
return contact.raw;
|
|
356
353
|
}
|
|
357
354
|
const card = new vCard();
|
|
358
|
-
writeName(card,
|
|
359
|
-
writePhones(card,
|
|
360
|
-
writeEmails(card,
|
|
361
|
-
writeAddresses(card,
|
|
362
|
-
writeOrg(card,
|
|
363
|
-
writeUrls(card,
|
|
364
|
-
if (
|
|
365
|
-
card.set("bday",
|
|
366
|
-
}
|
|
367
|
-
if (
|
|
368
|
-
card.set("note",
|
|
369
|
-
}
|
|
370
|
-
await writePhoto(card,
|
|
355
|
+
writeName(card, contact.name);
|
|
356
|
+
writePhones(card, contact.phones);
|
|
357
|
+
writeEmails(card, contact.emails);
|
|
358
|
+
writeAddresses(card, contact.addresses);
|
|
359
|
+
writeOrg(card, contact.org);
|
|
360
|
+
writeUrls(card, contact.urls);
|
|
361
|
+
if (contact.birthday) {
|
|
362
|
+
card.set("bday", contact.birthday);
|
|
363
|
+
}
|
|
364
|
+
if (contact.note) {
|
|
365
|
+
card.set("note", contact.note);
|
|
366
|
+
}
|
|
367
|
+
await writePhoto(card, contact.photo);
|
|
371
368
|
return card.toString();
|
|
372
369
|
};
|
|
373
370
|
|
|
374
|
-
// src/content/contact.ts
|
|
375
|
-
import vCard2 from "vcf";
|
|
376
|
-
import z from "zod";
|
|
377
|
-
var userRefSchema = z.object({
|
|
378
|
-
__platform: z.string(),
|
|
379
|
-
id: z.string()
|
|
380
|
-
});
|
|
381
|
-
var nameSchema = z.object({
|
|
382
|
-
formatted: z.string().optional(),
|
|
383
|
-
first: z.string().optional(),
|
|
384
|
-
last: z.string().optional(),
|
|
385
|
-
middle: z.string().optional(),
|
|
386
|
-
prefix: z.string().optional(),
|
|
387
|
-
suffix: z.string().optional()
|
|
388
|
-
});
|
|
389
|
-
var phoneTypeSchema = z.enum(["mobile", "home", "work", "other"]);
|
|
390
|
-
var emailTypeSchema = z.enum(["home", "work", "other"]);
|
|
391
|
-
var addressTypeSchema = z.enum(["home", "work", "other"]);
|
|
392
|
-
var phoneSchema = z.object({
|
|
393
|
-
value: z.string(),
|
|
394
|
-
type: phoneTypeSchema.optional()
|
|
395
|
-
});
|
|
396
|
-
var emailSchema = z.object({
|
|
397
|
-
value: z.string(),
|
|
398
|
-
type: emailTypeSchema.optional()
|
|
399
|
-
});
|
|
400
|
-
var addressSchema = z.object({
|
|
401
|
-
street: z.string().optional(),
|
|
402
|
-
city: z.string().optional(),
|
|
403
|
-
region: z.string().optional(),
|
|
404
|
-
postalCode: z.string().optional(),
|
|
405
|
-
country: z.string().optional(),
|
|
406
|
-
type: addressTypeSchema.optional()
|
|
407
|
-
});
|
|
408
|
-
var orgSchema = z.object({
|
|
409
|
-
name: z.string().optional(),
|
|
410
|
-
title: z.string().optional(),
|
|
411
|
-
department: z.string().optional()
|
|
412
|
-
});
|
|
413
|
-
var photoSchema = z.object({
|
|
414
|
-
mimeType: z.string(),
|
|
415
|
-
read: readSchema
|
|
416
|
-
});
|
|
417
|
-
var contactSchema = z.object({
|
|
418
|
-
type: z.literal("contact"),
|
|
419
|
-
user: userRefSchema.optional(),
|
|
420
|
-
name: nameSchema.optional(),
|
|
421
|
-
phones: z.array(phoneSchema).optional(),
|
|
422
|
-
emails: z.array(emailSchema).optional(),
|
|
423
|
-
addresses: z.array(addressSchema).optional(),
|
|
424
|
-
org: orgSchema.optional(),
|
|
425
|
-
urls: z.array(z.string()).optional(),
|
|
426
|
-
birthday: z.string().optional(),
|
|
427
|
-
note: z.string().optional(),
|
|
428
|
-
photo: photoSchema.optional(),
|
|
429
|
-
raw: z.unknown().optional()
|
|
430
|
-
});
|
|
431
|
-
var asContact = (input) => contactSchema.parse({ type: "contact", ...input });
|
|
432
|
-
var isUser = (value) => typeof value === "object" && value !== null && "__platform" in value && "id" in value && typeof value.__platform === "string" && typeof value.id === "string";
|
|
433
|
-
function contact(input, details) {
|
|
434
|
-
return {
|
|
435
|
-
build: async () => {
|
|
436
|
-
if (typeof input === "string") {
|
|
437
|
-
return asContact(fromVCard(input));
|
|
438
|
-
}
|
|
439
|
-
if (input instanceof vCard2) {
|
|
440
|
-
return asContact(fromVCard(input.toString()));
|
|
441
|
-
}
|
|
442
|
-
if (isUser(input)) {
|
|
443
|
-
return asContact({
|
|
444
|
-
user: { __platform: input.__platform, id: input.id },
|
|
445
|
-
...details
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
return asContact(input);
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
|
|
453
371
|
export {
|
|
454
372
|
fromVCard,
|
|
455
|
-
toVCard
|
|
456
|
-
asContact,
|
|
457
|
-
contact
|
|
373
|
+
toVCard
|
|
458
374
|
};
|
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
asRichlink
|
|
4
|
+
} from "./chunk-6BI4PFTP.js";
|
|
2
5
|
import {
|
|
3
6
|
asGroup,
|
|
4
|
-
asRichlink,
|
|
5
7
|
groupSchema
|
|
6
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-3B4QH4JG.js";
|
|
7
9
|
import {
|
|
8
10
|
asPoll,
|
|
9
11
|
asPollOption
|
|
10
12
|
} from "./chunk-2D27WW5B.js";
|
|
11
13
|
import {
|
|
12
|
-
cloud
|
|
14
|
+
cloud
|
|
15
|
+
} from "./chunk-3GEJYGZK.js";
|
|
16
|
+
import {
|
|
17
|
+
asContact
|
|
18
|
+
} from "./chunk-U7AWXDH6.js";
|
|
19
|
+
import {
|
|
13
20
|
mergeStreams,
|
|
14
21
|
stream
|
|
15
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-5XEFJBN2.js";
|
|
16
23
|
import {
|
|
17
|
-
asContact,
|
|
18
24
|
fromVCard,
|
|
19
25
|
toVCard
|
|
20
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-6UZFVXQF.js";
|
|
21
27
|
import {
|
|
22
28
|
UnsupportedError,
|
|
23
29
|
buildPhotoAction,
|
|
24
30
|
definePlatform,
|
|
25
31
|
photoActionSchema
|
|
26
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-NGC4DJIX.js";
|
|
27
33
|
import {
|
|
28
34
|
asAttachment,
|
|
29
35
|
asCustom,
|
|
@@ -2039,6 +2045,55 @@ var messages3 = (clients, projectConfig) => {
|
|
|
2039
2045
|
);
|
|
2040
2046
|
};
|
|
2041
2047
|
|
|
2048
|
+
// src/providers/imessage/remote/stream-text.ts
|
|
2049
|
+
var INITIAL_THROTTLE_MS = 1e3;
|
|
2050
|
+
var BACKOFF_FACTOR = 2;
|
|
2051
|
+
var MAX_EDITS = 5;
|
|
2052
|
+
var sendStreamText = async (remote, spaceId, content) => {
|
|
2053
|
+
const chat = toChatGuid(spaceId);
|
|
2054
|
+
let sent;
|
|
2055
|
+
let full = "";
|
|
2056
|
+
let lastSentText = "";
|
|
2057
|
+
let lastEditAt = 0;
|
|
2058
|
+
let editCount = 0;
|
|
2059
|
+
const flushEdit = async (text2) => {
|
|
2060
|
+
if (!sent || text2 === lastSentText) {
|
|
2061
|
+
return;
|
|
2062
|
+
}
|
|
2063
|
+
await remote.messages.edit(chat, toMessageGuid(sent.guid), text2);
|
|
2064
|
+
lastSentText = text2;
|
|
2065
|
+
lastEditAt = Date.now();
|
|
2066
|
+
editCount += 1;
|
|
2067
|
+
};
|
|
2068
|
+
for await (const delta of content.stream()) {
|
|
2069
|
+
full += delta;
|
|
2070
|
+
if (!sent) {
|
|
2071
|
+
sent = await remote.messages.sendText(chat, full);
|
|
2072
|
+
lastSentText = full;
|
|
2073
|
+
lastEditAt = Date.now();
|
|
2074
|
+
continue;
|
|
2075
|
+
}
|
|
2076
|
+
const hasBudgetForInterimEdit = editCount < MAX_EDITS - 1;
|
|
2077
|
+
const requiredGap = INITIAL_THROTTLE_MS * BACKOFF_FACTOR ** editCount;
|
|
2078
|
+
if (hasBudgetForInterimEdit && Date.now() - lastEditAt >= requiredGap) {
|
|
2079
|
+
await flushEdit(full);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
if (!sent) {
|
|
2083
|
+
throw unsupportedRemoteContent(
|
|
2084
|
+
"streamText",
|
|
2085
|
+
"stream produced no text \u2014 nothing to send"
|
|
2086
|
+
);
|
|
2087
|
+
}
|
|
2088
|
+
await flushEdit(full);
|
|
2089
|
+
return {
|
|
2090
|
+
id: sent.guid,
|
|
2091
|
+
content: asText(full),
|
|
2092
|
+
space: { id: spaceId },
|
|
2093
|
+
timestamp: sent.dateCreated
|
|
2094
|
+
};
|
|
2095
|
+
};
|
|
2096
|
+
|
|
2042
2097
|
// src/providers/imessage/remote/typing.ts
|
|
2043
2098
|
var startTyping = async (remote, spaceId) => {
|
|
2044
2099
|
await remote.chats.setTyping(toChatGuid(spaceId), true);
|
|
@@ -2063,6 +2118,7 @@ var stopTyping2 = async (remote, spaceId) => {
|
|
|
2063
2118
|
await stopTyping(remote, spaceId);
|
|
2064
2119
|
};
|
|
2065
2120
|
var send4 = async (remote, spaceId, content) => send3(remote, spaceId, content);
|
|
2121
|
+
var sendStreamText2 = async (remote, spaceId, content) => sendStreamText(remote, spaceId, content);
|
|
2066
2122
|
var replyToMessage2 = async (remote, spaceId, msgId, content) => replyToMessage(remote, spaceId, msgId, content);
|
|
2067
2123
|
var editMessage2 = async (remote, spaceId, msgId, content) => editMessage(remote, spaceId, msgId, content);
|
|
2068
2124
|
var reactToMessage2 = async (remote, spaceId, target, reaction) => {
|
|
@@ -2120,6 +2176,17 @@ var handleEdit = async (client, space, content) => {
|
|
|
2120
2176
|
const remote = clientForPhone(client, space.phone);
|
|
2121
2177
|
await editMessage2(remote, space.id, content.target.id, content.content);
|
|
2122
2178
|
};
|
|
2179
|
+
var handleStreamText = async (client, space, content) => {
|
|
2180
|
+
if (isLocal(client)) {
|
|
2181
|
+
throw UnsupportedError.action(
|
|
2182
|
+
"streamText",
|
|
2183
|
+
"iMessage (local mode)",
|
|
2184
|
+
"streaming text responses require remote iMessage"
|
|
2185
|
+
);
|
|
2186
|
+
}
|
|
2187
|
+
const remote = clientForPhone(client, space.phone);
|
|
2188
|
+
return await sendStreamText2(remote, space.id, content);
|
|
2189
|
+
};
|
|
2123
2190
|
var handleBackground = async (client, space, content) => {
|
|
2124
2191
|
if (isLocal(client)) {
|
|
2125
2192
|
throw UnsupportedError.action(
|
|
@@ -2350,6 +2417,9 @@ var imessage = definePlatform("iMessage", {
|
|
|
2350
2417
|
await handleEdit(client, space, content);
|
|
2351
2418
|
return;
|
|
2352
2419
|
}
|
|
2420
|
+
if (content.type === "streamText") {
|
|
2421
|
+
return await handleStreamText(client, space, content);
|
|
2422
|
+
}
|
|
2353
2423
|
if (content.type === "rename") {
|
|
2354
2424
|
await handleRename(client, space, content);
|
|
2355
2425
|
return;
|
|
@@ -216,7 +216,7 @@ var UnsupportedError = class _UnsupportedError extends Error {
|
|
|
216
216
|
};
|
|
217
217
|
|
|
218
218
|
// src/platform/define.ts
|
|
219
|
-
import { withSpan as withSpan2 } from "@photon-ai/otel";
|
|
219
|
+
import { createLogger as createLogger2, withSpan as withSpan2 } from "@photon-ai/otel";
|
|
220
220
|
|
|
221
221
|
// src/utils/identifier.ts
|
|
222
222
|
import { sanitizeEmail, sanitizePhone } from "@photon-ai/otel";
|
|
@@ -747,6 +747,7 @@ function buildMessage(params) {
|
|
|
747
747
|
}
|
|
748
748
|
|
|
749
749
|
// src/platform/define.ts
|
|
750
|
+
var platformLog2 = createLogger2("spectrum.platform");
|
|
750
751
|
function classifySpaceIdentifier(args) {
|
|
751
752
|
const stringArgs = args.filter((a) => typeof a === "string");
|
|
752
753
|
if (stringArgs.length > 1) {
|
|
@@ -910,13 +911,20 @@ function createPlatformInstance(def, runtime) {
|
|
|
910
911
|
const eventProperties = {};
|
|
911
912
|
const customEvents = def.events ?? {};
|
|
912
913
|
for (const eventName of Object.keys(customEvents)) {
|
|
913
|
-
const
|
|
914
|
-
if (
|
|
914
|
+
const declared = customEvents[eventName];
|
|
915
|
+
if (typeof declared === "function") {
|
|
916
|
+
const producer = declared;
|
|
915
917
|
eventProperties[eventName] = producer({
|
|
916
918
|
client: runtime.client,
|
|
917
919
|
config: runtime.config,
|
|
920
|
+
projectConfig: runtime.projectConfig,
|
|
918
921
|
store: runtime.store
|
|
919
922
|
});
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
const fusorEvents = runtime.subscribeEvent?.(eventName);
|
|
926
|
+
if (fusorEvents) {
|
|
927
|
+
eventProperties[eventName] = fusorEvents;
|
|
920
928
|
}
|
|
921
929
|
}
|
|
922
930
|
let messagesIterable;
|
|
@@ -948,8 +956,9 @@ function createPlatformInstance(def, runtime) {
|
|
|
948
956
|
eventProperties
|
|
949
957
|
);
|
|
950
958
|
}
|
|
951
|
-
function definePlatform(name,
|
|
952
|
-
const
|
|
959
|
+
function definePlatform(name, rawDef) {
|
|
960
|
+
const def = rawDef;
|
|
961
|
+
const fullDef = { ...def, name };
|
|
953
962
|
const platformCache = /* @__PURE__ */ new WeakMap();
|
|
954
963
|
const narrowSpectrum = (spectrum) => {
|
|
955
964
|
const cached = platformCache.get(spectrum);
|
|
@@ -969,17 +978,19 @@ function definePlatform(name, def) {
|
|
|
969
978
|
};
|
|
970
979
|
const narrowSpace = (input) => {
|
|
971
980
|
if (input.__platform !== name) {
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
981
|
+
platformLog2.warn("space platform mismatch; narrowing skipped", {
|
|
982
|
+
expected: name,
|
|
983
|
+
actual: input.__platform
|
|
984
|
+
});
|
|
975
985
|
}
|
|
976
986
|
return input;
|
|
977
987
|
};
|
|
978
988
|
const narrowMessage = (input) => {
|
|
979
989
|
if (input.platform !== name) {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
990
|
+
platformLog2.warn("message platform mismatch; narrowing skipped", {
|
|
991
|
+
expected: name,
|
|
992
|
+
actual: input.platform
|
|
993
|
+
});
|
|
983
994
|
}
|
|
984
995
|
return input;
|
|
985
996
|
};
|
|
@@ -1022,12 +1033,6 @@ function definePlatform(name, def) {
|
|
|
1022
1033
|
}
|
|
1023
1034
|
return narrower;
|
|
1024
1035
|
}
|
|
1025
|
-
function defineFusorPlatform(name, def) {
|
|
1026
|
-
return definePlatform(
|
|
1027
|
-
name,
|
|
1028
|
-
def
|
|
1029
|
-
);
|
|
1030
|
-
}
|
|
1031
1036
|
|
|
1032
1037
|
export {
|
|
1033
1038
|
photoActionSchema,
|
|
@@ -1042,6 +1047,5 @@ export {
|
|
|
1042
1047
|
senderAttrs,
|
|
1043
1048
|
wrapProviderMessage,
|
|
1044
1049
|
buildSpace,
|
|
1045
|
-
definePlatform
|
|
1046
|
-
defineFusorPlatform
|
|
1050
|
+
definePlatform
|
|
1047
1051
|
};
|
|
@@ -3,17 +3,19 @@ import {
|
|
|
3
3
|
asPollOption
|
|
4
4
|
} from "./chunk-2D27WW5B.js";
|
|
5
5
|
import {
|
|
6
|
-
cloud
|
|
7
|
-
|
|
8
|
-
stream
|
|
9
|
-
} from "./chunk-MC6ZKFSG.js";
|
|
6
|
+
cloud
|
|
7
|
+
} from "./chunk-3GEJYGZK.js";
|
|
10
8
|
import {
|
|
11
9
|
asContact
|
|
12
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-U7AWXDH6.js";
|
|
11
|
+
import {
|
|
12
|
+
mergeStreams,
|
|
13
|
+
stream
|
|
14
|
+
} from "./chunk-5XEFJBN2.js";
|
|
13
15
|
import {
|
|
14
16
|
UnsupportedError,
|
|
15
17
|
definePlatform
|
|
16
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-NGC4DJIX.js";
|
|
17
19
|
import {
|
|
18
20
|
asAttachment,
|
|
19
21
|
asCustom,
|