@madewithremy/admin 0.1.40 → 0.1.41

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/prod.js CHANGED
@@ -9372,7 +9372,12 @@ function seqOf(key) {
9372
9372
  );
9373
9373
  return Number.isFinite(n) ? n : 0;
9374
9374
  }
9375
- var DEFAULT_EXPORT_TIMEOUT_MS = 66e4;
9375
+ var DEFAULT_EXPORT_TIMEOUT_MS = 33 * 6e4;
9376
+ var EXPORT_PHASE_LABEL = {
9377
+ loading: "Preparing the replay",
9378
+ rendering: "Rendering the replay",
9379
+ encoding: "Encoding the video"
9380
+ };
9376
9381
  async function exportVideo(_ctx, params) {
9377
9382
  const body = {
9378
9383
  recordingSessionId: params.sessionId,
@@ -9385,7 +9390,12 @@ async function exportVideo(_ctx, params) {
9385
9390
  try {
9386
9391
  res = await fetch(`${SIDECAR_URL}/export-recording`, {
9387
9392
  method: "POST",
9388
- headers: { "Content-Type": "application/json" },
9393
+ // A line per progress event, then the answer (the sidecar's
9394
+ // streamRecordingExport).
9395
+ headers: {
9396
+ "Content-Type": "application/json",
9397
+ Accept: "application/x-ndjson"
9398
+ },
9389
9399
  body: JSON.stringify(body),
9390
9400
  signal: AbortSignal.timeout(
9391
9401
  params.timeoutMs ?? DEFAULT_EXPORT_TIMEOUT_MS
@@ -9396,12 +9406,53 @@ async function exportVideo(_ctx, params) {
9396
9406
  `Could not reach the sandbox at ${SIDECAR_URL} (${err instanceof Error ? err.message : String(err)}). Rendering a replay needs the dev box that recorded it \u2014 this command only works inside a Remy sandbox.`
9397
9407
  );
9398
9408
  }
9399
- const payload = await res.json().catch(() => ({}));
9400
- if (!res.ok) {
9409
+ if (!res.ok || !res.body) {
9410
+ const refused = await res.json().catch(() => ({}));
9401
9411
  throw new Error(
9402
- typeof payload.error === "string" ? payload.error : `The sandbox refused the export (HTTP ${res.status}).`
9412
+ typeof refused.error === "string" ? refused.error : `The sandbox refused the export (HTTP ${res.status}).`
9403
9413
  );
9404
9414
  }
9415
+ let payload = {};
9416
+ let shown = null;
9417
+ const decoder = new TextDecoder();
9418
+ let buffer = "";
9419
+ const read = (text) => {
9420
+ if (!text.trim()) {
9421
+ return;
9422
+ }
9423
+ let value;
9424
+ try {
9425
+ value = JSON.parse(text);
9426
+ } catch {
9427
+ return;
9428
+ }
9429
+ const progress2 = value.progress;
9430
+ if (!progress2) {
9431
+ payload = value;
9432
+ return;
9433
+ }
9434
+ const phase = progress2.phase ?? "rendering";
9435
+ const percent = Math.round(progress2.percent ?? 0);
9436
+ const step = Math.floor(percent / 10);
9437
+ if (shown?.phase !== phase || step > shown.step) {
9438
+ shown = { phase, step };
9439
+ params.onProgress?.(
9440
+ `${EXPORT_PHASE_LABEL[phase] ?? EXPORT_PHASE_LABEL.rendering}\u2026 ${percent}%`
9441
+ );
9442
+ }
9443
+ };
9444
+ for await (const chunk of res.body) {
9445
+ buffer += decoder.decode(chunk, { stream: true });
9446
+ let end;
9447
+ while ((end = buffer.indexOf("\n")) !== -1) {
9448
+ read(buffer.slice(0, end));
9449
+ buffer = buffer.slice(end + 1);
9450
+ }
9451
+ }
9452
+ read(buffer);
9453
+ if (typeof payload.error === "string") {
9454
+ throw new Error(payload.error);
9455
+ }
9405
9456
  const status2 = payload.export;
9406
9457
  if (!status2) {
9407
9458
  throw new Error(
@@ -9458,12 +9509,11 @@ async function qaRecordingsExport(ctx, a) {
9458
9509
  from,
9459
9510
  to,
9460
9511
  store: a.str("store"),
9461
- access: a.bool("private") ? "private" : void 0
9512
+ access: a.bool("private") ? "private" : void 0,
9513
+ onProgress: progress
9462
9514
  });
9463
9515
  if (result.status !== "completed") {
9464
- fatal(
9465
- result.errorCode === "FFMPEG_UNAVAILABLE" ? "This sandbox has no ffmpeg \u2014 video export needs a box on the current devbox image." : result.error ?? `Export ${result.status}.`
9466
- );
9516
+ fatal(result.error ?? `Export ${result.status}.`);
9467
9517
  }
9468
9518
  out(result);
9469
9519
  }
@@ -9479,10 +9529,12 @@ recording, not video). The chunks are ordinary private files in the
9479
9529
  for a link, download one, or copy one into a public store to embed it.
9480
9530
 
9481
9531
  'export' turns a replay into an mp4 \u2014 the shareable artifact, for a changelog
9482
- entry, a release note or a bug report. It renders on the dev box (real browser,
9483
- real ffmpeg, no AI-generated frames), so it only works inside a sandbox, it
9484
- blocks for the length of the clip, and it won't start while a video export is
9485
- already running.
9532
+ entry, a release note or a bug report. The dev box that recorded it packages
9533
+ the replay, and the platform renders it in a real browser, frame by frame (no
9534
+ AI-generated frames). So it only works inside a sandbox, and it won't start
9535
+ while a video export is already running. It blocks until the video is written,
9536
+ which takes minutes for a long clip (up to about 30), printing its progress to
9537
+ stderr as it goes; run it with a timeout to match.
9486
9538
 
9487
9539
  Subcommands:
9488
9540
  ls Recording sessions in this app, grouped into runs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madewithremy/admin",
3
- "version": "0.1.40",
3
+ "version": "0.1.41",
4
4
  "description": "Admin SDK + CLI for managing production Remy apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",