@spectrum-ts/core 9.1.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
  /**
@@ -580,6 +592,12 @@ interface Message<TPlatform extends string = string, TSender extends User = User
580
592
  declare const editSchema: z.ZodObject<{
581
593
  type: z.ZodLiteral<"edit">;
582
594
  content: z.ZodCustom<{
595
+ type: "text";
596
+ text: string;
597
+ } | {
598
+ type: "markdown";
599
+ markdown: string;
600
+ } | {
583
601
  type: "attachment";
584
602
  id: string;
585
603
  name: string;
@@ -587,12 +605,6 @@ declare const editSchema: z.ZodObject<{
587
605
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
588
606
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
589
607
  size?: number | undefined;
590
- } | {
591
- type: "text";
592
- text: string;
593
- } | {
594
- type: "markdown";
595
- markdown: string;
596
608
  } | {
597
609
  type: "contact";
598
610
  user?: {
@@ -659,16 +671,13 @@ declare const editSchema: z.ZodObject<{
659
671
  };
660
672
  selected: boolean;
661
673
  title: string;
662
- } | {
663
- type: "reaction";
664
- emoji: string;
665
- target: Message<string, User, Space<unknown>>;
666
674
  } | {
667
675
  type: "group";
668
676
  items: Message<string, User, Space<unknown>>[];
669
677
  } | {
670
- type: "richlink";
671
- url: string;
678
+ type: "reaction";
679
+ emoji: string;
680
+ target: Message<string, User, Space<unknown>>;
672
681
  } | {
673
682
  type: "streamText";
674
683
  stream: () => AsyncIterable<string>;
@@ -681,6 +690,9 @@ declare const editSchema: z.ZodObject<{
681
690
  name?: string | undefined;
682
691
  duration?: number | undefined;
683
692
  size?: number | undefined;
693
+ } | {
694
+ type: "richlink";
695
+ url: string;
684
696
  } | {
685
697
  type: "app";
686
698
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -694,9 +706,16 @@ declare const editSchema: z.ZodObject<{
694
706
  imageSubtitle: z.ZodOptional<z.ZodString>;
695
707
  summary: z.ZodOptional<z.ZodString>;
696
708
  }, z.core.$strip>>>;
709
+ live?: boolean | undefined;
697
710
  } | {
698
711
  type: "effect";
699
712
  content: {
713
+ type: "text";
714
+ text: string;
715
+ } | {
716
+ type: "markdown";
717
+ markdown: string;
718
+ } | {
700
719
  type: "attachment";
701
720
  id: string;
702
721
  name: string;
@@ -704,12 +723,6 @@ declare const editSchema: z.ZodObject<{
704
723
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
705
724
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
706
725
  size?: number | undefined;
707
- } | {
708
- type: "text";
709
- text: string;
710
- } | {
711
- type: "markdown";
712
- markdown: string;
713
726
  };
714
727
  effect: string;
715
728
  } | {
@@ -736,6 +749,12 @@ declare const editSchema: z.ZodObject<{
736
749
  } | {
737
750
  type: "leaveSpace";
738
751
  }, {
752
+ type: "text";
753
+ text: string;
754
+ } | {
755
+ type: "markdown";
756
+ markdown: string;
757
+ } | {
739
758
  type: "attachment";
740
759
  id: string;
741
760
  name: string;
@@ -743,12 +762,6 @@ declare const editSchema: z.ZodObject<{
743
762
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
744
763
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
745
764
  size?: number | undefined;
746
- } | {
747
- type: "text";
748
- text: string;
749
- } | {
750
- type: "markdown";
751
- markdown: string;
752
765
  } | {
753
766
  type: "contact";
754
767
  user?: {
@@ -815,16 +828,13 @@ declare const editSchema: z.ZodObject<{
815
828
  };
816
829
  selected: boolean;
817
830
  title: string;
818
- } | {
819
- type: "reaction";
820
- emoji: string;
821
- target: Message<string, User, Space<unknown>>;
822
831
  } | {
823
832
  type: "group";
824
833
  items: Message<string, User, Space<unknown>>[];
825
834
  } | {
826
- type: "richlink";
827
- url: string;
835
+ type: "reaction";
836
+ emoji: string;
837
+ target: Message<string, User, Space<unknown>>;
828
838
  } | {
829
839
  type: "streamText";
830
840
  stream: () => AsyncIterable<string>;
@@ -837,6 +847,9 @@ declare const editSchema: z.ZodObject<{
837
847
  name?: string | undefined;
838
848
  duration?: number | undefined;
839
849
  size?: number | undefined;
850
+ } | {
851
+ type: "richlink";
852
+ url: string;
840
853
  } | {
841
854
  type: "app";
842
855
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -850,9 +863,16 @@ declare const editSchema: z.ZodObject<{
850
863
  imageSubtitle: z.ZodOptional<z.ZodString>;
851
864
  summary: z.ZodOptional<z.ZodString>;
852
865
  }, z.core.$strip>>>;
866
+ live?: boolean | undefined;
853
867
  } | {
854
868
  type: "effect";
855
869
  content: {
870
+ type: "text";
871
+ text: string;
872
+ } | {
873
+ type: "markdown";
874
+ markdown: string;
875
+ } | {
856
876
  type: "attachment";
857
877
  id: string;
858
878
  name: string;
@@ -860,12 +880,6 @@ declare const editSchema: z.ZodObject<{
860
880
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
861
881
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
862
882
  size?: number | undefined;
863
- } | {
864
- type: "text";
865
- text: string;
866
- } | {
867
- type: "markdown";
868
- markdown: string;
869
883
  };
870
884
  effect: string;
871
885
  } | {
@@ -1122,6 +1136,12 @@ declare function rename(displayName: string): ContentBuilder;
1122
1136
  declare const replySchema: z.ZodObject<{
1123
1137
  type: z.ZodLiteral<"reply">;
1124
1138
  content: z.ZodCustom<{
1139
+ type: "text";
1140
+ text: string;
1141
+ } | {
1142
+ type: "markdown";
1143
+ markdown: string;
1144
+ } | {
1125
1145
  type: "attachment";
1126
1146
  id: string;
1127
1147
  name: string;
@@ -1129,12 +1149,6 @@ declare const replySchema: z.ZodObject<{
1129
1149
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1130
1150
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1131
1151
  size?: number | undefined;
1132
- } | {
1133
- type: "text";
1134
- text: string;
1135
- } | {
1136
- type: "markdown";
1137
- markdown: string;
1138
1152
  } | {
1139
1153
  type: "contact";
1140
1154
  user?: {
@@ -1201,16 +1215,13 @@ declare const replySchema: z.ZodObject<{
1201
1215
  };
1202
1216
  selected: boolean;
1203
1217
  title: string;
1204
- } | {
1205
- type: "reaction";
1206
- emoji: string;
1207
- target: Message<string, User, Space<unknown>>;
1208
1218
  } | {
1209
1219
  type: "group";
1210
1220
  items: Message<string, User, Space<unknown>>[];
1211
1221
  } | {
1212
- type: "richlink";
1213
- url: string;
1222
+ type: "reaction";
1223
+ emoji: string;
1224
+ target: Message<string, User, Space<unknown>>;
1214
1225
  } | {
1215
1226
  type: "streamText";
1216
1227
  stream: () => AsyncIterable<string>;
@@ -1223,6 +1234,9 @@ declare const replySchema: z.ZodObject<{
1223
1234
  name?: string | undefined;
1224
1235
  duration?: number | undefined;
1225
1236
  size?: number | undefined;
1237
+ } | {
1238
+ type: "richlink";
1239
+ url: string;
1226
1240
  } | {
1227
1241
  type: "app";
1228
1242
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -1236,9 +1250,16 @@ declare const replySchema: z.ZodObject<{
1236
1250
  imageSubtitle: z.ZodOptional<z.ZodString>;
1237
1251
  summary: z.ZodOptional<z.ZodString>;
1238
1252
  }, z.core.$strip>>>;
1253
+ live?: boolean | undefined;
1239
1254
  } | {
1240
1255
  type: "effect";
1241
1256
  content: {
1257
+ type: "text";
1258
+ text: string;
1259
+ } | {
1260
+ type: "markdown";
1261
+ markdown: string;
1262
+ } | {
1242
1263
  type: "attachment";
1243
1264
  id: string;
1244
1265
  name: string;
@@ -1246,12 +1267,6 @@ declare const replySchema: z.ZodObject<{
1246
1267
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1247
1268
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1248
1269
  size?: number | undefined;
1249
- } | {
1250
- type: "text";
1251
- text: string;
1252
- } | {
1253
- type: "markdown";
1254
- markdown: string;
1255
1270
  };
1256
1271
  effect: string;
1257
1272
  } | {
@@ -1278,6 +1293,12 @@ declare const replySchema: z.ZodObject<{
1278
1293
  } | {
1279
1294
  type: "leaveSpace";
1280
1295
  }, {
1296
+ type: "text";
1297
+ text: string;
1298
+ } | {
1299
+ type: "markdown";
1300
+ markdown: string;
1301
+ } | {
1281
1302
  type: "attachment";
1282
1303
  id: string;
1283
1304
  name: string;
@@ -1285,12 +1306,6 @@ declare const replySchema: z.ZodObject<{
1285
1306
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1286
1307
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1287
1308
  size?: number | undefined;
1288
- } | {
1289
- type: "text";
1290
- text: string;
1291
- } | {
1292
- type: "markdown";
1293
- markdown: string;
1294
1309
  } | {
1295
1310
  type: "contact";
1296
1311
  user?: {
@@ -1357,16 +1372,13 @@ declare const replySchema: z.ZodObject<{
1357
1372
  };
1358
1373
  selected: boolean;
1359
1374
  title: string;
1360
- } | {
1361
- type: "reaction";
1362
- emoji: string;
1363
- target: Message<string, User, Space<unknown>>;
1364
1375
  } | {
1365
1376
  type: "group";
1366
1377
  items: Message<string, User, Space<unknown>>[];
1367
1378
  } | {
1368
- type: "richlink";
1369
- url: string;
1379
+ type: "reaction";
1380
+ emoji: string;
1381
+ target: Message<string, User, Space<unknown>>;
1370
1382
  } | {
1371
1383
  type: "streamText";
1372
1384
  stream: () => AsyncIterable<string>;
@@ -1379,6 +1391,9 @@ declare const replySchema: z.ZodObject<{
1379
1391
  name?: string | undefined;
1380
1392
  duration?: number | undefined;
1381
1393
  size?: number | undefined;
1394
+ } | {
1395
+ type: "richlink";
1396
+ url: string;
1382
1397
  } | {
1383
1398
  type: "app";
1384
1399
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -1392,9 +1407,16 @@ declare const replySchema: z.ZodObject<{
1392
1407
  imageSubtitle: z.ZodOptional<z.ZodString>;
1393
1408
  summary: z.ZodOptional<z.ZodString>;
1394
1409
  }, z.core.$strip>>>;
1410
+ live?: boolean | undefined;
1395
1411
  } | {
1396
1412
  type: "effect";
1397
1413
  content: {
1414
+ type: "text";
1415
+ text: string;
1416
+ } | {
1417
+ type: "markdown";
1418
+ markdown: string;
1419
+ } | {
1398
1420
  type: "attachment";
1399
1421
  id: string;
1400
1422
  name: string;
@@ -1402,12 +1424,6 @@ declare const replySchema: z.ZodObject<{
1402
1424
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
1403
1425
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
1404
1426
  size?: number | undefined;
1405
- } | {
1406
- type: "text";
1407
- text: string;
1408
- } | {
1409
- type: "markdown";
1410
- markdown: string;
1411
1427
  };
1412
1428
  effect: string;
1413
1429
  } | {
@@ -6651,8 +6667,9 @@ interface SpectrumLike<Providers extends PlatformProviderConfig[] = PlatformProv
6651
6667
  };
6652
6668
  readonly __providers: Providers;
6653
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;
6654
6671
  interface Platform<Def extends AnyPlatformDef> {
6655
- 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>;
6656
6673
  is(input: Message): input is PlatformMessage<Def>;
6657
6674
  is(input: Space): input is PlatformSpace<Def>;
6658
6675
  is(input: unknown): input is PlatformMessage<Def> | PlatformSpace<Def>;
@@ -7004,6 +7021,7 @@ declare const baseContentSchema: z.ZodDiscriminatedUnion<readonly [z.ZodObject<{
7004
7021
  imageSubtitle: z.ZodOptional<z.ZodString>;
7005
7022
  summary: z.ZodOptional<z.ZodString>;
7006
7023
  }, z.core.$strip>>>;
7024
+ live: z.ZodOptional<z.ZodBoolean>;
7007
7025
  }, z.core.$strip>, z.ZodObject<{
7008
7026
  type: z.ZodLiteral<"reaction">;
7009
7027
  emoji: z.ZodString;
@@ -7181,6 +7199,7 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7181
7199
  imageSubtitle: z.ZodOptional<z.ZodString>;
7182
7200
  summary: z.ZodOptional<z.ZodString>;
7183
7201
  }, z.core.$strip>>>;
7202
+ live: z.ZodOptional<z.ZodBoolean>;
7184
7203
  }, z.core.$strip>, z.ZodObject<{
7185
7204
  type: z.ZodLiteral<"reaction">;
7186
7205
  emoji: z.ZodString;
@@ -7255,6 +7274,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7255
7274
  }, z.core.$strip>, z.ZodObject<{
7256
7275
  type: z.ZodLiteral<"reply">;
7257
7276
  content: z.ZodCustom<{
7277
+ type: "text";
7278
+ text: string;
7279
+ } | {
7280
+ type: "markdown";
7281
+ markdown: string;
7282
+ } | {
7258
7283
  type: "attachment";
7259
7284
  id: string;
7260
7285
  name: string;
@@ -7262,12 +7287,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7262
7287
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7263
7288
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7264
7289
  size?: number | undefined;
7265
- } | {
7266
- type: "text";
7267
- text: string;
7268
- } | {
7269
- type: "markdown";
7270
- markdown: string;
7271
7290
  } | {
7272
7291
  type: "contact";
7273
7292
  user?: {
@@ -7334,16 +7353,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7334
7353
  };
7335
7354
  selected: boolean;
7336
7355
  title: string;
7337
- } | {
7338
- type: "reaction";
7339
- emoji: string;
7340
- target: Message<string, User, Space<unknown>>;
7341
7356
  } | {
7342
7357
  type: "group";
7343
7358
  items: Message<string, User, Space<unknown>>[];
7344
7359
  } | {
7345
- type: "richlink";
7346
- url: string;
7360
+ type: "reaction";
7361
+ emoji: string;
7362
+ target: Message<string, User, Space<unknown>>;
7347
7363
  } | {
7348
7364
  type: "streamText";
7349
7365
  stream: () => AsyncIterable<string>;
@@ -7356,6 +7372,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7356
7372
  name?: string | undefined;
7357
7373
  duration?: number | undefined;
7358
7374
  size?: number | undefined;
7375
+ } | {
7376
+ type: "richlink";
7377
+ url: string;
7359
7378
  } | {
7360
7379
  type: "app";
7361
7380
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -7369,9 +7388,16 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7369
7388
  imageSubtitle: z.ZodOptional<z.ZodString>;
7370
7389
  summary: z.ZodOptional<z.ZodString>;
7371
7390
  }, z.core.$strip>>>;
7391
+ live?: boolean | undefined;
7372
7392
  } | {
7373
7393
  type: "effect";
7374
7394
  content: {
7395
+ type: "text";
7396
+ text: string;
7397
+ } | {
7398
+ type: "markdown";
7399
+ markdown: string;
7400
+ } | {
7375
7401
  type: "attachment";
7376
7402
  id: string;
7377
7403
  name: string;
@@ -7379,12 +7405,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7379
7405
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7380
7406
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7381
7407
  size?: number | undefined;
7382
- } | {
7383
- type: "text";
7384
- text: string;
7385
- } | {
7386
- type: "markdown";
7387
- markdown: string;
7388
7408
  };
7389
7409
  effect: string;
7390
7410
  } | {
@@ -7411,6 +7431,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7411
7431
  } | {
7412
7432
  type: "leaveSpace";
7413
7433
  }, {
7434
+ type: "text";
7435
+ text: string;
7436
+ } | {
7437
+ type: "markdown";
7438
+ markdown: string;
7439
+ } | {
7414
7440
  type: "attachment";
7415
7441
  id: string;
7416
7442
  name: string;
@@ -7418,12 +7444,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7418
7444
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7419
7445
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7420
7446
  size?: number | undefined;
7421
- } | {
7422
- type: "text";
7423
- text: string;
7424
- } | {
7425
- type: "markdown";
7426
- markdown: string;
7427
7447
  } | {
7428
7448
  type: "contact";
7429
7449
  user?: {
@@ -7490,16 +7510,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7490
7510
  };
7491
7511
  selected: boolean;
7492
7512
  title: string;
7493
- } | {
7494
- type: "reaction";
7495
- emoji: string;
7496
- target: Message<string, User, Space<unknown>>;
7497
7513
  } | {
7498
7514
  type: "group";
7499
7515
  items: Message<string, User, Space<unknown>>[];
7500
7516
  } | {
7501
- type: "richlink";
7502
- url: string;
7517
+ type: "reaction";
7518
+ emoji: string;
7519
+ target: Message<string, User, Space<unknown>>;
7503
7520
  } | {
7504
7521
  type: "streamText";
7505
7522
  stream: () => AsyncIterable<string>;
@@ -7512,6 +7529,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7512
7529
  name?: string | undefined;
7513
7530
  duration?: number | undefined;
7514
7531
  size?: number | undefined;
7532
+ } | {
7533
+ type: "richlink";
7534
+ url: string;
7515
7535
  } | {
7516
7536
  type: "app";
7517
7537
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -7525,9 +7545,16 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7525
7545
  imageSubtitle: z.ZodOptional<z.ZodString>;
7526
7546
  summary: z.ZodOptional<z.ZodString>;
7527
7547
  }, z.core.$strip>>>;
7548
+ live?: boolean | undefined;
7528
7549
  } | {
7529
7550
  type: "effect";
7530
7551
  content: {
7552
+ type: "text";
7553
+ text: string;
7554
+ } | {
7555
+ type: "markdown";
7556
+ markdown: string;
7557
+ } | {
7531
7558
  type: "attachment";
7532
7559
  id: string;
7533
7560
  name: string;
@@ -7535,12 +7562,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7535
7562
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7536
7563
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7537
7564
  size?: number | undefined;
7538
- } | {
7539
- type: "text";
7540
- text: string;
7541
- } | {
7542
- type: "markdown";
7543
- markdown: string;
7544
7565
  };
7545
7566
  effect: string;
7546
7567
  } | {
@@ -7571,6 +7592,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7571
7592
  }, z.core.$strip>, z.ZodObject<{
7572
7593
  type: z.ZodLiteral<"edit">;
7573
7594
  content: z.ZodCustom<{
7595
+ type: "text";
7596
+ text: string;
7597
+ } | {
7598
+ type: "markdown";
7599
+ markdown: string;
7600
+ } | {
7574
7601
  type: "attachment";
7575
7602
  id: string;
7576
7603
  name: string;
@@ -7578,12 +7605,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7578
7605
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7579
7606
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7580
7607
  size?: number | undefined;
7581
- } | {
7582
- type: "text";
7583
- text: string;
7584
- } | {
7585
- type: "markdown";
7586
- markdown: string;
7587
7608
  } | {
7588
7609
  type: "contact";
7589
7610
  user?: {
@@ -7650,16 +7671,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7650
7671
  };
7651
7672
  selected: boolean;
7652
7673
  title: string;
7653
- } | {
7654
- type: "reaction";
7655
- emoji: string;
7656
- target: Message<string, User, Space<unknown>>;
7657
7674
  } | {
7658
7675
  type: "group";
7659
7676
  items: Message<string, User, Space<unknown>>[];
7660
7677
  } | {
7661
- type: "richlink";
7662
- url: string;
7678
+ type: "reaction";
7679
+ emoji: string;
7680
+ target: Message<string, User, Space<unknown>>;
7663
7681
  } | {
7664
7682
  type: "streamText";
7665
7683
  stream: () => AsyncIterable<string>;
@@ -7672,6 +7690,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7672
7690
  name?: string | undefined;
7673
7691
  duration?: number | undefined;
7674
7692
  size?: number | undefined;
7693
+ } | {
7694
+ type: "richlink";
7695
+ url: string;
7675
7696
  } | {
7676
7697
  type: "app";
7677
7698
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -7685,9 +7706,16 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7685
7706
  imageSubtitle: z.ZodOptional<z.ZodString>;
7686
7707
  summary: z.ZodOptional<z.ZodString>;
7687
7708
  }, z.core.$strip>>>;
7709
+ live?: boolean | undefined;
7688
7710
  } | {
7689
7711
  type: "effect";
7690
7712
  content: {
7713
+ type: "text";
7714
+ text: string;
7715
+ } | {
7716
+ type: "markdown";
7717
+ markdown: string;
7718
+ } | {
7691
7719
  type: "attachment";
7692
7720
  id: string;
7693
7721
  name: string;
@@ -7695,12 +7723,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7695
7723
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7696
7724
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7697
7725
  size?: number | undefined;
7698
- } | {
7699
- type: "text";
7700
- text: string;
7701
- } | {
7702
- type: "markdown";
7703
- markdown: string;
7704
7726
  };
7705
7727
  effect: string;
7706
7728
  } | {
@@ -7727,6 +7749,12 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7727
7749
  } | {
7728
7750
  type: "leaveSpace";
7729
7751
  }, {
7752
+ type: "text";
7753
+ text: string;
7754
+ } | {
7755
+ type: "markdown";
7756
+ markdown: string;
7757
+ } | {
7730
7758
  type: "attachment";
7731
7759
  id: string;
7732
7760
  name: string;
@@ -7734,12 +7762,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7734
7762
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7735
7763
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7736
7764
  size?: number | undefined;
7737
- } | {
7738
- type: "text";
7739
- text: string;
7740
- } | {
7741
- type: "markdown";
7742
- markdown: string;
7743
7765
  } | {
7744
7766
  type: "contact";
7745
7767
  user?: {
@@ -7806,16 +7828,13 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7806
7828
  };
7807
7829
  selected: boolean;
7808
7830
  title: string;
7809
- } | {
7810
- type: "reaction";
7811
- emoji: string;
7812
- target: Message<string, User, Space<unknown>>;
7813
7831
  } | {
7814
7832
  type: "group";
7815
7833
  items: Message<string, User, Space<unknown>>[];
7816
7834
  } | {
7817
- type: "richlink";
7818
- url: string;
7835
+ type: "reaction";
7836
+ emoji: string;
7837
+ target: Message<string, User, Space<unknown>>;
7819
7838
  } | {
7820
7839
  type: "streamText";
7821
7840
  stream: () => AsyncIterable<string>;
@@ -7828,6 +7847,9 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7828
7847
  name?: string | undefined;
7829
7848
  duration?: number | undefined;
7830
7849
  size?: number | undefined;
7850
+ } | {
7851
+ type: "richlink";
7852
+ url: string;
7831
7853
  } | {
7832
7854
  type: "app";
7833
7855
  url: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodURL>>;
@@ -7841,9 +7863,16 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7841
7863
  imageSubtitle: z.ZodOptional<z.ZodString>;
7842
7864
  summary: z.ZodOptional<z.ZodString>;
7843
7865
  }, z.core.$strip>>>;
7866
+ live?: boolean | undefined;
7844
7867
  } | {
7845
7868
  type: "effect";
7846
7869
  content: {
7870
+ type: "text";
7871
+ text: string;
7872
+ } | {
7873
+ type: "markdown";
7874
+ markdown: string;
7875
+ } | {
7847
7876
  type: "attachment";
7848
7877
  id: string;
7849
7878
  name: string;
@@ -7851,12 +7880,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7851
7880
  read: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>>>;
7852
7881
  stream: z.core.$InferOuterFunctionType<z.ZodTuple<readonly [], null>, z.ZodPromise<z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>>>;
7853
7882
  size?: number | undefined;
7854
- } | {
7855
- type: "text";
7856
- text: string;
7857
- } | {
7858
- type: "markdown";
7859
- markdown: string;
7860
7883
  };
7861
7884
  effect: string;
7862
7885
  } | {
@@ -7923,4 +7946,4 @@ declare function attachment(input: AttachmentInput, options?: {
7923
7946
  name?: string;
7924
7947
  }): ContentBuilder;
7925
7948
  //#endregion
7926
- 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-B4H1Q8xO.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-B4H1Q8xO.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
@@ -2990,7 +2998,8 @@ function definePlatform(name, rawDef) {
2990
2998
  const def = rawDef;
2991
2999
  const fullDef = {
2992
3000
  ...def,
2993
- name
3001
+ name,
3002
+ config: envAwareConfig(name, def.config)
2994
3003
  };
2995
3004
  const platformCache = /* @__PURE__ */ new WeakMap();
