@spectrum-ts/core 7.0.0 → 8.1.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.
@@ -1,6 +1,6 @@
1
1
  import z from "zod";
2
- import vCard from "vcf";
3
2
  import { LogLevel } from "@photon-ai/otel";
3
+ import vCard from "vcf";
4
4
 
5
5
  //#region src/content/app.d.ts
6
6
  /**
@@ -447,12 +447,6 @@ interface Message<TPlatform extends string = string, TSender extends User = User
447
447
  declare const editSchema: z.ZodObject<{
448
448
  type: z.ZodLiteral<"edit">;
449
449
  content: z.ZodCustom<{
450
- type: "text";
451
- text: string;
452
- } | {
453
- type: "markdown";
454
- markdown: string;
455
- } | {
456
450
  type: "attachment";
457
451
  id: string;
458
452
  name: string;
@@ -507,19 +501,11 @@ declare const editSchema: z.ZodObject<{
507
501
  type: "custom";
508
502
  raw: unknown;
509
503
  } | {
510
- type: "reaction";
511
- emoji: string;
512
- target: Message<string, User, Space<unknown>>;
504
+ type: "text";
505
+ text: string;
513
506
  } | {
514
- type: "richlink";
515
- url: string;
516
- title: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
517
- summary: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
518
- cover: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
519
- mimeType: z.ZodOptional<z.ZodString>;
520
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
521
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
522
- }, z.core.$strip>>>>;
507
+ type: "markdown";
508
+ markdown: string;
523
509
  } | {
524
510
  type: "group";
525
511
  items: Message<string, User, Space<unknown>>[];
@@ -543,6 +529,13 @@ declare const editSchema: z.ZodObject<{
543
529
  };
544
530
  selected: boolean;
545
531
  title: string;
532
+ } | {
533
+ type: "reaction";
534
+ emoji: string;
535
+ target: Message<string, User, Space<unknown>>;
536
+ } | {
537
+ type: "richlink";
538
+ url: string;
546
539
  } | {
547
540
  type: "voice";
548
541
  mimeType: string;
@@ -571,12 +564,6 @@ declare const editSchema: z.ZodObject<{
571
564
  } | {
572
565
  type: "effect";
573
566
  content: {
574
- type: "text";
575
- text: string;
576
- } | {
577
- type: "markdown";
578
- markdown: string;
579
- } | {
580
567
  type: "attachment";
581
568
  id: string;
582
569
  name: string;
@@ -584,6 +571,12 @@ declare const editSchema: z.ZodObject<{
584
571
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
585
572
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
586
573
  size?: number | undefined;
574
+ } | {
575
+ type: "text";
576
+ text: string;
577
+ } | {
578
+ type: "markdown";
579
+ markdown: string;
587
580
  };
588
581
  effect: string;
589
582
  } | {
@@ -602,12 +595,6 @@ declare const editSchema: z.ZodObject<{
602
595
  kind: "clear";
603
596
  };
604
597
  }, {
605
- type: "text";
606
- text: string;
607
- } | {
608
- type: "markdown";
609
- markdown: string;
610
- } | {
611
598
  type: "attachment";
612
599
  id: string;
613
600
  name: string;
@@ -662,19 +649,11 @@ declare const editSchema: z.ZodObject<{
662
649
  type: "custom";
663
650
  raw: unknown;
664
651
  } | {
665
- type: "reaction";
666
- emoji: string;
667
- target: Message<string, User, Space<unknown>>;
652
+ type: "text";
653
+ text: string;
668
654
  } | {
669
- type: "richlink";
670
- url: string;
671
- title: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
672
- summary: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
673
- cover: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
674
- mimeType: z.ZodOptional<z.ZodString>;
675
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
676
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
677
- }, z.core.$strip>>>>;
655
+ type: "markdown";
656
+ markdown: string;
678
657
  } | {
679
658
  type: "group";
680
659
  items: Message<string, User, Space<unknown>>[];
@@ -698,6 +677,13 @@ declare const editSchema: z.ZodObject<{
698
677
  };
699
678
  selected: boolean;
700
679
  title: string;
680
+ } | {
681
+ type: "reaction";
682
+ emoji: string;
683
+ target: Message<string, User, Space<unknown>>;
684
+ } | {
685
+ type: "richlink";
686
+ url: string;
701
687
  } | {
702
688
  type: "voice";
703
689
  mimeType: string;
@@ -726,12 +712,6 @@ declare const editSchema: z.ZodObject<{
726
712
  } | {
727
713
  type: "effect";
728
714
  content: {
729
- type: "text";
730
- text: string;
731
- } | {
732
- type: "markdown";
733
- markdown: string;
734
- } | {
735
715
  type: "attachment";
736
716
  id: string;
737
717
  name: string;
@@ -739,6 +719,12 @@ declare const editSchema: z.ZodObject<{
739
719
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
740
720
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
741
721
  size?: number | undefined;
722
+ } | {
723
+ type: "text";
724
+ text: string;
725
+ } | {
726
+ type: "markdown";
727
+ markdown: string;
742
728
  };
743
729
  effect: string;
744
730
  } | {
@@ -982,12 +968,6 @@ declare function rename(displayName: string): ContentBuilder;
982
968
  declare const replySchema: z.ZodObject<{
983
969
  type: z.ZodLiteral<"reply">;
984
970
  content: z.ZodCustom<{
985
- type: "text";
986
- text: string;
987
- } | {
988
- type: "markdown";
989
- markdown: string;
990
- } | {
991
971
  type: "attachment";
992
972
  id: string;
993
973
  name: string;
@@ -1042,19 +1022,11 @@ declare const replySchema: z.ZodObject<{
1042
1022
  type: "custom";
1043
1023
  raw: unknown;
1044
1024
  } | {
1045
- type: "reaction";
1046
- emoji: string;
1047
- target: Message<string, User, Space<unknown>>;
1025
+ type: "text";
1026
+ text: string;
1048
1027
  } | {
1049
- type: "richlink";
1050
- url: string;
1051
- title: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
1052
- summary: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
1053
- cover: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
1054
- mimeType: z.ZodOptional<z.ZodString>;
1055
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1056
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1057
- }, z.core.$strip>>>>;
1028
+ type: "markdown";
1029
+ markdown: string;
1058
1030
  } | {
1059
1031
  type: "group";
1060
1032
  items: Message<string, User, Space<unknown>>[];
@@ -1078,6 +1050,13 @@ declare const replySchema: z.ZodObject<{
1078
1050
  };
1079
1051
  selected: boolean;
1080
1052
  title: string;
1053
+ } | {
1054
+ type: "reaction";
1055
+ emoji: string;
1056
+ target: Message<string, User, Space<unknown>>;
1057
+ } | {
1058
+ type: "richlink";
1059
+ url: string;
1081
1060
  } | {
1082
1061
  type: "voice";
1083
1062
  mimeType: string;
@@ -1106,12 +1085,6 @@ declare const replySchema: z.ZodObject<{
1106
1085
  } | {
1107
1086
  type: "effect";
1108
1087
  content: {
1109
- type: "text";
1110
- text: string;
1111
- } | {
1112
- type: "markdown";
1113
- markdown: string;
1114
- } | {
1115
1088
  type: "attachment";
1116
1089
  id: string;
1117
1090
  name: string;
@@ -1119,6 +1092,12 @@ declare const replySchema: z.ZodObject<{
1119
1092
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1120
1093
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1121
1094
  size?: number | undefined;
1095
+ } | {
1096
+ type: "text";
1097
+ text: string;
1098
+ } | {
1099
+ type: "markdown";
1100
+ markdown: string;
1122
1101
  };
1123
1102
  effect: string;
1124
1103
  } | {
@@ -1137,12 +1116,6 @@ declare const replySchema: z.ZodObject<{
1137
1116
  kind: "clear";
1138
1117
  };
1139
1118
  }, {
1140
- type: "text";
1141
- text: string;
1142
- } | {
1143
- type: "markdown";
1144
- markdown: string;
1145
- } | {
1146
1119
  type: "attachment";
1147
1120
  id: string;
1148
1121
  name: string;
@@ -1197,19 +1170,11 @@ declare const replySchema: z.ZodObject<{
1197
1170
  type: "custom";
1198
1171
  raw: unknown;
1199
1172
  } | {
1200
- type: "reaction";
1201
- emoji: string;
1202
- target: Message<string, User, Space<unknown>>;
1173
+ type: "text";
1174
+ text: string;
1203
1175
  } | {
1204
- type: "richlink";
1205
- url: string;
1206
- title: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
1207
- summary: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
1208
- cover: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
1209
- mimeType: z.ZodOptional<z.ZodString>;
1210
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1211
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1212
- }, z.core.$strip>>>>;
1176
+ type: "markdown";
1177
+ markdown: string;
1213
1178
  } | {
1214
1179
  type: "group";
1215
1180
  items: Message<string, User, Space<unknown>>[];
@@ -1233,6 +1198,13 @@ declare const replySchema: z.ZodObject<{
1233
1198
  };
1234
1199
  selected: boolean;
1235
1200
  title: string;
1201
+ } | {
1202
+ type: "reaction";
1203
+ emoji: string;
1204
+ target: Message<string, User, Space<unknown>>;
1205
+ } | {
1206
+ type: "richlink";
1207
+ url: string;
1236
1208
  } | {
1237
1209
  type: "voice";
1238
1210
  mimeType: string;
@@ -1261,12 +1233,6 @@ declare const replySchema: z.ZodObject<{
1261
1233
  } | {
1262
1234
  type: "effect";
1263
1235
  content: {
1264
- type: "text";
1265
- text: string;
1266
- } | {
1267
- type: "markdown";
1268
- markdown: string;
1269
- } | {
1270
1236
  type: "attachment";
1271
1237
  id: string;
1272
1238
  name: string;
@@ -1274,6 +1240,12 @@ declare const replySchema: z.ZodObject<{
1274
1240
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1275
1241
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1276
1242
  size?: number | undefined;
1243
+ } | {
1244
+ type: "text";
1245
+ text: string;
1246
+ } | {
1247
+ type: "markdown";
1248
+ markdown: string;
1277
1249
  };
1278
1250
  effect: string;
1279
1251
  } | {
@@ -1301,28 +1273,21 @@ declare function reply(content: ContentInput, target: Message | undefined): Cont
1301
1273
  declare const resolveContents: (items: readonly ContentInput[]) => Promise<Content[]>;
1302
1274
  //#endregion
1303
1275
  //#region src/content/richlink.d.ts
1276
+ /**
1277
+ * A URL the platform should render as a rich link preview.
1278
+ *
1279
+ * Outbound-only by design: inbound messages always surface as `text` content —
1280
+ * a URL received from a platform arrives as plain text, never as `richlink`, so
1281
+ * no metadata is fetched on the inbound path. On outbound, each platform asks
1282
+ * its native client to render the preview (remote iMessage: `enableLinkPreview`;
1283
+ * Telegram: auto-unfurls the bare URL), so the framework carries only the URL
1284
+ * and fetches nothing itself.
1285
+ */
1304
1286
  declare const richlinkSchema: z.ZodObject<{
1305
1287
  type: z.ZodLiteral<"richlink">;
1306
1288
  url: z.ZodURL;
1307
- title: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
1308
- summary: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
1309
- cover: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
1310
- mimeType: z.ZodOptional<z.ZodString>;
1311
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1312
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1313
- }, z.core.$strip>>>>;
1314
1289
  }, z.core.$strip>;
