@threadbase-sh/streamer 1.86.0 → 1.86.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadbase-sh/streamer",
3
- "version": "1.86.0",
3
+ "version": "1.86.1",
4
4
  "description": "PTY session management, WebSocket streaming, and REST API server for Claude Code conversations",
5
5
  "license": "MIT",
6
6
  "author": "Ronen Mars",
@@ -37,7 +37,9 @@
37
37
  }
38
38
  },
39
39
  "files": [
40
- "dist"
40
+ "dist",
41
+ "scripts/check-node-version.mjs",
42
+ "scripts/check-native-abi.mjs"
41
43
  ],
42
44
  "publishConfig": {
43
45
  "access": "public"
@@ -0,0 +1,56 @@
1
+ // Guards against a stale `better-sqlite3` native binary — one compiled for a
2
+ // different Node ABI / OS / arch than the one running now (moved repo, upgraded
3
+ // Node). Such a binary fails at require-time with a cryptic NODE_MODULE_VERSION
4
+ // error deep in the server; this surfaces it up front with the fix command.
5
+ //
6
+ // Wired into `preinstall` (catch a no-op install that leaves a stale binary)
7
+ // and `pretest` (fail fast instead of paying an unconditional rebuild).
8
+ //
9
+ // ponytail: only better-sqlite3 is checked. node-pty ships N-API prebuilds
10
+ // (node-addon-api, .node files selected by platform-arch, ABI-stable across
11
+ // Node versions) so it can't hit a NODE_MODULE_VERSION mismatch.
12
+ import { spawnSync } from "node:child_process";
13
+ import { existsSync } from "node:fs";
14
+ import { dirname, join } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ // --warn downgrades the failure to a notice. Used by `preinstall`, because
18
+ // `npm install` is one of the two remedies this check recommends — failing the
19
+ // install hard makes the guard block its own fix, and the only escape becomes
20
+ // `rm -rf node_modules` (the guard exits 0 when no binary exists at all).
21
+ const warnOnly = process.argv.includes("--warn");
22
+
23
+ const PKG = "better-sqlite3";
24
+ const root = join(dirname(fileURLToPath(import.meta.url)), "..");
25
+ const binary = join(root, "node_modules", PKG, "build", "Release", "better_sqlite3.node");
26
+
27
+ // Fresh install (no node_modules yet, or package not installed): nothing to
28
+ // compare against — a real install/rebuild will produce a matching binary.
29
+ if (!existsSync(binary)) process.exit(0);
30
+
31
+ // The authoritative test is whether *this* Node can dlopen the binary. A child
32
+ // process isolates the (possibly fatal) load. dlopen failing on a binary that
33
+ // exists means an ABI/OS/arch mismatch (NODE_MODULE_VERSION, wrong mach-o/ELF)
34
+ // — exactly what this guard is for. exit 3 = dlopen threw; anything else (spawn
35
+ // failure, unrelated crash) shouldn't block install/test.
36
+ const probe = `try { process.dlopen({ exports: {} }, ${JSON.stringify(binary)}); }
37
+ catch (e) { process.stderr.write(String(e && e.message || e)); process.exit(3); }`;
38
+ const res = spawnSync(process.execPath, ["-e", probe], { encoding: "utf8" });
39
+
40
+ if (res.status !== 3) process.exit(0);
41
+
42
+ const err = (res.stderr || "").trim();
43
+ console.error(`
44
+ ${warnOnly ? "⚠" : "✖"} ${PKG} native binary is incompatible with this Node.
45
+
46
+ Expected: Node ABI ${process.versions.modules} ${process.platform}/${process.arch} (node ${process.version})
47
+ Binary: ${binary}
48
+ Loader error: ${err.replace(/\s+/g, " ").slice(0, 300)}
49
+
50
+ The compiled binary was built for a different Node version, OS, or CPU arch.
51
+ Fix it with one of:
52
+
53
+ npm rebuild ${PKG}
54
+ rm -rf node_modules && npm install
55
+ `);
56
+ process.exit(warnOnly ? 0 : 1);
@@ -0,0 +1,60 @@
1
+ // Guards against running a build, test or deploy under a Node outside the
2
+ // range this repo supports.
3
+ //
4
+ // The authority is `engines.node` in package.json — the same declaration npm
5
+ // checks — because that is the range CI actually exercises. `.nvmrc` is the
6
+ // exact version to develop against and is quoted as the suggestion, but it is
7
+ // deliberately NOT the test: CI runs the matrix on several supported majors,
8
+ // and a guard keyed to the single pinned version would reject them.
9
+ //
10
+ // Why this exists when `engines` already exists: npm only enforces it when the
11
+ // consumer opts into `engine-strict`, and it never enforces it for a bare
12
+ // `node scripts/…` invocation. `scripts/deploy.sh` runs in a subshell that does
13
+ // not load nvm's lazy-init function, so its `node` is whatever the system
14
+ // provides — which is how a deploy ends up building native modules for an ABI
15
+ // the service cannot load, then "fixing" it with a rebuild that breaks the
16
+ // other side. See docs/troubleshooting.md, "Native modules / ABI mismatches".
17
+ //
18
+ // ponytail: major-only bounds parsed from `>=A <B`, no semver dependency. Every
19
+ // ABI break this guards against is a major change. If the range is ever written
20
+ // in a shape this cannot parse, the check disables itself rather than guessing
21
+ // — its absence is the status quo, a wrong verdict is not.
22
+ import { readFileSync } from "node:fs";
23
+ import { dirname, join } from "node:path";
24
+ import { fileURLToPath } from "node:url";
25
+
26
+ const warnOnly = process.argv.includes("--warn");
27
+ const root = join(dirname(fileURLToPath(import.meta.url)), "..");
28
+
29
+ const read = (file) => {
30
+ try {
31
+ return readFileSync(join(root, file), "utf8");
32
+ } catch {
33
+ return null;
34
+ }
35
+ };
36
+
37
+ const pkg = read("package.json");
38
+ const range = pkg ? (JSON.parse(pkg).engines?.node ?? "") : "";
39
+ const min = range.match(/>=\s*(\d+)/)?.[1];
40
+ const max = range.match(/<\s*(\d+)/)?.[1];
41
+ if (!min && !max) process.exit(0); // Unparseable or absent — nothing to enforce.
42
+
43
+ const major = Number(process.versions.node.split(".")[0]);
44
+ if ((!min || major >= Number(min)) && (!max || major < Number(max))) process.exit(0);
45
+
46
+ const suggested = read(".nvmrc")?.trim().replace(/^v/, "");
47
+ console.error(`
48
+ ${warnOnly ? "⚠" : "✖"} Node ${process.version} is outside the range this repo supports (${range}).
49
+
50
+ Running: ${process.execPath}
51
+ Develop against: ${suggested ? `v${suggested} (.nvmrc)` : `Node ${min ?? "?"}.x`}
52
+
53
+ Native modules are compiled per Node ABI, so building or deploying here produces
54
+ binaries the supported Node cannot load — and the reverse. Switch before continuing:
55
+
56
+ nvm use # or: fnm use / asdf install
57
+ nvm-windows: nvm use ${suggested?.split(".")[0] ?? min} (no auto-cd hook — it must be explicit)
58
+ `);
59
+
60
+ process.exit(warnOnly ? 0 : 1);