Skip to content

fix(scripts): narrow napi targets instead of staging placeholder binaries - #1664

Merged
popescuoctavian merged 3 commits into
mainfrom
fix/verdaccio-publish-napi-cli-3.8
Aug 25, 2026
Merged

fix(scripts): narrow napi targets instead of staging placeholder binaries#1664
popescuoctavian merged 3 commits into
mainfrom
fix/verdaccio-publish-napi-cli-3.8

Conversation

@popescuoctavian

@popescuoctavian popescuoctavian commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Fixes the Regression benchmark job on main, broken since #1650 bumped
@napi-rs/cli to 3.8.6 (first surfaced on #1648's run, the first to actually
execute the job after the bump):

Internal Error: Release package @nomicfoundation/edr-darwin-arm64 is incomplete: missing edr.darwin-arm64.node

@napi-rs/cli >= 3.8 validates during pre-publish that every target in
napi.targets has its .node binary staged — unconditionally, regardless of
--skip-optional-publish. #1650 fixed this for the release workflow by moving
pnpm artifacts before prepublish.sh, but the Verdaccio flow only ever
builds one binary, so validation fails on the first missing platform.

Fix: stage empty placeholder .node files for the platforms that weren't
built, run prepublish.sh unmodified — so pre-publish sees the exact same
configuration as a real release — then delete the placeholders. They can never
be published: prepublish.sh passes --skip-optional-publish, the script only
publishes the host's platform package, and they're removed right after
pre-publish returns. The existing optionalDependencies prune loop is kept
unchanged. This avoids hardcoding the platform→triple mapping and keeps the
Verdaccio route as close as possible to the real publish flow.

Verified locally against @napi-rs/cli 3.8.6: without placeholders,
pre-publish reproduces the exact CI error; with them it succeeds, and the
resulting package state (versions, optionalDependencies) is identical to
what the script produced before the CLI bump.

@popescuoctavian
popescuoctavian requested a review from Wodann August 24, 2026 13:20
@popescuoctavian popescuoctavian self-assigned this Aug 24, 2026
@popescuoctavian popescuoctavian added the no changeset needed This PR doesn't require a changeset label Aug 24, 2026
@changeset-bot

changeset-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1cb634f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@popescuoctavian
popescuoctavian temporarily deployed to github-action-benchmark August 24, 2026 13:20 — with GitHub Actions Inactive
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.01%. Comparing base (617568b) to head (1cb634f).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1664      +/-   ##
==========================================
- Coverage   80.02%   80.01%   -0.01%     
==========================================
  Files         464      464              
  Lines       80392    80392              
  Branches    80392    80392              
==========================================
- Hits        64332    64325       -7     
- Misses      13854    13860       +6     
- Partials     2206     2207       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Wodann Wodann left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a fix for this problem that:

  1. doesn't duplicate the supported platform "triples" into this script; and
  2. keeps the verdaccio publish route as close as possible to the real publish script?

@popescuoctavian
popescuoctavian force-pushed the fix/verdaccio-publish-napi-cli-3.8 branch from 0d0ca33 to ee6be45 Compare August 24, 2026 14:18
@popescuoctavian
popescuoctavian temporarily deployed to github-action-benchmark August 24, 2026 14:18 — with GitHub Actions Inactive
@popescuoctavian
popescuoctavian requested a review from Wodann August 24, 2026 14:18
@popescuoctavian

Copy link
Copy Markdown
Contributor Author

@Wodann I've pushed a different approach, which adds placeholders for missing binaries. This keeps the implementation closer to real publishing.