1315
1290
  type Richlink = z.infer<typeof richlinkSchema>;
1316
- /**
1317
- * Construct a `richlink` content value.
1318
- *
1319
- * Accessors (`title`, `summary`, `cover`) are async and lazy: the first call
1320
- * issues a single network request to the URL; subsequent calls share the
1321
- * cached result. Network / parse failures resolve to `undefined` and are
1322
- * cached — no retries. Callers who only need `title` / `summary` never
1323
- * trigger an image download; calling `cover.read()` triggers one additional
1324
- * request to fetch the image bytes.
1325
- */
1326
1291
  declare const asRichlink: (input: {
1327
1292
  url: string;
1328
1293
  }) => Richlink;
@@ -6807,13 +6772,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
6807
6772
  }, z.core.$strip>, z.ZodObject<{
6808
6773
  type: z.ZodLiteral<"richlink">;
6809
6774
  url: z.ZodURL;
6810
- title: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
6811
- summary: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
6812
- cover: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
6813
- mimeType: z.ZodOptional<z.ZodString>;
6814
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
6815
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
6816
- }, z.core.$strip>>>>;
6817
6775
  }, z.core.$strip>, z.ZodObject<{
6818
6776
  type: z.ZodLiteral<"app">;
6819
6777
  url: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -6893,12 +6851,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
6893
6851
  }, z.core.$strip>, z.ZodObject<{
6894
6852
  type: z.ZodLiteral<"reply">;
6895
6853
  content: z.ZodCustom<{
6896
- type: "text";
6897
- text: string;
6898
- } | {
6899
- type: "markdown";
6900
- markdown: string;
6901
- } | {
6902
6854
  type: "attachment";
6903
6855
  id: string;
6904
6856
  name: string;
@@ -6953,19 +6905,11 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
6953
6905
  type: "custom";
6954
6906
  raw: unknown;
6955
6907
  } | {
6956
- type: "reaction";
6957
- emoji: string;
6958
- target: Message<string, User, Space<unknown>>;
6908
+ type: "text";
6909
+ text: string;
6959
6910
  } | {
6960
- type: "richlink";
6961
- url: string;
6962
- title: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
6963
- summary: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
6964
- cover: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
6965
- mimeType: z.ZodOptional<z.ZodString>;
6966
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
6967
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
6968
- }, z.core.$strip>>>>;
6911
+ type: "markdown";
6912
+ markdown: string;
6969
6913
  } | {
6970
6914
  type: "group";
6971
6915
  items: Message<string, User, Space<unknown>>[];
@@ -6989,6 +6933,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
6989
6933
  };
