@antiphony/shared 0.4.0 → 0.5.1

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.
@@ -46,21 +46,109 @@ var FirestoreTimestampSchema = zod.z.union([
46
46
  return date;
47
47
  });
48
48
  var ProcessingStageStatusSchema = zod.z.enum(["pending", "ready", "failed", "skipped"]);
49
+ var PROCESSING_STAGES = ["denoise", "trim", "transcribe", "waveform"];
50
+ zod.z.enum(PROCESSING_STAGES);
49
51
  var ProcessingRequestSchema = zod.z.object({
50
52
  transcribe: zod.z.boolean().optional(),
51
- denoise: zod.z.boolean().optional()
53
+ denoise: zod.z.boolean().optional(),
54
+ trim: zod.z.boolean().optional(),
55
+ waveform: zod.z.boolean().optional(),
56
+ /**
57
+ * Whether a completed byte-mutating stage should invalidate and recompute
58
+ * the derived artifacts that describe the old audio. Defaults to **true**
59
+ * — a transcript of superseded audio is wrong, not merely stale.
60
+ *
61
+ * `false` opts out, for an app that would rather keep the existing
62
+ * transcript than pay to regenerate it. It does NOT name a stage, so a
63
+ * request carrying only `reprocess` requests no work.
64
+ */
65
+ reprocess: zod.z.boolean().optional()
52
66
  });
