spectrum-ts 0.5.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.
@@ -13,7 +13,7 @@ import {
13
13
  import {
14
14
  asText,
15
15
  definePlatform
16
- } from "../../chunk-XEEDIGVK.js";
16
+ } from "../../chunk-XZTTLPHE.js";
17
17
 
18
18
  // src/providers/imessage/index.ts
19
19
  import { createClient as createClient2, directChat } from "@photon-ai/advanced-imessage";
@@ -107,13 +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
- import {
115
- readAttachmentBytes
116
- } from "@photon-ai/imessage-kit";
114
+ var synthSendResult = () => ({
115
+ id: crypto.randomUUID(),
116
+ timestamp: /* @__PURE__ */ new Date()
117
+ });
117
118
  var DEFAULT_ATTACHMENT_NAME = "attachment";
118
119
  var VCARD_MIME_TYPES = /* @__PURE__ */ new Set([
119
120
  "text/vcard",
@@ -129,17 +130,21 @@ var isVCardAttachment = (mimeType, fileName) => {
129
130
  }
130
131
  return Boolean(fileName?.toLowerCase().endsWith(".vcf"));
131
132
  };
132
- var toSpace = (message) => ({
133
- id: message.chatId,
134
- type: message.chatKind === "group" ? "group" : "dm"
135
- });
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
+ };
136
141
  var toAttachmentContent = (att) => {
137
142
  const { localPath } = att;
138
143
  return asAttachment({
139
144
  name: att.fileName ?? DEFAULT_ATTACHMENT_NAME,
140
145
  mimeType: att.mimeType,
141
146
  size: att.sizeBytes,
142
- read: () => readAttachmentBytes(att),
147
+ read: () => readLocalAttachment(att),
143
148
  stream: localPath ? async () => Readable.toWeb(
144
149
  createReadStream(localPath)
145
150
  ) : void 0
@@ -147,16 +152,23 @@ var toAttachmentContent = (att) => {
147
152
  };
148
153
  var toVCardContent = async (att) => {
149
154
  try {
150
- const buf = await readAttachmentBytes(att);
155
+ const buf = await readLocalAttachment(att);
151
156
  return asContact(fromVCard(buf.toString("utf8")));
152
157
  } catch {
153
158
  return toAttachmentContent(att);
154
159
  }
155
160
  };
156
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
+ }
157
169
  const base = {
158
170
  sender: { id: message.participant ?? "" },
159
- space: toSpace(message),
171
+ space: { id: chatId, type: chatKind === "group" ? "group" : "dm" },
160
172
  timestamp: message.createdAt
161
173
  };
162
174
  if (message.attachments.length > 0) {
@@ -178,16 +190,23 @@ var toMessages = async (message) => {
178
190
  };
179
191
  var messages = (client) => stream((emit, end) => {
180
192
  let lastPromise = Promise.resolve();
181
- client.startWatching({
182
- onMessage: (message) => {
193
+ const startPromise = client.startWatching({
194
+ onIncomingMessage: (message) => {
183
195
  lastPromise = lastPromise.then(() => toMessages(message)).then((ms) => {
184
196
  for (const m of ms) {
185
197
  emit(m);
186
198
  }
187
- }).catch((error) => end(error));
188
- }
189
- });
190
- return () => client.stopWatching();
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
+ };
191
210
  });
192
211
  var vcardFileName = (content) => {
193
212
  const base = content.name?.formatted ?? content.user?.id ?? "contact";
@@ -199,7 +218,7 @@ var sendTempFile = async (client, spaceId, name, data) => {
199
218
  const tmp = join(dir, safeName);
200
219
  await writeFile(tmp, data);
201
220
  try {
202
- await client.send(spaceId, { attachments: [tmp] });
221
+ await client.send({ to: spaceId, attachments: [tmp] });
203
222
  } finally {
204
223
  await rm(dir, { recursive: true, force: true }).catch(() => {
205
224
  });
@@ -208,11 +227,11 @@ var sendTempFile = async (client, spaceId, name, data) => {
208
227
  var send = async (client, spaceId, content) => {
209
228
  switch (content.type) {
210
229
  case "text":
211
- await client.send(spaceId, content.text);
212
- break;
230
+ await client.send({ to: spaceId, text: content.text });
231
+ return synthSendResult();
213
232
  case "attachment":
214
233
  await sendTempFile(client, spaceId, content.name, await content.read());
215
- break;
234
+ return synthSendResult();
216
235
  case "contact": {
217
236
  const vcf = await toVCard(content);
218
237
  await sendTempFile(
@@ -221,10 +240,12 @@ var send = async (client, spaceId, content) => {
221
240
  vcardFileName(content),
222
241
  Buffer.from(vcf, "utf8")
223
242
  );
224
- break;
243
+ return synthSendResult();
225
244
  }
226
245
  default:
227
- break;
246
+ throw new Error(
247
+ `Unsupported iMessage local content type: ${content.type}`
248
+ );
228
249
  }
229
250
  };
230
251
 
@@ -237,7 +258,7 @@ import {
237
258
 
238
259
  // src/utils/audio.ts
239
260
  import { spawn } from "child_process";
240
- 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";
241
262
  import { tmpdir as tmpdir2 } from "os";
242
263
  import { join as join2 } from "path";
243
264
  var M4A_BRANDS = /* @__PURE__ */ new Set([
@@ -344,7 +365,7 @@ var transcodeToM4a = async (buffer) => {
344
365
  if (code !== 0) {
345
366
  throw new Error(`ffmpeg conversion failed (exit ${code}): ${stderr}`);
346
367
  }
347
- const out = await readFile(outPath);
368
+ const out = await readFile2(outPath);
348
369
  return { buffer: out, duration: parseDuration(stderr) };
349
370
  } finally {
350
371
  await rm2(dir, { recursive: true, force: true }).catch(() => {
@@ -359,6 +380,10 @@ var ensureM4a = async (buffer, mimeType) => {
359
380
  };
360
381
 
361
382
  // src/providers/imessage/remote.ts
383
+ var toSendResult = (receipt) => ({
384
+ id: receipt.guid,
385
+ timestamp: /* @__PURE__ */ new Date()
386
+ });
362
387
  var VCARD_MIME_TYPES2 = /* @__PURE__ */ new Set([
363
388
  "text/vcard",
364
389
  "text/x-vcard",
@@ -425,6 +450,9 @@ var clientStream = (client) => {
425
450
  (async () => {
426
451
  try {
427
452
  for await (const event of sub) {
453
+ if (event.message.isFromMe) {
454
+ continue;
455
+ }
428
456
  for (const message of await toMessages2(client, event)) {
429
457
  emit(message);
430
458
  }
@@ -469,27 +497,27 @@ var stopTyping = async (clients, spaceId) => {
469
497
  var send2 = async (clients, spaceId, content) => {
470
498
  const remote = clients[0];
471
499
  if (!remote) {
472
- return;
500
+ throw new Error("No remote iMessage client available");
473
501
  }
502
+ const chat = chatGuid(spaceId);
474
503
  switch (content.type) {
475
504
  case "text":
476
- await remote.messages.send(chatGuid(spaceId), content.text);
477
- break;
505
+ return toSendResult(await remote.messages.send(chat, content.text));
478
506
  case "attachment": {
479
507
  const attachment = await remote.attachments.upload({
480
508
  data: await content.read(),
481
509
  fileName: content.name,
482
510
  mimeType: content.mimeType
483
511
  });
484
- await remote.messages.send(chatGuid(spaceId), "", {
485
- attachment: attachment.guid
486
- });
487
- break;
512
+ return toSendResult(
513
+ await remote.messages.send(chat, "", {
514
+ attachment: attachment.guid
515
+ })
516
+ );
488
517
  }
489
518
  case "contact": {
490
519
  const attachment = await sendContactAttachment(remote, content);
491
- await remote.messages.send(chatGuid(spaceId), "", { attachment });
492
- break;
520
+ return toSendResult(await remote.messages.send(chat, "", { attachment }));
493
521
  }
494
522
  case "voice": {
495
523
  const { buffer } = await ensureM4a(
@@ -501,11 +529,12 @@ var send2 = async (clients, spaceId, content) => {
501
529
  fileName: content.name ?? "voice.m4a",
502
530
  mimeType: "audio/x-m4a"
503
531
  });
504
- await remote.messages.send(chatGuid(spaceId), "", {
505
- attachment: attachment.guid,
506
- audioMessage: true
507
- });
508
- break;
532
+ return toSendResult(
533
+ await remote.messages.send(chat, "", {
534
+ attachment: attachment.guid,
535
+ audioMessage: true
536
+ })
537
+ );
509
538
  }
510
539
  default:
511
540
  throw new Error(`Unsupported iMessage content type: ${content.type}`);
@@ -514,30 +543,33 @@ var send2 = async (clients, spaceId, content) => {
514
543
  var replyToMessage = async (clients, spaceId, msgId, content) => {
515
544
  const remote = clients[0];
516
545
  if (!remote) {
517
- return;
546
+ throw new Error("No remote iMessage client available");
518
547
  }
519
548
  const chat = chatGuid(spaceId);
520
549
  const replyTo = messageGuid(msgId);
521
550
  switch (content.type) {
522
551
  case "text":
523
- await remote.messages.send(chat, content.text, { replyTo });
524
- break;
552
+ return toSendResult(
553
+ await remote.messages.send(chat, content.text, { replyTo })
554
+ );
525
555
  case "attachment": {
526
556
  const attachment = await remote.attachments.upload({
527
557
  data: await content.read(),
528
558
  fileName: content.name,
529
559
  mimeType: content.mimeType
530
560
  });
531
- await remote.messages.send(chat, "", {
532
- attachment: attachment.guid,
533
- replyTo
534
- });
535
- break;
561
+ return toSendResult(
562
+ await remote.messages.send(chat, "", {
563
+ attachment: attachment.guid,
564
+ replyTo
565
+ })
566
+ );
536
567
  }
537
568
  case "contact": {
538
569
  const attachment = await sendContactAttachment(remote, content);
539
- await remote.messages.send(chat, "", { attachment, replyTo });
540
- break;
570
+ return toSendResult(
571
+ await remote.messages.send(chat, "", { attachment, replyTo })
572
+ );
541
573
  }
542
574
  case "voice": {
543
575
  const { buffer } = await ensureM4a(
@@ -549,17 +581,32 @@ var replyToMessage = async (clients, spaceId, msgId, content) => {
549
581
  fileName: content.name ?? "voice.m4a",
550
582
  mimeType: "audio/x-m4a"
551
583
  });
552
- await remote.messages.send(chat, "", {
553
- attachment: attachment.guid,
554
- audioMessage: true,
555
- replyTo
556
- });
557
- break;
584
+ return toSendResult(
585
+ await remote.messages.send(chat, "", {
586
+ attachment: attachment.guid,
587
+ audioMessage: true,
588
+ replyTo
589
+ })
590
+ );
558
591
  }
559
592
  default:
560
593
  throw new Error(`Unsupported iMessage content type: ${content.type}`);
561
594
  }
562
595
  };
596
+ var editMessage = async (clients, spaceId, msgId, content) => {
597
+ if (content.type !== "text") {
598
+ throw new Error("iMessage only supports editing text content");
599
+ }
600
+ const remote = clients[0];
601
+ if (!remote) {
602
+ throw new Error("No remote iMessage client available");
603
+ }
604
+ await remote.messages.edit(
605
+ chatGuid(spaceId),
606
+ messageGuid(msgId),
607
+ content.text
608
+ );
609
+ };
563
610
  var reactToMessage = async (clients, spaceId, msgId, reaction) => {
564
611
  const remote = clients[0];
565
612
  if (!remote) {
@@ -671,10 +718,9 @@ var imessage = definePlatform("iMessage", {
671
718
  actions: {
672
719
  send: async ({ space, content, client }) => {
673
720
  if (isLocal(client)) {
674
- await send(client, space.id, content);
675
- } else {
676
- await send2(client, space.id, content);
721
+ return await send(client, space.id, content);
677
722
  }
723
+ return await send2(client, space.id, content);
678
724
  },
679
725
  startTyping: async ({ space, client }) => {
680
726
  if (isLocal(client)) {
@@ -696,9 +742,19 @@ var imessage = definePlatform("iMessage", {
696
742
  },
697
743
  replyToMessage: async ({ space, messageId, content, client }) => {
698
744
  if (isLocal(client)) {
699
- return;
745
+ throw new Error(
746
+ "iMessage local mode does not support replying to messages"
747
+ );
748
+ }
749
+ return await replyToMessage(client, space.id, messageId, content);
750
+ },
751
+ editMessage: async ({ space, messageId, content, client }) => {
752
+ if (isLocal(client)) {
753
+ throw new Error(
754
+ "iMessage local mode does not support editing messages"
755
+ );
700
756
  }
701
- await replyToMessage(client, space.id, messageId, content);
757
+ await editMessage(client, space.id, messageId, content);
702
758
  }
703
759
  }
704
760
  });
@@ -1,4 +1,4 @@
1
- import { d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-CfiD_00g.js';
1
+ import { d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DZMHfgYQ.js';
2
2
  import * as node_readline from 'node:readline';
3
3
  import z__default from 'zod';
4
4
  import 'hotscript';
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  definePlatform
3
- } from "../../chunk-XEEDIGVK.js";
3
+ } from "../../chunk-XZTTLPHE.js";
4
4
 
5
5
  // src/providers/terminal/index.ts
6
6
  import { createInterface } from "readline";
@@ -49,9 +49,13 @@ var terminal = definePlatform("terminal", {
49
49
  },
50
50
  actions: {
51
51
  send: async ({ content }) => {
52
- if (content.type === "text") {
53
- console.log(content.text);
52
+ if (content.type !== "text") {
53
+ throw new Error(
54
+ `Terminal provider only supports text content, got "${content.type}"`
55
+ );
54
56
  }
57
+ console.log(content.text);
58
+ return { id: crypto.randomUUID(), timestamp: /* @__PURE__ */ new Date() };
55
59
  }
56
60
  }
57
61
  });
@@ -1,7 +1,7 @@
1
1
  import { M as ManagedStream } from '../../stream-DGy4geUK.js';
2
2
  import * as z from 'zod';
3
3
  import z__default from 'zod';
4
- import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-CfiD_00g.js';
4
+ import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DZMHfgYQ.js';
5
5
  import * as zod_v4_core from 'zod/v4/core';
6
6
  import { WhatsAppClient } from '@photon-ai/whatsapp-business';
7
7
  import 'hotscript';
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  asText,
9
9
  definePlatform
10
- } from "../../chunk-XEEDIGVK.js";
10
+ } from "../../chunk-XZTTLPHE.js";
11
11
 
12
12
  // src/providers/whatsapp-business/index.ts
13
13
  import {
@@ -16,6 +16,9 @@ import {
16
16
 
17
17
  // src/providers/whatsapp-business/messages.ts
18
18
  import { extension as mimeExtension } from "mime-types";
19
+ var toSendResult = (result) => ({
20
+ id: result.messageId
21
+ });
19
22
  var mapWaPhoneType = (type) => {
20
23
  if (!type) {
21
24
  return void 0;
@@ -311,8 +314,9 @@ var messages = (client) => {
311
314
  var send = async (client, spaceId, content) => {
312
315
  switch (content.type) {
313
316
  case "text":
314
- await client.messages.send({ to: spaceId, text: content.text });
315
- break;
317
+ return toSendResult(
318
+ await client.messages.send({ to: spaceId, text: content.text })
319
+ );
316
320
  case "attachment": {
317
321
  const { mediaId } = await client.media.upload({
318
322
  file: await content.read(),
@@ -321,32 +325,35 @@ var send = async (client, spaceId, content) => {
321
325
  });
322
326
  const mediaType = mimeToMediaType(content.mimeType);
323
327
  const mediaPayload = mediaType === "document" ? { id: mediaId, filename: content.name } : { id: mediaId };
324
- await client.messages.send({
325
- to: spaceId,
326
- [mediaType]: mediaPayload
327
- });
328
- break;
328
+ return toSendResult(
329
+ await client.messages.send({
330
+ to: spaceId,
331
+ [mediaType]: mediaPayload
332
+ })
333
+ );
329
334
  }
330
335
  case "contact":
331
- await client.messages.send({
332
- to: spaceId,
333
- contacts: [contactToWa(content)]
334
- });
335
- break;
336
+ return toSendResult(
337
+ await client.messages.send({
338
+ to: spaceId,
339
+ contacts: [contactToWa(content)]
340
+ })
341
+ );
336
342
  case "voice": {
337
343
  const { mediaId } = await client.media.upload({
338
344
  file: await content.read(),
339
345
  mimeType: content.mimeType,
340
346
  filename: voiceFilename(content)
341
347
  });
342
- await client.messages.send({
343
- to: spaceId,
344
- audio: { id: mediaId }
345
- });
346
- break;
348
+ return toSendResult(
349
+ await client.messages.send({
350
+ to: spaceId,
351
+ audio: { id: mediaId }
352
+ })
353
+ );
347
354
  }
348
355
  default:
349
- break;
356
+ throw new Error(`Unsupported WhatsApp content type: ${content.type}`);
350
357
  }
351
358
  };
352
359
  var reactToMessage = async (client, spaceId, messageId, reaction) => {
@@ -358,12 +365,13 @@ var reactToMessage = async (client, spaceId, messageId, reaction) => {
358
365
  var replyToMessage = async (client, spaceId, messageId, content) => {
359
366
  switch (content.type) {
360
367
  case "text":
361
- await client.messages.send({
362
- to: spaceId,
363
- replyTo: messageId,
364
- text: content.text
365
- });
366
- break;
368
+ return toSendResult(
369
+ await client.messages.send({
370
+ to: spaceId,
371
+ replyTo: messageId,
372
+ text: content.text
373
+ })
374
+ );
367
375
  case "attachment": {
368
376
  const { mediaId } = await client.media.upload({
369
377
  file: await content.read(),
@@ -372,35 +380,38 @@ var replyToMessage = async (client, spaceId, messageId, content) => {
372
380
  });
373
381
  const mediaType = mimeToMediaType(content.mimeType);
374
382
  const mediaPayload = mediaType === "document" ? { id: mediaId, filename: content.name } : { id: mediaId };
375
- await client.messages.send({
376
- to: spaceId,
377
- replyTo: messageId,
378
- [mediaType]: mediaPayload
379
- });
380
- break;
383
+ return toSendResult(
384
+ await client.messages.send({
385
+ to: spaceId,
386
+ replyTo: messageId,
387
+ [mediaType]: mediaPayload
388
+ })
389
+ );
381
390
  }
382
391
  case "contact":
383
- await client.messages.send({
384
- to: spaceId,
385
- replyTo: messageId,
386
- contacts: [contactToWa(content)]
387
- });
388
- break;
392
+ return toSendResult(
393
+ await client.messages.send({
394
+ to: spaceId,
395
+ replyTo: messageId,
396
+ contacts: [contactToWa(content)]
397
+ })
398
+ );
389
399
  case "voice": {
390
400
  const { mediaId } = await client.media.upload({
391
401
  file: await content.read(),
392
402
  mimeType: content.mimeType,
393
403
  filename: voiceFilename(content)
394
404
  });
395
- await client.messages.send({
396
- to: spaceId,
397
- replyTo: messageId,
398
- audio: { id: mediaId }
399
- });
400
- break;
405
+ return toSendResult(
406
+ await client.messages.send({
407
+ to: spaceId,
408
+ replyTo: messageId,
409
+ audio: { id: mediaId }
410
+ })
411
+ );
401
412
  }
402
413
  default:
403
- break;
414
+ throw new Error(`Unsupported WhatsApp content type: ${content.type}`);
404
415
  }
405
416
  };
406
417
 
@@ -457,7 +468,7 @@ var whatsappBusiness = definePlatform("WhatsApp Business", {
457
468
  },
458
469
  actions: {
459
470
  send: async ({ space, content, client }) => {
460
- await send(client, space.id, content);
471
+ return await send(client, space.id, content);
461
472
  },
462
473
  reactToMessage: async ({ space, messageId, reaction, client }) => {
463
474
  await reactToMessage(
@@ -468,7 +479,7 @@ var whatsappBusiness = definePlatform("WhatsApp Business", {
468
479
  );
469
480
  },
470
481
  replyToMessage: async ({ space, messageId, content, client }) => {
471
- await replyToMessage(
482
+ return await replyToMessage(
472
483
  client,
473
484
  space.id,
474
485
  messageId,
@@ -92,23 +92,35 @@ interface User {
92
92
 
93
93
  interface Space<_Def = unknown> {
94
94
  readonly __platform: string;
95
+ edit(message: OutboundMessage, newContent: ContentInput): Promise<void>;
95
96
  readonly id: string;
96
97
  responding<T>(fn: () => T | Promise<T>): Promise<T>;
97
- send(...content: [ContentInput, ...ContentInput[]]): Promise<void>;
98
+ send(content: ContentInput): Promise<OutboundMessage>;
99
+ send(...content: [ContentInput, ContentInput, ...ContentInput[]]): Promise<OutboundMessage[]>;
98
100
  startTyping(): Promise<void>;
99
101
  stopTyping(): Promise<void>;
100
102
  }
101
103
 
102
- interface Message<TPlatform extends string = string, TSender extends User = User, TSpace extends Space = Space> {
104
+ interface BaseMessage<TPlatform extends string = string, TSender extends User = User, TSpace extends Space = Space> {
103
105
  content: Content;
104
106
  readonly id: string;
105
107
  platform: TPlatform;
106
108
  react(reaction: string): Promise<void>;
107
- reply(...content: [ContentInput, ...ContentInput[]]): Promise<void>;
108
- sender: TSender;
109
+ reply(content: ContentInput): Promise<OutboundMessage<TPlatform, TSender, TSpace>>;
110
+ reply(...content: [ContentInput, ContentInput, ...ContentInput[]]): Promise<OutboundMessage<TPlatform, TSender, TSpace>[]>;
109
111
  space: TSpace;
110
112
  timestamp: Date;
111
113
  }
114
+ interface InboundMessage<TPlatform extends string = string, TSender extends User = User, TSpace extends Space = Space> extends BaseMessage<TPlatform, TSender, TSpace> {
115
+ direction: "inbound";
116
+ sender: TSender;
117
+ }
118
+ interface OutboundMessage<TPlatform extends string = string, TSender extends User = User, TSpace extends Space = Space> extends BaseMessage<TPlatform, TSender, TSpace> {
119
+ direction: "outbound";
120
+ edit(newContent: ContentInput): Promise<void>;
121
+ sender: TSender | undefined;
122
+ }
123
+ type Message<TPlatform extends string = string, TSender extends User = User, TSpace extends Space = Space> = InboundMessage<TPlatform, TSender, TSpace> | OutboundMessage<TPlatform, TSender, TSpace>;
112
124
 
113
125
  type ResolvedSpace = Pick<Space, "id">;
114
126
  type SpaceRef = Pick<Space, "id" | "__platform">;
@@ -131,6 +143,11 @@ type ProviderMessage<TSender extends ResolvedUser = ResolvedUser, TSpace extends
131
143
  space: TSpace;
132
144
  timestamp?: Date;
133
145
  } & TExtra;
146
+ interface SendResult<TSender extends ResolvedUser = ResolvedUser> {
147
+ id: string;
148
+ sender?: TSender;
149
+ timestamp?: Date;
150
+ }
134
151
  type MergeSchema<TSchema extends z__default.ZodType | undefined, TBase extends object> = TSchema extends z__default.ZodType ? string extends keyof z__default.infer<TSchema> ? TBase : Omit<z__default.infer<TSchema>, keyof TBase> & TBase : TBase;
135
152
  type SchemaMessage<TUserSchema extends z__default.ZodType | undefined = undefined, TSpaceSchema extends z__default.ZodType | undefined = undefined> = ProviderMessage<MergeSchema<TUserSchema, ResolvedUser>, MergeSchema<TSpaceSchema, ResolvedSpace>>;
136
153
  type InferEventPayload<T> = T extends (ctx: never) => AsyncIterable<infer P> ? P : never;
@@ -146,7 +163,7 @@ interface PlatformDef<_Name extends string = string, _ConfigSchema extends z__de
146
163
  content: Content;
147
164
  client: _Client;
148
165
  config: z__default.infer<_ConfigSchema>;
149
- }) => Promise<void>;
166
+ }) => Promise<SendResult<_ResolvedUser>>;
150
167
  startTyping?: (_: {
151
168
  space: _ResolvedSpace & SpaceRef;
152
169
  client: _Client;
@@ -170,6 +187,13 @@ interface PlatformDef<_Name extends string = string, _ConfigSchema extends z__de
170
187
  content: Content;
171
188
  client: _Client;
172
189
  config: z__default.infer<_ConfigSchema>;
190
+ }) => Promise<SendResult<_ResolvedUser>>;
191
+ editMessage?: (_: {
192
+ space: _ResolvedSpace & SpaceRef;
193
+ messageId: string;
194
+ content: Content;
195
+ client: _Client;
196
+ config: z__default.infer<_ConfigSchema>;
173
197
  }) => Promise<void>;
174
198
  };
175
199
  config: _ConfigSchema;
@@ -215,11 +239,12 @@ interface PlatformDef<_Name extends string = string, _ConfigSchema extends z__de
215
239
  }
216
240
  interface AnyPlatformDef {
217
241
  actions: {
218
- send: (_: any) => Promise<void>;
242
+ send: (_: any) => Promise<SendResult>;
219
243
  startTyping?: (_: any) => Promise<void>;
220
244
  stopTyping?: (_: any) => Promise<void>;
221
245
  reactToMessage?: (_: any) => Promise<void>;
222
- replyToMessage?: (_: any) => Promise<void>;
246
+ replyToMessage?: (_: any) => Promise<SendResult>;
247
+ editMessage?: (_: any) => Promise<void>;
223
248
  };
224
249
  config: z__default.ZodType<object>;
225
250
  events: {
@@ -318,4 +343,4 @@ interface Platform<Def extends AnyPlatformDef> {
318
343
  (message: Message): PlatformMessage<Def>;
319
344
  }
320
345
 
321
- export type { AnyPlatformDef as A, ContentBuilder as C, EventProducer as E, Message as M, ProviderMessage as P, SpectrumLike as S, User as U, ContentInput as a, Content as b, PlatformDef as c, Platform as d, PlatformProviderConfig as e, CustomEventStreams as f, Space as g, PlatformInstance as h, PlatformMessage as i, PlatformSpace as j, PlatformUser as k, SchemaMessage as l };
346
+ export type { AnyPlatformDef as A, ContentBuilder as C, EventProducer as E, InboundMessage as I, Message as M, OutboundMessage as O, ProviderMessage as P, SpectrumLike as S, User as U, ContentInput as a, Content as b, PlatformDef as c, Platform as d, PlatformProviderConfig as e, CustomEventStreams as f, Space as g, PlatformInstance as h, PlatformMessage as i, PlatformSpace as j, PlatformUser as k, SchemaMessage as l };