6990
6934
  selected: boolean;
6991
6935
  title: string;
6936
+ } | {
6937
+ type: "reaction";
6938
+ emoji: string;
6939
+ target: Message<string, User, Space<unknown>>;
6940
+ } | {
6941
+ type: "richlink";
6942
+ url: string;
6992
6943
  } | {
6993
6944
  type: "voice";
6994
6945
  mimeType: string;
@@ -7017,12 +6968,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7017
6968
  } | {
7018
6969
  type: "effect";
7019
6970
  content: {
7020
- type: "text";
7021
- text: string;
7022
- } | {
7023
- type: "markdown";
7024
- markdown: string;
7025
- } | {
7026
6971
  type: "attachment";
7027
6972
  id: string;
7028
6973
  name: string;
@@ -7030,6 +6975,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7030
6975
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7031
6976
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7032
6977
  size?: number | undefined;
6978
+ } | {
6979
+ type: "text";
6980
+ text: string;
6981
+ } | {
6982
+ type: "markdown";
6983
+ markdown: string;
7033
6984
  };
7034
6985
  effect: string;
7035
6986
  } | {
@@ -7048,12 +6999,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7048
6999
  kind: "clear";
7049
7000
  };
7050
7001
  }, {
7051
- type: "text";
7052
- text: string;
7053
- } | {
7054
- type: "markdown";
7055
- markdown: string;
7056
- } | {
7057
7002
  type: "attachment";
7058
7003
  id: string;
7059
7004
  name: string;
@@ -7108,19 +7053,11 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7108
7053
  type: "custom";
7109
7054
  raw: unknown;
7110
7055
  } | {
7111
- type: "reaction";
7112
- emoji: string;
7113
- target: Message<string, User, Space<unknown>>;
7056
+ type: "text";
7057
+ text: string;
7114
7058
  } | {
7115
- type: "richlink";
7116
- url: string;
7117
- title: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
7118
- summary: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
7119
- cover: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
7120
- mimeType: z.ZodOptional<z.ZodString>;
7121
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7122
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7123
- }, z.core.$strip>>>>;
7059
+ type: "markdown";
7060
+ markdown: string;
7124
7061
  } | {
7125
7062
  type: "group";
7126
7063
  items: Message<string, User, Space<unknown>>[];
@@ -7144,6 +7081,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7144
7081
  };
7145
7082
  selected: boolean;
7146
7083
  title: string;
7084
+ } | {
7085
+ type: "reaction";
7086
+ emoji: string;
7087
+ target: Message<string, User, Space<unknown>>;
7088
+ } | {
7089
+ type: "richlink";
7090
+ url: string;
7147
7091
  } | {
7148
7092
  type: "voice";
7149
7093
  mimeType: string;
@@ -7172,12 +7116,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7172
7116
  } | {
7173
7117
  type: "effect";
7174
7118
  content: {
7175
- type: "text";
7176
- text: string;
7177
- } | {
7178
- type: "markdown";
7179
- markdown: string;
7180
- } | {
7181
7119
  type: "attachment";
7182
7120
  id: string;
7183
7121
  name: string;
@@ -7185,6 +7123,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7185
7123
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7186
7124
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7187
7125
  size?: number | undefined;
7126
+ } | {
7127
+ type: "text";
7128
+ text: string;
7129
+ } | {
7130
+ type: "markdown";
7131
+ markdown: string;
7188
7132
  };
7189
7133
  effect: string;
7190
7134
  } | {
@@ -7207,12 +7151,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7207
7151
  }, z.core.$strip>, z.ZodObject<{
7208
7152
  type: z.ZodLiteral<"edit">;
7209
7153
  content: z.ZodCustom<{
7210
- type: "text";
7211
- text: string;
7212
- } | {
7213
- type: "markdown";
7214
- markdown: string;
7215
- } | {
7216
7154
  type: "attachment";
7217
7155
  id: string;
7218
7156
  name: string;
@@ -7267,19 +7205,11 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7267
7205
  type: "custom";
7268
7206
  raw: unknown;
7269
7207
  } | {
7270
- type: "reaction";
7271
- emoji: string;
7272
- target: Message<string, User, Space<unknown>>;
7208
+ type: "text";
7209
+ text: string;
7273
7210
  } | {
7274
- type: "richlink";
7275
- url: string;
7276
- title: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
7277
- summary: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
7278
- cover: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
7279
- mimeType: z.ZodOptional<z.ZodString>;
7280
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7281
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7282
- }, z.core.$strip>>>>;
7211
+ type: "markdown";
7212
+ markdown: string;
7283
7213
  } | {
7284
7214
  type: "group";
7285
7215
  items: Message<string, User, Space<unknown>>[];
@@ -7303,6 +7233,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7303
7233
  };
7304
7234
  selected: boolean;
7305
7235
  title: string;
7236
+ } | {
7237
+ type: "reaction";
7238
+ emoji: string;
7239
+ target: Message<string, User, Space<unknown>>;
7240
+ } | {
7241
+ type: "richlink";
7242
+ url: string;
7306
7243
  } | {
7307
7244
  type: "voice";
7308
7245
  mimeType: string;
@@ -7331,12 +7268,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7331
7268
  } | {
7332
7269
  type: "effect";
7333
7270
  content: {
7334
- type: "text";
7335
- text: string;
7336
- } | {
7337
- type: "markdown";
7338
- markdown: string;
7339
- } | {
7340
7271
  type: "attachment";
7341
7272
  id: string;
7342
7273
  name: string;
@@ -7344,6 +7275,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7344
7275
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7345
7276
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7346
7277
  size?: number | undefined;
7278
+ } | {
7279
+ type: "text";
7280
+ text: string;
7281
+ } | {
7282
+ type: "markdown";
7283
+ markdown: string;
7347
7284
  };
7348
7285
  effect: string;
7349
7286
  } | {
@@ -7362,12 +7299,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7362
7299
  kind: "clear";
7363
7300
  };
