@antiphony/shared 0.3.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 (44) hide show
  1. package/README.md +4 -4
  2. package/dist/cjs/api-codecs.cjs +74 -147
  3. package/dist/cjs/api-codecs.d.cts +105 -60
  4. package/dist/cjs/index.cjs +84 -197
  5. package/dist/cjs/index.d.cts +89 -7
  6. package/dist/cjs/nsid.cjs +6 -9
  7. package/dist/cjs/nsid.d.cts +7 -8
  8. package/dist/cjs/types/audio.cjs +60 -124
  9. package/dist/cjs/types/audio.d.cts +226 -185
  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 -45
  13. package/dist/cjs/types/records.d.cts +1 -103
  14. package/dist/esm/api-codecs.d.ts +135 -90
  15. package/dist/esm/api-codecs.js +4 -5
  16. package/dist/esm/chunk-D655OH2I.js +35 -0
  17. package/dist/esm/chunk-RUUHUNZ6.js +37 -0
  18. package/dist/esm/{chunk-6LROFBKK.js → chunk-SBYNIQRZ.js} +7 -9
  19. package/dist/esm/chunk-SMK4OZNU.js +17 -0
  20. package/dist/esm/{chunk-F7IHVM34.js → chunk-WL2GSPGC.js} +64 -12
  21. package/dist/esm/index.d.ts +89 -7
  22. package/dist/esm/index.js +5 -7
  23. package/dist/esm/nsid.d.ts +7 -8
  24. package/dist/esm/nsid.js +1 -1
  25. package/dist/esm/types/audio.d.ts +303 -262
  26. package/dist/esm/types/audio.js +3 -4
  27. package/dist/esm/types/blob.d.ts +21 -21
  28. package/dist/esm/types/blob.js +1 -1
  29. package/dist/esm/types/records.d.ts +1 -103
  30. package/dist/esm/types/records.js +1 -1
  31. package/package.json +90 -26
  32. package/dist/cjs/types/api.cjs +0 -166
  33. package/dist/cjs/types/api.d.cts +0 -242
  34. package/dist/cjs/types/views.cjs +0 -179
  35. package/dist/cjs/types/views.d.cts +0 -726
  36. package/dist/esm/chunk-5EHV73BA.js +0 -20
  37. package/dist/esm/chunk-FDM5FDN4.js +0 -46
  38. package/dist/esm/chunk-IHIBHQBJ.js +0 -78
  39. package/dist/esm/chunk-R6SBR3IG.js +0 -97
  40. package/dist/esm/chunk-Y6HNNRVD.js +0 -12
  41. package/dist/esm/types/api.d.ts +0 -242
  42. package/dist/esm/types/api.js +0 -4
  43. package/dist/esm/types/views.d.ts +0 -726
  44. package/dist/esm/types/views.js +0 -3
@@ -21,23 +21,15 @@ var __spreadValues = (a, b) => {
21
21
  var BlobRefSchema = zod.z.object({
22
22
  /** Discriminator for AT Protocol type system */
23
23
  $type: zod.z.literal("blob"),
24
- /** Content Identifier (CID) or URL pointing to the blob */
25
- ref: zod.z.string(),
24
+ /** IPLD link to the blob bytes: the content CID. */
25
+ ref: zod.z.object({
26
+ $link: zod.z.string().min(1)
27
+ }),
26
28
  /** MIME type of the blob (e.g., 'audio/webm') */
27
29
  mimeType: zod.z.string(),
28
30
  /** Size of the blob in bytes */
29
- size: zod.z.number()
31
+ size: zod.z.number().int().min(0)
30
32
  });
31
- function resolveAudioUrl(record) {
32
- var _a;
33
- if ((_a = record.audio) == null ? void 0 : _a.ref) return record.audio.ref;
34
- return record.audioUrl;
35
- }
36
- function httpsUrl() {
37
- return zod.z.string().trim().url().refine((u) => /^https?:\/\//i.test(u), {
38
- message: "URL must use the http or https scheme"
39
- });
40
- }
41
33
  var FirestoreTimestampSchema = zod.z.union([
42
34
  zod.z.custom((data) => {
43
35
  return data && typeof data === "object" && (typeof data.toDate === "function" || "seconds" in data && "nanoseconds" in data);
@@ -68,136 +60,22 @@ var FirestoreTimestampSchema = zod.z.union([
68
60
  }
69
61
  return date;
70
62
  });
71
- var UserRecordSchema = zod.z.object({
72
- /** Unique Firebase UID */
73
- id: zod.z.string(),
74
- /** Public handle (e.g. @brad). Optional for Lite Users. */
75
- handle: zod.z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]+$/).nullable().optional(),
76
- /** User stated intent (e.g. "Podcaster", "Listener") */
77
- usageIntent: zod.z.string().nullable().optional(),
78
- /** Domain for federated handle support. */
79
- domain: zod.z.string().default("antiphony.dev"),
80
- /**
81
- * Display Name (e.g. "Brad Thorson"). Nullable: Firestore stores `null`
82
- * when the user clears this field via the settings form, and the schema
83
- * must match storage reality or `UserRecordSchema.parse` (in
84
- * `getUserRecordByUid`) will throw.
85
- */
86
- displayName: zod.z.string().max(50).nullable().optional(),
87
- /** Short bio/description — nullable for the same reason as displayName. */
88
- bio: zod.z.string().max(160).nullable().optional(),
89
- /** URL to avatar image — nullable for the same reason as displayName. */
90
- avatarUrl: zod.z.string().url().nullable().optional(),
91
- /** Optional personal website surfaced on the public profile. */
92
- website: httpsUrl().nullable().optional(),
93
- /** Up to 5 additional public links (label + URL) shown under the bio. */
94
- links: zod.z.array(zod.z.object({
95
- label: zod.z.string().min(1).max(40),
96
- url: httpsUrl()
97
- })).max(5).optional(),
98
- /** When true and a Bluesky identity is linked, surfaces it on the public profile. */
99
- showBlueskyPublicly: zod.z.boolean().optional(),
100
- /** Server timestamp of creation */
101
- createdAt: FirestoreTimestampSchema,
102
- /** Individual account tier — free or creator_pro */
103
- tier: zod.z.enum(["free", "creator_pro"]).default("free"),
104
- /** Account status. Deactivated accounts retain data but are excluded from lookups. */
105
- status: zod.z.enum(["active", "deactivated"]).default("active"),
106
- /** Timestamp when the account was deactivated (soft deleted) */
107
- deactivatedAt: FirestoreTimestampSchema.optional()
63
+ var ProcessingStageStatusSchema = zod.z.enum(["pending", "ready", "failed", "skipped"]);
64
+ var ProcessingRequestSchema = zod.z.object({
65
+ transcribe: zod.z.boolean().optional(),
66
+ denoise: zod.z.boolean().optional()
108
67
  });
109
- var ProfileViewBasicSchema = zod.z.object({
110
- id: zod.z.string(),
111
- handle: zod.z.string().nullable().optional(),
112
- // `displayName` and `bio` are `.nullable()` Firestore stores `null` for
113
- // empty values on these fields (see users-dependencies.ts), and Zod's
114
- // `.optional()` alone rejects `null`. Consumers already use truthy
115
- // checks / `??` / `||`, so widening the type to include `null` is safe.
116
- displayName: zod.z.string().nullable().optional(),
117
- avatarUrl: zod.z.string().nullable().optional(),
118
- bio: zod.z.string().nullable().optional(),
119
- /** Personal website link surfaced on the public profile. */
120
- website: zod.z.string().nullable().optional(),
121
- /** Public links (label + URL) shown under the bio. */
122
- links: zod.z.array(zod.z.object({
123
- label: zod.z.string(),
124
- url: zod.z.string()
125
- })).optional(),
126
- /**
127
- * AT Protocol identity, surfaced on the public profile only when the user
128
- * opts in (`UserRecord.showBlueskyPublicly === true`). Projection happens
129
- * in the user dependency layer; this schema simply allows the field.
130
- */
131
- bluesky: zod.z.object({
132
- handle: zod.z.string(),
133
- did: zod.z.string()
134
- }).optional(),
135
- stats: zod.z.object({
136
- followers: zod.z.number().default(0),
137
- following: zod.z.number().default(0),
138
- prompts: zod.z.number().default(0)
139
- }).optional(),
140
- badges: zod.z.array(zod.z.string()).optional(),
141
- isVerified: zod.z.boolean().optional(),
142
- createdAt: FirestoreTimestampSchema.optional()
143
- });
144
- function toProfileViewBasic(profile) {
145
- const { id, handle, displayName, avatarUrl, bio, website, links, bluesky, showBlueskyPublicly, stats, badges, isVerified, createdAt } = profile;
146
- return {
147
- id,
148
- handle,
149
- displayName,
150
- avatarUrl,
151
- bio,
152
- website,
153
- links,
154
- bluesky: showBlueskyPublicly ? bluesky : void 0,
155
- stats,
156
- badges,
157
- isVerified,
158
- createdAt
159
- };
160
- }
161
- var ProfileViewDetailedSchema = ProfileViewBasicSchema.extend({
162
- /** AT Protocol Identity link */
163
- bluesky: zod.z.object({
164
- handle: zod.z.string(),
165
- did: zod.z.string()
166
- }).optional(),
167
- usageIntent: zod.z.string().nullable().optional()
168
- });
169
- var ProfileViewSelfSchema = ProfileViewDetailedSchema.extend({
170
- phoneNumber: zod.z.string().nullable().optional(),
171
- email: zod.z.string().optional(),
172
- lastSeenAt: FirestoreTimestampSchema.optional(),
173
- lastActiveAt: FirestoreTimestampSchema.optional(),
174
- unreadReplyCount: zod.z.number().default(0),
175
- newReplierCount: zod.z.number().default(0),
176
- /**
177
- * Account tier from UserRecord — surfaced on the self profile so the
178
- * client can gate paid features. Optional for legacy docs without the
179
- * field; consumers should treat missing as `'free'`.
180
- */
181
- tier: zod.z.enum(["free", "creator_pro"]).optional(),
182
- /**
183
- * Surfaces the linked Bluesky identity (handle + DID) on the public profile
184
- * when true. Persisted on UserRecord; exposed in self/detailed views so the
185
- * settings form can render the toggle's current state.
186
- */
187
- showBlueskyPublicly: zod.z.boolean().optional(),
188
- settings: zod.z.object({
189
- notifications: zod.z.boolean().optional(),
190
- theme: zod.z.string().optional()
191
- }).optional()
68
+ var ProcessingStateSchema = zod.z.object({
69
+ transcribe: ProcessingStageStatusSchema.optional(),
70
+ denoise: ProcessingStageStatusSchema.optional(),
71
+ /** Content CID of the denoised audio variant, once `denoise === 'ready'`. */
72
+ denoisedBlobCid: zod.z.string().optional(),
73
+ updatedAt: FirestoreTimestampSchema
192
74
  });
193
- var ProfileViewAdminSchema = ProfileViewSelfSchema.extend({
194
- blockedUsers: zod.z.array(zod.z.string()).optional(),
195
- followers: zod.z.array(zod.z.string()).optional(),
196
- following: zod.z.array(zod.z.string()).optional(),
197
- reportCount: zod.z.number().optional(),
198
- isBanned: zod.z.boolean().optional()
75
+ var ProcessingViewSchema = zod.z.object({
76
+ transcribe: ProcessingStageStatusSchema.optional(),
77
+ denoise: ProcessingStageStatusSchema.optional()
199
78
  });
200
- var ProfileViewSchema = ProfileViewAdminSchema;
201
79
 
202
80
  // types/audio.ts
203
81
  var StrongRefSchema = zod.z.object({
@@ -210,7 +88,7 @@ var ReplyRefSchema = zod.z.object({
210
88
  });
211
89
  var AudioEmbedSchema = zod.z.object({
212
90
  $type: zod.z.literal("dev.antiphony.embed.audio"),
213
- /** The audio bytes as a content-addressed storage ref (CID/path). */
91
+ /** The audio bytes as a content-addressed blob ref (`ref.$link` = CID). */
214
92
  audio: BlobRefSchema,
215
93
  /** Duration in MILLISECONDS (platform-wide unit; not seconds). */
216
94
  durationMs: zod.z.number().int().min(0).optional(),
@@ -240,11 +118,26 @@ var AudioEmbedViewSchema = zod.z.object({
240
118
  alt: zod.z.string().max(1e4).optional(),
241
119
  waveform: zod.z.array(zod.z.number().int().min(0).max(100)).max(1e3).optional(),
242
120
  /** Lifted from the transcript enrichment record; absent until transcription completes. */
243
- transcript: TimedTranscriptSchema.optional()
121
+ transcript: TimedTranscriptSchema.optional(),
122
+ /**
123
+ * Per-stage audio-processing status (transcribe / denoise), when the app
124
+ * opted into processing on create. Absent otherwise. A `pending` stage
125
+ * means the client should poll (or re-render) for the result. When
126
+ * `denoise === 'ready'`, `url` above already resolves to the cleaned
127
+ * audio variant. See `types/processing.ts`.
128
+ */
129
+ processing: ProcessingViewSchema.optional()
244
130
  });
245
131
  var AudioPostRecordSchema = zod.z.object({
246
132
  /** Storage id (rkey/doc id). */
247
133
  id: zod.z.string(),
134
+ /**
135
+ * Content CID of the canonical lexicon record (CIDv1, dag-cbor, sha2-256
136
+ * — the AT Protocol record-CID rule). Computed at write time over the
137
+ * lexicon projection (public fields only, NOT the storage/tenancy fields
138
+ * below), so StrongRefs built from it are verifiable content addresses.
139
+ */
140
+ cid: zod.z.string(),
248
141
  // --- Tenancy + facets (storage-indexed; NOT in the lexicon) ---
249
142
  /** Origin app that created this record — the multi-tenant isolation key. */
250
143
  originAppId: zod.z.string(),
@@ -262,9 +155,24 @@ var AudioPostRecordSchema = zod.z.object({
262
155
  * opened the branch. Set on replies (deduped, 1–2 ids); absent on prompts
263
156
  * (a prompt's repliers are the app's audience policy, not a fixed pair).
264
157
  * Inherited down the branch so reply gating is an O(1) field check, never a
265
- * thread walk. See `specs/antiphony-data-model.md` §6 "Reply gating".
158
+ * thread walk.
266
159
  */
267
160
  threadParticipants: zod.z.array(zod.z.string()).optional(),
161
+ /**
162
+ * Author of this reply's thread ROOT (the prompt) — the reply's recipient,
163
+ * the person whose "replies to me" feed it lands in. Denormalized at write
164
+ * time so "replies whose root author is X" is a cheap composite-index query
165
+ * (see `queryByRootAuthor`). Set on replies (`kind === 'reply'`); absent on
166
+ * prompts. Storage-layer facet, NOT in the public lexicon or the record CID.
167
+ */
168
+ rootAuthorId: zod.z.string().optional(),
169
+ /**
170
+ * Async audio-processing state (transcribe / denoise), present iff the app
171
+ * opted into processing on create. Mutated by the processing worker after
172
+ * the post is created — storage-layer, NOT in the lexicon or the record
173
+ * CID. See `types/processing.ts`.
174
+ */
175
+ processing: ProcessingStateSchema.optional(),
268
176
  // --- Lexicon fields (public contract) ---
269
177
  /** User-authored text (bsky-semantic). May be empty for pure-audio posts. NEVER the transcript. */
270
178
  text: zod.z.string().max(3e3),
@@ -283,10 +191,11 @@ var AudioPostRecordSchema = zod.z.object({
283
191
  }).refine(
284
192
  // `kind` is denormalized from `reply` presence at write time; enforce the
285
193
  // invariant so an inconsistent record can't be written or read silently.
286
- // A reply has `reply` and no `title`; a prompt has neither a `reply`.
287
- (r) => r.kind === "reply" ? !!r.reply && r.title === void 0 : !r.reply,
194
+ // A reply has `reply`, no `title`, and a stamped `rootAuthorId` (its
195
+ // recipient facet); a prompt has none of those.
196
+ (r) => r.kind === "reply" ? !!r.reply && r.title === void 0 && r.rootAuthorId !== void 0 : !r.reply && r.rootAuthorId === void 0,
288
197
  {
289
- message: "kind must match reply presence: 'reply' \u21D2 reply set & no title; 'prompt' \u21D2 no reply",
198
+ message: "kind must match reply presence: 'reply' \u21D2 reply set, no title, rootAuthorId set; 'prompt' \u21D2 no reply, no rootAuthorId",
290
199
  path: ["kind"]
291
200
  }
292
201
  );
@@ -329,9 +238,13 @@ var PostRecordPublicSchema = zod.z.object({
329
238
  var AudioPostViewSchema = zod.z.object({
330
239
  /** at:// URI (or internal ref) identifying the post. */
331
240
  uri: zod.z.string(),
332
- cid: zod.z.string().optional(),
241
+ /** Content CID of the canonical record (see `AudioPostRecordSchema.cid`). */
242
+ cid: zod.z.string(),
333
243
  kind: zod.z.enum(["prompt", "reply"]),
334
- author: ProfileViewBasicSchema,
244
+ /** The acting actor's app-scoped id — an opaque attribution ref, not a profile. */
245
+ authorId: zod.z.string(),
246
+ /** The author's app-asserted AT Protocol DID, when the caller provided one. */
247
+ authorDid: zod.z.string().optional(),
335
248
  record: PostRecordPublicSchema,
336
249
  /** Hydrated audio embed (signed URL + lifted transcript). */
337
250
  embed: AudioEmbedViewSchema.optional(),
@@ -351,7 +264,14 @@ var CreateAudioPostRequestSchema = zod.z.object({
351
264
  /** BCP-47 language tags. */
352
265
  langs: zod.z.array(zod.z.string()).max(3).optional(),
353
266
  /** Author self-label values (content warnings). */
354
- selfLabels: zod.z.array(zod.z.string()).optional()
267
+ selfLabels: zod.z.array(zod.z.string()).optional(),
268
+ /**
269
+ * Opt-in audio processing for this post's audio (transcribe / denoise).
270
+ * Both default off. Stages the deployment can't provide come back marked
271
+ * `skipped` on the view rather than failing the create. See
272
+ * `types/processing.ts`.
273
+ */
274
+ processing: ProcessingRequestSchema.optional()
355
275
  }).refine((d) => !(d.reply && d.title), {
356
276
  message: "Replies cannot have a title",
357
277
  path: ["title"]
@@ -359,34 +279,11 @@ var CreateAudioPostRequestSchema = zod.z.object({
359
279
  message: "Post must have text or an audio embed",
360
280
  path: ["text"]
361
281
  });
362
- var UpdateProfileRequestSchema = zod.z.object({
363
- handle: zod.z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]+$/).optional(),
364
- displayName: zod.z.string().max(50).optional(),
365
- bio: zod.z.string().max(160).optional(),
366
- avatarUrl: zod.z.string().url().nullable().optional(),
367
- usageIntent: zod.z.string().max(200).nullable().optional(),
368
- /**
369
- * Personal website surfaced on the public profile. Accepts a URL, empty
370
- * string, or null from the client; normalizes empty string → null so the
371
- * value stored on `UserRecord` (which requires `.url() | null`) round-trips
372
- * cleanly through `UserRecordSchema.parse` on subsequent reads.
373
- */
374
- website: zod.z.union([zod.z.string().url(), zod.z.literal(""), zod.z.null()]).optional().transform((v) => v === "" ? null : v),
375
- /** Up to 5 public links (label + URL) shown under the bio. */
376
- links: zod.z.array(zod.z.object({
377
- label: zod.z.string().min(1).max(40),
378
- url: zod.z.string().url()
379
- })).max(5).optional(),
380
- /** When true, surfaces the linked Bluesky identity on the public profile. */
381
- showBlueskyPublicly: zod.z.boolean().optional()
282
+ var PatchAudioPostRequestSchema = zod.z.object({
283
+ /** Opt-in audio processing to (re)run for this post's audio. Required — a
284
+ * PATCH with no processing request is a no-op and rejected as invalid. */
285
+ processing: ProcessingRequestSchema
382
286
  });
383
- var PublicProfileDtoSchema = ProfileViewBasicSchema.extend({
384
- bluesky: zod.z.object({
385
- handle: zod.z.string(),
386
- did: zod.z.string()
387
- }).optional()
388
- });
389
- var ActorViewSchema = ProfileViewSelfSchema;
390
287
 
391
288
  // nsid.ts
392
289
  var NSID = {
@@ -394,6 +291,10 @@ var NSID = {
394
291
  // See lexicons/dev/antiphony/ + packages/shared/types/audio.ts.
395
292
  AudioPost: "dev.antiphony.audio.post",
396
293
  AudioTranscript: "dev.antiphony.audio.transcript",
294
+ // Portable lexicon only — the core never stores actor profiles; the
295
+ // caller BFF is the sole authority for profile data (see
296
+ // specs/core-bff-boundary.md, "actor.profile lexicon"). Hence no
297
+ // COLLECTIONS entry below.
397
298
  ActorProfile: "dev.antiphony.actor.profile"
398
299
  };
399
300
  var EMBED_NSID = {
@@ -401,16 +302,10 @@ var EMBED_NSID = {
401
302
  RecordWithAudio: "dev.antiphony.embed.recordWithAudio"
402
303
  };
403
304
  var COLLECTIONS = {
404
- // One post collection + the transcript enrichment namespace + actors.
305
+ // One post collection + the transcript enrichment namespace.
405
306
  [NSID.AudioPost]: "posts",
406
- [NSID.AudioTranscript]: "audio_transcripts",
407
- [NSID.ActorProfile]: "users"
307
+ [NSID.AudioTranscript]: "audio_transcripts"
408
308
  };
409
- function nsidForCollection(collection) {
410
- const entries = Object.entries(COLLECTIONS);
411
- const match = entries.find(([, col]) => col === collection);
412
- return match == null ? void 0 : match[0];
413
- }
414
309
 
415
310
  // errors/index.ts
416
311
  var ServiceError = class extends Error {
@@ -502,7 +397,6 @@ function reportError(err, context) {
502
397
  }
503
398
 
504
399
  exports.ActorProfileRecordSchema = ActorProfileRecordSchema;
505
- exports.ActorViewSchema = ActorViewSchema;
506
400
  exports.AudioEmbedSchema = AudioEmbedSchema;
507
401
  exports.AudioEmbedViewSchema = AudioEmbedViewSchema;
508
402
  exports.AudioPostRecordSchema = AudioPostRecordSchema;
@@ -516,13 +410,12 @@ exports.FirestoreTimestampSchema = FirestoreTimestampSchema;
516
410
  exports.ForbiddenError = ForbiddenError;
517
411
  exports.NSID = NSID;
518
412
  exports.NotFoundError = NotFoundError;
413
+ exports.PatchAudioPostRequestSchema = PatchAudioPostRequestSchema;
519
414
  exports.PostRecordPublicSchema = PostRecordPublicSchema;
520
- exports.ProfileViewAdminSchema = ProfileViewAdminSchema;
521
- exports.ProfileViewBasicSchema = ProfileViewBasicSchema;
522
- exports.ProfileViewDetailedSchema = ProfileViewDetailedSchema;
523
- exports.ProfileViewSchema = ProfileViewSchema;
524
- exports.ProfileViewSelfSchema = ProfileViewSelfSchema;
525
- exports.PublicProfileDtoSchema = PublicProfileDtoSchema;
415
+ exports.ProcessingRequestSchema = ProcessingRequestSchema;
416
+ exports.ProcessingStageStatusSchema = ProcessingStageStatusSchema;
417
+ exports.ProcessingStateSchema = ProcessingStateSchema;
418
+ exports.ProcessingViewSchema = ProcessingViewSchema;
526
419
  exports.RateLimitError = RateLimitError;
527
420
  exports.ReplyRefSchema = ReplyRefSchema;
528
421
  exports.ServiceError = ServiceError;
@@ -531,14 +424,8 @@ exports.TimedTranscriptSchema = TimedTranscriptSchema;
531
424
  exports.TranscriptEnrichmentRecordSchema = TranscriptEnrichmentRecordSchema;
532
425
  exports.TranscriptSegmentSchema = TranscriptSegmentSchema;
533
426
  exports.UnauthorizedError = UnauthorizedError;
534
- exports.UpdateProfileRequestSchema = UpdateProfileRequestSchema;
535
- exports.UserRecordSchema = UserRecordSchema;
536
427
  exports.ValidationError = ValidationError;
537
428
  exports.ViewerStateSchema = ViewerStateSchema;
538
429
  exports.buildReportedErrorEvent = buildReportedErrorEvent;
539
- exports.httpsUrl = httpsUrl;
540
430
  exports.isFirestoreTimestamp = isFirestoreTimestamp;
541
- exports.nsidForCollection = nsidForCollection;
542
431
  exports.reportError = reportError;
543
- exports.resolveAudioUrl = resolveAudioUrl;
544
- exports.toProfileViewBasic = toProfileViewBasic;
@@ -1,11 +1,93 @@
1
- export { CreateAudioPostRequest, CreateAudioPostRequestSchema, UpdateProfileRequestSchema } from './api-codecs.cjs';
2
- export { FirestoreTimestamp, FirestoreTimestampSchema, UserRecord, UserRecordSchema, httpsUrl } from './types/records.cjs';
3
- export { ProfileView, ProfileViewAdmin, ProfileViewAdminSchema, ProfileViewBasic, ProfileViewBasicSchema, ProfileViewDetailed, ProfileViewDetailedSchema, ProfileViewSchema, ProfileViewSelf, ProfileViewSelfSchema, toProfileViewBasic } from './types/views.cjs';
1
+ export { CreateAudioPostRequest, CreateAudioPostRequestSchema, PatchAudioPostRequest, PatchAudioPostRequestSchema } from './api-codecs.cjs';
2
+ export { FirestoreTimestamp, FirestoreTimestampSchema } from './types/records.cjs';
4
3
  export { ActorProfileRecord, ActorProfileRecordSchema, AudioEmbed, AudioEmbedSchema, AudioEmbedView, AudioEmbedViewSchema, AudioPostRecord, AudioPostRecordSchema, AudioPostView, AudioPostViewSchema, PostRecordPublic, PostRecordPublicSchema, ReplyRef, ReplyRefSchema, StrongRef, StrongRefSchema, TimedTranscript, TimedTranscriptSchema, TranscriptEnrichmentRecord, TranscriptEnrichmentRecordSchema, TranscriptSegment, TranscriptSegmentSchema, ViewerState, ViewerStateSchema } from './types/audio.cjs';
5
- export { BlobRef, BlobRefSchema, resolveAudioUrl } from './types/blob.cjs';
6
- export { ActorView, ActorViewSchema, PublicProfileDto, PublicProfileDtoSchema } from './types/api.cjs';
7
- export { COLLECTIONS, EMBED_NSID, NSID, NsidValue, nsidForCollection } from './nsid.cjs';
4
+ import { z } from 'zod';
5
+ export { BlobRef, BlobRefSchema } from './types/blob.cjs';
6
+ export { COLLECTIONS, EMBED_NSID, NSID, NsidValue, StoredNsidValue } from './nsid.cjs';
8
7
  export { ConflictError, ForbiddenError, NotFoundError, RateLimitError, ServiceError, UnauthorizedError, ValidationError } from './errors/index.cjs';
9
8
  export { isFirestoreTimestamp } from './utils/index.cjs';
10
9
  export { ReportedErrorEvent, buildReportedErrorEvent, reportError } from './observability/report-error.cjs';
11
- import 'zod';
10
+
11
+ /**
12
+ * Audio hygiene / enrichment processing (B5).
13
+ *
14
+ * Antiphony can, when the calling app opts in, run two pieces of audio
15
+ * processing on a post's audio: **transcription** (machine transcript, the
16
+ * `dev.antiphony.audio.transcript` enrichment) and **denoise** (a cleaned
17
+ * audio variant for playback). Both are OFF by default — the app asks for
18
+ * them per post via `CreateAudioPostRequest.processing`.
19
+ *
20
+ * The work runs asynchronously (outside the create request), so a post
21
+ * carries a mutable `processing` state that starts `pending` and settles to
22
+ * `ready`/`failed`/`skipped` per stage. That state is a storage-layer field —
23
+ * it is NOT part of the canonical lexicon record and never enters the record
24
+ * CID (like `kind` and `threadParticipants`), so processing can update it
25
+ * without changing the post's content address.
26
+ */
27
+ /**
28
+ * Per-stage status.
29
+ * - `pending` — requested, not yet done (the worker acts on these).
30
+ * - `ready` — completed.
31
+ * - `failed` — attempted and errored.
32
+ * - `skipped` — requested but this deployment has no provider for it.
33
+ */
34
+ declare const ProcessingStageStatusSchema: z.ZodEnum<["pending", "ready", "failed", "skipped"]>;
35
+ type ProcessingStageStatus = z.infer<typeof ProcessingStageStatusSchema>;
36
+ /**
37
+ * What the calling app opts into, on `CreateAudioPostRequest`. Both default
38
+ * off; only `true` values request a stage.
39
+ */
40
+ declare const ProcessingRequestSchema: z.ZodObject<{
41
+ transcribe: z.ZodOptional<z.ZodBoolean>;
42
+ denoise: z.ZodOptional<z.ZodBoolean>;
43
+ }, "strip", z.ZodTypeAny, {
44
+ transcribe?: boolean | undefined;
45
+ denoise?: boolean | undefined;
46
+ }, {
47
+ transcribe?: boolean | undefined;
48
+ denoise?: boolean | undefined;
49
+ }>;
50
+ type ProcessingRequest = z.infer<typeof ProcessingRequestSchema>;
51
+ /**
52
+ * Stored processing state on the post record (storage-layer; not in the CID).
53
+ * A stage key is present iff that stage was requested. `denoisedBlobCid`
54
+ * points at the cleaned audio variant once denoise completes — the record's
55
+ * own `embed.audio.ref.$link` stays the ORIGINAL CID (immutable content
56
+ * address); only the read-time view swaps playback to the cleaned variant.
57
+ */
58
+ declare const ProcessingStateSchema: z.ZodObject<{
59
+ transcribe: z.ZodOptional<z.ZodEnum<["pending", "ready", "failed", "skipped"]>>;
60
+ denoise: z.ZodOptional<z.ZodEnum<["pending", "ready", "failed", "skipped"]>>;
61
+ /** Content CID of the denoised audio variant, once `denoise === 'ready'`. */
62
+ denoisedBlobCid: z.ZodOptional<z.ZodString>;
63
+ updatedAt: z.ZodEffects<z.ZodUnion<[z.ZodType<unknown, z.ZodTypeDef, unknown>, z.ZodString, z.ZodNumber, z.ZodDate]>, Date, unknown>;
64
+ }, "strip", z.ZodTypeAny, {
65
+ updatedAt: Date;
66
+ transcribe?: "pending" | "ready" | "failed" | "skipped" | undefined;
67
+ denoise?: "pending" | "ready" | "failed" | "skipped" | undefined;
68
+ denoisedBlobCid?: string | undefined;
69
+ }, {
70
+ transcribe?: "pending" | "ready" | "failed" | "skipped" | undefined;
71
+ denoise?: "pending" | "ready" | "failed" | "skipped" | undefined;
72
+ denoisedBlobCid?: string | undefined;
73
+ updatedAt?: unknown;
74
+ }>;
75
+ type ProcessingState = z.infer<typeof ProcessingStateSchema>;
76
+ /**
77
+ * The processing status surfaced on the hydrated view — the per-stage status
78
+ * only (no internal storage fields). Absent when no processing was requested.
79
+ * Clients treat any `pending` stage as "still working".
80
+ */
81
+ declare const ProcessingViewSchema: z.ZodObject<{
82
+ transcribe: z.ZodOptional<z.ZodEnum<["pending", "ready", "failed", "skipped"]>>;
83
+ denoise: z.ZodOptional<z.ZodEnum<["pending", "ready", "failed", "skipped"]>>;
84
+ }, "strip", z.ZodTypeAny, {
85
+ transcribe?: "pending" | "ready" | "failed" | "skipped" | undefined;
86
+ denoise?: "pending" | "ready" | "failed" | "skipped" | undefined;
87
+ }, {
88
+ transcribe?: "pending" | "ready" | "failed" | "skipped" | undefined;
89
+ denoise?: "pending" | "ready" | "failed" | "skipped" | undefined;
90
+ }>;
91
+ type ProcessingView = z.infer<typeof ProcessingViewSchema>;
92
+
93
+ export { type ProcessingRequest, ProcessingRequestSchema, type ProcessingStageStatus, ProcessingStageStatusSchema, type ProcessingState, ProcessingStateSchema, type ProcessingView, ProcessingViewSchema };
package/dist/cjs/nsid.cjs CHANGED
@@ -6,6 +6,10 @@ var NSID = {
6
6
  // See lexicons/dev/antiphony/ + packages/shared/types/audio.ts.
7
7
  AudioPost: "dev.antiphony.audio.post",
8
8
  AudioTranscript: "dev.antiphony.audio.transcript",
9
+ // Portable lexicon only — the core never stores actor profiles; the
10
+ // caller BFF is the sole authority for profile data (see
11
+ // specs/core-bff-boundary.md, "actor.profile lexicon"). Hence no
12
+ // COLLECTIONS entry below.
9
13
  ActorProfile: "dev.antiphony.actor.profile"
10
14
  };
11
15
  var EMBED_NSID = {
@@ -13,18 +17,11 @@ var EMBED_NSID = {
13
17
  RecordWithAudio: "dev.antiphony.embed.recordWithAudio"
14
18
  };
15
19
  var COLLECTIONS = {
16
- // One post collection + the transcript enrichment namespace + actors.
20
+ // One post collection + the transcript enrichment namespace.
17
21
  [NSID.AudioPost]: "posts",
18
- [NSID.AudioTranscript]: "audio_transcripts",
19
- [NSID.ActorProfile]: "users"
22
+ [NSID.AudioTranscript]: "audio_transcripts"
20
23
  };
21
- function nsidForCollection(collection) {
22
- const entries = Object.entries(COLLECTIONS);
23
- const match = entries.find(([, col]) => col === collection);
24
- return match == null ? void 0 : match[0];
25
- }
26
24
 
27
25
  exports.COLLECTIONS = COLLECTIONS;
28
26
  exports.EMBED_NSID = EMBED_NSID;
29
27
  exports.NSID = NSID;
30
- exports.nsidForCollection = nsidForCollection;
@@ -13,6 +13,8 @@ declare const NSID: {
13
13
  readonly ActorProfile: "dev.antiphony.actor.profile";
14
14
  };
15
15
  type NsidValue = typeof NSID[keyof typeof NSID];
16
+ /** The subset of record NSIDs the core actually stores. */
17
+ type StoredNsidValue = typeof NSID.AudioPost | typeof NSID.AudioTranscript;
16
18
  /**
17
19
  * Antiphony embed NSIDs. Embeds live inline on a post's `embed` field, not in
18
20
  * their own collection — kept out of `NSID`/`COLLECTIONS`.
@@ -22,13 +24,10 @@ declare const EMBED_NSID: {
22
24
  readonly RecordWithAudio: "dev.antiphony.embed.recordWithAudio";
23
25
  };
24
26
  /**
25
- * Maps AT Protocol record-type NSIDs to Firestore collection names.
26
- * When migrating to a PDS, this mapping becomes the adapter layer.
27
+ * Maps the STORED AT Protocol record-type NSIDs to Firestore collection
28
+ * names. When migrating to a PDS, this mapping becomes the adapter layer.
29
+ * `actor.profile` is deliberately absent — portable schema, no core storage.
27
30
  */
28
- declare const COLLECTIONS: Record<NsidValue, string>;
29
- /**
30
- * Reverse lookup: get the NSID for a Firestore collection name.
31
- */
32
- declare function nsidForCollection(collection: string): NsidValue | undefined;
31
+ declare const COLLECTIONS: Record<StoredNsidValue, string>;
33
32
 
34
- export { COLLECTIONS, EMBED_NSID, NSID, type NsidValue, nsidForCollection };
33
+ export { COLLECTIONS, EMBED_NSID, NSID, type NsidValue, type StoredNsidValue };