@vosjs/cli 0.60.1 → 0.61.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/README.md CHANGED
@@ -328,7 +328,7 @@ vos pull bright-loop [--since <versionId>] [--check] # what changed on vos.so
328
328
  # --check reports without writing; --since walks from a base you name
329
329
  vos duplicate <vosId> # a private sibling of your OWN vos (someone else's is remixed: fetch, then push --remix-of)
330
330
  vos folder list | create <name> [--parent] [--desc] | move <ids…> --to <folder|none> | pull <ref> [--media]
331
- vos asset push <file…> [--folder <slug>] | rename <id> <name.ext> # sound and video too: they land in Sound > Uploads
331
+ vos asset push <file…> [--folder <slug>] | rename <id> <name.ext> # any kind the platform takes (GET /api/limits): models, pictures, SVG, fonts, HDR, sound, video
332
332
  vos recipe push <FILE.md> --folder <slug> | --asset <id> # the one recipe write: create, or replace in place
333
333
  ```
334
334
 
@@ -4,7 +4,7 @@ import {
4
4
  localManifestRefs,
5
5
  pullManifest,
6
6
  uploadManifest
7
- } from "./chunk-YMVRTZ4L.js";
7
+ } from "./chunk-EZW6ZCEH.js";
8
8
  import "./chunk-WCF6KIOK.js";
9
9
  export {
10
10
  hostedLiteralWarnings,
@@ -12,4 +12,4 @@ export {
12
12
  pullManifest,
13
13
  uploadManifest
14
14
  };
15
- //# sourceMappingURL=assetManifest-Y5FYTZW6.js.map
15
+ //# sourceMappingURL=assetManifest-NS64PLY5.js.map
@@ -34,7 +34,7 @@ import {
34
34
  uploadDocRefs,
35
35
  uploadManifest,
36
36
  writeJson
37
- } from "./chunk-YMVRTZ4L.js";
37
+ } from "./chunk-EZW6ZCEH.js";
38
38
  import {
39
39
  CREDENTIALS_PATH,
40
40
  MEDIA_HEAD_BYTES,
@@ -7255,6 +7255,7 @@ async function pushTake(dir, flags, r) {
7255
7255
  `recording upload failed: ${e instanceof Error ? e.message : String(e)}`
7256
7256
  );
7257
7257
  }
7258
+ for (const note of upload.notes) r.log(` note: ${note}`);
7258
7259
  const assetId = upload.id;
7259
7260
  const assetUrl = upload.url;
7260
7261
  r.event({ event: "recording", assetId, reused: upload.reused });
@@ -8358,18 +8359,8 @@ async function writeProgramDoc(dir, hosted) {
8358
8359
  // src/plugin/asset.ts
8359
8360
  import { createHash as createHash2 } from "crypto";
8360
8361
  import { readFileSync as readFileSync3 } from "fs";
8361
- import { basename as basename3, extname as extname2 } from "path";
8362
+ import { basename as basename3 } from "path";
8362
8363
  var BOOLEAN_FLAGS3 = /* @__PURE__ */ new Set(["json", "help"]);
8363
- var MIME_BY_EXT = {
8364
- ".png": "image/png",
8365
- ".jpg": "image/jpeg",
8366
- ".jpeg": "image/jpeg",
8367
- ".webp": "image/webp",
8368
- ".gif": "image/gif",
8369
- ".glb": "model/gltf-binary",
8370
- ".gltf": "model/gltf+json",
8371
- ".md": "text/markdown"
8372
- };
8373
8364
  async function cmdRename(argv) {
8374
8365
  const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS3);
8375
8366
  const [assetId, filename] = positionals;
@@ -8408,7 +8399,6 @@ async function cmdPush(argv) {
8408
8399
  const folderRef = strFlag(flags, "folder");
8409
8400
  const folder = folderRef ? resolveFolder(await listFolders(origin, key), folderRef) : null;
8410
8401
  const uploaded = [];
8411
- let unfiledMedia = 0;
8412
8402
  for (const file of positionals) {
8413
8403
  const name = basename3(file);
8414
8404
  const body = readFileSync3(file);
@@ -8416,56 +8406,36 @@ async function cmdPush(argv) {
8416
8406
  head: body.subarray(0, MEDIA_HEAD_BYTES),
8417
8407
  filename: name
8418
8408
  });
8419
- if (/^(audio|video)\//.test(media.type)) {
8420
- const sent = nameForType(name, media.type);
8421
- let put;
8422
- try {
8423
- put = await uploadAsset({ origin, key }, new Uint8Array(body), {
8424
- filename: sent,
8425
- contentType: media.type,
8426
- contentHash: createHash2("sha256").update(body).digest("hex"),
8427
- ...folder ? { folderId: folder.id } : {}
8428
- });
8429
- } catch (e) {
8430
- const landed = uploaded.length ? ` (${uploaded.length} of ${positionals.length} landed before it)` : "";
8431
- throw new Error(
8432
- `push ${name}${landed}: ${e instanceof Error ? e.message : String(e)}`
8433
- );
8434
- }
8435
- if (!folder && !put.reused) unfiledMedia += 1;
8436
- uploaded.push({ id: put.id, filename: sent });
8437
- r.log(
8438
- `uploaded ${sent} (${put.id})${put.reused ? " \u2014 already on your shelf" : ""} ${put.url}`
8439
- );
8440
- continue;
8441
- }
8442
- const mime = MIME_BY_EXT[extname2(name).toLowerCase()] ?? "application/octet-stream";
8443
- const form = new FormData();
8444
- form.set("file", new Blob([body], { type: mime }), name);
8445
- if (folder) form.set("folderId", folder.id);
8446
- const res = await fetch(`${origin}/api/assets/upload`, {
8447
- method: "POST",
8448
- headers: { accept: "application/json", authorization: `Bearer ${key}` },
8449
- body: form
8450
- });
8451
- let payload = {};
8409
+ const isMedia = /^(audio|video)\//.test(media.type);
8410
+ const sent = isMedia ? nameForType(name, media.type) : name;
8411
+ let put;
8452
8412
  try {
8453
- payload = await res.json();
8454
- } catch {
8455
- }
8456
- if (res.status !== 200 && res.status !== 201) {
8413
+ put = await uploadAsset({ origin, key }, new Uint8Array(body), {
8414
+ filename: sent,
8415
+ ...isMedia ? { contentType: media.type } : {},
8416
+ contentHash: createHash2("sha256").update(body).digest("hex"),
8417
+ intent: "library",
8418
+ ...folder ? { folderId: folder.id } : {}
8419
+ });
8420
+ } catch (e) {
8457
8421
  const landed = uploaded.length ? ` (${uploaded.length} of ${positionals.length} landed before it)` : "";
8458
8422
  throw new Error(
8459
- apiError(`push ${name}${landed}`, {
8460
- status: res.status,
8461
- body: payload
8462
- })
8423
+ `push ${name}${landed}: ${e instanceof Error ? e.message : String(e)}`
8463
8424
  );
8464
8425
  }
8465
- uploaded.push({ id: payload.id, filename: payload.filename });
8426
+ const stored = put.filename || sent;
8427
+ uploaded.push({
8428
+ id: put.id,
8429
+ filename: stored,
8430
+ kind: put.kind,
8431
+ url: put.url,
8432
+ ...put.reused ? { reused: true } : {},
8433
+ ...put.notes.length ? { notes: put.notes } : {}
8434
+ });
8466
8435
  r.log(
8467
- `uploaded ${String(payload.filename ?? name)} (${String(payload.id)})`
8436
+ `uploaded ${stored} (${put.id})${put.reused ? " \u2014 already on your shelf" : ""} ${put.url}`
8468
8437
  );
8438
+ for (const note of put.notes) r.log(` note: ${note}`);
8469
8439
  }
8470
8440
  r.done(
8471
8441
  {
@@ -8473,8 +8443,7 @@ async function cmdPush(argv) {
8473
8443
  count: uploaded.length,
8474
8444
  folder: folder?.slug ?? null
8475
8445
  },
8476
- `pushed ${uploaded.length} asset${uploaded.length === 1 ? "" : "s"}${folder ? ` into ${folder.slug}` : ""}` + (unfiledMedia ? `
8477
- note: an unfiled sound or video that no document uses is removed after 7 days. Reference it from a doc (doc.audio key = its url) or push it with --folder <slug>` : "")
8446
+ `pushed ${uploaded.length} asset${uploaded.length === 1 ? "" : "s"}${folder ? ` into ${folder.slug}` : ""}`
8478
8447
  );
8479
8448
  return EXIT_OK;
8480
8449
  }
@@ -9185,7 +9154,7 @@ import { findFontFamily as findFontFamily3 } from "@vosjs/shared";
9185
9154
  import { existsSync as existsSync16, readFileSync as readFileSync5, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
9186
9155
  import { createServer as createServer2 } from "http";
9187
9156
  import { createRequire } from "module";
9188
- import { basename as basename5, extname as extname3, join as join19 } from "path";
9157
+ import { basename as basename5, extname as extname2, join as join19 } from "path";
9189
9158
  function themeColors(sources) {
9190
9159
  const out = {};
9191
9160
  const re = /\bconst\s+([A-Za-z_$][\w$]*)\s*(?::\s*string\s*)?=\s*['"](#[0-9a-fA-F]{3,8})['"]/g;
@@ -9366,7 +9335,7 @@ async function readRemotion(dir, log) {
9366
9335
  if (!f.startsWith(out) || !existsSync16(f) || statSync5(f).isDirectory())
9367
9336
  f = join19(out, "index.html");
9368
9337
  rs.writeHead(200, {
9369
- "content-type": TYPES[extname3(f)] ?? "application/octet-stream"
9338
+ "content-type": TYPES[extname2(f)] ?? "application/octet-stream"
9370
9339
  });
9371
9340
  rs.end(readFileSync5(f));
9372
9341
  }).listen(0, "127.0.0.1");
@@ -10684,6 +10653,7 @@ function scaffoldSourceDir(inv) {
10684
10653
  }
10685
10654
 
10686
10655
  // src/plugin/recipe.ts
10656
+ import { createHash as createHash3 } from "crypto";
10687
10657
  import { readFileSync as readFileSync8 } from "fs";
10688
10658
  import { basename as basename7 } from "path";
10689
10659
  var BOOLEAN_FLAGS9 = /* @__PURE__ */ new Set(["json", "help"]);
@@ -10712,55 +10682,49 @@ async function cmdPush2(argv) {
10712
10682
  });
10713
10683
  const key = requireCredential(strFlag(flags, "key"));
10714
10684
  if (assetId) {
10715
- const res2 = await apiJson(origin, `/api/assets/${assetId}/file`, {
10685
+ const res = await apiJson(origin, `/api/assets/${assetId}/file`, {
10716
10686
  method: "PUT",
10717
10687
  key,
10718
10688
  raw: new Uint8Array(body),
10719
10689
  headers: { "content-type": "text/markdown" }
10720
10690
  });
10721
- if (res2.status !== 200) {
10722
- throw new Error(apiError(`replace recipe ${assetId}`, res2));
10691
+ if (res.status !== 200) {
10692
+ throw new Error(apiError(`replace recipe ${assetId}`, res));
10723
10693
  }
10724
10694
  r.done(
10725
- { id: assetId, filename: res2.body.filename, replaced: true },
10726
- `replaced recipe ${assetId} (${String(res2.body.filename)}) in place \u2014 the prior body is kept, restore it from the recipe page`
10695
+ { id: assetId, filename: res.body.filename, replaced: true },
10696
+ `replaced recipe ${assetId} (${String(res.body.filename)}) in place \u2014 the prior body is kept, restore it from the recipe page`
10727
10697
  );
10728
10698
  return EXIT_OK;
10729
10699
  }
10730
10700
  const folder = resolveFolder(await listFolders(origin, key), folderRef);
10731
- const form = new FormData();
10732
- form.set("file", new Blob([body], { type: "text/markdown" }), filename);
10733
- form.set("folderId", folder.id);
10734
- const res = await fetch(`${origin}/api/assets/upload`, {
10735
- method: "POST",
10736
- headers: { accept: "application/json", authorization: `Bearer ${key}` },
10737
- body: form
10738
- });
10739
- let payload = {};
10701
+ let put;
10740
10702
  try {
10741
- payload = await res.json();
10742
- } catch {
10743
- }
10744
- if (res.status !== 200 && res.status !== 201) {
10703
+ put = await uploadAsset({ origin, key }, new Uint8Array(body), {
10704
+ filename,
10705
+ contentType: "text/markdown",
10706
+ contentHash: createHash3("sha256").update(body).digest("hex"),
10707
+ intent: "library",
10708
+ folderId: folder.id
10709
+ });
10710
+ } catch (e) {
10745
10711
  throw new Error(
10746
- apiError(`push recipe ${filename}`, {
10747
- status: res.status,
10748
- body: payload
10749
- })
10712
+ `push recipe ${filename}: ${e instanceof Error ? e.message : String(e)}`
10750
10713
  );
10751
10714
  }
10752
- const meta = payload.metadata ?? {};
10753
- const stored = typeof payload.filename === "string" ? payload.filename : filename;
10715
+ const meta = put.metadata ?? {};
10716
+ const stored = put.filename || filename;
10754
10717
  r.done(
10755
10718
  {
10756
- id: payload.id,
10757
- filename: payload.filename,
10719
+ id: put.id,
10720
+ filename: stored,
10758
10721
  folder: folder.slug,
10759
10722
  name: meta.name,
10760
- description: meta.description
10723
+ description: meta.description,
10724
+ ...put.notes.length ? { notes: put.notes } : {}
10761
10725
  },
10762
- `pushed ${stored} into ${folder.slug} (${String(payload.id)})${typeof meta.name === "string" ? ` \u2014 ${meta.name}` : ""}
10763
- Replace it later with: vos recipe push ${file} --asset ${String(payload.id)}`
10726
+ `pushed ${stored} into ${folder.slug} (${put.id})${typeof meta.name === "string" ? ` \u2014 ${meta.name}` : ""}
10727
+ Replace it later with: vos recipe push ${file} --asset ${put.id}`
10764
10728
  );
10765
10729
  return EXIT_OK;
10766
10730
  }
@@ -12683,12 +12647,12 @@ Platform (vos.so) \u2014 fetch, edit, push, pull, repeat
12683
12647
  and fileUrl untouched; the extension must keep matching the
12684
12648
  asset's kind (a recipe stays .md)
12685
12649
  vos asset push <file...> [--folder <folderId|slug>]
12686
- upload files onto your shelf (a key takes models .glb/.gltf,
12687
- recipes .md and images .png/.jpg/.webp/.gif \u2014 posters and
12688
- store stills file into the release's project; 40 images/24h \u2014
12689
- and sound and video, which land in Sound > Uploads and print
12690
- the url a doc.json audio key takes; an unfiled one that no
12691
- document uses is removed after 7 days, so pass --folder)
12650
+ add files to your library: models, pictures and SVGs, fonts,
12651
+ HDR maps, sound, video, captions and recipes. The platform
12652
+ reads each file and answers what it is and the name it is
12653
+ stored under; the same bytes twice are the same file. Prints
12654
+ the url a doc.json key takes. GET /api/limits lists the
12655
+ kinds, their size caps and their daily rates
12692
12656
  vos recipe push <file.md> --folder <folderId|slug>
12693
12657
  vos recipe push <file.md> --asset <assetId>
12694
12658
  put a recipe (a plain .md) on the shelf: --folder creates it
@@ -14643,4 +14607,4 @@ export {
14643
14607
  verbHelp,
14644
14608
  run
14645
14609
  };
14646
- //# sourceMappingURL=chunk-QL25OPZB.js.map
14610
+ //# sourceMappingURL=chunk-C4P6MZJG.js.map