Skip to content

feat: first blood, should just work#3

Merged
JounQin merged 2 commits intomainfrom
feat/work
Apr 19, 2025
Merged

feat: first blood, should just work#3
JounQin merged 2 commits intomainfrom
feat/work

Conversation

@JounQin
Copy link
Member

@JounQin JounQin commented Apr 19, 2025

Summary by CodeRabbit

  • New Features
    • Introduced a CLI command for package preparation.
    • Added robust fallback mechanisms to ensure native binaries are installed and available.
    • Provided TypeScript types and parsing utilities for native target triples.
  • Bug Fixes
    • Improved handling and detection of missing native binaries and dependencies.
  • Refactor
    • Renamed the package and project from "native-postinstall" to "napi-postinstall".
    • Switched package module type to CommonJS and updated export mappings.
    • Reorganized and enhanced build, test, and release workflows for better reliability.
  • Documentation
    • Updated README with new usage instructions, CLI examples, and expanded API documentation.
  • Chores
    • Improved .gitignore and .prettierignore settings.
    • Updated devDependencies and removed unused configuration files.
  • Tests
    • Rewrote and expanded test coverage for the package preparation process.

@JounQin JounQin requested a review from Copilot April 19, 2025 16:25
@changeset-bot
Copy link

changeset-bot bot commented Apr 19, 2025

🦋 Changeset detected

Latest commit: 8c06cd5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
napi-postinstall Minor

Not sure what this means? Click here to learn what changesets are.

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

@coderabbitai
Copy link

coderabbitai bot commented Apr 19, 2025

Warning

Rate limit exceeded

@JounQin has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 55 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 337d7f3 and 8c06cd5.

📒 Files selected for processing (1)
  • .changeset/solid-eagles-roll.md (1 hunks)

Walkthrough

This update introduces a comprehensive refactor and rebranding of the project from native-postinstall to napi-postinstall. The changes include renaming and updating all references to the new package name, restructuring the package for CommonJS compatibility, and introducing a CLI entry point. Several new modules are added to support native binary management, target parsing, and helper utilities. The project configuration files, including ESLint, Prettier, TypeScript, and GitHub Actions workflows, are updated for improved consistency, reliability, and CI/CD performance. Documentation is expanded to reflect the new features and usage patterns, while test coverage is updated to validate the new functionality.

Changes

File(s) Change Summary
.changeset/config.json, vercel.json, README.md, package.json Renamed project from native-postinstall to napi-postinstall across config, documentation, and metadata. Updated repository links, badges, and CLI references.
.github/workflows/autofix.yml, .github/workflows/pkg-pr-new.yml, .github/workflows/release.yml, .github/workflows/size-limit.yml Updated Node.js setup to enable npm caching and switched dependency installation from npm i to npm ci. Minor workflow improvements.
.github/workflows/ci.yml Improved Node.js setup with npm caching, split build and test steps, and added postinstall commands for rollup and unrs-resolver. Added Windows-specific Rollup package installation step.
.gitignore, .prettierignore Updated ignore patterns: removed package-lock.json from .gitignore, replaced .yarn with lib and public in .prettierignore, and unignored lib directory while ignoring build info files.
eslint.config.js, index.d.cts Removed old ESLint config and type declaration re-export files.
eslint.config.mjs Added new ESLint config with extended plugin recommendations and custom rule overrides.
tsconfig.json, vitest.config.mts Updated TypeScript base config and added tsconfig paths plugin to Vitest config.
patches/rollup+4.40.0.patch Added explicit export for package.json in rollup's export map.
src/cli.ts Introduced a new CLI entry script for running package preparation from the command line.
src/constants.ts Added a module exporting constants for npm registry, package name, version, and log prefix.
src/helpers.ts Added utility functions for npm registry resolution, directory removal, native target detection, error handling, and more.
src/target.ts Added module for parsing and representing target triples for native binaries.
src/types.ts Added TypeScript interfaces for N-API configuration, package info, and related metadata.
src/index.ts Completely replaced with robust logic for managing native binary installation, fallback mechanisms, and version checks. Exports main API and types.
test/basic.spec.ts Rewritten to test new checkAndPreparePackage function with positive and negative cases.
lib/cli.d.ts, lib/cli.js Added CLI executable script and its type declaration for command-line usage.
lib/constants.d.ts, lib/constants.js Added constants module with npm registry URL, package name, version, and log prefix, including type declarations.
lib/helpers.d.ts, lib/helpers.js Added helper utilities with type declarations for npm registry, directory removal, native target detection, and error extraction.
lib/index.d.ts, lib/index.js Added main module with type declarations and implementation for checking and preparing native packages with fallback installation methods.
lib/target.d.ts, lib/target.js Added target triple parsing module with types and implementation.
lib/types.d.ts, lib/types.js Added TypeScript interfaces for N-API and package metadata with minimal JS module.
.simple-git-hooks.js, .simple-git-hooks.mjs Removed old simple-git-hooks JS file and replaced with new .mjs config that runs build and stages lib before pre-commit.

Sequence Diagram(s)

sequenceDiagram
    participant CLI/User
    participant CLI Script
    participant Main Module (index.ts)
    participant Helpers
    participant NPM/Registry

    CLI/User->>CLI Script: Run `napi-postinstall <package>`
    CLI Script->>Main Module (index.ts): checkAndPreparePackage(package)
    Main Module->>Helpers: getNapiInfoFromPackageJson()
    Main Module->>Helpers: getNapiNativeTargets()
    loop For each native target
        Main Module->>Helpers: Check if binary package is installed
        alt Binary not found
            Main Module->>Helpers: isNpm()
            alt Not running under npm
                Main Module->>Main Module: Log warning about --no-optional
            end
            Main Module->>Main Module: Try installUsingNPM()
            alt installUsingNPM fails
                Main Module->>Main Module: Try downloadDirectlyFromNPM()
                Main Module->>NPM/Registry: Download tarball and extract binary
            end
        end
    end
    Main Module-->>CLI Script: Done
Loading

Poem

🐇
A hop and a leap, a name anew,
From native to napi, our purpose grew.
With helpers and targets, and constants in tow,
We fetch and prepare what binaries know.
The CLI now answers your postinstall call—
In CommonJS comfort, we welcome you all!
— Your code rabbit, bounding through change.


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request introduces the initial implementation of a postinstall helper for napi packages, with full support for target triple parsing, package installation using npm, and native target preparation. Key changes include the addition of new utility functions (such as parseTriple and checkAndPreparePackage), a complete rework of the install logic in src/index.ts, and updates to documentation, workflows, and ESLint configurations.

Reviewed Changes

Copilot reviewed 23 out of 26 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/target.ts Implements target triple parsing and mapping to NodeJS platform/arch values
src/index.ts Contains the logic for fetching, extracting, and installing napi packages
src/helpers.ts Adds npm registry, file removal, and other helper functions
src/constants.ts Updates constants including package metadata and default registry
src/cli.ts Introduces a CLI entry point
README.md Revises usage instructions and documentation to reflect the new package name
GitHub workflows (.github/*) Updates dependency installation steps and release/publishing scripts
Files not reviewed (3)
  • .changeset/config.json: Language not supported
  • .prettierignore: Language not supported
  • package.json: Language not supported

@socket-security
Copy link

socket-security bot commented Apr 19, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​types/​pnpapi@​0.0.5881008576100
Added@​unts/​patch-package@​8.1.17610010081100
Addedeslint-plugin-node-dependencies@​0.12.08010010079100
Updatedeslint@​9.25.0 ⏵ 9.24.09710010096100
Addednapi-postinstall@​0.0.0100100100100100

View full report

@github-actions
Copy link
Contributor

github-actions bot commented Apr 19, 2025

Deploy preview for native-postinstall ready!

✅ Preview
https://native-postinstall-je9xghhp4-1stg.vercel.app

Built with commit 8c06cd5.
This pull request is being automatically deployed with vercel-action

@github-actions
Copy link
Contributor

github-actions bot commented Apr 19, 2025

📊 Package size report   No changes

File Before After
Total (Includes all files) 44.5 kB 44.5 kB
Tarball size 12.8 kB 12.8 kB
Unchanged files
File Size
lib/cli.d.ts 31 B
lib/cli.js 289 B
lib/cli.js.map 282 B
lib/constants.d.ts 168 B
lib/constants.js 567 B
lib/constants.js.map 307 B
lib/helpers.d.ts 686 B
lib/helpers.js 7.8 kB
lib/helpers.js.map 6.3 kB
lib/index.d.ts 249 B
lib/index.js 7.1 kB
lib/index.js.map 5.9 kB
lib/target.d.ts 348 B
lib/target.js 1.5 kB
lib/target.js.map 1.5 kB
lib/types.d.ts 540 B
lib/types.js 110 B
lib/types.js.map 102 B
LICENSE 1.1 kB
package.json 3.4 kB
README.md 6.3 kB

🤖 This report was automatically generated by pkg-size-action

@JounQin JounQin force-pushed the feat/work branch 7 times, most recently from afb0bcc to 369f56e Compare April 19, 2025 17:01
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
src/target.ts (1)

65-78: Potential issue with destructuring assignment.

The destructuring assignment in line 77 assumes that the target triple always includes a vendor field, but there may be cases where it's omitted.

#!/bin/bash
# Look for target triple examples in the codebase or documentation
rg --type=ts 'triple|target(-|_)triple' -g '!node_modules/' -g '!*.json' -g '!*.lock'
🧹 Nitpick comments (8)
src/types.ts (1)

1-17: Well-structured Napi interface with optional properties.

The Napi interface is designed with many optional properties, providing flexibility for different configuration scenarios. However, consider documenting each property with JSDoc comments to improve developer understanding.

 export interface Napi {
+  /** Optional name for the binary file */
   binaryName?: string
+  /** Optional package name for resolution */
   packageName?: string
   package?: {
     name: string
   }
+  /** List of supported target platforms */
   targets?: string[]
   triples?: {
+    /** Whether to include default triples */
     defaults?: boolean
+    /** Additional custom triples to support */
     additional?: string[]
   }
   wasm?: {
     browser?: {
+      /** Whether to enable filesystem in browser WASM */
       fs?: boolean
     }
   }
 }
src/cli.ts (1)

1-5: CLI implementation looks good, but consider adding error handling

The CLI implementation follows Node.js best practices with the shebang line and proper module imports. However, there's no error handling for the Promise returned by checkAndPreparePackage.

-void checkAndPreparePackage(process.argv[2])
+checkAndPreparePackage(process.argv[2]).catch(err => {
+  console.error('Error during package preparation:', err)
+  process.exit(1)
+})
README.md (1)

16-16: Minor punctuation glitch after the project list.

Consider inserting a full stop ( . ) before “for” to avoid a run‑on sentence and satisfy spell‑/grammar‑checks.

- ecosystem packages like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver]
+ ecosystem packages like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver].
🧰 Tools
🪛 LanguageTool

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

src/helpers.ts (2)

20-36: Use built‑in fs.rmSync for safer, atomic directory removal.

fs.rmdirSync is deprecated and fails on non‑empty dirs in newer Node versions. You can simplify and make the function more robust (and Windows‑friendly) with:

-export function removeRecursive(dir: string) {
-  for (const entry of fs.readdirSync(dir)) {
-    const entryPath = path.join(dir, entry)
-    let stats: Stats
-    try {
-      stats = fs.lstatSync(entryPath)
-    } catch {
-      continue // Guard against https://github.com/nodejs/node/issues/4760
-    }
-    if (stats.isDirectory()) {
-      removeRecursive(entryPath)
-    } else {
-      fs.unlinkSync(entryPath)
-    }
-  }
-  fs.rmdirSync(dir)
-}
+export function removeRecursive(dir: string) {
+  // Node ≥ 14.14
+  fs.rmSync(dir, { recursive: true, force: true })
+}

Keeps Node 12 support? Detect version and fall back if necessary.


155-239: Return type can be simplified to always string[]

getNapiNativeTarget currently returns string | string[] | [], forcing callers to branch.
Since callers often normalise to an array anyway (getNapiNativeTargets does), consider:

