@spectrum-ts/core 9.0.0 → 9.3.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.
@@ -37,6 +37,7 @@ declare const appSchema: z.ZodObject<{
37
37
  imageSubtitle: z.ZodOptional<z.ZodString>;
38
38
  summary: z.ZodOptional<z.ZodString>;
39
39
  }, z.core.$strip>>>;
40
+ live: z.ZodOptional<z.ZodBoolean>;
40
41
  }, z.core.$strip>;
41
42
  type App = z.infer<typeof appSchema>;
42
43
  /**
@@ -45,7 +46,18 @@ type App = z.infer<typeof appSchema>;
45
46
  * computed at send time (e.g. minting a signed link).
46
47
  */
47
48
  type AppUrl = string | Promise<string> | (() => string | Promise<string>);
48
- declare function app(url: AppUrl): ContentBuilder;
49
+ /** Optional rendering behavior for an app card. */
50
+ interface AppOptions {
51
+ /** Render the installed app extension's live UI when the platform supports it. */
52
+ live?: boolean;
53
+ }
54
+ /**
55
+ * Construct an app card from a URL.
56
+ *
57
+ * Pass `{ live: true }` to ask supported platforms to render the installed
58
+ * app extension's live UI. Other platforms retain their normal URL fallback.
59
+ */
60
+ declare function app(url: AppUrl, options?: AppOptions): ContentBuilder;
49
61
  //#endregion
50
62
  //#region src/utils/photo-content.d.ts
51
63
  /**
@@ -426,6 +438,16 @@ interface Space<_Def = unknown> {
426
438
  * no implementation.
427
439
  */
428
440
  getAvatar(): Promise<AvatarData | undefined>;