7364
7301
  }, {
7365
- type: "text";
7366
- text: string;
7367
- } | {
7368
- type: "markdown";
7369
- markdown: string;
7370
- } | {
7371
7302
  type: "attachment";
7372
7303
  id: string;
7373
7304
  name: string;
@@ -7422,19 +7353,11 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7422
7353
  type: "custom";
7423
7354
  raw: unknown;
7424
7355
  } | {
7425
- type: "reaction";
7426
- emoji: string;
7427
- target: Message<string, User, Space<unknown>>;
7356
+ type: "text";
7357
+ text: string;
7428
7358
  } | {
7429
- type: "richlink";
7430
- url: string;
7431
- title: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
7432
- summary: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodString>>>;
7433
- cover: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodOptional<z.ZodObject<{
7434
- mimeType: z.ZodOptional<z.ZodString>;
7435
- read: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7436
- stream: z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7437
- }, z.core.$strip>>>>;
7359
+ type: "markdown";
7360
+ markdown: string;
7438
7361
  } | {
7439
7362
  type: "group";
7440
7363
  items: Message<string, User, Space<unknown>>[];
@@ -7458,6 +7381,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7458
7381
  };
7459
7382
  selected: boolean;
7460
7383
  title: string;
7384
+ } | {
7385
+ type: "reaction";
7386
+ emoji: string;
7387
+ target: Message<string, User, Space<unknown>>;
7388
+ } | {
7389
+ type: "richlink";
7390
+ url: string;
7461
7391
  } | {
7462
7392
  type: "voice";
7463
7393
  mimeType: string;
@@ -7486,12 +7416,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7486
7416
  } | {
7487
7417
  type: "effect";
7488
7418
  content: {
7489
- type: "text";
7490
- text: string;
7491
- } | {
7492
- type: "markdown";
7493
- markdown: string;
7494
- } | {
7495
7419
  type: "attachment";
7496
7420
  id: string;
7497
7421
  name: string;
@@ -7499,6 +7423,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7499
7423
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7500
7424
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7501
7425
  size?: number | undefined;
7426
+ } | {
7427
+ type: "text";
7428
+ text: string;
7429
+ } | {
7430
+ type: "markdown";
7431
+ markdown: string;
7502
7432
  };
7503
7433
  effect: string;
7504
7434
  } | {
@@ -1,6 +1,6 @@
1
- import { $t as groupSchema, Bt as asPollOption, Dn as buildPhotoAction, En as PhotoInput, H as ProviderMessageRecord, K as ManagedStream, Nt as asRead, On as photoActionSchema, St as asText, Tt as asRichlink, Wt as asMarkdown, Zt as asGroup, cn as reactionSchema, gt as asVoice, ln as asCustom, on as asReaction, r as asAttachment, yn as asContact, zt as asPoll } from "./attachment-BGIJLBk4.js";
1
+ import { $t as groupSchema, Bt as asPollOption, Dn as buildPhotoAction, En as PhotoInput, H as ProviderMessageRecord, K as ManagedStream, Nt as asRead, On as photoActionSchema, St as asText, Tt as asRichlink, Wt as asMarkdown, Zt as asGroup, cn as reactionSchema, gt as asVoice, ln as asCustom, on as asReaction, r as asAttachment, yn as asContact, zt as asPoll } from "./attachment-DSVZbNyn.js";
2
2
  import z from "zod";
3
- import { LogAttrs, LogAttrs as LogAttrs$1, LogLevel, PhotonLogger, createLogger, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, setLogLevel } from "@photon-ai/otel";
3
+ import { FetchSpanOptions, LogAttrs, LogAttrs as LogAttrs$1, LogLevel, PhotonLogger, SanitizeUrlOptions, createLogger, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl, setLogLevel } from "@photon-ai/otel";
4
4
  import { Token } from "marked";
5
5
 
6
6
  //#region src/content/effect.d.ts
@@ -30,6 +30,26 @@ declare const ensureM4a: (buffer: Buffer, mimeType: string) => Promise<{
30
30
  duration?: number;
31
31
  }>;
32
32
  //#endregion
33
+ //#region src/utils/instrumented-fetch.d.ts
34
+ /**
35
+ * Build a fetch that traces spectrum's OWN outbound HTTP: each request through
36
+ * the returned fetch emits a CLIENT span (tagged with `peer.service`) and
37
+ * carries W3C trace context downstream. It never mutates `globalThis.fetch`, so
38
+ * a consumer's unrelated requests stay untouched.
39
+ *
40
+ * The base delegates to `globalThis.fetch` at call time — deliberately NOT
41
+ * `createInstrumentedFetch(globalThis.fetch, …)`, which would capture the
42
+ * original and bypass a test's `spyOn(globalThis, "fetch")`. When telemetry is
43
+ * off (no `setupOtel`), the tracer is a no-op and this is a transparent
44
+ * pass-through. Create one per module: `const tf = tracedFetch("…")`.
45
+ *
46
+ * Pass `redactUrl` to strip secrets from a request URL before it is recorded as
47
+ * the span's `url.full` (e.g. a token in the path or query); the real request
48
+ * still uses the original URL. Pair with `sanitizeUrl` for semconv-style query
49
+ * redaction.
50
+ */
51
+ declare const tracedFetch: (peerService: string, options?: Pick<FetchSpanOptions, "ignore" | "redactUrl">) => typeof fetch;
52
+ //#endregion
33
53
  //#region src/utils/markdown.d.ts
34
54
  /**
35
55
  * Render a run of inline markdown tokens (a paragraph's or table cell's
@@ -103,4 +123,4 @@ declare const resumableOrderedStream: <TLive, TMissed, TOutput>(options: Resumab
103
123
  */
104
124
  declare function errorAttrs(error: unknown, prefix?: string): LogAttrs$1;
105
125
  //#endregion
106
- export { type CloseableAsyncIterable, type LogAttrs, type LogLevel, type PhotoInput, type PhotonLogger, type ProviderMessageRecord, type ResumableStreamItem, asAttachment, asContact, asCustom, asGroup, asMarkdown, asPoll, asPollOption, asReaction, asRead, asRichlink, asText, asVoice, buildPhotoAction, createLogger, ensureM4a, errorAttrs, groupSchema, messageEffectSchema, photoActionSchema, reactionSchema, renderInlineTokens, resumableOrderedStream, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, setLogLevel };
126
+ export { type CloseableAsyncIterable, type LogAttrs, type LogLevel, type PhotoInput, type PhotonLogger, type ProviderMessageRecord, type ResumableStreamItem, type SanitizeUrlOptions, asAttachment, asContact, asCustom, asGroup, asMarkdown, asPoll, asPollOption, asReaction, asRead, asRichlink, asText, asVoice, buildPhotoAction, createLogger, ensureM4a, errorAttrs, groupSchema, messageEffectSchema, photoActionSchema, reactionSchema, renderInlineTokens, resumableOrderedStream, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl, setLogLevel, tracedFetch };
package/dist/authoring.js CHANGED
@@ -1,8 +1,8 @@
1
- import { D as asGroup, E as markdownSchema, H as buildPhotoAction, I as asCustom, K as attachmentSchema, N as textSchema, R as asContact, U as photoActionSchema, W as asAttachment, _ as asReaction, b as asPoll, d as asVoice, h as asRead, i as stream, j as asText, k as groupSchema, l as renderInlineTokens, o as errorAttrs, p as asRichlink, w as asMarkdown, x as asPollOption, y as reactionSchema } from "./stream-BLWs7NJ5.js";
1
+ import { D as asGroup, E as markdownSchema, H as buildPhotoAction, I as asCustom, J as tracedFetch, K as attachmentSchema, N as textSchema, R as asContact, U as photoActionSchema, W as asAttachment, _ as asReaction, b as asPoll, d as asVoice, h as asRead, i as stream, j as asText, k as groupSchema, l as renderInlineTokens, o as errorAttrs, p as asRichlink, w as asMarkdown, x as asPollOption, y as reactionSchema } from "./stream-Cs0NMbNv.js";
2
2
  import z from "zod";
3
+ import { createLogger, createLogger as createLogger$1, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl, setLogLevel } from "@photon-ai/otel";
3
4
  import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
4
5
  import { join } from "node:path";
5
- import { createLogger, createLogger as createLogger$1, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, setLogLevel } from "@photon-ai/otel";
6
6
  import { spawn } from "node:child_process";
7
7
  import { tmpdir } from "node:os";
8
8
  //#region src/content/effect.ts
@@ -422,4 +422,4 @@ const resumableOrderedStream = (options) => stream((emit, end) => {
422
422
  };
423
423
  });
