@vosjs/cli 0.76.0 → 0.77.1

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.
@@ -9,7 +9,7 @@ import {
9
9
  reencodeStill,
10
10
  renderStill,
11
11
  videoFormat
12
- } from "./chunk-YZAM4W7B.js";
12
+ } from "./chunk-KDIRW72G.js";
13
13
  import {
14
14
  PREV_DOC_NAME,
15
15
  RECORDING_NAME,
@@ -28,6 +28,7 @@ import {
28
28
  readJson,
29
29
  readMediaHead,
30
30
  recordHostedMedia,
31
+ safePathName,
31
32
  sourceSidecarRefs,
32
33
  takeMediaFile,
33
34
  takePaths,
@@ -36,7 +37,7 @@ import {
36
37
  uploadDocRefs,
37
38
  uploadManifest,
38
39
  writeJson
39
- } from "./chunk-M3QIN457.js";
40
+ } from "./chunk-UY2N42P2.js";
40
41
  import {
41
42
  CREDENTIALS_PATH,
42
43
  MEDIA_HEAD_BYTES,
@@ -68,8 +69,9 @@ import {
68
69
  sniffMediaType,
69
70
  strFlag,
70
71
  writeCredential,
72
+ writeFileSafe,
71
73
  writeSyncState
72
- } from "./chunk-FL3E27WE.js";
74
+ } from "./chunk-B4U4URE3.js";
73
75
  import {
74
76
  deadLine,
75
77
  deadWarns
@@ -366,10 +368,13 @@ var EPS = 1e-3;
366
368
  var isNum = (v) => typeof v === "number" && Number.isFinite(v);
367
369
  var isObj = (v) => typeof v === "object" && v !== null;
368
370
  function htmlFontUrlProblem(url) {
369
- if (/^https?:\/\//.test(url)) return null;
371
+ if (/^https:\/\/assets\.vos\.so\//.test(url)) return null;
370
372
  if (/^\/api\/assets\/[^/]+\/file$/.test(url)) return null;
373
+ if (/^https?:\/\//i.test(url)) {
374
+ return `names ${url}: a face is fetched from https://assets.vos.so (the host a layer's images are held to), a hosted file (/api/assets/<id>/file) or a .woff2 beside the document, never another host`;
375
+ }
371
376
  if (/^(data:|blob:)/.test(url) || url.startsWith("/")) {
372
- return `must be an https URL, a hosted file (/api/assets/<id>/file) or a .woff2 beside the document (got ${url})`;
377
+ return `must be an https://assets.vos.so URL, a hosted file (/api/assets/<id>/file) or a .woff2 beside the document (got ${url})`;
373
378
  }
374
379
  if (url.split(/[\\/]/).includes("..")) {
375
380
  return `names ${url}, outside the document's directory: copy the font beside doc.json`;
@@ -2199,9 +2204,11 @@ import { readFile, rm } from "fs/promises";
2199
2204
  import { tweenRuntimeCode } from "@vosjs/tween/bundle";
2200
2205
  import { elementsBundleCode } from "@vosjs/elements/bundle";
2201
2206
  import { concatEncodedVideo, planChunks } from "@vosjs/render-core";
2202
- var MEDIABUNNY_URL = "https://esm.sh/mediabunny@1.55.7?target=es2022";
2203
- var THREE_URL = "https://esm.sh/three@0.183.0?target=es2022";
2204
- var THREE_ADDONS = "https://esm.sh/three@0.183.0&target=es2022/examples/jsm/";
2207
+ import { esmShModules } from "@vosjs/core/addons";
2208
+ var MODULES = esmShModules();
2209
+ var MEDIABUNNY_URL = MODULES.mediabunny;
2210
+ var THREE_URL = MODULES.three;
2211
+ var THREE_ADDONS = MODULES.threeAddons;
2205
2212
  function renderPageHtml() {
2206
2213
  const importmap = JSON.stringify({
2207
2214
  imports: { three: THREE_URL, "three/addons/": THREE_ADDONS }
@@ -6205,7 +6212,7 @@ async function writeScriptBeside(dir, doc) {
6205
6212
  }
6206
6213
 
6207
6214
  // src/plugin/folder.ts
6208
- import { mkdir as mkdir5, writeFile as writeFile8 } from "fs/promises";
6215
+ import { mkdir as mkdir5 } from "fs/promises";
6209
6216
  import { join as join12 } from "path";
6210
6217
  import { recipeHints } from "@vosjs/shared/frontmatter";
6211
6218
  import { migrateHostedDoc } from "@vosjs/studio-core";
@@ -6394,7 +6401,6 @@ function recipeLine(filename, body) {
6394
6401
  ].filter(Boolean);
6395
6402
  return `${filename}${facts.length ? ` (${facts.join(" \xB7 ")})` : ""}`;
6396
6403
  }
6397
- var safeName = (v) => v.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "file";
6398
6404
  async function cmdPull(argv) {
6399
6405
  const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS);
6400
6406
  const ref = positionals[0];
@@ -6413,26 +6419,27 @@ async function cmdPull(argv) {
6413
6419
  if (res.status !== 200)
6414
6420
  throw new Error(apiError(`pull folder ${folder.slug}`, res));
6415
6421
  const payload = res.body;
6416
- const out = strFlag(flags, "out") ?? folder.slug;
6422
+ const safeName = (v, id) => safePathName((v ?? "").toLowerCase(), id);
6423
+ const out = strFlag(flags, "out") ?? safeName(folder.slug, folder.id);
6417
6424
  await mkdir5(join12(out, "recipes"), { recursive: true });
6418
6425
  const lines = [];
6419
6426
  const recipes = [];
6420
6427
  for (const rec of payload.recipes) {
6421
- const path = join12(out, "recipes", safeName(rec.filename));
6422
- await writeFile8(path, rec.body ?? "");
6428
+ const path = join12(out, "recipes", safeName(rec.filename, rec.id));
6429
+ await writeFileSafe(path, rec.body ?? "");
6423
6430
  recipes.push({ path, line: recipeLine(rec.filename, rec.body ?? "") });
6424
6431
  }
6425
6432
  for (const rec of payload.inheritedRecipes) {
6426
- const from = safeName(rec.folderSlug ?? "inherited");
6433
+ const from = safeName(rec.folderSlug ?? "inherited", "inherited");
6427
6434
  await mkdir5(join12(out, "recipes", "_inherited", from), { recursive: true });
6428
6435
  const path = join12(
6429
6436
  out,
6430
6437
  "recipes",
6431
6438
  "_inherited",
6432
6439
  from,
6433
- safeName(rec.filename)
6440
+ safeName(rec.filename, rec.id)
6434
6441
  );
6435
- await writeFile8(path, rec.body ?? "");
6442
+ await writeFileSafe(path, rec.body ?? "");
6436
6443
  recipes.push({
6437
6444
  path,
6438
6445
  line: `${recipeLine(rec.filename, rec.body ?? "")} [inherited from ${rec.folderName ?? from}]`
@@ -6440,14 +6447,14 @@ async function cmdPull(argv) {
6440
6447
  }
6441
6448
  const members = [];
6442
6449
  for (const v of payload.voses) {
6443
- const dir = join12(out, "members", safeName(v.slug || v.title || v.id));
6450
+ const dir = join12(out, "members", safeName(v.slug || v.title, v.id));
6444
6451
  await mkdir5(dir, { recursive: true });
6445
6452
  const cfg = await apiJson(origin, `/api/vos/${v.id}/config`, { key });
6446
6453
  if (cfg.status !== 200) {
6447
6454
  lines.push(`skipped ${v.title}: ${apiError("fetch config", cfg)}`);
6448
6455
  continue;
6449
6456
  }
6450
- await writeFile8(
6457
+ await writeFileSafe(
6451
6458
  join12(dir, "config.json"),
6452
6459
  JSON.stringify(cfg.body.config, null, 2)
6453
6460
  );
@@ -6459,7 +6466,7 @@ async function cmdPull(argv) {
6459
6466
  { key }
6460
6467
  );
6461
6468
  if (doc.status === 200) {
6462
- await writeFile8(
6469
+ await writeFileSafe(
6463
6470
  join12(dir, "doc.json"),
6464
6471
  JSON.stringify(doc.body, null, 2)
6465
6472
  );
@@ -6991,7 +6998,7 @@ async function pushTakeClaimable(dir, flags, r) {
6991
6998
 
6992
6999
  // src/plugin/program.ts
6993
7000
  import { existsSync as existsSync13 } from "fs";
6994
- import { mkdir as mkdir6, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
7001
+ import { mkdir as mkdir6, readFile as readFile11 } from "fs/promises";
6995
7002
  import { createInterface as createInterface2 } from "readline/promises";
6996
7003
  import { basename as basename3, dirname as dirname2, join as join14 } from "path";
6997
7004
  import {
@@ -7209,9 +7216,9 @@ async function cmdFetch(argv) {
7209
7216
  if (cfg.status !== 200)
7210
7217
  throw new Error(apiError(`fetch config for ${vosId}`, cfg));
7211
7218
  const slug = typeof vosMeta.slug === "string" && vosMeta.slug ? vosMeta.slug : vosId;
7212
- const out = strFlag(flags, "out") ?? slug;
7219
+ const out = strFlag(flags, "out") ?? safePathName(slug, vosId);
7213
7220
  await mkdir6(out, { recursive: true });
7214
- await writeFile9(
7221
+ await writeFileSafe(
7215
7222
  join14(out, "config.json"),
7216
7223
  JSON.stringify(cfg.body.config, null, 2)
7217
7224
  );
@@ -7237,12 +7244,18 @@ async function cmdFetch(argv) {
7237
7244
  const hosted = migrateHostedDoc3(doc.body);
7238
7245
  const { config: own } = await writeProgramDoc(out, hosted);
7239
7246
  if (own) {
7240
- await writeFile9(join14(out, "config.json"), JSON.stringify(own, null, 2));
7247
+ await writeFileSafe(
7248
+ join14(out, "config.json"),
7249
+ JSON.stringify(own, null, 2)
7250
+ );
7241
7251
  }
7242
7252
  } else if (doc.status === 200) {
7243
7253
  take = true;
7244
7254
  const hosted = migrateHostedDoc3(doc.body);
7245
- await writeFile9(join14(out, "doc.json"), JSON.stringify(hosted, null, 2));
7255
+ await writeFileSafe(
7256
+ join14(out, "doc.json"),
7257
+ JSON.stringify(hosted, null, 2)
7258
+ );
7246
7259
  if (flags.media === true) {
7247
7260
  const media = await pullMedia({ origin, key }, out, hosted, r.log);
7248
7261
  await recordHostedMedia(out, vosId, media);
@@ -7263,7 +7276,7 @@ async function cmdFetch(argv) {
7263
7276
  if (hostedCount && flags.media === true) {
7264
7277
  const pulled = await pullManifest({ origin, key }, out, written, r.log);
7265
7278
  if (pulled) {
7266
- await writeFile9(
7279
+ await writeFileSafe(
7267
7280
  configPath,
7268
7281
  JSON.stringify({ ...written, assets: pulled.assets }, null, 2)
7269
7282
  );
@@ -7737,7 +7750,10 @@ async function cmdPullProgram(argv) {
7737
7750
  const configPath = join14(dir, "config.json");
7738
7751
  let backedUp = false;
7739
7752
  if (existsSync13(configPath)) {
7740
- await writeFile9(join14(dir, "config.backup.json"), await readFile11(configPath));
7753
+ await writeFileSafe(
7754
+ join14(dir, "config.backup.json"),
7755
+ await readFile11(configPath)
7756
+ );
7741
7757
  backedUp = true;
7742
7758
  }
7743
7759
  let headConfig = cfg.body.config;
@@ -7756,7 +7772,7 @@ async function cmdPullProgram(argv) {
7756
7772
  if (own) headConfig = own;
7757
7773
  }
7758
7774
  }
7759
- await writeFile9(configPath, JSON.stringify(headConfig, null, 2));
7775
+ await writeFileSafe(configPath, JSON.stringify(headConfig, null, 2));
7760
7776
  writeSyncState(dir, {
7761
7777
  vosId,
7762
7778
  versionId: typeof head.id === "string" ? head.id : since
@@ -7898,13 +7914,16 @@ async function setProgramStill(dir, t) {
7898
7914
  );
7899
7915
  doc = parsed;
7900
7916
  }
7901
- await writeFile9(docPath, JSON.stringify({ ...doc, still: t }, null, 2) + "\n");
7917
+ await writeFileSafe(
7918
+ docPath,
7919
+ JSON.stringify({ ...doc, still: t }, null, 2) + "\n"
7920
+ );
7902
7921
  }
7903
7922
  async function writeProgramDoc(dir, hosted) {
7904
7923
  const program = hosted.program && typeof hosted.program === "object" ? hosted.program : {};
7905
7924
  const { config, ...rest } = program;
7906
7925
  const onDisk = { ...hosted, program: rest };
7907
- await writeFile9(join14(dir, "doc.json"), JSON.stringify(onDisk, null, 2));
7926
+ await writeFileSafe(join14(dir, "doc.json"), JSON.stringify(onDisk, null, 2));
7908
7927
  return {
7909
7928
  config: config && typeof config === "object" ? config : null
7910
7929
  };
@@ -8013,6 +8032,130 @@ function nameFromUrl(url) {
8013
8032
  }
8014
8033
  }
8015
8034
 
8035
+ // src/plugin/netAddress.ts
8036
+ function privateHostReason(hostname2) {
8037
+ const host = hostname2.replace(/^\[|\]$/g, "").toLowerCase();
8038
+ if (host === "localhost" || host.endsWith(".localhost"))
8039
+ return "is this machine";
8040
+ const v4 = parseIPv4(host);
8041
+ if (v4) return privateIPv4Reason(v4);
8042
+ const v6 = expandIPv6(host);
8043
+ if (!v6) return null;
8044
+ const carried = carriedIPv4(v6);
8045
+ if (carried) return privateIPv4Reason(carried);
8046
+ if (v6.every((w) => w === 0)) return "is an unspecified address";
8047
+ if (v6.slice(0, 7).every((w) => w === 0) && v6[7] === 1)
8048
+ return "is this machine";
8049
+ if ((v6[0] & 65024) === 64512) return "is a private network address";
8050
+ if ((v6[0] & 65472) === 65152) return "is a link-local address";
8051
+ return null;
8052
+ }
8053
+ function privateIPv4Reason([a, b]) {
8054
+ if (a === 0) return "is an unspecified address";
8055
+ if (a === 127) return "is this machine";
8056
+ if (a === 10) return "is a private network address";
8057
+ if (a === 172 && b >= 16 && b <= 31) return "is a private network address";
8058
+ if (a === 192 && b === 168) return "is a private network address";
8059
+ if (a === 100 && b >= 64 && b <= 127) return "is a private network address";
8060
+ if (a === 169 && b === 254) return "is a link-local address";
8061
+ return null;
8062
+ }
8063
+ function parseIPv4(host) {
8064
+ if (!/^[0-9a-fx.]+$/i.test(host)) return null;
8065
+ const parts = host.split(".");
8066
+ if (parts.length > 4 || parts.some((p) => p === "")) return null;
8067
+ const nums = [];
8068
+ for (const p of parts) {
8069
+ let n;
8070
+ if (/^0x[0-9a-f]+$/i.test(p)) n = parseInt(p.slice(2), 16);
8071
+ else if (/^0[0-7]+$/.test(p)) n = parseInt(p, 8);
8072
+ else if (/^[0-9]+$/.test(p)) n = parseInt(p, 10);
8073
+ else return null;
8074
+ nums.push(n);
8075
+ }
8076
+ const last = nums[nums.length - 1];
8077
+ const lead = nums.slice(0, -1);
8078
+ if (lead.some((n) => n > 255)) return null;
8079
+ const fill = 4 - lead.length;
8080
+ if (last >= 256 ** fill) return null;
8081
+ const tail = [];
8082
+ let rest = last;
8083
+ for (let i = 0; i < fill; i++) {
8084
+ tail.unshift(rest % 256);
8085
+ rest = Math.floor(rest / 256);
8086
+ }
8087
+ return [...lead, ...tail];
8088
+ }
8089
+ function expandIPv6(host) {
8090
+ if (!host.includes(":")) return null;
8091
+ const zone = host.indexOf("%");
8092
+ const addr = zone >= 0 ? host.slice(0, zone) : host;
8093
+ if (!/^[0-9a-f:.]+$/i.test(addr)) return null;
8094
+ const halves = addr.split("::");
8095
+ if (halves.length > 2) return null;
8096
+ const words2 = (part) => {
8097
+ if (part === "") return [];
8098
+ const out = [];
8099
+ const groups = part.split(":");
8100
+ for (let i = 0; i < groups.length; i++) {
8101
+ const g = groups[i];
8102
+ if (g.includes(".")) {
8103
+ if (i !== groups.length - 1) return null;
8104
+ const v4 = parseIPv4(g);
8105
+ if (!v4) return null;
8106
+ out.push(v4[0] << 8 | v4[1], v4[2] << 8 | v4[3]);
8107
+ continue;
8108
+ }
8109
+ if (!/^[0-9a-f]{1,4}$/i.test(g)) return null;
8110
+ out.push(parseInt(g, 16));
8111
+ }
8112
+ return out;
8113
+ };
8114
+ const head = words2(halves[0]);
8115
+ const tail = halves.length === 2 ? words2(halves[1]) : [];
8116
+ if (!head || !tail) return null;
8117
+ if (halves.length === 1) return head.length === 8 ? head : null;
8118
+ const gap = 8 - head.length - tail.length;
8119
+ if (gap < 1) return null;
8120
+ return [...head, ...new Array(gap).fill(0), ...tail];
8121
+ }
8122
+ function carriedIPv4(v6) {
8123
+ const zeroLead = v6.slice(0, 5).every((w) => w === 0);
8124
+ const mapped = zeroLead && v6[5] === 65535;
8125
+ const compatible = zeroLead && v6[5] === 0 && (v6[6] !== 0 || v6[7] > 1);
8126
+ const nat64 = v6[0] === 100 && v6[1] === 65435;
8127
+ if (!mapped && !compatible && !nat64) return null;
8128
+ return [v6[6] >> 8, v6[6] & 255, v6[7] >> 8, v6[7] & 255];
8129
+ }
8130
+ function fetchRefusal(url) {
8131
+ let u;
8132
+ try {
8133
+ u = new URL(url);
8134
+ } catch {
8135
+ return `${url} is not a URL`;
8136
+ }
8137
+ if (u.protocol !== "http:" && u.protocol !== "https:")
8138
+ return `${url} is not an http(s) address, and the CLI fetches nothing else`;
8139
+ const reason = privateHostReason(u.hostname);
8140
+ if (reason)
8141
+ return `${u.hostname} ${reason}, and the CLI fetches only from the public internet`;
8142
+ return null;
8143
+ }
8144
+ var MAX_HOPS = 5;
8145
+ async function fetchPublic(url, init = {}, fetchImpl = fetch) {
8146
+ let at2 = url;
8147
+ for (let hop = 0; ; hop++) {
8148
+ const refused = fetchRefusal(at2);
8149
+ if (refused) throw new Error(refused);
8150
+ const res = await fetchImpl(at2, { ...init, redirect: "manual" });
8151
+ const location = res.headers.get("location");
8152
+ if (res.status < 300 || res.status > 399 || !location) return res;
8153
+ if (hop >= MAX_HOPS)
8154
+ throw new Error(`${url} redirected more than ${MAX_HOPS} times`);
8155
+ at2 = new URL(location, at2).href;
8156
+ }
8157
+ }
8158
+
8016
8159
  // src/plugin/asset.ts
8017
8160
  var BOOLEAN_FLAGS3 = /* @__PURE__ */ new Set(["json", "help"]);
8018
8161
  async function cmdRename(argv) {
@@ -8133,8 +8276,10 @@ async function cmdImport(argv) {
8133
8276
  const key = requireCredential(strFlag(flags, "key"));
8134
8277
  const folderRef = strFlag(flags, "folder");
8135
8278
  const folder = folderRef ? resolveFolder(await listFolders(origin, key), folderRef) : null;
8279
+ const refused = fetchRefusal(url);
8280
+ if (refused) throw new UsageError(`import: ${refused}`);
8136
8281
  r.log(`fetching ${url}`);
8137
- const res = await fetch(url, { redirect: "follow" });
8282
+ const res = await fetchPublic(url);
8138
8283
  if (!res.ok)
8139
8284
  throw new Error(`import ${url}: the address answered ${res.status}`);
8140
8285
  const declared = Number(res.headers.get("content-length") ?? 0);
@@ -10608,7 +10753,7 @@ async function cmdRecipe(argv) {
10608
10753
  }
10609
10754
 
10610
10755
  // src/plugin/brand.ts
10611
- import { writeFile as writeFile10 } from "fs/promises";
10756
+ import { writeFile as writeFile8 } from "fs/promises";
10612
10757
  import { resolve as resolve11 } from "path";
10613
10758
  import { parseFrontmatter as parseFrontmatter2 } from "@vosjs/shared/frontmatter";
10614
10759
  import { lookKindForGround } from "@vosjs/studio-core";
@@ -10907,7 +11052,7 @@ function renderBrandMd(c, claim) {
10907
11052
  }
10908
11053
  async function fetchText(url) {
10909
11054
  try {
10910
- const res = await fetch(url, { redirect: "follow" });
11055
+ const res = await fetchPublic(url);
10911
11056
  if (!res.ok) return null;
10912
11057
  const type = res.headers.get("content-type") ?? "";
10913
11058
  if (/text\/html/i.test(type)) return null;
@@ -10927,6 +11072,8 @@ async function cmdBrand(argv) {
10927
11072
  } catch {
10928
11073
  throw new UsageError(`not a URL: ${raw}`);
10929
11074
  }
11075
+ const refused = fetchRefusal(url);
11076
+ if (refused) throw new UsageError(refused);
10930
11077
  const r = createReporter(flags.json === true);
10931
11078
  const out = resolve11(strFlag(flags, "out") ?? "BRAND.md");
10932
11079
  r.log(`reading ${origin}/design.md and /llms.txt\u2026`);
@@ -10962,7 +11109,7 @@ async function cmdBrand(argv) {
10962
11109
  composition,
10963
11110
  llms?.claim ?? design?.description ?? null
10964
11111
  );
10965
- await writeFile10(out, md);
11112
+ await writeFile8(out, md);
10966
11113
  const k = composition.kit;
10967
11114
  r.done(
10968
11115
  {
@@ -10993,6 +11140,20 @@ function hostedEnv(actions, shell) {
10993
11140
  }
10994
11141
  return { env, missing };
10995
11142
  }
11143
+ function envNamesNotice(actions) {
11144
+ const names = setupEnvNames2(actions.setup);
11145
+ if (names.length === 0) return null;
11146
+ return {
11147
+ names,
11148
+ line: `the setup reads ${names.length === 1 ? "this environment variable" : "these environment variables"} from this shell: ${names.join(", ")} (names only; a value is never printed or stored)`
11149
+ };
11150
+ }
11151
+ function announceEnvNames(actions, r) {
11152
+ const notice = envNamesNotice(actions);
11153
+ if (!notice) return;
11154
+ r.log(notice.line);
11155
+ r.event({ event: "env", names: notice.names });
11156
+ }
10996
11157
  function isWallError(error) {
10997
11158
  return !!error && /^(\[\w+\] )?The page is behind a sign-in/.test(error);
10998
11159
  }
@@ -11076,8 +11237,11 @@ async function recordHosted(input) {
11076
11237
  };
11077
11238
  }
11078
11239
 
11240
+ // src/plugin/run.ts
11241
+ import { urlSchemeProblem } from "@vosjs/render-core/record";
11242
+
11079
11243
  // src/plugin/agentBrowser.ts
11080
- import { writeFile as writeFile11 } from "fs/promises";
11244
+ import { writeFile as writeFile9 } from "fs/promises";
11081
11245
  import { resolve as resolve12 } from "path";
11082
11246
  function parseAgentBrowserLog(text) {
11083
11247
  const records = [];
@@ -11575,7 +11739,7 @@ async function cmdActions(argv) {
11575
11739
  );
11576
11740
  return EXIT_ERROR;
11577
11741
  }
11578
- await writeFile11(out, `${JSON.stringify(result.actions, null, 2)}
11742
+ await writeFile9(out, `${JSON.stringify(result.actions, null, 2)}
11579
11743
  `);
11580
11744
  r.done(
11581
11745
  { ok: true, out, url: result.actions.url ?? null, ...summary2(result) },
@@ -11610,7 +11774,43 @@ async function cmdActionsScript(input, flags) {
11610
11774
  import { existsSync as existsSync20 } from "fs";
11611
11775
  import { copyFile, mkdir as mkdir7, readFile as readFile12, stat as stat2 } from "fs/promises";
11612
11776
  import { basename as basename9, join as join22, resolve as resolve13 } from "path";
11777
+
11778
+ // src/plugin/traceInflate.ts
11613
11779
  import { inflateRawSync } from "zlib";
11780
+ var TRACE_ENTRY_MAX_BYTES = 64 * 1024 * 1024;
11781
+ var TRACE_TOTAL_MAX_BYTES = 256 * 1024 * 1024;
11782
+ function traceBudget(caps = {}) {
11783
+ return {
11784
+ entry: caps.entry ?? TRACE_ENTRY_MAX_BYTES,
11785
+ total: caps.total ?? TRACE_TOTAL_MAX_BYTES,
11786
+ used: 0
11787
+ };
11788
+ }
11789
+ var mib = (n) => `${(n / (1024 * 1024)).toFixed(n < 10 * 1024 * 1024 ? 1 : 0)} MiB`;
11790
+ function inflateEntry(raw, entry, budget) {
11791
+ const room = Math.min(budget.entry, budget.total - budget.used);
11792
+ const over = (bytes) => new Error(
11793
+ `${entry.name} inflates to ${bytes}, past the ${mib(budget.entry)} an entry may take (${mib(budget.total)} for the whole trace); this is not a trace the recorder reads`
11794
+ );
11795
+ if (entry.size > room) throw over(mib(entry.size));
11796
+ let out;
11797
+ if (entry.method === 8) {
11798
+ try {
11799
+ out = new Uint8Array(inflateRawSync(raw, { maxOutputLength: room + 1 }));
11800
+ } catch (e) {
11801
+ if (e.code === "ERR_BUFFER_TOO_LARGE")
11802
+ throw over(`more than ${mib(room)}`);
11803
+ throw e;
11804
+ }
11805
+ } else {
11806
+ out = raw;
11807
+ }
11808
+ if (out.length > room) throw over(mib(out.length));
11809
+ budget.used += out.length;
11810
+ return out;
11811
+ }
11812
+
11813
+ // src/plugin/ingest.ts
11614
11814
  import {
11615
11815
  cursorFromPlaywrightTrace,
11616
11816
  cursorFromTrace,
@@ -11706,7 +11906,7 @@ async function readTraceFile(path, offsetMs) {
11706
11906
  }
11707
11907
  const raw = zipEntryBytes(bytes, entry);
11708
11908
  const text2 = new TextDecoder().decode(
11709
- entry.method === 8 ? new Uint8Array(inflateRawSync(raw)) : raw
11909
+ inflateEntry(raw, entry, traceBudget())
11710
11910
  );
11711
11911
  return cursorFromPlaywrightTrace(text2, { offsetMs });
11712
11912
  }
@@ -12867,6 +13067,9 @@ async function cmdRecord(argv) {
12867
13067
  const url = strFlag(flags, "url") ?? actions.url;
12868
13068
  if (!url)
12869
13069
  throw new UsageError('no URL \u2014 set "url" in the actions file or pass --url');
13070
+ const scheme = urlSchemeProblem(url);
13071
+ if (scheme) throw new UsageError(scheme);
13072
+ announceEnvNames(actions, r);
12870
13073
  const outDir = resolve14(strFlag(flags, "out") ?? "take");
12871
13074
  const storageState = takeStorageState(flags);
12872
13075
  const sessionName = takeSessionName(flags, storageState);
@@ -13112,6 +13315,9 @@ async function cmdCreate2(argv) {
13112
13315
  const url = strFlag(flags, "url") ?? actions.url;
13113
13316
  if (!url)
13114
13317
  throw new UsageError('no URL \u2014 set "url" in the actions file or pass --url');
13318
+ const scheme = urlSchemeProblem(url);
13319
+ if (scheme) throw new UsageError(scheme);
13320
+ announceEnvNames(actions, r);
13115
13321
  const outDir = resolve14(strFlag(flags, "out") ?? "take");
13116
13322
  const format = videoFormat(strFlag(flags, "format"), positionals[0]);
13117
13323
  const out = positionals[0] ?? join25(outDir, `out.${format}`);
@@ -14475,4 +14681,4 @@ export {
14475
14681
  verbHelp,
14476
14682
  run
14477
14683
  };
14478
- //# sourceMappingURL=chunk-OJ3ZCPYS.js.map
14684
+ //# sourceMappingURL=chunk-IJZ3C435.js.map