@popescuoctavian popescuoctavian changed the title fix(scripts): prune napi.targets to the host platform in publish_to_verdaccio.sh fix(scripts): stage placeholder binaries for napi pre-publish in publish_to_verdaccio.sh Aug 24, 2026
@popescuoctavian
popescuoctavian temporarily deployed to github-action-benchmark August 24, 2026 14:50 — with GitHub Actions Inactive
@popescuoctavian
popescuoctavian temporarily deployed to github-action-benchmark August 24, 2026 14:50 — with GitHub Actions Inactive
@Wodann
Wodann had a problem deploying to github-action-benchmark August 25, 2026 07:14 — with GitHub Actions Error
@Wodann Wodann changed the title fix(scripts): stage placeholder binaries for napi pre-publish in publish_to_verdaccio.sh fix(scripts): narrow napi targets instead of staging placeholder binaries Aug 25, 2026
@Wodann
Wodann force-pushed the fix/verdaccio-publish-napi-cli-3.8 branch from 2ddc413 to 501fd0a Compare August 25, 2026 07:22
@Wodann
Wodann temporarily deployed to github-action-benchmark August 25, 2026 07:22 — with GitHub Actions Inactive
@Wodann
Wodann had a problem deploying to github-action-benchmark August 25, 2026 07:32 — with GitHub Actions Failure
@Wodann
Wodann had a problem deploying to github-action-benchmark August 25, 2026 07:32 — with GitHub Actions Error
@Wodann
Wodann force-pushed the fix/verdaccio-publish-napi-cli-3.8 branch from 501fd0a to 826cf07 Compare August 25, 2026 08:01
@Wodann
Wodann had a problem deploying to github-action-benchmark August 25, 2026 08:01 — with GitHub Actions Error
…ries

`@napi-rs/cli` >= 3.8 validates during pre-publish that every target in
`napi.targets` has its .node binary staged, and `--skip-optional-publish`
does not exempt them. There is no flag to skip that validation: `prePublish`
loops over every target from `readNapiConfig` and calls
`validateReleasePackageContents` unconditionally.