424
424
  //#endregion
425
- export { asAttachment, asContact, asCustom, asGroup, asMarkdown, asPoll, asPollOption, asReaction, asRead, asRichlink, asText, asVoice, buildPhotoAction, createLogger, ensureM4a, errorAttrs, groupSchema, messageEffectSchema, photoActionSchema, reactionSchema, renderInlineTokens, resumableOrderedStream, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, setLogLevel };
425
+ export { asAttachment, asContact, asCustom, asGroup, asMarkdown, asPoll, asPollOption, asReaction, asRead, asRichlink, asText, asVoice, buildPhotoAction, createLogger, ensureM4a, errorAttrs, groupSchema, messageEffectSchema, photoActionSchema, reactionSchema, renderInlineTokens, resumableOrderedStream, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl, setLogLevel, tracedFetch };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as FusorTokenData, A as isFusorEvent, An as AppLayout, At as Rename, B as PlatformUser, C as FusorVerify, Cn as Avatar, Ct as text, D as WebhookRawResult, Dt as resolveContents, E as WebhookRawRequest, Et as richlink, F as PlatformInstance, Ft as Poll, G as Broadcaster, Gt as markdown, Ht as poll, I as PlatformMessage, It as PollChoice, J as mergeStreams, Jt as StreamTextSource, K as ManagedStream, Kt as DeltaExtractor, L as PlatformProviderConfig, Lt as PollChoiceInput, M as EventProducer, Mn as app, Mt as Read, N as Platform, Nn as appLayoutSchema, O as FusorEvent, Ot as Reply, P as PlatformDef, Pt as read, Q as DedicatedTokenData, Qt as group, R as PlatformRuntime, Rt as PollOption, S as FusorRespond, Sn as User, T as WebhookHandler, Tn as avatar, U as SchemaMessage, Ut as Markdown, V as ProviderMessage, Vt as option, W as SpaceNamespace, X as Store, Xt as Group, Y as stream, Yt as TextStreamOptions, Z as CloudPlatform, _ as FusorClient, _n as ContactOrg, _t as voice, a as Content, an as ReactionBuilder, at as SharedTokenData, b as FusorMessagesReturn, bn as contact, bt as Typing, c as fromVCard, ct as SpectrumCloudError, d as UnsupportedKind, dn as Contact, dt as TokenData, en as Edit, et as ImessageInfoData, f as Spectrum, fn as ContactAddress, ft as cloud, g as isFusorClient, gn as ContactName, h as fusor, hn as ContactInput, ht as Voice, i as attachment, in as Reaction, it as ProjectProfile, j as AnyPlatformDef, jn as AppUrl, jt as rename, k as fusorEvent, kn as App, kt as reply, l as toVCard, lt as SubscriptionData, m as definePlatform, mn as ContactEmail, mt as EmojiKey, n as AttachmentInput, nn as Message, nt as PlatformsData, o as ContentBuilder, ot as SlackTeamMeta, p as SpectrumInstance, pn as ContactDetails, pt as Emoji, q as broadcast, qt as StreamText, rn as Space, rt as ProjectData, s as ContentInput, sn as reaction, st as SlackTokenData, t as Attachment, tn as edit, tt as PlatformStatus, u as UnsupportedError, un as custom, ut as SubscriptionStatus, v as FusorMessages, vn as ContactPhone, vt as Unsend, w as FusorVerifyRequest, wn as AvatarInput, wt as Richlink, x as FusorReply, xn as AgentSender, xt as typing, y as FusorMessagesCtx, yt as unsend, z as PlatformSpace } from "./attachment-BGIJLBk4.js";
1
+ import { $ as FusorTokenData, A as isFusorEvent, An as AppLayout, At as Rename, B as PlatformUser, C as FusorVerify, Cn as Avatar, Ct as text, D as WebhookRawResult, Dt as resolveContents, E as WebhookRawRequest, Et as richlink, F as PlatformInstance, Ft as Poll, G as Broadcaster, Gt as markdown, Ht as poll, I as PlatformMessage, It as PollChoice, J as mergeStreams, Jt as StreamTextSource, K as ManagedStream, Kt as DeltaExtractor, L as PlatformProviderConfig, Lt as PollChoiceInput, M as EventProducer, Mn as app, Mt as Read, N as Platform, Nn as appLayoutSchema, O as FusorEvent, Ot as Reply, P as PlatformDef, Pt as read, Q as DedicatedTokenData, Qt as group, R as PlatformRuntime, Rt as PollOption, S as FusorRespond, Sn as User, T as WebhookHandler, Tn as avatar, U as SchemaMessage, Ut as Markdown, V as ProviderMessage, Vt as option, W as SpaceNamespace, X as Store, Xt as Group, Y as stream, Yt as TextStreamOptions, Z as CloudPlatform, _ as FusorClient, _n as ContactOrg, _t as voice, a as Content, an as ReactionBuilder, at as SharedTokenData, b as FusorMessagesReturn, bn as contact, bt as Typing, c as fromVCard, ct as SpectrumCloudError, d as UnsupportedKind, dn as Contact, dt as TokenData, en as Edit, et as ImessageInfoData, f as Spectrum, fn as ContactAddress, ft as cloud, g as isFusorClient, gn as ContactName, h as fusor, hn as ContactInput, ht as Voice, i as attachment, in as Reaction, it as ProjectProfile, j as AnyPlatformDef, jn as AppUrl, jt as rename, k as fusorEvent, kn as App, kt as reply, l as toVCard, lt as SubscriptionData, m as definePlatform, mn as ContactEmail, mt as EmojiKey, n as AttachmentInput, nn as Message, nt as PlatformsData, o as ContentBuilder, ot as SlackTeamMeta, p as SpectrumInstance, pn as ContactDetails, pt as Emoji, q as broadcast, qt as StreamText, rn as Space, rt as ProjectData, s as ContentInput, sn as reaction, st as SlackTokenData, t as Attachment, tn as edit, tt as PlatformStatus, u as UnsupportedError, un as custom, ut as SubscriptionStatus, v as FusorMessages, vn as ContactPhone, vt as Unsend, w as FusorVerifyRequest, wn as AvatarInput, wt as Richlink, x as FusorReply, xn as AgentSender, xt as typing, y as FusorMessagesCtx, yt as unsend, z as PlatformSpace } from "./attachment-DSVZbNyn.js";
2
2
  export { type AgentSender, type AnyPlatformDef, type App, type AppLayout, type AppUrl, type Attachment, type AttachmentInput, type Avatar, type AvatarInput, type Broadcaster, type CloudPlatform, type Contact, type ContactAddress, type ContactDetails, type ContactEmail, type ContactInput, type ContactName, type ContactOrg, type ContactPhone, type Content, type ContentBuilder, type ContentInput, type DedicatedTokenData, type DeltaExtractor, type Edit, Emoji, type EmojiKey, type EventProducer, type FusorClient, type FusorEvent, type FusorMessages, type FusorMessagesCtx, type FusorMessagesReturn, type FusorReply, type FusorRespond, type FusorTokenData, type FusorVerify, type FusorVerifyRequest, type Group, type ImessageInfoData, type ManagedStream, type Markdown, type Message, type Platform, type PlatformDef, type PlatformInstance, type PlatformMessage, type PlatformProviderConfig, type PlatformRuntime, type PlatformSpace, type PlatformStatus, type PlatformUser, type PlatformsData, type Poll, type PollChoice, type PollChoiceInput, type PollOption, type ProjectData, type ProjectProfile, type ProviderMessage, type Reaction, type ReactionBuilder, type Read, type Rename, type Reply, type Richlink, type SchemaMessage, type SharedTokenData, type SlackTeamMeta, type SlackTokenData, type Space, type SpaceNamespace, Spectrum, SpectrumCloudError, type SpectrumInstance, type Store, type StreamText, type StreamTextSource, type SubscriptionData, type SubscriptionStatus, type TextStreamOptions, type TokenData, type Typing, type Unsend, UnsupportedError, type UnsupportedKind, type User, type Voice, type WebhookHandler, type WebhookRawRequest, type WebhookRawResult, app, appLayoutSchema, attachment, avatar, broadcast, cloud, contact, custom, definePlatform, edit, fromVCard, fusor, fusorEvent, group, isFusorClient, isFusorEvent, markdown, mergeStreams, option, poll, reaction, read, rename, reply, resolveContents, richlink, stream, text, toVCard, typing, unsend, voice };
