@antiphony/shared 0.1.0 → 0.4.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.
Files changed (59) hide show
  1. package/README.md +4 -4
  2. package/dist/cjs/api-codecs.cjs +90 -787
  3. package/dist/cjs/api-codecs.d.cts +117 -290
  4. package/dist/cjs/index.cjs +102 -947
  5. package/dist/cjs/index.d.cts +89 -7
  6. package/dist/cjs/nsid.cjs +8 -18
  7. package/dist/cjs/nsid.d.cts +8 -17
  8. package/dist/cjs/types/audio.cjs +77 -662
  9. package/dist/cjs/types/audio.d.cts +285 -203
  10. package/dist/cjs/types/blob.cjs +5 -9
  11. package/dist/cjs/types/blob.d.cts +21 -21
  12. package/dist/cjs/types/records.cjs +0 -370
  13. package/dist/cjs/types/records.d.cts +1 -825
  14. package/dist/esm/api-codecs.d.ts +117 -290
  15. package/dist/esm/api-codecs.js +5 -6
  16. package/dist/esm/{chunk-ORMEWXMH.js → chunk-5JBD5THX.js} +1 -16
  17. package/dist/esm/{chunk-F2CANZZ7.js → chunk-BNNLHRH7.js} +1 -1
  18. package/dist/esm/chunk-D655OH2I.js +35 -0
  19. package/dist/esm/chunk-RUUHUNZ6.js +37 -0
  20. package/dist/esm/chunk-SBYNIQRZ.js +23 -0
  21. package/dist/esm/chunk-SMK4OZNU.js +17 -0
  22. package/dist/esm/{chunk-BUNMR4ZO.js → chunk-WL2GSPGC.js} +81 -12
  23. package/dist/esm/errors/index.js +1 -1
  24. package/dist/esm/index.d.ts +89 -7
  25. package/dist/esm/index.js +7 -9
  26. package/dist/esm/nsid.d.ts +8 -17
  27. package/dist/esm/nsid.js +2 -2
  28. package/dist/esm/observability/index.js +2 -2
  29. package/dist/esm/observability/report-error.js +2 -2
  30. package/dist/esm/types/audio.d.ts +285 -203
  31. package/dist/esm/types/audio.js +4 -5
  32. package/dist/esm/types/blob.d.ts +21 -21
  33. package/dist/esm/types/blob.js +2 -2
  34. package/dist/esm/types/records.d.ts +1 -825
  35. package/dist/esm/types/records.js +2 -3
  36. package/dist/esm/utils/index.js +1 -1
  37. package/package.json +90 -26
  38. package/dist/cjs/types/api.cjs +0 -726
  39. package/dist/cjs/types/api.d.cts +0 -494
  40. package/dist/cjs/types/channels.cjs +0 -170
  41. package/dist/cjs/types/channels.d.cts +0 -262
  42. package/dist/cjs/types/storage.cjs +0 -414
  43. package/dist/cjs/types/storage.d.cts +0 -197
  44. package/dist/cjs/types/views.cjs +0 -820
  45. package/dist/cjs/types/views.d.cts +0 -9806
  46. package/dist/esm/chunk-3WZJXJNU.js +0 -378
  47. package/dist/esm/chunk-5EHV73BA.js +0 -20
  48. package/dist/esm/chunk-7V44CPRR.js +0 -132
  49. package/dist/esm/chunk-EA4OONDV.js +0 -380
  50. package/dist/esm/chunk-TIZRJORN.js +0 -24
  51. package/dist/esm/chunk-XDBKR6LW.js +0 -32
  52. package/dist/esm/types/api.d.ts +0 -494
  53. package/dist/esm/types/api.js +0 -5
  54. package/dist/esm/types/channels.d.ts +0 -262
  55. package/dist/esm/types/channels.js +0 -162
  56. package/dist/esm/types/storage.d.ts +0 -197
  57. package/dist/esm/types/storage.js +0 -26
  58. package/dist/esm/types/views.d.ts +0 -9806
  59. package/dist/esm/types/views.js +0 -4
@@ -1,380 +0,0 @@
1
- import { FirestoreTimestampSchema, PromptRecordSchema, ReplyRecordSchema, OrganizationRecordSchema, OrganizationMemberRecordSchema, OrgInviteRecordSchema } from './chunk-3WZJXJNU.js';
2
- import { __objRest, __spreadProps, __spreadValues } from './chunk-ORMEWXMH.js';
3
- import { z } from 'zod';
4
-
5
- var ProfileViewBasicSchema = z.object({
6
- id: z.string(),
7
- handle: z.string().nullable().optional(),
8
- // `displayName` and `bio` are `.nullable()` — Firestore stores `null` for
9
- // empty values on these fields (see users-dependencies.ts), and Zod's
10
- // `.optional()` alone rejects `null`. This hit dashboard rendering on the
11
- // Phase 3.1 HTTP cutover, when transport-layer Zod validation started
12
- // actually exercising the wire shape. Consumers already use truthy
13
- // checks / `??` / `||`, so widening the type to include `null` is safe.
14
- displayName: z.string().nullable().optional(),
15
- avatarUrl: z.string().nullable().optional(),
16
- bio: z.string().nullable().optional(),
17
- /** Personal website link surfaced on the public profile. */
18
- website: z.string().nullable().optional(),
19
- /** Public links (label + URL) shown under the bio. */
20
- links: z.array(z.object({
21
- label: z.string(),
22
- url: z.string()
23
- })).optional(),
24
- /**
25
- * AT Protocol identity, surfaced on the public profile only when the user
26
- * opts in (`UserRecord.showBlueskyPublicly === true`). Projection happens
27
- * in the user dependency layer; this schema simply allows the field.
28
- */
29
- bluesky: z.object({
30
- handle: z.string(),
31
- did: z.string()
32
- }).optional(),
33
- stats: z.object({
34
- followers: z.number().default(0),
35
- following: z.number().default(0),
36
- prompts: z.number().default(0)
37
- }).optional(),
38
- badges: z.array(z.string()).optional(),
39
- isVerified: z.boolean().optional(),
40
- createdAt: FirestoreTimestampSchema.optional()
41
- });
42
- function toProfileViewBasic(profile) {
43
- const { id, handle, displayName, avatarUrl, bio, website, links, bluesky, showBlueskyPublicly, stats, badges, isVerified, createdAt } = profile;
44
- return {
45
- id,
46
- handle,
47
- displayName,
48
- avatarUrl,
49
- bio,
50
- website,
51
- links,
52
- bluesky: showBlueskyPublicly ? bluesky : void 0,
53
- stats,
54
- badges,
55
- isVerified,
56
- createdAt
57
- };
58
- }
59
- var ProfileViewDetailedSchema = ProfileViewBasicSchema.extend({
60
- /** AT Protocol Identity link */
61
- bluesky: z.object({
62
- handle: z.string(),
63
- did: z.string()
64
- }).optional(),
65
- usageIntent: z.string().nullable().optional(),
66
- /** Hydrated RSS Data (fetched from sub-collection) */
67
- rssSummary: z.object({
68
- title: z.string().optional(),
69
- description: z.string().optional(),
70
- items: z.array(z.object({
71
- title: z.string().optional(),
72
- link: z.string().optional(),
73
- content: z.string().optional(),
74
- pubDate: z.string().optional()
75
- })).optional(),
76
- lastFetchedAt: FirestoreTimestampSchema.optional()
77
- }).optional(),
78
- promptAudioUrl: z.string().optional(),
79
- /** @deprecated Use stats.prompts from ProfileViewBasic instead */
80
- totalPrompts: z.number().optional(),
81
- totalReplies: z.number().optional(),
82
- favoritePromptId: z.string().optional()
83
- });
84
- var ProfileViewSelfSchema = ProfileViewDetailedSchema.extend({
85
- phoneNumber: z.string().nullable().optional(),
86
- email: z.string().optional(),
87
- lastSeenAt: FirestoreTimestampSchema.optional(),
88
- lastActiveAt: FirestoreTimestampSchema.optional(),
89
- unreadReplyCount: z.number().default(0),
90
- newReplierCount: z.number().default(0),
91
- /**
92
- * Account tier from UserRecord — surfaced on the self profile so the
93
- * client can gate paid features (e.g. the Performance dashboard tab).
94
- * Optional for legacy docs without the field; consumers should treat
95
- * missing as `'free'`.
96
- */
97
- tier: z.enum(["free", "creator_pro"]).optional(),
98
- /**
99
- * Surfaces the linked Bluesky identity (handle + DID) on the public profile
100
- * when true. Persisted on UserRecord; exposed in self/detailed views so the
101
- * settings form can render the toggle's current state.
102
- */
103
- showBlueskyPublicly: z.boolean().optional(),
104
- settings: z.object({
105
- notifications: z.boolean().optional(),
106
- theme: z.string().optional()
107
- }).optional()
108
- });
109
- var ProfileViewAdminSchema = ProfileViewSelfSchema.extend({
110
- blockedUsers: z.array(z.string()).optional(),
111
- followers: z.array(z.string()).optional(),
112
- following: z.array(z.string()).optional(),
113
- reportCount: z.number().optional(),
114
- isBanned: z.boolean().optional()
115
- });
116
- var ProfileViewSchema = ProfileViewAdminSchema;
117
- var PromptViewSchema = z.object({
118
- /** AT Protocol URI (e.g. at://did:plc.../app.../123) */
119
- uri: z.string().optional(),
120
- /** IPFS Content ID */
121
- cid: z.string().optional(),
122
- /** The raw prompt data */
123
- record: PromptRecordSchema,
124
- /** The hydrated author profile */
125
- author: ProfileViewSchema,
126
- /** Total number of replies */
127
- replyCount: z.number().default(0),
128
- likeCount: z.number().default(0),
129
- updatedAt: FirestoreTimestampSchema.optional(),
130
- lastReplyAt: FirestoreTimestampSchema.optional(),
131
- tags: z.array(z.string()).optional(),
132
- visibility: z.enum(["public", "private", "unlisted", "archived"]).default("public"),
133
- analytics: z.object({
134
- views: z.number().default(0),
135
- listens: z.number().default(0),
136
- /**
137
- * Mean engagementScore (1–10) across this prompt's `status: 'live'`
138
- * replies that completed AI enrichment. `null` when no such replies
139
- * exist (0 would alias a valid bottom-of-range score). Derived in
140
- * hydration from the prompt doc's `engagementScoreSum / Count`.
141
- */
142
- avgEngagementScore: z.number().nullable().optional(),
143
- /**
144
- * Counts of `status: 'live'` AI-enriched replies grouped by sentiment.
145
- * Keys lowercase by convention; source enum
146
- * (`Positive | Neutral | Negative`) is mapped at the write site.
147
- */
148
- sentimentBreakdown: z.object({
149
- positive: z.number(),
150
- neutral: z.number(),
151
- negative: z.number()
152
- }).optional()
153
- }).optional(),
154
- moderation: z.object({
155
- flagged: z.boolean().default(false),
156
- reason: z.string().optional()
157
- }).optional(),
158
- // AI Enrichment Fields (Hydrated from Record but hidden from Record Schema)
159
- aiLabels: z.array(z.string()).optional(),
160
- aiSummary: z.string().optional(),
161
- aiStatus: z.enum(["pending", "complete", "error"]).optional(),
162
- aiError: z.string().optional(),
163
- transcription: z.string().optional()
164
- });
165
- var PromptViewPublicSchema = PromptViewSchema.omit({
166
- analytics: true,
167
- moderation: true,
168
- aiLabels: true,
169
- aiSummary: true,
170
- aiStatus: true,
171
- aiError: true,
172
- transcription: true
173
- }).extend({
174
- author: ProfileViewBasicSchema
175
- });
176
- function toPromptViewPublic(prompt) {
177
- const _a = prompt, { analytics, moderation, aiLabels, aiSummary, aiStatus, aiError, transcription } = _a, rest = __objRest(_a, ["analytics", "moderation", "aiLabels", "aiSummary", "aiStatus", "aiError", "transcription"]);
178
- return __spreadProps(__spreadValues({}, rest), {
179
- author: toProfileViewBasic(rest.author)
180
- });
181
- }
182
- var ReplyViewSchema = z.object({
183
- record: ReplyRecordSchema,
184
- author: ProfileViewSchema,
185
- recipient: ProfileViewSchema,
186
- /** GCS Storage Path for audio file */
187
- storagePath: z.string().optional(),
188
- duration: z.number().optional(),
189
- updatedAt: FirestoreTimestampSchema.optional(),
190
- isRead: z.boolean(),
191
- readBy: z.array(z.string()).default([]),
192
- isDeleted: z.boolean().default(false),
193
- reactions: z.record(z.string(), z.number()).optional(),
194
- moderation: z.object({
195
- flagged: z.boolean().default(false),
196
- reason: z.string().optional()
197
- }).optional(),
198
- // AI Enrichment Fields (Hydrated from Record but hidden from Record Schema)
199
- aiLabels: z.array(z.string()).optional(),
200
- aiSummary: z.string().optional(),
201
- aiStatus: z.enum(["pending", "complete", "error", "skipped_too_short"]).optional(),
202
- aiError: z.string().optional(),
203
- transcription: z.string().optional(),
204
- sentiment: z.enum(["Positive", "Negative", "Neutral"]).optional(),
205
- /** Must match the widened enum in `ReplyRecordSchema.energyLevel`. */
206
- energyLevel: z.enum(["High", "Low", "Neutral"]).optional(),
207
- engagementScore: z.number().min(1).max(10).optional(),
208
- // === Voice-isolation enrichment (lifted; see specs/ai-enrichment-split.md) ===
209
- //
210
- // `enhancedAudioUrl` is the only one of these the public view keeps —
211
- // it replaces `audioUrl` for downstream players when present.
212
- // `enhancedStoragePath` is private (storage paths are server-side
213
- // bookkeeping).
214
- enhancedAudioUrl: z.string().url().optional(),
215
- enhancedStoragePath: z.string().optional(),
216
- // === Social-share video enrichment (lifted; creator-only) ===
217
- //
218
- // All `socialVideo*` fields are stripped by `toReplyViewPublic` —
219
- // the URL points at a generated artifact the creator may share to
220
- // social media, NOT at content the reply page should render. Status /
221
- // error / source-audio are job-tracking state.
222
- socialVideoUrl: z.string().url().optional(),
223
- socialVideoStoragePath: z.string().optional(),
224
- socialVideoStatus: z.enum(["pending", "complete", "error"]).optional(),
225
- socialVideoError: z.string().optional(),
226
- socialVideoSourceAudio: z.string().optional(),
227
- /** @private Confirmed listener phone number (never exposed publicly) */
228
- listenerPhoneNumber: z.string().regex(/^\+[1-9]\d{1,14}$/).optional(),
229
- /**
230
- * @private Per-viewer private notes about this reply (CRM enrichment).
231
- * Lifted into the view from `enrichments/replies/{id}.notes` by the
232
- * hydrator when the viewer is the prompt author. Never populated for
233
- * non-author viewers; defensively stripped by `toReplyViewPublic`.
234
- */
235
- notes: z.string().optional()
236
- });
237
- var ReplyViewPublicSchema = ReplyViewSchema.omit({
238
- listenerPhoneNumber: true,
239
- notes: true,
240
- // AI cluster — only `transcription` survives.
241
- aiStatus: true,
242
- aiError: true,
243
- aiSummary: true,
244
- aiLabels: true,
245
- sentiment: true,
246
- energyLevel: true,
247
- engagementScore: true,
248
- // Voice isolation — keep enhancedAudioUrl, strip the path.
249
- enhancedStoragePath: true,
250
- // Social-video — entire cluster is creator-only.
251
- socialVideoUrl: true,
252
- socialVideoStoragePath: true,
253
- socialVideoStatus: true,
254
- socialVideoError: true,
255
- socialVideoSourceAudio: true
256
- });
257
- function toReplyViewPublic(reply) {
258
- const _a = reply, {
259
- listenerPhoneNumber,
260
- notes,
261
- aiStatus: aiStatus,
262
- aiError,
263
- aiSummary,
264
- aiLabels,
265
- sentiment,
266
- energyLevel,
267
- engagementScore,
268
- enhancedStoragePath: enhancedStoragePath,
269
- socialVideoUrl: socialVideoUrl,
270
- socialVideoStoragePath,
271
- socialVideoStatus,
272
- socialVideoError,
273
- socialVideoSourceAudio
274
- } = _a, publicReply = __objRest(_a, [
275
- "listenerPhoneNumber",
276
- "notes",
277
- // AI cluster (only transcription stays public)
278
- "aiStatus",
279
- "aiError",
280
- "aiSummary",
281
- "aiLabels",
282
- "sentiment",
283
- "energyLevel",
284
- "engagementScore",
285
- // Voice isolation (only enhancedAudioUrl stays public)
286
- "enhancedStoragePath",
287
- // Social-video (entire cluster is creator-only)
288
- "socialVideoUrl",
289
- "socialVideoStoragePath",
290
- "socialVideoStatus",
291
- "socialVideoError",
292
- "socialVideoSourceAudio"
293
- ]);
294
- return publicReply;
295
- }
296
- var OrganizationViewSchema = z.object({
297
- record: OrganizationRecordSchema,
298
- memberCount: z.number().default(1),
299
- currentUserRole: z.enum(["owner", "admin", "member"]).optional()
300
- });
301
- var OrganizationMemberViewSchema = z.object({
302
- record: OrganizationMemberRecordSchema,
303
- profile: ProfileViewBasicSchema
304
- });
305
- var OrgInviteViewSchema = z.object({
306
- record: OrgInviteRecordSchema,
307
- /** Display name of the user who sent the invite */
308
- inviterName: z.string().optional(),
309
- /** Name of the organization */
310
- orgName: z.string()
311
- });
312
- var PromptRepliersSchema = z.object({
313
- promptId: z.string(),
314
- repliers: z.record(z.string(), z.object({
315
- firstReplyAt: FirestoreTimestampSchema,
316
- lastReplyAt: FirestoreTimestampSchema,
317
- replyCount: z.number()
318
- }))
319
- });
320
- var PromptWithRepliesSchema = PromptViewSchema.extend({
321
- replies: z.array(ReplyViewSchema)
322
- });
323
- var ReplierSchema = z.object({
324
- handle: z.string(),
325
- /** ISO date string */
326
- lastReplyDate: z.string(),
327
- /** ISO date string */
328
- firstReplyAt: z.string(),
329
- totalReplies: z.number()
330
- });
331
- var HandleResolutionSchema = z.discriminatedUnion("type", [
332
- // Public endpoint (`GET /resolve/:handle`) — project to the basic shape so
333
- // PII/admin fields (email, phoneNumber, settings, blockedUsers, …) never
334
- // cross the public API boundary. See `toProfileViewBasic`.
335
- z.object({ type: z.literal("user"), profile: ProfileViewBasicSchema }),
336
- z.object({ type: z.literal("org"), org: OrganizationViewSchema })
337
- ]);
338
- var UserProfileDataSchema = z.object({
339
- // Public endpoint (`GET /users/:handle/profile`) — basic shape only, so the
340
- // owner's PII/admin fields never serialize to anonymous callers.
341
- profileUser: ProfileViewBasicSchema,
342
- // Each prompt's nested `author` is the profile owner, hydrated from the
343
- // wide admin profile (`getPromptsForUser` prefetches via getUserDataByUid).
344
- // Use the PUBLIC prompt/reply shapes so that nested author PII (email,
345
- // phoneNumber, settings, …) and owner-only prompt enrichment never leak.
346
- allPromptsWithReplies: z.array(PromptViewPublicSchema.extend({
347
- replies: z.array(ReplyViewPublicSchema)
348
- })),
349
- repliers: z.array(ReplierSchema)
350
- });
351
- var RssSummarySchema = z.object({
352
- title: z.string().optional(),
353
- description: z.string().optional(),
354
- image: z.string().optional(),
355
- link: z.string().optional(),
356
- items: z.array(z.object({
357
- title: z.string().optional(),
358
- link: z.string().optional(),
359
- content: z.string().optional(),
360
- pubDate: z.string().optional()
361
- })).optional(),
362
- lastFetchedAt: FirestoreTimestampSchema.optional()
363
- });
364
- var OrgProfileDataSchema = z.object({
365
- org: OrganizationViewSchema,
366
- prompts: z.array(PromptViewSchema),
367
- rssSummary: RssSummarySchema.nullable()
368
- });
369
- var EnrichedReplierSchema = z.object({
370
- profile: ProfileViewBasicSchema,
371
- totalReplies: z.number(),
372
- /** ISO date string */
373
- lastReplyDate: z.string(),
374
- /** ISO date string */
375
- firstReplyAt: z.string(),
376
- /** Phone number for anonymous repliers (from Firebase Auth, only visible to prompt author) */
377
- phoneNumber: z.string().optional()
378
- });
379
-
380
- export { EnrichedReplierSchema, HandleResolutionSchema, OrgInviteViewSchema, OrgProfileDataSchema, OrganizationMemberViewSchema, OrganizationViewSchema, ProfileViewAdminSchema, ProfileViewBasicSchema, ProfileViewDetailedSchema, ProfileViewSchema, ProfileViewSelfSchema, PromptRepliersSchema, PromptViewPublicSchema, PromptViewSchema, PromptWithRepliesSchema, ReplierSchema, ReplyViewPublicSchema, ReplyViewSchema, RssSummarySchema, UserProfileDataSchema, toProfileViewBasic, toPromptViewPublic, toReplyViewPublic };
@@ -1,24 +0,0 @@
1
- import { ProfileViewBasicSchema, ProfileViewSelfSchema } from './chunk-EA4OONDV.js';
2
- import { FirestoreTimestampSchema } from './chunk-3WZJXJNU.js';
3
- import { z } from 'zod';
4
-
5
- var PublicProfileDtoSchema = ProfileViewBasicSchema.extend({
6
- bluesky: z.object({
7
- handle: z.string(),
8
- did: z.string()
9
- }).optional(),
10
- rssFeedUrl: z.string().nullable().optional()
11
- });
12
- var PublicReplyDtoSchema = z.object({
13
- id: z.string(),
14
- audioUrl: z.string().url(),
15
- duration: z.number().optional(),
16
- createdAt: FirestoreTimestampSchema,
17
- transcription: z.string().optional(),
18
- sentiment: z.enum(["Positive", "Negative", "Neutral"]).optional(),
19
- aiSummary: z.string().optional(),
20
- author: PublicProfileDtoSchema
21
- });
22
- var ActorViewSchema = ProfileViewSelfSchema;
23
-
24
- export { ActorViewSchema, PublicProfileDtoSchema, PublicReplyDtoSchema };
@@ -1,32 +0,0 @@
1
- // nsid.ts
2
- var NSID = {
3
- // Legacy Vox Pop record types (deprecated; removed in Stream 4).
4
- Prompt: "com.voxpop.audio.prompt",
5
- Reply: "com.voxpop.audio.reply",
6
- Profile: "com.voxpop.actor.profile",
7
- // Antiphony canonical record types (dev.antiphony.*). Added additively in
8
- // Stream 1; see lexicons/dev/antiphony/ + packages/shared/types/audio.ts.
9
- AudioPost: "dev.antiphony.audio.post",
10
- AudioTranscript: "dev.antiphony.audio.transcript",
11
- ActorProfile: "dev.antiphony.actor.profile"
12
- };
13
- var EMBED_NSID = {
14
- Audio: "dev.antiphony.embed.audio",
15
- RecordWithAudio: "dev.antiphony.embed.recordWithAudio"
16
- };
17
- var COLLECTIONS = {
18
- [NSID.Prompt]: "prompts",
19
- [NSID.Reply]: "replies",
20
- [NSID.Profile]: "users",
21
- // Antiphony: one post collection + the transcript enrichment namespace.
22
- [NSID.AudioPost]: "posts",
23
- [NSID.AudioTranscript]: "audio_transcripts",
24
- [NSID.ActorProfile]: "users"
25
- };
26
- function nsidForCollection(collection) {
27
- const entries = Object.entries(COLLECTIONS);
28
- const match = entries.find(([, col]) => col === collection);
29
- return match == null ? void 0 : match[0];
30
- }
31
-
32
- export { COLLECTIONS, EMBED_NSID, NSID, nsidForCollection };