Rather than staging empty placeholders for the platforms this host did not
build, generate a config listing only this host's target and pass it via
`--config-path`, so the other platforms are never considered. The target
list is still derived from `napi.targets` (mapped to a platform package
suffix with napi's exported `parseTriple`), so adding a platform needs no
change here.

Narrowing the targets also makes the `optionalDependencies` pruning loop
redundant: `napi pre-publish` wires exactly the configured targets, so only
this host's platform package is ever added. It leaves 2 tracked files
modified rather than 8 — the full target list version-syncs all 7
`npm/*/package.json`, 6 of which are never published.

The config is written by `scripts/write_napi_host_config.ts`, following the
Hardhat repo's precedent of running TypeScript scripts directly with `node`.
`scripts/package.json` marks that directory as ESM; the repo root cannot be
`type: module` because `config/eslint/eslintrc.js` and `.syncpackrc.js` are
CommonJS. `scripts/tsconfig.json` and the `tsc:scripts` / `test:scripts`
entries give the directory the type-checking, formatting and test coverage
Hardhat's scripts have.

The tests cover the suffix-to-target lookup, the emitted config (including
feeding it to napi's own `readNapiConfig`, which the approach depends on
merging rather than replacing `package.json`'s `napi` field), the CLI's exit
codes, and the invariant that `napi.targets` and `crates/edr_napi/npm/` stay
in sync.

`engines.node` moves to >=22.18.0, the first release where Node runs
TypeScript without a flag.

`scripts/prepublish.sh` now forwards its arguments to `napi pre-publish`;
the release workflow passes none, so that path is unchanged.
@Wodann
Wodann force-pushed the fix/verdaccio-publish-napi-cli-3.8 branch from 826cf07 to b9a65f4 Compare August 25, 2026 08:04
@Wodann
Wodann had a problem deploying to github-action-benchmark August 25, 2026 08:04 — with GitHub Actions Error
@Wodann

Wodann commented Aug 25, 2026

Copy link
Copy Markdown
Member

Alternative: narrow napi.targets for this one invocation

Pushed as b9a65f4.

There's no flag to skip the pre-publish validation — prePublish() loops over every target from readNapiConfig and calls validateReleasePackageContents unconditionally (src/api/pre-publish.ts:342), and none of the documented options (--skip-optional-publish, --dry-run, --npm-dir, …) gate it. But --config-path overrides napi.targets for that invocation, so the other platforms are never considered in the first place.

Change

  • scripts/write_napi_host_config.ts writes a config naming only this host's target, looked up in napi.targets via napi's exported parseTriple — so adding a platform still needs no change here. It follows the Hardhat repo's precedent of running TypeScript scripts directly with node.
  • scripts/publish_to_verdaccio.sh calls it into a mktemp file (removed by an EXIT trap), checks the file is non-empty, and passes --config-path.
  • scripts/prepublish.sh forwards "$@" to napi pre-publish. The release workflow calls it with no args, so that path is unchanged.
  • scripts/tsconfig.json + tsc:scripts / test:scripts give scripts/ the type-checking, formatting and test coverage Hardhat's scripts have. scripts/package.json marks the directory ESM — the repo root can't be type: module because config/eslint/eslintrc.js and .syncpackrc.js are CommonJS.
  • engines.node moves to >=22.18.0, the first release where Node runs TypeScript without a flag. Every CI job is already on 24.

Why this over placeholders

  • No fake .node files on disk. Validation currently only does existsSync, but it already reads binary contents for wasm targets, so empty placeholders are betting on that not spreading to node targets.
  • The npm pkg delete optionalDependencies.… pruning loop becomes unnecessary — resolveRootOptionalDependencies wires exactly the configured targets, so only this host's is ever added.
  • Smaller blast radius on the working tree: 2 tracked files modified (root + host platform package.json) instead of 8 — with the full target list, napi version-syncs all 7 npm/*/package.json even though 6 are never published.

Tests (24, ~0.8s, no Rust build and no Verdaccio needed)

  • The suffix→target lookup, and the emitted config's exact bytes.
  • The CLI's exit codes and its refusal to write a config when no target matches.
  • The emitted config fed to napi's own readNapiConfig, asserting binaryName survives — see caveat 1.
  • The invariant that napi.targets and crates/edr_napi/npm/ stay in sync, generated from the real directory listing, so adding a platform to one and not the other fails with a named test.

Two things worth a look in review:

  1. napi prints

    Both napi field in crates/edr_napi/package.json and NAPI-RS config file are found, the NAPI-RS config file will be used.

    The message overstates it — the merge is a shallow Object.assign over pkgJson.napi (src/utils/config.ts:283), so binaryName and everything else survive and only targets is overridden. That's load-bearing, so there's a test pinning it: if an upgrade made it a true replacement, binaryName would silently fall back to "index" and pre-publish would look for the wrong .node.

  2. scripts/package.json is a 5-line ESM marker, not a workspace package (the pnpm globs don't cover scripts/, and it's private). Without it, node scripts/*.ts warns MODULE_TYPELESS_PACKAGE_JSON on every run.

Unrelated sharp edge found while testing: after running publish_to_verdaccio.sh locally, crates/edr_napi/package.json is left at the local version with an injected optionalDependencies, and pnpm run lint is green on that state — no prettier glob or syncpack rule covers crates/**/package.json. A git commit -a would ship a version downgrade of the published package. The script's header does say to run git checkout -- crates/edr_napi afterwards; might be worth making that harder to miss.

@Wodann
Wodann had a problem deploying to github-action-benchmark August 25, 2026 08:27 — with GitHub Actions Error
@Wodann

Wodann commented Aug 25, 2026

Copy link
Copy Markdown
Member

/bench

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Starting regression benchmark for 1cb634f10f69 against Hardhat main (benchmarks matching test solidity,test mocha,test vitest).

@github-actions

Copy link
Copy Markdown
Contributor

✅ Regression benchmark passed for 1cb634f10f69 against Hardhat main.

View workflow run

@popescuoctavian
popescuoctavian added this pull request to the merge queue Aug 25, 2026
Merged via the queue into main with commit 568f28a Aug 25, 2026
62 of 63 checks passed
@popescuoctavian
popescuoctavian deleted the fix/verdaccio-publish-napi-cli-3.8 branch August 25, 2026 10:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changeset needed This PR doesn't require a changeset

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants