@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
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import '../chunk-ORMEWXMH.js';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
var ChannelTypeSchema = z.enum([
|
|
5
|
-
// inbound
|
|
6
|
-
"web-capture",
|
|
7
|
-
"phone",
|
|
8
|
-
"bluesky-replies",
|
|
9
|
-
// outbound
|
|
10
|
-
"bluesky-publishing",
|
|
11
|
-
"phone-voicemail",
|
|
12
|
-
"rss",
|
|
13
|
-
"embed",
|
|
14
|
-
"sms-invites"
|
|
15
|
-
]);
|
|
16
|
-
var ChannelDirectionSchema = z.enum(["inbound", "outbound", "bidirectional"]);
|
|
17
|
-
var ChannelStateSchema = z.enum([
|
|
18
|
-
"active",
|
|
19
|
-
"pending",
|
|
20
|
-
"disabled",
|
|
21
|
-
"unconfigured",
|
|
22
|
-
"error",
|
|
23
|
-
"coming-soon"
|
|
24
|
-
]);
|
|
25
|
-
var ChannelViewSchema = z.object({
|
|
26
|
-
type: ChannelTypeSchema,
|
|
27
|
-
direction: ChannelDirectionSchema,
|
|
28
|
-
/** Human label, e.g. "Phone", "Bluesky publishing". */
|
|
29
|
-
label: z.string(),
|
|
30
|
-
/** One-line explanation rendered under the label. */
|
|
31
|
-
description: z.string(),
|
|
32
|
-
/** Generic lifecycle state the UI renders as a status pill. */
|
|
33
|
-
state: ChannelStateSchema,
|
|
34
|
-
/** Channel-specific human detail (e.g. a verification failure reason). */
|
|
35
|
-
statusDetail: z.string().nullable().optional(),
|
|
36
|
-
/** Whether the channel is currently switched on for this user. */
|
|
37
|
-
enabled: z.boolean(),
|
|
38
|
-
/** Always-on surfaces (web capture, RSS, embed) — no real disable. */
|
|
39
|
-
alwaysOn: z.boolean(),
|
|
40
|
-
/** Whether there's a per-channel config screen to open. */
|
|
41
|
-
configurable: z.boolean(),
|
|
42
|
-
/** Requires a paid tier to use (see `docs/feature-gates.md`). */
|
|
43
|
-
gated: z.boolean(),
|
|
44
|
-
/**
|
|
45
|
-
* A prerequisite that must be satisfied elsewhere before this channel works,
|
|
46
|
-
* e.g. `'bluesky-identity'` for Bluesky publishing. Null when self-contained.
|
|
47
|
-
*/
|
|
48
|
-
dependsOn: z.string().nullable().optional()
|
|
49
|
-
});
|
|
50
|
-
var ChannelsResponseSchema = z.object({
|
|
51
|
-
inbound: z.array(ChannelViewSchema),
|
|
52
|
-
outbound: z.array(ChannelViewSchema)
|
|
53
|
-
});
|
|
54
|
-
var CHANNEL_DESCRIPTORS = [
|
|
55
|
-
// ── Inbound ──────────────────────────────────────────────────────────
|
|
56
|
-
{
|
|
57
|
-
type: "web-capture",
|
|
58
|
-
direction: "inbound",
|
|
59
|
-
label: "Web capture",
|
|
60
|
-
description: "Replies left on your public prompt page and embedded widgets.",
|
|
61
|
-
alwaysOn: true,
|
|
62
|
-
configurable: false,
|
|
63
|
-
gated: false,
|
|
64
|
-
dependsOn: null,
|
|
65
|
-
comingSoon: false
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
type: "phone",
|
|
69
|
-
direction: "inbound",
|
|
70
|
-
// Inbound voice. Call forwarding and the SIP address are two ingress
|
|
71
|
-
// addresses of this one channel, not separate channels — both deliver a
|
|
72
|
-
// voice reply to the same inbox over the same telephony substrate.
|
|
73
|
-
label: "Phone",
|
|
74
|
-
description: "Forward calls \u2014 or point a VoIP softphone (SIP) \u2014 at your Vox Pop inbox.",
|
|
75
|
-
alwaysOn: false,
|
|
76
|
-
configurable: true,
|
|
77
|
-
gated: false,
|
|
78
|
-
dependsOn: null,
|
|
79
|
-
comingSoon: false
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
type: "bluesky-replies",
|
|
83
|
-
direction: "inbound",
|
|
84
|
-
label: "Bluesky replies",
|
|
85
|
-
description: "Pull replies and mentions from Bluesky into your inbox.",
|
|
86
|
-
alwaysOn: false,
|
|
87
|
-
configurable: false,
|
|
88
|
-
gated: false,
|
|
89
|
-
dependsOn: "bluesky-identity",
|
|
90
|
-
comingSoon: true
|
|
91
|
-
},
|
|
92
|
-
// ── Outbound ─────────────────────────────────────────────────────────
|
|
93
|
-
{
|
|
94
|
-
type: "bluesky-publishing",
|
|
95
|
-
direction: "outbound",
|
|
96
|
-
label: "Bluesky publishing",
|
|
97
|
-
description: "Publish your prompts to Bluesky.",
|
|
98
|
-
alwaysOn: false,
|
|
99
|
-
configurable: true,
|
|
100
|
-
gated: false,
|
|
101
|
-
dependsOn: "bluesky-identity",
|
|
102
|
-
comingSoon: false
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
type: "phone-voicemail",
|
|
106
|
-
direction: "outbound",
|
|
107
|
-
// The outbound face of telephony: when a caller reaches the line, the
|
|
108
|
-
// IVR plays the creator's inbox prompt as the voicemail greeting and
|
|
109
|
-
// offers their live prompts as keypad options (apps/telephony
|
|
110
|
-
// IvrService). That is the creator's prompt distributed by phone — a
|
|
111
|
-
// genuine outbound surface, not a coming-soon placeholder. Config (the
|
|
112
|
-
// greeting = the inbox prompt) is managed via prompts, so no inline
|
|
113
|
-
// Configure screen yet → configurable:false for now.
|
|
114
|
-
label: "Phone voicemail",
|
|
115
|
-
description: "Callers hear your prompt as the voicemail greeting, then leave a reply.",
|
|
116
|
-
alwaysOn: false,
|
|
117
|
-
configurable: false,
|
|
118
|
-
gated: false,
|
|
119
|
-
dependsOn: null,
|
|
120
|
-
comingSoon: false
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
type: "rss",
|
|
124
|
-
direction: "outbound",
|
|
125
|
-
label: "RSS feed",
|
|
126
|
-
description: "A podcast-ready feed of your prompts and replies.",
|
|
127
|
-
alwaysOn: true,
|
|
128
|
-
configurable: false,
|
|
129
|
-
gated: false,
|
|
130
|
-
dependsOn: null,
|
|
131
|
-
comingSoon: false
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
type: "embed",
|
|
135
|
-
direction: "outbound",
|
|
136
|
-
label: "Embed widget",
|
|
137
|
-
description: "Drop a capture widget onto your own site.",
|
|
138
|
-
alwaysOn: true,
|
|
139
|
-
configurable: false,
|
|
140
|
-
gated: false,
|
|
141
|
-
dependsOn: null,
|
|
142
|
-
comingSoon: false
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
type: "sms-invites",
|
|
146
|
-
direction: "outbound",
|
|
147
|
-
label: "SMS invites",
|
|
148
|
-
description: "Text a prompt link to your audience.",
|
|
149
|
-
alwaysOn: false,
|
|
150
|
-
configurable: true,
|
|
151
|
-
gated: true,
|
|
152
|
-
dependsOn: null,
|
|
153
|
-
comingSoon: true
|
|
154
|
-
}
|
|
155
|
-
];
|
|
156
|
-
function getChannelDescriptor(type) {
|
|
157
|
-
const d = CHANNEL_DESCRIPTORS.find((c) => c.type === type);
|
|
158
|
-
if (!d) throw new Error(`No channel descriptor for type: ${type}`);
|
|
159
|
-
return d;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export { CHANNEL_DESCRIPTORS, ChannelDirectionSchema, ChannelStateSchema, ChannelTypeSchema, ChannelViewSchema, ChannelsResponseSchema, getChannelDescriptor };
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
declare const PromptDocumentSchema: z.ZodObject<{
|
|
4
|
-
id: z.ZodString;
|
|
5
|
-
authorId: z.ZodString;
|
|
6
|
-
orgId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
7
|
-
title: z.ZodString;
|
|
8
|
-
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
9
|
-
createdBy: z.ZodOptional<z.ZodString>;
|
|
10
|
-
audioUrl: z.ZodUnion<[z.ZodString, z.ZodLiteral<"">]>;
|
|
11
|
-
audio: z.ZodOptional<z.ZodObject<{
|
|
12
|
-
$type: z.ZodLiteral<"blob">;
|
|
13
|
-
ref: z.ZodString;
|
|
14
|
-
mimeType: z.ZodString;
|
|
15
|
-
size: z.ZodNumber;
|
|
16
|
-
}, "strip", z.ZodTypeAny, {
|
|
17
|
-
$type: "blob";
|
|
18
|
-
ref: string;
|
|
19
|
-
mimeType: string;
|
|
20
|
-
size: number;
|
|
21
|
-
}, {
|
|
22
|
-
$type: "blob";
|
|
23
|
-
ref: string;
|
|
24
|
-
mimeType: string;
|
|
25
|
-
size: number;
|
|
26
|
-
}>>;
|
|
27
|
-
atprotoUri: z.ZodOptional<z.ZodString>;
|
|
28
|
-
createdAt: z.ZodEffects<z.ZodUnion<[z.ZodType<unknown, z.ZodTypeDef, unknown>, z.ZodString, z.ZodNumber, z.ZodDate]>, Date, unknown>;
|
|
29
|
-
status: z.ZodDefault<z.ZodEnum<["live", "archived", "deleted"]>>;
|
|
30
|
-
aiStatus: z.ZodOptional<z.ZodEnum<["pending", "complete", "error"]>>;
|
|
31
|
-
aiError: z.ZodOptional<z.ZodString>;
|
|
32
|
-
aiSummary: z.ZodOptional<z.ZodString>;
|
|
33
|
-
aiLabels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
34
|
-
transcription: z.ZodOptional<z.ZodString>;
|
|
35
|
-
waveformPeaks: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
|
|
36
|
-
socialVideoUrl: z.ZodOptional<z.ZodString>;
|
|
37
|
-
socialVideoStoragePath: z.ZodOptional<z.ZodString>;
|
|
38
|
-
socialVideoStatus: z.ZodOptional<z.ZodEnum<["pending", "complete", "error"]>>;
|
|
39
|
-
socialVideoError: z.ZodOptional<z.ZodString>;
|
|
40
|
-
socialVideoSourceAudio: z.ZodOptional<z.ZodString>;
|
|
41
|
-
} & {
|
|
42
|
-
replyCount: z.ZodDefault<z.ZodNumber>;
|
|
43
|
-
lastReplyAt: z.ZodOptional<z.ZodEffects<z.ZodUnion<[z.ZodType<unknown, z.ZodTypeDef, unknown>, z.ZodString, z.ZodNumber, z.ZodDate]>, Date, unknown>>;
|
|
44
|
-
engagementScoreSum: z.ZodDefault<z.ZodNumber>;
|
|
45
|
-
engagementScoreCount: z.ZodDefault<z.ZodNumber>;
|
|
46
|
-
sentimentCounts: z.ZodDefault<z.ZodObject<{
|
|
47
|
-
positive: z.ZodDefault<z.ZodNumber>;
|
|
48
|
-
neutral: z.ZodDefault<z.ZodNumber>;
|
|
49
|
-
negative: z.ZodDefault<z.ZodNumber>;
|
|
50
|
-
}, "strip", z.ZodTypeAny, {
|
|
51
|
-
positive: number;
|
|
52
|
-
neutral: number;
|
|
53
|
-
negative: number;
|
|
54
|
-
}, {
|
|
55
|
-
positive?: number | undefined;
|
|
56
|
-
neutral?: number | undefined;
|
|
57
|
-
negative?: number | undefined;
|
|
58
|
-
}>>;
|
|
59
|
-
}, "strip", z.ZodTypeAny, {
|
|
60
|
-
id: string;
|
|
61
|
-
authorId: string;
|
|
62
|
-
title: string;
|
|
63
|
-
audioUrl: string;
|
|
64
|
-
status: "live" | "archived" | "deleted";
|
|
65
|
-
createdAt: Date;
|
|
66
|
-
replyCount: number;
|
|
67
|
-
engagementScoreSum: number;
|
|
68
|
-
engagementScoreCount: number;
|
|
69
|
-
sentimentCounts: {
|
|
70
|
-
positive: number;
|
|
71
|
-
neutral: number;
|
|
72
|
-
negative: number;
|
|
73
|
-
};
|
|
74
|
-
orgId?: string | null | undefined;
|
|
75
|
-
description?: string | null | undefined;
|
|
76
|
-
createdBy?: string | undefined;
|
|
77
|
-
audio?: {
|
|
78
|
-
$type: "blob";
|
|
79
|
-
ref: string;
|
|
80
|
-
mimeType: string;
|
|
81
|
-
size: number;
|
|
82
|
-
} | undefined;
|
|
83
|
-
atprotoUri?: string | undefined;
|
|
84
|
-
aiStatus?: "pending" | "complete" | "error" | undefined;
|
|
85
|
-
aiError?: string | undefined;
|
|
86
|
-
aiSummary?: string | undefined;
|
|
87
|
-
aiLabels?: string[] | undefined;
|
|
88
|
-
transcription?: string | undefined;
|
|
89
|
-
waveformPeaks?: number[] | undefined;
|
|
90
|
-
socialVideoUrl?: string | undefined;
|
|
91
|
-
socialVideoStoragePath?: string | undefined;
|
|
92
|
-
socialVideoStatus?: "pending" | "complete" | "error" | undefined;
|
|
93
|
-
socialVideoError?: string | undefined;
|
|
94
|
-
socialVideoSourceAudio?: string | undefined;
|
|
95
|
-
lastReplyAt?: Date | undefined;
|
|
96
|
-
}, {
|
|
97
|
-
id: string;
|
|
98
|
-
authorId: string;
|
|
99
|
-
title: string;
|
|
100
|
-
audioUrl: string;
|
|
101
|
-
orgId?: string | null | undefined;
|
|
102
|
-
description?: string | null | undefined;
|
|
103
|
-
createdBy?: string | undefined;
|
|
104
|
-
status?: "live" | "archived" | "deleted" | undefined;
|
|
105
|
-
audio?: {
|
|
106
|
-
$type: "blob";
|
|
107
|
-
ref: string;
|
|
108
|
-
mimeType: string;
|
|
109
|
-
size: number;
|
|
110
|
-
} | undefined;
|
|
111
|
-
atprotoUri?: string | undefined;
|
|
112
|
-
createdAt?: unknown;
|
|
113
|
-
aiStatus?: "pending" | "complete" | "error" | undefined;
|
|
114
|
-
aiError?: string | undefined;
|
|
115
|
-
aiSummary?: string | undefined;
|
|
116
|
-
aiLabels?: string[] | undefined;
|
|
117
|
-
transcription?: string | undefined;
|
|
118
|
-
waveformPeaks?: number[] | undefined;
|
|
119
|
-
socialVideoUrl?: string | undefined;
|
|
120
|
-
socialVideoStoragePath?: string | undefined;
|
|
121
|
-
socialVideoStatus?: "pending" | "complete" | "error" | undefined;
|
|
122
|
-
socialVideoError?: string | undefined;
|
|
123
|
-
socialVideoSourceAudio?: string | undefined;
|
|
124
|
-
replyCount?: number | undefined;
|
|
125
|
-
lastReplyAt?: unknown;
|
|
126
|
-
engagementScoreSum?: number | undefined;
|
|
127
|
-
engagementScoreCount?: number | undefined;
|
|
128
|
-
sentimentCounts?: {
|
|
129
|
-
positive?: number | undefined;
|
|
130
|
-
neutral?: number | undefined;
|
|
131
|
-
negative?: number | undefined;
|
|
132
|
-
} | undefined;
|
|
133
|
-
}>;
|
|
134
|
-
type PromptDocument = z.infer<typeof PromptDocumentSchema>;
|
|
135
|
-
/**
|
|
136
|
-
* The ReplyDocument (Storage Schema).
|
|
137
|
-
* Currently identical to ReplyRecordSchema as there are no computed fields stored on the Reply document itself.
|
|
138
|
-
*/
|
|
139
|
-
declare const ReplyDocumentSchema: z.ZodObject<{
|
|
140
|
-
id: z.ZodString;
|
|
141
|
-
promptId: z.ZodString;
|
|
142
|
-
authorId: z.ZodString;
|
|
143
|
-
audioUrl: z.ZodString;
|
|
144
|
-
audio: z.ZodOptional<z.ZodObject<{
|
|
145
|
-
$type: z.ZodLiteral<"blob">;
|
|
146
|
-
ref: z.ZodString;
|
|
147
|
-
mimeType: z.ZodString;
|
|
148
|
-
size: z.ZodNumber;
|
|
149
|
-
}, "strip", z.ZodTypeAny, {
|
|
150
|
-
$type: "blob";
|
|
151
|
-
ref: string;
|
|
152
|
-
mimeType: string;
|
|
153
|
-
size: number;
|
|
154
|
-
}, {
|
|
155
|
-
$type: "blob";
|
|
156
|
-
ref: string;
|
|
157
|
-
mimeType: string;
|
|
158
|
-
size: number;
|
|
159
|
-
}>>;
|
|
160
|
-
createdAt: z.ZodEffects<z.ZodUnion<[z.ZodType<unknown, z.ZodTypeDef, unknown>, z.ZodString, z.ZodNumber, z.ZodDate]>, Date, unknown>;
|
|
161
|
-
status: z.ZodDefault<z.ZodEnum<["live", "archived", "deleted"]>>;
|
|
162
|
-
waveformPeaks: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
|
|
163
|
-
audioDurationSec: z.ZodOptional<z.ZodNumber>;
|
|
164
|
-
}, "strip", z.ZodTypeAny, {
|
|
165
|
-
id: string;
|
|
166
|
-
authorId: string;
|
|
167
|
-
audioUrl: string;
|
|
168
|
-
status: "live" | "archived" | "deleted";
|
|
169
|
-
createdAt: Date;
|
|
170
|
-
promptId: string;
|
|
171
|
-
audio?: {
|
|
172
|
-
$type: "blob";
|
|
173
|
-
ref: string;
|
|
174
|
-
mimeType: string;
|
|
175
|
-
size: number;
|
|
176
|
-
} | undefined;
|
|
177
|
-
waveformPeaks?: number[] | undefined;
|
|
178
|
-
audioDurationSec?: number | undefined;
|
|
179
|
-
}, {
|
|
180
|
-
id: string;
|
|
181
|
-
authorId: string;
|
|
182
|
-
audioUrl: string;
|
|
183
|
-
promptId: string;
|
|
184
|
-
status?: "live" | "archived" | "deleted" | undefined;
|
|
185
|
-
audio?: {
|
|
186
|
-
$type: "blob";
|
|
187
|
-
ref: string;
|
|
188
|
-
mimeType: string;
|
|
189
|
-
size: number;
|
|
190
|
-
} | undefined;
|
|
191
|
-
createdAt?: unknown;
|
|
192
|
-
waveformPeaks?: number[] | undefined;
|
|
193
|
-
audioDurationSec?: number | undefined;
|
|
194
|
-
}>;
|
|
195
|
-
type ReplyDocument = z.infer<typeof ReplyDocumentSchema>;
|
|
196
|
-
|
|
197
|
-
export { type PromptDocument, PromptDocumentSchema, type ReplyDocument, ReplyDocumentSchema };
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { PromptRecordSchema, FirestoreTimestampSchema, ReplyRecordSchema } from '../chunk-3WZJXJNU.js';
|
|
2
|
-
import '../chunk-5EHV73BA.js';
|
|
3
|
-
import '../chunk-ORMEWXMH.js';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
|
|
6
|
-
var PromptDocumentSchema = PromptRecordSchema.extend({
|
|
7
|
-
replyCount: z.number().default(0),
|
|
8
|
-
// Computed field lives here
|
|
9
|
-
lastReplyAt: FirestoreTimestampSchema.optional(),
|
|
10
|
-
// Good for sorting feeds
|
|
11
|
-
// Per-prompt aggregates over `status: 'live'` replies whose AI enrichment
|
|
12
|
-
// landed (sentiment + engagementScore). Maintained by the AI-enrichment
|
|
13
|
-
// trigger and the reply-status-flip path via FieldValue.increment deltas.
|
|
14
|
-
// Sum + count rather than a pre-divided average: only sum/count compose
|
|
15
|
-
// safely under concurrent writes (no read-modify-write).
|
|
16
|
-
engagementScoreSum: z.number().default(0),
|
|
17
|
-
engagementScoreCount: z.number().default(0),
|
|
18
|
-
sentimentCounts: z.object({
|
|
19
|
-
positive: z.number().default(0),
|
|
20
|
-
neutral: z.number().default(0),
|
|
21
|
-
negative: z.number().default(0)
|
|
22
|
-
}).default({ positive: 0, neutral: 0, negative: 0 })
|
|
23
|
-
});
|
|
24
|
-
var ReplyDocumentSchema = ReplyRecordSchema;
|
|
25
|
-
|
|
26
|
-
export { PromptDocumentSchema, ReplyDocumentSchema };
|