vlt
Version:
The vlt CLI
308 lines (306 loc) • 8.73 kB
JavaScript
var global = globalThis;
import {Buffer} from "node:buffer";
import {setTimeout,clearTimeout,setImmediate,clearImmediate,setInterval,clearInterval} from "node:timers";
import {createRequire as _vlt_createRequire} from "node:module";
var require = _vlt_createRequire(import.meta.filename);
import {
prettyBytes
} from "./chunk-QGJUWLFF.js";
import {
stderr,
stdout
} from "./chunk-KNHO4BUR.js";
import "./chunk-BQNTW6JU.js";
import {
ViewClass
} from "./chunk-YESBS37V.js";
import "./chunk-J25GTXK2.js";
import "./chunk-3VS4XBYN.js";
import {
CacheEntry
} from "./chunk-OTLTOVZN.js";
import {
commandUsage
} from "./chunk-L3E552CT.js";
import {
Spec2 as Spec
} from "./chunk-U5J4TCIV.js";
import "./chunk-KPA4XNCN.js";
import "./chunk-VYJVN3B6.js";
import "./chunk-B4MAUXR2.js";
import "./chunk-W7RMFRDJ.js";
import "./chunk-O57KIW5U.js";
import "./chunk-JBBINXAZ.js";
import "./chunk-OAYCZMD4.js";
import "./chunk-BA67AKYJ.js";
import {
error
} from "./chunk-KVH5ECIG.js";
import "./chunk-AECDW3EJ.js";
// ../../src/cli-sdk/src/commands/cache.ts
import { mkdir, rm } from "node:fs/promises";
var view;
var CacheView = class extends ViewClass {
constructor(options, conf) {
super(options, conf);
view = this;
}
stdout(...args) {
stdout(...args);
}
};
var views = {
human: CacheView
};
var usageDef = {
command: "cache",
usage: "<command> [flags]",
description: "Work with vlt cache folders",
subcommands: {
add: {
usage: "<package-spec> [<package-spec>...]",
description: `Resolve the referenced package identifiers and ensure they
are cached.`
},
ls: {
usage: "[<key>...]",
description: `Show cache entries. If no keys are provided, then a list of
available keys will be printed. If one or more keys are
provided, then details will be shown for the specified
items.`
},
info: {
usage: "<key>",
description: `Print metadata details for the specified cache key to
stderr, and the response body to stdout.`
},
clean: {
usage: "[<key>...]",
description: `Purge expired cache entries. If one or more keys are
provided, then only those cache entries will be
considered.`
},
delete: {
usage: "<key> [<key>...]",
description: `Purge items explicitly, whether expired or not. If one or
more keys are provided, then only those cache entries will
be considered.`
},
"delete-before": {
usage: "<date>",
description: `Purge all cache items from before a given date. Date can be
provided in any format that JavaScript can parse.`
},
"delete-all": {
usage: "",
description: `Delete the entire cache folder to make vlt slower.`
}
},
examples: {
"vlt cache ls https://registry.npmjs.org/typescript": {
description: `Show cache metadata for a given registry URL`
},
"vlt cache add eslint@latest": {
description: `Add a given package specifier to the cache by fetching
its resolved value.`
},
"vlt cache info https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz > eslint.tgz": {
description: `Print the cache metadata to stderr, and write the tarball
on stdout, redirecting to a file.`
},
"vlt cache delete-before 2025-01-01": {
description: "Delete all entries created before Jan 1, 2025"
}
}
};
var usage = () => commandUsage(usageDef);
var command = async (conf) => {
const [sub, ...args] = conf.positionals;
switch (sub) {
case "ls":
return ls(conf, args, view);
case "info":
return info(conf, args, view);
case "add":
return add(conf, args, view);
case "clean":
return clean(conf, args, view);
case "delete":
return deleteKeys(conf, args, view);
case "delete-before":
return deleteBefore(conf, args, view);
case "delete-all":
return deleteAll(conf, args, view);
default: {
throw error("Unrecognized cache command", {
code: "EUSAGE",
found: sub,
validOptions: Object.keys(usageDef.subcommands)
});
}
}
};
var ls = async (conf, keys, view2) => keys.length ? await fetchKeys(
conf,
keys,
(entry, key) => {
view2?.stdout(
key.includes(" ") ? JSON.stringify(key) : key,
entry
);
return true;
},
view2
) : await fetchAll(conf, (_, key) => {
view2?.stdout(key.includes(" ") ? JSON.stringify(key) : key);
return true;
});
var info = async (conf, keys, view2) => {
const [key] = keys;
if (keys.length !== 1 || !key) {
throw error("Must provide exactly one cache key", {
code: "EUSAGE"
});
}
await fetchKeys(
conf,
[key],
(entry, key2) => {
stderr(
/* c8 ignore next */
key2.includes(" ") ? JSON.stringify(key2) : key2,
entry
);
if (entry.isJSON) {
stdout(JSON.stringify(entry.body, null, 2));
} else {
process.stdout.write(entry.body);
}
return true;
},
view2
);
};
var fetchAll = async (conf, test) => {
const rc = conf.options.packageInfo.registryClient;
const { cache } = rc;
const map = {};
for await (const [key, val] of cache) {
const entry = CacheEntry.decode(val);
if (!test(entry, key, val)) continue;
map[key] = entry.toJSON();
}
return map;
};
var fetchKeys = async (conf, keys, test, view2) => {
const rc = conf.options.packageInfo.registryClient;
const { cache } = rc;
const map = {};
const results = await Promise.all(
keys.map(async (key) => {
return [key, await cache.fetch(key)];
})
);
for (const [key, val] of results) {
if (!val) {
view2?.stdout("Not found:", key);
} else {
const entry = CacheEntry.decode(val);
if (!test(entry, key, val)) continue;
map[key] = entry.toJSON();
}
}
return map;
};
var deleteEntries = async (conf, keys, test, view2) => {
const rc = conf.options.packageInfo.registryClient;
const { cache } = rc;
let count = 0;
let size = 0;
const testAction = (entry, key, val) => {
if (!test(entry)) {
return false;
}
count++;
const s2 = val.byteLength + key.length;
cache.delete(key, true, entry.integrity);
const k = key.includes(" ") ? JSON.stringify(key) : key;
view2?.stdout("-", k, s2);
size += s2;
return true;
};
const map = await (keys.length ? fetchKeys(conf, keys, testAction, view2) : fetchAll(conf, testAction));
const pb = prettyBytes(size, { binary: true });
const s = count === 1 ? "" : "s";
await cache.promise();
view2?.stdout(`Removed ${count} item${s} totalling ${pb}`);
return map;
};
var clean = async (conf, keys, view2) => deleteEntries(conf, keys, (entry) => !entry.valid, view2);
var deleteBefore = async (conf, args, view2) => {
if (!args.length) {
throw error("Must provide a date to delete before", {
code: "EUSAGE"
});
}
const now = /* @__PURE__ */ new Date();
const before = new Date(args.join(" "));
if (before >= now) {
throw error("Cannot delete cache entries from the future", {
code: "EUSAGE",
found: before
});
}
return deleteEntries(
conf,
[],
(entry) => !!entry.date && entry.date < before,
view2
);
};
var deleteKeys = async (conf, keys, view2) => {
if (!keys.length) {
throw error("Must provide cache keys to delete", {
code: "EUSAGE"
});
}
return deleteEntries(conf, keys, () => true, view2);
};
var deleteAll = async (conf, _, view2) => {
const { cache } = conf.options.packageInfo.registryClient;
await rm(cache.path(), { recursive: true, force: true });
await mkdir(cache.path(), { recursive: true });
view2?.stdout("Deleted all cache entries.");
};
var add = async (conf, specs, view2) => {
if (!specs.length) {
throw error("Must provide specs to add to the cache", {
code: "EUSAGE"
});
}
const { packageInfo } = conf.options;
const promises = [];
for (const spec of specs) {
const p = packageInfo.resolve(Spec.parseArgs(spec, conf.options), {
staleWhileRevalidate: false
}).then(async (r) => {
const { resolved, integrity } = r;
await packageInfo.registryClient.request(resolved, {
...conf.options,
integrity,
staleWhileRevalidate: false,
query: void 0
});
view2?.stdout("+", spec, r.resolved);
});
promises.push(p);
}
await Promise.all(promises);
};
export {
CacheView,
command,
usage,
views
};
//# sourceMappingURL=cache-WBS2SOZN.js.map