53
- var ProcessingStateSchema = zod.z.object({
67
+ var ProcessingStageMapSchema = zod.z.object({
54
68
  transcribe: ProcessingStageStatusSchema.optional(),
55
69
  denoise: ProcessingStageStatusSchema.optional(),
56
- /** Content CID of the denoised audio variant, once `denoise === 'ready'`. */
57
- denoisedBlobCid: zod.z.string().optional(),
58
- updatedAt: FirestoreTimestampSchema
70
+ trim: ProcessingStageStatusSchema.optional(),
71
+ waveform: ProcessingStageStatusSchema.optional()
59
72
  });
60
- var ProcessingViewSchema = zod.z.object({
61
- transcribe: ProcessingStageStatusSchema.optional(),
62
- denoise: ProcessingStageStatusSchema.optional()
73
+ var ResolvedProcessingSchema = ProcessingStageMapSchema.extend({
74
+ reprocess: zod.z.boolean().optional()
63
75
  });
76
+ var ProcessingStateSchema = ResolvedProcessingSchema.extend({
77
+ /**
78
+ * Content CID of the processed audio variant — the composed output of every
79
+ * byte-mutating stage that has completed. The record's own
80
+ * `embed.audio.ref.$link` stays the ORIGINAL CID (immutable content
81
+ * address); only the read-time view swaps playback to this variant.
82
+ */
83
+ processedBlobCid: zod.z.string().optional(),
84
+ /**
85
+ * MIME type of the processed variant. Present because providers may
86
+ * TRANSCODE — the ElevenLabs Voice Isolator returns MP3 regardless of what
87
+ * it is given — so the variant's type cannot be assumed to match
88
+ * `embed.audio.mimeType`. Anything reading the variant's bytes must use
89
+ * this, not the embed's.
90
+ */
91
+ processedMimeType: zod.z.string().optional(),
92
+ /**
93
+ * Duration of the processed variant, when a byte-mutating stage changed it
94
+ * (i.e. trim). Absent when the variant's duration matches the original.
95
+ */
96
+ processedDurationMs: zod.z.number().int().min(0).optional(),
97
+ /**
98
+ * Which denoiser produced the variant's denoise contribution — provenance,
99
+ * the counterpart to a transcript record's `model`.
100
+ *
101
+ * Lives here because a cleaned variant, unlike a transcript, has no record
102
+ * of its own to carry it: it is a blob CID on this state. Without it,
103
+ * changing denoisers leaves no way to tell which variants predate the
104
+ * switch, so nothing can identify what to re-run.
105
+ *
106
+ * Named for the STAGE, not the variant (`processedModel`), because it
107
+ * describes one link of the byte-mutating chain rather than the composed
108
+ * artifact. Trim contributes to the same variant and has no model, and a
109
+ * later external link would want its own field rather than to overwrite
110
+ * this one.
111
+ *
112
+ * Written on every successful denoise, never cleared — it moves with
113
+ * `processedBlobCid`, which is only ever set, never reset. A denoise that
114
+ * FAILS leaves both alone, which is correct: the variant still holds the
115
+ * previous denoiser's output, so the previous model still describes it.
116
+ *
117
+ * Internal, like the other variant fields — `toProcessingView` projects
118
+ * stages only, so this never reaches a client.
119
+ */
120
+ denoiseModel: zod.z.string().optional(),
121
+ /**
122
+ * Peaks for the processed variant, once the `waveform` stage completes.
123
+ * Same normalization and bounds as `embed.waveform` (0–100, max 1000), so
124
+ * a view can never carry a larger payload than the record allows.
125
+ */
126
+ waveformPeaks: zod.z.array(zod.z.number().int().min(0).max(100)).max(1e3).optional(),
127
+ /**
128
+ * When the current runner's exclusive claim on this post expires.
129
+ *
130
+ * Queue delivery is at-least-once, so the same job can arrive twice and
131
+ * run CONCURRENTLY. `process()` is idempotent under sequential retry — it
132
+ * acts on `pending` and re-does nothing already settled — but two passes
133
+ * interleaved is a different failure: both read the same `pending` state,
134
+ * both bill the provider for the same stage, and both write
135
+ * `processedBlobCid`, so the surviving variant is whichever finished last
136
+ * and the other's blob is orphaned.
137
+ *
138
+ * A runner claims this field transactionally before doing any work and
139
+ * clears it when finished; a second runner finding it unexpired declines
140
+ * and returns. It is an EXPIRY, not a boolean lock, because the holder can
141
+ * die mid-run (instance recycled, process killed) with no chance to
142
+ * release — a plain flag would strand the post permanently, where a lapsed
143
+ * lease lets the next delivery pick it up.
144
+ *
145
+ * Internal, like the variant fields above: `toProcessingView` projects
146
+ * stages only, so this never reaches a client.
147
+ */
148
+ leaseUntil: FirestoreTimestampSchema.optional(),
149
+ updatedAt: FirestoreTimestampSchema
150
+ });
151
+ var ProcessingViewSchema = ProcessingStageMapSchema;
64
152
 
65
153
  // types/audio.ts
66
154
  var StrongRefSchema = zod.z.object({
@@ -96,20 +184,34 @@ var TimedTranscriptSchema = zod.z.object({
96
184
  });
97
185
  var AudioEmbedViewSchema = zod.z.object({
98
186
  $type: zod.z.literal("dev.antiphony.embed.audio#view"),
187
+ /**
188
+ * `url`, `durationMs` and `waveform` are RESOLVED, not copied: once
189
+ * processing has produced an audio variant they describe that variant
190
+ * rather than the bytes the client uploaded. They always agree with one
191
+ * another — a duration and a set of peaks are only meaningful against the
192
+ * audio `url` actually points at.
193
+ *
194
+ * A client that stored `durationMs` at upload time should therefore expect
195
+ * it to change (trim removes leading/trailing silence), and should render
196
+ * these three as a set rather than caching them independently. The record's
197
+ * originals are immutable and unaffected; this is a read-time resolution.
198
+ */
99
199
  url: zod.z.string().url(),
100
200
  durationMs: zod.z.number().int().min(0).optional(),
101
- // `alt`/`waveform` are copied from the stored embed; keep the same bounds
102
- // so a view can never carry a larger payload than the record allows.
201
+ // `alt` is copied from the stored embed; keep the same bounds so a view can
202
+ // never carry a larger payload than the record allows.
103
203
  alt: zod.z.string().max(1e4).optional(),
104
204
  waveform: zod.z.array(zod.z.number().int().min(0).max(100)).max(1e3).optional(),
105
205
  /** Lifted from the transcript enrichment record; absent until transcription completes. */
106
206
  transcript: TimedTranscriptSchema.optional(),
107
207
  /**
108
- * Per-stage audio-processing status (transcribe / denoise), when the app
109
- * opted into processing on create. Absent otherwise. A `pending` stage
110
- * means the client should poll (or re-render) for the result. When
111
- * `denoise === 'ready'`, `url` above already resolves to the cleaned
112
- * audio variant. See `types/processing.ts`.
208
+ * Per-stage audio-processing status (denoise / trim / transcribe /
209
+ * waveform), when the app opted into processing. Absent otherwise. A
210
+ * `pending` stage means the client should poll (or re-render) for the
211
+ * result including a stage that returns to `pending` after having been
212
+ * `ready`, which is how a recompute surfaces. Once a byte-mutating stage
213
+ * completes, `url`/`durationMs`/`waveform` above already resolve to the
214
+ * processed audio variant. See `types/processing.ts`.
113
215
  */
114
216
  processing: ProcessingViewSchema.optional()
115
217
  });
@@ -213,10 +315,15 @@ var ViewerStateSchema = zod.z.object({
213
315
  replyDisabledReason: zod.z.enum(["unauthenticated", "not_a_participant"]).optional()
214
316
  });
215
317
  var PostRecordPublicSchema = zod.z.object({
216
- text: zod.z.string(),
217
- title: zod.z.string().optional(),
318
+ // `text`, `title` and `langs` keep the record's bounds, for the same reason
319
+ // `AudioEmbedViewSchema.alt` does: a view must never be able to carry a
320
+ // larger payload than the record it projects. The write path already
321
+ // enforces these, so no stored post can exceed them — stating them here
322
+ // keeps the published contract honest rather than adding a new constraint.
323
+ text: zod.z.string().max(3e3),
324
+ title: zod.z.string().max(3e3).optional(),
218
325
  reply: ReplyRefSchema.optional(),
219
- langs: zod.z.array(zod.z.string()).optional(),
326
+ langs: zod.z.array(zod.z.string()).max(3).optional(),
220
327
  selfLabels: zod.z.array(zod.z.string()).optional(),
221
328
  createdAt: FirestoreTimestampSchema
222
329
  });
@@ -251,9 +358,11 @@ var CreateAudioPostRequestSchema = zod.z.object({
251
358
  /** Author self-label values (content warnings). */
252
359
  selfLabels: zod.z.array(zod.z.string()).optional(),
253
360
  /**
254
- * Opt-in audio processing for this post's audio (transcribe / denoise).
255
- * Both default off. Stages the deployment can't provide come back marked
256
- * `skipped` on the view rather than failing the create. See
361
+ * Opt-in audio processing for this post's audio (denoise / trim /
362
+ * transcribe / waveform). All default off. Stages the deployment can't
363
+ * provide come back marked `skipped` on the view rather than failing the
364
+ * create. A multi-stage request runs denoise → trim → (transcribe,
365
+ * waveform); request stages individually to override that order. See
257
366
  * `types/processing.ts`.
258
367
  */
259
368
  processing: ProcessingRequestSchema.optional()
@@ -53,9 +53,9 @@ declare const CreateAudioPostRequestSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
53
53
  mimeType: string;
54
54
  size: number;
55
55
  };
56
+ waveform?: number[] | undefined;
56
57
  durationMs?: number | undefined;
57
58
  alt?: string | undefined;
58
- waveform?: number[] | undefined;
59
59
  }, {
60
60
  $type: "dev.antiphony.embed.audio";
61
61
  audio: {
@@ -66,9 +66,9 @@ declare const CreateAudioPostRequestSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
66
66
  mimeType: string;
67
67
  size: number;
68
68
  };
69
+ waveform?: number[] | undefined;
69
70
  durationMs?: number | undefined;
70
71
  alt?: string | undefined;
71
- waveform?: number[] | undefined;
72
72
  }>>;
73
73
  /** Present ⇒ this is a reply (StrongRef root + parent). */
74
74
  reply: z.ZodOptional<z.ZodObject<{
@@ -116,26 +116,40 @@ declare const CreateAudioPostRequestSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
116
116
  /** Author self-label values (content warnings). */
117
117
  selfLabels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
118
118
  /**
119
- * Opt-in audio processing for this post's audio (transcribe / denoise).
120
- * Both default off. Stages the deployment can't provide come back marked
121
- * `skipped` on the view rather than failing the create. See
119
+ * Opt-in audio processing for this post's audio (denoise / trim /
120
+ * transcribe / waveform). All default off. Stages the deployment can't
121
+ * provide come back marked `skipped` on the view rather than failing the
122
+ * create. A multi-stage request runs denoise → trim → (transcribe,
123
+ * waveform); request stages individually to override that order. See
122
124
  * `types/processing.ts`.
123
125
  */
124
126
  processing: z.ZodOptional<z.ZodObject<{
125
127
  transcribe: z.ZodOptional<z.ZodBoolean>;
126
128
  denoise: z.ZodOptional<z.ZodBoolean>;
129
+ trim: z.ZodOptional<z.ZodBoolean>;
130
+ waveform: z.ZodOptional<z.ZodBoolean>;
131
+ reprocess: z.ZodOptional<z.ZodBoolean>;
127
132
  }, "strip", z.ZodTypeAny, {
128
- transcribe?: boolean | undefined;
129
133
  denoise?: boolean | undefined;
130
- }, {
134
+ trim?: boolean | undefined;
131
135
  transcribe?: boolean | undefined;
136
+ waveform?: boolean | undefined;
137
+ reprocess?: boolean | undefined;
138
+ }, {
132
139
  denoise?: boolean | undefined;
140
+ trim?: boolean | undefined;
141
+ transcribe?: boolean | undefined;
142
+ waveform?: boolean | undefined;
143
+ reprocess?: boolean | undefined;
133
144
  }>>;
134
145
  }, "strip", z.ZodTypeAny, {
135
146
  text: string;
136
147
  processing?: {
137
- transcribe?: boolean | undefined;
138
148
  denoise?: boolean | undefined;
149
+ trim?: boolean | undefined;
150
+ transcribe?: boolean | undefined;
151
+ waveform?: boolean | undefined;
152
+ reprocess?: boolean | undefined;
139
153
  } | undefined;
140
154
  reply?: {
141
155
  root: {
@@ -158,17 +172,20 @@ declare const CreateAudioPostRequestSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
158
172
  mimeType: string;
159
173
  size: number;
160
174
  };
175
+ waveform?: number[] | undefined;
161
176
  durationMs?: number | undefined;
162
177
  alt?: string | undefined;
163
- waveform?: number[] | undefined;
164
178
  } | undefined;
165
179
  langs?: string[] | undefined;
166
180
  selfLabels?: string[] | undefined;
167
181
  }, {
168
182
  text?: string | undefined;
169
183
  processing?: {
170
- transcribe?: boolean | undefined;
171
184
  denoise?: boolean | undefined;
185
+ trim?: boolean | undefined;
186
+ transcribe?: boolean | undefined;
187
+ waveform?: boolean | undefined;
188
+ reprocess?: boolean | undefined;
172
189
  } | undefined;
173
190
  reply?: {
174
191
  root: {
@@ -191,17 +208,20 @@ declare const CreateAudioPostRequestSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
191
208
  mimeType: string;
192
209
  size: number;
193
210
  };
211
+ waveform?: number[] | undefined;
194
212
  durationMs?: number | undefined;
195
213
  alt?: string | undefined;
196
- waveform?: number[] | undefined;
197
214
  } | undefined;
198
215
  langs?: string[] | undefined;
199
216
  selfLabels?: string[] | undefined;
200
217
  }>, {
201
218
  text: string;
202
219
  processing?: {
203
- transcribe?: boolean | undefined;
204
220
  denoise?: boolean | undefined;
221
+ trim?: boolean | undefined;
222
+ transcribe?: boolean | undefined;
223
+ waveform?: boolean | undefined;
224
+ reprocess?: boolean | undefined;
205
225
  } | undefined;
206
226
  reply?: {
207
227
  root: {
@@ -224,17 +244,20 @@ declare const CreateAudioPostRequestSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
224
244
  mimeType: string;
225
245
  size: number;
226
246
  };
247
+ waveform?: number[] | undefined;
227
248
  durationMs?: number | undefined;
228
249
  alt?: string | undefined;
229
- waveform?: number[] | undefined;
230
250
  } | undefined;
231
251
  langs?: string[] | undefined;
232
252
  selfLabels?: string[] | undefined;
233
253
  }, {
234
254
  text?: string | undefined;
235
255
  processing?: {
236
- transcribe?: boolean | undefined;
237
256
  denoise?: boolean | undefined;
257
+ trim?: boolean | undefined;
258
+ transcribe?: boolean | undefined;
259
+ waveform?: boolean | undefined;
260
+ reprocess?: boolean | undefined;
238
261
  } | undefined;
239
262
  reply?: {
240
263
  root: {
@@ -257,17 +280,20 @@ declare const CreateAudioPostRequestSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
257
280
  mimeType: string;
258
281
  size: number;
259
282
  };
283
+ waveform?: number[] | undefined;
260
284
  durationMs?: number | undefined;
261
285
  alt?: string | undefined;
262
- waveform?: number[] | undefined;
263
286
  } | undefined;
264
287
  langs?: string[] | undefined;
265
288
  selfLabels?: string[] | undefined;
266
289
  }>, {
267
290
  text: string;
268
291
  processing?: {
269
- transcribe?: boolean | undefined;
270
292
  denoise?: boolean | undefined;
293
+ trim?: boolean | undefined;
294
+ transcribe?: boolean | undefined;
295
+ waveform?: boolean | undefined;
296
+ reprocess?: boolean | undefined;
271
297
  } | undefined;
272
298
  reply?: {
273
299
  root: {
@@ -290,17 +316,20 @@ declare const CreateAudioPostRequestSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
290
316
  mimeType: string;
291
317
  size: number;
292
318
  };
319
+ waveform?: number[] | undefined;
293
320
  durationMs?: number | undefined;
294
321
  alt?: string | undefined;
295
- waveform?: number[] | undefined;
296
322
  } | undefined;
297
323
  langs?: string[] | undefined;
298
324
  selfLabels?: string[] | undefined;
299
325
  }, {
300
326
  text?: string | undefined;
301
327
  processing?: {
302
- transcribe?: boolean | undefined;
303
328
  denoise?: boolean | undefined;
329
+ trim?: boolean | undefined;
330
+ transcribe?: boolean | undefined;
331
+ waveform?: boolean | undefined;
332
+ reprocess?: boolean | undefined;
304
333
  } | undefined;
305
334
  reply?: {
306
335
  root: {
@@ -323,9 +352,9 @@ declare const CreateAudioPostRequestSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
323
352
  mimeType: string;
324
353
  size: number;
325
354
  };
355
+ waveform?: number[] | undefined;
326
356
  durationMs?: number | undefined;
327
357
  alt?: string | undefined;
328
- waveform?: number[] | undefined;
329
358
  } | undefined;
330
359
  langs?: string[] | undefined;
331
360
  selfLabels?: string[] | undefined;
@@ -346,22 +375,37 @@ declare const PatchAudioPostRequestSchema: z.ZodObject<{
346
375
  processing: z.ZodObject<{
347
376
  transcribe: z.ZodOptional<z.ZodBoolean>;
348
377
  denoise: z.ZodOptional<z.ZodBoolean>;
378
+ trim: z.ZodOptional<z.ZodBoolean>;
379
+ waveform: z.ZodOptional<z.ZodBoolean>;
380
+ reprocess: z.ZodOptional<z.ZodBoolean>;
349
381
  }, "strip", z.ZodTypeAny, {
350
- transcribe?: boolean | undefined;
351
382
  denoise?: boolean | undefined;
352
- }, {
383
+ trim?: boolean | undefined;
353
384
  transcribe?: boolean | undefined;
385
+ waveform?: boolean | undefined;
386
+ reprocess?: boolean | undefined;
387
+ }, {
354
388
  denoise?: boolean | undefined;
389
+ trim?: boolean | undefined;
390
+ transcribe?: boolean | undefined;
391
+ waveform?: boolean | undefined;
392
+ reprocess?: boolean | undefined;
355
393
  }>;
356
394
  }, "strip", z.ZodTypeAny, {
357
395
  processing: {
358
- transcribe?: boolean | undefined;
359
396
  denoise?: boolean | undefined;
397
+ trim?: boolean | undefined;
398
+ transcribe?: boolean | undefined;
399
+ waveform?: boolean | undefined;
400
+ reprocess?: boolean | undefined;
360
401
  };
361
402
  }, {
362
403
  processing: {
363
- transcribe?: boolean | undefined;
364
404
  denoise?: boolean | undefined;
405
+ trim?: boolean | undefined;
406
+ transcribe?: boolean | undefined;
407
+ waveform?: boolean | undefined;
408
+ reprocess?: boolean | undefined;
365
409
  };
366
410
  }>;
367
411
  type PatchAudioPostRequest = z.infer<typeof PatchAudioPostRequestSchema>;