@antiphony/shared 0.1.0 → 0.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.
- package/dist/cjs/api-codecs.cjs +26 -650
- package/dist/cjs/api-codecs.d.cts +15 -233
- package/dist/cjs/index.cjs +29 -761
- package/dist/cjs/index.d.cts +4 -4
- package/dist/cjs/nsid.cjs +3 -10
- package/dist/cjs/nsid.d.cts +1 -9
- package/dist/cjs/types/api.cjs +11 -571
- package/dist/cjs/types/api.d.cts +13 -265
- package/dist/cjs/types/audio.cjs +26 -547
- package/dist/cjs/types/audio.d.cts +93 -52
- package/dist/cjs/types/records.cjs +3 -328
- package/dist/cjs/types/records.d.cts +7 -729
- package/dist/cjs/types/views.cjs +8 -649
- package/dist/cjs/types/views.d.cts +43 -9123
- package/dist/esm/api-codecs.d.ts +46 -264
- package/dist/esm/api-codecs.js +5 -5
- package/dist/esm/{chunk-ORMEWXMH.js → chunk-5JBD5THX.js} +1 -16
- package/dist/esm/{chunk-XDBKR6LW.js → chunk-6LROFBKK.js} +3 -10
- package/dist/esm/{chunk-F2CANZZ7.js → chunk-BNNLHRH7.js} +1 -1
- package/dist/esm/{chunk-BUNMR4ZO.js → chunk-F7IHVM34.js} +20 -3
- package/dist/esm/chunk-FDM5FDN4.js +46 -0
- package/dist/esm/chunk-IHIBHQBJ.js +78 -0
- package/dist/esm/chunk-R6SBR3IG.js +97 -0
- package/dist/esm/chunk-Y6HNNRVD.js +12 -0
- package/dist/esm/errors/index.js +1 -1
- package/dist/esm/index.d.ts +4 -4
- package/dist/esm/index.js +8 -8
- package/dist/esm/nsid.d.ts +1 -9
- package/dist/esm/nsid.js +2 -2
- package/dist/esm/observability/index.js +2 -2
- package/dist/esm/observability/report-error.js +2 -2
- package/dist/esm/types/api.d.ts +15 -267
- package/dist/esm/types/api.js +4 -5
- package/dist/esm/types/audio.d.ts +170 -129
- package/dist/esm/types/audio.js +4 -4
- package/dist/esm/types/blob.js +1 -1
- package/dist/esm/types/records.d.ts +10 -732
- package/dist/esm/types/records.js +2 -3
- package/dist/esm/types/views.d.ts +51 -9131
- package/dist/esm/types/views.js +3 -4
- package/dist/esm/utils/index.js +1 -1
- package/package.json +1 -1
- package/dist/cjs/types/channels.cjs +0 -170
- package/dist/cjs/types/channels.d.cts +0 -262
- package/dist/cjs/types/storage.cjs +0 -414
- package/dist/cjs/types/storage.d.cts +0 -197
- package/dist/esm/chunk-3WZJXJNU.js +0 -378
- package/dist/esm/chunk-7V44CPRR.js +0 -132
- package/dist/esm/chunk-EA4OONDV.js +0 -380
- package/dist/esm/chunk-TIZRJORN.js +0 -24
- package/dist/esm/types/channels.d.ts +0 -262
- package/dist/esm/types/channels.js +0 -162
- package/dist/esm/types/storage.d.ts +0 -197
- package/dist/esm/types/storage.js +0 -26
|
@@ -303,6 +303,15 @@ declare const AudioPostRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
303
303
|
orgId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
304
304
|
/** Denormalized from `reply` presence: `reply` set ⇒ 'reply', else 'prompt'. */
|
|
305
305
|
kind: z.ZodEnum<["prompt", "reply"]>;
|
|
306
|
+
/**
|
|
307
|
+
* Branch participant pair (author ids) for reply gating — the parties to a
|
|
308
|
+
* reply's sub-thread: the creator (thread-root author) + the responder who
|
|
309
|
+
* opened the branch. Set on replies (deduped, 1–2 ids); absent on prompts
|
|
310
|
+
* (a prompt's repliers are the app's audience policy, not a fixed pair).
|
|
311
|
+
* Inherited down the branch so reply gating is an O(1) field check, never a
|
|
312
|
+
* thread walk. See `specs/antiphony-data-model.md` §6 "Reply gating".
|
|
313
|
+
*/
|
|
314
|
+
threadParticipants: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
306
315
|
/** User-authored text (bsky-semantic). May be empty for pure-audio posts. NEVER the transcript. */
|
|
307
316
|
text: z.ZodString;
|
|
308
317
|
/** Optional headline; a prompt feature, not the discriminator. */
|
|
@@ -406,13 +415,12 @@ declare const AudioPostRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
406
415
|
}, "strip", z.ZodTypeAny, {
|
|
407
416
|
id: string;
|
|
408
417
|
createdAt: Date;
|
|
409
|
-
authorId: string;
|
|
410
418
|
text: string;
|
|
411
419
|
originAppId: string;
|
|
420
|
+
authorId: string;
|
|
412
421
|
kind: "prompt" | "reply";
|
|
413
|
-
orgId?: string | null | undefined;
|
|
414
|
-
title?: string | undefined;
|
|
415
422
|
authorDid?: string | undefined;
|
|
423
|
+
orgId?: string | null | undefined;
|
|
416
424
|
reply?: {
|
|
417
425
|
root: {
|
|
418
426
|
uri: string;
|
|
@@ -423,6 +431,8 @@ declare const AudioPostRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
423
431
|
cid: string;
|
|
424
432
|
};
|
|
425
433
|
} | undefined;
|
|
434
|
+
threadParticipants?: string[] | undefined;
|
|
435
|
+
title?: string | undefined;
|
|
426
436
|
embed?: {
|
|
427
437
|
$type: "dev.antiphony.embed.audio";
|
|
428
438
|
audio: {
|
|
@@ -439,14 +449,13 @@ declare const AudioPostRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
439
449
|
selfLabels?: string[] | undefined;
|
|
440
450
|
}, {
|
|
441
451
|
id: string;
|
|
442
|
-
authorId: string;
|
|
443
452
|
text: string;
|
|
444
453
|
originAppId: string;
|
|
454
|
+
authorId: string;
|
|
445
455
|
kind: "prompt" | "reply";
|
|
446
456
|
createdAt?: unknown;
|
|
447
|
-
orgId?: string | null | undefined;
|
|
448
|
-
title?: string | undefined;
|
|
449
457
|
authorDid?: string | undefined;
|
|
458
|
+
orgId?: string | null | undefined;
|
|
450
459
|
reply?: {
|
|
451
460
|
root: {
|
|
452
461
|
uri: string;
|
|
@@ -457,6 +466,8 @@ declare const AudioPostRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
457
466
|
cid: string;
|
|
458
467
|
};
|
|
459
468
|
} | undefined;
|
|
469
|
+
threadParticipants?: string[] | undefined;
|
|
470
|
+
title?: string | undefined;
|
|
460
471
|
embed?: {
|
|
461
472
|
$type: "dev.antiphony.embed.audio";
|
|
462
473
|
audio: {
|
|
@@ -474,13 +485,12 @@ declare const AudioPostRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
474
485
|
}>, {
|
|
475
486
|
id: string;
|
|
476
487
|
createdAt: Date;
|
|
477
|
-
authorId: string;
|
|
478
488
|
text: string;
|
|
479
489
|
originAppId: string;
|
|
490
|
+
authorId: string;
|
|
480
491
|
kind: "prompt" | "reply";
|
|
481
|
-
orgId?: string | null | undefined;
|
|
482
|
-
title?: string | undefined;
|
|
483
492
|
authorDid?: string | undefined;
|
|
493
|
+
orgId?: string | null | undefined;
|
|
484
494
|
reply?: {
|
|
485
495
|
root: {
|
|
486
496
|
uri: string;
|
|
@@ -491,6 +501,8 @@ declare const AudioPostRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
491
501
|
cid: string;
|
|
492
502
|
};
|
|
493
503
|
} | undefined;
|
|
504
|
+
threadParticipants?: string[] | undefined;
|
|
505
|
+
title?: string | undefined;
|
|
494
506
|
embed?: {
|
|
495
507
|
$type: "dev.antiphony.embed.audio";
|
|
496
508
|
audio: {
|
|
@@ -507,14 +519,13 @@ declare const AudioPostRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
507
519
|
selfLabels?: string[] | undefined;
|
|
508
520
|
}, {
|
|
509
521
|
id: string;
|
|
510
|
-
authorId: string;
|
|
511
522
|
text: string;
|
|
512
523
|
originAppId: string;
|
|
524
|
+
authorId: string;
|
|
513
525
|
kind: "prompt" | "reply";
|
|
514
526
|
createdAt?: unknown;
|
|
515
|
-
orgId?: string | null | undefined;
|
|
516
|
-
title?: string | undefined;
|
|
517
527
|
authorDid?: string | undefined;
|
|
528
|
+
orgId?: string | null | undefined;
|
|
518
529
|
reply?: {
|
|
519
530
|
root: {
|
|
520
531
|
uri: string;
|
|
@@ -525,6 +536,8 @@ declare const AudioPostRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
525
536
|
cid: string;
|
|
526
537
|
};
|
|
527
538
|
} | undefined;
|
|
539
|
+
threadParticipants?: string[] | undefined;
|
|
540
|
+
title?: string | undefined;
|
|
528
541
|
embed?: {
|
|
529
542
|
$type: "dev.antiphony.embed.audio";
|
|
530
543
|
audio: {
|
|
@@ -663,10 +676,22 @@ type ActorProfileRecord = z.infer<typeof ActorProfileRecordSchema>;
|
|
|
663
676
|
declare const ViewerStateSchema: z.ZodObject<{
|
|
664
677
|
/** True when the authenticated caller authored this post. */
|
|
665
678
|
isAuthor: z.ZodDefault<z.ZodBoolean>;
|
|
679
|
+
/**
|
|
680
|
+
* Whether the caller may reply to this post (reply gating, §6). A prompt is
|
|
681
|
+
* repliable by any authenticated viewer (the app's audience-policy default);
|
|
682
|
+
* a reply only by its branch participants (`{ creator, branch responder }`).
|
|
683
|
+
*/
|
|
684
|
+
canReply: z.ZodDefault<z.ZodBoolean>;
|
|
685
|
+
/** Why `canReply` is false, when it is (omitted when the caller can reply). */
|
|
686
|
+
replyDisabledReason: z.ZodOptional<z.ZodEnum<["unauthenticated", "not_a_participant"]>>;
|
|
666
687
|
}, "strip", z.ZodTypeAny, {
|
|
667
688
|
isAuthor: boolean;
|
|
689
|
+
canReply: boolean;
|
|
690
|
+
replyDisabledReason?: "unauthenticated" | "not_a_participant" | undefined;
|
|
668
691
|
}, {
|
|
669
692
|
isAuthor?: boolean | undefined;
|
|
693
|
+
canReply?: boolean | undefined;
|
|
694
|
+
replyDisabledReason?: "unauthenticated" | "not_a_participant" | undefined;
|
|
670
695
|
}>;
|
|
671
696
|
type ViewerState = z.infer<typeof ViewerStateSchema>;
|
|
672
697
|
/**
|
|
@@ -722,7 +747,6 @@ declare const PostRecordPublicSchema: z.ZodObject<{
|
|
|
722
747
|
}, "strip", z.ZodTypeAny, {
|
|
723
748
|
createdAt: Date;
|
|
724
749
|
text: string;
|
|
725
|
-
title?: string | undefined;
|
|
726
750
|
reply?: {
|
|
727
751
|
root: {
|
|
728
752
|
uri: string;
|
|
@@ -733,12 +757,12 @@ declare const PostRecordPublicSchema: z.ZodObject<{
|
|
|
733
757
|
cid: string;
|
|
734
758
|
};
|
|
735
759
|
} | undefined;
|
|
760
|
+
title?: string | undefined;
|
|
736
761
|
langs?: string[] | undefined;
|
|
737
762
|
selfLabels?: string[] | undefined;
|
|
738
763
|
}, {
|
|
739
764
|
text: string;
|
|
740
765
|
createdAt?: unknown;
|
|
741
|
-
title?: string | undefined;
|
|
742
766
|
reply?: {
|
|
743
767
|
root: {
|
|
744
768
|
uri: string;
|
|
@@ -749,6 +773,7 @@ declare const PostRecordPublicSchema: z.ZodObject<{
|
|
|
749
773
|
cid: string;
|
|
750
774
|
};
|
|
751
775
|
} | undefined;
|
|
776
|
+
title?: string | undefined;
|
|
752
777
|
langs?: string[] | undefined;
|
|
753
778
|
selfLabels?: string[] | undefined;
|
|
754
779
|
}>;
|
|
@@ -904,7 +929,6 @@ declare const AudioPostViewSchema: z.ZodObject<{
|
|
|
904
929
|
}, "strip", z.ZodTypeAny, {
|
|
905
930
|
createdAt: Date;
|
|
906
931
|
text: string;
|
|
907
|
-
title?: string | undefined;
|
|
908
932
|
reply?: {
|
|
909
933
|
root: {
|
|
910
934
|
uri: string;
|
|
@@ -915,12 +939,12 @@ declare const AudioPostViewSchema: z.ZodObject<{
|
|
|
915
939
|
cid: string;
|
|
916
940
|
};
|
|
917
941
|
} | undefined;
|
|
942
|
+
title?: string | undefined;
|
|
918
943
|
langs?: string[] | undefined;
|
|
919
944
|
selfLabels?: string[] | undefined;
|
|
920
945
|
}, {
|
|
921
946
|
text: string;
|
|
922
947
|
createdAt?: unknown;
|
|
923
|
-
title?: string | undefined;
|
|
924
948
|
reply?: {
|
|
925
949
|
root: {
|
|
926
950
|
uri: string;
|
|
@@ -931,6 +955,7 @@ declare const AudioPostViewSchema: z.ZodObject<{
|
|
|
931
955
|
cid: string;
|
|
932
956
|
};
|
|
933
957
|
} | undefined;
|
|
958
|
+
title?: string | undefined;
|
|
934
959
|
langs?: string[] | undefined;
|
|
935
960
|
selfLabels?: string[] | undefined;
|
|
936
961
|
}>;
|
|
@@ -1012,30 +1037,26 @@ declare const AudioPostViewSchema: z.ZodObject<{
|
|
|
1012
1037
|
viewer: z.ZodObject<{
|
|
1013
1038
|
/** True when the authenticated caller authored this post. */
|
|
1014
1039
|
isAuthor: z.ZodDefault<z.ZodBoolean>;
|
|
1040
|
+
/**
|
|
1041
|
+
* Whether the caller may reply to this post (reply gating, §6). A prompt is
|
|
1042
|
+
* repliable by any authenticated viewer (the app's audience-policy default);
|
|
1043
|
+
* a reply only by its branch participants (`{ creator, branch responder }`).
|
|
1044
|
+
*/
|
|
1045
|
+
canReply: z.ZodDefault<z.ZodBoolean>;
|
|
1046
|
+
/** Why `canReply` is false, when it is (omitted when the caller can reply). */
|
|
1047
|
+
replyDisabledReason: z.ZodOptional<z.ZodEnum<["unauthenticated", "not_a_participant"]>>;
|
|
1015
1048
|
}, "strip", z.ZodTypeAny, {
|
|
1016
1049
|
isAuthor: boolean;
|
|
1050
|
+
canReply: boolean;
|
|
1051
|
+
replyDisabledReason?: "unauthenticated" | "not_a_participant" | undefined;
|
|
1017
1052
|
}, {
|
|
1018
1053
|
isAuthor?: boolean | undefined;
|
|
1054
|
+
canReply?: boolean | undefined;
|
|
1055
|
+
replyDisabledReason?: "unauthenticated" | "not_a_participant" | undefined;
|
|
1019
1056
|
}>;
|
|
1020
1057
|
}, "strip", z.ZodTypeAny, {
|
|
1021
1058
|
uri: string;
|
|
1022
|
-
|
|
1023
|
-
createdAt: Date;
|
|
1024
|
-
text: string;
|
|
1025
|
-
title?: string | undefined;
|
|
1026
|
-
reply?: {
|
|
1027
|
-
root: {
|
|
1028
|
-
uri: string;
|
|
1029
|
-
cid: string;
|
|
1030
|
-
};
|
|
1031
|
-
parent: {
|
|
1032
|
-
uri: string;
|
|
1033
|
-
cid: string;
|
|
1034
|
-
};
|
|
1035
|
-
} | undefined;
|
|
1036
|
-
langs?: string[] | undefined;
|
|
1037
|
-
selfLabels?: string[] | undefined;
|
|
1038
|
-
};
|
|
1059
|
+
kind: "prompt" | "reply";
|
|
1039
1060
|
author: {
|
|
1040
1061
|
id: string;
|
|
1041
1062
|
handle?: string | null | undefined;
|
|
@@ -1060,9 +1081,27 @@ declare const AudioPostViewSchema: z.ZodObject<{
|
|
|
1060
1081
|
badges?: string[] | undefined;
|
|
1061
1082
|
isVerified?: boolean | undefined;
|
|
1062
1083
|
};
|
|
1063
|
-
|
|
1084
|
+
record: {
|
|
1085
|
+
createdAt: Date;
|
|
1086
|
+
text: string;
|
|
1087
|
+
reply?: {
|
|
1088
|
+
root: {
|
|
1089
|
+
uri: string;
|
|
1090
|
+
cid: string;
|
|
1091
|
+
};
|
|
1092
|
+
parent: {
|
|
1093
|
+
uri: string;
|
|
1094
|
+
cid: string;
|
|
1095
|
+
};
|
|
1096
|
+
} | undefined;
|
|
1097
|
+
title?: string | undefined;
|
|
1098
|
+
langs?: string[] | undefined;
|
|
1099
|
+
selfLabels?: string[] | undefined;
|
|
1100
|
+
};
|
|
1064
1101
|
viewer: {
|
|
1065
1102
|
isAuthor: boolean;
|
|
1103
|
+
canReply: boolean;
|
|
1104
|
+
replyDisabledReason?: "unauthenticated" | "not_a_participant" | undefined;
|
|
1066
1105
|
};
|
|
1067
1106
|
cid?: string | undefined;
|
|
1068
1107
|
embed?: {
|
|
@@ -1082,23 +1121,7 @@ declare const AudioPostViewSchema: z.ZodObject<{
|
|
|
1082
1121
|
} | undefined;
|
|
1083
1122
|
}, {
|
|
1084
1123
|
uri: string;
|
|
1085
|
-
|
|
1086
|
-
text: string;
|
|
1087
|
-
createdAt?: unknown;
|
|
1088
|
-
title?: string | undefined;
|
|
1089
|
-
reply?: {
|
|
1090
|
-
root: {
|
|
1091
|
-
uri: string;
|
|
1092
|
-
cid: string;
|
|
1093
|
-
};
|
|
1094
|
-
parent: {
|
|
1095
|
-
uri: string;
|
|
1096
|
-
cid: string;
|
|
1097
|
-
};
|
|
1098
|
-
} | undefined;
|
|
1099
|
-
langs?: string[] | undefined;
|
|
1100
|
-
selfLabels?: string[] | undefined;
|
|
1101
|
-
};
|
|
1124
|
+
kind: "prompt" | "reply";
|
|
1102
1125
|
author: {
|
|
1103
1126
|
id: string;
|
|
1104
1127
|
handle?: string | null | undefined;
|
|
@@ -1123,9 +1146,27 @@ declare const AudioPostViewSchema: z.ZodObject<{
|
|
|
1123
1146
|
badges?: string[] | undefined;
|
|
1124
1147
|
isVerified?: boolean | undefined;
|
|
1125
1148
|
};
|
|
1126
|
-
|
|
1149
|
+
record: {
|
|
1150
|
+
text: string;
|
|
1151
|
+
createdAt?: unknown;
|
|
1152
|
+
reply?: {
|
|
1153
|
+
root: {
|
|
1154
|
+
uri: string;
|
|
1155
|
+
cid: string;
|
|
1156
|
+
};
|
|
1157
|
+
parent: {
|
|
1158
|
+
uri: string;
|
|
1159
|
+
cid: string;
|
|
1160
|
+
};
|
|
1161
|
+
} | undefined;
|
|
1162
|
+
title?: string | undefined;
|
|
1163
|
+
langs?: string[] | undefined;
|
|
1164
|
+
selfLabels?: string[] | undefined;
|
|
1165
|
+
};
|
|
1127
1166
|
viewer: {
|
|
1128
1167
|
isAuthor?: boolean | undefined;
|
|
1168
|
+
canReply?: boolean | undefined;
|
|
1169
|
+
replyDisabledReason?: "unauthenticated" | "not_a_participant" | undefined;
|
|
1129
1170
|
};
|
|
1130
1171
|
cid?: string | undefined;
|
|
1131
1172
|
embed?: {
|
|
@@ -2,18 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
var zod = require('zod');
|
|
4
4
|
|
|
5
|
-
// types/records.ts
|
|
6
|
-
var BlobRefSchema = zod.z.object({
|
|
7
|
-
/** Discriminator for AT Protocol type system */
|
|
8
|
-
$type: zod.z.literal("blob"),
|
|
9
|
-
/** Content Identifier (CID) or URL pointing to the blob */
|
|
10
|
-
ref: zod.z.string(),
|
|
11
|
-
/** MIME type of the blob (e.g., 'audio/webm') */
|
|
12
|
-
mimeType: zod.z.string(),
|
|
13
|
-
/** Size of the blob in bytes */
|
|
14
|
-
size: zod.z.number()
|
|
15
|
-
});
|
|
16
|
-
|
|
17
5
|
// types/records.ts
|
|
18
6
|
function httpsUrl() {
|
|
19
7
|
return zod.z.string().trim().url().refine((u) => /^https?:\/\//i.test(u), {
|
|
@@ -57,11 +45,8 @@ var UserRecordSchema = zod.z.object({
|
|
|
57
45
|
handle: zod.z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]+$/).nullable().optional(),
|
|
58
46
|
/** User stated intent (e.g. "Podcaster", "Listener") */
|
|
59
47
|
usageIntent: zod.z.string().nullable().optional(),
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
* Defaults to 'voxpop.com'.
|
|
63
|
-
*/
|
|
64
|
-
domain: zod.z.string().default("voxpop.com"),
|
|
48
|
+
/** Domain for federated handle support. */
|
|
49
|
+
domain: zod.z.string().default("antiphony.dev"),
|
|
65
50
|
/**
|
|
66
51
|
* Display Name (e.g. "Brad Thorson"). Nullable: Firestore stores `null`
|
|
67
52
|
* when the user clears this field via the settings form, and the schema
|
|
@@ -89,319 +74,9 @@ var UserRecordSchema = zod.z.object({
|
|
|
89
74
|
/** Account status. Deactivated accounts retain data but are excluded from lookups. */
|
|
90
75
|
status: zod.z.enum(["active", "deactivated"]).default("active"),
|
|
91
76
|
/** Timestamp when the account was deactivated (soft deleted) */
|
|
92
|
-
deactivatedAt: FirestoreTimestampSchema.optional()
|
|
93
|
-
/**
|
|
94
|
-
* Denormalized org memberships — { orgId: role } for fast lookup.
|
|
95
|
-
* Source of truth is organizations/{orgId}/members/{userId}.
|
|
96
|
-
* Kept in sync by Cloud Function trigger.
|
|
97
|
-
*/
|
|
98
|
-
orgMemberships: zod.z.record(zod.z.string(), zod.z.enum(["owner", "admin", "member"])).optional()
|
|
99
|
-
});
|
|
100
|
-
var PromptRecordSchema = zod.z.object({
|
|
101
|
-
/** Unique Prompt ID */
|
|
102
|
-
id: zod.z.string(),
|
|
103
|
-
/** ID of the User who created this prompt. Always a user ID, never an org ID. @see UserRecord */
|
|
104
|
-
authorId: zod.z.string(),
|
|
105
|
-
/** Organization context this prompt belongs to (null = personal/no org) */
|
|
106
|
-
orgId: zod.z.string().nullable().optional(),
|
|
107
|
-
/** The main text of the question/prompt */
|
|
108
|
-
title: zod.z.string().min(3),
|
|
109
|
-
/** Optional extra context */
|
|
110
|
-
description: zod.z.string().nullable().optional(),
|
|
111
|
-
/** User who created this prompt (differs from authorId when org-owned) */
|
|
112
|
-
createdBy: zod.z.string().optional(),
|
|
113
|
-
/** URL to the recorded audio file (GCS) */
|
|
114
|
-
audioUrl: zod.z.string().url().or(zod.z.literal("")),
|
|
115
|
-
/** AT Protocol blob reference (future replacement for audioUrl) */
|
|
116
|
-
audio: BlobRefSchema.optional(),
|
|
117
|
-
/**
|
|
118
|
-
* AT Protocol URI returned by the publisher after a successful
|
|
119
|
-
* `repo.putRecord` against the author's PDS — e.g.
|
|
120
|
-
* `at://did:plc:abc123/com.voxpop.audio.prompt/3kj4...`. Optional,
|
|
121
|
-
* no migration: existing rows leave it unset. Format-validated so
|
|
122
|
-
* malformed strings surface at the schema-parse boundary rather than
|
|
123
|
-
* being silently stored.
|
|
124
|
-
*/
|
|
125
|
-
atprotoUri: zod.z.string().regex(/^at:\/\/.+/).optional(),
|
|
126
|
-
/** Server timestamp of creation */
|
|
127
|
-
createdAt: FirestoreTimestampSchema,
|
|
128
|
-
/**
|
|
129
|
-
* Life-cycle status.
|
|
130
|
-
* - `live`: Visible and accepting replies.
|
|
131
|
-
* - `archived`: Visible but closed for new replies.
|
|
132
|
-
* - `deleted`: Soft deleted.
|
|
133
|
-
*/
|
|
134
|
-
status: zod.z.enum(["live", "archived", "deleted"]).default("live"),
|
|
135
|
-
/** AI Enrichment Fields */
|
|
136
|
-
aiStatus: zod.z.enum(["pending", "complete", "error"]).optional(),
|
|
137
|
-
aiError: zod.z.string().optional(),
|
|
138
|
-
aiSummary: zod.z.string().optional(),
|
|
139
|
-
aiLabels: zod.z.array(zod.z.string()).optional(),
|
|
140
|
-
transcription: zod.z.string().optional(),
|
|
141
|
-
/** Pre-computed waveform peaks (normalized 0–1) for instant audio visualization */
|
|
142
|
-
waveformPeaks: zod.z.array(zod.z.number()).optional(),
|
|
143
|
-
/** Social Share Video Fields */
|
|
144
|
-
socialVideoUrl: zod.z.string().url().optional(),
|
|
145
|
-
socialVideoStoragePath: zod.z.string().optional(),
|
|
146
|
-
socialVideoStatus: zod.z.enum(["pending", "complete", "error"]).optional(),
|
|
147
|
-
socialVideoError: zod.z.string().optional(),
|
|
148
|
-
/** The audio URL/path used to generate the current video (for cache invalidation) */
|
|
149
|
-
socialVideoSourceAudio: zod.z.string().optional()
|
|
150
|
-
});
|
|
151
|
-
var ReplyRecordSchema = zod.z.object({
|
|
152
|
-
/** Unique Reply ID */
|
|
153
|
-
id: zod.z.string(),
|
|
154
|
-
/** The Prompt being replied to. @see PromptRecord */
|
|
155
|
-
promptId: zod.z.string(),
|
|
156
|
-
/** The User who replied. @see UserRecord */
|
|
157
|
-
authorId: zod.z.string(),
|
|
158
|
-
/** URL to the recorded audio file (GCS) */
|
|
159
|
-
audioUrl: zod.z.string().url(),
|
|
160
|
-
/** AT Protocol blob reference (future replacement for audioUrl) */
|
|
161
|
-
audio: BlobRefSchema.optional(),
|
|
162
|
-
/** Server timestamp of creation */
|
|
163
|
-
createdAt: FirestoreTimestampSchema,
|
|
164
|
-
/**
|
|
165
|
-
* Life-cycle status.
|
|
166
|
-
* - `live`: Visible and accepting replies.
|
|
167
|
-
* - `archived`: Visible but closed for new replies.
|
|
168
|
-
* - `deleted`: Soft deleted.
|
|
169
|
-
*/
|
|
170
|
-
status: zod.z.enum(["live", "archived", "deleted"]).default("live"),
|
|
171
|
-
/**
|
|
172
|
-
* Pre-computed waveform peaks (normalized 0–1) for instant audio
|
|
173
|
-
* visualization. **Stays on canonical** (does NOT move to the
|
|
174
|
-
* enrichment doc) — produced by a plain ffmpeg pass at ingestion,
|
|
175
|
-
* not an AI step; a self-hoster without paid-tier AI still needs
|
|
176
|
-
* this on every reply for the audio player. See
|
|
177
|
-
* `specs/ai-enrichment-split.md` § 5.
|
|
178
|
-
*/
|
|
179
|
-
waveformPeaks: zod.z.array(zod.z.number()).optional(),
|
|
180
|
-
/**
|
|
181
|
-
* Duration of the audio in seconds, computed server-side from
|
|
182
|
-
* ffmpeg. **Stays on canonical** (same reasoning as `waveformPeaks`
|
|
183
|
-
* above — ingestion ffmpeg output, not an AI enrichment). See
|
|
184
|
-
* `specs/ai-enrichment-split.md` § 5.
|
|
185
|
-
*/
|
|
186
|
-
audioDurationSec: zod.z.number().optional()
|
|
187
|
-
});
|
|
188
|
-
var ReplyEnrichmentRecordSchema = zod.z.object({
|
|
189
|
-
id: zod.z.string(),
|
|
190
|
-
/** Private notes by the prompt author about this reply. */
|
|
191
|
-
notes: zod.z.string().optional(),
|
|
192
|
-
// === AI-enrichment fields (sole source of truth post Stage 4) ===
|
|
193
|
-
//
|
|
194
|
-
// These lifted off canonical in Stage 4 of `specs/ai-enrichment-split.md`.
|
|
195
|
-
// Writers (`functions/`) route AI updates here via the split-write
|
|
196
|
-
// helper in `functions/src/services/replyEnrichmentDualWrite.ts`;
|
|
197
|
-
// readers source them via the hydrator's enrichment branch (see
|
|
198
|
-
// `packages/core/services/hydration.ts`).
|
|
199
|
-
// --- AI core (Gemini-generated) ---
|
|
200
|
-
aiStatus: zod.z.enum(["pending", "complete", "error", "skipped_too_short"]).optional(),
|
|
201
|
-
aiError: zod.z.string().optional(),
|
|
202
|
-
aiSummary: zod.z.string().optional(),
|
|
203
|
-
aiLabels: zod.z.array(zod.z.string()).optional(),
|
|
204
|
-
transcription: zod.z.string().optional(),
|
|
205
|
-
sentiment: zod.z.enum(["Positive", "Negative", "Neutral"]).optional(),
|
|
206
|
-
/** Must match the widened enum in `ReplyRecordSchema.energyLevel`. */
|
|
207
|
-
energyLevel: zod.z.enum(["High", "Low", "Neutral"]).optional(),
|
|
208
|
-
engagementScore: zod.z.number().min(1).max(10).optional(),
|
|
209
|
-
// --- Voice isolation (ElevenLabs, paid tier) ---
|
|
210
|
-
/** Noise-reduced audio URL — replaces `audioUrl` for downstream players when present. PUBLIC. */
|
|
211
|
-
enhancedAudioUrl: zod.z.string().url().optional(),
|
|
212
|
-
/** Storage path companion to `enhancedAudioUrl` — private. */
|
|
213
|
-
enhancedStoragePath: zod.z.string().optional(),
|
|
214
|
-
// --- Social-share video (paid tier) ---
|
|
215
|
-
//
|
|
216
|
-
// All `socialVideo*` fields are creator-only. The URL points at the
|
|
217
|
-
// generated artifact (a video file the creator can download and post
|
|
218
|
-
// to social media); the reply detail page does NOT render it.
|
|
219
|
-
socialVideoUrl: zod.z.string().url().optional(),
|
|
220
|
-
socialVideoStoragePath: zod.z.string().optional(),
|
|
221
|
-
socialVideoStatus: zod.z.enum(["pending", "complete", "error"]).optional(),
|
|
222
|
-
socialVideoError: zod.z.string().optional(),
|
|
223
|
-
/** The audio URL/path used to generate the current video (for cache invalidation). */
|
|
224
|
-
socialVideoSourceAudio: zod.z.string().optional()
|
|
225
|
-
});
|
|
226
|
-
var PersonEnrichmentRecordSchema = zod.z.object({
|
|
227
|
-
/** Composite key `${viewerUid}_${targetUid}`. */
|
|
228
|
-
id: zod.z.string(),
|
|
229
|
-
/** Per-viewer CRM notes about the target. */
|
|
230
|
-
notes: zod.z.string().optional(),
|
|
231
|
-
/** Per-viewer freeform tags about the target. */
|
|
232
|
-
tags: zod.z.array(zod.z.string()).optional(),
|
|
233
|
-
// === Identity-merge: alias set ===
|
|
234
|
-
//
|
|
235
|
-
// Other identifiers the viewer has declared to be the SAME person as
|
|
236
|
-
// this entry's `targetUid`. vCard/URI-aligned: each entry is a
|
|
237
|
-
// scheme-prefixed identifier, so one field generalizes across networks
|
|
238
|
-
// AND across the future contact-sync import (which carries phone/email):
|
|
239
|
-
// "uid:<firebaseUid>" | "did:plc:…" | "handle:bob.bsky.social"
|
|
240
|
-
// | "tel:+15551234567" | "mailto:x@example.com"
|
|
241
|
-
// Mirrors vCard 4.0's `UID` + `CLIENTPIDMAP`/`PID` source-tracking
|
|
242
|
-
// (RFC 6350) — the standard answer to "the same person from multiple
|
|
243
|
-
// sources". See `specs/people-lexicon-prior-art.md`. The People
|
|
244
|
-
// read-path collapses any replier whose "uid:<uid>" appears here into
|
|
245
|
-
// this primary entry. Empty until the merge feature is used.
|
|
246
|
-
aliases: zod.z.array(zod.z.string()).optional(),
|
|
247
|
-
lastUpdated: FirestoreTimestampSchema.optional()
|
|
248
|
-
});
|
|
249
|
-
var SipEnrichmentSchema = zod.z.object({
|
|
250
|
-
sipUri: zod.z.string(),
|
|
251
|
-
sipUsername: zod.z.string(),
|
|
252
|
-
sipSecret: zod.z.string(),
|
|
253
|
-
provider: zod.z.enum(["twilio", "plivo", "internal"])
|
|
254
|
-
});
|
|
255
|
-
var CallForwardingConfigSchema = zod.z.object({
|
|
256
|
-
/** User's personal phone number (E.164) */
|
|
257
|
-
phoneNumber: zod.z.string(),
|
|
258
|
-
/** Line type from Twilio Lookup v2 */
|
|
259
|
-
lineType: zod.z.string().nullable(),
|
|
260
|
-
/** Carrier name from Twilio Lookup v2 */
|
|
261
|
-
carrier: zod.z.string().nullable(),
|
|
262
|
-
/** free = shared Twilio number (ForwardedFrom routing), paid = dedicated number */
|
|
263
|
-
tier: zod.z.enum(["free", "paid"]),
|
|
264
|
-
/** The VoxPop Twilio number calls forward to (E.164) */
|
|
265
|
-
voxpopNumber: zod.z.string(),
|
|
266
|
-
/** Twilio Phone Number SID (paid tier only) */
|
|
267
|
-
twilioNumberSid: zod.z.string().nullable().optional(),
|
|
268
|
-
/** Forwarding verification state */
|
|
269
|
-
verificationStatus: zod.z.enum(["pending", "verifying", "verified", "failed"]).default("pending"),
|
|
270
|
-
/** Last verification attempt timestamp */
|
|
271
|
-
lastVerificationAt: FirestoreTimestampSchema.optional(),
|
|
272
|
-
/** Number of verification attempts */
|
|
273
|
-
verificationAttempts: zod.z.number().default(0),
|
|
274
|
-
/** Reason for verification failure */
|
|
275
|
-
failureReason: zod.z.string().nullable().optional(),
|
|
276
|
-
/** Whether call forwarding is active */
|
|
277
|
-
enabled: zod.z.boolean().default(false),
|
|
278
|
-
createdAt: FirestoreTimestampSchema,
|
|
279
|
-
updatedAt: FirestoreTimestampSchema
|
|
280
|
-
});
|
|
281
|
-
var ConnectorTypeSchema = zod.z.enum(["telephony"]);
|
|
282
|
-
var ConnectorStatusSchema = zod.z.object({
|
|
283
|
-
/** Coarse, generic lifecycle the control-plane UI can render without
|
|
284
|
-
* connector-specific knowledge. */
|
|
285
|
-
state: zod.z.enum(["unconfigured", "pending", "active", "error", "disabled"]).default("unconfigured"),
|
|
286
|
-
detail: zod.z.string().nullable().optional(),
|
|
287
|
-
/** Opaque, connector-specific status detail (e.g. telephony's
|
|
288
|
-
* `{ verificationStatus, verificationAttempts, failureReason }`). Connector-
|
|
289
|
-
* owned like the rest of `status` — never user-writable. Nullable so a doc
|
|
290
|
-
* that stored `data: null` round-trips without a parse error. */
|
|
291
|
-
data: zod.z.record(zod.z.unknown()).nullable().optional(),
|
|
292
|
-
updatedAt: FirestoreTimestampSchema.optional()
|
|
293
|
-
});
|
|
294
|
-
var ConnectorConfigRecordSchema = zod.z.object({
|
|
295
|
-
connectorType: ConnectorTypeSchema,
|
|
296
|
-
/** The owning user. Org-scoping (ownerId as an orgId) is a later step. */
|
|
297
|
-
ownerId: zod.z.string(),
|
|
298
|
-
/** Opaque, connector-specific blob. Core does not interpret this. */
|
|
299
|
-
settings: zod.z.record(zod.z.unknown()).default({}),
|
|
300
|
-
/** Reference into a secret store (e.g. Secret Manager key). Never a raw secret. */
|
|
301
|
-
secretRef: zod.z.string().nullable().optional(),
|
|
302
|
-
enabled: zod.z.boolean().default(false),
|
|
303
|
-
status: ConnectorStatusSchema.default({ state: "unconfigured" }),
|
|
304
|
-
createdAt: FirestoreTimestampSchema,
|
|
305
|
-
updatedAt: FirestoreTimestampSchema
|
|
306
|
-
});
|
|
307
|
-
var ScreeningRuleRecordSchema = zod.z.object({
|
|
308
|
-
id: zod.z.string(),
|
|
309
|
-
ownerId: zod.z.string(),
|
|
310
|
-
/** The caller number this rule matches (E.164). Format-enforced at the
|
|
311
|
-
* record level so any writer (API, future contact-sync/callback) can't
|
|
312
|
-
* persist a malformed number. */
|
|
313
|
-
e164: zod.z.string().regex(/^\+[1-9]\d{6,14}$/, "Must be an E.164 phone number"),
|
|
314
|
-
/** Display label, e.g. "Mom" / "Delta Airlines". null = unlabeled. */
|
|
315
|
-
label: zod.z.string().nullable().optional(),
|
|
316
|
-
/** `allow` = ring through; `screen` = async voicemail. */
|
|
317
|
-
action: zod.z.enum(["allow", "screen"]),
|
|
318
|
-
/** Provenance. `manual` = user-created; the others are future writers. */
|
|
319
|
-
source: zod.z.enum(["manual", "contact-sync", "callback"]),
|
|
320
|
-
/** null = permanent; a date = self-expiring exception. */
|
|
321
|
-
expiresAt: FirestoreTimestampSchema.nullable().optional(),
|
|
322
|
-
createdAt: FirestoreTimestampSchema
|
|
323
|
-
});
|
|
324
|
-
var OrganizationRecordSchema = zod.z.object({
|
|
325
|
-
id: zod.z.string(),
|
|
326
|
-
/** Display name of the organization */
|
|
327
|
-
name: zod.z.string().min(3).max(50),
|
|
328
|
-
/**
|
|
329
|
-
* Unique handle for the organization (e.g. voxpop.com/@mypodcast).
|
|
330
|
-
* Used for public URLs.
|
|
331
|
-
*/
|
|
332
|
-
slug: zod.z.string().min(3).max(30).regex(/^[a-z0-9-]+$/),
|
|
333
|
-
/** URL to avatar/logo */
|
|
334
|
-
avatarUrl: zod.z.string().url().optional(),
|
|
335
|
-
/** URL to the podcast RSS feed */
|
|
336
|
-
rssFeedUrl: zod.z.string().url().optional(),
|
|
337
|
-
/** External website URL */
|
|
338
|
-
websiteUrl: httpsUrl().optional(),
|
|
339
|
-
/** Description or tagline */
|
|
340
|
-
description: zod.z.string().optional(),
|
|
341
|
-
/** Owner ID (User ID) */
|
|
342
|
-
ownerId: zod.z.string(),
|
|
343
|
-
/** Server timestamp of creation */
|
|
344
|
-
createdAt: FirestoreTimestampSchema,
|
|
345
|
-
/** Verified domain (e.g., "acme.com") — enables auto-join, enterprise features */
|
|
346
|
-
domain: zod.z.string().nullable().optional(),
|
|
347
|
-
/** Whether the domain has been verified via DNS TXT record */
|
|
348
|
-
domainVerified: zod.z.boolean().default(false),
|
|
349
|
-
/** DNS verification token (stored server-side until verification completes) */
|
|
350
|
-
domainVerificationToken: zod.z.string().optional(),
|
|
351
|
-
/** Billing email — required for paid orgs, where invoices go */
|
|
352
|
-
billingEmail: zod.z.string().email().nullable().optional(),
|
|
353
|
-
/**
|
|
354
|
-
* Tier determines isolation and feature set. Orgs are meant to be paid
|
|
355
|
-
* (business or enterprise); free/pro exist on the enum for the individual track.
|
|
356
|
-
* Default is provisionally `business` (the entry paid tier) — it's assigned at
|
|
357
|
-
* creation with no subscription behind it yet, so it stays provisional until billing
|
|
358
|
-
* promotes/reconciles the org. See docs/tech-debt.md "Org tier billing reconciliation".
|
|
359
|
-
*/
|
|
360
|
-
tier: zod.z.enum(["free", "pro", "business", "enterprise"]).default("business"),
|
|
361
|
-
/** Stripe Customer ID */
|
|
362
|
-
stripeCustomerId: zod.z.string().optional(),
|
|
363
|
-
/** Subscription Status */
|
|
364
|
-
subscriptionStatus: zod.z.enum(["active", "trialing", "past_due", "canceled", "unpaid"]).optional()
|
|
365
|
-
});
|
|
366
|
-
var OrganizationMemberRecordSchema = zod.z.object({
|
|
367
|
-
orgId: zod.z.string(),
|
|
368
|
-
userId: zod.z.string(),
|
|
369
|
-
/** Role in the organization */
|
|
370
|
-
role: zod.z.enum(["owner", "admin", "member"]),
|
|
371
|
-
/** Server timestamp of joining */
|
|
372
|
-
joinedAt: FirestoreTimestampSchema,
|
|
373
|
-
invitedBy: zod.z.string().optional()
|
|
374
|
-
});
|
|
375
|
-
var OrgInviteRecordSchema = zod.z.object({
|
|
376
|
-
id: zod.z.string(),
|
|
377
|
-
orgId: zod.z.string(),
|
|
378
|
-
/** Email the invite was sent to */
|
|
379
|
-
email: zod.z.string().email(),
|
|
380
|
-
/** Role to assign on acceptance */
|
|
381
|
-
role: zod.z.enum(["admin", "member"]),
|
|
382
|
-
/** User ID of who sent the invite */
|
|
383
|
-
invitedBy: zod.z.string(),
|
|
384
|
-
/** Invite lifecycle status */
|
|
385
|
-
status: zod.z.enum(["pending", "accepted", "expired", "revoked"]).default("pending"),
|
|
386
|
-
/** Server timestamp of creation */
|
|
387
|
-
createdAt: FirestoreTimestampSchema,
|
|
388
|
-
/** When this invite expires */
|
|
389
|
-
expiresAt: FirestoreTimestampSchema
|
|
77
|
+
deactivatedAt: FirestoreTimestampSchema.optional()
|
|
390
78
|
});
|
|
391
79
|
|
|
392
|
-
exports.CallForwardingConfigSchema = CallForwardingConfigSchema;
|
|
393
|
-
exports.ConnectorConfigRecordSchema = ConnectorConfigRecordSchema;
|
|
394
|
-
exports.ConnectorStatusSchema = ConnectorStatusSchema;
|
|
395
|
-
exports.ConnectorTypeSchema = ConnectorTypeSchema;
|
|
396
80
|
exports.FirestoreTimestampSchema = FirestoreTimestampSchema;
|
|
397
|
-
exports.OrgInviteRecordSchema = OrgInviteRecordSchema;
|
|
398
|
-
exports.OrganizationMemberRecordSchema = OrganizationMemberRecordSchema;
|
|
399
|
-
exports.OrganizationRecordSchema = OrganizationRecordSchema;
|
|
400
|
-
exports.PersonEnrichmentRecordSchema = PersonEnrichmentRecordSchema;
|
|
401
|
-
exports.PromptRecordSchema = PromptRecordSchema;
|
|
402
|
-
exports.ReplyEnrichmentRecordSchema = ReplyEnrichmentRecordSchema;
|
|
403
|
-
exports.ReplyRecordSchema = ReplyRecordSchema;
|
|
404
|
-
exports.ScreeningRuleRecordSchema = ScreeningRuleRecordSchema;
|
|
405
|
-
exports.SipEnrichmentSchema = SipEnrichmentSchema;
|
|
406
81
|
exports.UserRecordSchema = UserRecordSchema;
|
|
407
82
|
exports.httpsUrl = httpsUrl;
|