package/dist/index.js CHANGED
@@ -1,8 +1,56 @@
1
- import { A as resolveContents, B as fromVCard, C as poll, F as drainStreamText, G as attachment, H as buildPhotoAction, I as asCustom, J as fetchLinkMetadata, L as custom, M as text, O as group, P as StreamConsumedError, R as asContact, S as option, T as markdown, U as photoActionSchema, V as toVCard, W as asAttachment, a as contentAttrs, c as markdownToPlainText, f as voice, g as read, i as stream, j as asText, m as richlink, n as createAsyncQueue, o as errorAttrs, p as asRichlink, q as fetchImage, r as mergeStreams, s as senderAttrs, t as broadcast, u as classifyIdentifier, v as reaction, w as asMarkdown, z as contact } from "./stream-BLWs7NJ5.js";
1
+ import { A as resolveContents, B as fromVCard, C as poll, F as drainStreamText, G as attachment, H as buildPhotoAction, I as asCustom, J as tracedFetch, L as custom, M as text, O as group, P as StreamConsumedError, R as asContact, S as option, T as markdown, U as photoActionSchema, V as toVCard, W as asAttachment, a as contentAttrs, c as markdownToPlainText, f as voice, g as read, i as stream, j as asText, m as richlink, n as createAsyncQueue, o as errorAttrs, q as fetchUrlBytes, r as mergeStreams, s as senderAttrs, t as broadcast, u as classifyIdentifier, v as reaction, w as asMarkdown, z as contact } from "./stream-Cs0NMbNv.js";
2
2
  import z from "zod";
3
- import { createHmac, timingSafeEqual } from "node:crypto";
3
+ import ogs from "open-graph-scraper";
4
4
  import { createLogger, setLogLevel, setupOtel, withSpan } from "@photon-ai/otel";
5
+ import { createHmac, timingSafeEqual } from "node:crypto";
5
6
  import { RawInboundEvent } from "@photon-ai/proto/photon/fusor/v1/inbound";
7
+ //#region src/utils/link-metadata.ts
8
+ const DEFAULT_TIMEOUT_MS = 5e3;
9
+ const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15 spectrum-ts/richlink";
10
+ const normaliseImageUrl = (raw, base) => {
11
+ try {
12
+ return new URL(raw, base).toString();
13
+ } catch {
14
+ return;
15
+ }
16
+ };
17
+ const cleanString = (v) => {
18
+ if (typeof v !== "string") return;
19
+ const trimmed = v.trim();
20
+ return trimmed.length > 0 ? trimmed : void 0;
21
+ };
22
+ const fetchLinkMetadata = async (url) => {
23
+ try {
24
+ const result = await ogs({
25
+ url,
26
+ timeout: DEFAULT_TIMEOUT_MS,
27
+ fetchOptions: { headers: { "User-Agent": USER_AGENT } }
28
+ });
29
+ if (result.error) return {};
30
+ const { ogTitle, ogDescription, ogImage, ogSiteName, twitterTitle, twitterDescription, twitterImage } = result.result;
31
+ const title = cleanString(ogTitle) ?? cleanString(twitterTitle);
32
+ const summary = cleanString(ogDescription) ?? cleanString(twitterDescription);
33
+ const siteName = cleanString(ogSiteName);
34
+ const imageCandidate = ogImage?.[0] ?? twitterImage?.[0];
35
+ const resolved = imageCandidate ? normaliseImageUrl(imageCandidate.url, url) : void 0;
36
+ return {
37
+ title,
38
+ summary,
39
+ siteName,
40
+ image: imageCandidate && resolved ? {
41
+ url: resolved,
42
+ mimeType: "type" in imageCandidate && typeof imageCandidate.type === "string" ? imageCandidate.type : void 0
43
+ } : void 0
44
+ };
45
+ } catch {
46
+ return {};
47
+ }
48
+ };
49
+ const fetchImage = (url) => fetchUrlBytes(new URL(url), {
50
+ timeoutMs: DEFAULT_TIMEOUT_MS,
51
+ headers: { "User-Agent": USER_AGENT }
52
+ });
53
+ //#endregion
6
54
  //#region src/content/app.ts