2996
3005
  const narrowSpectrum = (spectrum) => {
@@ -3042,7 +3051,7 @@ function definePlatform(name, rawDef) {
3042
3051
  }
3043
3052
  //#endregion
3044
3053
  //#region src/build-env.ts
3045
- const SPECTRUM_SDK_VERSION = "9.1.0";
3054
+ const SPECTRUM_SDK_VERSION = "9.3.0";
3046
3055
  //#endregion
3047
3056
  //#region src/utils/provider-packages.ts
3048
3057
  const OFFICIAL_PROVIDER_PACKAGES = {
@@ -4082,12 +4091,27 @@ function bootstrapTelemetry(opts) {
4082
4091
  function applyLogLevel(level) {
4083
4092
  if (level) setLogLevel(level);
4084
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
+ }
4085
4104
  async function Spectrum(options) {
4086
- spectrumConfigSchema.parse(options);
4087
- 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;
4088
4112
  const flattenGroups = runtimeOptions?.flattenGroups ?? false;
4089
4113
  applyLogLevel(runtimeOptions?.logLevel);
4090
- const resolvedWebhookSecret = webhookSecret ?? process.env.SPECTRUM_WEBHOOK_SECRET;
4114
+ const resolvedWebhookSecret = webhookSecret ?? process.env[envFor("WEBHOOK", "SECRET")];
4091
4115
  const otelHandle = telemetry ? bootstrapTelemetry({
4092
4116
  projectId,
4093
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.1.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",