video-editing 2.0.0 → 3.1.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/index.d.ts CHANGED
@@ -3029,8 +3029,8 @@ declare function resolvePhrase(stream: StreamWord[], phrase: string, opts?: Reso
3029
3029
  type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
3030
3030
  declare const DEFAULT_TIMEOUT_MS = 30000;
3031
3031
  declare const DEFAULT_DOWNLOAD_TIMEOUT_MS = 300000;
3032
- /** base = --api-base flag → CLIPREADY_API_BASE → API_BASE. */
3033
- declare function resolveApiBase(flag: string | undefined, env?: NodeJS.ProcessEnv): string | undefined;
3032
+ /** base = --api-base flag → CLIPREADY_API_BASE → API_BASE → the hosted cloud. */
3033
+ declare function resolveApiBase(flag: string | undefined, env?: NodeJS.ProcessEnv): string;
3034
3034
  /** credential = --api-key flag → CLIPREADY_API_KEY → RUN_TOKEN. */
3035
3035
  declare function resolveApiKey(flag: string | undefined, env?: NodeJS.ProcessEnv): string | undefined;
3036
3036
  /** video id = --video-id flag → VIDEO_ID. */
@@ -3059,8 +3059,16 @@ declare function meUrl(base: string): string;
3059
3059
  declare function projectsUrl(base: string): string;
3060
3060
  declare function projectVideosUrl(base: string, projectId: string): string;
3061
3061
  declare function runUrl(base: string, runId: string): string;
3062
+ /** Chunked-upload session routes: /api/v1/uploads/multipart[/parts|complete|abort|relay|relay-complete]. */
3063
+ declare function multipartUrl(base: string, tail?: "parts" | "complete" | "abort" | "relay" | "relay-complete"): string;
3064
+ /** Authenticated relay POST for one raw sub-chunk of a multipart part
3065
+ * (i is the 1-based sub-chunk index, of the sub-chunk count). */
3066
+ declare function multipartRelayUrl(base: string, uploadId: string, n: number, i: number, of: number): string;
3062
3067
  declare function filesUrl(base: string, videoId: string, path?: string): string;
3063
3068
  declare function transcribeUrl(base: string, videoId: string): string;
3069
+ /** POST /videos/{id}/ingest — server-side probe + audio extraction +
3070
+ * transcription + screening over the uploaded source (202 {run_id}). */
3071
+ declare function ingestUrl(base: string, videoId: string): string;
3064
3072
  declare function compileUrl(base: string, videoId: string): string;
3065
3073
  declare function resolveUrl(base: string, videoId: string): string;
3066
3074
  declare function verifyUrl(base: string, videoId: string): string;
@@ -3106,6 +3114,18 @@ interface QaWaveformResult {
3106
3114
  url: string;
3107
3115
  words: QaWaveWord[];
3108
3116
  }
3117
+ /** POST /videos/{id}/qa {kind:"inspect"} → the combined filmstrip + waveform
3118
+ * composite with the plan's cut regions shaded. */
3119
+ interface QaInspectResult {
3120
+ url: string;
3121
+ tStart: number;
3122
+ tEnd: number;
3123
+ cuts: Array<{
3124
+ start: number;
3125
+ end: number;
3126
+ }>;
3127
+ cached: boolean;
3128
+ }
3109
3129
  /** One row of the VFS listing. */
3110
3130
  interface VfsFileEntry {
3111
3131
  path: string;
@@ -3196,6 +3216,18 @@ declare class CloudClient {
3196
3216
  private readonly timeoutMs;
3197
3217
  constructor(cfg: ResolvedConfig, opts?: ClientOptions);
3198
3218
  private requireVideoId;
3219
+ /** Same client (same fetch/timeout) bound to a video id — for flows that
3220
+ * create the video mid-run (init). */
3221
+ withVideoId(videoId: string): CloudClient;
3222
+ /** The injected fetch — for helpers outside the class (multipart part PUTs)
3223
+ * that need raw Response access (e.g. the ETag header). */
3224
+ get fetch(): FetchLike;
3225
+ /** POST a JSON body to an absolute API URL with auth — public wrapper over
3226
+ * the private transport for helpers living outside the class (multipart). */
3227
+ postJson(url: string, body: unknown): Promise<unknown>;
3228
+ /** POST raw binary bytes to an authenticated API URL (multipart relay
3229
+ * sub-chunks). Content-Type application/octet-stream; JSON response. */
3230
+ postBinary(url: string, bytes: Uint8Array, timeoutMs?: number): Promise<unknown>;
3199
3231
  private request;
3200
3232
  createRender(mode: RenderMode): Promise<RenderCreate>;
3201
3233
  getRender(renderId: string): Promise<RenderState>;
@@ -3209,6 +3241,11 @@ declare class CloudClient {
3209
3241
  start: number;
3210
3242
  end: number;
3211
3243
  }): Promise<QaWaveformResult>;
3244
+ qaInspect(args: {
3245
+ start: number;
3246
+ end: number;
3247
+ nFrames?: number;
3248
+ }): Promise<QaInspectResult>;
3212
3249
  listArtifacts(): Promise<string[]>;
3213
3250
  getArtifact(name: string): Promise<ArtifactContent>;
3214
3251
  /** POST /api/v1/assets: request an asset row + presigned upload URL
@@ -3220,8 +3257,11 @@ declare class CloudClient {
3220
3257
  filename?: string;
3221
3258
  }): Promise<AssetCreate>;
3222
3259
  /** PUT raw bytes to a presigned upload URL. No Authorization header — the
3223
- * signed URL carries its own credentials and may be a different host. */
3224
- upload(url: string, bytes: Uint8Array, contentType: string, timeoutMs?: number): Promise<void>;
3260
+ * signed URL carries its own credentials and may be a different host.
3261
+ * Mid-stream network failures (connection resets, TLS record errors) and
3262
+ * 5xx responses are retried with exponential backoff — the whole body is
3263
+ * an in-memory buffer, so every attempt is a clean full replay. */
3264
+ upload(url: string, bytes: Uint8Array, contentType: string, timeoutMs?: number, maxAttempts?: number): Promise<void>;
3225
3265
  getReview(): Promise<ReviewSession>;
3226
3266
  /** POST a review-round event ({run_id, type, payload?}); expects {ok:true}. */
3227
3267
  pushReview(body: {
@@ -3276,13 +3316,29 @@ declare class CloudClient {
3276
3316
  }): Promise<{
3277
3317
  runId: string;
3278
3318
  }>;
3279
- /** POST /videos/{id}/verify → 202 {run_id}. */
3280
- verifyStart(body: {
3281
- wav_path: string;
3282
- preview_duration_s: number;
3319
+ /** POST /videos/{id}/ingest {stem?} → 202 {run_id}. Server-side probe + audio
3320
+ * extraction + transcription + screening over the uploaded source. The stem
3321
+ * names every derived artifact (transcripts/<stem>.json, audio/<stem>.wav) —
3322
+ * omit it and the server defaults to "source". */
3323
+ ingestStart(stem?: string): Promise<{
3324
+ runId: string;
3325
+ }>;
3326
+ /** POST /videos/{id}/verify {mode?, window_s?} → 202 {run_id}. The server
3327
+ * sources the preview audio itself — nothing is uploaded. */
3328
+ verifyStart(body?: {
3283
3329
  mode?: string;
3284
3330
  window_s?: number;
3285
- edl?: unknown;
3331
+ }): Promise<{
3332
+ runId: string;
3333
+ }>;
3334
+ smoothJoinsStart(body?: {
3335
+ crossfade_ms?: number;
3336
+ curve?: string;
3337
+ max_ms?: number;
3338
+ joins?: {
3339
+ index: number;
3340
+ crossfade_ms: number;
3341
+ }[];
3286
3342
  }): Promise<{
3287
3343
  runId: string;
3288
3344
  }>;
@@ -3386,9 +3442,70 @@ interface PushedFile {
3386
3442
  * inline; larger/binary payloads go presign → upload → commit. */
3387
3443
  declare function pushFiles(client: CloudClient, jobDir: string, paths: string[], opts?: {
3388
3444
  onFile?: (f: PushedFile) => void;
3445
+ log?: (line: string) => void;
3389
3446
  }): Promise<PushedFile[]>;
3390
- /** Upload one in-memory payload to the VFS (presign path used for WAVs). */
3391
- declare function uploadVfsBytes(client: CloudClient, vfsPath: string, bytes: Uint8Array, contentType: string): Promise<void>;
3447
+ /** Upload one in-memory payload to the VFS (used for WAVs and pushed renders).
3448
+ * Payloads over 8MB go chunked (multipart, per-part retry) when the server
3449
+ * supports it; otherwise — and for small payloads — the classic presign →
3450
+ * single PUT → commit flow. */
3451
+ declare function uploadVfsPayload(client: CloudClient, vfsPath: string, bytes: Uint8Array, contentType: string, opts?: {
3452
+ sha256?: string;
3453
+ log?: (line: string) => void;
3454
+ }): Promise<void>;
3455
+ /** Back-compat alias: upload one in-memory payload to the VFS. */
3456
+ declare function uploadVfsBytes(client: CloudClient, vfsPath: string, bytes: Uint8Array, contentType: string, log?: (line: string) => void): Promise<void>;
3457
+
3458
+ /** Payloads LARGER than this go multipart; at or below, the single-shot path. */
3459
+ declare const MULTIPART_THRESHOLD_BYTES: number;
3460
+ /** Direct part-PUT transport failures before the relay fallback kicks in. */
3461
+ declare const RELAY_DIRECT_ATTEMPTS = 3;
3462
+ /** Relay sub-chunk ceiling (3.5MB — under the API route's body limit). */
3463
+ declare const RELAY_SUBCHUNK_BYTES = 3670016;
3464
+ /** Multipart applies above the 8MB threshold. Accepts a byte count (streaming
3465
+ * callers stat the file) or an in-memory payload. */
3466
+ declare function shouldMultipart(sizeOrBytes: number | Uint8Array): boolean;
3467
+ /** A random-access byte source: only `len`-sized windows are ever materialized,
3468
+ * so uploads stay 2GB-safe (memory ≤ concurrency × part_size). */
3469
+ interface MultipartSource {
3470
+ size: number;
3471
+ /** Read exactly min(len, size - offset) bytes starting at offset. */
3472
+ readSlice(offset: number, len: number): Promise<Buffer>;
3473
+ }
3474
+ /** Wrap an in-memory payload as a source (small VFS pushes). */
3475
+ declare function bytesSource(bytes: Uint8Array): MultipartSource;
3476
+ interface FileSource extends MultipartSource {
3477
+ /** Close the underlying fd. Callers MUST close on completion AND failure. */
3478
+ close(): Promise<void>;
3479
+ }
3480
+ /** File-backed source: fs/promises open + positional reads. Never loads the
3481
+ * whole file; concurrent readSlice calls are safe (positional pread). */
3482
+ declare function openFileSource(path: string): Promise<FileSource>;
3483
+ interface MultipartOptions {
3484
+ kind: "asset" | "jobfile";
3485
+ /** In-memory payload (small VFS pushes). Exactly one of bytes/source. */
3486
+ bytes?: Uint8Array;
3487
+ /** Streaming payload (init sources) — 2GB-safe. */
3488
+ source?: MultipartSource;
3489
+ contentType: string;
3490
+ /** kind "asset": original filename (no video exists yet at init time). */
3491
+ filename?: string;
3492
+ /** kind "jobfile": owning video + VFS path (+ sha256 for integrity). */
3493
+ videoId?: string;
3494
+ path?: string;
3495
+ sha256?: string;
3496
+ log?: (line: string) => void;
3497
+ /** Retry backoff schedule override (tests) — defaults to jitteredBackoffMs. */
3498
+ backoffMs?: (attempt: number) => number;
3499
+ }
3500
+ /** Chunked upload of a payload (in-memory bytes OR a streaming source).
3501
+ * Returns "unavailable" ONLY when the server cannot do multipart at all
3502
+ * (503 multipart_unavailable / 404 / 405 on session create) so the caller can
3503
+ * fall back to the single-shot presign path. Any other failure aborts the
3504
+ * session (best-effort) and throws. Parts are sliced through
3505
+ * source.readSlice, so memory stays ≤ PART_CONCURRENCY × part_size. */
3506
+ declare function uploadMultipart(client: CloudClient, opts: MultipartOptions, timeoutMs?: number): Promise<{
3507
+ assetId?: string;
3508
+ } | "unavailable">;
3392
3509
 
3393
3510
  interface JobFile {
3394
3511
  video_id: string;
@@ -3396,6 +3513,10 @@ interface JobFile {
3396
3513
  api_base: string;
3397
3514
  stem: string;
3398
3515
  duration_s: number;
3516
+ /** Absolute path of the original init source (used as the transcribe media
3517
+ * fallback and to re-bake vertical_src.mp4 on demand). Optional: job.json
3518
+ * files written before 2.0.1 don't have it. */
3519
+ source_path?: string;
3399
3520
  }
3400
3521
  declare function jobJsonPath(jobDir: string): string;
3401
3522
  declare function writeJobFile(jobDir: string, job: JobFile): string;
@@ -3403,12 +3524,24 @@ declare function readJobFile(jobDir: string): JobFile | null;
3403
3524
  /** Video id fallback for job-dir verbs: flag/env (already resolved) → job.json. */
3404
3525
  declare function videoIdFromJob(jobDir: string, resolved: string | undefined): string;
3405
3526
 
3527
+ /** Sanitize a source-derived stem to the server's filename-safe charset
3528
+ * (letters, digits, `.` `_` `-`): every run of anything else becomes a single
3529
+ * `-`, leading/trailing `-` are trimmed. Apostrophes, spaces, unicode
3530
+ * punctuation etc. in the source filename must never leak into the stem —
3531
+ * the server rejects them ("stem must be a filename-safe string"). Falls back
3532
+ * to "source" when nothing survives. */
3533
+ declare function sanitizeStem(name: string): string;
3534
+ /** The artifact set init pulls after the ingest run completes (plus the
3535
+ * prompts/ prefix). probe.json carries the server-side media probe. */
3536
+ declare function ingestArtifactSet(stem: string): string[];
3537
+ /** Read duration_s out of a pulled probe.json ({duration_s, width, height,
3538
+ * rotation}). Throws when the file is absent or carries no usable duration. */
3539
+ declare function readProbeDuration(jobDir: string): number;
3406
3540
  interface InitOptions {
3407
3541
  source: string;
3408
3542
  jobDir?: string;
3409
3543
  title?: string;
3410
- /** Bake the vertical 9:16 master locally and upload THAT as the source. */
3411
- master?: boolean;
3544
+ pollIntervalMs?: number;
3412
3545
  verbose?: boolean;
3413
3546
  }
3414
3547
  interface InitResult {
@@ -3420,63 +3553,28 @@ interface InitResult {
3420
3553
  durationS: number;
3421
3554
  uploaded: string;
3422
3555
  uploadedBytes: number;
3556
+ runId: string;
3557
+ pulled: FilesPullResult;
3558
+ /** Watch/review page in the clipready web app. */
3559
+ webUrl: string;
3423
3560
  }
3424
3561
  declare function initCloudJob(client: CloudClient, opts: InitOptions): Promise<InitResult>;
3425
3562
 
3426
3563
  interface Transcribe2Options {
3427
- /** Local media to extract the WAV from (source or vertical master). */
3428
- media: string;
3429
3564
  stem: string;
3430
- language?: string;
3431
- numSpeakers?: number;
3432
3565
  pollIntervalMs?: number;
3433
3566
  verbose?: boolean;
3434
3567
  }
3435
3568
  interface Transcribe2Result {
3436
- runId: string;
3437
- wavPath: string;
3438
- durationS: number;
3569
+ /** null when the artifacts already existed server-side (pull only). */
3570
+ runId: string | null;
3439
3571
  pulled: FilesPullResult;
3440
3572
  }
3441
- /** The artifact set `transcribe` pulls after the run completes. */
3573
+ /** The artifact set `transcribe` pulls (probe.json rides along since v3 —
3574
+ * it feeds job.json duration_s after an ingest re-run). */
3442
3575
  declare function transcribeArtifactSet(stem: string): string[];
3443
- /** Extract mono 16k pcm_s16le WAV + enforce the A/V clock guard. Returns the
3444
- * WAV bytes and the decoded audio duration. */
3445
- declare function extractGuardedWav(media: string): Promise<{
3446
- bytes: Buffer;
3447
- durationS: number;
3448
- }>;
3449
3576
  declare function transcribeCloud(client: CloudClient, jobDir: string, opts: Transcribe2Options): Promise<Transcribe2Result>;
3450
3577
 
3451
- interface SilenceInterval {
3452
- start: number;
3453
- end: number;
3454
- }
3455
- interface DesilenceOptions {
3456
- /** Silence threshold in dB (ffmpeg silencedetect `noise`). Default -39. */
3457
- noiseDb: number;
3458
- /** Minimum silence length (s) to act on — also silencedetect `d`. Default 0.30. */
3459
- minSilence: number;
3460
- /** Total air (s) to leave where an internal silence is cut. Default 0.13. */
3461
- targetGap: number;
3462
- /** Air kept BEFORE speech resumes at a cut / leading edge. Default 0.05. */
3463
- leadKeep: number;
3464
- /** Air kept AFTER speech ends at a cut / trailing edge. Default 0.08. */
3465
- trailKeep: number;
3466
- /** Drop any resulting sub-range shorter than this (s). Default 0.10. */
3467
- minSegment: number;
3468
- }
3469
- declare const DEFAULT_DESILENCE: DesilenceOptions;
3470
- /** ffmpeg argv for an amplitude silence scan. No video, null muxer; the report
3471
- * lands on stderr. Pure (no execution). */
3472
- declare function silenceDetectArgs(source: string, noiseDb: number, minSilenceS: number): string[];
3473
- /** Parse `silence_start:` / `silence_end:` pairs out of ffmpeg stderr.
3474
- * A dangling silence_start (silence runs to EOF) is closed at `sourceDurationS`
3475
- * when provided (>0), otherwise dropped. */
3476
- declare function parseSilenceDetect(stderr: string, sourceDurationS?: number): SilenceInterval[];
3477
- /** Run silencedetect on a source and return the silence intervals. */
3478
- declare function detectSilences(source: string, noiseDb: number, minSilenceS: number, sourceDurationS: number): Promise<SilenceInterval[]>;
3479
-
3480
3578
  declare function timelineJsonPath2(jobDir: string): string;
3481
3579
  declare function planPath2(jobDir: string): string;
3482
3580
  declare function diagnosticsPath2(jobDir: string): string;
@@ -3494,8 +3592,6 @@ declare function validateLocal(doc: TimelineV2): {
3494
3592
  errors: Diagnostic[];
3495
3593
  warnings: Diagnostic[];
3496
3594
  };
3497
- /** Commodity local silence detection for every timeline source. */
3498
- declare function detectSilencesForDoc(jobDir: string, doc: TimelineV2): Promise<Record<string, SilenceInterval[]>>;
3499
3595
  /** Stat pass over asset refs so the server compile can emit asset-missing. */
3500
3596
  declare function statAssetsForDoc(jobDir: string, doc: TimelineV2): Record<string, boolean>;
3501
3597
  interface CompileRemoteResult {
@@ -3505,8 +3601,9 @@ interface CompileRemoteResult {
3505
3601
  diagnosticsPath: string;
3506
3602
  response: Record<string, unknown>;
3507
3603
  }
3508
- /** POST the raw timeline (+ local silences/asset stats) to the server compile
3509
- * and write plan/diagnostics/edl exactly as returned (verbatim JSON). */
3604
+ /** POST the raw timeline (+ local asset stats) to the server compile and
3605
+ * write plan/diagnostics/edl exactly as returned (verbatim JSON). The server
3606
+ * sources silences from the VFS — no silences_by_source from the client. */
3510
3607
  declare function compileRemote(client: CloudClient, jobDir: string, loaded: LoadedTimeline2): Promise<CompileRemoteResult>;
3511
3608
 
3512
3609
  interface Verify2Options {
@@ -3523,87 +3620,37 @@ interface Verify2Result {
3523
3620
  }
3524
3621
  declare function verifyCloud(client: CloudClient, jobDir: string, opts?: Verify2Options): Promise<Verify2Result>;
3525
3622
 
3526
- interface Compose2Options {
3527
- render?: boolean;
3528
- quality?: string;
3529
- fps?: number;
3530
- out?: string;
3531
- proxyCrf?: number;
3532
- verbose?: boolean;
3623
+ /** QA output dir: <job>/qa when a job dir is given, else ./qa in cwd. */
3624
+ declare function qaDir(jobDir?: string): string;
3625
+ declare function framesPngPath(dir: string, start: number, end: number, suffix?: string): string;
3626
+ declare function waveformPngPath(dir: string, start: number, end: number): string;
3627
+ declare function waveformWordsPath(dir: string, start: number, end: number): string;
3628
+ /** The slice of a plan segment the QA math needs. */
3629
+ interface QaPlanSegment {
3630
+ srcStart: number;
3631
+ srcEnd: number;
3632
+ outStart: number;
3633
+ outEnd: number;
3533
3634
  }
3534
- interface Compose2Result {
3535
- compositionDir: string;
3536
- entry: string;
3537
- counts: Record<string, unknown>;
3538
- media: Array<{
3539
- src: string;
3540
- role: string;
3541
- }>;
3542
- out?: string;
3543
- renderCmd: string[];
3544
- rendered: boolean;
3545
- renderExit?: number;
3546
- }
3547
- /** Build one media entry under <composition>/. Roles:
3548
- * - "video": compressed proxy of the local vertical master (vertical_src.mp4)
3549
- * - "audio": the continuous cut audio extracted from preview.mp4
3550
- * - anything else: a straight copy of the job-dir file named by `src`
3551
- * (stripping a leading "media/"). */
3552
- declare function buildMediaEntry(jobDir: string, compDir: string, entry: {
3553
- src: string;
3554
- role: string;
3555
- }, opts: {
3556
- proxyCrf: number;
3557
- }): Promise<string>;
3558
- declare function composeCloud(client: CloudClient, jobDir: string, opts?: Compose2Options): Promise<Compose2Result>;
3559
-
3560
- interface QaWindow {
3561
- video: string;
3635
+ /** Read the segments array out of <job>/resolved/plan.json. */
3636
+ declare function readPlanSegments(jobDir: string): QaPlanSegment[];
3637
+ /** A source-time QA window; `suffix` distinguishes multi-window requests
3638
+ * ("-a"/"-b"/… — empty for a single window). */
3639
+ interface QaSourceWindow {
3562
3640
  start: number;
3563
3641
  end: number;
3564
- output: string;
3565
- }
3566
- /** ffmpeg argv for a filmstrip: `frames` evenly spaced frames of the window,
3567
- * tiled `cols` per row, each frame scaled to `frameWidth`. Pure. */
3568
- declare function qaFramesArgs(win: QaWindow, opts?: {
3569
- frames?: number;
3570
- cols?: number;
3571
- frameWidth?: number;
3572
- }): string[];
3573
- /** ffmpeg argv for a waveform PNG of the window (showwavespic). Pure. */
3574
- declare function qaWaveformArgs(win: QaWindow, opts?: {
3575
- width?: number;
3576
- height?: number;
3577
- }): string[];
3578
- interface QaWord {
3579
- t: number;
3580
- end: number;
3581
- text: string;
3642
+ suffix: string;
3582
3643
  }
3583
- /** Words inside [start, end] from a pulled Scribe transcript JSON, as the
3584
- * waveform sidecar shape ({t, end, text}, window-absolute source seconds). */
3585
- declare function qaWordsForWindow(transcriptJson: string, start: number, end: number): QaWord[];
3586
- /** Locate a pulled transcript for the sidecar: transcripts/<stem>.json when a
3587
- * stem is known, else the lone transcripts/*.json. */
3588
- declare function findLocalTranscript(jobDir: string, stem?: string): string | null;
3589
- interface QaLocalResult {
3590
- png: string;
3591
- wordsPath?: string;
3592
- words?: number;
3593
- }
3594
- declare function qaFramesLocal(jobDir: string, args: {
3595
- video: string;
3596
- start: number;
3597
- end: number;
3598
- frames?: number;
3599
- cols?: number;
3600
- }): Promise<QaLocalResult>;
3601
- declare function qaWaveformLocal(jobDir: string, args: {
3602
- video: string;
3603
- start: number;
3604
- end: number;
3605
- stem?: string;
3606
- }): Promise<QaLocalResult>;
3644
+ /** Source-time windows around join `i` (1-based: the boundary between plan
3645
+ * segments i and i+1): the last `spanS` seconds of segment i (tail, "-a")
3646
+ * and the first `spanS` seconds of segment i+1 (head, "-b"), each clamped
3647
+ * to its segment. */
3648
+ declare function joinSourceWindows(segments: QaPlanSegment[], joinIndex: number, spanS: number): QaSourceWindow[];
3649
+ /** Map an OUTPUT-time window onto source-time windows: intersect
3650
+ * [outStart, outEnd] with each segment's output range and shift into source
3651
+ * time (srcT = seg.srcStart + (outT - seg.outStart)). One window per
3652
+ * overlapped segment, suffixed -a/-b/… when the window crosses a join. */
3653
+ declare function outWindowToSourceWindows(segments: QaPlanSegment[], outStart: number, outEnd: number): QaSourceWindow[];
3607
3654
 
3608
3655
  declare function reviewDir2(jobDir: string): string;
3609
3656
  declare function roundJsonPath2(jobDir: string): string;
@@ -3707,4 +3754,4 @@ declare function loadPublicConfigEnv(env?: NodeJS.ProcessEnv): void;
3707
3754
  /** Write/update ONE managed key in the config file, preserving other lines. */
3708
3755
  declare function savePublicConfigKey(key: ManagedKey, value: string): string;
3709
3756
 
3710
- export { type Anchor, type AssetCreate, type AudioItem, CAPABILITIES, CAPTION_STYLE_DEFAULTS, type Capability, type CapabilityStatus, type CaptionOverride, type CaptionPreset, type CaptionStyle, type ChangeOutcome2, type ClientOptions, CloudClient, type CloudFlags, CloudHttpError, type CompileRemoteResult, type Compose2Options, type Compose2Result, type CutBoundary, type CutRange, DEFAULT_DESILENCE, DEFAULT_DOWNLOAD_TIMEOUT_MS, DEFAULT_TIMEOUT_MS, type DesilenceOptions, type Diagnostic, type Diagnostics, type Edl, type EdlRange, type FeatureKey, type FetchLike, type FilesPullResult, type GradeSetting, INLINE_MAX_BYTES, type InitOptions, type InitResult, type InstallResult, type JobFile, type LoadedTimeline2, MAX_POLL_MS, MAX_RUN_POLL_MS, type OutputAnchor, type OverlayFx, type OverlayItem, type ParseResult, type PhraseMatch, type PhraseSuggestion, type PollOptions, type Provenance, type PullReview2Result, type PulledFile, type Push2Failure, type PushComplete2Success, type PushTimeline2Success, type PushedFile, type QaLocalResult, type QaWord, REVIEW_STAGES2, type RenderCreate, type RenderMode, type RenderState, type RenderStatus, type ResolveOptions, type ResolveOutcome, type ResolvedConfig, type ReviewChange, type ReviewRound, type ReviewSession, type RunEvent, type RunPollOptions, type RunState, type RunStatus, type ScribeTranscript, type ScribeWord, type SilenceInterval, type SourceAnchor, type StreamWord, type TimelineSettings, type TimelineSource, type TimelineV2, type Transcribe2Options, type Transcribe2Result, type Verify2Options, type Verify2Result, type VerifyJoinFinding, type VerifyResult, type VfsFileContent, type VfsFileEntry, type VfsPresign, type WordsAnchor, type ZoomItem, assertRunCompleted, assetContentType2, assetsUrl, buildMediaEntry, bundledSkillDir, checkCapabilities, collectPlanAssetRefs2, compileRemote, compileUrl, composeCloud, composeUrl, defaultRenderOut, defaultSkillTarget, detectSilences, detectSilencesForDoc, diagnosticsPath2, downloadTo, emptyDiagnostics, extractGuardedWav, filesUrl, findLocalTranscript, findPhrase, formatRunEvent, fuzzySuggestions, initCloudJob, installSkill, instructionPath2, isTerminalRunStatus, isTerminalStatus, jobJsonPath, loadPublicConfigEnv, loadTimeline2, meUrl, normalizePhrase, normalizeToken, parseFileContent, parseFileList, parseFilePresign, parseRenderCreate, parseRenderState, parseRunState, parseSilenceDetect, parseTimeline, planPath2, pollRender, pollRun, projectVideosUrl, projectsUrl, publicConfigDir, publicConfigEnvPath, pullFiles, pullReview2, pushComplete2, pushFiles, pushStage2, pushTimeline2, qaFramesArgs, qaFramesLocal, qaWaveformArgs, qaWaveformLocal, qaWordsForWindow, readJobFile, readOutcomesFile2, renderUrl, rendersUrl, resolveApiBase, resolveApiKey, resolveConfig, resolvePhrase, resolveRunId2, resolveUrl, resolveVideoId, reviewDir2, reviewUrl, roundJsonPath2, runUrl, sameSha, savePublicConfigKey, sha256Hex, silenceDetectArgs, statAssetsForDoc, stripTrailingSlash, syncAssets2, timelineJsonPath2, timelineV2Schema, toVfsPath, transcribeArtifactSet, transcribeCloud, transcribeUrl, uploadVfsBytes, usesFromDoc, validateLocal, validateTimeline, verifyCloud, verifyUrl, vfsContentType, vfsLocalPath, videoIdFromJob, wordStream, writeJobFile };
3757
+ export { type Anchor, type AssetCreate, type AudioItem, CAPABILITIES, CAPTION_STYLE_DEFAULTS, type Capability, type CapabilityStatus, type CaptionOverride, type CaptionPreset, type CaptionStyle, type ChangeOutcome2, type ClientOptions, CloudClient, type CloudFlags, CloudHttpError, type CompileRemoteResult, type CutBoundary, type CutRange, DEFAULT_DOWNLOAD_TIMEOUT_MS, DEFAULT_TIMEOUT_MS, type Diagnostic, type Diagnostics, type Edl, type EdlRange, type FeatureKey, type FetchLike, type FileSource, type FilesPullResult, type GradeSetting, INLINE_MAX_BYTES, type InitOptions, type InitResult, type InstallResult, type JobFile, type LoadedTimeline2, MAX_POLL_MS, MAX_RUN_POLL_MS, MULTIPART_THRESHOLD_BYTES, type MultipartOptions, type MultipartSource, type OutputAnchor, type OverlayFx, type OverlayItem, type ParseResult, type PhraseMatch, type PhraseSuggestion, type PollOptions, type Provenance, type PullReview2Result, type PulledFile, type Push2Failure, type PushComplete2Success, type PushTimeline2Success, type PushedFile, type QaPlanSegment, type QaSourceWindow, RELAY_DIRECT_ATTEMPTS, RELAY_SUBCHUNK_BYTES, REVIEW_STAGES2, type RenderCreate, type RenderMode, type RenderState, type RenderStatus, type ResolveOptions, type ResolveOutcome, type ResolvedConfig, type ReviewChange, type ReviewRound, type ReviewSession, type RunEvent, type RunPollOptions, type RunState, type RunStatus, type ScribeTranscript, type ScribeWord, type SourceAnchor, type StreamWord, type TimelineSettings, type TimelineSource, type TimelineV2, type Transcribe2Options, type Transcribe2Result, type Verify2Options, type Verify2Result, type VerifyJoinFinding, type VerifyResult, type VfsFileContent, type VfsFileEntry, type VfsPresign, type WordsAnchor, type ZoomItem, assertRunCompleted, assetContentType2, assetsUrl, bundledSkillDir, bytesSource, checkCapabilities, collectPlanAssetRefs2, compileRemote, compileUrl, composeUrl, defaultRenderOut, defaultSkillTarget, diagnosticsPath2, downloadTo, emptyDiagnostics, filesUrl, findPhrase, formatRunEvent, framesPngPath, fuzzySuggestions, ingestArtifactSet, ingestUrl, initCloudJob, installSkill, instructionPath2, isTerminalRunStatus, isTerminalStatus, jobJsonPath, joinSourceWindows, loadPublicConfigEnv, loadTimeline2, meUrl, multipartRelayUrl, multipartUrl, normalizePhrase, normalizeToken, openFileSource, outWindowToSourceWindows, parseFileContent, parseFileList, parseFilePresign, parseRenderCreate, parseRenderState, parseRunState, parseTimeline, planPath2, pollRender, pollRun, projectVideosUrl, projectsUrl, publicConfigDir, publicConfigEnvPath, pullFiles, pullReview2, pushComplete2, pushFiles, pushStage2, pushTimeline2, qaDir, readJobFile, readOutcomesFile2, readPlanSegments, readProbeDuration, renderUrl, rendersUrl, resolveApiBase, resolveApiKey, resolveConfig, resolvePhrase, resolveRunId2, resolveUrl, resolveVideoId, reviewDir2, reviewUrl, roundJsonPath2, runUrl, sameSha, sanitizeStem, savePublicConfigKey, sha256Hex, shouldMultipart, statAssetsForDoc, stripTrailingSlash, syncAssets2, timelineJsonPath2, timelineV2Schema, toVfsPath, transcribeArtifactSet, transcribeCloud, transcribeUrl, uploadMultipart, uploadVfsBytes, uploadVfsPayload, usesFromDoc, validateLocal, validateTimeline, verifyCloud, verifyUrl, vfsContentType, vfsLocalPath, videoIdFromJob, waveformPngPath, waveformWordsPath, wordStream, writeJobFile };