441
+ /**
442
+ * Read the current chat's display name (group/chat title). Resolves
443
+ * `undefined` when the chat has none — an unnamed group, or a 1:1 chat on a
444
+ * platform that stores no title for DMs. Round-trips into `space.rename()`.
445
+ *
446
+ * Universal API; unlike `rename` the read is not group-only. Per-platform
447
+ * constraints (e.g. iMessage: remote only) surface as `UnsupportedError`, as
448
+ * do platforms with no implementation.
449
+ */
450
+ getDisplayName(): Promise<string | undefined>;
429
451
  /**
430
452
  * List the chat's current participants, excluding the agent's own account
431
453
  * where the platform can identify it. Each entry is a `User` tagged with
@@ -570,6 +592,12 @@ interface Message<TPlatform extends string = string, TSender extends User = User
570
592
  declare const editSchema: z.ZodObject<{
571
593
  type: z.ZodLiteral<"edit">;
572
594
  content: z.ZodCustom<{
595
+ type: "text";
596
+ text: string;
597
+ } | {
598
+ type: "markdown";
599
+ markdown: string;
600
+ } | {
573
601
  type: "attachment";
574
602
  id: string;
575
603
  name: string;
@@ -620,18 +648,9 @@ declare const editSchema: z.ZodObject<{
620
648
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
621
649
  } | undefined;
622
650
  raw?: unknown;
623
- } | {
624
- type: "text";
625
- text: string;
626
- } | {
627
- type: "markdown";
628
- markdown: string;
629
651
  } | {
630
652
  type: "custom";
631
653
  raw: unknown;
632
- } | {
633
- type: "group";
634
- items: Message<string, User, Space<unknown>>[];
635
654
  } | {
636
655
  type: "poll";
637
656
  title: string;
@@ -652,13 +671,13 @@ declare const editSchema: z.ZodObject<{
652
671
  };
653
672
  selected: boolean;
654
673
  title: string;
674
+ } | {
675
+ type: "group";
676
+ items: Message<string, User, Space<unknown>>[];
655
677
  } | {
656
678
  type: "reaction";
657
679
  emoji: string;
658
680
  target: Message<string, User, Space<unknown>>;
659
- } | {
660
- type: "richlink";
661
- url: string;
662
681
  } | {
663
682
  type: "streamText";
664
683
  stream: () => AsyncIterable<string>;
@@ -671,6 +690,9 @@ declare const editSchema: z.ZodObject<{
671
690
  name?: string | undefined;
672
691
  duration?: number | undefined;
673
692
  size?: number | undefined;
693
+ } | {
694
+ type: "richlink";
695
+ url: string;
674
696
  } | {
675
697
  type: "app";
676
698
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -684,9 +706,16 @@ declare const editSchema: z.ZodObject<{
684
706
  imageSubtitle: z.ZodOptional<z.ZodString>;
685
707
  summary: z.ZodOptional<z.ZodString>;
686
708
  }, z.core.$strip>>>;
709
+ live?: boolean | undefined;
687
710
  } | {
688
711
  type: "effect";
689
712
  content: {
713
+ type: "text";
714
+ text: string;
715
+ } | {
716
+ type: "markdown";
717
+ markdown: string;
718
+ } | {
690
719
  type: "attachment";
691
720
  id: string;
692
721
  name: string;
@@ -694,12 +723,6 @@ declare const editSchema: z.ZodObject<{
694
723
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
695
724
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
696
725
  size?: number | undefined;
697
- } | {
698
- type: "text";
699
- text: string;
700
- } | {
701
- type: "markdown";
702
- markdown: string;
703
726
  };
704
727
  effect: string;
705
728
  } | {
@@ -726,6 +749,12 @@ declare const editSchema: z.ZodObject<{
726
749
  } | {
727
750
  type: "leaveSpace";
728
751
  }, {
752
+ type: "text";
753
+ text: string;
754
+ } | {
755
+ type: "markdown";
756
+ markdown: string;
757
+ } | {
729
758
  type: "attachment";
730
759
  id: string;
731
760
  name: string;
@@ -776,18 +805,9 @@ declare const editSchema: z.ZodObject<{
776
805
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
777
806
  } | undefined;
778
807
  raw?: unknown;
779
- } | {
780
- type: "text";
781
- text: string;
782
- } | {
783
- type: "markdown";
784
- markdown: string;
785
808
  } | {
786
809
  type: "custom";
787
810
  raw: unknown;
788
- } | {
789
- type: "group";
790
- items: Message<string, User, Space<unknown>>[];
791
811
  } | {
792
812
  type: "poll";
793
813
  title: string;
@@ -808,13 +828,13 @@ declare const editSchema: z.ZodObject<{
808
828
  };
809
829
  selected: boolean;
810
830
  title: string;
831
+ } | {
832
+ type: "group";
833
+ items: Message<string, User, Space<unknown>>[];
811
834
  } | {
812
835
  type: "reaction";
813
836
  emoji: string;
814
837
  target: Message<string, User, Space<unknown>>;
815
- } | {
816
- type: "richlink";
817
- url: string;
818
838
  } | {
819
839
  type: "streamText";
820
840
  stream: () => AsyncIterable<string>;
@@ -827,6 +847,9 @@ declare const editSchema: z.ZodObject<{
827
847
  name?: string | undefined;
828
848
  duration?: number | undefined;
829
849
  size?: number | undefined;
850
+ } | {
851
+ type: "richlink";
852
+ url: string;
830
853
  } | {
831
854
  type: "app";
832
855
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -840,9 +863,16 @@ declare const editSchema: z.ZodObject<{
840
863
  imageSubtitle: z.ZodOptional<z.ZodString>;
841
864
  summary: z.ZodOptional<z.ZodString>;
842
865
  }, z.core.$strip>>>;
866
+ live?: boolean | undefined;
843
867
  } | {
844
868
  type: "effect";
845
869
  content: {
870
+ type: "text";
871
+ text: string;
872
+ } | {
873
+ type: "markdown";
874
+ markdown: string;
875
+ } | {
846
876
  type: "attachment";
847
877
  id: string;
848
878
  name: string;
@@ -850,12 +880,6 @@ declare const editSchema: z.ZodObject<{
850
880
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
851
881
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
852
882
  size?: number | undefined;
853
- } | {
854
- type: "text";
855
- text: string;
856
- } | {
857
- type: "markdown";
858
- markdown: string;
859
883
  };
860
884
  effect: string;
861
885
  } | {
@@ -1112,6 +1136,12 @@ declare function rename(displayName: string): ContentBuilder;
1112
1136
  declare const replySchema: z.ZodObject<{
1113
1137
  type: z.ZodLiteral<"reply">;
1114
1138
  content: z.ZodCustom<{
1139
+ type: "text";
1140
+ text: string;
1141
+ } | {
1142
+ type: "markdown";
1143
+ markdown: string;
1144
+ } | {
1115
1145
  type: "attachment";
1116
1146
  id: string;
1117
1147
  name: string;
@@ -1162,18 +1192,9 @@ declare const replySchema: z.ZodObject<{
1162
1192
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1163
1193
  } | undefined;
1164
1194
  raw?: unknown;
1165
- } | {
1166
- type: "text";
1167
- text: string;
1168
- } | {
1169
- type: "markdown";
1170
- markdown: string;
1171
1195
  } | {
1172
1196
  type: "custom";
1173
1197
  raw: unknown;
1174
- } | {
1175
- type: "group";
1176
- items: Message<string, User, Space<unknown>>[];
1177
1198
  } | {
1178
1199
  type: "poll";
1179
1200
  title: string;
@@ -1194,13 +1215,13 @@ declare const replySchema: z.ZodObject<{
1194
1215
  };
1195
1216
  selected: boolean;
1196
1217
  title: string;
1218
+ } | {
1219
+ type: "group";
1220
+ items: Message<string, User, Space<unknown>>[];
1197
1221
  } | {
1198
1222
  type: "reaction";
1199
1223
  emoji: string;
1200
1224
  target: Message<string, User, Space<unknown>>;
1201
- } | {
1202
- type: "richlink";
1203
- url: string;
1204
1225
  } | {
1205
1226
  type: "streamText";
1206
1227
  stream: () => AsyncIterable<string>;
@@ -1213,6 +1234,9 @@ declare const replySchema: z.ZodObject<{
1213
1234
  name?: string | undefined;
1214
1235
  duration?: number | undefined;
1215
1236
  size?: number | undefined;
1237
+ } | {
1238
+ type: "richlink";
1239
+ url: string;
1216
1240
  } | {
1217
1241
  type: "app";
1218
1242
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -1226,9 +1250,16 @@ declare const replySchema: z.ZodObject<{
1226
1250
  imageSubtitle: z.ZodOptional<z.ZodString>;
1227
1251
  summary: z.ZodOptional<z.ZodString>;
1228
1252
  }, z.core.$strip>>>;
1253
+ live?: boolean | undefined;
1229
1254
  } | {
1230
1255
  type: "effect";
1231
1256
  content: {
1257
+ type: "text";
1258
+ text: string;
1259
+ } | {
1260
+ type: "markdown";
1261
+ markdown: string;
1262
+ } | {
1232
1263
  type: "attachment";
1233
1264
  id: string;
1234
1265
  name: string;
@@ -1236,12 +1267,6 @@ declare const replySchema: z.ZodObject<{
1236
1267
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1237
1268
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1238
1269
  size?: number | undefined;
1239
- } | {
1240
- type: "text";
1241
- text: string;
1242
- } | {
1243
- type: "markdown";
1244
- markdown: string;
1245
1270
  };
1246
1271
  effect: string;
1247
1272
  } | {
@@ -1268,6 +1293,12 @@ declare const replySchema: z.ZodObject<{
1268
1293
  } | {
1269
1294
  type: "leaveSpace";
1270
1295
  }, {
1296
+ type: "text";
1297
+ text: string;
1298
+ } | {
1299
+ type: "markdown";
1300
+ markdown: string;
1301
+ } | {
1271
1302
  type: "attachment";
1272
1303
  id: string;
1273
1304
  name: string;
@@ -1318,18 +1349,9 @@ declare const replySchema: z.ZodObject<{
1318
1349
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1319
1350
  } | undefined;
1320
1351
  raw?: unknown;
1321
- } | {
1322
- type: "text";
1323
- text: string;
1324
- } | {
1325
- type: "markdown";
1326
- markdown: string;
1327
1352
  } | {
1328
1353
  type: "custom";
1329
1354
  raw: unknown;
1330
- } | {
1331
- type: "group";
1332
- items: Message<string, User, Space<unknown>>[];
1333
1355
  } | {
1334
1356
  type: "poll";
1335
1357
  title: string;
@@ -1350,13 +1372,13 @@ declare const replySchema: z.ZodObject<{
1350
1372
  };
1351
1373
  selected: boolean;
1352
1374
  title: string;
1375
+ } | {
1376
+ type: "group";
1377
+ items: Message<string, User, Space<unknown>>[];
1353
1378
  } | {
1354
1379
  type: "reaction";
1355
1380
  emoji: string;
1356
1381
  target: Message<string, User, Space<unknown>>;
1357
- } | {
1358
- type: "richlink";
1359
- url: string;
1360
1382
  } | {
1361
1383
  type: "streamText";
1362
1384
  stream: () => AsyncIterable<string>;
@@ -1369,6 +1391,9 @@ declare const replySchema: z.ZodObject<{
1369
1391
  name?: string | undefined;
1370
1392
  duration?: number | undefined;
1371
1393
  size?: number | undefined;
1394
+ } | {
1395
+ type: "richlink";
1396
+ url: string;
1372
1397
  } | {
1373
1398
  type: "app";
1374
1399
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -1382,9 +1407,16 @@ declare const replySchema: z.ZodObject<{
1382
1407
  imageSubtitle: z.ZodOptional<z.ZodString>;
1383
1408
  summary: z.ZodOptional<z.ZodString>;
1384
1409
  }, z.core.$strip>>>;
1410
+ live?: boolean | undefined;
1385
1411
  } | {
1386
1412
  type: "effect";
1387
1413
  content: {
1414
+ type: "text";
1415
+ text: string;
1416
+ } | {
1417
+ type: "markdown";
1418
+ markdown: string;
1419
+ } | {
1388
1420
  type: "attachment";
1389
1421
  id: string;
1390
1422
  name: string;
@@ -1392,12 +1424,6 @@ declare const replySchema: z.ZodObject<{
1392
1424
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1393
1425
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1394
1426
  size?: number | undefined;
1395
- } | {
1396
- type: "text";
1397
- text: string;
1398
- } | {
1399
- type: "markdown";
1400
- markdown: string;
1401
1427
  };
1402
1428
  effect: string;
1403
1429
  } | {
@@ -6224,6 +6250,14 @@ interface PlatformWiseActions<_ResolvedSpace extends {
6224
6250
  id: string;
6225
6251
  __platform: string;
6226
6252
  }) => Promise<AvatarData | undefined>;
6253
+ getDisplayName: (ctx: {
6254
+ client: _Client;
6255
+ config: _Config;
6256
+ store: Store;
6257
+ }, space: _ResolvedSpace & {
6258
+ id: string;
6259
+ __platform: string;
6260
+ }) => Promise<string | undefined>;
6227
6261
  getMembers: (ctx: {
6228
6262
  client: _Client;
6229
6263
  config: _Config;
@@ -6605,6 +6639,7 @@ type ReservedInstanceKeys<Def extends AnyPlatformDef> = "user" | "space" | "mess
6605
6639
  type InstanceActionMethods<Def extends AnyPlatformDef> = { [K in Exclude<keyof InstanceActionFns<Def>, ReservedInstanceKeys<Def> | symbol | number>]: (...args: TailArgs<Parameters<InstanceActionFns<Def>[K]>>) => ReturnType<InstanceActionFns<Def>[K]> };
6606
6640
  interface PlatformWiseInstanceMethods<Def extends AnyPlatformDef> {
6607
6641
  getAvatar: (space: PlatformSpace<Def>) => Promise<AvatarData | undefined>;
6642
+ getDisplayName: (space: PlatformSpace<Def>) => Promise<string | undefined>;
6608
6643
  getMembers: (space: PlatformSpace<Def>) => Promise<PlatformUser<Def>[]>;
6609
6644
  getMessage: (space: PlatformSpace<Def>, messageId: string) => Promise<PlatformMessage<Def> | undefined>;
6610
6645
  }
@@ -6632,8 +6667,9 @@ interface SpectrumLike<Providers extends PlatformProviderConfig[] = PlatformProv
6632
6667
  };
6633
6668
  readonly __providers: Providers;
6634
6669
  }
6670
+ type ConfigInput<Def extends AnyPlatformDef> = z.input<Def["config"]> extends infer Input ? Input extends unknown ? { [K in keyof Input]?: Input[K] } : never : never;
6635
6671
  interface Platform<Def extends AnyPlatformDef> {
6636
- config(...args: Record<string, never> extends z.input<Def["config"]> ? [config?: z.input<Def["config"]>] : [config: z.input<Def["config"]>]): PlatformProviderConfig<Def>;
6672
+ config(...args: Record<string, never> extends ConfigInput<Def> ? [config?: ConfigInput<Def>] : [config: ConfigInput<Def>]): PlatformProviderConfig<Def>;
6637
6673
  is(input: Message): input is PlatformMessage<Def>;
6638
6674
  is(input: Space): input is PlatformSpace<Def>;
6639
6675
  is(input: unknown): input is PlatformMessage<Def> | PlatformSpace<Def>;
@@ -6985,6 +7021,7 @@ declare const baseContentSchema: z.ZodDiscriminatedUnion<readonly [z.ZodObject<{
6985
7021
  imageSubtitle: z.ZodOptional<z.ZodString>;
6986
7022
  summary: z.ZodOptional<z.ZodString>;
6987
7023
  }, z.core.$strip>>>;
7024
+ live: z.ZodOptional<z.ZodBoolean>;
6988
7025
  }, z.core.$strip>, z.ZodObject<{
6989
7026
  type: z.ZodLiteral<"reaction">;
6990
7027
  emoji: z.ZodString;
@@ -7162,6 +7199,7 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7162
7199
  imageSubtitle: z.ZodOptional<z.ZodString>;
7163
7200
  summary: z.ZodOptional<z.ZodString>;
7164
7201
  }, z.core.$strip>>>;
7202
+ live: z.ZodOptional<z.ZodBoolean>;
7165
7203
  }, z.core.$strip>, z.ZodObject<{
7166
7204
  type: z.ZodLiteral<"reaction">;
7167
7205
  emoji: z.ZodString;
@@ -7236,6 +7274,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7236
7274
  }, z.core.$strip>, z.ZodObject<{
7237
7275
  type: z.ZodLiteral<"reply">;
7238
7276
  content: z.ZodCustom<{
7277
+ type: "text";
7278
+ text: string;
7279
+ } | {
7280
+ type: "markdown";
7281
+ markdown: string;
7282
+ } | {
7239
7283
  type: "attachment";
7240
7284
  id: string;
7241
7285
  name: string;
@@ -7286,18 +7330,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7286
7330
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7287
7331
  } | undefined;
7288
7332
  raw?: unknown;
7289
- } | {
7290
- type: "text";
7291
- text: string;
7292
- } | {
7293
- type: "markdown";
7294
- markdown: string;
7295
7333
  } | {
7296
7334
  type: "custom";
7297
7335
  raw: unknown;
7298
- } | {
7299
- type: "group";
7300
- items: Message<string, User, Space<unknown>>[];
7301
7336
  } | {
7302
7337
  type: "poll";
7303
7338
  title: string;
@@ -7318,13 +7353,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7318
7353
  };
7319
7354
  selected: boolean;
7320
7355
  title: string;
7356
+ } | {
7357
+ type: "group";
7358
+ items: Message<string, User, Space<unknown>>[];
7321
7359
  } | {
7322
7360
  type: "reaction";
7323
7361
  emoji: string;
7324
7362
  target: Message<string, User, Space<unknown>>;
7325
- } | {
7326
- type: "richlink";
7327
- url: string;
7328
7363
  } | {
7329
7364
  type: "streamText";
7330
7365
  stream: () => AsyncIterable<string>;
@@ -7337,6 +7372,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7337
7372
  name?: string | undefined;
7338
7373
  duration?: number | undefined;
7339
7374
  size?: number | undefined;
7375
+ } | {
7376
+ type: "richlink";
7377
+ url: string;
7340
7378
  } | {
7341
7379
  type: "app";
7342
7380
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -7350,9 +7388,16 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7350
7388
  imageSubtitle: z.ZodOptional<z.ZodString>;
7351
7389
  summary: z.ZodOptional<z.ZodString>;
7352
7390
  }, z.core.$strip>>>;
7391
+ live?: boolean | undefined;
7353
7392
  } | {
7354
7393
  type: "effect";
7355
7394
  content: {
7395
+ type: "text";
7396
+ text: string;
7397
+ } | {
7398
+ type: "markdown";
7399
+ markdown: string;
7400
+ } | {
7356
7401
  type: "attachment";
7357
7402
  id: string;
7358
7403
  name: string;
@@ -7360,12 +7405,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7360
7405
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7361
7406
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7362
7407
  size?: number | undefined;
7363
- } | {
7364
- type: "text";
7365
- text: string;
7366
- } | {
7367
- type: "markdown";
7368
- markdown: string;
7369
7408
  };
7370
7409
  effect: string;
7371
7410
  } | {
@@ -7392,6 +7431,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7392
7431
  } | {
7393
7432
  type: "leaveSpace";
7394
7433
  }, {
7434
+ type: "text";
7435
+ text: string;
7436
+ } | {
7437
+ type: "markdown";
7438
+ markdown: string;
7439
+ } | {
7395
7440
  type: "attachment";
7396
7441
  id: string;
7397
7442
  name: string;
@@ -7442,18 +7487,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7442
7487
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7443
7488
  } | undefined;
7444
7489
  raw?: unknown;
7445
- } | {
7446
- type: "text";
7447
- text: string;
7448
- } | {
7449
- type: "markdown";
7450
- markdown: string;
7451
7490
  } | {
7452
7491
  type: "custom";
7453
7492
  raw: unknown;
7454
- } | {
7455
- type: "group";
7456
- items: Message<string, User, Space<unknown>>[];
7457
7493
  } | {
7458
7494
  type: "poll";
7459
7495
  title: string;
@@ -7474,13 +7510,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7474
7510
  };
7475
7511
  selected: boolean;
7476
7512
  title: string;
7513
+ } | {
7514
+ type: "group";
7515
+ items: Message<string, User, Space<unknown>>[];
7477
7516
  } | {
7478
7517
  type: "reaction";
7479
7518
  emoji: string;
7480
7519
  target: Message<string, User, Space<unknown>>;
7481
- } | {
7482
- type: "richlink";
7483
- url: string;
7484
7520
  } | {
7485
7521
  type: "streamText";
7486
7522
  stream: () => AsyncIterable<string>;
@@ -7493,6 +7529,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7493
7529
  name?: string | undefined;
7494
7530
  duration?: number | undefined;
7495
7531
  size?: number | undefined;
7532
+ } | {
7533
+ type: "richlink";
7534
+ url: string;
7496
7535
  } | {
7497
7536
  type: "app";
7498
7537
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -7506,9 +7545,16 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7506
7545
  imageSubtitle: z.ZodOptional<z.ZodString>;
7507
7546
  summary: z.ZodOptional<z.ZodString>;
7508
7547
  }, z.core.$strip>>>;
7548
+ live?: boolean | undefined;
7509
7549
  } | {
7510
7550
  type: "effect";
7511
7551
  content: {
7552
+ type: "text";
7553
+ text: string;
7554
+ } | {
7555
+ type: "markdown";
7556
+ markdown: string;
7557
+ } | {
7512
7558
  type: "attachment";
7513
7559
  id: string;
7514
7560
  name: string;
@@ -7516,12 +7562,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7516
7562
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7517
7563
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7518
7564
  size?: number | undefined;
7519
- } | {
7520
- type: "text";
7521
- text: string;
7522
- } | {
7523
- type: "markdown";
7524
- markdown: string;
7525
7565
  };
7526
7566
  effect: string;
7527
7567
  } | {
@@ -7552,6 +7592,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7552
7592
  }, z.core.$strip>, z.ZodObject<{
7553
7593
  type: z.ZodLiteral<"edit">;
7554
7594
  content: z.ZodCustom<{
7595
+ type: "text";
7596
+ text: string;
7597
+ } | {
7598
+ type: "markdown";
7599
+ markdown: string;
7600
+ } | {
7555
7601
  type: "attachment";
7556
7602
  id: string;
7557
7603
  name: string;
@@ -7602,18 +7648,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7602
7648
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7603
7649
  } | undefined;
7604
7650
  raw?: unknown;
7605
- } | {
7606
- type: "text";
7607
- text: string;
7608
- } | {
7609
- type: "markdown";
7610
- markdown: string;
7611
7651
  } | {
7612
7652
  type: "custom";
7613
7653
  raw: unknown;
7614
- } | {
7615
- type: "group";
7616
- items: Message<string, User, Space<unknown>>[];
7617
7654
  } | {
7618
7655
  type: "poll";
7619
7656
  title: string;
@@ -7634,13 +7671,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7634
7671
  };
7635
7672
  selected: boolean;
7636
7673
  title: string;
7674
+ } | {
7675
+ type: "group";
7676
+ items: Message<string, User, Space<unknown>>[];
7637
7677
  } | {
7638
7678
  type: "reaction";
7639
7679
  emoji: string;
7640
7680
  target: Message<string, User, Space<unknown>>;
7641
- } | {
7642
- type: "richlink";
7643
- url: string;
7644
7681
  } | {
7645
7682
  type: "streamText";
7646
7683
  stream: () => AsyncIterable<string>;
@@ -7653,6 +7690,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7653
7690
  name?: string | undefined;
7654
7691
  duration?: number | undefined;
7655
7692
  size?: number | undefined;
7693
+ } | {
7694
+ type: "richlink";
7695
+ url: string;
7656
7696
  } | {
7657
7697
  type: "app";
7658
7698
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -7666,9 +7706,16 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7666
7706
  imageSubtitle: z.ZodOptional<z.ZodString>;
7667
7707
  summary: z.ZodOptional<z.ZodString>;
7668
7708
  }, z.core.$strip>>>;
7709
+ live?: boolean | undefined;
7669
7710
  } | {
7670
7711
  type: "effect";
7671
7712
  content: {
7713
+ type: "text";
7714
+ text: string;
7715
+ } | {
7716
+ type: "markdown";
7717
+ markdown: string;
7718
+ } | {
7672
7719
  type: "attachment";
7673
7720
  id: string;
7674
7721
  name: string;
@@ -7676,12 +7723,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7676
7723
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7677
7724
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7678
7725
  size?: number | undefined;
7679
- } | {
7680
- type: "text";
7681
- text: string;
7682
- } | {
7683
- type: "markdown";
7684
- markdown: string;
7685
7726
  };
7686
7727
  effect: string;
7687
7728
  } | {
@@ -7708,6 +7749,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7708
7749
  } | {
7709
7750
  type: "leaveSpace";
7710
7751
  }, {
7752
+ type: "text";
7753
+ text: string;
7754
+ } | {
7755
+ type: "markdown";
7756
+ markdown: string;
7757
+ } | {
7711
7758
  type: "attachment";
7712
7759
  id: string;
7713
7760
  name: string;
@@ -7758,18 +7805,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7758
7805
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7759
7806
  } | undefined;
7760
7807
  raw?: unknown;
7761
- } | {
7762
- type: "text";
7763
- text: string;
7764
- } | {
7765
- type: "markdown";
7766
- markdown: string;
7767
7808
  } | {
7768
7809
  type: "custom";
7769
7810
  raw: unknown;
7770
- } | {
7771
- type: "group";
7772
- items: Message<string, User, Space<unknown>>[];
7773
7811
  } | {
7774
7812
  type: "poll";
7775
7813
  title: string;
@@ -7790,13 +7828,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7790
7828
  };
7791
7829
  selected: boolean;
7792
7830
  title: string;
7831
+ } | {
7832
+ type: "group";
7833
+ items: Message<string, User, Space<unknown>>[];
7793
7834
  } | {
7794
7835
  type: "reaction";
7795
7836
  emoji: string;
7796
7837
  target: Message<string, User, Space<unknown>>;
7797
- } | {
7798
- type: "richlink";
7799
- url: string;
7800
7838
  } | {
7801
7839
  type: "streamText";
7802
7840
  stream: () => AsyncIterable<string>;
@@ -7809,6 +7847,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7809
7847
  name?: string | undefined;
7810
7848
  duration?: number | undefined;
7811
7849
  size?: number | undefined;
7850
+ } | {
7851
+ type: "richlink";
7852
+ url: string;
7812
7853
  } | {
7813
7854
  type: "app";
7814
7855
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -7822,9 +7863,16 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7822
7863
  imageSubtitle: z.ZodOptional<z.ZodString>;
7823
7864
  summary: z.ZodOptional<z.ZodString>;
7824
7865
  }, z.core.$strip>>>;
7866
+ live?: boolean | undefined;
7825
7867
  } | {
7826
7868
  type: "effect";
7827
7869
  content: {
7870
+ type: "text";
7871
+ text: string;
7872
+ } | {
7873
+ type: "markdown";
7874
+ markdown: string;
7875
+ } | {
7828
7876
  type: "attachment";
7829
7877
  id: string;
7830
7878
  name: string;
@@ -7832,12 +7880,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7832
7880
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7833
7881
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7834
7882
  size?: number | undefined;
7835
- } | {
7836
- type: "text";
7837
- text: string;
7838
- } | {
7839
- type: "markdown";
7840
- markdown: string;
7841
7883
  };
7842
7884
  effect: string;
7843
7885
  } | {
@@ -7904,4 +7946,4 @@ declare function attachment(input: AttachmentInput, options?: {
7904
7946
  name?: string;
7905
7947
  }): ContentBuilder;
7906
7948
  //#endregion
7907
- export { DedicatedTokenData as $, TextStreamOptions as $t, isFusorEvent as A, ContactName as An, asReply as At, PlatformUser as B, avatar as Bn, PollChoice as Bt, FusorVerify as C, asCustom as Cn, asText as Ct, WebhookRawResult as D, ContactDetails as Dn, richlink as Dt, WebhookRawRequest as E, ContactAddress as En, asRichlink as Et, PlatformInstance as F, AgentSender as Fn, renameSchema as Ft, SpaceNamespace as G, App as Gn, option as Gt, ProviderMessageRecord as H, PhotoInput as Hn, PollOption as Ht, PlatformMessage as I, User as In, Read as It, broadcast as J, app as Jn, asMarkdown as Jt, Broadcaster as K, AppLayout as Kn, poll as Kt, PlatformProviderConfig as L, Avatar as Ln, asRead as Lt, EventProducer as M, ContactPhone as Mn, replySchema as Mt, Platform as N, asContact as Nn, Rename as Nt, FusorEvent as O, ContactEmail as On, resolveContents as Ot, PlatformDef as P, contact as Pn, rename as Pt, CloudPlatform as Q, StreamTextSource as Qt, PlatformRuntime as R, AvatarData as Rn, read as Rt, FusorRespond as S, reactionSchema as Sn, typing as St, WebhookHandler as T, Contact as Tn, Richlink as Tt, ProviderUserRecord as U, buildPhotoAction as Un, asPoll as Ut, ProviderMessage as V, avatarSchema as Vn, PollChoiceInput as Vt, SchemaMessage as W, photoActionSchema as Wn, asPollOption as Wt, stream as X, DeltaExtractor as Xt, mergeStreams as Y, appLayoutSchema as Yn, markdown as Yt, Store as Z, StreamText as Zt, FusorClient as _, removeMemberSchema as _n, asVoice as _t, Content as a, edit as an, ProjectProfile as at, FusorMessagesReturn as b, asReaction as bn, unsend as bt, fromVCard as c, AddMember as cn, SlackTokenData as ct, UnsupportedKind as d, RemoveMember as dn, SubscriptionStatus as dt, Group as en, FusorTokenData as et, Spectrum as f, addMember as fn, TokenData as ft, isFusorClient as g, removeMember as gn, Voice as gt, fusor as h, leaveSpaceSchema as hn, EmojiKey as ht, attachment as i, Edit as in, ProjectData as it, AnyPlatformDef as j, ContactOrg as jn, reply as jt, fusorEvent as k, ContactInput as kn, Reply as kt, toVCard as l, LeaveSpace as ln, SpectrumCloudError as lt, definePlatform as m, leaveSpace as mn, Emoji as mt, AttachmentInput as n, group as nn, PlatformStatus as nt, ContentBuilder as o, Message as on, SharedTokenData as ot, SpectrumInstance as p, addMemberSchema as pn, cloud as pt, ManagedStream as q, AppUrl as qn, Markdown as qt, asAttachment as r, groupSchema as rn, PlatformsData as rt, ContentInput as s, Space as sn, SlackTeamMeta as st, Attachment as t, asGroup as tn, ImessageInfoData as tt, UnsupportedError as u, MemberInput as un, SubscriptionData as ut, FusorMessages as v, Reaction as vn, voice as vt, FusorVerifyRequest as w, custom as wn, text as wt, FusorReply as x, reaction as xn, Typing as xt, FusorMessagesCtx as y, ReactionBuilder as yn, Unsend as yt, PlatformSpace as z, AvatarInput as zn, Poll as zt };
7949
+ export { DedicatedTokenData as $, TextStreamOptions as $t, isFusorEvent as A, ContactName as An, asReply as At, PlatformUser as B, avatar as Bn, PollChoice as Bt, FusorVerify as C, asCustom as Cn, asText as Ct, WebhookRawResult as D, ContactDetails as Dn, richlink as Dt, WebhookRawRequest as E, ContactAddress as En, asRichlink as Et, PlatformInstance as F, AgentSender as Fn, renameSchema as Ft, SpaceNamespace as G, App as Gn, option as Gt, ProviderMessageRecord as H, PhotoInput as Hn, PollOption as Ht, PlatformMessage as I, User as In, Read as It, broadcast as J, AppUrl as Jn, asMarkdown as Jt, Broadcaster as K, AppLayout as Kn, poll as Kt, PlatformProviderConfig as L, Avatar as Ln, asRead as Lt, EventProducer as M, ContactPhone as Mn, replySchema as Mt, Platform as N, asContact as Nn, Rename as Nt, FusorEvent as O, ContactEmail as On, resolveContents as Ot, PlatformDef as P, contact as Pn, rename as Pt, CloudPlatform as Q, StreamTextSource as Qt, PlatformRuntime as R, AvatarData as Rn, read as Rt, FusorRespond as S, reactionSchema as Sn, typing as St, WebhookHandler as T, Contact as Tn, Richlink as Tt, ProviderUserRecord as U, buildPhotoAction as Un, asPoll as Ut, ProviderMessage as V, avatarSchema as Vn, PollChoiceInput as Vt, SchemaMessage as W, photoActionSchema as Wn, asPollOption as Wt, stream as X, appLayoutSchema as Xn, DeltaExtractor as Xt, mergeStreams as Y, app as Yn, markdown as Yt, Store as Z, StreamText as Zt, FusorClient as _, removeMemberSchema as _n, asVoice as _t, Content as a, edit as an, ProjectProfile as at, FusorMessagesReturn as b, asReaction as bn, unsend as bt, fromVCard as c, AddMember as cn, SlackTokenData as ct, UnsupportedKind as d, RemoveMember as dn, SubscriptionStatus as dt, Group as en, FusorTokenData as et, Spectrum as f, addMember as fn, TokenData as ft, isFusorClient as g, removeMember as gn, Voice as gt, fusor as h, leaveSpaceSchema as hn, EmojiKey as ht, attachment as i, Edit as in, ProjectData as it, AnyPlatformDef as j, ContactOrg as jn, reply as jt, fusorEvent as k, ContactInput as kn, Reply as kt, toVCard as l, LeaveSpace as ln, SpectrumCloudError as lt, definePlatform as m, leaveSpace as mn, Emoji as mt, AttachmentInput as n, group as nn, PlatformStatus as nt, ContentBuilder as o, Message as on, SharedTokenData as ot, SpectrumInstance as p, addMemberSchema as pn, cloud as pt, ManagedStream as q, AppOptions as qn, Markdown as qt, asAttachment as r, groupSchema as rn, PlatformsData as rt, ContentInput as s, Space as sn, SlackTeamMeta as st, Attachment as t, asGroup as tn, ImessageInfoData as tt, UnsupportedError as u, MemberInput as un, SubscriptionData as ut, FusorMessages as v, Reaction as vn, voice as vt, FusorVerifyRequest as w, custom as wn, text as wt, FusorReply as x, reaction as xn, Typing as xt, FusorMessagesCtx as y, ReactionBuilder as yn, Unsend as yt, PlatformSpace as z, AvatarInput as zn, Poll as zt };
@@ -1,4 +1,4 @@
1
- import { At as asReply, Cn as asCustom, Ct as asText, Et as asRichlink, Ft as renameSchema, H as ProviderMessageRecord, Hn as PhotoInput, Jt as asMarkdown, Lt as asRead, Mt as replySchema, Nn as asContact, Sn as reactionSchema, U as ProviderUserRecord, Un as buildPhotoAction, Ut as asPoll, Vn as avatarSchema, Wn as photoActionSchema, Wt as asPollOption, _n as removeMemberSchema, _t as asVoice, bn as asReaction, hn as leaveSpaceSchema, pn as addMemberSchema, q as ManagedStream, r as asAttachment, rn as groupSchema, tn as asGroup } from "./attachment-Bn3rw5jW.js";
1
+ import { At as asReply, Cn as asCustom, Ct as asText, Et as asRichlink, Ft as renameSchema, H as ProviderMessageRecord, Hn as PhotoInput, Jt as asMarkdown, Lt as asRead, Mt as replySchema, Nn as asContact, Sn as reactionSchema, U as ProviderUserRecord, Un as buildPhotoAction, Ut as asPoll, Vn as avatarSchema, Wn as photoActionSchema, Wt as asPollOption, _n as removeMemberSchema, _t as asVoice, bn as asReaction, hn as leaveSpaceSchema, pn as addMemberSchema, q as ManagedStream, r as asAttachment, rn as groupSchema, tn as asGroup } from "./attachment-BpPKbxT1.js";
2
2
  import z from "zod";
3
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";
@@ -30,6 +30,61 @@ declare const ensureM4a: (buffer: Buffer, mimeType: string) => Promise<{
30
30
  duration?: number;
31
31
  }>;
32
32
  //#endregion
33
+ //#region src/utils/env.d.ts
34
+ /**
35
+ * Build a Spectrum config env-var name from a channel and a key, centralizing
36
+ * the `SPECTRUM_<CHANNEL>_<KEY>` convention so the prefix can't drift or be
37
+ * mistyped per field. Both segments are joined verbatim (callers pass them
38
+ * already upper-snake-cased), e.g. `envFor("TELEGRAM", "BOT_TOKEN")` →
39
+ * `"SPECTRUM_TELEGRAM_BOT_TOKEN"`.
40
+ */
41
+ declare const envFor: (channel: string, key: string) => string;
42
+ /**
43
+ * Wrap a config-field schema so it falls back to an environment variable when
44
+ * the field is omitted. Precedence is **explicit value > env var > the inner
45
+ * schema's own default/required check**:
46
+ *
47
+ * - An explicit value (anything other than `undefined`) is passed straight
48
+ * through — a caller-supplied config always wins over the environment.
49
+ * - When the field is `undefined`, `process.env[envKey]` is substituted. An
50
+ * env var set to the empty string is treated as unset (a common deploy
51
+ * footgun) so it doesn't satisfy a `.min(1)` by accident.
52
+ * - The inner `schema` then validates the resolved value, keeping its exact
53
+ * semantics — regex, `.min(1)`, `.url()`, `.optional()`, `.default(...)`.
54
+ * When both the field and the env var are absent, a required inner schema
55
+ * raises its normal "required" error.
56
+ *
57
+ * The output type is the inner schema's output type, so call sites are
58
+ * unchanged. Because substitution only happens on `undefined`, wrapping a
59
+ * field inside a `z.object` leaves it a plain key on the parsed result — union
60
+ * discriminators like `"accessToken" in config` keep working.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * botToken: fromEnv("SPECTRUM_TELEGRAM_BOT_TOKEN", z.string().regex(BOT_TOKEN_PATTERN)),
65
+ * ```
66
+ */
67
+ declare const fromEnv: <T extends z.ZodType>(envKey: string, schema: T) => z.ZodPreprocess<T>;
68
+ /**
69
+ * Rewrite a platform's config schema so every string-leaf field falls back to
70
+ * `SPECTRUM_<PLATFORM>_<KEY>` when omitted which is the equivalent of
71
+ * hand-wrapping each field with {@link fromEnv}. Called once by
72
+ * `definePlatform`, so adapters declare plain Zod and get env fallback for free.
73
+ *
74
+ * - **object**: each string-leaf field is wrapped with `fromEnv`; non-string
75
+ * fields (records, arrays, nested objects, booleans, numbers) are left as-is.
76
+ * The object is only reconstructed when a field actually changed, and
77
+ * `.strict()` is preserved so an empty strict "cloud" branch is untouched.
78
+ * - **union**: each option is rewritten independently, so an env value only
79
+ * satisfies the branch that declares that field (a direct/cloud union stays
80
+ * correctly discriminated).
81
+ * - anything else is returned unchanged.
82
+ *
83
+ * The output type is identical to the input schema's. Only omitted fields gain
84
+ * an env fallback which means that `z.infer` and downstream contexts are unaffected.
85
+ */
86
+ declare const envAwareConfig: <T extends z.ZodType>(name: string, schema: T) => T;
87
+ //#endregion
33
88
  //#region src/utils/instrumented-fetch.d.ts
34
89
  /**
35
90
  * Build a fetch that traces spectrum's OWN outbound HTTP: each request through
@@ -123,4 +178,4 @@ declare const resumableOrderedStream: <TLive, TMissed, TOutput>(options: Resumab
123
178
  */
124
179
  declare function errorAttrs(error: unknown, prefix?: string): LogAttrs$1;
125
180
  //#endregion
126
- export { type CloseableAsyncIterable, type LogAttrs, type LogLevel, type PhotoInput, type PhotonLogger, type ProviderMessageRecord, type ProviderUserRecord, type ResumableStreamItem, type SanitizeUrlOptions, addMemberSchema, asAttachment, asContact, asCustom, asGroup, asMarkdown, asPoll, asPollOption, asReaction, asRead, asReply, asRichlink, asText, asVoice, avatarSchema, buildPhotoAction, createLogger, ensureM4a, errorAttrs, groupSchema, leaveSpaceSchema, messageEffectSchema, photoActionSchema, reactionSchema, removeMemberSchema, renameSchema, renderInlineTokens, replySchema, resumableOrderedStream, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl, setLogLevel, tracedFetch };
181
+ export { type CloseableAsyncIterable, type LogAttrs, type LogLevel, type PhotoInput, type PhotonLogger, type ProviderMessageRecord, type ProviderUserRecord, type ResumableStreamItem, type SanitizeUrlOptions, addMemberSchema, asAttachment, asContact, asCustom, asGroup, asMarkdown, asPoll, asPollOption, asReaction, asRead, asReply, asRichlink, asText, asVoice, avatarSchema, buildPhotoAction, createLogger, ensureM4a, envAwareConfig, envFor, errorAttrs, fromEnv, groupSchema, leaveSpaceSchema, messageEffectSchema, photoActionSchema, reactionSchema, removeMemberSchema, renameSchema, renderInlineTokens, replySchema, resumableOrderedStream, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl, setLogLevel, tracedFetch };
package/dist/authoring.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as addMemberSchema, B as groupSchema, E as asPollOption, F as asMarkdown, H as asText, L as markdownSchema, M as leaveSpaceSchema, P as removeMemberSchema, R as asGroup, S as asReaction, T as asPoll, W as textSchema, Y as asContact, _ as replySchema, at as attachmentSchema, b as asRead, d as asVoice, et as avatarSchema, h as asReply, i as stream, l as renderInlineTokens, nt as photoActionSchema, o as errorAttrs, p as asRichlink, q as asCustom, rt as asAttachment, st as tracedFetch, tt as buildPhotoAction, w as reactionSchema, y as renameSchema } from "./stream-DxI5ZiE2.js";
1
+ import { B as markdownSchema, C as asRead, D as reactionSchema, F as leaveSpaceSchema, G as asText, L as removeMemberSchema, N as addMemberSchema, O as asPoll, Q as asContact, R as asMarkdown, S as renameSchema, T as asReaction, U as groupSchema, V as asGroup, X as asCustom, at as photoActionSchema, b as replySchema, ct as attachmentSchema, d as envAwareConfig, f as envFor, g as asRichlink, i as stream, it as buildPhotoAction, k as asPollOption, l as renderInlineTokens, m as asVoice, o as errorAttrs, ot as asAttachment, p as fromEnv, q as textSchema, rt as avatarSchema, ut as tracedFetch, v as asReply } from "./stream-DAfZ5DFR.js";
2
2
  import z from "zod";
3
3
  import { createLogger, createLogger as createLogger$1, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl, setLogLevel } from "@photon-ai/otel";
4
4
  import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
@@ -422,4 +422,4 @@ const resumableOrderedStream = (options) => stream((emit, end) => {
422
422
  };
423
423
  });
424
424
  //#endregion
425
- export { addMemberSchema, asAttachment, asContact, asCustom, asGroup, asMarkdown, asPoll, asPollOption, asReaction, asRead, asReply, asRichlink, asText, asVoice, avatarSchema, buildPhotoAction, createLogger, ensureM4a, errorAttrs, groupSchema, leaveSpaceSchema, messageEffectSchema, photoActionSchema, reactionSchema, removeMemberSchema, renameSchema, renderInlineTokens, replySchema, resumableOrderedStream, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl, setLogLevel, tracedFetch };
425
+ export { addMemberSchema, asAttachment, asContact, asCustom, asGroup, asMarkdown, asPoll, asPollOption, asReaction, asRead, asReply, asRichlink, asText, asVoice, avatarSchema, buildPhotoAction, createLogger, ensureM4a, envAwareConfig, envFor, errorAttrs, fromEnv, groupSchema, leaveSpaceSchema, messageEffectSchema, photoActionSchema, reactionSchema, removeMemberSchema, renameSchema, renderInlineTokens, replySchema, resumableOrderedStream, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, sanitizeUrl, setLogLevel, tracedFetch };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as DedicatedTokenData, $t as TextStreamOptions, A as isFusorEvent, An as ContactName, B as PlatformUser, Bn as avatar, Bt as PollChoice, C as FusorVerify, D as WebhookRawResult, Dn as ContactDetails, Dt as richlink, E as WebhookRawRequest, En as ContactAddress, F as PlatformInstance, Fn as AgentSender, G as SpaceNamespace, Gn as App, Gt as option, Ht as PollOption, I as PlatformMessage, In as User, It as Read, J as broadcast, Jn as app, K as Broadcaster, Kn as AppLayout, Kt as poll, L as PlatformProviderConfig, Ln as Avatar, M as EventProducer, Mn as ContactPhone, N as Platform, Nt as Rename, O as FusorEvent, On as ContactEmail, Ot as resolveContents, P as PlatformDef, Pn as contact, Pt as rename, Q as CloudPlatform, Qt as StreamTextSource, R as PlatformRuntime, Rn as AvatarData, Rt as read, S as FusorRespond, St as typing, T as WebhookHandler, Tn as Contact, Tt as Richlink, V as ProviderMessage, Vt as PollChoiceInput, W as SchemaMessage, X as stream, Xt as DeltaExtractor, Y as mergeStreams, Yn as appLayoutSchema, Yt as markdown, Z as Store, Zt as StreamText, _ as FusorClient, a as Content, an as edit, at as ProjectProfile, b as FusorMessagesReturn, bt as unsend, c as fromVCard, cn as AddMember, ct as SlackTokenData, d as UnsupportedKind, dn as RemoveMember, dt as SubscriptionStatus, en as Group, et as FusorTokenData, f as Spectrum, fn as addMember, ft as TokenData, g as isFusorClient, gn as removeMember, gt as Voice, h as fusor, ht as EmojiKey, i as attachment, in as Edit, it as ProjectData, j as AnyPlatformDef, jn as ContactOrg, jt as reply, k as fusorEvent, kn as ContactInput, kt as Reply, l as toVCard, ln as LeaveSpace, lt as SpectrumCloudError, m as definePlatform, mn as leaveSpace, mt as Emoji, n as AttachmentInput, nn as group, nt as PlatformStatus, o as ContentBuilder, on as Message, ot as SharedTokenData, p as SpectrumInstance, pt as cloud, q as ManagedStream, qn as AppUrl, qt as Markdown, rt as PlatformsData, s as ContentInput, sn as Space, st as SlackTeamMeta, t as Attachment, tt as ImessageInfoData, u as UnsupportedError, un as MemberInput, ut as SubscriptionData, v as FusorMessages, vn as Reaction, vt as voice, w as FusorVerifyRequest, wn as custom, wt as text, x as FusorReply, xn as reaction, xt as Typing, y as FusorMessagesCtx, yn as ReactionBuilder, yt as Unsend, z as PlatformSpace, zn as AvatarInput, zt as Poll } from "./attachment-Bn3rw5jW.js";
2
- export { type AddMember, type AgentSender, type AnyPlatformDef, type App, type AppLayout, type AppUrl, type Attachment, type AttachmentInput, type Avatar, type AvatarData, 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 LeaveSpace, type ManagedStream, type Markdown, type MemberInput, 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 RemoveMember, 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, addMember, app, appLayoutSchema, attachment, avatar, broadcast, cloud, contact, custom, definePlatform, edit, fromVCard, fusor, fusorEvent, group, isFusorClient, isFusorEvent, leaveSpace, markdown, mergeStreams, option, poll, reaction, read, removeMember, rename, reply, resolveContents, richlink, stream, text, toVCard, typing, unsend, voice };
1
+ import { $ as DedicatedTokenData, $t as TextStreamOptions, A as isFusorEvent, An as ContactName, B as PlatformUser, Bn as avatar, Bt as PollChoice, C as FusorVerify, D as WebhookRawResult, Dn as ContactDetails, Dt as richlink, E as WebhookRawRequest, En as ContactAddress, F as PlatformInstance, Fn as AgentSender, G as SpaceNamespace, Gn as App, Gt as option, Ht as PollOption, I as PlatformMessage, In as User, It as Read, J as broadcast, Jn as AppUrl, K as Broadcaster, Kn as AppLayout, Kt as poll, L as PlatformProviderConfig, Ln as Avatar, M as EventProducer, Mn as ContactPhone, N as Platform, Nt as Rename, O as FusorEvent, On as ContactEmail, Ot as resolveContents, P as PlatformDef, Pn as contact, Pt as rename, Q as CloudPlatform, Qt as StreamTextSource, R as PlatformRuntime, Rn as AvatarData, Rt as read, S as FusorRespond, St as typing, T as WebhookHandler, Tn as Contact, Tt as Richlink, V as ProviderMessage, Vt as PollChoiceInput, W as SchemaMessage, X as stream, Xn as appLayoutSchema, Xt as DeltaExtractor, Y as mergeStreams, Yn as app, Yt as markdown, Z as Store, Zt as StreamText, _ as FusorClient, a as Content, an as edit, at as ProjectProfile, b as FusorMessagesReturn, bt as unsend, c as fromVCard, cn as AddMember, ct as SlackTokenData, d as UnsupportedKind, dn as RemoveMember, dt as SubscriptionStatus, en as Group, et as FusorTokenData, f as Spectrum, fn as addMember, ft as TokenData, g as isFusorClient, gn as removeMember, gt as Voice, h as fusor, ht as EmojiKey, i as attachment, in as Edit, it as ProjectData, j as AnyPlatformDef, jn as ContactOrg, jt as reply, k as fusorEvent, kn as ContactInput, kt as Reply, l as toVCard, ln as LeaveSpace, lt as SpectrumCloudError, m as definePlatform, mn as leaveSpace, mt as Emoji, n as AttachmentInput, nn as group, nt as PlatformStatus, o as ContentBuilder, on as Message, ot as SharedTokenData, p as SpectrumInstance, pt as cloud, q as ManagedStream, qn as AppOptions, qt as Markdown, rt as PlatformsData, s as ContentInput, sn as Space, st as SlackTeamMeta, t as Attachment, tt as ImessageInfoData, u as UnsupportedError, un as MemberInput, ut as SubscriptionData, v as FusorMessages, vn as Reaction, vt as voice, w as FusorVerifyRequest, wn as custom, wt as text, x as FusorReply, xn as reaction, xt as Typing, y as FusorMessagesCtx, yn as ReactionBuilder, yt as Unsend, z as PlatformSpace, zn as AvatarInput, zt as Poll } from "./attachment-BpPKbxT1.js";
2
+ export { type AddMember, type AgentSender, type AnyPlatformDef, type App, type AppLayout, type AppOptions, type AppUrl, type Attachment, type AttachmentInput, type Avatar, type AvatarData, 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 LeaveSpace, type ManagedStream, type Markdown, type MemberInput, 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 RemoveMember, 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, addMember, app, appLayoutSchema, attachment, avatar, broadcast, cloud, contact, custom, definePlatform, edit, fromVCard, fusor, fusorEvent, group, isFusorClient, isFusorEvent, leaveSpace, markdown, mergeStreams, option, poll, reaction, read, removeMember, rename, reply, resolveContents, richlink, stream, text, toVCard, typing, unsend, voice };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as avatar, A as addMemberSchema, C as reaction, D as option, F as asMarkdown, G as StreamConsumedError, H as asText, I as markdown, J as custom, K as drainStreamText, M as leaveSpaceSchema, N as removeMember, O as poll, P as removeMemberSchema, Q as toVCard, U as text, V as resolveContents, X as contact, Y as asContact, Z as fromVCard, a as contentAttrs, c as markdownToPlainText, et as avatarSchema, f as voice, g as reply, i as stream, it as attachment, j as leaveSpace, k as addMember, m as richlink, n as createAsyncQueue, o as errorAttrs, ot as fetchUrlBytes, q as asCustom, r as mergeStreams, rt as asAttachment, s as senderAttrs, st as tracedFetch, t as broadcast, u as classifyIdentifier, v as rename, x as read, y as renameSchema, z as group } from "./stream-DxI5ZiE2.js";
1
+ import { $ as contact, A as option, E as reaction, F as leaveSpaceSchema, G as asText, H as group, I as removeMember, J as StreamConsumedError, K as text, L as removeMemberSchema, M as addMember, N as addMemberSchema, P as leaveSpace, Q as asContact, R as asMarkdown, S as renameSchema, W as resolveContents, X as asCustom, Y as drainStreamText, Z as custom, _ as richlink, a as contentAttrs, c as markdownToPlainText, d as envAwareConfig, et as fromVCard, f as envFor, h as voice, i as stream, j as poll, lt as fetchUrlBytes, n as createAsyncQueue, nt as avatar, o as errorAttrs, ot as asAttachment, r as mergeStreams, rt as avatarSchema, s as senderAttrs, st as attachment, t as broadcast, tt as toVCard, u as classifyIdentifier, ut as tracedFetch, w as read, x as rename, y as reply, z as markdown } from "./stream-DAfZ5DFR.js";
2
2
  import z from "zod";
