@vosjs/cli 0.35.0 → 0.36.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/{chunk-VQXOM2NU.js → chunk-MIZWK5AN.js} +181 -52
- package/dist/chunk-MIZWK5AN.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{run-4DNLUCJH.js → run-LHMYTKV7.js} +2 -2
- package/package.json +5 -5
- package/dist/chunk-VQXOM2NU.js.map +0 -1
- /package/dist/{run-4DNLUCJH.js.map → run-LHMYTKV7.js.map} +0 -0
|
@@ -3876,9 +3876,9 @@ function proposeTransitions(input, kind) {
|
|
|
3876
3876
|
for (const step of steps) {
|
|
3877
3877
|
if (!step.navigated || step.skipped) continue;
|
|
3878
3878
|
const name = step.id ?? String(step.step);
|
|
3879
|
-
const
|
|
3880
|
-
const outEnd = round3(
|
|
3881
|
-
const inStart = round3(
|
|
3879
|
+
const wait2 = step.do === "wait";
|
|
3880
|
+
const outEnd = round3(wait2 ? step.tStart : step.tEnd);
|
|
3881
|
+
const inStart = round3(wait2 ? step.tEnd : step.tEnd + STEP_SETTLE_SECONDS);
|
|
3882
3882
|
const segs = doc.segments;
|
|
3883
3883
|
if (segs.some(
|
|
3884
3884
|
(s) => !s.media && Math.abs(s.out - outEnd) < 0.05 && s !== segs.at(-1)
|
|
@@ -6165,8 +6165,8 @@ async function clockMotion(dur, at2, clock) {
|
|
|
6165
6165
|
await at2(easeInOutCubic(Math.min(1, elapsed / dur)));
|
|
6166
6166
|
samples++;
|
|
6167
6167
|
const next = start + Math.ceil((clock.now() - start) / MOTION_TICK_MS) * MOTION_TICK_MS;
|
|
6168
|
-
const
|
|
6169
|
-
if (
|
|
6168
|
+
const wait2 = Math.min(next, start + dur) - clock.now();
|
|
6169
|
+
if (wait2 > 0) await clock.sleep(wait2);
|
|
6170
6170
|
}
|
|
6171
6171
|
await at2(1);
|
|
6172
6172
|
return samples + 1;
|
|
@@ -6176,8 +6176,8 @@ async function clockTyping(chars, delay, type, clock) {
|
|
|
6176
6176
|
for (let i = 0; i < chars.length; i++) {
|
|
6177
6177
|
await type(chars[i], i);
|
|
6178
6178
|
const due = start + (i + 1) * delay;
|
|
6179
|
-
const
|
|
6180
|
-
if (
|
|
6179
|
+
const wait2 = due - clock.now();
|
|
6180
|
+
if (wait2 > 0 && i < chars.length - 1) await clock.sleep(wait2);
|
|
6181
6181
|
}
|
|
6182
6182
|
}
|
|
6183
6183
|
function askedMs(step) {
|
|
@@ -7385,7 +7385,7 @@ async function cmdMove(argv) {
|
|
|
7385
7385
|
});
|
|
7386
7386
|
const key = requireCredential(strFlag(flags, "key"));
|
|
7387
7387
|
const folderId = toRef === "none" ? null : resolveFolder(await listFolders(origin, key), toRef).id;
|
|
7388
|
-
let
|
|
7388
|
+
let failed2 = 0;
|
|
7389
7389
|
const moved = [];
|
|
7390
7390
|
for (const raw of positionals) {
|
|
7391
7391
|
const id = parseVosId(raw);
|
|
@@ -7400,28 +7400,28 @@ async function cmdMove(argv) {
|
|
|
7400
7400
|
continue;
|
|
7401
7401
|
}
|
|
7402
7402
|
if (asVos.status === 404) {
|
|
7403
|
-
const
|
|
7403
|
+
const asAsset2 = await apiJson(origin, `/api/assets/${id}`, {
|
|
7404
7404
|
method: "PATCH",
|
|
7405
7405
|
key,
|
|
7406
7406
|
body: { folderId }
|
|
7407
7407
|
});
|
|
7408
|
-
if (
|
|
7408
|
+
if (asAsset2.status === 200) {
|
|
7409
7409
|
moved.push({ id, kind: "asset" });
|
|
7410
7410
|
r.log(`moved asset ${id}`);
|
|
7411
7411
|
continue;
|
|
7412
7412
|
}
|
|
7413
|
-
|
|
7414
|
-
r.log(apiError(`move ${id}`,
|
|
7413
|
+
failed2++;
|
|
7414
|
+
r.log(apiError(`move ${id}`, asAsset2));
|
|
7415
7415
|
continue;
|
|
7416
7416
|
}
|
|
7417
|
-
|
|
7417
|
+
failed2++;
|
|
7418
7418
|
r.log(apiError(`move ${id}`, asVos));
|
|
7419
7419
|
}
|
|
7420
7420
|
r.done(
|
|
7421
|
-
{ moved, failed, folderId },
|
|
7422
|
-
`moved ${moved.length}/${positionals.length} into ${toRef === "none" ? "the top level" : toRef}${
|
|
7421
|
+
{ moved, failed: failed2, folderId },
|
|
7422
|
+
`moved ${moved.length}/${positionals.length} into ${toRef === "none" ? "the top level" : toRef}${failed2 ? ` \u2014 ${failed2} failed` : ""}`
|
|
7423
7423
|
);
|
|
7424
|
-
return
|
|
7424
|
+
return failed2 ? EXIT_ERROR : EXIT_OK;
|
|
7425
7425
|
}
|
|
7426
7426
|
function recipeLine(filename, body) {
|
|
7427
7427
|
const h = recipeHints(body);
|
|
@@ -7567,6 +7567,144 @@ async function cmdFolder(argv) {
|
|
|
7567
7567
|
}
|
|
7568
7568
|
}
|
|
7569
7569
|
|
|
7570
|
+
// src/plugin/uploadAsset.ts
|
|
7571
|
+
var SINGLE_SHOT_MAX_BYTES = 32 * 1024 * 1024;
|
|
7572
|
+
var PART_ATTEMPTS = 3;
|
|
7573
|
+
function planParts(totalBytes, partBytes) {
|
|
7574
|
+
if (totalBytes <= 0 || partBytes <= 0) return [];
|
|
7575
|
+
const parts = [];
|
|
7576
|
+
for (let start = 0; start < totalBytes; start += partBytes) {
|
|
7577
|
+
parts.push({
|
|
7578
|
+
partNumber: parts.length + 1,
|
|
7579
|
+
start,
|
|
7580
|
+
end: Math.min(start + partBytes, totalBytes)
|
|
7581
|
+
});
|
|
7582
|
+
}
|
|
7583
|
+
return parts;
|
|
7584
|
+
}
|
|
7585
|
+
function failed(what, r) {
|
|
7586
|
+
const detail = typeof r.body.error === "string" ? r.body.error : "";
|
|
7587
|
+
return new Error(`${what} (${r.status})${detail ? `: ${detail}` : ""}`);
|
|
7588
|
+
}
|
|
7589
|
+
function asAsset(body) {
|
|
7590
|
+
return {
|
|
7591
|
+
id: String(body.id),
|
|
7592
|
+
url: String(body.url),
|
|
7593
|
+
size: typeof body.size === "number" ? body.size : 0,
|
|
7594
|
+
reused: body.reused === true
|
|
7595
|
+
};
|
|
7596
|
+
}
|
|
7597
|
+
function transient(status) {
|
|
7598
|
+
return status >= 500 || status === 429;
|
|
7599
|
+
}
|
|
7600
|
+
var wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
7601
|
+
async function uploadAsset(target, bytes, opts) {
|
|
7602
|
+
return bytes.length > SINGLE_SHOT_MAX_BYTES ? uploadInParts(target, bytes, opts) : uploadWhole(target, bytes, opts);
|
|
7603
|
+
}
|
|
7604
|
+
async function uploadWhole(target, bytes, opts) {
|
|
7605
|
+
const res = await apiJson(target.origin, "/api/assets/recording", {
|
|
7606
|
+
method: "POST",
|
|
7607
|
+
key: target.key,
|
|
7608
|
+
headers: {
|
|
7609
|
+
"Content-Type": opts.contentType,
|
|
7610
|
+
"Content-Length": String(bytes.length),
|
|
7611
|
+
"X-Filename": opts.filename,
|
|
7612
|
+
"X-Content-Hash": opts.contentHash,
|
|
7613
|
+
...opts.durationSeconds && opts.durationSeconds > 0 ? { "X-Content-Duration": opts.durationSeconds.toFixed(3) } : {}
|
|
7614
|
+
},
|
|
7615
|
+
raw: bytes
|
|
7616
|
+
});
|
|
7617
|
+
if (res.status !== 201 && res.status !== 200)
|
|
7618
|
+
throw failed("upload failed", res);
|
|
7619
|
+
return asAsset(res.body);
|
|
7620
|
+
}
|
|
7621
|
+
async function uploadInParts(target, bytes, opts) {
|
|
7622
|
+
const begun = await apiJson(
|
|
7623
|
+
target.origin,
|
|
7624
|
+
"/api/assets/recording/multipart",
|
|
7625
|
+
{
|
|
7626
|
+
method: "POST",
|
|
7627
|
+
key: target.key,
|
|
7628
|
+
body: {
|
|
7629
|
+
filename: opts.filename,
|
|
7630
|
+
contentType: opts.contentType,
|
|
7631
|
+
size: bytes.length,
|
|
7632
|
+
contentHash: opts.contentHash,
|
|
7633
|
+
...opts.durationSeconds && opts.durationSeconds > 0 ? { durationSeconds: opts.durationSeconds } : {}
|
|
7634
|
+
}
|
|
7635
|
+
}
|
|
7636
|
+
);
|
|
7637
|
+
if (begun.status !== 201 && begun.status !== 200) {
|
|
7638
|
+
throw failed("upload failed", begun);
|
|
7639
|
+
}
|
|
7640
|
+
if (begun.body.reused === true || typeof begun.body.url === "string") {
|
|
7641
|
+
return asAsset(begun.body);
|
|
7642
|
+
}
|
|
7643
|
+
const uploadId = String(begun.body.id);
|
|
7644
|
+
const partBytes = Number(begun.body.partBytes);
|
|
7645
|
+
if (!Number.isFinite(partBytes) || partBytes <= 0) {
|
|
7646
|
+
throw new Error("upload failed: the platform returned no part size");
|
|
7647
|
+
}
|
|
7648
|
+
const parts = planParts(bytes.length, partBytes);
|
|
7649
|
+
const etags = [];
|
|
7650
|
+
try {
|
|
7651
|
+
for (const part of parts) {
|
|
7652
|
+
const chunk2 = bytes.subarray(part.start, part.end);
|
|
7653
|
+
let sent = null;
|
|
7654
|
+
for (let attempt = 1; attempt <= PART_ATTEMPTS; attempt++) {
|
|
7655
|
+
try {
|
|
7656
|
+
sent = await apiJson(
|
|
7657
|
+
target.origin,
|
|
7658
|
+
`/api/assets/recording/multipart/${uploadId}/parts/${part.partNumber}`,
|
|
7659
|
+
{
|
|
7660
|
+
method: "PUT",
|
|
7661
|
+
key: target.key,
|
|
7662
|
+
headers: {
|
|
7663
|
+
"Content-Type": "application/octet-stream",
|
|
7664
|
+
"Content-Length": String(chunk2.length)
|
|
7665
|
+
},
|
|
7666
|
+
raw: chunk2
|
|
7667
|
+
}
|
|
7668
|
+
);
|
|
7669
|
+
} catch (networkError) {
|
|
7670
|
+
if (attempt === PART_ATTEMPTS) throw networkError;
|
|
7671
|
+
await wait(500 * 2 ** (attempt - 1));
|
|
7672
|
+
continue;
|
|
7673
|
+
}
|
|
7674
|
+
if (sent.status === 200) break;
|
|
7675
|
+
if (!transient(sent.status) || attempt === PART_ATTEMPTS) {
|
|
7676
|
+
throw failed(`part ${part.partNumber} failed`, sent);
|
|
7677
|
+
}
|
|
7678
|
+
await wait(500 * 2 ** (attempt - 1));
|
|
7679
|
+
}
|
|
7680
|
+
if (!sent || sent.status !== 200) {
|
|
7681
|
+
throw new Error(`part ${part.partNumber} failed`);
|
|
7682
|
+
}
|
|
7683
|
+
etags.push({
|
|
7684
|
+
partNumber: Number(sent.body.partNumber),
|
|
7685
|
+
etag: String(sent.body.etag)
|
|
7686
|
+
});
|
|
7687
|
+
opts.onPart?.(etags.length, parts.length);
|
|
7688
|
+
}
|
|
7689
|
+
const sealed = await apiJson(
|
|
7690
|
+
target.origin,
|
|
7691
|
+
`/api/assets/recording/multipart/${uploadId}/complete`,
|
|
7692
|
+
{ method: "POST", key: target.key, body: { parts: etags } }
|
|
7693
|
+
);
|
|
7694
|
+
if (sealed.status !== 201 && sealed.status !== 200) {
|
|
7695
|
+
throw failed("upload failed", sealed);
|
|
7696
|
+
}
|
|
7697
|
+
return asAsset(sealed.body);
|
|
7698
|
+
} catch (err) {
|
|
7699
|
+
await apiJson(
|
|
7700
|
+
target.origin,
|
|
7701
|
+
`/api/assets/recording/multipart/${uploadId}`,
|
|
7702
|
+
{ method: "DELETE", key: target.key }
|
|
7703
|
+
).catch(() => void 0);
|
|
7704
|
+
throw err;
|
|
7705
|
+
}
|
|
7706
|
+
}
|
|
7707
|
+
|
|
7570
7708
|
// src/plugin/sync.ts
|
|
7571
7709
|
function apiContext(flags) {
|
|
7572
7710
|
return {
|
|
@@ -7649,31 +7787,25 @@ async function pushTake(dir, flags, r) {
|
|
|
7649
7787
|
const bytes = await readFile13(take.paths.recording);
|
|
7650
7788
|
const hash = createHash("sha256").update(bytes).digest("hex");
|
|
7651
7789
|
r.log(`uploading recording (${Math.round(bytes.length / 1024)} kB)\u2026`);
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
"
|
|
7657
|
-
|
|
7658
|
-
"X-Content-Hash": hash,
|
|
7790
|
+
let upload;
|
|
7791
|
+
try {
|
|
7792
|
+
upload = await uploadAsset(ctx, new Uint8Array(bytes), {
|
|
7793
|
+
filename: RECORDING_NAME,
|
|
7794
|
+
contentType: "video/webm",
|
|
7795
|
+
contentHash: hash,
|
|
7659
7796
|
// The take's length so the server holds it to the plan's cap.
|
|
7660
|
-
...take.meta.durationMs > 0 ? {
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
})
|
|
7664
|
-
if (upload.status !== 201 && upload.status !== 200) {
|
|
7797
|
+
...take.meta.durationMs > 0 ? { durationSeconds: take.meta.durationMs / 1e3 } : {},
|
|
7798
|
+
onPart: (done, total) => r.log(` part ${done}/${total}`)
|
|
7799
|
+
});
|
|
7800
|
+
} catch (e) {
|
|
7665
7801
|
throw new Error(
|
|
7666
|
-
`recording upload failed
|
|
7802
|
+
`recording upload failed: ${e instanceof Error ? e.message : String(e)}`
|
|
7667
7803
|
);
|
|
7668
7804
|
}
|
|
7669
|
-
const assetId =
|
|
7670
|
-
const assetUrl =
|
|
7671
|
-
r.event({
|
|
7672
|
-
|
|
7673
|
-
assetId,
|
|
7674
|
-
reused: upload.json.reused === true
|
|
7675
|
-
});
|
|
7676
|
-
if (upload.json.reused === true) r.log(" recording already hosted \u2014 reused");
|
|
7805
|
+
const assetId = upload.id;
|
|
7806
|
+
const assetUrl = upload.url;
|
|
7807
|
+
r.event({ event: "recording", assetId, reused: upload.reused });
|
|
7808
|
+
if (upload.reused) r.log(" recording already hosted \u2014 reused");
|
|
7677
7809
|
const docForPush = structuredClone(take.doc);
|
|
7678
7810
|
docForPush.source.videoKey = assetUrl;
|
|
7679
7811
|
if (docForPush.source.camKey && !/^(https?:)?\//.test(docForPush.source.camKey)) {
|
|
@@ -7693,24 +7825,21 @@ async function pushTake(dir, flags, r) {
|
|
|
7693
7825
|
const media = await readFile13(file);
|
|
7694
7826
|
const mediaHash = createHash("sha256").update(media).digest("hex");
|
|
7695
7827
|
const type = mediaContentType(file);
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
raw: new Uint8Array(media)
|
|
7705
|
-
});
|
|
7706
|
-
if (put.status !== 201 && put.status !== 200) {
|
|
7828
|
+
let put;
|
|
7829
|
+
try {
|
|
7830
|
+
put = await uploadAsset(ctx, new Uint8Array(media), {
|
|
7831
|
+
filename: basename(file),
|
|
7832
|
+
contentType: type,
|
|
7833
|
+
contentHash: mediaHash
|
|
7834
|
+
});
|
|
7835
|
+
} catch (e) {
|
|
7707
7836
|
throw new Error(
|
|
7708
|
-
`${ref.where} upload failed
|
|
7837
|
+
`${ref.where} upload failed: ${e instanceof Error ? e.message : String(e)}`
|
|
7709
7838
|
);
|
|
7710
7839
|
}
|
|
7711
|
-
ref.set(
|
|
7840
|
+
ref.set(put.url);
|
|
7712
7841
|
r.log(
|
|
7713
|
-
` ${ref.where}: ${ref.key} \u2192 asset ${
|
|
7842
|
+
` ${ref.where}: ${ref.key} \u2192 asset ${put.id}${put.reused ? " (reused)" : ""}`
|
|
7714
7843
|
);
|
|
7715
7844
|
}
|
|
7716
7845
|
const lowered = lowerToComposition3(docForPush);
|
|
@@ -11246,4 +11375,4 @@ export {
|
|
|
11246
11375
|
convertAgentBrowser,
|
|
11247
11376
|
run
|
|
11248
11377
|
};
|
|
11249
|
-
//# sourceMappingURL=chunk-
|
|
11378
|
+
//# sourceMappingURL=chunk-MIZWK5AN.js.map
|