spectrum-ts 0.6.1 → 0.8.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.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import {
2
- SpectrumCloudError,
3
- cloud
4
- } from "./chunk-HXM64ENV.js";
2
+ richlink
3
+ } from "./chunk-H5XYVRHM.js";
5
4
  import {
5
+ SpectrumCloudError,
6
6
  attachment,
7
7
  bufferToStream,
8
+ cloud,
8
9
  contact,
9
10
  custom,
10
11
  fromVCard,
@@ -13,14 +14,15 @@ import {
13
14
  stream,
14
15
  streamSchema,
15
16
  toVCard
16
- } from "./chunk-UZWRB3FZ.js";
17
+ } from "./chunk-ZNUORCLB.js";
17
18
  import {
19
+ UnsupportedError,
18
20
  buildMessage,
19
21
  buildSpace,
20
22
  definePlatform,
21
23
  resolveContents,
22
24
  text
23
- } from "./chunk-XZTTLPHE.js";
25
+ } from "./chunk-4O6MQC5Z.js";
24
26
 
25
27
  // src/content/voice.ts
26
28
  import { createReadStream } from "fs";
@@ -174,11 +176,11 @@ async function Spectrum(options) {
174
176
  const adaptIterable = (iterable) => {
175
177
  return stream((emit, end) => {
176
178
  const iterator = iterable[Symbol.asyncIterator]();
177
- (async () => {
179
+ const pump = (async () => {
178
180
  try {
179
181
  let result = await iterator.next();
180
182
  while (!result.done) {
181
- emit(result.value);
183
+ await emit(result.value);
182
184
  result = await iterator.next();
183
185
  }
184
186
  end();
@@ -188,6 +190,7 @@ async function Spectrum(options) {
188
190
  })();
189
191
  return async () => {
190
192
  await iterator.return?.();
193
+ await pump;
191
194
  };
192
195
  });
193
196
  };
@@ -236,14 +239,14 @@ async function Spectrum(options) {
236
239
  return adaptIterable(bindSend());
237
240
  };
238
241
  const createMessagesStream = () => {
239
- return stream(async (emit, end) => {
242
+ return stream((emit, end) => {
240
243
  const merged = mergeStreams(
241
244
  Array.from(platformStates.values(), createProviderMessagesStream)
242
245
  );
243
- (async () => {
246
+ const pump = (async () => {
244
247
  try {
245
248
  for await (const value of merged) {
246
- emit(value);
249
+ await emit(value);
247
250
  }
248
251
  end();
249
252
  } catch (error) {
@@ -252,11 +255,12 @@ async function Spectrum(options) {
252
255
  })();
253
256
  return async () => {
254
257
  await merged.close();
258
+ await pump;
255
259
  };
256
260
  });
257
261
  };
258
262
  const createCustomEventStream = (eventName) => {
259
- return stream(async (emit, end) => {
263
+ return stream((emit, end) => {
260
264
  const providerStreams = Array.from(platformStates.values(), (state) => {
261
265
  const { client, config, definition } = state;
262
266
  const producer = definition.events[eventName];
@@ -274,10 +278,10 @@ async function Spectrum(options) {
274
278
  (value) => value !== void 0
275
279
  );
276
280
  const merged = mergeStreams(providerStreams);
277
- (async () => {
281
+ const pump = (async () => {
278
282
  try {
279
283
  for await (const value of merged) {
280
- emit(value);
284
+ await emit(value);
281
285
  }
282
286
  end();
283
287
  } catch (error) {
@@ -286,6 +290,7 @@ async function Spectrum(options) {
286
290
  })();
287
291
  return async () => {
288
292
  await merged.close();
293
+ await pump;
289
294
  };
290
295
  });
291
296
  };
@@ -367,6 +372,7 @@ async function Spectrum(options) {
367
372
  export {
368
373
  Spectrum,
369
374
  SpectrumCloudError,
375
+ UnsupportedError,
370
376
  attachment,
371
377
  cloud,
372
378
  contact,
@@ -375,6 +381,7 @@ export {
375
381
  fromVCard,
376
382
  mergeStreams,
377
383
  resolveContents,
384
+ richlink,
378
385
  stream,
379
386
  text,
380
387
  toVCard,
@@ -1,9 +1,9 @@
1
- import { M as ManagedStream } from '../../stream-DGy4geUK.js';
1
+ import { M as ManagedStream } from '../../stream-B55k7W8-.js';
2
2
  import { AdvancedIMessage } from '@photon-ai/advanced-imessage';
3
3
  import { IMessageSDK } from '@photon-ai/imessage-kit';
4
4
  import * as z from 'zod';
5
5
  import z__default from 'zod';
6
- import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DZMHfgYQ.js';
6
+ import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DLrsDzV-.js';
7
7
  import * as zod_v4_core from 'zod/v4/core';
8
8
  import 'hotscript';
9
9
 
@@ -1,19 +1,21 @@
1
1
  import {
2
- cloud
3
- } from "../../chunk-HXM64ENV.js";
2
+ asRichlink
3
+ } from "../../chunk-H5XYVRHM.js";
4
4
  import {
5
5
  asAttachment,
6
6
  asContact,
7
7
  asCustom,
8
+ cloud,
8
9
  fromVCard,
9
10
  mergeStreams,
10
11
  stream,
11
12
  toVCard
12
- } from "../../chunk-UZWRB3FZ.js";
13
+ } from "../../chunk-ZNUORCLB.js";
13
14
  import {
15
+ UnsupportedError,
14
16
  asText,
15
17
  definePlatform
16
- } from "../../chunk-XZTTLPHE.js";
18
+ } from "../../chunk-4O6MQC5Z.js";
17
19
 
18
20
  // src/providers/imessage/index.ts
19
21
  import { createClient as createClient2, directChat } from "@photon-ai/advanced-imessage";
@@ -192,9 +194,9 @@ var messages = (client) => stream((emit, end) => {
192
194
  let lastPromise = Promise.resolve();
193
195
  const startPromise = client.startWatching({
194
196
  onIncomingMessage: (message) => {
195
- lastPromise = lastPromise.then(() => toMessages(message)).then((ms) => {
197
+ lastPromise = lastPromise.then(() => toMessages(message)).then(async (ms) => {
196
198
  for (const m of ms) {
197
- emit(m);
199
+ await emit(m);
198
200
  }
199
201
  }).catch(end);
200
202
  },
@@ -243,9 +245,7 @@ var send = async (client, spaceId, content) => {
243
245
  return synthSendResult();
244
246
  }
245
247
  default:
246
- throw new Error(
247
- `Unsupported iMessage local content type: ${content.type}`
248
- );
248
+ throw UnsupportedError.content(content.type, "iMessage (local mode)");
249
249
  }
250
250
  };
251
251
 
@@ -380,6 +380,9 @@ var ensureM4a = async (buffer, mimeType) => {
380
380
  };
381
381
 
382
382
  // src/providers/imessage/remote.ts
383
+ var PLATFORM = "iMessage";
384
+ var URL_BALLOON_BUNDLE_ID = "com.apple.messages.URLBalloonProvider";
385
+ var unsupportedContent = (type) => UnsupportedError.content(type, PLATFORM);
383
386
  var toSendResult = (receipt) => ({
384
387
  id: receipt.guid,
385
388
  timestamp: /* @__PURE__ */ new Date()
@@ -423,9 +426,29 @@ var toVCardContent2 = async (client, info) => {
423
426
  return toAttachmentContent2(client, info);
424
427
  }
425
428
  };
429
+ var getBalloonBundleId = (message) => {
430
+ const raw = message._raw;
431
+ const id = raw?.balloonBundleId;
432
+ return typeof id === "string" ? id : void 0;
433
+ };
434
+ var toRichlinkMessage = (event, base, id) => {
435
+ const url = event.message.text ?? "";
436
+ try {
437
+ return { ...base, id, content: asRichlink({ url }) };
438
+ } catch {
439
+ return {
440
+ ...base,
441
+ id,
442
+ content: url ? asText(url) : asCustom(event.message)
443
+ };
444
+ }
445
+ };
426
446
  var toMessages2 = async (client, event) => {
427
447
  const base = baseMessage(event);
428
448
  const messageGuidStr = event.message.guid;
449
+ if (getBalloonBundleId(event.message) === URL_BALLOON_BUNDLE_ID) {
450
+ return [toRichlinkMessage(event, base, messageGuidStr)];
451
+ }
429
452
  if (event.message.attachments.length > 0) {
430
453
  return Promise.all(
431
454
  event.message.attachments.map(async (info) => ({
@@ -447,14 +470,14 @@ var toMessages2 = async (client, event) => {
447
470
  var clientStream = (client) => {
448
471
  const sub = client.messages.subscribe("message.received");
449
472
  return stream((emit, end) => {
450
- (async () => {
473
+ const pump = (async () => {
451
474
  try {
452
475
  for await (const event of sub) {
453
476
  if (event.message.isFromMe) {
454
477
  continue;
455
478
  }
456
479
  for (const message of await toMessages2(client, event)) {
457
- emit(message);
480
+ await emit(message);
458
481
  }
459
482
  }
460
483
  end();
@@ -462,7 +485,10 @@ var clientStream = (client) => {
462
485
  end(e);
463
486
  }
464
487
  })();
465
- return () => sub.close();
488
+ return async () => {
489
+ sub.close();
490
+ await pump;
491
+ };
466
492
  });
467
493
  };
468
494
  var sendVCardAttachment = (remote, name, vcf) => remote.attachments.upload({
@@ -503,6 +529,10 @@ var send2 = async (clients, spaceId, content) => {
503
529
  switch (content.type) {
504
530
  case "text":
505
531
  return toSendResult(await remote.messages.send(chat, content.text));
532
+ case "richlink":
533
+ return toSendResult(
534
+ await remote.messages.send(chat, content.url, { richLink: true })
535
+ );
506
536
  case "attachment": {
507
537
  const attachment = await remote.attachments.upload({
508
538
  data: await content.read(),
@@ -537,7 +567,7 @@ var send2 = async (clients, spaceId, content) => {
537
567
  );
538
568
  }
539
569
  default:
540
- throw new Error(`Unsupported iMessage content type: ${content.type}`);
570
+ throw unsupportedContent(content.type);
541
571
  }
542
572
  };
543
573
  var replyToMessage = async (clients, spaceId, msgId, content) => {
@@ -552,6 +582,13 @@ var replyToMessage = async (clients, spaceId, msgId, content) => {
552
582
  return toSendResult(
553
583
  await remote.messages.send(chat, content.text, { replyTo })
554
584
  );
585
+ case "richlink":
586
+ return toSendResult(
587
+ await remote.messages.send(chat, content.url, {
588
+ richLink: true,
589
+ replyTo
590
+ })
591
+ );
555
592
  case "attachment": {
556
593
  const attachment = await remote.attachments.upload({
557
594
  data: await content.read(),
@@ -590,12 +627,16 @@ var replyToMessage = async (clients, spaceId, msgId, content) => {
590
627
  );
591
628
  }
592
629
  default:
593
- throw new Error(`Unsupported iMessage content type: ${content.type}`);
630
+ throw unsupportedContent(content.type);
594
631
  }
595
632
  };
596
633
  var editMessage = async (clients, spaceId, msgId, content) => {
597
634
  if (content.type !== "text") {
598
- throw new Error("iMessage only supports editing text content");
635
+ throw UnsupportedError.content(
636
+ content.type,
637
+ PLATFORM,
638
+ "only text content can be edited"
639
+ );
599
640
  }
600
641
  const remote = clients[0];
601
642
  if (!remote) {
@@ -659,8 +700,10 @@ var imessage = definePlatform("iMessage", {
659
700
  schema: spaceSchema,
660
701
  resolve: async ({ input, client }) => {
661
702
  if (isLocal(client)) {
662
- throw new Error(
663
- "Space creation is not supported in local mode. Local mode only supports replying to messages."
703
+ throw UnsupportedError.action(
704
+ "createSpace",
705
+ "iMessage (local mode)",
706
+ "local mode only supports replying to existing messages"
664
707
  );
665
708
  }
666
709
  if (input.users.length === 0) {
@@ -742,17 +785,13 @@ var imessage = definePlatform("iMessage", {
742
785
  },
743
786
  replyToMessage: async ({ space, messageId, content, client }) => {
744
787
  if (isLocal(client)) {
745
- throw new Error(
746
- "iMessage local mode does not support replying to messages"
747
- );
788
+ throw UnsupportedError.action("reply", "iMessage (local mode)");
748
789
  }
749
790
  return await replyToMessage(client, space.id, messageId, content);
750
791
  },
751
792
  editMessage: async ({ space, messageId, content, client }) => {
752
793
  if (isLocal(client)) {
753
- throw new Error(
754
- "iMessage local mode does not support editing messages"
755
- );
794
+ throw UnsupportedError.action("edit", "iMessage (local mode)");
756
795
  }
757
796
  await editMessage(client, space.id, messageId, content);
758
797
  }
@@ -1,4 +1,4 @@
1
- import { d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DZMHfgYQ.js';
1
+ import { d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DLrsDzV-.js';
2
2
  import * as node_readline from 'node:readline';
3
3
  import z__default from 'zod';
4
4
  import 'hotscript';
@@ -1,6 +1,7 @@
1
1
  import {
2
+ UnsupportedError,
2
3
  definePlatform
3
- } from "../../chunk-XZTTLPHE.js";
4
+ } from "../../chunk-4O6MQC5Z.js";
4
5
 
5
6
  // src/providers/terminal/index.ts
6
7
  import { createInterface } from "readline";
@@ -50,9 +51,7 @@ var terminal = definePlatform("terminal", {
50
51
  actions: {
51
52
  send: async ({ content }) => {
52
53
  if (content.type !== "text") {
53
- throw new Error(
54
- `Terminal provider only supports text content, got "${content.type}"`
55
- );
54
+ throw UnsupportedError.content(content.type, "terminal");
56
55
  }
57
56
  console.log(content.text);
58
57
  return { id: crypto.randomUUID(), timestamp: /* @__PURE__ */ new Date() };
@@ -1,24 +1,25 @@
1
- import { M as ManagedStream } from '../../stream-DGy4geUK.js';
1
+ import { M as ManagedStream } from '../../stream-B55k7W8-.js';
2
+ import { WhatsAppClient } from '@photon-ai/whatsapp-business';
2
3
  import * as z from 'zod';
3
4
  import z__default from 'zod';
4
- import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DZMHfgYQ.js';
5
+ import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-DLrsDzV-.js';
5
6
  import * as zod_v4_core from 'zod/v4/core';
6
- import { WhatsAppClient } from '@photon-ai/whatsapp-business';
7
7
  import 'hotscript';
8
8
 
9
+ type WhatsAppClients = WhatsAppClient[];
9
10
  declare const userSchema: z__default.ZodObject<{}, z__default.core.$strip>;
10
11
  declare const spaceSchema: z__default.ZodObject<{
11
12
  id: z__default.ZodString;
12
13
  }, z__default.core.$strip>;
13
14
  type WhatsAppMessage = SchemaMessage<typeof userSchema, typeof spaceSchema>;
14
15
 
15
- declare const whatsappBusiness: Platform<PlatformDef<"WhatsApp Business", z.ZodObject<{
16
+ declare const whatsappBusiness: Platform<PlatformDef<"WhatsApp Business", z.ZodUnion<readonly [z.ZodObject<{
16
17
  accessToken: z.ZodString;
17
- phoneNumberId: z.ZodString;
18
18
  appSecret: z.ZodOptional<z.ZodString>;
19
- }, zod_v4_core.$strip>, z.ZodType<object, unknown, zod_v4_core.$ZodTypeInternals<object, unknown>> | undefined, z.ZodObject<{
19
+ phoneNumberId: z.ZodString;
20
+ }, zod_v4_core.$strip>, z.ZodObject<{}, zod_v4_core.$strict>]>, z.ZodType<object, unknown, zod_v4_core.$ZodTypeInternals<object, unknown>> | undefined, z.ZodObject<{
20
21
  id: z.ZodString;
21
- }, zod_v4_core.$strip>, z.ZodType<object, unknown, zod_v4_core.$ZodTypeInternals<object, unknown>> | undefined, WhatsAppClient, {
22
+ }, zod_v4_core.$strip>, z.ZodType<object, unknown, zod_v4_core.$ZodTypeInternals<object, unknown>> | undefined, WhatsAppClients, {
22
23
  id: string;
23
24
  }, {
24
25
  id: string;
@@ -28,12 +29,12 @@ declare const whatsappBusiness: Platform<PlatformDef<"WhatsApp Business", z.ZodO
28
29
  id: string;
29
30
  }, Record<never, never>>, {
30
31
  messages: ({ client }: {
31
- client: WhatsAppClient;
32
+ client: WhatsAppClients;
32
33
  config: {
33
34
  accessToken: string;
34
35
  phoneNumberId: string;
35
36
  appSecret?: string | undefined;
36
- };
37
+ } | Record<string, never>;
37
38
  }) => ManagedStream<WhatsAppMessage>;
38
39
  }>> & Readonly<Record<never, never>>;
39
40