-export function getNapiNativeTarget(): string[] | string {
+export function getNapiNativeTarget(): string[] {
...
-        return 'android-arm64'
+        return ['android-arm64']
...
-  return []
+  return []

This reduces API friction and type assertions.

src/index.ts (2)

23-43: fetch() lacks robust redirect & error handling

The helper handles only 301/302 redirects and assumes an absolute Location header. Consider:
• Supporting 303, 307, 308 status codes.
• Resolving relative Location headers via new URL(location, url).
• Aborting the initial request when following a redirect to free sockets.
• Imposing a maximum redirect depth to avoid loops.

These changes improve resilience when registry mirrors are configured.


45-70: Minor: tar extraction assumes small archives and loads entire buffer

extractFileFromTarGzip unzips the whole archive into memory and iterates synchronously. For large native bundles (≥ tens of MB) this can blow RAM in constrained environments.

If performance becomes a concern, consider a streaming approach (zlib.createGunzip() + incremental tar parser such as tar-stream), aborting once the desired entry is found. Not urgent but worth tracking.

src/constants.ts (1)

1-11: Good centralization of constants

Creating a dedicated constants file improves maintainability by providing a single source of truth for configuration values.

Consider using a consistent module system approach. The file mixes ESM-style imports with CommonJS-style require(). For better ESM compatibility, you could use:

-export const { name, version } = require(
-  path.resolve(__dirname, '../package.json'),
-) as PackageJson
+import { fileURLToPath } from 'node:url'
+import { dirname } from 'node:path'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = dirname(__filename)
+
+export const { name, version } = JSON.parse(
+  readFileSync(path.resolve(__dirname, '../package.json'), 'utf8')
+) as PackageJson

Don't forget to add the import for readFileSync from the fs module.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7213e33 and 369f56e.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (24)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (0 hunks)
  • .prettierignore (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (3)
  • index.d.cts
  • .gitignore
  • eslint.config.js
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/constants.ts (1)
src/types.ts (1)
  • PackageJson (24-29)
test/basic.spec.ts (1)
src/index.ts (1)
  • checkAndPreparePackage (174-258)
src/index.ts (3)
src/constants.ts (2)
  • require (7-9)
  • LOG_PREFIX (11-11)
src/helpers.ts (6)
  • removeRecursive (20-36)
  • getGlobalNpmRegistry (9-18)
  • getErrorMessage (251-253)
  • getNapiInfoFromPackageJson (51-91)
  • getNapiNativeTargets (243-249)
  • downloadedNodePath (38-41)
src/types.ts (1)
  • PackageJson (24-29)
src/helpers.ts (3)
src/constants.ts (1)
  • DEFAULT_NPM_REGISTRY (5-5)
src/types.ts (2)
  • PackageJson (24-29)
  • NapiInfo (19-22)
src/target.ts (1)
  • parseTriple (47-89)
🪛 LanguageTool
README.md

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
🔇 Additional comments (31)
.prettierignore (1)

1-1: Configuration updated to ignore the public directory.

The .prettierignore file now excludes the public directory from Prettier formatting, aligning with the project renaming and restructuring from native-postinstall to napi-postinstall.

src/target.ts (9)

1-2: Source attribution is good practice.

Properly crediting the source code you've based your implementation on demonstrates transparency and good open-source citizenship.


3-6: Good type extensions for cross-platform compatibility.

The custom type definitions extending the NodeJS namespace with additional platforms and architectures will help with stronger typing throughout the codebase.


7-14: CPU architecture mapping for cross-platform compatibility.

This mapping correctly translates common CPU architecture names to their corresponding NodeJS architecture identifiers.


16-21: System to platform mapping for cross-platform compatibility.

The mapping provides a clean way to normalize system names to their corresponding NodeJS platform identifiers.


23-29: Well-structured Target interface.

The Target interface provides a comprehensive representation of platform, architecture, and ABI details.


31-46: Great documentation for the triple format.

The detailed JSDoc comment explains the target triple format clearly, which is essential for understanding the parsing logic.


47-60: Special case handling for WebAssembly.

Good handling of WebAssembly-specific target triples as a special case before general parsing.


61-64: EABI suffix normalization.

This pre-processing step ensures consistent handling of EABI suffixes in the triple format.


80-89: Fallback to original values for unknown platforms and architectures.

Good use of the nullish coalescing operator to handle unknown platform and architecture values by falling back to the original input values.

src/types.ts (2)

19-22: Simple NapiInfo interface.

The NapiInfo interface appropriately combines the Napi configuration with a version string.


24-29: PackageJson interface with essential properties.

This interface captures the core properties needed from package.json files for this library's functionality.

vercel.json (1)

4-4: Updated alias to reflect project renaming.

The Vercel deployment alias has been updated from "native-postinstall.vercel.app" to "napi-postinstall.vercel.app" to match the project's new name.

.changeset/config.json (1)

6-6: Repository name correctly updated for package rebranding.

The change from "un-ts/native-postinstall" to "un-ts/napi-postinstall" properly aligns with the overall project rebranding efforts. This ensures that changelogs will be generated with the correct repository reference.

.github/workflows/pkg-pr-new.yml (1)

22-25: Workflow performance and reliability improvements.

Two positive changes to the GitHub Actions workflow:

  1. Added npm caching, which will speed up workflow execution by reusing previously downloaded dependencies
  2. Switched from npm i to npm ci, which ensures consistent installations based on the lockfile and is the recommended approach for CI environments

These changes align with GitHub Actions best practices and are consistent with similar updates made to other workflow files.

vitest.config.mts (1)

1-1: Support for TypeScript path mappings in tests.

The addition of the vite-tsconfig-paths plugin correctly enables Vitest to resolve the TypeScript path aliases defined in tsconfig.json. This will allow tests to properly import modules using the napi-postinstall alias.

Also applies to: 5-5

tsconfig.json (2)

5-7: Path mapping supports new package name.

The addition of TypeScript path mapping for napi-postinstall correctly facilitates module resolution throughout the codebase. This aligns with the project renaming and supports consistent import patterns in both source code and tests.


2-2:

Details

❓ Verification inconclusive

Verify the impact of changing the base TypeScript configuration.

Changing from @1stg/tsconfig/node16 to @1stg/tsconfig/node might affect the target Node.js environment or compiler defaults. Please ensure this change is intentional and compatible with your project requirements.


🏁 Script executed:

#!/bin/bash
# Check the differences between the two base configurations

# Try to find the two config files
echo "Searching for the base TypeScript configurations..."
fd --type file --glob "node16.json" --glob "node.json" --exec echo "Found: {}"

# Try to look at package.json to see the dependencies
echo "Checking package.json for @1stg/tsconfig..."
cat package.json | grep -A 5 "@1stg/tsconfig"

# Check the node version in package.json engines field
echo "Checking Node.js version requirements..."
cat package.json | grep -A 3 "engines"

Length of output: 637


Verify compatibility of the updated base TypeScript config

Switching the extends in tsconfig.json from

-"@1stg/tsconfig/node16"
+"@1stg/tsconfig/node"

can change default compiler settings (target, lib, module resolution, strictness, etc.). Please confirm:

  • You’ve reviewed node_modules/@1stg/tsconfig/node.json (or the upstream repo) and compared its defaults against the former node16 preset.
  • The new preset still aligns with your project’s Node.js engines (^12.20.0 || ^14.18.0 || >=16.0.0) and any custom compiler options you rely on.
  • There are no unintended regressions in emitted code or type‑checking behavior.
.github/workflows/size-limit.yml (2)

22-22: Great addition of npm cache!

Adding the npm cache configuration will significantly improve workflow performance by reusing previously downloaded dependencies.


25-25: Good practice using npm ci instead of npm i

Using npm ci ensures deterministic and reproducible builds by installing exact versions from the lockfile, which is ideal for CI environments.

.github/workflows/release.yml (3)

32-32: Great addition of npm cache!

Adding the npm cache configuration will significantly improve workflow performance by reusing previously downloaded dependencies.


35-35: Good practice using npm ci instead of npm i

Using npm ci ensures deterministic and reproducible builds by installing exact versions from the lockfile, which is ideal for CI environments.


40-41: Package name updated correctly in commit and PR titles

The commit and PR titles have been properly updated to reflect the rebranding from "native-postinstall" to "napi-postinstall".

patches/rollup+4.40.0.patch (1)

9-11: Good patch for enabling direct package.json imports

This patch correctly adds an explicit export for rollup's package.json, which aligns with modern Node.js package export patterns and enables direct imports of the package.json file.

eslint.config.mjs (1)

2-6:

Details

✅ Verification successful

Verify availability of flat/recommended config in eslint-plugin-node-dependencies.

nodeDependencies.configs['flat/recommended'] assumes that the plugin ships a flat‑config preset with that exact key.
Older (and even some latest) versions only expose 'recommended'. If the key is not found ESLint will silently ignore the spread element and you will lose the dependency‑linting rules altogether.

  1. Double‑check the plugin’s release notes / typings.
  2. Pin the required version in devDependencies (≥ 0.12.0?) or switch to 'recommended' if flat support is not yet published.

Run:


🏁 Script executed:

#!/usr/bin/env bash
npm ls eslint-plugin-node-dependencies --depth=0
node -e "const p=require('eslint-plugin-node-dependencies');console.log(Object.keys(p.configs))"

Length of output: 279


No action needed: flat/recommended is available in eslint-plugin-node-dependencies v0.12.0

Confirmed via:

  • npm ls eslint-plugin-node-dependencies --depth=0 reports v0.12.0
  • Object.keys(require('eslint-plugin-node-dependencies').configs) returns ['recommended', 'flat/recommended']

The spread of nodeDependencies.configs['flat/recommended'] will work as expected.

src/helpers.ts (1)

70-76: Potential NPE if napi.packageName & napi.package.name are both undefined.

If a third‑party package defines napi.targets but omits packageName/package, constructing
`${napi!.packageName ?? napi!.package!.name}-${platformArchABI}`
throws at runtime.

Consider a fallback to the parent package’s name or a clearer error:

-const pkg = `${napi!.packageName ?? napi!.package!.name}-${platformArchABI}`
+const base = napi?.packageName ?? napi?.package?.name
+if (!base) {
+  throw new Error(`Missing NAPI package name metadata in ${name}`)
+}
+const pkg = `${base}-${platformArchABI}`
.github/workflows/autofix.yml (1)

25-25: Excellent CI performance improvements!

Adding npm caching and switching to npm ci are best practices for CI environments that will:

  • Speed up workflow execution by reusing cached dependencies
  • Ensure reproducible builds through exact package-lock.json versioning
  • Improve reliability with clean node_modules installation

Also applies to: 28-28

.github/workflows/ci.yml (3)

34-34: Good CI performance optimizations

Adding npm caching and switching to npm ci will improve build reliability and speed.

Also applies to: 37-37


39-44: Well-structured build step with validation

Splitting the build into its own step and adding post-build verification with napi-postinstall provides a more organized workflow and validates the package functionality with real dependencies.


45-46: Clean separation of concerns

Separating lint and test into a distinct step improves workflow organization and readability.

test/basic.spec.ts (1)

1-12: Well-structured tests covering key scenarios

The test suite effectively validates both success and error paths for the core checkAndPreparePackage function:

  1. Verifies successful operation with a properly configured package
  2. Confirms appropriate error handling when required configuration is missing

The async/await syntax with Jest's promise assertions creates clean, readable tests.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/index.ts (2)

80-110: ⚠️ Potential issue

Fix potential command injection vulnerability in installUsingNPM

The current implementation uses execSync with template literals for pkg and version values, which could be vulnerable to command injection if these values are malicious. Although inputs typically come from package.json, it's better to implement defense-in-depth security measures.

Replace with spawnSync to avoid shell interpolation, improving security and Windows compatibility:

-import { execSync } from 'node:child_process'
+import { execSync, spawnSync } from 'node:child_process'
...
-    execSync(
-      `npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${version}`,
-      { cwd: installDir, stdio: 'pipe', env },
-    )
+    const { status, error } = spawnSync(
+      'npm',
+      [
+        'install',
+        '--loglevel=error',
+        '--prefer-offline',
+        '--no-audit',
+        '--progress=false',
+        `${pkg}@${version}`,
+      ],
+      { cwd: installDir, stdio: 'pipe', env },
+    )
+    if (status !== 0) throw error ?? new Error('npm install failed')

238-252: ⚠️ Potential issue

Incorrect version is used when fetching/installing the binary package

Inside the loop you derive pkg at L199, yet the subsequent calls to both installUsingNPM() (L238-L243) and downloadDirectlyFromNPM() (L247-L252) forward the host package version (version) instead of the version declared in optionalDependencies![pkg].

When checkVersion is false (which you explicitly support), this silently fetches the wrong tarball or npm install target, leading to checksum mismatches or runtime ABI errors.

-        installUsingNPM(name, pkg, version, subpath, nodePath)
+        installUsingNPM(name, pkg, optionalDependencies![pkg]!, subpath, nodePath)
...
-          await downloadDirectlyFromNPM(pkg, version, subpath, nodePath)
+          await downloadDirectlyFromNPM(pkg, optionalDependencies![pkg]!, subpath, nodePath)
🧹 Nitpick comments (7)
src/index.ts (4)

198-208: Use consistent object naming scheme in checkAndPreparePackage

The code derives pkg based on the target and packageName at L199, but the naming is inconsistent with how the native package naming works internally from what I can see from the rest of the codebase.

For better readability and consistency, ensure that the package name construction follows a consistent pattern throughout the codebase. Consider extracting this into a helper function if it's used in multiple places.


202-204: Consider explicit null check instead of non-null assertion

While the code includes a comment indicating that optionalDependencies is ensured to exist by getNapiInfoFromPackageJson, defensive programming would benefit from an explicit check rather than relying on non-null assertions.

-    /** @see {optionalDependencies} has been ensured to exist with @see {getNapiInfoFromPackageJson} */
-    if (!optionalDependencies![pkg]) {
+    // optionalDependencies is ensured to exist by getNapiInfoFromPackageJson
+    if (!optionalDependencies?.[pkg]) {
       continue
     }

216-222: Improve readability of multi-line error message

The multi-line error message could be improved for better readability using a template literal.

-      console.error(`${LOG_PREFIX}Failed to find package "${pkg}" on the file system
-
-This can happen if you use the "--no-optional" flag. The "optionalDependencies"
-package.json feature is used by ${name} to install the correct napi binary
-for your current platform. This install script will now attempt to work around
-this. If that fails, you need to remove the "--no-optional" flag to use ${name}.
-`)
+      console.error(`${LOG_PREFIX}Failed to find package "${pkg}" on the file system
+
+This can happen if you use the "--no-optional" flag. The "optionalDependencies"
+package.json feature is used by ${name} to install the correct napi binary
+for your current platform. This install script will now attempt to work around
+this. If that fails, you need to remove the "--no-optional" flag to use ${name}.`)

173-177: Mark exported function as stable API

The main exported function checkAndPreparePackage is a public API and should have a JSDoc comment describing its purpose, parameters, and return value, especially since it's likely to be used by external consumers.

// eslint-disable-next-line sonarjs/cognitive-complexity
+/**
+ * Checks and prepares native packages for a given package
+ * @param packageNameOrPackageJson - The package name or package.json object
+ * @param checkVersion - Whether to check version consistency
+ */
export async function checkAndPreparePackage(
  packageNameOrPackageJson: PackageJson | string,
  checkVersion?: boolean,
) {
README.md (2)

16-16: Add a period at the end of the description

The description sentence is missing a period at the end.

-The `postinstall` script helper for handling native bindings in legacy `npm` versions, this is a reimplementation of the [`node-install`][node-install] functionality from [`esbuild`][esbuild] for [`napi-rs`][napi-rs] ecosystem packages like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver]
+The `postinstall` script helper for handling native bindings in legacy `npm` versions, this is a reimplementation of the [`node-install`][node-install] functionality from [`esbuild`][esbuild] for [`napi-rs`][napi-rs] ecosystem packages like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver].
🧰 Tools
🪛 LanguageTool

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)


95-95: Add more detailed example code

The current example is very minimal. Consider adding a more comprehensive example showing both the CLI and API usage scenarios, including handling errors and working with optional arguments.

-checkAndPreparePackage('unrs-resolver' /* <napi-package-name> */)
+// Basic usage
+try {
+  await checkAndPreparePackage('unrs-resolver')
+  console.log('Native dependencies prepared successfully')
+} catch (error) {
+  console.error('Failed to prepare native dependencies:', error)
+}
+
+// With version checking
+try {
+  await checkAndPreparePackage('unrs-resolver', true)
+  console.log('Native dependencies prepared successfully with version checking')
+} catch (error) {
+  console.error('Failed to prepare native dependencies:', error)
+}
+
+// With package.json object
+import fs from 'node:fs'
+
+const packageJson = JSON.parse(fs.readFileSync('path/to/package.json', 'utf8'))
+try {
+  await checkAndPreparePackage(packageJson)
+  console.log('Native dependencies prepared successfully')
+} catch (error) {
+  console.error('Failed to prepare native dependencies:', error)
+}
package.json (1)

2-4: Consider adding a description that includes the package renaming in comments

Adding a comment about the package renaming history could be helpful for users familiar with the old name.

{
  "name": "napi-postinstall",
  "version": "0.0.0",
+  // Renamed from native-postinstall
  "type": "commonjs",
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 369f56e and 844d59c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (25)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (0 hunks)
  • .prettierignore (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (3)
  • index.d.cts
  • .gitignore
  • eslint.config.js
✅ Files skipped from review due to trivial changes (3)
  • .size-limit.json
  • patches/rollup+4.40.0.patch
  • src/constants.ts
🚧 Files skipped from review as they are similar to previous changes (16)
  • .github/workflows/autofix.yml
  • vercel.json
  • vitest.config.mts
  • .github/workflows/size-limit.yml
  • .github/workflows/pkg-pr-new.yml
  • .changeset/config.json
  • .github/workflows/release.yml
  • .github/workflows/ci.yml
  • tsconfig.json
  • src/cli.ts
  • test/basic.spec.ts
  • eslint.config.mjs
  • .prettierignore
  • src/target.ts
  • src/helpers.ts
  • src/types.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/index.ts (3)
src/constants.ts (2)
  • require (7-9)
  • LOG_PREFIX (11-11)
src/helpers.ts (6)
  • removeRecursive (20-36)
  • getGlobalNpmRegistry (9-18)
  • getErrorMessage (251-253)
  • getNapiInfoFromPackageJson (51-91)
  • getNapiNativeTargets (243-249)
  • downloadedNodePath (38-41)
src/types.ts (1)
  • PackageJson (24-29)
🪛 LanguageTool
README.md

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
🔇 Additional comments (2)
package.json (2)

17-25: Good job fixing the inconsistent entry points

The entry points for CommonJS and the exports field are now correctly aligned, both pointing to the .js extension.


46-46: Verify if the vercel-build command sequence is correct

The script now uses the package's own binary (napi-postinstall rollup), which might cause a circular dependency issue during the first build process.

Could you verify that this works as expected during a fresh installation? If there are any issues, consider using a direct Node.js call to the CLI script:

-  "vercel-build": "npm run build && napi-postinstall rollup && npm run docs:build",
+  "vercel-build": "npm run build && node lib/cli.js rollup && npm run docs:build",

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (5)
README.md (1)

76-83: PackageJson interface still incomplete

Previous reviews already flagged that optionalDependencies and napi fields are missing. The example type should reflect the actual structure or newcomers will copy an invalid shape.

src/helpers.ts (1)

38-41: Path truncation bug when resolving downloaded binary sub‑paths

Using path.basename(subpath) drops intermediate directories (darwin/x64/native.nodenative.node) and can cause name clashes between different targets.

-return path.join(pkgLibDir, `${path.basename(subpath)}`)
+// Preserve the relative structure to avoid collisions
+return path.join(pkgLibDir, subpath)
src/index.ts (3)

106-109: ⚠️ Potential issue

Fix command injection vulnerability in npm install execution

The current implementation uses string concatenation with execSync, which makes it vulnerable to command injection if pkg or version contains shell metacharacters.

Replace with spawnSync to avoid shell interpretation:

-    execSync(
-      `npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${version}`,
-      { cwd: installDir, stdio: 'pipe', env },
-    )
+    const { status, error } = spawnSync(
+      'npm',
+      [
+        'install',
+        '--loglevel=error',
+        '--prefer-offline',
+        '--no-audit',
+        '--progress=false',
+        `${pkg}@${version}`,
+      ],
+      { cwd: installDir, stdio: 'pipe', env },
+    )
+    if (status !== 0) throw error ?? new Error('npm install failed')

238-240: ⚠️ Potential issue

Use correct package version from optionalDependencies

You're using the host package version (version) instead of the version specified in optionalDependencies for the specific package.

-        installUsingNPM(name, pkg, version, subpath, nodePath)
+        installUsingNPM(name, pkg, optionalDependencies![pkg]!, subpath, nodePath)

249-252: ⚠️ Potential issue

Use correct package version from optionalDependencies

You're using the host package version (version) instead of the version specified in optionalDependencies for the specific package.

-          await downloadDirectlyFromNPM(pkg, version, subpath, nodePath)
+          await downloadDirectlyFromNPM(pkg, optionalDependencies![pkg]!, subpath, nodePath)
🧹 Nitpick comments (8)
README.md (1)

14-17: Add a missing comma for readability

The sentence runs together after the inline link list; inserting a comma improves clarity:

-ecosystem packages like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver].
+ecosystem packages, like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver].
🧰 Tools
🪛 LanguageTool

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

src/helpers.ts (1)

20-36: Use modern, atomic removal API

fs.rmdirSync(dir) is deprecated and removed in recent Node versions.
fs.rmSync(dir, { recursive: true, force: true }) is the recommended replacement and eliminates the manual recursion.

-export function removeRecursive(dir: string) {
-  for (const entry of fs.readdirSync(dir)) {
-    const entryPath = path.join(dir, entry)
-    let stats: Stats
-    try {
-      stats = fs.lstatSync(entryPath)
-    } catch {
-      continue // Guard against https://github.com/nodejs/node/issues/4760
-    }
-    if (stats.isDirectory()) {
-      removeRecursive(entryPath)
-    } else {
-      fs.unlinkSync(entryPath)
-    }
-  }
-  fs.rmdirSync(dir)
-}
+export function removeRecursive(dir: string) {
+  fs.rmSync(dir, { recursive: true, force: true })
+}
src/index.ts (6)

158-158: Improve URL construction for scoped packages

The URL construction for npm packages has different logic for scoped vs. non-scoped packages embedded in a single line, making it harder to understand.

-  const url = `${getGlobalNpmRegistry()}${pkg}/-/${pkg.startsWith('@') ? pkg.split('/')[1] : pkg}-${version}.tgz`
+  const packageName = pkg.startsWith('@') ? pkg.split('/')[1] : pkg
+  const url = `${getGlobalNpmRegistry()}${pkg}/-/${packageName}-${version}.tgz`

50-51: Use imported getErrorMessage helper

You've imported the getErrorMessage helper function but aren't using it consistently in the code.

-      `Invalid gzip data in archive: ${(err as Error | undefined)?.message || String(err)}`,
+      `Invalid gzip data in archive: ${getErrorMessage(err)}`,

23-43: Consider adding retry logic to fetch function

The fetch function handles redirects but doesn't have retry logic for transient network errors, which can be common when downloading from npm.

Consider adding retry logic with exponential backoff for more robust downloads:

+function wait(ms: number) {
+  return new Promise(resolve => setTimeout(resolve, ms));
+}
+
-function fetch(url: string) {
+async function fetch(url: string, retries = 3, backoff = 300) {
+  try {
+    return await fetchOnce(url);
+  } catch (err) {
+    if (retries <= 0) throw err;
+    await wait(backoff);
+    return fetch(url, retries - 1, backoff * 2);
+  }
+}
+
+function fetchOnce(url: string) {
  return new Promise<Buffer>((resolve, reject) => {
    https
      .get(url, res => {
        if (
          (res.statusCode === 301 || res.statusCode === 302) &&
          res.headers.location
        ) {
-          fetch(res.headers.location).then(resolve, reject)
+          fetchOnce(res.headers.location).then(resolve, reject)
          return
        }
        if (res.statusCode !== 200) {
          return reject(new Error(`Server responded with ${res.statusCode}`))
        }
        const chunks: Buffer[] = []
        res.on('data', (chunk: Buffer) => chunks.push(chunk))
        res.on('end', () => resolve(Buffer.concat(chunks)))
      })
      .on('error', reject)
  })
}

173-258: Reduce cognitive complexity of checkAndPreparePackage function

The function is marked with an ESLint disable comment for cognitive complexity. Consider breaking it down into smaller, more focused functions.

You could extract the target handling loop into a separate function:

-// eslint-disable-next-line sonarjs/cognitive-complexity
 export async function checkAndPreparePackage(
   packageNameOrPackageJson: PackageJson | string,
   checkVersion?: boolean,
 ) {
   const packageJson =
     typeof packageNameOrPackageJson === 'string'
       ? (require(packageNameOrPackageJson + '/package.json') as PackageJson)
       : packageNameOrPackageJson

   const { napi, version: napiVersion } = getNapiInfoFromPackageJson(
     packageJson,
     checkVersion,
   )

   const { name, version, optionalDependencies } = packageJson

   if (checkVersion && version !== napiVersion) {
     throw new Error(
       `Inconsistent package versions found for \`${name}\` v${version} vs \`${napi.packageName}\` v${napiVersion}.`,
     )
   }

   const targets = getNapiNativeTargets()
+   
+   await findAndPrepareTarget(name, napi, version, optionalDependencies!, targets)
+ }
+ 
+ async function findAndPrepareTarget(
+   name: string,
+   napi: NonNullable<PackageJson['napi']>,
+   version: string,
+   optionalDependencies: NonNullable<PackageJson['optionalDependencies']>,
+   targets: string[]
+ ) {
   for (const target of targets) {
     const pkg = `${napi.packageName}-${target}`

-    /** @see {optionalDependencies} has been ensured to exist with @see {getNapiInfoFromPackageJson} */
-    if (!optionalDependencies![pkg]) {
+    if (!optionalDependencies[pkg]) {
       continue
     }

     const binaryPrefix = napi.binaryName ? `${napi.binaryName}.` : ''
     const subpath = `${binaryPrefix}${target}.node`

     try {
       // First check for the binary package from our "optionalDependencies". This
       // package should have been installed alongside this package at install time.
       require.resolve(`${pkg}/${subpath}`)
       break
     } catch {
       if (!isNpm()) {
         console.error(`${LOG_PREFIX}Failed to find package "${pkg}" on the file system

This can happen if you use the "--no-optional" flag. The "optionalDependencies"
package.json feature is used by ${name} to install the correct napi binary
for your current platform. This install script will now attempt to work around
this. If that fails, you need to remove the "--no-optional" flag to use ${name}.
`)
       }

       // If that didn't work, then someone probably installed <napi> with the
       // "--no-optional" flag. Attempt to compensate for this by downloading the
       // package using a nested call to "npm" instead.
       //
       // THIS MAY NOT WORK. Package installation uses "optionalDependencies" for
       // a reason: manually downloading the package has a lot of obscure edge
       // cases that fail because people have customized their environment in
       // some strange way that breaks downloading. This code path is just here
       // to be helpful but it's not the supported way of installing <napi>.
       const nodePath = downloadedNodePath(name, subpath)
       try {
         console.error(
           `${LOG_PREFIX}Trying to install package "${pkg}" using npm`,
         )
-        installUsingNPM(name, pkg, version, subpath, nodePath)
+        installUsingNPM(name, pkg, optionalDependencies[pkg]!, subpath, nodePath)
         break
       } catch (err) {
         console.error(
           `${LOG_PREFIX}Failed to install package "${pkg}" using npm: ${getErrorMessage(err)}`,
         )

         // If that didn't also work, then something is likely wrong with the "npm"
         // command. Attempt to compensate for this by manually downloading the
         // package from the npm registry over HTTP as a last resort.
         try {
-          await downloadDirectlyFromNPM(pkg, version, subpath, nodePath)
+          await downloadDirectlyFromNPM(pkg, optionalDependencies[pkg]!, subpath, nodePath)
           break
         } catch {
           throw new Error(`Failed to install package "${pkg}"`)
         }
       }
     }
   }
 }

202-202: Avoid non-null assertion operator

You're using the non-null assertion operator (!) which might not be safe in all cases.

-    if (!optionalDependencies![pkg]) {
+    // We ensured optionalDependencies exists in getNapiInfoFromPackageJson
+    if (!optionalDependencies?.[pkg]) {

216-222: Improve error message readability

The multi-line template literal is concatenated with the log prefix in a way that creates an odd line break after the first line.

-        console.error(`${LOG_PREFIX}Failed to find package "${pkg}" on the file system
-
-This can happen if you use the "--no-optional" flag. The "optionalDependencies"
-package.json feature is used by ${name} to install the correct napi binary
-for your current platform. This install script will now attempt to work around
-this. If that fails, you need to remove the "--no-optional" flag to use ${name}.
-`)
+        console.error(
+          `${LOG_PREFIX}Failed to find package "${pkg}" on the file system\n` +
+          `\n` +
+          `This can happen if you use the "--no-optional" flag. The "optionalDependencies"\n` +
+          `package.json feature is used by ${name} to install the correct napi binary\n` +
+          `for your current platform. This install script will now attempt to work around\n` +
+          `this. If that fails, you need to remove the "--no-optional" flag to use ${name}.`
+        )
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 844d59c and 9dee2f4.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (25)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (0 hunks)
  • .prettierignore (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (3)
  • .gitignore
  • index.d.cts
  • eslint.config.js
✅ Files skipped from review due to trivial changes (3)
  • .size-limit.json
  • patches/rollup+4.40.0.patch
  • src/constants.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • vitest.config.mts
  • .prettierignore
  • vercel.json
  • .github/workflows/pkg-pr-new.yml
  • .github/workflows/autofix.yml
  • .github/workflows/release.yml
  • .github/workflows/size-limit.yml
  • src/cli.ts
  • .github/workflows/ci.yml
  • tsconfig.json
  • eslint.config.mjs
  • src/target.ts
  • src/types.ts
  • .changeset/config.json
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/helpers.ts (3)
src/constants.ts (1)
  • DEFAULT_NPM_REGISTRY (5-5)
src/types.ts (2)
  • PackageJson (24-29)
  • NapiInfo (19-22)
src/target.ts (1)
  • parseTriple (47-89)
src/index.ts (3)
src/constants.ts (2)
  • require (7-9)
  • LOG_PREFIX (11-11)
src/helpers.ts (6)
  • removeRecursive (20-36)
  • getGlobalNpmRegistry (9-18)
  • getErrorMessage (251-253)
  • getNapiInfoFromPackageJson (51-91)
  • getNapiNativeTargets (243-249)
  • downloadedNodePath (38-41)
src/types.ts (1)
  • PackageJson (24-29)
🪛 LanguageTool
README.md

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Package Size Report
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
🔇 Additional comments (1)
package.json (1)

14-16: Verify CLI shebang is emitted

bin.napi-postinstall points to ./lib/cli.js.  If the compiled file lacks a #!/usr/bin/env node shebang, npm will mark it non‑executable on POSIX systems, breaking direct invocation (napi-postinstall …).

Please confirm the compiled output retains the shebang or add it manually, e.g.:

// src/cli.ts
#!/usr/bin/env node

and ensure tsc preserves it (removeComments: false).

@JounQin JounQin force-pushed the feat/work branch 2 times, most recently from 0b9d37d to a914e64 Compare April 19, 2025 17:38
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

♻️ Duplicate comments (3)
src/helpers.ts (1)

38-41: ⚠️ Potential issue

Path‑truncation bug previously reported is still present

path.basename(subpath) removes nested directories so "darwin/x64/native.node" collapses to native.node, risking clashes across archs.

This is the exact issue flagged in a past review; please address it:

-return path.join(pkgLibDir, `${path.basename(subpath)}`)
+// preserve the relative directory structure
+return path.join(pkgLibDir, subpath)
src/index.ts (2)

106-109: ⚠️ Potential issue

Command‑injection & Windows quoting issues in installUsingNPM

Building a shell string with ${pkg}@${version} re‑introduces the injection vector previously highlighted. A malicious (or simply malformed) version like 1.2.3 && rm -rf / compromises the host.

Please switch to spawnSync('npm', [...args]), which bypasses the shell:

-    execSync(
-      `npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${version}`,
-      { cwd: installDir, stdio: 'pipe', env },
-    )
+    const { status, error } = spawnSync(
+      'npm',
+      [
+        'install',
+        '--loglevel=error',
+        '--prefer-offline',
+        '--no-audit',
+        '--progress=false',
+        `${pkg}@${version}`,
+      ],
+      { cwd: installDir, stdio: 'pipe', env },
+    )
+    if (status !== 0) throw error ?? new Error('npm install failed')

238-241: ⚠️ Potential issue

Wrong package version passed to fallback installers

installUsingNPM(name, pkg, version, …) forwards the host package version (package.json.version) instead of the binary’s declared version in optionalDependencies[pkg].

Same bug occurs for downloadDirectlyFromNPM at L250‑251.
This installs or downloads the wrong tarball, leading to checksum/ABI mismatch.

-        installUsingNPM(name, pkg, version, subpath, nodePath)
+        installUsingNPM(
+          name,
+          pkg,
+          optionalDependencies![pkg]!, // guaranteed by earlier guard
+          subpath,
+          nodePath,
+        )

and

-          await downloadDirectlyFromNPM(pkg, version, subpath, nodePath)
+          await downloadDirectlyFromNPM(
+            pkg,
+            optionalDependencies![pkg]!,
+            subpath,
+            nodePath,
+          )
🧹 Nitpick comments (3)
package.json (1)

10-13: Node 12 is EOL – consider dropping it from the engines range

"node": "^12.20.0 || ^14.18.0 || >=16.0.0" still lists Node 12 which left active LTS in Apr 2022.
Continuing support complicates your code (e.g. process.report is Node >= 12. Makes musl detection brittle). If you no longer test against 12, update the range to >=14.18 or higher.

src/helpers.ts (1)

9-18: Honor npm_config_registry before shelling out

getGlobalNpmRegistry() ignores the already‑parsed environment variable npm_config_registry and always spawns npm config get, incurring ~40 ms overhead on every call and failing when npm isn’t in PATH.

 export function getGlobalNpmRegistry() {
-  try {
+  if (process.env.npm_config_registry) {
+    const r = process.env.npm_config_registry
+    return r.endsWith('/') ? r : `${r}/`
+  }
+  try {
src/index.ts (1)

150-170: Consider streaming the tarball to disk instead of buffering

fetch() loads the entire .tgz into memory and extractFileFromTarGzip decompresses it again in‑memory, doubling peak RAM. Large prebuilds (e.g. TensorFlow) can OOM small CI agents.

For a future improvement, pipe the response into zlib.createUnzip() and parse the tar headers on the fly.

🛑 Comments failed to post (2)
package.json (2)

78-79: ⚠️ Potential issue

Self‑referencing devDependency can break local installs

"napi-postinstall": "file:",

Adding the package itself as a file: devDependency causes an extra node_modules/napi-postinstall symlink that may confuse tools (e.g. Jest’s module resolver) and bloats the tarball.
Unless you rely on this for an e2e test, please remove the entry or gate it behind a workspace alias.

-    "napi-postinstall": "file:",

14-16: 🛠️ Refactor suggestion

🏷️ bin entry may ship an unusable executable without a shebang

"napi-postinstall": "./lib/cli.js" expects lib/cli.js to be directly runnable by the OS.
Please double‑check that the compiled file starts with a POSIX shebang (#!/usr/bin/env node) and has the executable bit set during npm pack, otherwise npx napi-postinstall will fail on *nix systems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
README.md (1)

79-82: Incomplete PackageJson interface in README
The PackageJson interface examples in the README omit the optionalDependencies and napi fields present in the actual API. It should include:

 export interface PackageJson {
   name: string
   version: string
+  optionalDependencies?: Partial<Record<string, string>>
+  napi?: {
+    packageName?: string
+    binaryName?: string
+    targets?: string[]
+  }
 }
🧹 Nitpick comments (2)
README.md (2)

16-16: Fix run‑on sentence in project description
The description sentence is currently a run‑on. Consider splitting into two sentences or using a semicolon. For example:

-The `postinstall` script helper for handling native bindings in legacy `npm` versions, this is a reimplementation of the [`node-install`][node-install] functionality...
+The `postinstall` script helper for handling native bindings in legacy `npm` versions. This is a reimplementation of the [`node-install`][node-install] functionality...
🧰 Tools
🪛 LanguageTool

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)


59-59: Clarify CLI usage placeholder
Using #<napi-package-name> in a shell snippet may be misleading because # starts a comment. Prefer a placeholder without the hash:

-napi-postinstall unrs-resolver #<napi-package-name>
+napi-postinstall <napi-package-name>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b9d37d and a914e64.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (25)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (0 hunks)
  • .prettierignore (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (3)
  • .gitignore
  • index.d.cts
  • eslint.config.js
✅ Files skipped from review due to trivial changes (3)
  • patches/rollup+4.40.0.patch
  • src/constants.ts
  • src/helpers.ts
🚧 Files skipped from review as they are similar to previous changes (18)
  • .changeset/config.json
  • vercel.json
  • .size-limit.json
  • .prettierignore
  • vitest.config.mts
  • .github/workflows/pkg-pr-new.yml
  • .github/workflows/size-limit.yml
  • tsconfig.json
  • .github/workflows/release.yml
  • src/cli.ts
  • .github/workflows/autofix.yml
  • .github/workflows/ci.yml
  • eslint.config.mjs
  • test/basic.spec.ts
  • src/types.ts
  • src/target.ts
  • src/index.ts
  • package.json
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
🔇 Additional comments (5)
README.md (5)

1-1: Project name updated in title
Great job updating the H1 title to napi-postinstall to reflect the rebrand.


3-8: Badges updated to reflect new package name
All shields (GitHub Actions, Codecov, type‑coverage, CodeRabbit, npm, GitHub Release) now reference napi-postinstall.


28-31: TOC updated with CLI, Types, and Example sections
The table of contents now includes the new [CLI], [Types], and [Example] entries under Usage and API. Looks consistent.


44-54: Installation commands updated
All installation snippets (pnpm, yarn, npm, bun) correctly reference napi-postinstall.


66-66: CI integration snippet is correct
The example shows how to wire napi-postinstall into scripts.postinstall in package.json. No changes needed here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
src/helpers.ts (1)

38-41: ⚠️ Potential issue

Path‑truncation bug is still present
path.basename(subpath) discards intermediate directories, so a binary like darwin/x64/native.node flattens to native.node, causing collisions between targets and breaking require.resolve(). Preserve the relative directory structure instead.

-  return path.join(pkgLibDir, `${path.basename(subpath)}`)
+  // Keep the original sub‑directory layout to avoid name clashes
+  return path.join(pkgLibDir, subpath)
src/index.ts (2)

106-109: 🛠️ Refactor suggestion

Shell‑injection & Windows‑portability risk in npm install call
Building an execSync command string allows malicious pkg/version values (they come from package.json but defence‑in‑depth is recommended) and relies on a shell being present. Prefer spawnSync('npm', [...args]).

-import { execSync } from 'node:child_process'
+import { spawnSync } from 'node:child_process'-    execSync(
-      `npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${version}`,
-      { cwd: installDir, stdio: 'pipe', env },
-    )
+    const { status, error } = spawnSync(
+      'npm',
+      [
+        'install',
+        '--loglevel=error',
+        '--prefer-offline',
+        '--no-audit',
+        '--progress=false',
+        `${pkg}@${version}`,
+      ],
+      { cwd: installDir, stdio: 'pipe', env },
+    )
+    if (status !== 0) throw error ?? new Error('npm install failed')

238-259: ⚠️ Potential issue

Incorrect package version is forwarded during fallback installation
installUsingNPM() and downloadDirectlyFromNPM() receive the host package’s version (${version}) instead of the binary package’s version declared in optionalDependencies![pkg]. This installs/ downloads the wrong tarball and can lead to runtime ABI errors.

-        installUsingNPM(name, pkg, version, subpath, nodePath)
+        installUsingNPM(name, pkg, optionalDependencies![pkg]!, subpath, nodePath)-          await downloadDirectlyFromNPM(pkg, version, subpath, nodePath)
+          await downloadDirectlyFromNPM(pkg, optionalDependencies![pkg]!, subpath, nodePath)
README.md (1)

78-83: PackageJson type is still incomplete in documentation
optionalDependencies and the napi field are essential for this library yet are omitted from the README type example, which may mislead users.

 export interface PackageJson {
   name: string
   version: string
+  optionalDependencies?: Partial<Record<string, string>>
+  napi?: {
+    packageName?: string
+    binaryName?: string
+    targets?: string[]
+    triples?: { additional?: string[] }
+  }
 }
🧹 Nitpick comments (1)
src/index.ts (1)

238-259: Consider trying the next target instead of hard‑failing
If installation for the first target (darwin-universal, linux-musl, …) fails, the loop aborts with an error even though a secondary target in napi.targets might already be present locally. Re‑ordering or continuing the loop after a failed attempt will improve robustness.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a914e64 and f3478cc.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (25)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (0 hunks)
  • .prettierignore (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (3)
  • .gitignore
  • index.d.cts
  • eslint.config.js
🚧 Files skipped from review as they are similar to previous changes (18)
  • .changeset/config.json
  • .size-limit.json
  • vercel.json
  • .github/workflows/pkg-pr-new.yml
  • .github/workflows/autofix.yml
  • vitest.config.mts
  • .github/workflows/release.yml
  • patches/rollup+4.40.0.patch
  • tsconfig.json
  • .prettierignore
  • .github/workflows/size-limit.yml
  • .github/workflows/ci.yml
  • src/cli.ts
  • src/constants.ts
  • test/basic.spec.ts
  • eslint.config.mjs
  • src/target.ts
  • src/types.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/index.ts (3)
src/constants.ts (2)
  • require (7-9)
  • LOG_PREFIX (11-11)
src/helpers.ts (6)
  • removeRecursive (20-36)
  • getGlobalNpmRegistry (9-18)
  • getErrorMessage (251-253)
  • getNapiInfoFromPackageJson (51-91)
  • getNapiNativeTargets (243-249)
  • downloadedNodePath (38-41)
src/types.ts (1)
  • PackageJson (25-30)
🪛 LanguageTool
README.md

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
🔇 Additional comments (8)
package.json (8)

2-4: Confirm package rename and module type
The package has been rebranded from native-postinstall to napi-postinstall and switched to CommonJS via "type": "commonjs". Ensure downstream consumers and CI workflows accommodate this rename and module type change.


6-6: Verify repository URL update
The repository field now points to https://github.com/un-ts/napi-postinstall.git. Confirm this is the correct GitHub organization and repository name.


14-17: Validate CLI and main entry points
The bin mapping (napi-postinstall: ./lib/cli.js) and main entry (./lib/index.js) should align with the built outputs. Confirm that your build step emits both cli.js and index.js under lib.


18-25: Review exports configuration
The exports field explicitly defines the types, default, and exports of package.json, and it matches the main/types fields. This alignment supports both CJS and type-aware imports.


31-31: Approve updated build script
Switching to "build": "tsc -b src" simplifies the TypeScript compilation. Ensure your tsconfig.json paths and build references are correctly set up for project references.


41-41: Approve prepare script integration
The prepare script now runs patch-package and simple-git-hooks to apply local patches and install Git hooks. Verify that the patches directory exists and that the hooks are correctly configured for your repo.


46-46: Verify Vercel build command
The vercel-build script invokes napi-postinstall rollup. Confirm that the CLI offers a rollup command and that it works seamlessly with your Vite docs build.


62-62: Review added devDependencies
New devDependencies (@types/pnpapi, @unts/patch-package, eslint-plugin-node-dependencies, size-limit-preset-node-lib, vite-tsconfig-paths) support PnP, patching, lint rules, size-limit presets, and path aliasing. Ensure each is utilized in your configs or code.

Also applies to: 66-66, 74-74, 88-88, 93-93

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (4)
README.md (1)

79-82: Extend the PackageJson interface to align with implementation
The PackageJson interface omits properties used in your code (e.g., optionalDependencies, napi). Please include them so the docs match the actual types.

 export interface PackageJson {
   name: string
   version: string
+  optionalDependencies?: Partial<Record<string, string>>
+  napi?: {
+    packageName?: string
+    binaryName?: string
+    targets?: string[]
+  }
 }
src/helpers.ts (1)

38-41: ⚠️ Potential issue

Path‑truncation bug when resolving downloaded binaries
(duplicate of a past review)

path.basename(subpath) strips intermediate directories, so
"darwin/x64/native.node" collapses to native.node, causing collisions.

-return path.join(pkgLibDir, `${path.basename(subpath)}`)
+// preserve directory structure relative to the package root
+return path.join(pkgLibDir, subpath)
src/index.ts (2)

106-109: Shell‑string construction in execSync enables command‑injection
(same as previously flagged)

The interpolated shell string can be broken by malicious or malformed pkg/version values.
Please switch to spawnSync('npm', [...args]) to avoid invoking the shell.


239-251: ⚠️ Potential issue

Incorrect package version is used for fallback installation

version refers to the host package (${name}) version, not the binary package in optionalDependencies.
Passing it to both installUsingNPM and downloadDirectlyFromNPM fetches the wrong tarball, leading to checksum or ABI mismatches.

-        installUsingNPM(name, pkg, version, subpath, nodePath)
+        installUsingNPM(
+          name,
+          pkg,
+          optionalDependencies![pkg]!, // use the binary’s declared version
+          subpath,
+          nodePath,
+        )-          await downloadDirectlyFromNPM(pkg, version, subpath, nodePath)
+          await downloadDirectlyFromNPM(
+            pkg,
+            optionalDependencies![pkg]!, // same here
+            subpath,
+            nodePath,
+          )
🧹 Nitpick comments (12)
lib/types.js (1)

1-1: Redundant "use strict" directive
ES modules are strict by default; you can safely remove this line.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/cli.js (1)

2-2: Remove redundant "use strict" directive
CommonJS modules in Node.js are strict by default; this directive can be removed.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js (1)

1-1: Remove redundant "use strict" directive
CommonJS modules are strict by default in Node.js; you can safely remove this line.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

README.md (1)

16-16: Fix run-on sentence in introduction
The sentence here is a bit long and should be split for clarity. For example:

- The `postinstall` script helper for handling native bindings in legacy `npm` versions, this is a reimplementation...
+ The `postinstall` script helper for handling native bindings in legacy `npm` versions. This is a reimplementation...
🧰 Tools
🪛 LanguageTool

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

lib/target.js (1)

1-1: Remove redundant "use strict" directive

Node treats every CommonJS module as strict‑mode by default, so the leading directive is unnecessary noise.
Removing it prevents the Biome warning without changing behaviour.

-"use strict";
+// Strict mode is implicit in CommonJS modules
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js (2)

1-1: Drop redundant "use strict"

Same reasoning as in lib/target.js; this keeps the compiled output clean and silences Biome.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)


31-37: Use gunzipSync instead of unzipSync for npm tarballs

npm packages are *.tgz (gzip) archives; zlib.unzipSync works but incurs an
extra format‑detection step and fails on some edge‑cases.
gunzipSync is purpose‑built for gzip and slightly faster.

- buffer = node_zlib_1.default.unzipSync(buffer);
+ buffer = node_zlib_1.default.gunzipSync(buffer);
package.json (1)

78-79: Self‑reference in devDependencies is still risky

"napi-postinstall": "file:." works for local development but:

  1. Confuses some package‑managers (pnpm ≤7, older Yarn) during hoisting.
  2. Bloats the tarball (npm pack embeds the entire project twice).

Consider replacing with a workspace version ("workspace:*") or removing the
entry entirely—tests can import from src/lib directly.

src/helpers.ts (1)

9-18: Honor npm_config_registry environment variable first

npm config get registry spawns a process and fails when npm isn’t in PATH
(e.g. during pnpm or Yarn installs). A simpler, faster fallback is the
well‑known env var.

 export function getGlobalNpmRegistry() {
-  try {
+  const registryEnv = process.env.npm_config_registry
+  if (registryEnv) {
+    return registryEnv.endsWith('/') ? registryEnv : `${registryEnv}/`
+  }
+  try {
lib/helpers.js (2)

1-1: Remove the redundant "use strict" directive

JavaScript modules are automatically executed in strict mode. Keeping the directive here is harmless but clutters the top of every compiled file and is flagged by Biome.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)


94-99: Fallback path for ldd lookup may miss common location

Some distributions place ldd under /usr/bin, others under /bin.
If /usr/bin/ldd is absent the function returns null even though the file exists elsewhere, degrading musl detection accuracy.

Consider trying the alternative path before giving up:

-    return node_fs_1.default.readFileSync('/usr/bin/ldd', 'utf8').includes('musl');
+    for (const p of ['/usr/bin/ldd', '/bin/ldd']) {
+      try {
+        if (node_fs_1.default.readFileSync(p, 'utf8').includes('musl')) return true;
+      } catch {}
+    }
+    return false;
src/index.ts (1)

23-43: fetch() has no redirect limit and can recurse indefinitely

If the registry or a proxy misbehaves and produces a redirect loop, the current implementation will recurse until the call stack overflows.

Add a hop counter (e.g. maxRedirects = 5) or switch to node-fetch/undici which handle this internally.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3478cc and 365625f.

⛔ Files ignored due to path filters (7)
  • lib/cli.js.map is excluded by !**/*.map
  • lib/constants.js.map is excluded by !**/*.map
  • lib/helpers.js.map is excluded by !**/*.map
  • lib/index.js.map is excluded by !**/*.map
  • lib/target.js.map is excluded by !**/*.map
  • lib/types.js.map is excluded by !**/*.map
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (37)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (1 hunks)
  • .prettierignore (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • lib/cli.d.ts (1 hunks)
  • lib/cli.js (1 hunks)
  • lib/constants.d.ts (1 hunks)
  • lib/constants.js (1 hunks)
  • lib/helpers.d.ts (1 hunks)
  • lib/helpers.js (1 hunks)
  • lib/index.d.ts (1 hunks)
  • lib/index.js (1 hunks)
  • lib/target.d.ts (1 hunks)
  • lib/target.js (1 hunks)
  • lib/types.d.ts (1 hunks)
  • lib/types.js (1 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (2)
  • index.d.cts
  • eslint.config.js
✅ Files skipped from review due to trivial changes (7)
  • .github/workflows/autofix.yml
  • lib/cli.d.ts
  • lib/constants.d.ts
  • lib/index.d.ts
  • lib/target.d.ts
  • lib/types.d.ts
  • lib/helpers.d.ts
🚧 Files skipped from review as they are similar to previous changes (17)
  • .changeset/config.json
  • vercel.json
  • .github/workflows/size-limit.yml
  • .github/workflows/pkg-pr-new.yml
  • vitest.config.mts
  • patches/rollup+4.40.0.patch
  • tsconfig.json
  • .size-limit.json
  • .github/workflows/release.yml
  • .github/workflows/ci.yml
  • src/cli.ts
  • src/constants.ts
  • eslint.config.mjs
  • .gitignore
  • test/basic.spec.ts
  • src/types.ts
  • src/target.ts
🧰 Additional context used
🧬 Code Graph Analysis (3)
lib/target.js (1)
src/target.ts (1)
  • parseTriple (47-89)
src/index.ts (3)
src/constants.ts (2)
  • require (7-9)
  • LOG_PREFIX (11-11)
src/helpers.ts (6)
  • removeRecursive (20-36)
  • getGlobalNpmRegistry (9-18)
  • getErrorMessage (261-263)
  • getNapiInfoFromPackageJson (51-101)
  • getNapiNativeTargets (253-259)
  • downloadedNodePath (38-41)
src/types.ts (1)
  • PackageJson (28-33)
lib/constants.js (3)
lib/helpers.js (2)
  • tslib_1 (10-10)
  • node_path_1 (13-13)
lib/index.js (2)
  • tslib_1 (4-4)
  • node_path_1 (8-8)
src/constants.ts (1)
  • require (7-9)
🪛 Biome (1.9.4)
lib/target.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/helpers.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/cli.js

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/types.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

🪛 LanguageTool
README.md

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: Package Size Report
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on macos-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on ubuntu-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
🔇 Additional comments (4)
lib/types.js (1)

1-3: Verify the purpose of this stub file
lib/types.js emits no runtime exports apart from module markers. If it exists solely to support .d.ts files, consider removing it or adding explicit re-exports (e.g., export * from "../src/types";) to clarify its intent.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

.prettierignore (1)

1-2: Ignoring compiled output and static assets
It’s correct to ignore the lib and public directories so that Prettier skips build artifacts and static files.

lib/constants.js (1)

8-8:

Details

✅ Verification successful

Ensure package.json is included in the published package
This module dynamically requires package.json at runtime. Verify via npm pack --dry-run that package.json is part of the packaged files to avoid runtime MODULE_NOT_FOUND errors.


🏁 Script executed:

#!/bin/bash
npm pack --dry-run | grep "package.json"

Length of output: 1177


package.json is included in the published package
Verified via npm pack --dry-run, which lists package.json among the tarball contents. No further action required.

package.json (1)

14-17: CLI binary is exposed but not shipped if lib/ is git‑ignored

bin.napi-postinstall points to ./lib/cli.js and "files": ["lib", …]
whitelists the directory, so the file will publish correctly as long as
lib is committed
.
Double‑check that your .gitignore no longer excludes lib/, otherwise users
will install an empty executable.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (9)
lib/cli.js (1)

5-5: Add error handling for the CLI invocation

Currently, unhandled promise rejections from checkAndPreparePackage won't set a non-zero exit code, which can mask failures in scripts. Wrap the call to catch errors and exit with code 1.

Apply this diff:

- void (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]));
+ (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]))
+  .catch(err => {
+    console.error(err);
+    process.exit(1);
+  });
README.md (1)

79-82: Incomplete PackageJson interface in README

The PackageJson interface in the README is incomplete compared to the actual implementation. It's missing the optionalDependencies and napi properties that are crucial for the package functionality.

export interface PackageJson {
  name: string
  version: string
+  optionalDependencies?: Partial<Record<string, string>>
+  napi?: {
+    packageName?: string
+    binaryName?: string
+    targets?: string[]
+  }
}
lib/target.js (1)

31-33: ⚠️ Potential issue

Fix the eabi suffix normalization to avoid suffix duplication

Currently, the code will incorrectly handle target triples that end with "gnueabi" by splitting "gnu" and "eabi", causing incorrect platform detection.

- const triple = rawTriple.endsWith('eabi')
-     ? `${rawTriple.slice(0, -4)}-eabi`
+ const triple = rawTriple.endsWith('-eabi')
+     ? `${rawTriple.slice(0, -5)}-eabi`
      : rawTriple;
lib/index.js (2)

12-30: ⚠️ Potential issue

Fix redirect handling for HTTP responses

The current redirect handling has two issues:

  1. It only handles 301 and 302 status codes, missing 303, 307, and 308 redirects
  2. It doesn't properly handle relative URLs in the location header
- if ((res.statusCode === 301 || res.statusCode === 302) &&
-     res.headers.location) {
-   fetch(res.headers.location).then(resolve, reject);
+ const redirectCodes = [301, 302, 303, 307, 308];
+ if (redirectCodes.includes(res.statusCode) && res.headers.location) {
+   const nextUrl = res.headers.location.startsWith('http')
+     ? res.headers.location
+     : new URL(res.headers.location, url).toString();
+   fetch(nextUrl).then(resolve, reject);
   return;
 }

68-68: ⚠️ Potential issue

Fix shell injection vulnerability in npm install command

The current implementation embeds package name and version directly in a shell command, which presents a security risk if these values contain malicious shell commands.

- (0, node_child_process_1.execSync)(`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${version}`, { cwd: installDir, stdio: 'pipe', env });
+ (0, node_child_process_1.execFileSync)('npm', [
+   'install',
+   '--loglevel=error',
+   '--prefer-offline',
+   '--no-audit',
+   '--progress=false',
+   `${pkg}@${version}`
+ ], { cwd: installDir, stdio: 'pipe', env });
lib/helpers.js (1)

27-45: 🛠️ Refactor suggestion

Modernize recursive directory removal implementation

The current implementation uses the deprecated fs.rmdirSync() method, which will eventually be removed from Node.js. Modern Node.js versions provide a simpler and more robust solution.

 function removeRecursive(dir) {
-  for (const entry of node_fs_1.default.readdirSync(dir)) {
-    const entryPath = node_path_1.default.join(dir, entry);
-    let stats;
-    try {
-      stats = node_fs_1.default.lstatSync(entryPath);
-    }
-    catch (_a) {
-      continue;
-    }
-    if (stats.isDirectory()) {
-      removeRecursive(entryPath);
-    }
-    else {
-      node_fs_1.default.unlinkSync(entryPath);
-    }
-  }
-  node_fs_1.default.rmdirSync(dir);
+  // `rmSync` is available since Node 14.14 and replaces the
+  // deprecated `rmdirSync` for recursive deletions.
+  node_fs_1.default.rmSync(dir, { recursive: true, force: true });
 }
src/index.ts (3)

106-109: ⚠️ Potential issue

Security Issue: Potential command injection vulnerability.

The use of template literals with execSync can lead to command injection vulnerabilities if pkg or version contains malicious characters. This was previously flagged in a past review but remains unaddressed.

-import { execSync } from 'node:child_process'
+import { execSync, spawnSync } from 'node:child_process'

-    execSync(
-      `npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${version}`,
-      { cwd: installDir, stdio: 'pipe', env },
-    )
+    const { status, error } = spawnSync(
+      'npm',
+      [
+        'install',
+        '--loglevel=error',
+        '--prefer-offline',
+        '--no-audit',
+        '--progress=false',
+        `${pkg}@${version}`,
+      ],
+      { cwd: installDir, stdio: 'pipe', env },
+    )
+    if (status !== 0) throw error ?? new Error('npm install failed')

239-239: ⚠️ Potential issue

Incorrect version used when installing the binary package.

This line uses the host package version (version) instead of the version declared in optionalDependencies[pkg]. This can lead to checksum mismatches or runtime ABI errors when checkVersion is false.

-        installUsingNPM(name, pkg, version, subpath, nodePath)
+        installUsingNPM(name, pkg, optionalDependencies![pkg]!, subpath, nodePath)

250-250: ⚠️ Potential issue

Incorrect version used when downloading the binary package.

Similarly to the previous issue, this line uses the host package version (version) instead of the version declared in optionalDependencies[pkg].

-          await downloadDirectlyFromNPM(pkg, version, subpath, nodePath)
+          await downloadDirectlyFromNPM(pkg, optionalDependencies![pkg]!, subpath, nodePath)
🧹 Nitpick comments (8)
lib/types.js (1)

1-1: Consider removing redundant "use strict" directive

JavaScript modules are automatically in strict mode, making this directive unnecessary.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

README.md (1)

16-22: Fix run-on sentence in project description

The project description contains a run-on sentence that could be improved for clarity.

-The `postinstall` script helper for handling native bindings in legacy `npm` versions, this is a reimplementation of the [`node-install`][node-install] functionality from [`esbuild`][esbuild] for [`napi-rs`][napi-rs] ecosystem packages like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver].
+The `postinstall` script helper for handling native bindings in legacy `npm` versions. This is a reimplementation of the [`node-install`][node-install] functionality from [`esbuild`][esbuild] for [`napi-rs`][napi-rs] ecosystem packages like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver].
🧰 Tools
🪛 LanguageTool

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

lib/target.js (1)

1-1: Remove redundant "use strict" directive

ES modules are automatically in strict mode, making this directive unnecessary.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js (1)

1-1: Remove redundant "use strict" directive

ES modules are automatically in strict mode, making this directive unnecessary.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/helpers.js (1)

1-1: Remove redundant "use strict" directive

ES modules are automatically in strict mode, making this directive unnecessary.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

src/index.ts (3)

158-158: Improve package name handling in URL construction.

The logic for extracting the package name from scoped packages is complex and could be clearer. Consider extracting this into a separate utility function for better readability and maintainability.

-  const url = `${getGlobalNpmRegistry()}${pkg}/-/${pkg.startsWith('@') ? pkg.split('/')[1] : pkg}-${version}.tgz`
+  const packageFileName = pkg.startsWith('@') ? pkg.split('/')[1] : pkg
+  const url = `${getGlobalNpmRegistry()}${pkg}/-/${packageFileName}-${version}.tgz`

202-204: Avoid non-null assertion operator.

Although the comment indicates optionalDependencies has been verified to exist, using the non-null assertion operator (!) is generally not recommended as it bypasses TypeScript's type checking.

-    if (!optionalDependencies![pkg]) {
+    if (!optionalDependencies?.[pkg]) {
       continue
     }

196-198: Consider filtering targets based on the current platform.

The code iterates through all targets returned by getNapiNativeTargets() without filtering for the current platform first. This could be inefficient, especially when there are many targets.

  const targets = getNapiNativeTargets()
+  
+  // Filter targets to prioritize the current platform
+  const currentPlatformTargets = targets.filter(target => 
+    target.includes(process.platform) && target.includes(process.arch)
+  );
+  const targetList = currentPlatformTargets.length > 0 ? currentPlatformTargets : targets;

-  for (const target of targets) {
+  for (const target of targetList) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 365625f and 2c42fe8.

⛔ Files ignored due to path filters (7)
  • lib/cli.js.map is excluded by !**/*.map
  • lib/constants.js.map is excluded by !**/*.map
  • lib/helpers.js.map is excluded by !**/*.map
  • lib/index.js.map is excluded by !**/*.map
  • lib/target.js.map is excluded by !**/*.map
  • lib/types.js.map is excluded by !**/*.map
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (37)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (1 hunks)
  • .prettierignore (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • lib/cli.d.ts (1 hunks)
  • lib/cli.js (1 hunks)
  • lib/constants.d.ts (1 hunks)
  • lib/constants.js (1 hunks)
  • lib/helpers.d.ts (1 hunks)
  • lib/helpers.js (1 hunks)
  • lib/index.d.ts (1 hunks)
  • lib/index.js (1 hunks)
  • lib/target.d.ts (1 hunks)
  • lib/target.js (1 hunks)
  • lib/types.d.ts (1 hunks)
  • lib/types.js (1 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (2)
  • index.d.cts
  • eslint.config.js
✅ Files skipped from review due to trivial changes (4)
  • .github/workflows/pkg-pr-new.yml
  • lib/constants.d.ts
  • .github/workflows/autofix.yml
  • lib/types.d.ts
🚧 Files skipped from review as they are similar to previous changes (22)
  • vercel.json
  • .changeset/config.json
  • .prettierignore
  • vitest.config.mts
  • .size-limit.json
  • .gitignore
  • tsconfig.json
  • .github/workflows/release.yml
  • lib/cli.d.ts
  • .github/workflows/size-limit.yml
  • patches/rollup+4.40.0.patch
  • src/constants.ts
  • src/cli.ts
  • eslint.config.mjs
  • .github/workflows/ci.yml
  • test/basic.spec.ts
  • lib/helpers.d.ts
  • lib/index.d.ts
  • src/target.ts
  • src/helpers.ts
  • src/types.ts
  • lib/target.d.ts
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/index.ts (3)
src/constants.ts (2)
  • require (7-9)
  • LOG_PREFIX (11-11)
src/helpers.ts (6)
  • removeRecursive (20-36)
  • getGlobalNpmRegistry (9-18)
  • getErrorMessage (261-263)
  • getNapiInfoFromPackageJson (51-101)
  • getNapiNativeTargets (253-259)
  • downloadedNodePath (38-41)
src/types.ts (1)
  • PackageJson (28-33)
lib/constants.js (3)
lib/helpers.js (2)
  • tslib_1 (10-10)
  • node_path_1 (13-13)
lib/index.js (2)
  • tslib_1 (4-4)
  • node_path_1 (8-8)
src/constants.ts (1)
  • require (7-9)
lib/target.js (1)
src/target.ts (1)
  • parseTriple (47-89)
🪛 LanguageTool
README.md

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

🪛 Biome (1.9.4)
lib/cli.js

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/helpers.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/target.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/types.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
🔇 Additional comments (14)
lib/types.js (1)

2-3: LGTM: Module ES export setup is correct

This sets up the module as an ES module with the __esModule property, providing proper interoperability with TypeScript declarations in src/types.ts and lib/types.d.ts.

lib/cli.js (1)

1-4: CLI shebang and imports look good

The shebang line and imports are correctly set up for a Node.js CLI executable.

Consider removing the redundant "use strict" directive as JavaScript modules are automatically in strict mode:

#!/usr/bin/env node
-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js (3)

1-6: Initial setup for constants module looks good

The module imports and exports declaration are correctly set up with TypeScript interoperability.

Consider removing the redundant "use strict" directive:

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)


7-7: Default NPM registry constant is correct

The URL for the default NPM registry is properly defined.


9-9: Log prefix format is clear and consistent

The LOG_PREFIX format with package name and version is well-structured for logging.

README.md (5)

1-8: Project renaming and badges are correctly updated

All references to the project name have been properly updated from native-postinstall to napi-postinstall in the badges and links.


58-72: CLI documentation is clear and helpful

The CLI usage examples and instructions for integrating with package.json are well-documented.


84-87: Function signature documentation looks good

The checkAndPreparePackage function signature is well-documented with appropriate types and parameters.


92-96: Usage example is clear and up-to-date

The example code correctly demonstrates how to use the package with the new import style.


122-126: References to related projects are complete

All references to related projects like node-install, esbuild, napi-rs, rollup, and unrs-resolver are correctly linked.

package.json (3)

78-78: LGTM: Local file dependency properly specified

The self-reference for development testing is correctly configured.


14-16: LGTM: CLI binary entry point properly configured

The binary entry point for the CLI tool is correctly configured to point to the compiled JavaScript file.


19-25: LGTM: Export mappings correctly structured

The exports field properly defines the entry points for the package, including type definitions and the package.json itself.

lib/helpers.js (1)

129-206: LGTM: Comprehensive platform detection for native binaries

The getNapiNativeTarget function provides thorough platform, architecture, and libc variant detection for a wide range of environments. This implementation properly handles special cases like:

  • WebAssembly/WASI targets
  • Darwin universal binaries
  • Musl vs GNU libc distinctions on Linux
  • Various architectures including arm, arm64, x64, ia32, riscv64, ppc64, and s390x

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (7)
lib/cli.js (1)

5-5: Add error handling for the CLI invocation

Currently, unhandled promise rejections from checkAndPreparePackage won't set a non-zero exit code, which can mask failures in scripts. Wrap the call to catch errors and exit with code 1.

Apply this diff:

- void (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]));
+ (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]))
+  .catch(err => {
+    console.error(err);
+    process.exit(1);
+  });
lib/constants.js (1)

8-8: Add error handling for package.json loading

The code directly requires package.json without any error handling. If the file is missing or invalid, this will throw an uncaught exception.

-_a = require(node_path_1.default.resolve(__dirname, '../package.json')), exports.name = _a.name, exports.version = _a.version;
+try {
+  _a = require(node_path_1.default.resolve(__dirname, '../package.json'));
+  exports.name = _a.name;
+  exports.version = _a.version;
+} catch (error) {
+  console.error('Failed to load package.json:', error);
+  exports.name = 'napi-postinstall';
+  exports.version = 'unknown';
+}
README.md (1)

79-82: Incomplete PackageJson interface in README

The PackageJson interface in the README is incomplete compared to the actual implementation. It's missing the optionalDependencies and napi properties that are crucial for the package functionality.

export interface PackageJson {
  name: string
  version: string
+  optionalDependencies?: Partial<Record<string, string>>
+  napi?: {
+    packageName?: string
+    binaryName?: string
+    targets?: string[]
+  }
}
lib/target.js (1)

31-33: ⚠️ Potential issue

Double “‑eabi” suffix bug is still present
Previous feedback noted that checking rawTriple.endsWith('eabi') and slicing -4 produces armv7-unknown-linux-gnu‑eabi (duplicated hyphen) for triples already ending in gnueabi.

-const triple = rawTriple.endsWith('eabi')
-  ? `${rawTriple.slice(0, -4)}-eabi`
+const triple = rawTriple.endsWith('-eabi')
+  ? `${rawTriple.slice(0, -5)}-eabi`

This keeps existing “gnueabi” intact while normalising genuine “‑eabi” triples.

lib/index.js (2)

16-20: ⚠️ Potential issue

Redirect handler still ignores 303/307/308 and relative locations
Earlier review covered this; the current logic only follows 301/302 and assumes an absolute URL. This will break against the npm registry and other CDNs.

- if ((res.statusCode === 301 || res.statusCode === 302) && res.headers.location) {
-   fetch(res.headers.location).then(resolve, reject);
+ const redirects = [301, 302, 303, 307, 308];
+ if (redirects.includes(res.statusCode) && res.headers.location) {
+   const next = res.headers.location.startsWith('http')
+     ? res.headers.location
+     : new URL(res.headers.location, url).toString();
+   fetch(next).then(resolve, reject);
   return;
 }

68-69: ⚠️ Potential issue

Command‑injection / escaping issue in installUsingNPM
Interpolating ${pkg}@${version} inside a shell string lets a crafted version slip arbitrary commands (1.2.3 && rm -rf /). Switch to the argument form of execFileSync (or at least spawnSync) so Node handles escaping for you.

- execSync(`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${version}`, { cwd: installDir, stdio: 'pipe', env })
+ execSync(
+   'npm',
+   ['install', '--loglevel=error', '--prefer-offline', '--no-audit',
+    '--progress=false', `${pkg}@${version}`],
+   { cwd: installDir, stdio: 'pipe', env }
+ )
src/helpers.ts (1)

38-41: ⚠️ Potential issue

Binary sub‑path is truncated – may cause name collisions
Using path.basename(subpath) strips directory structure (darwin/x64/native.nodenative.node). Multiple targets can therefore overwrite each other.

-return path.join(pkgLibDir, `${path.basename(subpath)}`)
+// Preserve relative folders to avoid collisions between different targets
+return path.join(pkgLibDir, subpath)
🧹 Nitpick comments (8)
lib/types.js (1)

1-3: Redundant strict mode directive in ES module

This file appears to be a compiled JavaScript file with an empty module structure. The strict mode directive on line 1 is redundant since JavaScript modules are automatically in strict mode.

While this doesn't affect functionality (and may be auto-generated), consider updating your TypeScript compilation settings to avoid redundant strict mode directives:

-"use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
 //# sourceMappingURL=types.js.map
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/cli.js (1)

1-2: Redundant strict mode directive in ES module

JavaScript modules are automatically in strict mode, making the strict mode directive redundant.

#!/usr/bin/env node
-"use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js (1)

1-1: Redundant strict mode directive in ES module

JavaScript modules are automatically in strict mode, making the strict mode directive redundant.

-"use strict";
 var _a;
 Object.defineProperty(exports, "__esModule", { value: true });
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

README.md (1)

16-16: Improve sentence readability with proper punctuation

The description sentence lacks proper punctuation between clauses, making it harder to read.

-The `postinstall` script helper for handling native bindings in legacy `npm` versions, this is a reimplementation of the [`node-install`][node-install] functionality from [`esbuild`][esbuild] for [`napi-rs`][napi-rs] ecosystem packages like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver].
+The `postinstall` script helper for handling native bindings in legacy `npm` versions. This is a reimplementation of the [`node-install`][node-install] functionality from [`esbuild`][esbuild] for [`napi-rs`][napi-rs] ecosystem packages like [`rollup`][rollup] and [`unrs-resolver`][unrs-resolver].
🧰 Tools
🪛 LanguageTool

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

lib/target.js (1)

1-1: Remove redundant "use strict"
Node treats every .mjs/ES‑module file as strict‑mode already, so the directive can be deleted.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js (1)

1-1: Redundant "use strict" – safe to remove for the same reason as above.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

package.json (1)

78-78: Self‑referential devDependency may confuse some tooling
"napi-postinstall": "file:." points back to the package itself. While npm tolerates this in devDependencies, some package managers (pnpm, yarn‑berry) and security scanners flag it as a circular reference. Consider replacing with a workspace/monorepo alias or dropping it entirely when publishing.

src/helpers.ts (1)

35-35: fs.rmdirSync is deprecated
Node 16+ recommends fs.rmSync(dir, { recursive: true, force: true }). This avoids deprecation warnings and future breakage.

- fs.rmdirSync(dir)
+ fs.rmSync(dir, { recursive: true, force: true })
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c42fe8 and f0834cb.

⛔ Files ignored due to path filters (7)
  • lib/cli.js.map is excluded by !**/*.map
  • lib/constants.js.map is excluded by !**/*.map
  • lib/helpers.js.map is excluded by !**/*.map
  • lib/index.js.map is excluded by !**/*.map
  • lib/target.js.map is excluded by !**/*.map
  • lib/types.js.map is excluded by !**/*.map
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (37)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (1 hunks)
  • .prettierignore (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • lib/cli.d.ts (1 hunks)
  • lib/cli.js (1 hunks)
  • lib/constants.d.ts (1 hunks)
  • lib/constants.js (1 hunks)
  • lib/helpers.d.ts (1 hunks)
  • lib/helpers.js (1 hunks)
  • lib/index.d.ts (1 hunks)
  • lib/index.js (1 hunks)
  • lib/target.d.ts (1 hunks)
  • lib/target.js (1 hunks)
  • lib/types.d.ts (1 hunks)
  • lib/types.js (1 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (2)
  • index.d.cts
  • eslint.config.js
✅ Files skipped from review due to trivial changes (4)
  • .github/workflows/autofix.yml
  • src/constants.ts
  • .github/workflows/pkg-pr-new.yml
  • lib/constants.d.ts
🚧 Files skipped from review as they are similar to previous changes (22)
  • vercel.json
  • .prettierignore
  • .github/workflows/size-limit.yml
  • lib/cli.d.ts
  • patches/rollup+4.40.0.patch
  • tsconfig.json
  • .changeset/config.json
  • .github/workflows/release.yml
  • src/cli.ts
  • .size-limit.json
  • lib/index.d.ts
  • vitest.config.mts
  • test/basic.spec.ts
  • .gitignore
  • .github/workflows/ci.yml
  • src/target.ts
  • lib/target.d.ts
  • src/types.ts
  • lib/helpers.d.ts
  • eslint.config.mjs
  • lib/types.d.ts
  • src/index.ts
🧰 Additional context used
🧠 Learnings (1)
lib/helpers.js (1)
Learnt from: JounQin
PR: un-ts/napi-postinstall#3
File: lib/helpers.js:27-45
Timestamp: 2025-04-19T18:11:27.979Z
Learning: Skip reviewing files in the `lib` folder as requested by the repository owner. This folder likely contains compiled/generated code that doesn't need manual review.
🧬 Code Graph Analysis (4)
src/helpers.ts (3)
src/constants.ts (1)
  • DEFAULT_NPM_REGISTRY (5-5)
src/types.ts (2)
  • PackageJson (28-33)
  • NapiInfo (23-26)
src/target.ts (1)
  • parseTriple (47-89)
lib/constants.js (3)
lib/helpers.js (2)
  • tslib_1 (10-10)
  • node_path_1 (13-13)
lib/index.js (2)
  • tslib_1 (4-4)
  • node_path_1 (8-8)
src/constants.ts (1)
  • require (7-9)
lib/helpers.js (1)
src/helpers.ts (7)
  • getGlobalNpmRegistry (9-18)
  • removeRecursive (20-36)
  • downloadedNodePath (38-41)
  • getNapiInfoFromPackageJson (51-101)
  • getNapiNativeTarget (166-249)
  • getNapiNativeTargets (253-259)
  • getErrorMessage (261-263)
lib/target.js (1)
src/target.ts (1)
  • parseTriple (47-89)
🪛 LanguageTool
README.md

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

🪛 Biome (1.9.4)
lib/cli.js

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/helpers.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/target.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/types.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
🔇 Additional comments (1)
lib/helpers.js (1)

1-218: Skipping review for compiled/generated code.

As per the repository owner’s preference, files in the lib directory are generated and do not require manual review.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (6)
lib/cli.js (1)

5-5: Add error handling for the CLI invocation

Currently, unhandled promise rejections from checkAndPreparePackage won't set a non-zero exit code, which can mask failures in scripts. Wrap the call to catch errors and exit with code 1.

- void (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]));
+ (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]))
+  .catch(err => {
+    console.error(err);
+    process.exit(1);
+  });
lib/constants.js (1)

8-8: Add error handling for package.json loading

The code directly requires package.json without any error handling. If the file is missing or invalid, this will throw an uncaught exception.

-_a = require(node_path_1.default.resolve(__dirname, '../package.json')), exports.name = _a.name, exports.version = _a.version;
+try {
+  _a = require(node_path_1.default.resolve(__dirname, '../package.json'));
+  exports.name = _a.name;
+  exports.version = _a.version;
+} catch (error) {
+  console.error('Failed to load package.json:', error);
+  exports.name = 'napi-postinstall';
+  exports.version = 'unknown';
+}
README.md (1)

79-82: 🛠️ Refactor suggestion

Update the PackageJson interface to match implementation.

The PackageJson interface shown in the README is incomplete compared to the actual implementation in the code.

export interface PackageJson {
  name: string
  version: string
+  optionalDependencies?: Partial<Record<string, string>>
+  napi?: {
+    packageName?: string
+    binaryName?: string
+    targets?: string[]
+  }
}
lib/target.js (1)

31-33: ⚠️ Potential issue

Update normalization to only target "‑eabi" suffix.

Currently rawTriple.endsWith('eabi') will also match "gnueabi" (e.g. armv7-unknown-linux-gnueabi), which would incorrectly split "gnueabi" into "gnu" and "eabi".

-const triple = rawTriple.endsWith('eabi')
-    ? `${rawTriple.slice(0, -4)}-eabi`
+const triple = rawTriple.endsWith('-eabi')
+    ? `${rawTriple.slice(0, -5)}-eabi`
    : rawTriple;
lib/index.js (2)

16-19: 🛠️ Refactor suggestion

Improve HTTP redirect handling.

The current implementation has two issues:

  1. It doesn't handle relative URLs in Location headers
  2. It only supports 301/302 redirects, not 303/307/308 which are used by npm registries
-if ((res.statusCode === 301 || res.statusCode === 302) &&
-    res.headers.location) {
-    fetch(res.headers.location).then(resolve, reject);
+const redirectCodes = [301, 302, 303, 307, 308]
+if (redirectCodes.includes(res.statusCode) && res.headers.location) {
+    const nextUrl = res.headers.location.startsWith('http')
+        ? res.headers.location
+        : new URL(res.headers.location, url).toString()
+    fetch(nextUrl).then(resolve, reject);
    return;
}

61-69: 🛠️ Refactor suggestion

Shell-escaping risk when spawning npm install.

Embedding pkg & version directly in the shell command is a security risk if these values come from untrusted sources.

Use the array form of execFileSync to prevent shell injection:

-execSync(`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${version}`, { cwd: installDir, stdio: 'pipe', env });
+execFileSync(
+  'npm',
+  ['install', '--loglevel=error', '--prefer-offline', '--no-audit',
+   '--progress=false', `${pkg}@${version}`],
+  { cwd: installDir, stdio: 'pipe', env }
+)
🧹 Nitpick comments (5)
lib/types.js (1)

1-2: Remove redundant "use strict" directive in ES modules

ES modules are automatically in strict mode without needing an explicit declaration. This directive can be safely removed.

-"use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/cli.js (1)

1-2: Remove redundant "use strict" directive in ES modules

ES modules are automatically in strict mode without needing an explicit declaration. This directive can be safely removed.

#!/usr/bin/env node
-"use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js (1)

1-1: Remove redundant "use strict" directive in ES modules

ES modules are automatically in strict mode without needing an explicit declaration. This directive can be safely removed.

-"use strict";
 var _a;
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/target.js (1)

1-1: Remove redundant "use strict" directive.

JavaScript modules are automatically in strict mode, making this directive unnecessary.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js (1)

1-1: Remove redundant "use strict" directive.

JavaScript modules are automatically in strict mode, making this directive unnecessary.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f0834cb and 6504801.

⛔ Files ignored due to path filters (7)
  • lib/cli.js.map is excluded by !**/*.map
  • lib/constants.js.map is excluded by !**/*.map
  • lib/helpers.js.map is excluded by !**/*.map
  • lib/index.js.map is excluded by !**/*.map
  • lib/target.js.map is excluded by !**/*.map
  • lib/types.js.map is excluded by !**/*.map
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (39)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (1 hunks)
  • .prettierignore (1 hunks)
  • .simple-git-hooks.js (0 hunks)
  • .simple-git-hooks.mjs (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • lib/cli.d.ts (1 hunks)
  • lib/cli.js (1 hunks)
  • lib/constants.d.ts (1 hunks)
  • lib/constants.js (1 hunks)
  • lib/helpers.d.ts (1 hunks)
  • lib/helpers.js (1 hunks)
  • lib/index.d.ts (1 hunks)
  • lib/index.js (1 hunks)
  • lib/target.d.ts (1 hunks)
  • lib/target.js (1 hunks)
  • lib/types.d.ts (1 hunks)
  • lib/types.js (1 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (3)
  • index.d.cts
  • eslint.config.js
  • .simple-git-hooks.js
✅ Files skipped from review due to trivial changes (5)
  • .github/workflows/pkg-pr-new.yml
  • eslint.config.mjs
  • lib/constants.d.ts
  • src/constants.ts
  • lib/target.d.ts
🚧 Files skipped from review as they are similar to previous changes (21)
  • vercel.json
  • .size-limit.json
  • .changeset/config.json
  • lib/cli.d.ts
  • tsconfig.json
  • vitest.config.mts
  • .github/workflows/release.yml
  • .prettierignore
  • .github/workflows/autofix.yml
  • patches/rollup+4.40.0.patch
  • src/cli.ts
  • .github/workflows/ci.yml
  • lib/index.d.ts
  • .github/workflows/size-limit.yml
  • src/target.ts
  • lib/helpers.d.ts
  • .gitignore
  • src/index.ts
  • lib/types.d.ts
  • src/types.ts
  • src/helpers.ts
🧰 Additional context used
🧠 Learnings (2)
test/basic.spec.ts (1)
Learnt from: JounQin
PR: un-ts/napi-postinstall#3
File: test/basic.spec.ts:10-14
Timestamp: 2025-04-19T17:37:36.098Z
Learning: JounQin prefers using `resolves.not.toThrow()` for testing Promise<void> functions to verify successful resolution, rather than explicitly checking for `undefined` with `resolves.toBeUndefined()`.
lib/helpers.js (1)
Learnt from: JounQin
PR: un-ts/napi-postinstall#3
File: lib/helpers.js:27-45
Timestamp: 2025-04-19T18:11:27.979Z
Learning: Skip reviewing files in the `lib` folder as requested by the repository owner. This folder likely contains compiled/generated code that doesn't need manual review.
🧬 Code Graph Analysis (5)
test/basic.spec.ts (1)
src/index.ts (1)
  • checkAndPreparePackage (174-260)
lib/helpers.js (1)
src/helpers.ts (7)
  • getGlobalNpmRegistry (9-18)
  • removeRecursive (20-36)
  • downloadedNodePath (38-41)
  • getNapiInfoFromPackageJson (51-101)
  • getNapiNativeTarget (166-249)
  • getNapiNativeTargets (253-259)
  • getErrorMessage (261-263)
lib/cli.js (2)
src/constants.ts (1)
  • require (7-9)
lib/index.js (1)
  • process (55-55)
lib/constants.js (3)
lib/helpers.js (2)
  • tslib_1 (10-10)
  • node_path_1 (13-13)
lib/index.js (2)
  • tslib_1 (4-4)
  • node_path_1 (8-8)
src/constants.ts (1)
  • require (7-9)
lib/target.js (1)
src/target.ts (1)
  • parseTriple (47-89)
🪛 Biome (1.9.4)
lib/helpers.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/cli.js

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/target.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/types.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

🪛 LanguageTool
README.md

[uncategorized] ~16-~16: A punctuation mark might be missing here.
Context: ...i-rs][napi-rs] ecosystem packages like [rollup][rollup] and [unrs-resolver`][u...

(AI_EN_LECTOR_MISSING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
🔇 Additional comments (12)
.simple-git-hooks.mjs (1)

3-6: LGTM, well-structured pre-commit hook

The pre-commit hook configuration ensures the build artifacts in lib are updated and staged before running the standard pre-commit checks. This is a good practice for maintaining build consistency.

test/basic.spec.ts (1)

1-22: LGTM! Test suite properly verifies core functionality.

The test effectively covers the main scenarios for checkAndPreparePackage:

  • Version mismatch error when checkVersion is true (lines 5-9)
  • Successful resolution without version check (line 10)
  • Successful resolution with version check for supported package (lines 12-14)
  • Error when a package lacks the required fields (lines 16-20)

The use of resolves.not.toThrow() to test Promise functions matches your preferred testing style.

package.json (9)

2-2: The package rename is consistently applied across package name and repository URL.

The package rename from "native-postinstall" to "napi-postinstall" has been properly implemented in both the package name and repository URL fields.

Also applies to: 6-6


4-4: Type field correctly set to "commonjs".

The package type has been changed from "module" to "commonjs", which aligns with the new CommonJS module structure and output formats described in the summary.


14-16: CLI binary configuration correctly set up.

A new CLI executable entry point has been properly defined, allowing users to run the tool directly from the command line with the napi-postinstall command.


17-25: Main and exports fields are properly aligned.

The package's entry points are now consistently defined with both main and exports fields pointing to the same file extensions. This resolves the previous issue where main pointed to a .cjs file while exports.default pointed to a .js file.


31-31: Build command simplified to use TypeScript directly.

The build command has been streamlined to use TypeScript's project references (tsc -b src), which should produce more predictable output.


41-41: Prepare script now includes patch-package.

The prepare script now correctly runs patch-package before simple-git-hooks, which allows for applying patches to dependencies during installation.


46-46: Vercel build script added for platform-specific dependencies.

A new script for Vercel builds has been added to install platform-specific esbuild and rollup packages before building documentation, which should help with deployment compatibility.


62-62: New development dependencies added to support the updated package structure.

New dependencies have been added including:

  • @types/pnpapi for Plug'n'Play API typings
  • @unts/patch-package for patching dependencies
  • eslint-plugin-node-dependencies for linting node dependencies
  • The package itself as a file reference for development testing
  • size-limit-preset-node-lib replacing size-limit presets for browser
  • vite-tsconfig-paths for resolving TypeScript paths in Vite

These additions align with the project's move to CommonJS format and improved development workflow.

Also applies to: 66-67, 74-74, 78-79, 88-88, 93-93


78-78: Local file dependency correctly configured.

The local file dependency "napi-postinstall": "file:." is now properly configured with a path, resolving the previous issue where the path was missing.

lib/helpers.js (1)

1-222: Skipping review of generated code in the lib folder.

Based on the repository owner's explicit request (as noted in the retrieved learnings), I'm skipping the review of files in the lib folder as they likely contain compiled/generated code that doesn't need manual review.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
lib/cli.js (1)

5-5: Add error handling for the CLI invocation

Currently, unhandled promise rejections from checkAndPreparePackage won't set a non-zero exit code, which can mask failures in scripts. Wrap the call to catch errors and exit with code 1.

- void (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]));
+ (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]))
+  .catch(err => {
+    console.error(err);
+    process.exit(1);
+  });
lib/constants.js (1)

8-8: Add error handling for package.json loading

The code directly requires package.json without any error handling. If the file is missing or invalid, this will throw an uncaught exception.

-_a = require(node_path_1.default.resolve(__dirname, '../package.json')), exports.name = _a.name, exports.version = _a.version;
+try {
+  _a = require(node_path_1.default.resolve(__dirname, '../package.json'));
+  exports.name = _a.name;
+  exports.version = _a.version;
+} catch (error) {
+  console.error('Failed to load package.json:', error);
+  exports.name = 'napi-postinstall';
+  exports.version = 'unknown';
+}
🧹 Nitpick comments (3)
lib/types.js (1)

1-1: Consider removing the redundant "use strict" directive.

In ES modules, code is already in strict mode by default, making this directive unnecessary.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/cli.js (1)

1-2: Consider removing the redundant "use strict" directive.

In ES modules, code is already in strict mode by default, making this directive unnecessary.

#!/usr/bin/env node
-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js (1)

1-1: Consider removing the redundant "use strict" directive.

In ES modules, code is already in strict mode by default, making this directive unnecessary.

-"use strict";
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6504801 and 0396ca0.

⛔ Files ignored due to path filters (7)
  • lib/cli.js.map is excluded by !**/*.map
  • lib/constants.js.map is excluded by !**/*.map
  • lib/helpers.js.map is excluded by !**/*.map
  • lib/index.js.map is excluded by !**/*.map
  • lib/target.js.map is excluded by !**/*.map
  • lib/types.js.map is excluded by !**/*.map
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (39)
  • .changeset/config.json (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (1 hunks)
  • .prettierignore (1 hunks)
  • .simple-git-hooks.js (0 hunks)
  • .simple-git-hooks.mjs (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • lib/cli.d.ts (1 hunks)
  • lib/cli.js (1 hunks)
  • lib/constants.d.ts (1 hunks)
  • lib/constants.js (1 hunks)
  • lib/helpers.d.ts (1 hunks)
  • lib/helpers.js (1 hunks)
  • lib/index.d.ts (1 hunks)
  • lib/index.js (1 hunks)
  • lib/target.d.ts (1 hunks)
  • lib/target.js (1 hunks)
  • lib/types.d.ts (1 hunks)
  • lib/types.js (1 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (3)
  • index.d.cts
  • .simple-git-hooks.js
  • eslint.config.js
✅ Files skipped from review due to trivial changes (6)
  • .github/workflows/pkg-pr-new.yml
  • src/constants.ts
  • .simple-git-hooks.mjs
  • lib/index.d.ts
  • lib/constants.d.ts
  • lib/types.d.ts
🚧 Files skipped from review as they are similar to previous changes (22)
  • vercel.json
  • .prettierignore
  • vitest.config.mts
  • .github/workflows/size-limit.yml
  • tsconfig.json
  • .github/workflows/autofix.yml
  • .changeset/config.json
  • .size-limit.json
  • .gitignore
  • .github/workflows/release.yml
  • src/cli.ts
  • lib/cli.d.ts
  • patches/rollup+4.40.0.patch
  • eslint.config.mjs
  • .github/workflows/ci.yml
  • README.md
  • lib/target.d.ts
  • lib/helpers.d.ts
  • src/target.ts
  • src/index.ts
  • src/types.ts
  • src/helpers.ts
🧰 Additional context used
🧠 Learnings (2)
test/basic.spec.ts (1)
Learnt from: JounQin
PR: un-ts/napi-postinstall#3
File: test/basic.spec.ts:10-14
Timestamp: 2025-04-19T17:37:36.098Z
Learning: JounQin prefers using `resolves.not.toThrow()` for testing Promise<void> functions to verify successful resolution, rather than explicitly checking for `undefined` with `resolves.toBeUndefined()`.
lib/helpers.js (1)
Learnt from: JounQin
PR: un-ts/napi-postinstall#3
File: lib/helpers.js:27-45
Timestamp: 2025-04-19T18:11:27.979Z
Learning: Skip reviewing files in the `lib` folder as requested by the repository owner. This folder likely contains compiled/generated code that doesn't need manual review.
🧬 Code Graph Analysis (4)
lib/constants.js (3)
lib/helpers.js (2)
  • tslib_1 (10-10)
  • node_path_1 (13-13)
lib/index.js (2)
  • tslib_1 (4-4)
  • node_path_1 (8-8)
src/constants.ts (1)
  • require (7-9)
lib/helpers.js (1)
src/helpers.ts (7)
  • getGlobalNpmRegistry (9-18)
  • removeRecursive (20-36)
  • downloadedNodePath (38-41)
  • getNapiInfoFromPackageJson (51-101)
  • getNapiNativeTarget (166-249)
  • getNapiNativeTargets (253-259)
  • getErrorMessage (261-263)
lib/index.js (2)
src/index.ts (1)
  • checkAndPreparePackage (181-267)
lib/helpers.js (5)
  • version (59-59)
  • napi (57-57)
  • targets (53-53)
  • targets (157-157)
  • targets (213-213)
lib/target.js (1)
src/target.ts (1)
  • parseTriple (47-89)
🪛 Biome (1.9.4)
lib/cli.js

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/helpers.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/target.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/types.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: Lint and Test with Node.js 20 on macos-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
🔇 Additional comments (6)
test/basic.spec.ts (1)

1-26: Test coverage looks good, maintaining preferred assertion style.

The test suite effectively covers various scenarios for the checkAndPreparePackage function, including both success and failure cases. I notice you're using resolves.not.toThrow() for testing Promise functions, which aligns with your previously stated preference.

package.json (2)

2-2: LGTM! Package is now properly renamed and reconfigured.

The consistent renaming from "native-postinstall" to "napi-postinstall" along with the switch to CommonJS format and the addition of CLI support is well executed.

Also applies to: 4-4, 6-6, 14-16, 17-18, 19-25


78-78: Self-reference dependency looks good.

Using "file:." reference is the correct format for local development and testing.

lib/target.js (1)

1-56: Repository owner requested to skip reviewing lib folder

As requested in previous discussions, I'll skip reviewing files in the lib folder as they appear to be compiled/generated code from TypeScript sources.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js (1)

1-154: Repository owner requested to skip reviewing lib folder

As requested in previous discussions, I'll skip reviewing files in the lib folder as they appear to be compiled/generated code from TypeScript sources.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/helpers.js (1)

1-222: Repository owner requested to skip reviewing lib folder

As previously instructed, I'll skip reviewing files in the lib folder as they appear to be compiled/generated code from TypeScript sources.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

@JounQin
Copy link
Member Author

JounQin commented Apr 19, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Apr 19, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (7)
lib/cli.js (1)

5-5: Add error handling for the CLI invocation

Currently, unhandled promise rejections from checkAndPreparePackage won't set a non-zero exit code, which can mask failures in scripts. Wrap the call to catch errors and exit with code 1.

Apply this diff:

- void (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]));
+ (0, index_js_1.checkAndPreparePackage)(process.argv[2], ['1', 'check', 'true', 'yes'].includes(process.argv[3]))
+  .catch(err => {
+    console.error(err);
+    process.exit(1);
+  });
lib/constants.js (1)

8-8: Add error handling for package.json loading

The code directly requires package.json without any error handling. If the file is missing or invalid, this will throw an uncaught exception.

-_a = require(node_path_1.default.resolve(__dirname, '../package.json')), exports.name = _a.name, exports.version = _a.version;
+try {
+  _a = require(node_path_1.default.resolve(__dirname, '../package.json'));
+  exports.name = _a.name;
+  exports.version = _a.version;
+} catch (error) {
+  console.error('Failed to load package.json:', error);
+  exports.name = 'napi-postinstall';
+  exports.version = 'unknown';
+}
lib/target.js (1)

31-33: ⚠️ Potential issue

Fix double “‑eabi” suffix & false‑positive matches (repeat of earlier advice)

The normalisation still checks rawTriple.endsWith('eabi'), which matches any string ending in those four letters (e.g. gnueabi).
For armv7-unknown-linux-gnueabi this yields armv7-unknown-linux-gnu-eabi (note the duplicate hyphen), breaking subsequent parsing and optional‑dependency look‑ups.

-const triple = rawTriple.endsWith('eabi')
-  ? `${rawTriple.slice(0, -4)}-eabi`
+const triple = rawTriple.endsWith('-eabi')
+  ? `${rawTriple.slice(0, -5)}-eabi`
   : rawTriple;

This keeps the single “‑eabi” suffix and only rewrites true -eabi triples.
(See identical comment on the previous commit.)

lib/index.js (3)

16-19: 🛠️ Refactor suggestion

Broaden redirect handling & support relative locations (repeat)

Only 301/302 are followed and the Location header is assumed to be absolute. npm’s registry frequently replies with 303/307/308 and relative paths.

- if ((res.statusCode === 301 || res.statusCode === 302) &&
-     res.headers.location) {
-   fetch(res.headers.location).then(resolve, reject);
+ const redirectCodes = [301, 302, 303, 307, 308];
+ if (redirectCodes.includes(res.statusCode) && res.headers.location) {
+   const next = res.headers.location.startsWith('http')
+     ? res.headers.location
+     : new URL(res.headers.location, url).toString();
+   fetch(next).then(resolve, reject);
   return;
 }

Failure to follow these redirects breaks downloads from mirrors/CDNs.
(Previously raised but still unresolved.)


68-69: ⚠️ Potential issue

Shell‑injection risk when spawning npm install (repeat)

execSync executes a shell string containing ${pkg} and ${version}. A malicious version such as 1.2.3 && rm -rf / would be executed.

Use the argument‑vector form to avoid shell parsing:

- execSync(`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${version}`, { cwd: installDir, stdio: 'pipe', env });
+ execSync('npm', [
+   'install',
+   '--loglevel=error',
+   '--prefer-offline',
+   '--no-audit',
+   '--progress=false',
+   `${pkg}@${version}`,
+ ], { cwd: installDir, stdio: 'pipe', env });

(Identical to the earlier suggestion.)


108-116: ⚠️ Potential issue

optionalDependencies may be undefined (repeat)

package.json is destructured but later accessed without a null‑check:

const { name, version, optionalDependencies } = packageJson;
// …
if (!optionalDependencies[pkg]) {   // ← TypeError if field is missing

Guard the access:

-if (!optionalDependencies[pkg]) {
+if (!optionalDependencies?.[pkg]) {
   continue;
}

Prevents crashes when the field is absent.

src/helpers.ts (1)

38-41: ⚠️ Potential issue

Preserve sub‑directory structure when computing downloaded binary path (repeat)

Using path.basename(subpath) collapses darwin/x64/native.node to native.node, risking name collisions between architectures and breaking require() paths.

-return path.join(pkgLibDir, `${path.basename(subpath)}`)
+// keep the relative directory layout created by most prebuild tools
+return path.join(pkgLibDir, subpath)

Same issue was pointed out earlier.

🧹 Nitpick comments (3)
test/basic.spec.ts (1)

4-25: Consider splitting into multiple test cases

While the current approach works well, separating each package test into individual test cases would improve test readability and make failures more specific.

-  it('should check and prepare package', async () => {
-    await expect(
-      checkAndPreparePackage('rollup', true),
-    ).rejects.toMatchInlineSnapshot(
-      `[Error: No version found for \`rollup\` with \`@rollup/rollup-linux-ppc64-gnu\`.]`,
-    )
-    await expect(checkAndPreparePackage('rollup')).resolves.not.toThrow()
-
-    await expect(
-      checkAndPreparePackage('@swc/core', true),
-    ).resolves.not.toThrow()
-
-    await expect(
-      checkAndPreparePackage('unrs-resolver', true),
-    ).resolves.not.toThrow()
-
-    await expect(
-      checkAndPreparePackage('napi-postinstall'),
-    ).rejects.toThrowErrorMatchingInlineSnapshot(
-      `[Error: No \`napi.targets\` nor \`optionalDependencies\` field found in \`napi-postinstall\`'s \`package.json\`. Please ensure the package is built with NAPI support.]`,
-    )
-  })
+  it('should reject for rollup with version check', async () => {
+    await expect(
+      checkAndPreparePackage('rollup', true),
+    ).rejects.toMatchInlineSnapshot(
+      `[Error: No version found for \`rollup\` with \`@rollup/rollup-linux-ppc64-gnu\`.]`,
+    )
+  })
+
+  it('should resolve for rollup without version check', async () => {
+    await expect(checkAndPreparePackage('rollup')).resolves.not.toThrow()
+  })
+
+  it('should resolve for @swc/core with version check', async () => {
+    await expect(
+      checkAndPreparePackage('@swc/core', true),
+    ).resolves.not.toThrow()
+  })
+
+  it('should resolve for unrs-resolver with version check', async () => {
+    await expect(
+      checkAndPreparePackage('unrs-resolver', true),
+    ).resolves.not.toThrow()
+  })
+
+  it('should reject for napi-postinstall with missing fields', async () => {
+    await expect(
+      checkAndPreparePackage('napi-postinstall'),
+    ).rejects.toThrowErrorMatchingInlineSnapshot(
+      `[Error: No \`napi.targets\` nor \`optionalDependencies\` field found in \`napi-postinstall\`'s \`package.json\`. Please ensure the package is built with NAPI support.]`,
+    )
+  })
package.json (1)

19-25: Add explicit require / import conditions for clarity

The exports map relies on the implicit default condition. While Node will fall back to default, adding explicit entries improves tooling compatibility and reader clarity:

"exports": {
  ".": {
    "types": "./lib/index.d.ts",
+   "require": "./lib/index.js",
+   "import": "./lib/index.js",
    "default": "./lib/index.js"
  },
  "./package.json": "./package.json"
}

Purely a readability & DX tweak – feel free to skip.

src/helpers.ts (1)

20-36: Replace deprecated fs.rmdirSync with fs.rmSync

fs.rmdirSync(dir) with recursive removal is deprecated since Node 14 and removed in 20.
Use fs.rmSync(dir, { recursive: true, force: true }) which handles files & dirs safely:

- fs.rmdirSync(dir)
+ fs.rmSync(dir, { recursive: true, force: true })

Reduces future maintenance warnings.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0396ca0 and 337d7f3.

⛔ Files ignored due to path filters (7)
  • lib/cli.js.map is excluded by !**/*.map
  • lib/constants.js.map is excluded by !**/*.map
  • lib/helpers.js.map is excluded by !**/*.map
  • lib/index.js.map is excluded by !**/*.map
  • lib/target.js.map is excluded by !**/*.map
  • lib/types.js.map is excluded by !**/*.map
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (40)
  • .changeset/config.json (1 hunks)
  • .changeset/solid-eagles-roll.md (1 hunks)
  • .github/workflows/autofix.yml (1 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/pkg-pr-new.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/size-limit.yml (1 hunks)
  • .gitignore (1 hunks)
  • .prettierignore (1 hunks)
  • .simple-git-hooks.js (0 hunks)
  • .simple-git-hooks.mjs (1 hunks)
  • .size-limit.json (1 hunks)
  • README.md (3 hunks)
  • eslint.config.js (0 hunks)
  • eslint.config.mjs (1 hunks)
  • index.d.cts (0 hunks)
  • lib/cli.d.ts (1 hunks)
  • lib/cli.js (1 hunks)
  • lib/constants.d.ts (1 hunks)
  • lib/constants.js (1 hunks)
  • lib/helpers.d.ts (1 hunks)
  • lib/helpers.js (1 hunks)
  • lib/index.d.ts (1 hunks)
  • lib/index.js (1 hunks)
  • lib/target.d.ts (1 hunks)
  • lib/target.js (1 hunks)
  • lib/types.d.ts (1 hunks)
  • lib/types.js (1 hunks)
  • package.json (4 hunks)
  • patches/rollup+4.40.0.patch (1 hunks)
  • src/cli.ts (1 hunks)
  • src/constants.ts (1 hunks)
  • src/helpers.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/target.ts (1 hunks)
  • src/types.ts (1 hunks)
  • test/basic.spec.ts (1 hunks)
  • tsconfig.json (1 hunks)
  • vercel.json (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (3)
  • .simple-git-hooks.js
  • eslint.config.js
  • index.d.cts
✅ Files skipped from review due to trivial changes (6)
  • .changeset/solid-eagles-roll.md
  • .github/workflows/autofix.yml
  • .github/workflows/pkg-pr-new.yml
  • lib/constants.d.ts
  • src/constants.ts
  • lib/target.d.ts
🚧 Files skipped from review as they are similar to previous changes (22)
  • .size-limit.json
  • vitest.config.mts
  • vercel.json
  • .github/workflows/release.yml
  • .github/workflows/size-limit.yml
  • lib/cli.d.ts
  • .gitignore
  • .changeset/config.json
  • .prettierignore
  • .simple-git-hooks.mjs
  • eslint.config.mjs
  • src/cli.ts
  • patches/rollup+4.40.0.patch
  • lib/index.d.ts
  • .github/workflows/ci.yml
  • tsconfig.json
  • lib/types.d.ts
  • lib/helpers.d.ts
  • src/target.ts
  • README.md
  • src/index.ts
  • src/types.ts
🧰 Additional context used
🧠 Learnings (2)
test/basic.spec.ts (1)
Learnt from: JounQin
PR: un-ts/napi-postinstall#3
File: test/basic.spec.ts:10-14
Timestamp: 2025-04-19T17:37:36.098Z
Learning: JounQin prefers using `resolves.not.toThrow()` for testing Promise<void> functions to verify successful resolution, rather than explicitly checking for `undefined` with `resolves.toBeUndefined()`.
lib/helpers.js (1)
Learnt from: JounQin
PR: un-ts/napi-postinstall#3
File: lib/helpers.js:27-45
Timestamp: 2025-04-19T18:11:27.979Z
Learning: Skip reviewing files in the `lib` folder as requested by the repository owner. This folder likely contains compiled/generated code that doesn't need manual review.
🧬 Code Graph Analysis (3)
test/basic.spec.ts (1)
src/index.ts (1)
  • checkAndPreparePackage (181-267)
lib/constants.js (3)
lib/helpers.js (2)
  • tslib_1 (10-10)
  • node_path_1 (13-13)
lib/index.js (2)
  • tslib_1 (4-4)
  • node_path_1 (8-8)
src/constants.ts (1)
  • require (7-9)
lib/target.js (1)
src/target.ts (1)
  • parseTriple (47-89)
🪛 Biome (1.9.4)
lib/cli.js

[error] 1-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/constants.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/helpers.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/index.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/target.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/types.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
  • GitHub Check: Lint and Test with Node.js 20 on windows-latest
  • GitHub Check: Lint and Test with Node.js 22 on windows-latest
  • GitHub Check: Lint and Test with Node.js 18 on windows-latest
🔇 Additional comments (4)
lib/types.js (1)

1-3: Looks good, module exports declaration is set up correctly.

While static analysis flags the "use strict" directive as redundant in JavaScript modules, this is a compiled file where the directive is likely auto-generated by the TypeScript compiler.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

test/basic.spec.ts (1)

4-25: Test suite looks comprehensive

Good job testing both successful and error cases. The test verifies multiple scenarios against different packages:

  1. Expected rejection for 'rollup' with version checking
  2. Successful execution for 'rollup' without version check
  3. Successful execution for '@swc/core' and 'unrs-resolver' with version check
  4. Expected rejection for 'napi-postinstall' due to missing required fields

Using resolves.not.toThrow() is appropriate here for Promise verification, as per your preference.

lib/target.js (1)

1-1: "use strict" is fine here – ignore the static‑analysis warning

The file is emitted as CommonJS, where strict mode is not implicit. Retaining the directive is harmless and avoids accidental sloppy‑mode code injection.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

lib/helpers.js (1)

1-222: Skipping review as requested.

I'm skipping the review of files in the lib folder as per your request. This appears to be compiled/generated code that doesn't need manual review.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

@JounQin JounQin merged commit cc98bce into main Apr 19, 2025
24 of 27 checks passed
@JounQin JounQin deleted the feat/work branch April 19, 2025 19:04
@pkg-pr-new
Copy link

pkg-pr-new bot commented Apr 19, 2025

Open in StackBlitz

npm i https://pkg.pr.new/napi-postinstall@3

commit: 8c06cd5

@github-actions
Copy link
Contributor

size-limit report 📦

Path Size
lib/index.js 2.16 KB (0%)

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.

2 participants