7
55
  /**
8
56
  * Visible layout of an app card. Mirrors Apple's `MSMessageTemplateLayout`
@@ -2994,7 +3042,7 @@ function definePlatform(name, rawDef) {
2994
3042
  }
2995
3043
  //#endregion
2996
3044
  //#region src/build-env.ts
2997
- const SPECTRUM_SDK_VERSION = "7.0.0";
3045
+ const SPECTRUM_SDK_VERSION = "8.1.0";
2998
3046
  //#endregion
2999
3047
  //#region src/utils/provider-packages.ts
3000
3048
  const OFFICIAL_PROVIDER_PACKAGES = {
@@ -3031,8 +3079,9 @@ var SpectrumCloudError = class extends Error {
3031
3079
  this.code = code;
3032
3080
  }
3033
3081
  };
3082
+ const cloudFetch = tracedFetch("spectrum-cloud");
3034
3083
  const request = async (path, init) => {
3035
- const response = await fetch(`${SPECTRUM_CLOUD_URL}${path}`, init);
3084
+ const response = await cloudFetch(`${SPECTRUM_CLOUD_URL}${path}`, init);
3036
3085
  if (!response.ok) {
3037
3086
  const body = await response.text().catch(() => "");
3038
3087
  try {
@@ -3744,7 +3793,10 @@ const mapContent = (content, platform, spaceRef, ctx) => {
3744
3793
  type: "text",
3745
3794
  text: asString(raw.text)
3746
3795
  };
3747
- case "richlink": return asRichlink({ url: asString(raw.url) });
3796
+ case "richlink": return {
3797
+ type: "text",
3798
+ text: asString(raw.url)
3799
+ };
3748
3800
  case "contact": return deserializeContact(raw);
3749
3801
  case "reaction": return deserializeReaction(raw, spaceRef);
3750
3802
  case "group": return deserializeGroup(raw, platform, spaceRef, ctx);
@@ -3984,7 +4036,9 @@ function bootstrapTelemetry(opts) {
3984
4036
  serviceVersion: SPECTRUM_SDK_VERSION,
3985
4037
  endpoint: PHOTON_OTEL_ENDPOINT,
3986
4038
  headers,
3987
- resourceAttributes
4039
+ resourceAttributes,
4040
+ instrumentFetch: false,
4041
+ register: false
3988
4042
  });
3989
4043
  }
3990
4044
  function applyLogLevel(level) {
@@ -1,5 +1,5 @@
1
1
  import z from "zod";
2
- import ogs from "open-graph-scraper";
2
+ import { createInstrumentedFetch, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl } from "@photon-ai/otel";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { createReadStream } from "node:fs";
5
5
  import { readFile, stat } from "node:fs/promises";
@@ -7,9 +7,31 @@ import { basename } from "node:path";
7
7
  import { Readable } from "node:stream";
8
8
  import { lookup } from "mime-types";
9
9
  import vCard from "vcf";
10
- import { sanitizeEmail, sanitizeErrorMessage, sanitizePhone } from "@photon-ai/otel";
11
10
  import { Marked } from "marked";
12
11
  import { Repeater } from "@repeaterjs/repeater";
12
+ //#region src/utils/instrumented-fetch.ts
13
+ /**
14
+ * Build a fetch that traces spectrum's OWN outbound HTTP: each request through
15
+ * the returned fetch emits a CLIENT span (tagged with `peer.service`) and
16
+ * carries W3C trace context downstream. It never mutates `globalThis.fetch`, so
17
+ * a consumer's unrelated requests stay untouched.
18
+ *
19
+ * The base delegates to `globalThis.fetch` at call time — deliberately NOT
20
+ * `createInstrumentedFetch(globalThis.fetch, …)`, which would capture the
21
+ * original and bypass a test's `spyOn(globalThis, "fetch")`. When telemetry is
22
+ * off (no `setupOtel`), the tracer is a no-op and this is a transparent
23
+ * pass-through. Create one per module: `const tf = tracedFetch("…")`.
24
+ *
25
+ * Pass `redactUrl` to strip secrets from a request URL before it is recorded as
26
+ * the span's `url.full` (e.g. a token in the path or query); the real request
27
+ * still uses the original URL. Pair with `sanitizeUrl` for semconv-style query
28
+ * redaction.
29
+ */
30
+ const tracedFetch = (peerService, options) => createInstrumentedFetch(((input, init) => globalThis.fetch(input, init)), {
31
+ attributes: { "peer.service": peerService },
32
+ ...options
33
+ });
34
+ //#endregion
13
35
  //#region src/utils/io.ts
