@faable/faable 4.9.0 → 4.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import ora from 'ora';
2
2
  import { version } from '../../config.js';
3
3
  import { isDevBuild, getLatestVersion, isNewerVersion, CLI_PACKAGE } from '../../lib/UpdateChecker.js';
4
- import { cmd } from '../../lib/cmd.js';
4
+ import { upgradeTo, npmDeps } from '../../lib/self_upgrade.js';
5
5
  import { log } from '../../log.js';
6
6
 
7
7
  const upgrade = {
@@ -22,15 +22,25 @@ const upgrade = {
22
22
  return;
23
23
  }
24
24
  const spinner = ora(`Upgrading ${CLI_PACKAGE} ${version} → ${latest}`).start();
25
- try {
26
- await cmd(`npm install -g --prefer-online ${CLI_PACKAGE}@latest`, { timeout: 180_000 });
25
+ const res = await upgradeTo(latest, npmDeps, {
26
+ onRetry: () => {
27
+ spinner.text = `${latest} was just published and the npm registry is still propagating it — retrying…`;
28
+ },
29
+ });
30
+ if (res.ok) {
27
31
  spinner.succeed(`Upgraded to ${latest}`);
32
+ return;
28
33
  }
29
- catch {
30
- spinner.fail("Upgrade failed");
31
- log.error(`❌ Could not upgrade automatically. Try manually: npm install -g --prefer-online ${CLI_PACKAGE}@latest`);
32
- process.exit(1);
34
+ spinner.fail("Upgrade failed");
35
+ if (res.reason === "not_propagated") {
36
+ log.error(`❌ ${latest} is not available from the npm registry yet (still on ${res.installed ?? version}). A release takes a few minutes to propagate — run \`faable upgrade\` again shortly.`);
37
+ }
38
+ else {
39
+ if (res.output)
40
+ log.error(res.output.trim());
41
+ log.error(`❌ Could not upgrade automatically. Try manually: npm install -g ${CLI_PACKAGE}@${latest}`);
33
42
  }
43
+ process.exit(1);
34
44
  },
35
45
  };
36
46
 
@@ -0,0 +1,51 @@
1
+ import { execFile } from 'child_process';
2
+ import { CLI_PACKAGE } from './UpdateChecker.js';
3
+
4
+ // npm's ways of saying "that version does not exist (here, yet)".
5
+ const NOT_FOUND = /ETARGET|notarget|No matching version|E404/i;
6
+ const upgradeTo = async (target, deps, { attempts = 5, wait_ms = 30_000, onRetry = (_n) => { } } = {}) => {
7
+ let output = "";
8
+ for (let n = 1; n <= attempts; n++) {
9
+ const res = await deps.install(target);
10
+ output = res.output;
11
+ if (res.ok) {
12
+ const installed = await deps.installed();
13
+ if (installed === target)
14
+ return { ok: true, attempts: n };
15
+ // npm said yes and changed nothing: the same lag, from another angle.
16
+ }
17
+ else if (!NOT_FOUND.test(res.output)) {
18
+ return { ok: false, reason: "install_failed", output };
19
+ }
20
+ if (n < attempts) {
21
+ onRetry(n);
22
+ await deps.sleep(wait_ms);
23
+ }
24
+ }
25
+ return {
26
+ ok: false,
27
+ reason: "not_propagated",
28
+ output,
29
+ installed: await deps.installed(),
30
+ };
31
+ };
32
+ const run = (file, args, timeout) => new Promise((resolve) => {
33
+ execFile(file, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => resolve({ ok: !err, output: `${stdout ?? ""}${stderr ?? ""}` }));
34
+ });
35
+ const npm = process.platform === "win32" ? "npm.cmd" : "npm";
36
+ /** The real thing: global npm. */
37
+ const npmDeps = {
38
+ install: (version) => run(npm, ["install", "-g", "--prefer-online", `${CLI_PACKAGE}@${version}`], 180_000),
39
+ installed: async () => {
40
+ const res = await run(npm, ["ls", "-g", "--json", "--depth=0", CLI_PACKAGE], 30_000);
41
+ try {
42
+ return JSON.parse(res.output).dependencies?.[CLI_PACKAGE]?.version;
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ },
48
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
49
+ };
50
+
51
+ export { npmDeps, upgradeTo };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faable/faable",
3
- "version": "4.9.0",
3
+ "version": "4.9.1",
4
4
  "main": "dist/index.js",
5
5
  "license": "MIT",
6
6
  "author": "Marc Pomar <marc@faable.com>",