@vosjs/cli 0.85.0 → 0.86.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 +6 -5
- package/dist/{assetManifest-32VI7OK7.js → assetManifest-QFJ7X6TT.js} +3 -3
- package/dist/{chunk-Q47FUCYN.js → chunk-2LAXJZCG.js} +2 -2
- package/dist/{chunk-PF2NEZYU.js → chunk-7A3PZARL.js} +10 -3
- package/dist/{chunk-PF2NEZYU.js.map → chunk-7A3PZARL.js.map} +1 -1
- package/dist/{chunk-EPSYIF2S.js → chunk-PZP76YJI.js} +298 -58
- package/dist/chunk-PZP76YJI.js.map +1 -0
- package/dist/{chunk-M5ZBQFPG.js → chunk-V3RUNUNP.js} +2 -2
- package/dist/{chunk-NJBUBXFE.js → chunk-ZXFO32KW.js} +284 -62
- package/dist/chunk-ZXFO32KW.js.map +1 -0
- package/dist/cli.js +7 -7
- package/dist/index.d.ts +24 -6
- package/dist/index.js +5 -5
- package/dist/manifest-OLVFUZTW.js +8 -0
- package/dist/{run-XFKADM6I.js → run-KB36L2ZI.js} +5 -5
- package/package.json +3 -3
- package/skills/VERSION +1 -1
- package/skills/launch-kit/SKILL.md +6 -2
- package/skills/product-video/SKILL.md +13 -3
- package/skills/vos-cut/SKILL.md +6 -2
- package/skills/vos-score/SKILL.md +15 -5
- package/dist/chunk-EPSYIF2S.js.map +0 -1
- package/dist/chunk-NJBUBXFE.js.map +0 -1
- package/dist/manifest-GPE4CVDR.js +0 -8
- /package/dist/{assetManifest-32VI7OK7.js.map → assetManifest-QFJ7X6TT.js.map} +0 -0
- /package/dist/{chunk-Q47FUCYN.js.map → chunk-2LAXJZCG.js.map} +0 -0
- /package/dist/{chunk-M5ZBQFPG.js.map → chunk-V3RUNUNP.js.map} +0 -0
- /package/dist/{manifest-GPE4CVDR.js.map → manifest-OLVFUZTW.js.map} +0 -0
- /package/dist/{run-XFKADM6I.js.map → run-KB36L2ZI.js.map} +0 -0
package/README.md
CHANGED
|
@@ -39,8 +39,9 @@ Node 18 or newer and a Chromium-family browser. A system Chrome is used when pre
|
|
|
39
39
|
```bash
|
|
40
40
|
vos setup [--agent claude,cursor,codex,copilot|all] [--global] [--no-skills] [--skills-from-catalog] [--no-rules] [--no-browser] [--url <dev server>]
|
|
41
41
|
vos doctor [--url <dev server>] # what is ready, in words; exit 3 when no browser
|
|
42
|
-
vos whoami # the key's name and
|
|
43
|
-
vos
|
|
42
|
+
vos whoami # the account in use, its key's name, and every other account stored; never a key
|
|
43
|
+
vos switch [<handle>] # use another stored account (with two stored, the other one)
|
|
44
|
+
vos logout [<handle>] [--all] # forget the account in use, a named one, or every stored credential
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|
`vos setup` detects the agents present by their directories (`.claude/`, `.cursor/`, `.codex/` or `.agents/`, `.github/copilot`; the home forms under `--global`), installs the skills into them from the copy of the catalog this package ships (`skills/`, the catalog at the tag this release was cut from; `--skills-from-catalog` fetches that same tag through skills.sh instead, with the bundled copy as the fallback when it cannot be reached), finds a browser in the recorder's own order or installs Chromium, writes one block between `<!-- vos:begin -->` and `<!-- vos:end -->` markers into `AGENTS.md` (or `CLAUDE.md` when only that exists), so a second run replaces its own text and never yours, and ends with `doctor`. These four verbs print NDJSON whenever stdout is not a TTY, and every `done` event carries `next_step`.
|
|
@@ -531,10 +532,10 @@ vos brand https://your.app --out BRAND.md # the brand kit,
|
|
|
531
532
|
|
|
532
533
|
## The vos.so loop
|
|
533
534
|
|
|
534
|
-
Everything that runs on your machine is open source; [vos.so](https://vos.so) is the hosted platform: a studio for the human half of an edit, version history with a typed changelog, a shelf of projects and recipes. All vos.so traffic lives behind one client: one origin (`VOS_ORIGIN`, default `https://vos.so`; `--origin` per call), one credential ladder (`--key`, then `VOS_API_KEY`, then
|
|
535
|
+
Everything that runs on your machine is open source; [vos.so](https://vos.so) is the hosted platform: a studio for the human half of an edit, version history with a typed changelog, a shelf of projects and recipes. All vos.so traffic lives behind one client: one origin (`VOS_ORIGIN`, default `https://vos.so`; `--origin` per call), one credential ladder (`--key`, then `--account <handle>`, then `VOS_API_KEY`, then `VOS_ACCOUNT`, then the account in use at `~/.config/vos/credentials`; a `vos_rg_` remix grant is just a key), one tracking file (`vos.json` beside the artifact). **A person is many accounts** (themselves, and every organization they act for), so `vos login` is additive: the approval page asks which account the terminal is signed in as, every account signed in is stored by name under `~/.config/vos/accounts/<host>/<id>`, the one in use is copied to `~/.config/vos/credentials` (its first line is still the key, for every older reader), `vos switch [<handle>]` changes which, `vos whoami` says which is in use and what else is stored, and `--account <handle>` or `VOS_ACCOUNT` picks a stored one for a command without switching; a name nothing is stored under is refused in words, never answered with another account. A key acts for exactly the account it belongs to, so switching is choosing a key. Credentials are never printed, and a stored one is sent only to the origin it was minted for (a file written before the origin line is `https://vos.so`'s): a command aimed at another origin sends no key and says so, so pass `--key` or `VOS_API_KEY` for it, or `vos login --origin <it>`. Keys can never publish: pushes are private, and humans publish on vos.so.
|
|
535
536
|
|
|
536
537
|
```bash
|
|
537
|
-
vos login [--key <k>] [--label <name>] [--no-browser] # browser sign-in: a code and a vos.so/cli/auth URL, a human approves, the key stores itself
|
|
538
|
+
vos login [--key <k>] [--label <name>] [--no-browser] # browser sign-in: a code and a vos.so/cli/auth URL, a human approves (as themselves or an org), the key stores itself beside the ones already stored
|
|
538
539
|
vos login --handoff https://vos.so/h/<token> # the setup link a signed-in person's line carries: exchanged once for a key, no click
|
|
539
540
|
vos fetch <vosId|url> [--out <slug>] [--media] # a program writes config.json + vos.json; a take writes doc.json (+ the recording with --media)
|
|
540
541
|
vos check bright-loop/config.json # full local validation
|
|
@@ -593,7 +594,7 @@ vos push /tmp/take --label "$TAG launch" --yes --json # VOS_API_KEY as a r
|
|
|
593
594
|
- **`--max-duration <s>`** on `record` and `create` defaults to the hosted recording cap, read live from `GET /api/limits` (2 s, fail-open to 30 min when the origin is unreachable): the capture stops there and the done event says so. Cut the flow rather than raising the cap; the platform refuses a longer take.
|
|
594
595
|
- **`create`** is the one-shot verb: record, auto-plan and render in one command and one browser session. The take directory still lands on disk, so the full loop (frames, edit `doc.json`, re-render) stays open afterwards.
|
|
595
596
|
- **`vos validate <thing>`** takes an `actions.json`, a take directory, a program directory (`config.json`, plus its program document when present), or a `kit.json`; exit 1 on any problem.
|
|
596
|
-
- **Environment.** `VOS_ORIGIN` (the platform, and the studio `vos open` opens), `VOS_API_KEY
|
|
597
|
+
- **Environment.** `VOS_ORIGIN` (the platform, and the studio `vos open` opens), `VOS_API_KEY` (a key, as a CI secret; it outranks the store), `VOS_ACCOUNT` (a stored account by handle, for a shell or a runner that never holds a key), `VOS_BROWSER_PATH`, `VOS_CLIENT` (the client string a push self-reports; unset, a push names the coding agent that spawned the CLI, read from its environment the way `@vercel/detect-agent` reads it, e.g. `claude-code vos-cli`, else `vos-cli`).
|
|
597
598
|
|
|
598
599
|
## Programmatic use
|
|
599
600
|
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
localManifestRefs,
|
|
5
5
|
pullManifest,
|
|
6
6
|
uploadManifest
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-V3RUNUNP.js";
|
|
8
|
+
import "./chunk-PZP76YJI.js";
|
|
9
9
|
export {
|
|
10
10
|
hostedLiteralWarnings,
|
|
11
11
|
localManifestRefs,
|
|
12
12
|
pullManifest,
|
|
13
13
|
uploadManifest
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=assetManifest-
|
|
15
|
+
//# sourceMappingURL=assetManifest-QFJ7X6TT.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
ASSET_ROUTE,
|
|
4
4
|
UsageError,
|
|
5
5
|
serveFile
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PZP76YJI.js";
|
|
7
7
|
|
|
8
8
|
// src/loadConfig.ts
|
|
9
9
|
import { readFile } from "fs/promises";
|
|
@@ -573,4 +573,4 @@ export {
|
|
|
573
573
|
setFlags,
|
|
574
574
|
applyDataSets
|
|
575
575
|
};
|
|
576
|
-
//# sourceMappingURL=chunk-
|
|
576
|
+
//# sourceMappingURL=chunk-2LAXJZCG.js.map
|
|
@@ -128,13 +128,20 @@ var manifest = {
|
|
|
128
128
|
},
|
|
129
129
|
{
|
|
130
130
|
name: "whoami",
|
|
131
|
-
summary: "the
|
|
131
|
+
summary: "the account in use and every other one stored for the origin, never a key"
|
|
132
132
|
},
|
|
133
|
-
{
|
|
133
|
+
{
|
|
134
|
+
name: "switch",
|
|
135
|
+
summary: "use another stored account (vos login once per account stores them all)"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "logout",
|
|
139
|
+
summary: "forget the account in use, a named one (vos logout <handle>), or all (--all)"
|
|
140
|
+
}
|
|
134
141
|
]
|
|
135
142
|
};
|
|
136
143
|
|
|
137
144
|
export {
|
|
138
145
|
manifest
|
|
139
146
|
};
|
|
140
|
-
//# sourceMappingURL=chunk-
|
|
147
|
+
//# sourceMappingURL=chunk-7A3PZARL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin/manifest.ts"],"sourcesContent":["/**\n * The verb manifest of the take pipeline and the vos.so verbs — what\n * `vos help` lists under the engine verbs. It kept the shape a separately\n * installed plugin once handed the host (name + host range), so a script\n * reading it keeps working.\n */\nexport interface PluginVerb {\n name: string\n summary: string\n}\n\nexport interface PluginManifest {\n name: string\n /** Host versions this plugin speaks the run(argv) contract with. */\n hostRange: string\n verbs: PluginVerb[]\n}\n\nexport const manifest: PluginManifest = {\n name: '@vosjs/cli',\n hostRange: '>=0.9.0',\n verbs: [\n {\n name: 'create',\n summary: 'record + auto-plan + render, one command (--strict)',\n },\n {\n name: 'record',\n summary: 'drive actions.json into a take (screencast + cursor track)',\n },\n {\n name: 'look',\n summary:\n 'see a page before scripting it (signed in, like record): a screenshot + every control in view with one proposed stable selector',\n },\n {\n name: 'plan',\n summary:\n 'plan zoom/cursor effects into doc.json (wand contract); --reuse re-times a previous cut onto a re-recording',\n },\n {\n name: 'render',\n summary: 'render a take directory (engine configs render in the host)',\n },\n {\n name: 'frames',\n summary:\n 'PNG stills at output times / zoom apexes (each checked against its zoom-off twin) / moments / exact sizes',\n },\n {\n name: 'check-video',\n summary:\n 'check a rendered file: facts, scene changes, loudness, first and last frames',\n },\n {\n name: 'deliver',\n summary:\n 'render a take to release video destinations (YouTube, X, Shorts/LinkedIn, GitHub) + verified kit.json',\n },\n {\n name: 'digest',\n summary:\n 'see a recording before cutting it: moments (clicks, typing, scrolls, idle, scenes) + footage frames + crops, in doc units',\n },\n { name: 'open', summary: 'serve the take into the vos.so studio' },\n {\n name: 'validate',\n summary:\n 'lint actions.json, a take dir (doc.json semantics), or re-measure a kit.json against the channel specs',\n },\n {\n name: 'actions',\n summary:\n 'from-agent-browser: turn an agent-browser walk (steps.jsonl) into actions.json; what cannot follow is named',\n },\n {\n name: 'ingest',\n summary:\n 'a take from a recording someone else made, with its cursor track from a trace beside it (Playwright trace.zip, stamped records, CSV); without one nothing is planned',\n },\n {\n name: 'join',\n summary:\n 'several takes and video files as one take: each next input a media, its spans tagged, its layers moved to where it starts; --captions anchors every step caption',\n },\n {\n name: 'score',\n summary:\n \"a music track as the film's score, its strongest swell landed on a step or a second (--dry-run prints the loudness envelope and the plan)\",\n },\n {\n name: 'audio',\n summary:\n 'measure: every audio clip’s loudness (integrated LUFS, sample peak) written beside it, which a clip’s normalize target plays it to',\n },\n {\n name: 'music',\n summary:\n 'ls: the library one line per track (tempo, vocals, loops, the sentence); pick: the beds that fit this film, best first, with reasons and the vos score line that places each',\n },\n {\n name: 'port',\n summary:\n 'bring a page, a HyperFrames or a Remotion piece: inventory (its words, colours, faces, media, scenes) then scaffold (a data-first program.mjs to translate the motion into)',\n },\n {\n name: 'build',\n summary:\n 'program.mjs (real functions) → config.json, refusing what cannot run on its own (module-scope reads, syntax the page cannot parse, non-JSON data)',\n },\n {\n name: 'compare',\n summary:\n \"a program against the source's own render: per-frame SSIM and source | vos | difference sheets; exits 1 when any frame is under the threshold\",\n },\n {\n name: 'brand',\n summary:\n \"write a product's BRAND.md, witnessed: /design.md, /llms.txt, then the page (palette, faces, marks, the avoid list)\",\n },\n {\n name: 'fetch',\n summary: 'download a hosted program: config.json + vos.json tracking',\n },\n {\n name: 'push',\n summary: 'push a config.json or take to vos.so (private; versioned)',\n },\n {\n name: 'duplicate',\n summary:\n 'a private sibling of your OWN vos (someone else\\u2019s is remixed: fetch + push --remix-of)',\n },\n {\n name: 'pull',\n summary:\n 'sync what changed on vos.so since your base (--media brings a take’s footage home)',\n },\n {\n name: 'folder',\n summary:\n 'list/create/pull folders, move voses and assets into them (pull = the context package on disk)',\n },\n {\n name: 'asset',\n summary:\n 'your files: push or import one, list them (assets ls), see storage (assets usage) and what uses a file (assets why)',\n },\n {\n name: 'recipe',\n summary:\n 'push a recipe .md into a folder, or replace one in place (prior body kept)',\n },\n {\n name: 'login',\n summary: 'sign in via the browser (or --key); stores a content key',\n },\n {\n name: 'setup',\n summary:\n 'ready this machine: the vos skills into your agent, a browser, one rules block, then doctor',\n },\n {\n name: 'doctor',\n summary:\n 'what is ready, in words: node, browser, ffmpeg, skills, a credential (never printed), the dev server',\n },\n {\n name: 'whoami',\n summary
|
|
1
|
+
{"version":3,"sources":["../src/plugin/manifest.ts"],"sourcesContent":["/**\n * The verb manifest of the take pipeline and the vos.so verbs — what\n * `vos help` lists under the engine verbs. It kept the shape a separately\n * installed plugin once handed the host (name + host range), so a script\n * reading it keeps working.\n */\nexport interface PluginVerb {\n name: string\n summary: string\n}\n\nexport interface PluginManifest {\n name: string\n /** Host versions this plugin speaks the run(argv) contract with. */\n hostRange: string\n verbs: PluginVerb[]\n}\n\nexport const manifest: PluginManifest = {\n name: '@vosjs/cli',\n hostRange: '>=0.9.0',\n verbs: [\n {\n name: 'create',\n summary: 'record + auto-plan + render, one command (--strict)',\n },\n {\n name: 'record',\n summary: 'drive actions.json into a take (screencast + cursor track)',\n },\n {\n name: 'look',\n summary:\n 'see a page before scripting it (signed in, like record): a screenshot + every control in view with one proposed stable selector',\n },\n {\n name: 'plan',\n summary:\n 'plan zoom/cursor effects into doc.json (wand contract); --reuse re-times a previous cut onto a re-recording',\n },\n {\n name: 'render',\n summary: 'render a take directory (engine configs render in the host)',\n },\n {\n name: 'frames',\n summary:\n 'PNG stills at output times / zoom apexes (each checked against its zoom-off twin) / moments / exact sizes',\n },\n {\n name: 'check-video',\n summary:\n 'check a rendered file: facts, scene changes, loudness, first and last frames',\n },\n {\n name: 'deliver',\n summary:\n 'render a take to release video destinations (YouTube, X, Shorts/LinkedIn, GitHub) + verified kit.json',\n },\n {\n name: 'digest',\n summary:\n 'see a recording before cutting it: moments (clicks, typing, scrolls, idle, scenes) + footage frames + crops, in doc units',\n },\n { name: 'open', summary: 'serve the take into the vos.so studio' },\n {\n name: 'validate',\n summary:\n 'lint actions.json, a take dir (doc.json semantics), or re-measure a kit.json against the channel specs',\n },\n {\n name: 'actions',\n summary:\n 'from-agent-browser: turn an agent-browser walk (steps.jsonl) into actions.json; what cannot follow is named',\n },\n {\n name: 'ingest',\n summary:\n 'a take from a recording someone else made, with its cursor track from a trace beside it (Playwright trace.zip, stamped records, CSV); without one nothing is planned',\n },\n {\n name: 'join',\n summary:\n 'several takes and video files as one take: each next input a media, its spans tagged, its layers moved to where it starts; --captions anchors every step caption',\n },\n {\n name: 'score',\n summary:\n \"a music track as the film's score, its strongest swell landed on a step or a second (--dry-run prints the loudness envelope and the plan)\",\n },\n {\n name: 'audio',\n summary:\n 'measure: every audio clip’s loudness (integrated LUFS, sample peak) written beside it, which a clip’s normalize target plays it to',\n },\n {\n name: 'music',\n summary:\n 'ls: the library one line per track (tempo, vocals, loops, the sentence); pick: the beds that fit this film, best first, with reasons and the vos score line that places each',\n },\n {\n name: 'port',\n summary:\n 'bring a page, a HyperFrames or a Remotion piece: inventory (its words, colours, faces, media, scenes) then scaffold (a data-first program.mjs to translate the motion into)',\n },\n {\n name: 'build',\n summary:\n 'program.mjs (real functions) → config.json, refusing what cannot run on its own (module-scope reads, syntax the page cannot parse, non-JSON data)',\n },\n {\n name: 'compare',\n summary:\n \"a program against the source's own render: per-frame SSIM and source | vos | difference sheets; exits 1 when any frame is under the threshold\",\n },\n {\n name: 'brand',\n summary:\n \"write a product's BRAND.md, witnessed: /design.md, /llms.txt, then the page (palette, faces, marks, the avoid list)\",\n },\n {\n name: 'fetch',\n summary: 'download a hosted program: config.json + vos.json tracking',\n },\n {\n name: 'push',\n summary: 'push a config.json or take to vos.so (private; versioned)',\n },\n {\n name: 'duplicate',\n summary:\n 'a private sibling of your OWN vos (someone else\\u2019s is remixed: fetch + push --remix-of)',\n },\n {\n name: 'pull',\n summary:\n 'sync what changed on vos.so since your base (--media brings a take’s footage home)',\n },\n {\n name: 'folder',\n summary:\n 'list/create/pull folders, move voses and assets into them (pull = the context package on disk)',\n },\n {\n name: 'asset',\n summary:\n 'your files: push or import one, list them (assets ls), see storage (assets usage) and what uses a file (assets why)',\n },\n {\n name: 'recipe',\n summary:\n 'push a recipe .md into a folder, or replace one in place (prior body kept)',\n },\n {\n name: 'login',\n summary: 'sign in via the browser (or --key); stores a content key',\n },\n {\n name: 'setup',\n summary:\n 'ready this machine: the vos skills into your agent, a browser, one rules block, then doctor',\n },\n {\n name: 'doctor',\n summary:\n 'what is ready, in words: node, browser, ffmpeg, skills, a credential (never printed), the dev server',\n },\n {\n name: 'whoami',\n summary:\n 'the account in use and every other one stored for the origin, never a key',\n },\n {\n name: 'switch',\n summary:\n 'use another stored account (vos login once per account stores them all)',\n },\n {\n name: 'logout',\n summary:\n 'forget the account in use, a named one (vos logout <handle>), or all (--all)',\n },\n ],\n}\n"],"mappings":";;;AAkBO,IAAM,WAA2B;AAAA,EACtC,MAAM;AAAA,EACN,WAAW;AAAA,EACX,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA,EAAE,MAAM,QAAQ,SAAS,wCAAwC;AAAA,IACjE;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,EACF;AACF;","names":[]}
|
|
@@ -341,9 +341,8 @@ function hasFlag(flags, name) {
|
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
// src/plugin/platform.ts
|
|
344
|
-
import {
|
|
345
|
-
import {
|
|
346
|
-
import { dirname as dirname2, join } from "path";
|
|
344
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
345
|
+
import { join as join2 } from "path";
|
|
347
346
|
|
|
348
347
|
// src/plugin/hostAgent.ts
|
|
349
348
|
import { existsSync } from "fs";
|
|
@@ -389,6 +388,204 @@ function detectHostAgent(env = process.env, exists = existsSync) {
|
|
|
389
388
|
return null;
|
|
390
389
|
}
|
|
391
390
|
|
|
391
|
+
// src/plugin/accounts.ts
|
|
392
|
+
import {
|
|
393
|
+
existsSync as existsSync2,
|
|
394
|
+
mkdirSync as mkdirSync2,
|
|
395
|
+
readFileSync,
|
|
396
|
+
readdirSync,
|
|
397
|
+
rmSync,
|
|
398
|
+
writeFileSync as writeFileSync2
|
|
399
|
+
} from "fs";
|
|
400
|
+
import { homedir } from "os";
|
|
401
|
+
import { dirname as dirname2, join } from "path";
|
|
402
|
+
var CREDENTIALS_PATH = join(homedir(), ".config", "vos", "credentials");
|
|
403
|
+
var ACCOUNTS_DIR = join(homedir(), ".config", "vos", "accounts");
|
|
404
|
+
var DEFAULT_ORIGIN = "https://vos.so";
|
|
405
|
+
var ACCOUNT_ENV = "VOS_ACCOUNT";
|
|
406
|
+
var DEFAULT_STORE = {
|
|
407
|
+
credentialsPath: CREDENTIALS_PATH,
|
|
408
|
+
accountsDir: ACCOUNTS_DIR
|
|
409
|
+
};
|
|
410
|
+
function originOf(url) {
|
|
411
|
+
try {
|
|
412
|
+
return new URL(url).origin;
|
|
413
|
+
} catch {
|
|
414
|
+
return url.replace(/\/+$/, "");
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
function accountFrom(value) {
|
|
418
|
+
if (!value || typeof value !== "object") return null;
|
|
419
|
+
const u = value;
|
|
420
|
+
if (typeof u.id !== "string" || !u.id) return null;
|
|
421
|
+
return {
|
|
422
|
+
id: u.id,
|
|
423
|
+
kind: u.kind === "org" ? "org" : "person",
|
|
424
|
+
handle: typeof u.username === "string" && u.username ? u.username : null
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
function formatCredential(c) {
|
|
428
|
+
const account = c.account ? `account=${c.account.id} ${c.account.kind}${c.account.handle ? ` ${c.account.handle}` : ""}
|
|
429
|
+
` : "";
|
|
430
|
+
return `${c.key.trim()}
|
|
431
|
+
origin=${originOf(c.origin)}
|
|
432
|
+
${account}`;
|
|
433
|
+
}
|
|
434
|
+
function parseCredential(text) {
|
|
435
|
+
const [first, ...rest] = text.split("\n");
|
|
436
|
+
const key = first.trim();
|
|
437
|
+
if (!key) return null;
|
|
438
|
+
let origin = "";
|
|
439
|
+
let account = null;
|
|
440
|
+
for (const raw of rest) {
|
|
441
|
+
const line = raw.trim();
|
|
442
|
+
if (line.startsWith("origin=")) origin = originOf(line.slice(7).trim());
|
|
443
|
+
else if (line.startsWith("account=")) {
|
|
444
|
+
const [id, kind, handle] = line.slice(8).trim().split(/\s+/);
|
|
445
|
+
if (id)
|
|
446
|
+
account = {
|
|
447
|
+
id,
|
|
448
|
+
kind: kind === "org" ? "org" : "person",
|
|
449
|
+
handle: handle || null
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return { key, origin: origin || DEFAULT_ORIGIN, account };
|
|
454
|
+
}
|
|
455
|
+
function readFile(path) {
|
|
456
|
+
try {
|
|
457
|
+
return parseCredential(readFileSync(path, "utf8"));
|
|
458
|
+
} catch {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function writeFile2(path, c) {
|
|
463
|
+
mkdirSync2(dirname2(path), { recursive: true, mode: 448 });
|
|
464
|
+
writeFileSync2(path, formatCredential(c), { mode: 384 });
|
|
465
|
+
}
|
|
466
|
+
function hostDir(origin) {
|
|
467
|
+
let host;
|
|
468
|
+
try {
|
|
469
|
+
host = new URL(origin).host;
|
|
470
|
+
} catch {
|
|
471
|
+
host = origin.replace(/^https?:\/\//, "").replace(/\/.*$/, "");
|
|
472
|
+
}
|
|
473
|
+
return host.replace(/[^A-Za-z0-9.-]/g, "_") || "unknown";
|
|
474
|
+
}
|
|
475
|
+
function accountPath(store, origin, accountId) {
|
|
476
|
+
return join(store.accountsDir, hostDir(origin), accountId);
|
|
477
|
+
}
|
|
478
|
+
function readActive(store = DEFAULT_STORE) {
|
|
479
|
+
return readFile(store.credentialsPath);
|
|
480
|
+
}
|
|
481
|
+
function listStored(store = DEFAULT_STORE, origin) {
|
|
482
|
+
const active = readActive(store);
|
|
483
|
+
const want = origin ? originOf(origin) : null;
|
|
484
|
+
const out = [];
|
|
485
|
+
const seen = /* @__PURE__ */ new Set();
|
|
486
|
+
const push = (c) => {
|
|
487
|
+
if (!c || want && c.origin !== want || seen.has(c.key)) return;
|
|
488
|
+
seen.add(c.key);
|
|
489
|
+
out.push(c);
|
|
490
|
+
};
|
|
491
|
+
push(active);
|
|
492
|
+
let hosts = [];
|
|
493
|
+
try {
|
|
494
|
+
hosts = readdirSync(store.accountsDir);
|
|
495
|
+
} catch {
|
|
496
|
+
return out;
|
|
497
|
+
}
|
|
498
|
+
for (const host of hosts.sort()) {
|
|
499
|
+
let files = [];
|
|
500
|
+
try {
|
|
501
|
+
files = readdirSync(join(store.accountsDir, host));
|
|
502
|
+
} catch {
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
for (const file of files.sort()) {
|
|
506
|
+
push(readFile(join(store.accountsDir, host, file)));
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return out;
|
|
510
|
+
}
|
|
511
|
+
function isActive(c, store = DEFAULT_STORE) {
|
|
512
|
+
return readActive(store)?.key === c.key;
|
|
513
|
+
}
|
|
514
|
+
function accountLabel(a) {
|
|
515
|
+
if (!a) return "an unnamed account";
|
|
516
|
+
return a.handle ? `@${a.handle}` : a.id;
|
|
517
|
+
}
|
|
518
|
+
function matchesAccount(a, ref) {
|
|
519
|
+
if (!a) return false;
|
|
520
|
+
const want = ref.trim().replace(/^@/, "");
|
|
521
|
+
if (!want) return false;
|
|
522
|
+
if (a.id === want) return true;
|
|
523
|
+
return !!a.handle && a.handle.toLowerCase() === want.toLowerCase();
|
|
524
|
+
}
|
|
525
|
+
function findStored(store, origin, ref) {
|
|
526
|
+
return listStored(store, origin).find((c) => matchesAccount(c.account, ref)) ?? null;
|
|
527
|
+
}
|
|
528
|
+
function activate(store, c) {
|
|
529
|
+
writeFile2(store.credentialsPath, c);
|
|
530
|
+
return store.credentialsPath;
|
|
531
|
+
}
|
|
532
|
+
function storeCredential(store, c) {
|
|
533
|
+
const previous = readActive(store);
|
|
534
|
+
let setAside = null;
|
|
535
|
+
if (previous && previous.key !== c.key) {
|
|
536
|
+
if (previous.account) {
|
|
537
|
+
writeFile2(
|
|
538
|
+
accountPath(store, previous.origin, previous.account.id),
|
|
539
|
+
previous
|
|
540
|
+
);
|
|
541
|
+
setAside = previous;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (c.account) writeFile2(accountPath(store, c.origin, c.account.id), c);
|
|
545
|
+
return { path: activate(store, c), setAside };
|
|
546
|
+
}
|
|
547
|
+
function removeStored(store, c) {
|
|
548
|
+
const wasActive = isActive(c, store);
|
|
549
|
+
if (c.account) {
|
|
550
|
+
rmSync(accountPath(store, c.origin, c.account.id), { force: true });
|
|
551
|
+
}
|
|
552
|
+
if (wasActive) rmSync(store.credentialsPath, { force: true });
|
|
553
|
+
return { wasActive };
|
|
554
|
+
}
|
|
555
|
+
function removeAll(store) {
|
|
556
|
+
const had = existsSync2(store.credentialsPath) || existsSync2(store.accountsDir);
|
|
557
|
+
rmSync(store.credentialsPath, { force: true });
|
|
558
|
+
rmSync(store.accountsDir, { recursive: true, force: true });
|
|
559
|
+
return { had };
|
|
560
|
+
}
|
|
561
|
+
function switchTarget(stored, activeKey, ref, origin) {
|
|
562
|
+
if (ref) {
|
|
563
|
+
const to = stored.find((c) => matchesAccount(c.account, ref));
|
|
564
|
+
if (!to)
|
|
565
|
+
return {
|
|
566
|
+
ok: false,
|
|
567
|
+
error: `no credential stored for ${ref.startsWith("@") ? ref : `@${ref.replace(/^@/, "")}`} on ${origin}; run vos login and approve as it${stored.length ? `, or vos switch ${stored.map((c) => accountLabel(c.account)).join(" | ")}` : ""}`
|
|
568
|
+
};
|
|
569
|
+
return { ok: true, to };
|
|
570
|
+
}
|
|
571
|
+
const others = stored.filter((c) => c.key !== activeKey);
|
|
572
|
+
if (stored.length === 0)
|
|
573
|
+
return {
|
|
574
|
+
ok: false,
|
|
575
|
+
error: `nothing is stored for ${origin}; run vos login`
|
|
576
|
+
};
|
|
577
|
+
if (stored.length === 1)
|
|
578
|
+
return {
|
|
579
|
+
ok: false,
|
|
580
|
+
error: `only ${accountLabel(stored[0].account)} is stored for ${origin}; run vos login and approve as another account to add one`
|
|
581
|
+
};
|
|
582
|
+
if (others.length === 1) return { ok: true, to: others[0] };
|
|
583
|
+
return {
|
|
584
|
+
ok: false,
|
|
585
|
+
error: `say which: vos switch ${stored.map((c) => accountLabel(c.account)).join(" | ")}`
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
|
|
392
589
|
// src/plugin/platform.ts
|
|
393
590
|
function platformOrigin(flags = {}) {
|
|
394
591
|
const legacyEnv = process.env.VOS_API_BASE?.trim();
|
|
@@ -422,40 +619,63 @@ function parseVosId(input) {
|
|
|
422
619
|
function deriveSlug(title) {
|
|
423
620
|
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 50).replace(/-+$/, "") || "remix";
|
|
424
621
|
}
|
|
425
|
-
var CREDENTIALS_PATH = join(homedir(), ".config", "vos", "credentials");
|
|
426
|
-
var DEFAULT_ORIGIN = "https://vos.so";
|
|
427
|
-
function originOf(url) {
|
|
428
|
-
try {
|
|
429
|
-
return new URL(url).origin;
|
|
430
|
-
} catch {
|
|
431
|
-
return url.replace(/\/+$/, "");
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
function readStoredCredential(path = CREDENTIALS_PATH) {
|
|
435
|
-
let text;
|
|
436
|
-
try {
|
|
437
|
-
text = readFileSync(path, "utf8");
|
|
438
|
-
} catch {
|
|
439
|
-
return null;
|
|
440
|
-
}
|
|
441
|
-
const [first, ...rest] = text.split("\n");
|
|
442
|
-
const key = first.trim();
|
|
443
|
-
if (!key) return null;
|
|
444
|
-
const line = rest.map((l) => l.trim()).find((l) => l.startsWith("origin="));
|
|
445
|
-
const origin = line ? originOf(line.slice("origin=".length).trim()) : "";
|
|
446
|
-
return { key, origin: origin || DEFAULT_ORIGIN };
|
|
447
|
-
}
|
|
448
622
|
var storedFor = /* @__PURE__ */ new Map();
|
|
449
623
|
var warned = /* @__PURE__ */ new Set();
|
|
624
|
+
var lastResolved = null;
|
|
625
|
+
function lastCredential() {
|
|
626
|
+
return lastResolved;
|
|
627
|
+
}
|
|
628
|
+
function credentialFlags(flags) {
|
|
629
|
+
const str = (name) => typeof flags[name] === "string" ? flags[name] : void 0;
|
|
630
|
+
return {
|
|
631
|
+
key: str("key"),
|
|
632
|
+
account: str("account"),
|
|
633
|
+
origin: platformOrigin({ origin: str("origin"), api: str("api") })
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function fromStore(c, via) {
|
|
637
|
+
if (!c) return null;
|
|
638
|
+
storedFor.set(c.key, c.origin);
|
|
639
|
+
lastResolved = { key: c.key, via, account: c.account, origin: c.origin };
|
|
640
|
+
return c.key;
|
|
641
|
+
}
|
|
450
642
|
function resolveCredential(explicit, path = CREDENTIALS_PATH) {
|
|
451
|
-
const
|
|
452
|
-
|
|
643
|
+
const ask = typeof explicit === "string" || explicit === void 0 ? { key: explicit } : explicit;
|
|
644
|
+
const store = ask.store ?? {
|
|
645
|
+
...DEFAULT_STORE,
|
|
646
|
+
...path !== CREDENTIALS_PATH ? { credentialsPath: path } : {}
|
|
647
|
+
};
|
|
648
|
+
const origin = ask.origin ?? platformOrigin();
|
|
649
|
+
const flag = ask.key?.trim();
|
|
650
|
+
if (flag) {
|
|
651
|
+
lastResolved = { key: flag, via: "flag", account: null, origin: null };
|
|
652
|
+
return flag;
|
|
653
|
+
}
|
|
654
|
+
const named = ask.account?.trim();
|
|
655
|
+
if (named) {
|
|
656
|
+
const found = findStored(store, origin, named);
|
|
657
|
+
if (!found)
|
|
658
|
+
throw new Error(noSuchAccount(store, origin, named, "--account"));
|
|
659
|
+
return fromStore(found, "account-flag");
|
|
660
|
+
}
|
|
453
661
|
const env = process.env.VOS_API_KEY?.trim();
|
|
454
|
-
if (env)
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
662
|
+
if (env) {
|
|
663
|
+
lastResolved = { key: env, via: "env", account: null, origin: null };
|
|
664
|
+
return env;
|
|
665
|
+
}
|
|
666
|
+
const envName = process.env[ACCOUNT_ENV]?.trim();
|
|
667
|
+
if (envName) {
|
|
668
|
+
const found = findStored(store, origin, envName);
|
|
669
|
+
if (!found)
|
|
670
|
+
throw new Error(noSuchAccount(store, origin, envName, ACCOUNT_ENV));
|
|
671
|
+
return fromStore(found, "account-env");
|
|
672
|
+
}
|
|
673
|
+
return fromStore(readActive(store), "stored");
|
|
674
|
+
}
|
|
675
|
+
function noSuchAccount(store, origin, ref, how) {
|
|
676
|
+
const have = listStored(store, origin).map((c) => accountLabel(c.account));
|
|
677
|
+
const name = ref.startsWith("@") ? ref : `@${ref}`;
|
|
678
|
+
return `${how} names ${name}, and no credential for it is stored for ${origin}: run vos login and approve as ${name}` + (have.length ? ` (stored: ${have.join(", ")})` : "");
|
|
459
679
|
}
|
|
460
680
|
function bearerFor(key, url) {
|
|
461
681
|
if (!key) return {};
|
|
@@ -477,20 +697,25 @@ var mintAt = (origin = DEFAULT_ORIGIN) => `${originOf(origin)}/app/api`;
|
|
|
477
697
|
function requireCredential(explicit, origin) {
|
|
478
698
|
const key = resolveCredential(explicit);
|
|
479
699
|
if (!key) {
|
|
700
|
+
const at = origin ?? (typeof explicit === "object" ? explicit.origin : void 0) ?? platformOrigin();
|
|
480
701
|
throw new Error(
|
|
481
|
-
`no credential found \u2014 pass --key, set VOS_API_KEY, or run \`vos login\` (mint a content key at ${mintAt(
|
|
702
|
+
`no credential found \u2014 pass --key, set VOS_API_KEY, or run \`vos login\` (mint a content key at ${mintAt(at)}; a vos_rg_ remix grant works too)`
|
|
482
703
|
);
|
|
483
704
|
}
|
|
484
705
|
return key;
|
|
485
706
|
}
|
|
486
|
-
function writeCredential(key, origin = DEFAULT_ORIGIN, path = CREDENTIALS_PATH) {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
707
|
+
function writeCredential(key, origin = DEFAULT_ORIGIN, path = CREDENTIALS_PATH, account = null) {
|
|
708
|
+
return storeLogin(key, origin, account, {
|
|
709
|
+
...DEFAULT_STORE,
|
|
710
|
+
...path !== CREDENTIALS_PATH ? { credentialsPath: path } : {}
|
|
711
|
+
}).path;
|
|
712
|
+
}
|
|
713
|
+
function storeLogin(key, origin, account, store = DEFAULT_STORE) {
|
|
714
|
+
return storeCredential(store, {
|
|
715
|
+
key: key.trim(),
|
|
716
|
+
origin: originOf(origin),
|
|
717
|
+
account
|
|
492
718
|
});
|
|
493
|
-
return path;
|
|
494
719
|
}
|
|
495
720
|
function clientId(env = process.env, exists) {
|
|
496
721
|
const explicit = env.VOS_CLIENT?.trim();
|
|
@@ -560,13 +785,13 @@ function hostedMediaOf(value) {
|
|
|
560
785
|
}
|
|
561
786
|
function readJsonFile(file) {
|
|
562
787
|
try {
|
|
563
|
-
return JSON.parse(
|
|
788
|
+
return JSON.parse(readFileSync2(file, "utf8"));
|
|
564
789
|
} catch {
|
|
565
790
|
return null;
|
|
566
791
|
}
|
|
567
792
|
}
|
|
568
793
|
function readSyncState(dir) {
|
|
569
|
-
const own = readJsonFile(
|
|
794
|
+
const own = readJsonFile(join2(dir, SYNC_STATE_NAME));
|
|
570
795
|
if (own && typeof own.vosId === "string") {
|
|
571
796
|
return {
|
|
572
797
|
vosId: own.vosId,
|
|
@@ -578,7 +803,7 @@ function readSyncState(dir) {
|
|
|
578
803
|
...hostedMediaOf(own.hostedMedia) ? { hostedMedia: hostedMediaOf(own.hostedMedia) } : {}
|
|
579
804
|
};
|
|
580
805
|
}
|
|
581
|
-
const push = readJsonFile(
|
|
806
|
+
const push = readJsonFile(join2(dir, "push.json"));
|
|
582
807
|
if (push && typeof push.vosId === "string") {
|
|
583
808
|
return {
|
|
584
809
|
vosId: push.vosId,
|
|
@@ -586,7 +811,7 @@ function readSyncState(dir) {
|
|
|
586
811
|
...typeof push.pushedAt === "string" ? { pushedAt: push.pushedAt } : {}
|
|
587
812
|
};
|
|
588
813
|
}
|
|
589
|
-
const meta = readJsonFile(
|
|
814
|
+
const meta = readJsonFile(join2(dir, "meta.json"));
|
|
590
815
|
if (meta && typeof meta.id === "string") {
|
|
591
816
|
return {
|
|
592
817
|
vosId: meta.id,
|
|
@@ -604,7 +829,7 @@ function writeSyncState(dir, patch) {
|
|
|
604
829
|
...patch
|
|
605
830
|
};
|
|
606
831
|
writeFileSafeSync(
|
|
607
|
-
|
|
832
|
+
join2(dir, SYNC_STATE_NAME),
|
|
608
833
|
`${JSON.stringify(merged, null, 2)}
|
|
609
834
|
`
|
|
610
835
|
);
|
|
@@ -631,19 +856,19 @@ function serverWarnings(body, log) {
|
|
|
631
856
|
import { createHash } from "crypto";
|
|
632
857
|
import {
|
|
633
858
|
closeSync,
|
|
634
|
-
existsSync as
|
|
859
|
+
existsSync as existsSync3,
|
|
635
860
|
mkdirSync as mkdirSync3,
|
|
636
861
|
openSync,
|
|
637
862
|
readSync,
|
|
638
|
-
readdirSync,
|
|
863
|
+
readdirSync as readdirSync2,
|
|
639
864
|
realpathSync,
|
|
640
865
|
renameSync,
|
|
641
|
-
rmSync,
|
|
866
|
+
rmSync as rmSync2,
|
|
642
867
|
statSync,
|
|
643
868
|
writeFileSync as writeFileSync3
|
|
644
869
|
} from "fs";
|
|
645
870
|
import { homedir as homedir2 } from "os";
|
|
646
|
-
import { extname, join as
|
|
871
|
+
import { extname, join as join3, resolve, sep } from "path";
|
|
647
872
|
var ASSET_ROUTE = "/__assets/";
|
|
648
873
|
var UUID = "[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}";
|
|
649
874
|
var HOSTED_URI = new RegExp(`^asset:(${UUID})$`);
|
|
@@ -729,7 +954,7 @@ function localFile(ref, baseDir) {
|
|
|
729
954
|
};
|
|
730
955
|
}
|
|
731
956
|
const file = resolve(baseDir, ref);
|
|
732
|
-
if (!
|
|
957
|
+
if (!existsSync3(file) || !statSync(file).isFile()) {
|
|
733
958
|
return { refused: "which is not a file beside the config" };
|
|
734
959
|
}
|
|
735
960
|
const root = realpathSync(baseDir);
|
|
@@ -765,11 +990,11 @@ function manifestRefs(config) {
|
|
|
765
990
|
return out;
|
|
766
991
|
}
|
|
767
992
|
async function fetchHosted(id, opts) {
|
|
768
|
-
const dir = opts.cacheDir ??
|
|
769
|
-
const cached =
|
|
993
|
+
const dir = opts.cacheDir ?? join3(homedir2(), ".cache", "vos", "assets");
|
|
994
|
+
const cached = existsSync3(dir) ? readdirSync2(dir).find(
|
|
770
995
|
(f) => (f === id || f.startsWith(`${id}.`)) && !f.endsWith(".part")
|
|
771
996
|
) : void 0;
|
|
772
|
-
if (cached) return
|
|
997
|
+
if (cached) return join3(dir, cached);
|
|
773
998
|
if (!opts.origin || !opts.key) {
|
|
774
999
|
opts.log(
|
|
775
1000
|
`note: asset ${id} is hosted and no credential is set, so the render cannot load it (vos login, or keep the file beside the config and name its path)`
|
|
@@ -787,7 +1012,7 @@ async function fetchHosted(id, opts) {
|
|
|
787
1012
|
}
|
|
788
1013
|
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
789
1014
|
const type = (res.headers.get("content-type") ?? "").split(";")[0].trim();
|
|
790
|
-
const file =
|
|
1015
|
+
const file = join3(dir, `${id}${extensionFor(type)}`);
|
|
791
1016
|
const partial = `${file}.part`;
|
|
792
1017
|
try {
|
|
793
1018
|
writeFileSync3(partial, new Uint8Array(await res.arrayBuffer()), {
|
|
@@ -795,7 +1020,7 @@ async function fetchHosted(id, opts) {
|
|
|
795
1020
|
});
|
|
796
1021
|
renameSync(partial, file);
|
|
797
1022
|
} finally {
|
|
798
|
-
|
|
1023
|
+
rmSync2(partial, { force: true });
|
|
799
1024
|
}
|
|
800
1025
|
return file;
|
|
801
1026
|
}
|
|
@@ -920,10 +1145,25 @@ export {
|
|
|
920
1145
|
numFlag2,
|
|
921
1146
|
strFlag,
|
|
922
1147
|
hasFlag,
|
|
1148
|
+
CREDENTIALS_PATH,
|
|
1149
|
+
ACCOUNT_ENV,
|
|
1150
|
+
DEFAULT_STORE,
|
|
1151
|
+
originOf,
|
|
1152
|
+
accountFrom,
|
|
1153
|
+
readActive,
|
|
1154
|
+
listStored,
|
|
1155
|
+
isActive,
|
|
1156
|
+
accountLabel,
|
|
1157
|
+
findStored,
|
|
1158
|
+
activate,
|
|
1159
|
+
removeStored,
|
|
1160
|
+
removeAll,
|
|
1161
|
+
switchTarget,
|
|
923
1162
|
platformOrigin,
|
|
924
1163
|
parseVosId,
|
|
925
1164
|
deriveSlug,
|
|
926
|
-
|
|
1165
|
+
lastCredential,
|
|
1166
|
+
credentialFlags,
|
|
927
1167
|
resolveCredential,
|
|
928
1168
|
bearerFor,
|
|
929
1169
|
mintAt,
|
|
@@ -947,4 +1187,4 @@ export {
|
|
|
947
1187
|
programAssets,
|
|
948
1188
|
missingManifestFiles
|
|
949
1189
|
};
|
|
950
|
-
//# sourceMappingURL=chunk-
|
|
1190
|
+
//# sourceMappingURL=chunk-PZP76YJI.js.map
|