@madewithremy/admin 0.1.39 → 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
@@ -1913,7 +1913,8 @@ Notes:
1913
1913
  returns both. 'remove' on an apex also removes its paired www.
1914
1914
  - 'list'/'records'/'status' read a CF-synced cache that can be up to ~5
1915
1915
  minutes stale. After the customer adds DNS, use 'retry' to force a
1916
- synchronous re-check.
1916
+ synchronous re-check. On a domain bought through Remy there are no records
1917
+ to add, so there's nothing to retry while it waits on the registry.
1917
1918
  - 'uiStatus' values: waiting_for_dns | issuing_ssl | live | action_needed | reconnecting.
1918
1919
  - 'buy' charges the workspace the price at once, and it isn't refundable; the
1919
1920
  domain renews yearly at its renewal price while auto-renew is on (the owner
@@ -9371,7 +9372,12 @@ function seqOf(key) {
9371
9372
  );
9372
9373
  return Number.isFinite(n) ? n : 0;
9373
9374
  }
9374
- 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
+ };
9375
9381
  async function exportVideo(_ctx, params) {
9376
9382
  const body = {
9377
9383
  recordingSessionId: params.sessionId,
@@ -9384,7 +9390,12 @@ async function exportVideo(_ctx, params) {
9384
9390
  try {
9385
9391
  res = await fetch(`${SIDECAR_URL}/export-recording`, {
9386
9392
  method: "POST",
9387
- 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
+ },
9388
9399
  body: JSON.stringify(body),
9389
9400
  signal: AbortSignal.timeout(
9390
9401
  params.timeoutMs ?? DEFAULT_EXPORT_TIMEOUT_MS
@@ -9395,12 +9406,53 @@ async function exportVideo(_ctx, params) {
9395
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.`
9396
9407
  );
9397
9408
  }
9398
- const payload = await res.json().catch(() => ({}));
9399
- if (!res.ok) {
9409
+ if (!res.ok || !res.body) {
9410
+ const refused = await res.json().catch(() => ({}));
9400
9411
  throw new Error(
9401
- 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}).`
9402
9413
  );
9403
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
+ }
9404
9456
  const status2 = payload.export;
9405
9457
  if (!status2) {
9406
9458
  throw new Error(
@@ -9457,12 +9509,11 @@ async function qaRecordingsExport(ctx, a) {
9457
9509
  from,
9458
9510
  to,
9459
9511
  store: a.str("store"),
9460
- access: a.bool("private") ? "private" : void 0
9512
+ access: a.bool("private") ? "private" : void 0,
9513
+ onProgress: progress
9461
9514
  });
9462
9515
  if (result.status !== "completed") {
9463
- fatal(
9464
- 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}.`
9465
- );
9516
+ fatal(result.error ?? `Export ${result.status}.`);
9466
9517
  }
9467
9518
  out(result);
9468
9519
  }
@@ -9478,10 +9529,12 @@ recording, not video). The chunks are ordinary private files in the
9478
9529
  for a link, download one, or copy one into a public store to embed it.
9479
9530
 
9480
9531
  'export' turns a replay into an mp4 \u2014 the shareable artifact, for a changelog
9481
- entry, a release note or a bug report. It renders on the dev box (real browser,
9482
- real ffmpeg, no AI-generated frames), so it only works inside a sandbox, it
9483
- blocks for the length of the clip, and it won't start while a video export is
9484
- 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.
9485
9538
 
9486
9539
  Subcommands:
9487
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.39",
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",