14
36
  const readSchema$1 = z.function({
15
37
  input: [],
@@ -24,6 +46,7 @@ const bufferToStream = (buf) => new ReadableStream({ start(controller) {
24
46
  controller.close();
25
47
  } });
26
48
  const DEFAULT_FETCH_TIMEOUT_MS = 1e4;
49
+ const mediaFetch = tracedFetch("media", { redactUrl: sanitizeUrl });
27
50
  /**
28
51
  * Fetch URL bytes into memory — never touches the filesystem, so callers
29
52
  * remain safe in read-only environments. Returns the response's Content-Type
@@ -33,7 +56,7 @@ const fetchUrlBytes = async (url, options) => {
33
56
  const controller = new AbortController();
34
57
  const timer = setTimeout(() => controller.abort(), options?.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS);
35
58
  try {
36
- const res = await fetch(url, {
59
+ const res = await mediaFetch(url, {
37
60
  signal: controller.signal,
38
61
  headers: options?.headers
39
62
  });
@@ -47,53 +70,6 @@ const fetchUrlBytes = async (url, options) => {
47
70
  }
48
71
  };
49
72
  //#endregion
50
- //#region src/utils/link-metadata.ts
51
- const DEFAULT_TIMEOUT_MS = 5e3;
52
- const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15 spectrum-ts/richlink";
53
- const normaliseImageUrl = (raw, base) => {
54
- try {
55
- return new URL(raw, base).toString();
56
- } catch {
57
- return;
58
- }
59
- };
60
- const cleanString = (v) => {
61
- if (typeof v !== "string") return;
62
- const trimmed = v.trim();
63
- return trimmed.length > 0 ? trimmed : void 0;
64
- };
65
- const fetchLinkMetadata = async (url) => {
66
- try {
67
- const result = await ogs({
68
- url,
69
- timeout: DEFAULT_TIMEOUT_MS,
70
- fetchOptions: { headers: { "User-Agent": USER_AGENT } }
71
- });
72
- if (result.error) return {};
73
- const { ogTitle, ogDescription, ogImage, ogSiteName, twitterTitle, twitterDescription, twitterImage } = result.result;
74
- const title = cleanString(ogTitle) ?? cleanString(twitterTitle);
75
- const summary = cleanString(ogDescription) ?? cleanString(twitterDescription);
76
- const siteName = cleanString(ogSiteName);
77
- const imageCandidate = ogImage?.[0] ?? twitterImage?.[0];
78
- const resolved = imageCandidate ? normaliseImageUrl(imageCandidate.url, url) : void 0;
79
- return {
80
- title,
81
- summary,
82
- siteName,
83
- image: imageCandidate && resolved ? {
84
- url: resolved,
85
- mimeType: "type" in imageCandidate && typeof imageCandidate.type === "string" ? imageCandidate.type : void 0
86
- } : void 0
87
- };
88
- } catch {
89
- return {};
90
- }
91
- };
92
- const fetchImage = (url) => fetchUrlBytes(new URL(url), {
93
- timeoutMs: DEFAULT_TIMEOUT_MS,
94
- headers: { "User-Agent": USER_AGENT }
95
- });
96
- //#endregion
97
73
  //#region src/content/attachment.ts
98
74
  const DEFAULT_ATTACHMENT_NAME = "attachment";
99
75
  const attachmentSchema = z.object({
@@ -916,67 +892,24 @@ function read(target) {
916
892
  }
917
893
  //#endregion
918
894
  //#region src/content/richlink.ts
919
- const richlinkCoverSchema = z.object({
920
- mimeType: z.string().min(1).optional(),
921
- read: readSchema$1,
922
- stream: streamSchema
923
- });
924
- const optionalStringAccessor = z.function({
925
- input: [],
926
- output: z.promise(z.string().min(1).optional())
927
- });
928
- const coverAccessor = z.function({
929
- input: [],
930
- output: z.promise(richlinkCoverSchema.optional())
931
- });
932
- const richlinkSchema = z.object({
933
- type: z.literal("richlink"),
934
- url: z.url(),
935
- title: optionalStringAccessor,
936
- summary: optionalStringAccessor,
937
- cover: coverAccessor
938
- });
939
- const memoize = (factory) => {
940
- let cached;
941
- return () => {
942
- cached ??= factory();
943
- return cached;
944
- };
945
- };
946
- const buildCover = (image) => {
947
- const read = memoize(() => fetchImage(image.url).then((r) => r.data).catch(() => Buffer.alloc(0)));
948
- return {
949
- mimeType: image.mimeType,
950
- read,
951
- stream: async () => bufferToStream(await read())
952
- };
953
- };
954
895
  /**
955
- * Construct a `richlink` content value.
896
+ * A URL the platform should render as a rich link preview.
956
897
  *
957
- * Accessors (`title`, `summary`, `cover`) are async and lazy: the first call
958
- * issues a single network request to the URL; subsequent calls share the
959
- * cached result. Network / parse failures resolve to `undefined` and are
960
- * cached no retries. Callers who only need `title` / `summary` never
961
- * trigger an image download; calling `cover.read()` triggers one additional
962
- * request to fetch the image bytes.
898
+ * Outbound-only by design: inbound messages always surface as `text` content
899
+ * a URL received from a platform arrives as plain text, never as `richlink`, so
900
+ * no metadata is fetched on the inbound path. On outbound, each platform asks
901
+ * its native client to render the preview (remote iMessage: `enableLinkPreview`;
902
+ * Telegram: auto-unfurls the bare URL), so the framework carries only the URL
903
+ * and fetches nothing itself.
963
904
  */
964
- const asRichlink = (input) => {
965
- const getMetadata = memoize(() => fetchLinkMetadata(input.url));
966
- const getCover = memoize(async () => {
967
- const { image } = await getMetadata();
968
- return image ? buildCover(image) : void 0;
969
- });
970
- const title = async () => (await getMetadata()).title;
971
- const summary = async () => (await getMetadata()).summary;
972
- return richlinkSchema.parse({
973
- type: "richlink",
974
- url: input.url,
975
- title,
976
- summary,
977
- cover: getCover
978
- });
979
- };
905
+ const richlinkSchema = z.object({
906
+ type: z.literal("richlink"),
907
+ url: z.url()
908
+ });
909
+ const asRichlink = (input) => richlinkSchema.parse({
910
+ type: "richlink",
911
+ url: input.url
912
+ });
980
913
  function richlink(url) {
981
914
  return { build: async () => asRichlink({ url }) };
982
915
  }
@@ -1486,4 +1419,4 @@ function broadcast(source) {
1486
1419
  };
1487
1420
  }
1488
1421
  //#endregion
1489
- export { resolveContents as A, fromVCard as B, poll as C, asGroup as D, markdownSchema as E, drainStreamText as F, attachment as G, buildPhotoAction as H, asCustom as I, fetchLinkMetadata as J, attachmentSchema as K, custom as L, text as M, textSchema as N, group as O, StreamConsumedError as P, asContact as R, option as S, markdown as T, photoActionSchema as U, toVCard as V, asAttachment as W, asReaction as _, contentAttrs as a, asPoll as b, markdownToPlainText as c, asVoice as d, voice as f, read as g, asRead as h, stream as i, asText as j, groupSchema as k, renderInlineTokens as l, richlink as m, createAsyncQueue as n, errorAttrs as o, asRichlink as p, fetchImage as q, mergeStreams as r, senderAttrs as s, broadcast as t, classifyIdentifier as u, reaction as v, asMarkdown as w, asPollOption as x, reactionSchema as y, contact as z };
1422
+ export { resolveContents as A, fromVCard as B, poll as C, asGroup as D, markdownSchema as E, drainStreamText as F, attachment as G, buildPhotoAction as H, asCustom as I, tracedFetch as J, attachmentSchema as K, custom as L, text as M, textSchema as N, group as O, StreamConsumedError as P, asContact as R, option as S, markdown as T, photoActionSchema as U, toVCard as V, asAttachment as W, asReaction as _, contentAttrs as a, asPoll as b, markdownToPlainText as c, asVoice as d, voice as f, read as g, asRead as h, stream as i, asText as j, groupSchema as k, renderInlineTokens as l, richlink as m, createAsyncQueue as n, errorAttrs as o, asRichlink as p, fetchUrlBytes as q, mergeStreams as r, senderAttrs as s, broadcast as t, classifyIdentifier as u, reaction as v, asMarkdown as w, asPollOption as x, reactionSchema as y, contact as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectrum-ts/core",
3
- "version": "7.0.0",
3
+ "version": "8.1.0",
4
4
  "description": "The spectrum-ts runtime — Spectrum, content builders, fusor, and the provider authoring API.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -32,7 +32,7 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@photon-ai/otel": "^1.0.0",
35
+ "@photon-ai/otel": "^3.1.0",
36
36
  "@photon-ai/proto": "^0.2.4",
37
37
  "@repeaterjs/repeater": "^3.0.6",
38
38
  "marked": "^18.0.5",