rshow 0.0.8 → 0.0.9
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/main.js +567 -46
- package/package.json +1 -1
- package/skills/rshow/reference/cli.md +5 -0
- package/worker/index.js +11 -32
- package/worker/migrations/0006_retired_slugs.sql +5 -0
package/dist/main.js
CHANGED
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
// src/main.ts
|
|
29
|
-
import
|
|
30
|
-
import
|
|
29
|
+
import path28 from "node:path";
|
|
30
|
+
import process25 from "node:process";
|
|
31
31
|
|
|
32
32
|
// src/binary.ts
|
|
33
33
|
import { mkdir, mkdtemp, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -38,7 +38,7 @@ import process from "node:process";
|
|
|
38
38
|
// src/version.ts
|
|
39
39
|
import { readFileSync } from "node:fs";
|
|
40
40
|
import { fileURLToPath } from "node:url";
|
|
41
|
-
var VERSION = true ? "0.0.
|
|
41
|
+
var VERSION = true ? "0.0.9" : versionFromPackage();
|
|
42
42
|
|
|
43
43
|
// src/binary.ts
|
|
44
44
|
var ASSET_MANIFEST = "assets.json";
|
|
@@ -998,6 +998,7 @@ commands:
|
|
|
998
998
|
pin <slug> <n|live> serve version n, or live for the newest
|
|
999
999
|
delete <slug> [--version n] [--force] --yes
|
|
1000
1000
|
delete an artifact, or one version of it
|
|
1001
|
+
upgrade [--check] update rshow to the newest release
|
|
1001
1002
|
login [--url u] save the API token for this account
|
|
1002
1003
|
logout [--url u] remove the saved token for a server
|
|
1003
1004
|
completion <shell> print a completion script for bash, zsh or fish
|
|
@@ -1275,6 +1276,31 @@ A theme or a theme version also needs --force, because pages link to it.
|
|
|
1275
1276
|
A pinned version and the only version of an artifact cannot be deleted.
|
|
1276
1277
|
A public version can stay visible for up to 5 minutes after the delete, and a
|
|
1277
1278
|
theme file for longer.`;
|
|
1279
|
+
var UPGRADE_USAGE = `usage: rshow upgrade [--check] [--version <x.y.z>] [--force]
|
|
1280
|
+
|
|
1281
|
+
Updates rshow to the newest release, or to the release --version names, which
|
|
1282
|
+
may be an older one.
|
|
1283
|
+
A single executable is replaced in place, and an npm global install runs
|
|
1284
|
+
npm install -g rshow@<version>.
|
|
1285
|
+
Any other install, such as a source checkout, an npx cache or a local
|
|
1286
|
+
dependency, is left alone and named with the tool that owns it.
|
|
1287
|
+
Running the command is the consent: there is no --yes.
|
|
1288
|
+
No config and no token are read, so it works before rshow init.
|
|
1289
|
+
|
|
1290
|
+
--check prints the current and the newest version and changes nothing, and
|
|
1291
|
+
exits 0 either way; --json prints {current, latest, upgrade_available}.
|
|
1292
|
+
A run prints upgraded <old> -> <new>, or already at <version>. --json prints
|
|
1293
|
+
{previous, version, upgraded, kind}, where kind is binary or npm.
|
|
1294
|
+
--version takes x.y.z with an optional leading v; --force reinstalls the same
|
|
1295
|
+
version, which is how a broken binary comes back.
|
|
1296
|
+
Skills that rshow installed are refreshed by the new rshow, and a bash, zsh or
|
|
1297
|
+
fish completion that is already there is replaced; RSHOW_NO_COMPLETIONS=1
|
|
1298
|
+
leaves the completions alone.
|
|
1299
|
+
RSHOW_DOWNLOAD_BASE downloads from a mirror instead of the release, and takes
|
|
1300
|
+
an http or https url; it cannot be used with --check.
|
|
1301
|
+
|
|
1302
|
+
A release older than this one has no upgrade command, so after a downgrade
|
|
1303
|
+
come back with curl -fsSL https://rslib.github.io/rshow/install.sh | sh.`;
|
|
1278
1304
|
var LOGIN_USAGE = `usage: rshow login [--url u]
|
|
1279
1305
|
|
|
1280
1306
|
Reads the token from stdin, checks it with the API, then saves it in the macOS
|
|
@@ -1968,27 +1994,27 @@ var sqrtTall = function sqrtTall2(extraVinculum, hLinePad2, viewBoxHeight) {
|
|
|
1968
1994
|
};
|
|
1969
1995
|
var sqrtPath = function sqrtPath2(size, extraVinculum, viewBoxHeight) {
|
|
1970
1996
|
extraVinculum = 1e3 * extraVinculum;
|
|
1971
|
-
var
|
|
1997
|
+
var path29 = "";
|
|
1972
1998
|
switch (size) {
|
|
1973
1999
|
case "sqrtMain":
|
|
1974
|
-
|
|
2000
|
+
path29 = sqrtMain(extraVinculum, hLinePad);
|
|
1975
2001
|
break;
|
|
1976
2002
|
case "sqrtSize1":
|
|
1977
|
-
|
|
2003
|
+
path29 = sqrtSize1(extraVinculum, hLinePad);
|
|
1978
2004
|
break;
|
|
1979
2005
|
case "sqrtSize2":
|
|
1980
|
-
|
|
2006
|
+
path29 = sqrtSize2(extraVinculum, hLinePad);
|
|
1981
2007
|
break;
|
|
1982
2008
|
case "sqrtSize3":
|
|
1983
|
-
|
|
2009
|
+
path29 = sqrtSize3(extraVinculum, hLinePad);
|
|
1984
2010
|
break;
|
|
1985
2011
|
case "sqrtSize4":
|
|
1986
|
-
|
|
2012
|
+
path29 = sqrtSize4(extraVinculum, hLinePad);
|
|
1987
2013
|
break;
|
|
1988
2014
|
case "sqrtTall":
|
|
1989
|
-
|
|
2015
|
+
path29 = sqrtTall(extraVinculum, hLinePad, viewBoxHeight);
|
|
1990
2016
|
}
|
|
1991
|
-
return
|
|
2017
|
+
return path29;
|
|
1992
2018
|
};
|
|
1993
2019
|
var innerPath = function innerPath2(name, height) {
|
|
1994
2020
|
switch (name) {
|
|
@@ -6202,8 +6228,8 @@ var svgData = {
|
|
|
6202
6228
|
};
|
|
6203
6229
|
var staticSvg = function staticSvg2(value, options) {
|
|
6204
6230
|
var _svgData$value = svgData[value], pathName = _svgData$value[0], width = _svgData$value[1], height = _svgData$value[2];
|
|
6205
|
-
var
|
|
6206
|
-
var svgNode = new SvgNode([
|
|
6231
|
+
var path29 = new PathNode(pathName);
|
|
6232
|
+
var svgNode = new SvgNode([path29], {
|
|
6207
6233
|
"width": makeEm(width),
|
|
6208
6234
|
"height": makeEm(height),
|
|
6209
6235
|
// Override CSS rule `.katex svg { width: 100% }`
|
|
@@ -7346,8 +7372,8 @@ var stretchySvg = function stretchySvg2(group, options) {
|
|
|
7346
7372
|
pathName = "tilde" + imgIndex;
|
|
7347
7373
|
}
|
|
7348
7374
|
}
|
|
7349
|
-
var
|
|
7350
|
-
var svgNode = new SvgNode([
|
|
7375
|
+
var path29 = new PathNode(pathName);
|
|
7376
|
+
var svgNode = new SvgNode([path29], {
|
|
7351
7377
|
"width": "100%",
|
|
7352
7378
|
"height": makeEm(_height),
|
|
7353
7379
|
"viewBox": "0 0 " + viewBoxWidth + " " + viewBoxHeight,
|
|
@@ -8561,8 +8587,8 @@ var makeGlyphSpan = function makeGlyphSpan2(symbol, font, mode, options) {
|
|
|
8561
8587
|
};
|
|
8562
8588
|
var makeInner = function makeInner2(ch2, height, options) {
|
|
8563
8589
|
var width = fontMetricsData["Size4-Regular"][ch2.charCodeAt(0)] ? fontMetricsData["Size4-Regular"][ch2.charCodeAt(0)][4] : fontMetricsData["Size1-Regular"][ch2.charCodeAt(0)][4];
|
|
8564
|
-
var
|
|
8565
|
-
var svgNode = new SvgNode([
|
|
8590
|
+
var path29 = new PathNode("inner", innerPath(ch2, Math.round(1e3 * height)));
|
|
8591
|
+
var svgNode = new SvgNode([path29], {
|
|
8566
8592
|
"width": makeEm(width),
|
|
8567
8593
|
"height": makeEm(height),
|
|
8568
8594
|
// Override CSS rule `.katex svg { width: 100% }`
|
|
@@ -8731,10 +8757,10 @@ var makeStackedDelim = function makeStackedDelim2(delim, heightTotal, center, op
|
|
|
8731
8757
|
var midHeight = realHeightTotal - topHeightTotal - bottomHeightTotal;
|
|
8732
8758
|
var viewBoxHeight = Math.round(realHeightTotal * 1e3);
|
|
8733
8759
|
var pathStr = tallDelim(svgLabel, Math.round(midHeight * 1e3));
|
|
8734
|
-
var
|
|
8760
|
+
var path29 = new PathNode(svgLabel, pathStr);
|
|
8735
8761
|
var width = makeEm(viewBoxWidth / 1e3);
|
|
8736
8762
|
var height = makeEm(viewBoxHeight / 1e3);
|
|
8737
|
-
var svg = new SvgNode([
|
|
8763
|
+
var svg = new SvgNode([path29], {
|
|
8738
8764
|
"width": width,
|
|
8739
8765
|
"height": height,
|
|
8740
8766
|
"viewBox": "0 0 " + viewBoxWidth + " " + viewBoxHeight
|
|
@@ -8775,8 +8801,8 @@ var makeStackedDelim = function makeStackedDelim2(delim, heightTotal, center, op
|
|
|
8775
8801
|
var vbPad = 80;
|
|
8776
8802
|
var emPad = 0.08;
|
|
8777
8803
|
var sqrtSvg = function sqrtSvg2(sqrtName, height, viewBoxHeight, extraVinculum, options) {
|
|
8778
|
-
var
|
|
8779
|
-
var pathNode = new PathNode(sqrtName,
|
|
8804
|
+
var path29 = sqrtPath(sqrtName, extraVinculum, viewBoxHeight);
|
|
8805
|
+
var pathNode = new PathNode(sqrtName, path29);
|
|
8780
8806
|
var svg = new SvgNode([pathNode], {
|
|
8781
8807
|
// Note: 1000:1 ratio of viewBox to document em width.
|
|
8782
8808
|
"width": "400em",
|
|
@@ -9275,8 +9301,8 @@ var htmlBuilder$7 = (group, options) => {
|
|
|
9275
9301
|
var angleHeight = inner2.height + inner2.depth + lineWeight + clearance;
|
|
9276
9302
|
inner2.style.paddingLeft = makeEm(angleHeight / 2 + lineWeight);
|
|
9277
9303
|
var viewBoxHeight = Math.floor(1e3 * angleHeight * scale);
|
|
9278
|
-
var
|
|
9279
|
-
var svgNode = new SvgNode([new PathNode("phase",
|
|
9304
|
+
var path29 = phasePath(viewBoxHeight);
|
|
9305
|
+
var svgNode = new SvgNode([new PathNode("phase", path29)], {
|
|
9280
9306
|
"width": "400em",
|
|
9281
9307
|
"height": makeEm(viewBoxHeight / 1e3),
|
|
9282
9308
|
"viewBox": "0 0 400000 " + viewBoxHeight,
|
|
@@ -13305,11 +13331,11 @@ var newcommand = (context, existsOK, nonexistsOK, skipIfExists) => {
|
|
|
13305
13331
|
throw new ParseError("\\newcommand's first argument must be a macro name");
|
|
13306
13332
|
}
|
|
13307
13333
|
var name = arg[0].text;
|
|
13308
|
-
var
|
|
13309
|
-
if (
|
|
13334
|
+
var exists3 = context.isDefined(name);
|
|
13335
|
+
if (exists3 && !existsOK) {
|
|
13310
13336
|
throw new ParseError("\\newcommand{" + name + "} attempting to redefine " + (name + "; use \\renewcommand"));
|
|
13311
13337
|
}
|
|
13312
|
-
if (!
|
|
13338
|
+
if (!exists3 && !nonexistsOK) {
|
|
13313
13339
|
throw new ParseError("\\renewcommand{" + name + "} when command " + name + " does not yet exist; use \\newcommand");
|
|
13314
13340
|
}
|
|
13315
13341
|
var numArgs = 0;
|
|
@@ -13327,7 +13353,7 @@ var newcommand = (context, existsOK, nonexistsOK, skipIfExists) => {
|
|
|
13327
13353
|
numArgs = parseInt(argText);
|
|
13328
13354
|
arg = context.consumeArg().tokens;
|
|
13329
13355
|
}
|
|
13330
|
-
if (!(
|
|
13356
|
+
if (!(exists3 && skipIfExists)) {
|
|
13331
13357
|
context.macros.set(name, {
|
|
13332
13358
|
tokens: arg,
|
|
13333
13359
|
numArgs
|
|
@@ -17046,7 +17072,7 @@ function sameFiles(local, remote) {
|
|
|
17046
17072
|
const paths = Object.keys(local);
|
|
17047
17073
|
const other = remote;
|
|
17048
17074
|
if (paths.length !== Object.keys(other).length) return false;
|
|
17049
|
-
return paths.every((
|
|
17075
|
+
return paths.every((path29) => other[path29]?.hash === local[path29]?.hash);
|
|
17050
17076
|
}
|
|
17051
17077
|
function reportUnchanged(out, result) {
|
|
17052
17078
|
out.data({ unchanged: true, slug: result.slug, version: result.version.n });
|
|
@@ -17784,8 +17810,8 @@ function keyLine(text2, key2, mode) {
|
|
|
17784
17810
|
}
|
|
17785
17811
|
return 0;
|
|
17786
17812
|
}
|
|
17787
|
-
function finding(
|
|
17788
|
-
return { path:
|
|
17813
|
+
function finding(path29, line, severity, message) {
|
|
17814
|
+
return { path: path29, line: Math.max(1, line), severity, message };
|
|
17789
17815
|
}
|
|
17790
17816
|
function resolveValue(name, map, fallback) {
|
|
17791
17817
|
let current = map[name] ?? fallback[name];
|
|
@@ -19171,8 +19197,8 @@ async function create(argv, ctx) {
|
|
|
19171
19197
|
if (baseDir === void 0) throw new UsageError(`no built-in theme: ${from}`);
|
|
19172
19198
|
const parent = path18.resolve(stringValue(args, "dir") ?? ".");
|
|
19173
19199
|
const target = path18.join(parent, name);
|
|
19174
|
-
const
|
|
19175
|
-
if (
|
|
19200
|
+
const exists3 = await stat13(target).catch(() => void 0);
|
|
19201
|
+
if (exists3 !== void 0) throw new UsageError(`${target} already exists`);
|
|
19176
19202
|
const values = await baseRoleValues(baseDir, ROLE_TOKENS);
|
|
19177
19203
|
const doc = { name, extends: from, tokens: {}, modeTokens: values };
|
|
19178
19204
|
await mkdir6(target, { recursive: true });
|
|
@@ -22729,6 +22755,7 @@ var USAGE = {
|
|
|
22729
22755
|
delete: DELETE_USAGE,
|
|
22730
22756
|
login: LOGIN_USAGE,
|
|
22731
22757
|
logout: LOGOUT_USAGE,
|
|
22758
|
+
upgrade: UPGRADE_USAGE,
|
|
22732
22759
|
completion: COMPLETION_USAGE
|
|
22733
22760
|
};
|
|
22734
22761
|
var WHEN = {
|
|
@@ -23105,6 +23132,7 @@ var SPECS = {
|
|
|
23105
23132
|
delete: { usage: DELETE_USAGE },
|
|
23106
23133
|
login: { usage: LOGIN_USAGE },
|
|
23107
23134
|
logout: { usage: LOGOUT_USAGE },
|
|
23135
|
+
upgrade: { usage: UPGRADE_USAGE },
|
|
23108
23136
|
completion: { usage: COMPLETION_USAGE, choices: [...SHELLS] }
|
|
23109
23137
|
};
|
|
23110
23138
|
function optionsOf(usage) {
|
|
@@ -23470,15 +23498,507 @@ async function run20(argv, ctx, platform = process21.platform) {
|
|
|
23470
23498
|
ctx.out.line(`logged in as ${email} (scope ${scope}) for ${url}, saved in ${store2.description}`);
|
|
23471
23499
|
}
|
|
23472
23500
|
|
|
23473
|
-
// src/commands/
|
|
23501
|
+
// src/commands/upgrade.ts
|
|
23502
|
+
import { realpath as realpath2 } from "node:fs/promises";
|
|
23503
|
+
import path27 from "node:path";
|
|
23504
|
+
import process23 from "node:process";
|
|
23505
|
+
|
|
23506
|
+
// src/upgrade.ts
|
|
23507
|
+
import { execFile, spawn as spawn6 } from "node:child_process";
|
|
23508
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
23509
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
23510
|
+
import { chmod as chmod2, copyFile as copyFile2, lstat as lstat2, mkdtemp as mkdtemp5, readFile as readFile19, realpath, rename as rename3, rm as rm8, stat as stat15 } from "node:fs/promises";
|
|
23511
|
+
import path26 from "node:path";
|
|
23474
23512
|
import process22 from "node:process";
|
|
23475
|
-
|
|
23513
|
+
import { Readable } from "node:stream";
|
|
23514
|
+
import { pipeline } from "node:stream/promises";
|
|
23515
|
+
var REPO = "rslib/rshow";
|
|
23516
|
+
var NPM_HINT = "npm i -g rshow";
|
|
23517
|
+
var INSTALLER_ELSEWHERE = `curl -fsSL https://rslib.github.io/rshow/install.sh | RSHOW_INSTALL_DIR=$HOME/.local/bin sh`;
|
|
23518
|
+
var LATEST_URL = `https://github.com/${REPO}/releases/latest`;
|
|
23519
|
+
var RELEASES = `https://github.com/${REPO}/releases/download/v`;
|
|
23520
|
+
var TARGETS = ["linux-x64", "linux-arm64", "darwin-arm64"];
|
|
23521
|
+
var VERSION_PATTERN = /^v?([0-9]+\.[0-9]+\.[0-9]+)$/;
|
|
23522
|
+
var TAG_PATH = /\/tag\/v([0-9]+\.[0-9]+\.[0-9]+)$/;
|
|
23523
|
+
var LOOKUP_TIMEOUT_MS = 15e3;
|
|
23524
|
+
var DOWNLOAD_TIMEOUT_MS = 6e5;
|
|
23525
|
+
var UNPACK_TIMEOUT_MS = 12e4;
|
|
23526
|
+
var RUN_TIMEOUT_MS = 2e4;
|
|
23527
|
+
var NPM_TIMEOUT_MS = 3e5;
|
|
23528
|
+
var SKILLS_TIMEOUT_MS = 12e4;
|
|
23529
|
+
var UpgradeFailure = class extends Error {
|
|
23530
|
+
exit;
|
|
23531
|
+
constructor(message, exit = EXIT.api) {
|
|
23532
|
+
super(message);
|
|
23533
|
+
this.name = "UpgradeFailure";
|
|
23534
|
+
this.exit = exit;
|
|
23535
|
+
}
|
|
23536
|
+
};
|
|
23537
|
+
function messageOf12(err) {
|
|
23538
|
+
return err instanceof Error ? err.message : String(err);
|
|
23539
|
+
}
|
|
23540
|
+
function codeOf(err) {
|
|
23541
|
+
const code = typeof err === "object" && err !== null ? err.code : void 0;
|
|
23542
|
+
if (typeof code === "number") return `exit ${code}`;
|
|
23543
|
+
if (typeof code === "string" && code !== "") return code;
|
|
23544
|
+
return messageOf12(err);
|
|
23545
|
+
}
|
|
23546
|
+
function runProgram(file, args, options = {}) {
|
|
23547
|
+
return new Promise((resolve2, reject) => {
|
|
23548
|
+
const run23 = { timeout: options.timeoutMs, maxBuffer: 16 * 1024 * 1024 };
|
|
23549
|
+
execFile(file, [...args], run23, (err, stdout) => {
|
|
23550
|
+
if (err !== null) {
|
|
23551
|
+
reject(err);
|
|
23552
|
+
return;
|
|
23553
|
+
}
|
|
23554
|
+
resolve2(stdout);
|
|
23555
|
+
});
|
|
23556
|
+
});
|
|
23557
|
+
}
|
|
23558
|
+
function parseVersion(raw) {
|
|
23559
|
+
const found = VERSION_PATTERN.exec(raw.trim());
|
|
23560
|
+
if (found === null) throw new UsageError(`--version needs x.y.z, got: ${raw}`);
|
|
23561
|
+
return found[1];
|
|
23562
|
+
}
|
|
23563
|
+
function compareVersions(left, right) {
|
|
23564
|
+
const a = left.split(".").map(Number);
|
|
23565
|
+
const b = right.split(".").map(Number);
|
|
23566
|
+
for (let index = 0; index < 3; index += 1) {
|
|
23567
|
+
const diff = (a[index] ?? 0) - (b[index] ?? 0);
|
|
23568
|
+
if (diff !== 0) return diff < 0 ? -1 : 1;
|
|
23569
|
+
}
|
|
23570
|
+
return 0;
|
|
23571
|
+
}
|
|
23572
|
+
function targetOf2(platform, arch) {
|
|
23573
|
+
const name = `${platform}-${arch}`;
|
|
23574
|
+
return TARGETS.includes(name) ? name : void 0;
|
|
23575
|
+
}
|
|
23576
|
+
function releaseTagOf(location) {
|
|
23577
|
+
if (location === null || location.trim() === "") return void 0;
|
|
23578
|
+
let pathname;
|
|
23579
|
+
try {
|
|
23580
|
+
pathname = new URL(location, LATEST_URL).pathname;
|
|
23581
|
+
} catch {
|
|
23582
|
+
return void 0;
|
|
23583
|
+
}
|
|
23584
|
+
return TAG_PATH.exec(pathname)?.[1];
|
|
23585
|
+
}
|
|
23586
|
+
async function latestVersion(options) {
|
|
23587
|
+
const reply = await sendRequest(
|
|
23588
|
+
options.fetch,
|
|
23589
|
+
LATEST_URL,
|
|
23590
|
+
{ redirect: "manual", signal: AbortSignal.timeout(LOOKUP_TIMEOUT_MS) },
|
|
23591
|
+
options.env
|
|
23592
|
+
);
|
|
23593
|
+
const location = reply.headers.get("location");
|
|
23594
|
+
const version2 = releaseTagOf(location);
|
|
23595
|
+
if (version2 === void 0) {
|
|
23596
|
+
throw new UpgradeFailure(`${LATEST_URL} did not name a release (location: ${location ?? "none"})`);
|
|
23597
|
+
}
|
|
23598
|
+
return version2;
|
|
23599
|
+
}
|
|
23600
|
+
function mirrorOf(options) {
|
|
23601
|
+
const raw = (options.env.RSHOW_DOWNLOAD_BASE ?? "").trim();
|
|
23602
|
+
if (raw === "") return void 0;
|
|
23603
|
+
const base = raw.replace(/\/+$/, "");
|
|
23604
|
+
let protocol;
|
|
23605
|
+
try {
|
|
23606
|
+
protocol = new URL(base).protocol;
|
|
23607
|
+
} catch {
|
|
23608
|
+
throw new UsageError(`RSHOW_DOWNLOAD_BASE is not a url: ${raw}`);
|
|
23609
|
+
}
|
|
23610
|
+
if (protocol !== "http:" && protocol !== "https:") {
|
|
23611
|
+
throw new UsageError(`RSHOW_DOWNLOAD_BASE needs an http or https url, got: ${raw}`);
|
|
23612
|
+
}
|
|
23613
|
+
return base;
|
|
23614
|
+
}
|
|
23615
|
+
function otherError(options) {
|
|
23616
|
+
const from = options.install.argv1 ?? options.install.execPath;
|
|
23617
|
+
const version2 = options.wanted ?? "<version>";
|
|
23618
|
+
const where = from.split(path26.sep).join("/");
|
|
23619
|
+
if (where.includes("/_npx/")) {
|
|
23620
|
+
return new UsageError(`rshow runs from ${from}, an npx cache that npm owns; run npx rshow@${version2}`);
|
|
23621
|
+
}
|
|
23622
|
+
if (where.includes("/node_modules/")) {
|
|
23623
|
+
return new UsageError(
|
|
23624
|
+
`rshow runs from ${from}, a local dependency that npm owns; run npm install rshow@${version2} to update it`
|
|
23625
|
+
);
|
|
23626
|
+
}
|
|
23627
|
+
return new UsageError(`rshow runs from ${from}, a source checkout; update it with git pull and npm run build`);
|
|
23628
|
+
}
|
|
23629
|
+
function dataHome(env) {
|
|
23630
|
+
const xdg = (env.XDG_DATA_HOME ?? "").trim();
|
|
23631
|
+
return xdg !== "" ? xdg : path26.join(homeDir(env), ".local", "share");
|
|
23632
|
+
}
|
|
23633
|
+
function configHome(env) {
|
|
23634
|
+
const xdg = (env.XDG_CONFIG_HOME ?? "").trim();
|
|
23635
|
+
return xdg !== "" ? xdg : path26.join(homeDir(env), ".config");
|
|
23636
|
+
}
|
|
23637
|
+
function completionPaths(env) {
|
|
23638
|
+
const data = dataHome(env);
|
|
23639
|
+
const config = configHome(env);
|
|
23640
|
+
return [
|
|
23641
|
+
{ name: "rshow.bash", dst: path26.join(data, "bash-completion", "completions", "rshow") },
|
|
23642
|
+
{ name: "_rshow", dst: path26.join(data, "zsh", "site-functions", "_rshow") },
|
|
23643
|
+
{ name: "rshow.fish", dst: path26.join(config, "fish", "completions", "rshow.fish") }
|
|
23644
|
+
];
|
|
23645
|
+
}
|
|
23646
|
+
async function exists2(file) {
|
|
23647
|
+
return await stat15(file).catch(() => void 0) !== void 0;
|
|
23648
|
+
}
|
|
23649
|
+
function missingFile(name, url, named) {
|
|
23650
|
+
if (named === void 0) {
|
|
23651
|
+
return new UpgradeFailure(
|
|
23652
|
+
`this release has no ${name} (${url}); a new release attaches its binaries a few minutes after it appears, so try again`
|
|
23653
|
+
);
|
|
23654
|
+
}
|
|
23655
|
+
return new UpgradeFailure(
|
|
23656
|
+
`release v${named} has no ${name} (${url}); it may not exist, and a release before 0.0.6 has no tarball, so use the installer with RSHOW_VERSION=${named}`
|
|
23657
|
+
);
|
|
23658
|
+
}
|
|
23659
|
+
async function download(options, url, file, name, named) {
|
|
23660
|
+
const reply = await sendRequest(options.fetch, url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS) }, options.env);
|
|
23661
|
+
if (reply.status === 404) throw missingFile(name, url, named);
|
|
23662
|
+
if (reply.status !== 200 || reply.body === null) {
|
|
23663
|
+
throw new UpgradeFailure(`cannot download ${url}: HTTP ${reply.status}`);
|
|
23664
|
+
}
|
|
23665
|
+
try {
|
|
23666
|
+
await pipeline(Readable.fromWeb(reply.body), createWriteStream(file));
|
|
23667
|
+
} catch (err) {
|
|
23668
|
+
throw new UpgradeFailure(`cannot write ${file}: ${messageOf12(err)}`);
|
|
23669
|
+
}
|
|
23670
|
+
}
|
|
23671
|
+
function sumOf(text2, name) {
|
|
23672
|
+
for (const line of text2.split("\n")) {
|
|
23673
|
+
const parts2 = line.trim().split(/\s+/);
|
|
23674
|
+
if (parts2.length < 2) continue;
|
|
23675
|
+
if (parts2[1].replace(/^\*/, "") === name) return parts2[0];
|
|
23676
|
+
}
|
|
23677
|
+
return void 0;
|
|
23678
|
+
}
|
|
23679
|
+
async function sha256Of(file) {
|
|
23680
|
+
const hash = createHash3("sha256");
|
|
23681
|
+
await pipeline(createReadStream(file), hash);
|
|
23682
|
+
return hash.digest("hex");
|
|
23683
|
+
}
|
|
23684
|
+
async function checkSum(file, name, sumsFile) {
|
|
23685
|
+
const expected = sumOf(await readFile19(sumsFile, "utf8"), name);
|
|
23686
|
+
const actual = await sha256Of(file);
|
|
23687
|
+
if (expected === void 0) {
|
|
23688
|
+
throw new UpgradeFailure(`SHA256SUMS holds no line for ${name}, and the download is ${actual}`);
|
|
23689
|
+
}
|
|
23690
|
+
if (expected !== actual) {
|
|
23691
|
+
throw new UpgradeFailure(`checksum mismatch for ${name}: SHA256SUMS says ${expected}, the download is ${actual}`);
|
|
23692
|
+
}
|
|
23693
|
+
}
|
|
23694
|
+
async function unpack2(file, dir, tarball) {
|
|
23695
|
+
try {
|
|
23696
|
+
await runProgram("tar", ["-xzf", file, "-C", dir], { timeoutMs: UNPACK_TIMEOUT_MS });
|
|
23697
|
+
} catch (err) {
|
|
23698
|
+
throw new UpgradeFailure(`cannot unpack ${tarball}: ${codeOf(err)}`);
|
|
23699
|
+
}
|
|
23700
|
+
}
|
|
23701
|
+
async function printedVersion(file) {
|
|
23702
|
+
try {
|
|
23703
|
+
return (await runProgram(file, ["--version"], { timeoutMs: RUN_TIMEOUT_MS })).trim();
|
|
23704
|
+
} catch (err) {
|
|
23705
|
+
throw new UpgradeFailure(`the new rshow does not run (${codeOf(err)}); the old rshow is still in place`);
|
|
23706
|
+
}
|
|
23707
|
+
}
|
|
23708
|
+
async function replaceCompletions(options, dir, target) {
|
|
23709
|
+
if ((options.env.RSHOW_NO_COMPLETIONS ?? "").trim() === "1") return;
|
|
23710
|
+
for (const entry of completionPaths(options.env)) {
|
|
23711
|
+
const src = path26.join(dir, `rshow-${target}`, "completions", entry.name);
|
|
23712
|
+
try {
|
|
23713
|
+
if (!await exists2(entry.dst) || !await exists2(src)) continue;
|
|
23714
|
+
await copyFile2(src, entry.dst);
|
|
23715
|
+
} catch (err) {
|
|
23716
|
+
warn(`cannot replace the completion ${entry.dst}: ${messageOf12(err)}`);
|
|
23717
|
+
}
|
|
23718
|
+
}
|
|
23719
|
+
}
|
|
23720
|
+
function modeOf(target, statuses) {
|
|
23721
|
+
const kinds = statuses.filter((entry) => entry.target === target).map((entry) => entry.state.kind);
|
|
23722
|
+
if (kinds.includes("copy")) return "copy";
|
|
23723
|
+
if (kinds.includes("link")) return "link";
|
|
23724
|
+
return void 0;
|
|
23725
|
+
}
|
|
23726
|
+
async function refreshSkills(options, file, prefix) {
|
|
23727
|
+
const targets = await detectedTargets(options.home);
|
|
23728
|
+
if (targets.length === 0) return;
|
|
23729
|
+
let source;
|
|
23730
|
+
try {
|
|
23731
|
+
source = await skillsSource(options.env);
|
|
23732
|
+
} catch {
|
|
23733
|
+
return;
|
|
23734
|
+
}
|
|
23735
|
+
if (source === void 0) return;
|
|
23736
|
+
const statuses = await skillsStatus({ home: options.home, source, targets });
|
|
23737
|
+
const groups = { copy: [], link: [] };
|
|
23738
|
+
for (const target of targets) {
|
|
23739
|
+
const mode = modeOf(target, statuses);
|
|
23740
|
+
if (mode !== void 0) groups[mode].push(target);
|
|
23741
|
+
}
|
|
23742
|
+
for (const mode of ["copy", "link"]) {
|
|
23743
|
+
if (groups[mode].length === 0) continue;
|
|
23744
|
+
try {
|
|
23745
|
+
await runProgram(file, [...prefix, "skills", "install", `--${mode}`, ...groups[mode]], {
|
|
23746
|
+
timeoutMs: SKILLS_TIMEOUT_MS
|
|
23747
|
+
});
|
|
23748
|
+
} catch (err) {
|
|
23749
|
+
warn(`the new rshow could not refresh the skills (${codeOf(err)}); run rshow skills install`);
|
|
23750
|
+
}
|
|
23751
|
+
}
|
|
23752
|
+
}
|
|
23753
|
+
function versionIn(printed) {
|
|
23754
|
+
return /^rshow ([0-9]+\.[0-9]+\.[0-9]+)/.exec(printed)?.[1];
|
|
23755
|
+
}
|
|
23756
|
+
async function replaceBinary(job, dest) {
|
|
23757
|
+
const dir = path26.dirname(dest);
|
|
23758
|
+
let tmp;
|
|
23759
|
+
try {
|
|
23760
|
+
tmp = await mkdtemp5(path26.join(dir, ".rshow-upgrade-"));
|
|
23761
|
+
} catch (err) {
|
|
23762
|
+
const code = err.code;
|
|
23763
|
+
if (code === "EACCES" || code === "EPERM" || code === "EROFS") {
|
|
23764
|
+
throw new UpgradeFailure(`${dir} is not writable; install elsewhere instead: ${INSTALLER_ELSEWHERE}`);
|
|
23765
|
+
}
|
|
23766
|
+
throw new UpgradeFailure(`cannot write next to ${dest}: ${messageOf12(err)}`);
|
|
23767
|
+
}
|
|
23768
|
+
try {
|
|
23769
|
+
const tarball = `rshow-${job.target}.tar.gz`;
|
|
23770
|
+
const file = path26.join(tmp, tarball);
|
|
23771
|
+
const sums = path26.join(tmp, "SHA256SUMS");
|
|
23772
|
+
const url = `${job.base}/${tarball}`;
|
|
23773
|
+
process22.stderr.write(`rshow: downloading ${url}
|
|
23774
|
+
`);
|
|
23775
|
+
await download(job.options, url, file, tarball, job.named);
|
|
23776
|
+
await download(job.options, `${job.base}/SHA256SUMS`, sums, "SHA256SUMS", job.named);
|
|
23777
|
+
await checkSum(file, tarball, sums);
|
|
23778
|
+
await unpack2(file, tmp, tarball);
|
|
23779
|
+
const folder = `rshow-${job.target}`;
|
|
23780
|
+
const unpacked = path26.join(tmp, folder, "rshow");
|
|
23781
|
+
const info = await lstat2(unpacked).catch(() => void 0);
|
|
23782
|
+
if (info === void 0) {
|
|
23783
|
+
throw new UpgradeFailure(`${tarball} holds no ${folder}/rshow; the old rshow is still in place`);
|
|
23784
|
+
}
|
|
23785
|
+
if (!info.isFile()) {
|
|
23786
|
+
throw new UpgradeFailure(`${tarball} holds a ${folder}/rshow that is not a file; the old rshow is still in place`);
|
|
23787
|
+
}
|
|
23788
|
+
await chmod2(unpacked, 493);
|
|
23789
|
+
const printed = await printedVersion(unpacked);
|
|
23790
|
+
let version2;
|
|
23791
|
+
if (job.version === void 0) {
|
|
23792
|
+
const found = versionIn(printed);
|
|
23793
|
+
if (found === void 0) {
|
|
23794
|
+
throw new UpgradeFailure(`the new rshow printed ${printed || "no version"}; the old rshow is still in place`);
|
|
23795
|
+
}
|
|
23796
|
+
if (!job.force && found === job.options.current) return { replaced: false, version: found };
|
|
23797
|
+
version2 = found;
|
|
23798
|
+
} else {
|
|
23799
|
+
if (!printed.startsWith(`rshow ${job.version}`)) {
|
|
23800
|
+
throw new UpgradeFailure(
|
|
23801
|
+
`the new rshow printed ${printed || "no version"}, not rshow ${job.version}; the old rshow is still in place`
|
|
23802
|
+
);
|
|
23803
|
+
}
|
|
23804
|
+
version2 = job.version;
|
|
23805
|
+
}
|
|
23806
|
+
await rename3(unpacked, dest);
|
|
23807
|
+
await replaceCompletions(job.options, tmp, job.target);
|
|
23808
|
+
return { replaced: true, version: version2 };
|
|
23809
|
+
} finally {
|
|
23810
|
+
await rm8(tmp, { recursive: true, force: true });
|
|
23811
|
+
}
|
|
23812
|
+
}
|
|
23813
|
+
async function installPath(options) {
|
|
23814
|
+
try {
|
|
23815
|
+
return await realpath(options.install.execPath);
|
|
23816
|
+
} catch (err) {
|
|
23817
|
+
throw new UpgradeFailure(`cannot read ${options.install.execPath}: ${messageOf12(err)}`);
|
|
23818
|
+
}
|
|
23819
|
+
}
|
|
23820
|
+
function targetOrFail(options) {
|
|
23821
|
+
const platform = options.platform ?? process22.platform;
|
|
23822
|
+
const arch = options.arch ?? process22.arch;
|
|
23823
|
+
const target = targetOf2(platform, arch);
|
|
23824
|
+
if (target === void 0) {
|
|
23825
|
+
throw new UsageError(`no rshow single executable for ${platform}-${arch}; run ${NPM_HINT}`);
|
|
23826
|
+
}
|
|
23827
|
+
return target;
|
|
23828
|
+
}
|
|
23829
|
+
async function installBinary(job) {
|
|
23830
|
+
const dest = await installPath(job.options);
|
|
23831
|
+
const outcome = await replaceBinary(job, dest);
|
|
23832
|
+
if (!outcome.replaced) return { status: "current", kind: "binary", version: outcome.version };
|
|
23833
|
+
await refreshSkills(job.options, dest, []);
|
|
23834
|
+
return { status: "upgraded", kind: "binary", previous: job.options.current, version: outcome.version };
|
|
23835
|
+
}
|
|
23836
|
+
function runNpm(args) {
|
|
23837
|
+
return new Promise((resolve2, reject) => {
|
|
23838
|
+
const child = spawn6("npm", [...args], { stdio: ["ignore", 2, 2], timeout: NPM_TIMEOUT_MS });
|
|
23839
|
+
child.on("error", (err) => {
|
|
23840
|
+
child.emit("exit", null, null);
|
|
23841
|
+
reject(err);
|
|
23842
|
+
});
|
|
23843
|
+
child.on("close", (code, signal) => {
|
|
23844
|
+
if (code === 0) {
|
|
23845
|
+
resolve2();
|
|
23846
|
+
return;
|
|
23847
|
+
}
|
|
23848
|
+
if (code !== null) {
|
|
23849
|
+
const err = Object.assign(new Error(`npm exited ${code}`), { code });
|
|
23850
|
+
reject(err);
|
|
23851
|
+
return;
|
|
23852
|
+
}
|
|
23853
|
+
reject(new Error(`npm stopped on ${signal ?? "a timeout"}`));
|
|
23854
|
+
});
|
|
23855
|
+
});
|
|
23856
|
+
}
|
|
23857
|
+
async function npmInstall(version2) {
|
|
23858
|
+
const command = `npm install -g rshow@${version2}`;
|
|
23859
|
+
try {
|
|
23860
|
+
await runNpm(["install", "-g", `rshow@${version2}`]);
|
|
23861
|
+
} catch (err) {
|
|
23862
|
+
const code = err.code;
|
|
23863
|
+
if (typeof code === "number") throw new UpgradeFailure(`${command} failed (exit ${code})`, code);
|
|
23864
|
+
throw new UpgradeFailure(`cannot run npm (${codeOf(err)}); run ${command}`, EXIT.usage);
|
|
23865
|
+
}
|
|
23866
|
+
}
|
|
23867
|
+
async function upgrade(options) {
|
|
23868
|
+
const mirror = mirrorOf(options);
|
|
23869
|
+
const force = options.force === true;
|
|
23870
|
+
const kind = options.install.kind;
|
|
23871
|
+
if (options.check === true) {
|
|
23872
|
+
if (mirror !== void 0) {
|
|
23873
|
+
throw new UsageError(`--check cannot be used with RSHOW_DOWNLOAD_BASE (${mirror}), which names no release`);
|
|
23874
|
+
}
|
|
23875
|
+
const latest = options.wanted ?? await latestVersion(options);
|
|
23876
|
+
return {
|
|
23877
|
+
status: "check",
|
|
23878
|
+
current: options.current,
|
|
23879
|
+
latest,
|
|
23880
|
+
upgrade: compareVersions(latest, options.current) > 0
|
|
23881
|
+
};
|
|
23882
|
+
}
|
|
23883
|
+
if (kind === "other") throw otherError(options);
|
|
23884
|
+
if (kind === "binary" && mirror !== void 0 && options.wanted === void 0) {
|
|
23885
|
+
return installBinary({ options, base: mirror, target: targetOrFail(options), force });
|
|
23886
|
+
}
|
|
23887
|
+
let version2 = options.wanted;
|
|
23888
|
+
if (version2 === void 0) {
|
|
23889
|
+
const latest = await latestVersion(options);
|
|
23890
|
+
if (compareVersions(latest, options.current) < 0) {
|
|
23891
|
+
return { status: "newer", kind, current: options.current, latest };
|
|
23892
|
+
}
|
|
23893
|
+
version2 = latest;
|
|
23894
|
+
}
|
|
23895
|
+
if (version2 === options.current && !force) {
|
|
23896
|
+
return { status: "current", kind, version: version2 };
|
|
23897
|
+
}
|
|
23898
|
+
if (kind === "binary") {
|
|
23899
|
+
const base = mirror ?? `${RELEASES}${version2}`;
|
|
23900
|
+
return installBinary({ options, base, target: targetOrFail(options), version: version2, named: options.wanted, force });
|
|
23901
|
+
}
|
|
23902
|
+
await npmInstall(version2);
|
|
23903
|
+
const argv1 = options.install.argv1;
|
|
23904
|
+
if (argv1 !== void 0) await refreshSkills(options, process22.execPath, [argv1]);
|
|
23905
|
+
return { status: "upgraded", kind: "npm", previous: options.current, version: version2 };
|
|
23906
|
+
}
|
|
23907
|
+
function reportOf(result) {
|
|
23908
|
+
if (result.status === "check") {
|
|
23909
|
+
return {
|
|
23910
|
+
data: { current: result.current, latest: result.latest, upgrade_available: result.upgrade },
|
|
23911
|
+
lines: [`current: ${result.current}`, `latest: ${result.latest}`]
|
|
23912
|
+
};
|
|
23913
|
+
}
|
|
23914
|
+
if (result.status === "newer") {
|
|
23915
|
+
return {
|
|
23916
|
+
data: { previous: result.current, version: result.current, upgraded: false, kind: result.kind },
|
|
23917
|
+
lines: [`rshow: ${result.current} is newer than the newest release, ${result.latest}`]
|
|
23918
|
+
};
|
|
23919
|
+
}
|
|
23920
|
+
if (result.status === "current") {
|
|
23921
|
+
return {
|
|
23922
|
+
data: { previous: result.version, version: result.version, upgraded: false, kind: result.kind },
|
|
23923
|
+
lines: [`rshow: already at ${result.version}`]
|
|
23924
|
+
};
|
|
23925
|
+
}
|
|
23926
|
+
return {
|
|
23927
|
+
data: { previous: result.previous, version: result.version, upgraded: true, kind: result.kind },
|
|
23928
|
+
lines: [`rshow: upgraded ${result.previous} -> ${result.version}`]
|
|
23929
|
+
};
|
|
23930
|
+
}
|
|
23931
|
+
|
|
23932
|
+
// src/commands/upgrade.ts
|
|
23933
|
+
var TIMEOUT_MS2 = 6e4;
|
|
23934
|
+
function isUnder2(file, dir) {
|
|
23935
|
+
const rel2 = path27.relative(dir, file);
|
|
23936
|
+
return rel2 !== "" && rel2 !== ".." && !rel2.startsWith(`..${path27.sep}`) && !path27.isAbsolute(rel2);
|
|
23937
|
+
}
|
|
23938
|
+
async function npmRoot() {
|
|
23939
|
+
try {
|
|
23940
|
+
const root2 = (await runProgram("npm", ["root", "-g"], { timeoutMs: TIMEOUT_MS2 })).trim();
|
|
23941
|
+
return root2 === "" ? void 0 : await realpath2(root2);
|
|
23942
|
+
} catch {
|
|
23943
|
+
return void 0;
|
|
23944
|
+
}
|
|
23945
|
+
}
|
|
23946
|
+
async function installKind() {
|
|
23947
|
+
if (await isBinary()) return { kind: "binary", execPath: process23.execPath };
|
|
23948
|
+
const argv1 = process23.argv[1];
|
|
23949
|
+
const root2 = await npmRoot();
|
|
23950
|
+
if (root2 !== void 0 && argv1 !== void 0) {
|
|
23951
|
+
const script3 = await realpath2(argv1).catch(() => void 0);
|
|
23952
|
+
if (script3 !== void 0 && isUnder2(script3, root2)) {
|
|
23953
|
+
return { kind: "npm", execPath: process23.execPath, argv1: script3 };
|
|
23954
|
+
}
|
|
23955
|
+
}
|
|
23956
|
+
return { kind: "other", execPath: process23.execPath, argv1 };
|
|
23957
|
+
}
|
|
23958
|
+
async function run21(argv, ctx) {
|
|
23959
|
+
const args = parseCommandArgs(
|
|
23960
|
+
argv,
|
|
23961
|
+
{ check: { type: "boolean" }, version: { type: "string" }, force: { type: "boolean" } },
|
|
23962
|
+
0,
|
|
23963
|
+
0,
|
|
23964
|
+
UPGRADE_USAGE
|
|
23965
|
+
);
|
|
23966
|
+
const raw = stringValue(args, "version");
|
|
23967
|
+
const wanted = raw === void 0 ? void 0 : parseVersion(raw);
|
|
23968
|
+
const env = process23.env;
|
|
23969
|
+
let result;
|
|
23970
|
+
try {
|
|
23971
|
+
result = await upgrade({
|
|
23972
|
+
current: VERSION,
|
|
23973
|
+
wanted,
|
|
23974
|
+
check: boolValue(args, "check"),
|
|
23975
|
+
force: boolValue(args, "force"),
|
|
23976
|
+
install: await installKind(),
|
|
23977
|
+
fetch,
|
|
23978
|
+
env,
|
|
23979
|
+
home: homeDir(env)
|
|
23980
|
+
});
|
|
23981
|
+
} catch (err) {
|
|
23982
|
+
if (!(err instanceof UpgradeFailure)) throw err;
|
|
23983
|
+
process23.stderr.write(`rshow: ${err.message}
|
|
23984
|
+
`);
|
|
23985
|
+
return err.exit;
|
|
23986
|
+
}
|
|
23987
|
+
const report = reportOf(result);
|
|
23988
|
+
ctx.out.data(report.data);
|
|
23989
|
+
for (const line of report.lines) ctx.out.line(line);
|
|
23990
|
+
return EXIT.ok;
|
|
23991
|
+
}
|
|
23992
|
+
|
|
23993
|
+
// src/commands/logout.ts
|
|
23994
|
+
import process24 from "node:process";
|
|
23995
|
+
async function run22(argv, ctx, platform = process24.platform) {
|
|
23476
23996
|
const args = parseCommandArgs(argv, { url: { type: "string" } }, 0, 0, LOGOUT_USAGE);
|
|
23477
23997
|
const settings = await ctx.config();
|
|
23478
23998
|
const given = (stringValue(args, "url") ?? "").trim();
|
|
23479
23999
|
const url = (given === "" ? requireUrl(settings) : given).replace(/\/+$/, "");
|
|
23480
24000
|
const removed = [];
|
|
23481
|
-
for (const store2 of await every(
|
|
24001
|
+
for (const store2 of await every(process24.env, platform)) {
|
|
23482
24002
|
if (await store2.remove(url)) removed.push(store2.description);
|
|
23483
24003
|
}
|
|
23484
24004
|
if (removed.length === 0) {
|
|
@@ -23508,14 +24028,15 @@ var COMMANDS = {
|
|
|
23508
24028
|
pin: { usage: PIN_USAGE, run: run12 },
|
|
23509
24029
|
delete: { usage: DELETE_USAGE, run: run13 },
|
|
23510
24030
|
login: { usage: LOGIN_USAGE, run: run20 },
|
|
23511
|
-
logout: { usage: LOGOUT_USAGE, run:
|
|
24031
|
+
logout: { usage: LOGOUT_USAGE, run: run22 },
|
|
24032
|
+
upgrade: { usage: UPGRADE_USAGE, run: run21 },
|
|
23512
24033
|
completion: { usage: COMPLETION_USAGE, run: run19 },
|
|
23513
24034
|
// Kept out of the general help: the docs site runs it, a person rarely does.
|
|
23514
24035
|
docs: { usage: DOCS_USAGE, run: run18 }
|
|
23515
24036
|
};
|
|
23516
24037
|
function fail(err) {
|
|
23517
24038
|
const message = err instanceof Error ? err.message : String(err);
|
|
23518
|
-
|
|
24039
|
+
process25.stderr.write(`rshow: ${message}
|
|
23519
24040
|
`);
|
|
23520
24041
|
if (err instanceof UsageError) return EXIT.usage;
|
|
23521
24042
|
if (err instanceof CheckError) return EXIT.check;
|
|
@@ -23535,17 +24056,17 @@ async function main2(argv) {
|
|
|
23535
24056
|
const wantsVersion = versionAt >= 0 && (commandAt < 0 || versionAt < commandAt);
|
|
23536
24057
|
if (wantsVersion) {
|
|
23537
24058
|
const suffix = await isBinary() ? " (binary)" : "";
|
|
23538
|
-
|
|
24059
|
+
process25.stdout.write(`rshow ${VERSION}${suffix}
|
|
23539
24060
|
`);
|
|
23540
24061
|
return EXIT.ok;
|
|
23541
24062
|
}
|
|
23542
24063
|
if (wantsHelp) {
|
|
23543
|
-
|
|
24064
|
+
process25.stdout.write(`${spec === void 0 ? GENERAL_USAGE : spec.usage}
|
|
23544
24065
|
`);
|
|
23545
24066
|
return EXIT.ok;
|
|
23546
24067
|
}
|
|
23547
24068
|
if (name === void 0) {
|
|
23548
|
-
|
|
24069
|
+
process25.stderr.write(`${GENERAL_USAGE}
|
|
23549
24070
|
`);
|
|
23550
24071
|
return EXIT.usage;
|
|
23551
24072
|
}
|
|
@@ -23555,12 +24076,12 @@ async function main2(argv) {
|
|
|
23555
24076
|
const rest = [...args.slice(0, commandAt), ...args.slice(commandAt + 1)];
|
|
23556
24077
|
const configs = /* @__PURE__ */ new Map();
|
|
23557
24078
|
const clients = /* @__PURE__ */ new Map();
|
|
23558
|
-
const keyOf = (dir) => dir === void 0 ? "" :
|
|
24079
|
+
const keyOf = (dir) => dir === void 0 ? "" : path28.resolve(dir);
|
|
23559
24080
|
const configFor = (dir) => {
|
|
23560
24081
|
const key2 = keyOf(dir);
|
|
23561
24082
|
let pending = configs.get(key2);
|
|
23562
24083
|
if (pending === void 0) {
|
|
23563
|
-
pending = loadConfig(
|
|
24084
|
+
pending = loadConfig(process25.env, dir);
|
|
23564
24085
|
configs.set(key2, pending);
|
|
23565
24086
|
}
|
|
23566
24087
|
return pending;
|
|
@@ -23573,7 +24094,7 @@ async function main2(argv) {
|
|
|
23573
24094
|
if (cached !== void 0) return cached;
|
|
23574
24095
|
const settings = await configFor(dir);
|
|
23575
24096
|
const url = requireUrl(settings);
|
|
23576
|
-
const client = new Client(url, await readToken(
|
|
24097
|
+
const client = new Client(url, await readToken(process25.env, url));
|
|
23577
24098
|
clients.set(key2, client);
|
|
23578
24099
|
return client;
|
|
23579
24100
|
},
|
|
@@ -23582,11 +24103,11 @@ async function main2(argv) {
|
|
|
23582
24103
|
const code = await spec.run(rest, ctx);
|
|
23583
24104
|
return code ?? EXIT.ok;
|
|
23584
24105
|
}
|
|
23585
|
-
main2(
|
|
24106
|
+
main2(process25.argv.slice(2)).then(
|
|
23586
24107
|
(code) => {
|
|
23587
|
-
|
|
24108
|
+
process25.exitCode = code;
|
|
23588
24109
|
},
|
|
23589
24110
|
(err) => {
|
|
23590
|
-
|
|
24111
|
+
process25.exitCode = fail(err);
|
|
23591
24112
|
}
|
|
23592
24113
|
);
|
package/package.json
CHANGED
|
@@ -28,6 +28,7 @@ This file is the whole surface, both config files and the exit codes.
|
|
|
28
28
|
| `rshow config [dir] [--offline]` | print the merged config as JSON, with `theme` as `<name>@latest` and, with the network, `theme_resolved` as the version it resolves to |
|
|
29
29
|
| `rshow init --url <admin-url> --art <viewer-url>` | write the global config file, with `--theme` and `--force` |
|
|
30
30
|
| `rshow doctor [dir]` | check node, config, token, api, art, theme and skills, one `ok\|warn\|fail` line each |
|
|
31
|
+
| `rshow upgrade [--check] [--version x.y.z] [--force]` | replace the single executable, or run `npm install -g` on an npm install, with another release |
|
|
31
32
|
| `rshow list` | list artifacts you own or that are shared with you, with `--project`, `--tag` and `--q` filters |
|
|
32
33
|
| `rshow show <slug>` | print the artifact, its versions, its shares, its project and its tags |
|
|
33
34
|
| `rshow share <slug>` | set the mode, or add and remove shares |
|
|
@@ -51,6 +52,10 @@ This file is the whole surface, both config files and the exit codes.
|
|
|
51
52
|
`--help` on its own prints the general usage, and `--help` after a command prints that command.
|
|
52
53
|
`--json` is global and makes stdout the API reply, which is how a script reads a version number.
|
|
53
54
|
|
|
55
|
+
`rshow upgrade` moves an installed rshow to the newest release, or to the one `--version` names, and `--check` prints both versions and changes nothing.
|
|
56
|
+
It needs no config and no token, and a source checkout or an npx cache is named with the tool that owns it instead of being touched.
|
|
57
|
+
Run `rshow upgrade` only when the person asks for it.
|
|
58
|
+
|
|
54
59
|
Every flag takes `--flag value` or `--flag=value`.
|
|
55
60
|
`--add`, `--editor`, `--remove` and `--tag` accept several values in a row after one flag.
|
|
56
61
|
|
package/worker/index.js
CHANGED
|
@@ -3277,18 +3277,15 @@ __name(etagMatches, "etagMatches");
|
|
|
3277
3277
|
|
|
3278
3278
|
// src/cache.ts
|
|
3279
3279
|
var CACHE_ORIGIN = "https://rshow.internal";
|
|
3280
|
-
var ACCESS_TTL_MS = 15e3;
|
|
3281
|
-
var ACCESS_MAX_ENTRIES = 500;
|
|
3282
3280
|
var MANIFEST_MAX_ENTRIES = 200;
|
|
3283
3281
|
var VERSION_MAX_ENTRIES = 500;
|
|
3284
|
-
var ACCESS_CACHE_CONTROL = "max-age=
|
|
3282
|
+
var ACCESS_CACHE_CONTROL = "max-age=2";
|
|
3285
3283
|
var MANIFEST_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
3286
3284
|
var VERSION_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
3287
3285
|
var JSON_CONTENT_TYPE = "application/json";
|
|
3288
3286
|
var BLOB_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
3289
3287
|
var ARTIFACT_COLUMNS2 = "slug, title, owner, mode, pinned, latest, last_n, version_gen, project, created_at, updated_at";
|
|
3290
3288
|
var VERSION_COLUMNS = "slug, n, label, manifest_key, files, bytes, created_by, created_at";
|
|
3291
|
-
var accessMemory = /* @__PURE__ */ new Map();
|
|
3292
3289
|
var manifestMemory = /* @__PURE__ */ new Map();
|
|
3293
3290
|
var versionMemory = /* @__PURE__ */ new Map();
|
|
3294
3291
|
var versionKeys = /* @__PURE__ */ new Map();
|
|
@@ -3313,16 +3310,6 @@ function versionMemoryKey(slug, n, gen) {
|
|
|
3313
3310
|
return `${slug}/${n}/${gen}`;
|
|
3314
3311
|
}
|
|
3315
3312
|
__name(versionMemoryKey, "versionMemoryKey");
|
|
3316
|
-
function rememberAccess(slug, value, expires) {
|
|
3317
|
-
accessMemory.delete(slug);
|
|
3318
|
-
accessMemory.set(slug, { value, expires });
|
|
3319
|
-
while (accessMemory.size > ACCESS_MAX_ENTRIES) {
|
|
3320
|
-
const oldest = accessMemory.keys().next().value;
|
|
3321
|
-
if (oldest === void 0) break;
|
|
3322
|
-
accessMemory.delete(oldest);
|
|
3323
|
-
}
|
|
3324
|
-
}
|
|
3325
|
-
__name(rememberAccess, "rememberAccess");
|
|
3326
3313
|
function rememberManifest(key, value) {
|
|
3327
3314
|
manifestMemory.delete(key);
|
|
3328
3315
|
manifestMemory.set(key, value);
|
|
@@ -3453,30 +3440,18 @@ async function loadAccess(env, slug) {
|
|
|
3453
3440
|
}
|
|
3454
3441
|
__name(loadAccess, "loadAccess");
|
|
3455
3442
|
async function accessFor(env, slug) {
|
|
3456
|
-
const now = Date.now();
|
|
3457
|
-
const memory = accessMemory.get(slug);
|
|
3458
|
-
if (memory && memory.expires > now) {
|
|
3459
|
-
rememberAccess(slug, memory.value, memory.expires);
|
|
3460
|
-
return memory.value;
|
|
3461
|
-
}
|
|
3462
|
-
accessMemory.delete(slug);
|
|
3463
3443
|
const key = accessCacheKey(slug);
|
|
3464
3444
|
const cached = await cacheGet(key);
|
|
3465
3445
|
if (cached) {
|
|
3466
3446
|
const decoded = decodeAccess(await cached.text());
|
|
3467
|
-
if (decoded.ok)
|
|
3468
|
-
rememberAccess(slug, decoded.value, now + ACCESS_TTL_MS);
|
|
3469
|
-
return decoded.value;
|
|
3470
|
-
}
|
|
3447
|
+
if (decoded.ok) return decoded.value;
|
|
3471
3448
|
}
|
|
3472
3449
|
const value = await loadAccess(env, slug);
|
|
3473
|
-
rememberAccess(slug, value, now + ACCESS_TTL_MS);
|
|
3474
3450
|
await cachePut(key, JSON.stringify(value), ACCESS_CACHE_CONTROL);
|
|
3475
3451
|
return value;
|
|
3476
3452
|
}
|
|
3477
3453
|
__name(accessFor, "accessFor");
|
|
3478
3454
|
async function invalidateAccess(slug) {
|
|
3479
|
-
accessMemory.delete(slug);
|
|
3480
3455
|
const key = accessCacheKey(slug);
|
|
3481
3456
|
trackedKeys.delete(key);
|
|
3482
3457
|
try {
|
|
@@ -4036,10 +4011,11 @@ function registerArtifactCreate(app) {
|
|
|
4036
4011
|
const existing = await getArtifact(c.env, slug);
|
|
4037
4012
|
if (existing) return jsonError("slug is already taken", 409);
|
|
4038
4013
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4014
|
+
let counters;
|
|
4039
4015
|
try {
|
|
4040
|
-
await c.env.DB.prepare(
|
|
4041
|
-
"INSERT INTO artifacts (slug, title, owner, mode, pinned, latest, project, created_at, updated_at)
|
|
4042
|
-
).bind(slug, title2, email, MODE.private, project, now).
|
|
4016
|
+
counters = await c.env.DB.prepare(
|
|
4017
|
+
"INSERT INTO artifacts (slug, title, owner, mode, pinned, latest, last_n, version_gen, project, created_at, updated_at) SELECT ?1, ?2, ?3, ?4, NULL, NULL, COALESCE((SELECT last_n FROM retired_slugs WHERE slug = ?1), 0), COALESCE((SELECT version_gen FROM retired_slugs WHERE slug = ?1), 0), ?5, ?6, ?6 RETURNING last_n, version_gen"
|
|
4018
|
+
).bind(slug, title2, email, MODE.private, project, now).first();
|
|
4043
4019
|
} catch {
|
|
4044
4020
|
return jsonError("slug is already taken", 409);
|
|
4045
4021
|
}
|
|
@@ -4055,8 +4031,8 @@ function registerArtifactCreate(app) {
|
|
|
4055
4031
|
mode: MODE.private,
|
|
4056
4032
|
pinned: null,
|
|
4057
4033
|
latest: null,
|
|
4058
|
-
last_n: 0,
|
|
4059
|
-
version_gen: 0,
|
|
4034
|
+
last_n: counters?.last_n ?? 0,
|
|
4035
|
+
version_gen: counters?.version_gen ?? 0,
|
|
4060
4036
|
project,
|
|
4061
4037
|
created_at: now,
|
|
4062
4038
|
updated_at: now
|
|
@@ -4210,6 +4186,9 @@ function registerArtifactItem(app) {
|
|
|
4210
4186
|
if (keys.length > 0) await c.env.BUCKET.delete(keys);
|
|
4211
4187
|
await deleteArtifactData(c.env, access.artifact.slug);
|
|
4212
4188
|
await c.env.DB.batch([
|
|
4189
|
+
c.env.DB.prepare(
|
|
4190
|
+
"INSERT INTO retired_slugs (slug, last_n, version_gen) SELECT slug, MAX(last_n, COALESCE(latest, 0)), version_gen + 1 FROM artifacts WHERE slug = ?1 ON CONFLICT(slug) DO UPDATE SET last_n = excluded.last_n, version_gen = excluded.version_gen"
|
|
4191
|
+
).bind(access.artifact.slug),
|
|
4213
4192
|
c.env.DB.prepare("DELETE FROM page_data WHERE slug = ?1").bind(access.artifact.slug),
|
|
4214
4193
|
c.env.DB.prepare("DELETE FROM artifact_tags WHERE slug = ?1").bind(access.artifact.slug),
|
|
4215
4194
|
c.env.DB.prepare("DELETE FROM versions WHERE slug = ?1").bind(access.artifact.slug),
|