recappi 0.1.60 → 0.1.61

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.js CHANGED
@@ -17868,12 +17868,19 @@ var recordingTranscribeDataSchema = external_exports.object({
17868
17868
  });
17869
17869
  var jobDataSchema = external_exports.object({
17870
17870
  jobId: external_exports.string(),
17871
+ origin: external_exports.string().optional(),
17871
17872
  recordingId: external_exports.string().optional(),
17872
17873
  transcriptId: external_exports.string().nullable().optional(),
17873
17874
  status: transcriptionJobStatusSchema,
17874
17875
  provider: external_exports.string().optional(),
17875
17876
  model: external_exports.string().optional(),
17876
- language: external_exports.string().nullable().optional()
17877
+ language: external_exports.string().nullable().optional(),
17878
+ progressPercent: external_exports.number().min(0).max(100).nullable().optional(),
17879
+ processedDurationMs: external_exports.number().int().nonnegative().nullable().optional(),
17880
+ recording: external_exports.object({
17881
+ title: external_exports.string().nullable().optional(),
17882
+ durationMs: external_exports.number().int().nonnegative().nullable().optional()
17883
+ }).optional()
17877
17884
  });
17878
17885
  var jobStatusFilterSchema = external_exports.enum([
17879
17886
  "active",
@@ -18033,6 +18040,7 @@ var operationEventTypeSchema = external_exports.enum(["started", "progress", "re
18033
18040
  var operationEventSchema = external_exports.object({
18034
18041
  type: operationEventTypeSchema,
18035
18042
  command: external_exports.string(),
18043
+ origin: external_exports.string().optional(),
18036
18044
  filePath: external_exports.string().optional(),
18037
18045
  recordingId: external_exports.string().optional(),
18038
18046
  jobId: external_exports.string().optional(),
@@ -19277,9 +19285,12 @@ var RecappiApiClient = class {
19277
19285
  opts.onEvent?.({
19278
19286
  type: "progress",
19279
19287
  command: "jobs wait",
19288
+ origin: this.auth.origin,
19280
19289
  jobId,
19290
+ ...job.recordingId ? { recordingId: job.recordingId } : {},
19281
19291
  status: job.status,
19282
- ...job.transcriptId ? { transcriptId: job.transcriptId } : {}
19292
+ ...job.transcriptId ? { transcriptId: job.transcriptId } : {},
19293
+ ...typeof job.progressPercent === "number" ? { percent: job.progressPercent } : {}
19283
19294
  });
19284
19295
  if (job.status === "succeeded") return job;
19285
19296
  if (job.status === "failed") {
@@ -19317,6 +19328,15 @@ var RecappiApiClient = class {
19317
19328
  message: "Finishing upload"
19318
19329
  });
19319
19330
  await this.postJson(`/api/recordings/${init.id}/complete`, { parts });
19331
+ opts.onEvent?.({
19332
+ type: "progress",
19333
+ command: "upload",
19334
+ origin: this.auth.origin,
19335
+ filePath: relative,
19336
+ recordingId: init.id,
19337
+ status: "uploaded",
19338
+ message: `Uploaded \xB7 ${recordingCloudUrl(this.auth.origin, init.id)}`
19339
+ });
19320
19340
  let jobId;
19321
19341
  let transcriptId;
19322
19342
  let status = "ready";
@@ -19324,6 +19344,7 @@ var RecappiApiClient = class {
19324
19344
  opts.onEvent?.({
19325
19345
  type: "progress",
19326
19346
  command: "upload",
19347
+ origin: this.auth.origin,
19327
19348
  filePath: relative,
19328
19349
  recordingId: init.id,
19329
19350
  status: "starting_transcription",
@@ -19341,6 +19362,17 @@ var RecappiApiClient = class {
19341
19362
  jobId = transcribe.jobId;
19342
19363
  status = transcribe.status;
19343
19364
  if (transcribe.transcriptId) transcriptId = transcribe.transcriptId;
19365
+ opts.onEvent?.({
19366
+ type: "progress",
19367
+ command: "upload",
19368
+ origin: this.auth.origin,
19369
+ filePath: relative,
19370
+ recordingId: init.id,
19371
+ jobId,
19372
+ status,
19373
+ ...transcriptId ? { transcriptId } : {},
19374
+ message: status === "succeeded" ? "Transcription already ready" : "Transcription queued"
19375
+ });
19344
19376
  if (opts.wait) {
19345
19377
  const waited = await this.waitForJob(jobId, {
19346
19378
  onEvent: (event) => opts.onEvent?.({
@@ -19411,14 +19443,27 @@ var RecappiApiClient = class {
19411
19443
  if (typeof parsed.id !== "string" || typeof parsed.status !== "string") {
19412
19444
  throw cliError("cloud.invalid_response", "Job response was missing id or status.");
19413
19445
  }
19446
+ const recording = isRecord2(parsed.recording) ? parsed.recording : void 0;
19447
+ const processedDurationMs = typeof parsed.processedDurationMs === "number" || parsed.processedDurationMs === null ? parsed.processedDurationMs : void 0;
19448
+ const recordingDurationMs = recording && (typeof recording.durationMs === "number" || recording.durationMs === null) ? recording.durationMs : void 0;
19449
+ const progressPercent = jobProgressPercent(parsed, processedDurationMs, recordingDurationMs);
19414
19450
  return {
19415
19451
  jobId: parsed.id,
19452
+ origin: this.auth.origin,
19416
19453
  ...typeof parsed.recordingId === "string" ? { recordingId: parsed.recordingId } : {},
19417
19454
  status: parsed.status,
19418
19455
  ...typeof parsed.transcriptId === "string" || parsed.transcriptId === null ? { transcriptId: parsed.transcriptId } : {},
19419
19456
  ...typeof parsed.provider === "string" ? { provider: parsed.provider } : {},
19420
19457
  ...typeof parsed.model === "string" ? { model: parsed.model } : {},
19421
- ...typeof parsed.language === "string" || parsed.language === null ? { language: parsed.language } : {}
19458
+ ...typeof parsed.language === "string" || parsed.language === null ? { language: parsed.language } : {},
19459
+ ...progressPercent !== void 0 ? { progressPercent } : {},
19460
+ ...processedDurationMs !== void 0 ? { processedDurationMs } : {},
19461
+ ...recording ? {
19462
+ recording: {
19463
+ ...typeof recording.title === "string" || recording.title === null ? { title: recording.title } : {},
19464
+ ...recordingDurationMs !== void 0 ? { durationMs: recordingDurationMs } : {}
19465
+ }
19466
+ } : {}
19422
19467
  };
19423
19468
  }
19424
19469
  async getJson(path6) {
@@ -19737,6 +19782,21 @@ function stringValue2(value) {
19737
19782
  function numberValue2(value) {
19738
19783
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
19739
19784
  }
19785
+ function recordingCloudUrl(origin, recordingId) {
19786
+ return `${origin.replace(/\/+$/, "")}/recordings/${encodeURIComponent(recordingId)}`;
19787
+ }
19788
+ function jobProgressPercent(row, processedDurationMs, recordingDurationMs) {
19789
+ const chunkProgress = isRecord2(row.chunkProgress) ? row.chunkProgress : void 0;
19790
+ const chunkPercent = numberValue2(chunkProgress?.percent);
19791
+ if (chunkPercent !== void 0) return clampPercent(chunkPercent);
19792
+ if (typeof processedDurationMs === "number" && typeof recordingDurationMs === "number" && recordingDurationMs > 0) {
19793
+ return clampPercent(processedDurationMs / recordingDurationMs * 100);
19794
+ }
19795
+ return void 0;
19796
+ }
19797
+ function clampPercent(value) {
19798
+ return Math.max(0, Math.min(100, Math.round(value)));
19799
+ }
19740
19800
  function nullableCap(value) {
19741
19801
  if (value === null) return null;
19742
19802
  const number4 = numberValue2(value);
@@ -20191,7 +20251,10 @@ function renderEvent(event, opts) {
20191
20251
  }
20192
20252
  if ((event.type === "started" || event.type === "progress") && opts.mode === "human") {
20193
20253
  const line = formatHumanProgress(event, opts);
20194
- if (line) writeHumanProgress(line, opts);
20254
+ if (line) {
20255
+ if (isPersistentProgressEvent(event)) writePersistentHumanProgress(line, opts);
20256
+ else writeHumanProgress(line, opts);
20257
+ }
20195
20258
  }
20196
20259
  }
20197
20260
  function renderEnvelope(envelope, opts) {
@@ -20355,10 +20418,12 @@ Next:
20355
20418
  }
20356
20419
  if (command === "upload" && isUploadBatch(data)) {
20357
20420
  if (data.successes.length > 0) {
20358
- opts.stdout(data.successes.length === 1 ? "Upload complete\n" : "Uploads complete\n");
20421
+ opts.stdout(uploadSuccessHeading(data.successes));
20359
20422
  }
20360
20423
  for (const item of data.successes) {
20361
20424
  opts.stdout(` recordingId: ${item.recordingId}
20425
+ `);
20426
+ opts.stdout(` recordingUrl: ${uploadRecordingUrl(item)}
20362
20427
  `);
20363
20428
  if (item.jobId) opts.stdout(` jobId: ${item.jobId}
20364
20429
  `);
@@ -20450,7 +20515,11 @@ Next:
20450
20515
  }
20451
20516
  if ((command === "jobs wait" || command === "upload") && isRecord4(data)) {
20452
20517
  if (typeof data.transcriptId === "string") {
20453
- opts.stdout("Transcription ready\n");
20518
+ opts.stdout("Transcript ready\n");
20519
+ if (typeof data.recordingId === "string" && typeof data.origin === "string") {
20520
+ opts.stdout(` recordingUrl: ${jobRecordingUrl(data.origin, data.recordingId, data.jobId)}
20521
+ `);
20522
+ }
20454
20523
  opts.stdout(` transcriptId: ${data.transcriptId}
20455
20524
  `);
20456
20525
  opts.stdout(`
@@ -20529,17 +20598,20 @@ function formatUploadProgress(event, opts, scope) {
20529
20598
  return `Uploading${event.filePath ? ` ${humanFileLabel(event.filePath)}` : ""}: ${event.percent}%`;
20530
20599
  }
20531
20600
  if (event.status === "finishing_upload") return "Finalizing upload";
20601
+ if (event.status === "uploaded") {
20602
+ return event.message ?? uploadedLine(event.origin, event.recordingId);
20603
+ }
20532
20604
  if (event.status === "starting_transcription") return "Starting transcription";
20533
20605
  return formatJobProgress(event);
20534
20606
  }
20535
20607
  function formatJobProgress(event) {
20536
20608
  switch (event.status) {
20537
20609
  case "queued":
20538
- return "Waiting for transcription";
20610
+ return event.jobId ? `Waiting for transcription (job ${event.jobId})` : "Waiting for transcription";
20539
20611
  case "running":
20540
- return "Transcribing";
20612
+ return typeof event.percent === "number" ? `Transcribing: ${event.percent}%` : "Transcribing\u2026";
20541
20613
  case "succeeded":
20542
- return "Transcription ready";
20614
+ return "\u2713 Transcript ready";
20543
20615
  case "failed":
20544
20616
  return "Transcription failed";
20545
20617
  default:
@@ -20557,6 +20629,11 @@ function writeHumanProgress(line, opts) {
20557
20629
  opts.stderr(`\r${line}${padding}`);
20558
20630
  state.activeLineLength = line.length;
20559
20631
  }
20632
+ function writePersistentHumanProgress(line, opts) {
20633
+ finishHumanProgress(opts);
20634
+ opts.stderr(`${line}
20635
+ `);
20636
+ }
20560
20637
  function finishHumanProgress(opts) {
20561
20638
  const state = opts.progress;
20562
20639
  if (!state?.interactive || state.activeLineLength === 0) return;
@@ -20566,11 +20643,32 @@ function finishHumanProgress(opts) {
20566
20643
  function progressScope(event) {
20567
20644
  return [event.command, event.filePath, event.recordingId, event.jobId].filter(Boolean).join(":");
20568
20645
  }
20646
+ function isPersistentProgressEvent(event) {
20647
+ return event.command === "upload" && event.status === "uploaded";
20648
+ }
20569
20649
  function humanFileLabel(filePath) {
20570
20650
  if (!filePath) return void 0;
20571
20651
  const normalized = filePath.replaceAll("\\", "/");
20572
20652
  return normalized.split("/").filter(Boolean).at(-1) ?? filePath;
20573
20653
  }
20654
+ function uploadRecordingUrl(item) {
20655
+ return jobRecordingUrl(item.origin, item.recordingId, item.jobId);
20656
+ }
20657
+ function uploadSuccessHeading(successes) {
20658
+ const transcriptReady = successes.length > 0 && successes.every((item) => Boolean(item.transcriptId));
20659
+ if (transcriptReady) return successes.length === 1 ? "\u2713 Transcript ready\n" : "\u2713 Transcripts ready\n";
20660
+ return successes.length === 1 ? "Upload complete\n" : "Uploads complete\n";
20661
+ }
20662
+ function jobRecordingUrl(origin, recordingId, jobId) {
20663
+ const base = recordingCloudUrl2(origin, recordingId);
20664
+ return typeof jobId === "string" ? `${base}?job=${encodeURIComponent(jobId)}` : base;
20665
+ }
20666
+ function uploadedLine(origin, recordingId) {
20667
+ return origin && recordingId ? `Uploaded \xB7 ${recordingCloudUrl2(origin, recordingId)}` : "Uploaded";
20668
+ }
20669
+ function recordingCloudUrl2(origin, recordingId) {
20670
+ return `${origin.replace(/\/+$/, "")}/recordings/${encodeURIComponent(recordingId)}`;
20671
+ }
20574
20672
  function renderTranscriptHuman(data, opts) {
20575
20673
  const segments = Array.isArray(data.segments) ? data.segments : [];
20576
20674
  let printedBody = false;