3
3
  import ogs from "open-graph-scraper";
4
4
  import { createLogger, setLogLevel, setupOtel, withSpan } from "@photon-ai/otel";
@@ -89,7 +89,8 @@ const layoutAccessor = z.function({
89
89
  const appSchema = z.object({
90
90
  type: z.literal("app"),
91
91
  url: urlAccessor,
92
- layout: layoutAccessor
92
+ layout: layoutAccessor,
93
+ live: z.boolean().optional()
93
94
  });
94
95
  const memoize = (factory) => {
95
96
  let cached;
@@ -136,7 +137,7 @@ const buildLayout = (metadata, url, image) => {
136
137
  * across `url()` / `layout()`; fetch / parse failures resolve to a host-only
137
138
  * caption (no throw, no retry).
138
139
  */
139
- const asApp = (url) => {
140
+ const asApp = (url, options = {}) => {
140
141
  const getUrl = resolveUrl(url);
141
142
  const getMetadata = memoize(async () => fetchLinkMetadata(await getUrl()));
142
143
  const getLayout = memoize(async () => {
@@ -154,11 +155,18 @@ const asApp = (url) => {
154
155
  return appSchema.parse({
155
156
  type: "app",
156
157
  url: getUrl,
157
- layout: getLayout
158
+ layout: getLayout,
159
+ ...options
158
160
  });
159
161
  };
160
- function app(url) {
161
- return { build: async () => asApp(url) };
162
+ /**
163
+ * Construct an app card from a URL.
164
+ *
165
+ * Pass `{ live: true }` to ask supported platforms to render the installed
166
+ * app extension's live UI. Other platforms retain their normal URL fallback.
167
+ */
168
+ function app(url, options = {}) {
169
+ return { build: async () => asApp(url, options) };
162
170
  }
163
171
  //#endregion
164
172
  //#region src/content/edit.ts
@@ -2313,6 +2321,7 @@ const RESERVED_SPACE_KEYS = new Set([
2313
2321
  "getMessage",
2314
2322
  "getMembers",
2315
2323
  "getAvatar",
2324
+ "getDisplayName",
2316
2325
  "rename",
2317
2326
  "avatar",
2318
2327
  "add",
@@ -2325,7 +2334,8 @@ const RESERVED_SPACE_KEYS = new Set([
2325
2334
  const PLATFORM_WISE_ACTION_KEYS = new Set([
2326
2335
  "getMessage",
2327
2336
  "getMembers",
2328
- "getAvatar"
2337
+ "getAvatar",
2338
+ "getDisplayName"
2329
2339
  ]);
2330
2340
  const RESERVED_MESSAGE_KEYS = new Set([
2331
2341
  "content",
@@ -2687,6 +2697,18 @@ function buildSpace(params) {
2687
2697
  store
2688
2698
  }, spaceRef));
2689
2699
  }
2700
+ async function getDisplayNameImpl() {
2701
+ const getDisplayName = definition.actions?.getDisplayName;
2702
+ if (!getDisplayName) throw UnsupportedError.action("getDisplayName", definition.name);
2703
+ return withSpan("spectrum.space.displayName.get", {
2704
+ "spectrum.provider": definition.name,
2705
+ "spectrum.space.id": spaceRef.id
2706
+ }, async () => await getDisplayName({
2707
+ client,
2708
+ config,
2709
+ store
2710
+ }, spaceRef));
2711
+ }
2690
2712
  const platformActions = {};
2691
2713
  const declaredActions = definition.space.actions;
2692
2714
  if (declaredActions) for (const [name, factory] of Object.entries(declaredActions)) {
@@ -2715,6 +2737,7 @@ function buildSpace(params) {
2715
2737
  getMessage: getMessageImpl,
2716
2738
  getMembers: getMembersImpl,
2717
2739
  getAvatar: getAvatarImpl,
2740
+ getDisplayName: getDisplayNameImpl,
2718
2741
  rename: async (displayName) => {
2719
2742
  await space.send(rename(displayName));
2720
2743
  },
@@ -2975,7 +2998,8 @@ function definePlatform(name, rawDef) {
2975
2998
  const def = rawDef;
2976
2999
  const fullDef = {
2977
3000
  ...def,
2978
- name
3001
+ name,
3002
+ config: envAwareConfig(name, def.config)
2979
3003
  };
2980
3004
  const platformCache = /* @__PURE__ */ new WeakMap();
2981
3005
  const narrowSpectrum = (spectrum) => {
@@ -3027,7 +3051,7 @@ function definePlatform(name, rawDef) {
3027
3051
  }
3028
3052
  //#endregion
3029
3053
  //#region src/build-env.ts
3030
- const SPECTRUM_SDK_VERSION = "9.0.0";
3054
+ const SPECTRUM_SDK_VERSION = "9.3.0";
3031
3055
  //#endregion
3032
3056
  //#region src/utils/provider-packages.ts
3033
3057
  const OFFICIAL_PROVIDER_PACKAGES = {
@@ -4067,12 +4091,27 @@ function bootstrapTelemetry(opts) {
4067
4091
  function applyLogLevel(level) {
4068
4092
  if (level) setLogLevel(level);
4069
4093
  }
4094
+ function envValue(key) {
4095
+ const value = process.env[key];
4096
+ return value === "" ? void 0 : value;
4097
+ }
4098
+ function resolveProjectCredentials(options) {
4099
+ return {
4100
+ projectId: options.projectId ?? envValue(envFor("PROJECT", "ID")),
4101
+ projectSecret: options.projectSecret ?? envValue(envFor("PROJECT", "SECRET"))
4102
+ };
4103
+ }
4070
4104
  async function Spectrum(options) {
4071
- spectrumConfigSchema.parse(options);
4072
- const { projectId, projectSecret, providers, options: runtimeOptions, telemetry, webhookSecret } = options;
4105
+ const { projectId, projectSecret } = resolveProjectCredentials(options);
4106
+ spectrumConfigSchema.parse({
4107
+ ...options,
4108
+ projectId,
4109
+ projectSecret
4110
+ });
4111
+ const { providers, options: runtimeOptions, telemetry, webhookSecret } = options;
4073
4112
  const flattenGroups = runtimeOptions?.flattenGroups ?? false;
4074
4113
  applyLogLevel(runtimeOptions?.logLevel);
4075
- const resolvedWebhookSecret = webhookSecret ?? process.env.SPECTRUM_WEBHOOK_SECRET;
4114
+ const resolvedWebhookSecret = webhookSecret ?? process.env[envFor("WEBHOOK", "SECRET")];
4076
4115
  const otelHandle = telemetry ? bootstrapTelemetry({
4077
4116
  projectId,
4078
4117
  projectSecret
@@ -1158,6 +1158,128 @@ function voice(input, options) {
1158
1158
  } };
1159
1159
  }
1160
1160
  //#endregion
1161
+ //#region src/utils/env.ts
1162
+ /**
1163
+ * Build a Spectrum config env-var name from a channel and a key, centralizing
1164
+ * the `SPECTRUM_<CHANNEL>_<KEY>` convention so the prefix can't drift or be
1165
+ * mistyped per field. Both segments are joined verbatim (callers pass them
1166
+ * already upper-snake-cased), e.g. `envFor("TELEGRAM", "BOT_TOKEN")` →
1167
+ * `"SPECTRUM_TELEGRAM_BOT_TOKEN"`.
1168
+ */
1169
+ const envFor = (channel, key) => `SPECTRUM_${channel}_${key}`;
1170
+ /**
1171
+ * Wrap a config-field schema so it falls back to an environment variable when
1172
+ * the field is omitted. Precedence is **explicit value > env var > the inner
1173
+ * schema's own default/required check**:
1174
+ *
1175
+ * - An explicit value (anything other than `undefined`) is passed straight
1176
+ * through — a caller-supplied config always wins over the environment.
1177
+ * - When the field is `undefined`, `process.env[envKey]` is substituted. An
1178
+ * env var set to the empty string is treated as unset (a common deploy
1179
+ * footgun) so it doesn't satisfy a `.min(1)` by accident.
1180
+ * - The inner `schema` then validates the resolved value, keeping its exact
1181
+ * semantics — regex, `.min(1)`, `.url()`, `.optional()`, `.default(...)`.
1182
+ * When both the field and the env var are absent, a required inner schema
1183
+ * raises its normal "required" error.
1184
+ *
1185
+ * The output type is the inner schema's output type, so call sites are
1186
+ * unchanged. Because substitution only happens on `undefined`, wrapping a
1187
+ * field inside a `z.object` leaves it a plain key on the parsed result — union
1188
+ * discriminators like `"accessToken" in config` keep working.
1189
+ *
1190
+ * @example
1191
+ * ```ts
1192
+ * botToken: fromEnv("SPECTRUM_TELEGRAM_BOT_TOKEN", z.string().regex(BOT_TOKEN_PATTERN)),
1193
+ * ```
1194
+ */
1195
+ const fromEnv = (envKey, schema) => z.preprocess((value) => {
1196
+ if (value !== void 0) return value;
1197
+ const envValue = process.env[envKey];
1198
+ return envValue === "" ? void 0 : envValue;
1199
+ }, schema);
1200
+ /**
1201
+ * Normalize a platform id into the env-var prefix segment: upper-case, with any
1202
+ * run of non-alphanumeric characters collapsed to a single `_`. This is a
1203
+ * whole-name transform, NOT camelCase splitting, so it reproduces the prefixes
1204
+ * the adapters used by hand — `"telegram"` → `TELEGRAM`,
1205
+ * `"WhatsApp Business"` → `WHATSAPP_BUSINESS`, `"Slack"` → `SLACK`.
1206
+ */
1207
+ const NON_ALPHANUMERIC_RUN = /[^A-Z0-9]+/;
1208
+ const normalizePlatformName = (name) => name.toUpperCase().split(NON_ALPHANUMERIC_RUN).filter(Boolean).join("_");
1209
+ const CAMEL_BOUNDARY = /([a-z0-9])([A-Z])/g;
1210
+ /** Convert a camelCase config field name into its UPPER_SNAKE env-var suffix. */
1211
+ const toEnvKey = (field) => field.replace(CAMEL_BOUNDARY, "$1_$2").toUpperCase();
1212
+ const INNER_TYPE_WRAPPERS = new Set([
1213
+ "optional",
1214
+ "nullable",
1215
+ "default",
1216
+ "readonly",
1217
+ "catch",
1218
+ "nonoptional",
1219
+ "prefault"
1220
+ ]);
1221
+ const asInternal = (schema) => schema;
1222
+ const unwrapSchema = (schema) => {
1223
+ let current = asInternal(schema);
1224
+ for (let depth = 0; depth < 20; depth++) {
1225
+ const { type } = current.def;
1226
+ if (INNER_TYPE_WRAPPERS.has(type) && current.def.innerType) {
1227
+ current = current.def.innerType;
1228
+ continue;
1229
+ }
1230
+ if (type === "pipe" && (current.def.out || current.def.in)) {
1231
+ current = current.def.out ?? current.def.in;
1232
+ continue;
1233
+ }
1234
+ break;
1235
+ }
1236
+ return current;
1237
+ };
1238
+ const isStringLeaf = (schema) => unwrapSchema(schema).def.type === "string";
1239
+ const isStrictObject = (def) => def.catchall?.def.type === "never";
1240
+ /**
1241
+ * Rewrite a platform's config schema so every string-leaf field falls back to
1242
+ * `SPECTRUM_<PLATFORM>_<KEY>` when omitted which is the equivalent of
1243
+ * hand-wrapping each field with {@link fromEnv}. Called once by
1244
+ * `definePlatform`, so adapters declare plain Zod and get env fallback for free.
1245
+ *
1246
+ * - **object**: each string-leaf field is wrapped with `fromEnv`; non-string
1247
+ * fields (records, arrays, nested objects, booleans, numbers) are left as-is.
1248
+ * The object is only reconstructed when a field actually changed, and
1249
+ * `.strict()` is preserved so an empty strict "cloud" branch is untouched.
1250
+ * - **union**: each option is rewritten independently, so an env value only
1251
+ * satisfies the branch that declares that field (a direct/cloud union stays
1252
+ * correctly discriminated).
1253
+ * - anything else is returned unchanged.
1254
+ *
1255
+ * The output type is identical to the input schema's. Only omitted fields gain
1256
+ * an env fallback which means that `z.infer` and downstream contexts are unaffected.
1257
+ */
1258
+ const envAwareConfig = (name, schema) => {
1259
+ return rewrite(`SPECTRUM_${normalizePlatformName(name)}`, schema);
1260
+ };
1261
+ const rewrite = (prefix, schema) => {
1262
+ const { def } = asInternal(schema);
1263
+ if (def.type === "object" && def.shape) return rewriteObject(prefix, def, schema);
1264
+ if (def.type === "union" && def.options) {
1265
+ const options = def.options.map((option) => rewrite(prefix, option));
1266
+ return z.union(options);
1267
+ }
1268
+ return schema;
1269
+ };
1270
+ const rewriteObject = (prefix, def, original) => {
1271
+ const shape = def.shape;
1272
+ const nextShape = {};
1273
+ let changed = false;
1274
+ for (const [key, field] of Object.entries(shape)) if (isStringLeaf(field)) {
1275
+ nextShape[key] = fromEnv(`${prefix}_${toEnvKey(key)}`, field);
1276
+ changed = true;
1277
+ } else nextShape[key] = field;
1278
+ if (!changed) return original;
1279
+ const rebuilt = z.object(nextShape);
1280
+ return isStrictObject(def) ? rebuilt.strict() : rebuilt;
1281
+ };
1282
+ //#endregion
1161
1283
  //#region src/utils/identifier.ts
1162
1284
  const PHONE_LIKE = /^\+?[\d\s()\-.]{7,}$/;
1163
1285
  const EMAIL_LIKE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
@@ -1576,4 +1698,4 @@ function broadcast(source) {
1576
1698
  };
1577
1699
  }
1578
1700
  //#endregion
1579
- export { avatar as $, addMemberSchema as A, groupSchema as B, reaction as C, option as D, asPollOption as E, asMarkdown as F, StreamConsumedError as G, asText as H, markdown as I, custom as J, drainStreamText as K, markdownSchema as L, leaveSpaceSchema as M, removeMember as N, poll as O, removeMemberSchema as P, toVCard as Q, asGroup as R, asReaction as S, asPoll as T, text as U, resolveContents as V, textSchema as W, contact as X, asContact as Y, fromVCard as Z, replySchema as _, contentAttrs as a, attachmentSchema as at, asRead as b, markdownToPlainText as c, asVoice as d, avatarSchema as et, voice as f, reply as g, asReply as h, stream as i, attachment as it, leaveSpace as j, addMember as k, renderInlineTokens as l, richlink as m, createAsyncQueue as n, photoActionSchema as nt, errorAttrs as o, fetchUrlBytes as ot, asRichlink as p, asCustom as q, mergeStreams as r, asAttachment as rt, senderAttrs as s, tracedFetch as st, broadcast as t, buildPhotoAction as tt, classifyIdentifier as u, rename as v, reactionSchema as w, read as x, renameSchema as y, group as z };
1701
+ export { contact as $, option as A, markdownSchema as B, asRead as C, reactionSchema as D, reaction as E, leaveSpaceSchema as F, asText as G, group as H, removeMember as I, StreamConsumedError as J, text as K, removeMemberSchema as L, addMember as M, addMemberSchema as N, asPoll as O, leaveSpace as P, asContact as Q, asMarkdown as R, renameSchema as S, asReaction as T, groupSchema as U, asGroup as V, resolveContents as W, asCustom as X, drainStreamText as Y, custom as Z, richlink as _, contentAttrs as a, photoActionSchema as at, replySchema as b, markdownToPlainText as c, attachmentSchema as ct, envAwareConfig as d, fromVCard as et, envFor as f, asRichlink as g, voice as h, stream as i, buildPhotoAction as it, poll as j, asPollOption as k, renderInlineTokens as l, fetchUrlBytes as lt, asVoice as m, createAsyncQueue as n, avatar as nt, errorAttrs as o, asAttachment as ot, fromEnv as p, textSchema as q, mergeStreams as r, avatarSchema as rt, senderAttrs as s, attachment as st, broadcast as t, toVCard as tt, classifyIdentifier as u, tracedFetch as ut, asReply as v, read as w, rename as x, reply as y, markdown as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectrum-ts/core",
3
- "version": "9.0.0",
3
+ "version": "9.3.0",
4
4
  "description": "The spectrum-ts runtime — Spectrum, content builders, fusor, and the provider authoring API.",
5
5
  "repository": {
6
6
  "type": "git",