@orb44/cli 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,11 +13,11 @@ npx @orb44/cli login --url https://orb44.com
13
13
  Open the printed link in a browser where you are already signed in, confirm the domain, then optionally install the systemd daemon (default no). After a global install the command is `orb44`.
14
14
 
15
15
  ```bash
16
- npx @orb44/cli@0.1.7 status
17
- npx @orb44/cli@0.1.7 pulse
18
- npx @orb44/cli@0.1.7 install # later: background pulse, starts after reboot
16
+ npx @orb44/cli@0.1.8 status
17
+ npx @orb44/cli@0.1.8 pulse
18
+ npx @orb44/cli@0.1.8 install # later: background pulse, starts after reboot
19
19
  orb44 update # after install: replace /usr/lib/orb44-sat from npm
20
- npx @orb44/cli@0.1.7 logout
20
+ npx @orb44/cli@0.1.8 logout
21
21
  ```
22
22
 
23
23
  Do not run bare `npx @orb44/cli` — it can reuse an old cache. Pin the version or use `orb44` after install.
package/bin/orb44.mjs CHANGED
@@ -169,6 +169,8 @@ function printAdvice(notes) {
169
169
 
170
170
  async function sendPulse(device, { preview = true } = {}) {
171
171
  const pulse = collectPulse();
172
+ const ver = readCliVersion(SCRIPT);
173
+ if (ver && ver !== "0.0.0") pulse.cliVersion = ver;
172
174
  if (preview) {
173
175
  console.log(bold("📡 " + t(lang, "payload")));
174
176
  console.log(formatPulsePreview(pulse, lang));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orb44/cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Orb44: street snapshot of your site. This CLI is the Watch satellite — pulse from the host (load, listeners, hardening). The cabinet does not run commands on the machine.",
5
5
  "type": "module",
6
6
  "bin": {
package/server/pulse.mjs CHANGED
@@ -266,6 +266,7 @@ export function sanitizePulse(raw = {}) {
266
266
  const limited = Boolean(raw.limited);
267
267
  const oom = Boolean(raw.oom) || hardening.oomKills > 0;
268
268
  const pressure = sanitizePressure(raw.pressure || raw);
269
+ const cliVersion = sanitizeCliVersion(raw.cliVersion);
269
270
  const base = {
270
271
  ts: Number(raw.ts) || Date.now(),
271
272
  hostname: sanitizeComm(raw.hostname) || os.hostname().slice(0, 40),
@@ -281,10 +282,18 @@ export function sanitizePulse(raw = {}) {
281
282
  limited,
282
283
  hardening,
283
284
  pressure,
285
+ cliVersion,
284
286
  };
285
287
  return { ...base, gradeInside: gradeInside(base) };
286
288
  }
287
289
 
290
+ function sanitizeCliVersion(raw) {
291
+ const v = String(raw || "").trim();
292
+ if (!/^\d{1,3}\.\d{1,3}\.\d{1,3}(-[a-z0-9.]+)?$/i.test(v)) return null;
293
+ if (v === "0.0.0") return null;
294
+ return v.slice(0, 32);
295
+ }
296
+
288
297
  const ADMIN_PORTS = new Set([2019, 2375, 2376, 3306, 5432, 6379, 27017, 9200, 11211, 15672, 8500, 2379, 6443, 9090, 5601, 7474, 7687, 1080, 6432]);
289
298
 
290
299
  const SERVICE_NAME = {
@@ -104,13 +104,35 @@ export async function fetchLatestMeta(fetchFn = fetch) {
104
104
  const version = j?.version;
105
105
  const tarball = j?.dist?.tarball;
106
106
  if (!version || !tarball) throw new Error("registry meta");
107
- return { version: String(version), tarball: String(tarball) };
107
+ return { version: String(version), tarball: canonicalTarballUrl(tarball) };
108
108
  }
109
109
 
110
- export async function unpackTarball(url, tmp, fetchFn = fetch) {
111
- const r = await fetchFn(url);
112
- if (!r?.ok) throw new Error(`tarball ${r?.status || "fail"}`);
113
- const buf = Buffer.from(await r.arrayBuffer());
110
+ /** npm metadata uses /@scope/name/; GET of the tarball is more reliable as /@scope%2fname/. */
111
+ export function canonicalTarballUrl(url) {
112
+ try {
113
+ const u = new URL(String(url));
114
+ u.pathname = u.pathname.replace(/^\/@([^/]+)\/([^/]+)\//, "/@$1%2f$2/");
115
+ return u.href;
116
+ } catch {
117
+ return String(url || "");
118
+ }
119
+ }
120
+
121
+ export async function unpackTarball(url, tmp, fetchFn = fetch, { retries = 4, delayMs = 1500 } = {}) {
122
+ const href = canonicalTarballUrl(url);
123
+ let last = "fail";
124
+ let buf = null;
125
+ for (let i = 0; i < retries; i++) {
126
+ const r = await fetchFn(href);
127
+ last = r?.status || "fail";
128
+ if (r?.ok) {
129
+ buf = Buffer.from(await r.arrayBuffer());
130
+ break;
131
+ }
132
+ if (Number(last) !== 404 && Number(last) !== 429) break;
133
+ if (i < retries - 1 && delayMs) await new Promise((ok) => setTimeout(ok, delayMs * (i + 1)));
134
+ }
135
+ if (!buf) throw new Error(`tarball ${last}`);
114
136
  const tgz = path.join(tmp, "pkg.tgz");
115
137
  fs.writeFileSync(tgz, buf);
116
138
  const unpack = path.join(tmp, "unpack");