Skip to content

Add npm run fetch-prebuild so JS-only contributions need no C++ toolchain - #454

Merged
TimelordUK merged 1 commit into
masterfrom
feat/fetch-prebuild-for-js-devs
Sep 13, 2026
Merged

TimelordUK merged 1 commit into
masterfrom
feat/fetch-prebuild-for-js-devs

Conversation

@TimelordUK

Copy link
Copy Markdown
Owner

Bundling the binaries in #451 regressed the contributor workflow. I missed this in 5.5.0.

Before: a dev install in a clone pulled down a usable binary as a side effect of prebuild-install running as the install script. You could patch lib/ without ever compiling.

Now: a fresh clone tracks neither prebuilds/ nor build/, the install script is node-gyp-build, and that compiles from source when it finds no binary. So anyone wanting to patch the JavaScript is pushed into a full C++ build, and requiring the driver before that succeeds fails with:

Error: No native build was found for platform=win32 arch=x64 runtime=node abi=137 uv=1 libc=glibc node=24.15.0

The old fallback of grabbing a tarball from the release page is gone too — gh release view v5.5.0 --json assets returns 0.

The fix

The binary does still exist somewhere a contributor can use it: inside the published npm package.

npm install --ignore-scripts
npm run fetch-prebuild            # latest published
npm run fetch-prebuild -- 5.5.0   # pinned

This deliberately does not restore an automatic download on install — that's the behaviour 5.5.0 set out to remove for consumers. It's an explicit, opt-in dev step.

node-gyp-build resolves build/Release → build/Debug → prebuilds/, so a fetched binary is used only while you haven't built from source. Run npm run rebuild later and your own build wins automatically, with nothing to undo.

Two Windows gotchas, both hit while building this

  • It talks to the registry over https rather than shelling out to npm. Spawning npm.cmd from Node fails with EINVAL unless a shell is used — a consequence of the CVE-2024-27980 fix. My first attempt did exactly that and died.
  • It runs tar with cwd set and a bare filename, never an absolute path. GNU tar reads D:\... as a remote host:path and dies with Cannot connect to D:. Relative names suit both GNU tar and the bsdtar in System32, so this works outside Git Bash too.

Verification, not assumption

The script resolves the binary through node-gyp-build, loads lib/sql.js and checks the export count — it can't report success on the strength of having copied some files. It also says when an existing build/ takes precedence rather than silently looking wrong.

Nothing is deleted until the fetched package is known to contain prebuilds/, so a bad version argument can't destroy a working tree.

Tested from a genuinely empty tree (build/ and prebuilds/ both moved aside):

case result
clean tree, latest 4 binaries written, resolves prebuilds/win32-x64, loads, 46 exports
explicit 5.5.0 same
5.4.0 (pre-bundling) clear error, existing prebuilds/ left intact
9.9.9 not found on the registry
with a real build/Release/*.node resolves build/Release, reports precedence

Note

The rest of CONTRIBUTING.md is stale Microsoft boilerplate — it references WindowsAzure/node-sqlserver, a Microsoft CLA, and a git submit command that doesn't exist. I only added the new section rather than rewriting it; that's a separate job, probably alongside the wiki.

🤖 Generated with Claude Code

https://claude.ai/code/session_01K5wuZia58hUzEqN7CvHtz9

…olchain

Bundling the binaries regressed the contributor workflow, which I missed in
5.5.0.

Before, a dev install in a clone pulled a usable binary down as a side effect
of prebuild-install running as the install script. That is gone. A fresh clone
tracks neither prebuilds/ nor build/, the install script is now
node-gyp-build, and node-gyp-build compiles from source when it finds no
binary. So anyone wanting to patch lib/ was pushed into a full C++ build, and
requiring the driver before that fails with "No native build was found for
platform=...". The old fallback of grabbing a tarball from the GitHub release
page is gone too, since releases no longer carry per-platform assets.

The binary does still exist in a form a contributor can use: inside the
published npm package. tools/fetch-prebuild.js downloads it and copies
prebuilds/ into the working tree.

  npm install --ignore-scripts
  npm run fetch-prebuild            # latest published
  npm run fetch-prebuild -- 5.5.0   # pinned

This deliberately does not restore an automatic download on install: that is
the behaviour 5.5.0 set out to remove for consumers. It is an explicit,
opt-in dev step.

Implementation notes, both learned the hard way on Windows:

  - It talks to the registry over https rather than shelling out to npm.
    Spawning npm.cmd from Node fails with EINVAL unless a shell is used, a
    consequence of the CVE-2024-27980 fix.
  - It runs tar with cwd set and a bare filename, never an absolute path.
    GNU tar reads "D:\..." as a remote host:path and dies with "Cannot
    connect to D:". Relative names suit both GNU tar and the bsdtar in
    System32, so this works outside Git Bash too.

The script verifies rather than assumes: it resolves the binary through
node-gyp-build, loads lib/sql.js, and checks the export count, so it cannot
report success on the strength of having copied some files. It also reports
when an existing build/ takes precedence instead of silently looking wrong.

Nothing is deleted until the fetched package is known to contain prebuilds/,
so a bad version argument cannot destroy a working tree. Verified: fetching
5.4.0 fails with a clear message and leaves the existing prebuilds/ intact.

CONTRIBUTING.md gains a "Setting up a development build" section covering
this, the resolution order, and when you genuinely do have to build from
source. Note the rest of that file is stale Microsoft boilerplate - it still
references WindowsAzure/node-sqlserver, a Microsoft CLA and a `git submit`
command that does not exist - and wants rewriting separately.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5wuZia58hUzEqN7CvHtz9
@TimelordUK
TimelordUK merged commit c6e4310 into master Sep 13, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant