unum-cloud / usearch

Fast Open-Source Search & Clustering engine × for Vectors & 🔜 Strings × in C++, C, Python, JavaScript, Rust, Java, Objective-C, Swift, C#, GoLang, and Wolfram 🔍
https://unum-cloud.github.io/usearch/
Apache License 2.0
2.27k stars 143 forks source link

Bug: usearch@2.10.x nodejs installation fails #377

Open jlarmstrongiv opened 7 months ago

jlarmstrongiv commented 7 months ago

Describe the bug

NPM install fails on arm64 linux. I presume it couldn’t find a new prebuilt binary (exciting new feature from @sroussey), and fell back to compiling from scratch, which it can no longer do because the source and gyp files have been removed from the npm package.

Run npm ci
npm WARN deprecated @npmcli/move-file@2.0.1: This functionality has been moved to @npmcli/fs
npm WARN deprecated @aws-sdk/middleware-retry@3.374.0: This package has moved to @smithy/middleware-retry
npm WARN deprecated @aws-sdk/config-resolver@3.374.0: This package has moved to @smithy/config-resolver
npm WARN deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm WARN deprecated @aws-sdk/smithy-client@3.374.0: This package has moved to @smithy/smithy-client
npm WARN deprecated @astrojs/webapi@3.0.0: This package is not used by Astro any more and is no longer maintained. In Astro 3.0 polyfills are part of a core module.
npm ERR! code 1
npm ERR! path /home/runner/actions-runner/_work/project/project/node_modules/usearch
npm ERR! command failed
npm ERR! command sh -c node-gyp-build
npm ERR! gyp info it worked if it ends with ok
npm ERR! gyp info using node-gyp@10.1.0
npm ERR! gyp info using node@20.11.1 | linux | arm64
npm ERR! gyp info find Python using Python version 3.10.12 found at "/usr/bin/python3"
npm ERR! gyp http GET https://nodejs.org/download/release/v20.11.1/node-v20.11.1-headers.tar.gz
npm ERR! gyp http 200 https://nodejs.org/download/release/v20.11.1/node-v20.11.1-headers.tar.gz
npm ERR! gyp http GET https://nodejs.org/download/release/v20.11.1/SHASUMS256.txt
npm ERR! gyp http 200 https://nodejs.org/download/release/v20.11.1/SHASUMS256.txt
npm ERR! gyp info spawn /usr/bin/python3
npm ERR! gyp info spawn args [
npm ERR! gyp info spawn args '/home/runner/actions-runner/_work/project/project/node_modules/node-gyp/gyp/gyp_main.py',
npm ERR! gyp info spawn args 'binding.gyp',
npm ERR! gyp info spawn args '-f',
npm ERR! gyp info spawn args 'make',
npm ERR! gyp info spawn args '-I',
npm ERR! gyp info spawn args '/home/runner/actions-runner/_work/project/project/node_modules/usearch/build/config.gypi',
npm ERR! gyp info spawn args '-I',
npm ERR! gyp info spawn args '/home/runner/actions-runner/_work/project/project/node_modules/node-gyp/addon.gypi',
npm ERR! gyp info spawn args '-I',
npm ERR! gyp info spawn args '/home/runner/.cache/node-gyp/20.11.1/include/node/common.gypi',
npm ERR! gyp info spawn args '-Dlibrary=shared_library',
npm ERR! gyp info spawn args '-Dvisibility=default',
npm ERR! gyp info spawn args '-Dnode_root_dir=/home/runner/.cache/node-gyp/20.11.1',
npm ERR! gyp info spawn args '-Dnode_gyp_dir=/home/runner/actions-runner/_work/project/project/node_modules/node-gyp',
npm ERR! gyp info spawn args '-Dnode_lib_file=/home/runner/.cache/node-gyp/20.11.1/<(target_arch)/node.lib',
npm ERR! gyp info spawn args '-Dmodule_root_dir=/home/runner/actions-runner/_work/project/project/node_modules/usearch',
npm ERR! gyp info spawn args '-Dnode_engine=v8',
npm ERR! gyp info spawn args '--depth=.',
npm ERR! gyp info spawn args '--no-parallel',
npm ERR! gyp info spawn args '--generator-output',
npm ERR! gyp info spawn args 'build',
npm ERR! gyp info spawn args '-Goutput_dir=.'
npm ERR! gyp info spawn args ]
npm ERR! gyp: binding.gyp not found (cwd: /home/runner/actions-runner/_work/project/project/node_modules/usearch) while trying to load binding.gyp
npm ERR! gyp ERR! configure error 
npm ERR! gyp ERR! stack Error: `gyp` failed with exit code: 1
npm ERR! gyp ERR! stack at ChildProcess.<anonymous> (/home/runner/actions-runner/_work/project/project/node_modules/node-gyp/lib/configure.js:297:18)
npm ERR! gyp ERR! stack at ChildProcess.emit (node:events:518:28)
npm ERR! gyp ERR! stack at ChildProcess._handle.onexit (node:internal/child_process:294:12)
npm ERR! gyp ERR! System Linux 5.15.0-84-generic
npm ERR! gyp ERR! command "/opt/hostedtoolcache/node/20.11.1/arm64/bin/node" "/home/runner/actions-runner/_work/project/project/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
npm ERR! gyp ERR! cwd /home/runner/actions-runner/_work/project/project/node_modules/usearch
npm ERR! gyp ERR! node -v v20.11.1
npm ERR! gyp ERR! node-gyp -v v10.1.0
npm ERR! gyp ERR! not ok

npm ERR! A complete log of this run can be found in: /home/runner/.npm/_logs/2024-04-01T21_50_25_304Z-debug-0.log
Error: Process completed with exit code 1.

Steps to reproduce

On an arm64 machine, run

docker run -it --entrypoint /bin/bash --rm public.ecr.aws/lambda/nodejs:20-arm64

Inside the container, run

dnf install -y python3 make gcc-c++
npm init -y
npm i usearch

View the error:

npm ERR! code 1
npm ERR! path /var/task/node_modules/usearch
npm ERR! command failed
npm ERR! command sh -c node-gyp-build
npm ERR! gyp info it worked if it ends with ok
npm ERR! gyp info using node-gyp@9.4.0
npm ERR! gyp info using node@20.9.0 | linux | arm64
npm ERR! gyp info find Python using Python version 3.9.16 found at "/usr/bin/python3"
npm ERR! gyp http GET https://nodejs.org/download/release/v20.9.0/node-v20.9.0-headers.tar.gz
npm ERR! gyp http 200 https://nodejs.org/download/release/v20.9.0/node-v20.9.0-headers.tar.gz
npm ERR! gyp http GET https://nodejs.org/download/release/v20.9.0/SHASUMS256.txt
npm ERR! gyp http 200 https://nodejs.org/download/release/v20.9.0/SHASUMS256.txt
npm ERR! gyp info spawn /usr/bin/python3
npm ERR! gyp info spawn args [
npm ERR! gyp info spawn args   '/var/lang/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
npm ERR! gyp info spawn args   'binding.gyp',
npm ERR! gyp info spawn args   '-f',
npm ERR! gyp info spawn args   'make',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   '/var/task/node_modules/usearch/build/config.gypi',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   '/var/lang/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   '/root/.cache/node-gyp/20.9.0/include/node/common.gypi',
npm ERR! gyp info spawn args   '-Dlibrary=shared_library',
npm ERR! gyp info spawn args   '-Dvisibility=default',
npm ERR! gyp info spawn args   '-Dnode_root_dir=/root/.cache/node-gyp/20.9.0',
npm ERR! gyp info spawn args   '-Dnode_gyp_dir=/var/lang/lib/node_modules/npm/node_modules/node-gyp',
npm ERR! gyp info spawn args   '-Dnode_lib_file=/root/.cache/node-gyp/20.9.0/<(target_arch)/node.lib',
npm ERR! gyp info spawn args   '-Dmodule_root_dir=/var/task/node_modules/usearch',
npm ERR! gyp info spawn args   '-Dnode_engine=v8',
npm ERR! gyp info spawn args   '--depth=.',
npm ERR! gyp info spawn args   '--no-parallel',
npm ERR! gyp info spawn args   '--generator-output',
npm ERR! gyp info spawn args   'build',
npm ERR! gyp info spawn args   '-Goutput_dir=.'
npm ERR! gyp info spawn args ]
npm ERR! gyp: binding.gyp not found (cwd: /var/task/node_modules/usearch) while trying to load binding.gyp
npm ERR! gyp ERR! configure error
npm ERR! gyp ERR! stack Error: `gyp` failed with exit code: 1
npm ERR! gyp ERR! stack     at ChildProcess.onCpExit (/var/lang/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:325:16)
npm ERR! gyp ERR! stack     at ChildProcess.emit (node:events:514:28)
npm ERR! gyp ERR! stack     at ChildProcess._handle.onexit (node:internal/child_process:294:12)
npm ERR! gyp ERR! System Linux 6.6.12-linuxkit
npm ERR! gyp ERR! command "/var/lang/bin/node" "/var/lang/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
npm ERR! gyp ERR! cwd /var/task/node_modules/usearch
npm ERR! gyp ERR! node -v v20.9.0
npm ERR! gyp ERR! node-gyp -v v9.4.0
npm ERR! gyp ERR! not ok

npm ERR! A complete log of this run can be found in: /root/.npm/_logs/2024-04-01T23_50_47_987Z-debug-0.log

Expected behavior

NPM install to work with the linux-arm64 prebuilds

Regardless, it’s important for falling back to compiling from scratch with node-gyp to continue to work.

USearch version

2.10.x

Operating System

Amazon Linux 2023

Hardware architecture

Arm

Which interface are you using?

Other bindings

Contact Details

Ping me in Discord

Is there an existing issue for this?

Code of Conduct

ashvardanian commented 7 months ago

That's good to know! Another related issue I am solving is the lack of Doxygen support for TypeScript. Maybe we should provide both binding.gyp and prebuilt, as well as TypeScript + JavaScript?

sroussey commented 7 months ago

I guess I was overzealous on files[] part of the package.json. Will fix.

sroussey commented 7 months ago

It is odd since there should be a pre-built binary for linux-arm64

https://www.npmjs.com/package/usearch?activeTab=code

image
sroussey commented 7 months ago

I did cross compile it so maybe i did something wrong

sroussey commented 7 months ago

Oh, they are the same size, so definitely not right.

sroussey commented 7 months ago

See https://github.com/unum-cloud/usearch/pull/379

ashvardanian commented 7 months ago

:tada: This issue has been resolved in version 2.10.4 :tada:

The release is available on GitHub release

Your semantic-release bot :package::rocket:

jlarmstrongiv commented 7 months ago

I will try it as soon as 2.10.4 is released on npm 😄

ashvardanian commented 7 months ago

@jlarmstrongiv, sadly, the build fails. @sroussey, would you be able to double-check the cross-compilation commands? I am also looking to extend cross-compilation in Rust as well (for #378).

sroussey commented 7 months ago

I will try it as soon as 2.10.4 is released on npm 😄

Try npm install @sroussey/usearch

as a test.

jlarmstrongiv commented 7 months ago
bash-5.2# npm install @sroussey/usearch

added 5 packages, and audited 6 packages in 6s

found 0 vulnerabilities

The install passed! Haven’t tried running sample code yet though

sroussey commented 7 months ago

@jlarmstrongiv, sadly, the build fails. @sroussey, would you be able to double-check the cross-compilation commands? I am also looking to extend cross-compilation in Rust as well (for #378).

Might remove the cross compile for now while I do more investigation.

ashvardanian commented 7 months ago

How is it going, @sroussey? How should I change the CI for builds to pass?

sroussey commented 7 months ago

I’m home a bit today, so I’ll comment out that section until I have a working version.

sroussey commented 7 months ago

See https://github.com/unum-cloud/usearch/commit/c6fb87574f0410cd50b4939b856b1cdbacec42cc

It has what i think is the fix, but I am not setup to test it.

So farther down I have it skip the cross compiling.

sroussey commented 7 months ago

I have a docker setup on x86_64 but I can't get it to compile normally, so I can't test cross compiling.

image

@ashvardanian Have any idea how i set things up wrong?

sroussey commented 7 months ago
image
sroussey commented 7 months ago
root@6a1e9ab171d0:/usr/usearch# uname -a 
Linux 6a1e9ab171d0 6.4.16-linuxkit #1 SMP PREEMPT Thu Nov 16 10:49:20 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
apt install -y cmake build-essential libjemalloc-dev libomp-dev gcc-12 g++-12 
apt install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu g++-aarch64-linux-gnu
root@6a1e9ab171d0:/usr/usearch# git submodule
 0a92994d729ff76a58f692d3028ca1b64b145d91 fp16 (heads/master)
 127ead1da7c39957b30a50dd85e74814edb022d6 simsimd (v4.2.2)
 c2848c1ba777c541af2903501f3d6344d711638b stringzilla (v3.7.0)
sroussey commented 7 months ago

Works fine on MacOS though.

ashvardanian commented 7 months ago

The _ph suffixes are for half-precision. GCC 12 must support it. You download it, but seems like you are not using it, @sroussey 🤷

sroussey commented 7 months ago

update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 60 --slave /usr/bin/g++ g++ /usr/bin/g++-12 fixed it, thanks.

sroussey commented 7 months ago

cross compile says it goes fine, but it doesn't contain a build

image
sroussey commented 7 months ago

Oh, it did build it:

root@6a1e9ab171d0:/usr/usearch# file build/Release/obj.target/usearch.node
build/Release/obj.target/usearch.node: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=c0650f24bd82a89cca3a4a773455913f2477a789, not stripped

It just didn't get moved over. I wonder if a strip issue.

sroussey commented 7 months ago

Indeed, something went wrong with strip. Manually works though. I can work around this...

sroussey commented 7 months ago

See https://github.com/unum-cloud/usearch/pull/383

ashvardanian commented 7 months ago

@jlarmstrongiv is the issue resolved now?

jlarmstrongiv commented 7 months ago

Hmm, I get errors that:

Error: src/usearch.ts(11,5): error TS2322: Type '"cos"' is not assignable to type 'MetricKind'.
Error: src/usearch.ts(13,5): error TS2322: Type '"f32"' is not assignable to type 'ScalarKind'.

Did the types change?

jlarmstrongiv commented 7 months ago

Fixed the types… testing

jlarmstrongiv commented 7 months ago

It seems my bundling for usearch does not work with the new package structure. I am using https://www.npmjs.com/package/@vercel/ncc, I wonder why that would break and not detect the usearch.node file anymore

Uncaught Exception  {
  "errorType": "Error",
  "errorMessage": "Could not find native build for usearch",
  "stack": [
    "Error: Could not find native build for usearch",
    "    at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1080:15)",
    "    at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1081:12)",
    "    at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1081:12)",
    "    at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1081:12)",
    "    at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1081:12)",
    "    at 128 (/opt/nodejs/node_modules/usearch/index.js:605:48)",
    "    at __nccwpck_require__ (/opt/nodejs/node_modules/usearch/index.js:1117:43)",
    "    at /opt/nodejs/node_modules/usearch/index.js:1137:37",
    "    at Object.<anonymous> (/opt/nodejs/node_modules/usearch/index.js:1140:12)",
    "    at Module._compile (node:internal/modules/cjs/loader:1376:14)"
  ]
}
sroussey commented 7 months ago

These tools are not smart enough to deal with .node or .wasm files (generally). They will require extra steps on your side.

sroussey commented 7 months ago

Oh, and if it has something like "external" you might use that. Bun can make a single file as well, and it has something like that. I use externals for transformers.js since it has wasm files.

ashvardanian commented 7 months ago

@sroussey 64-bit Arm is a popular platform. We should make sure it works fine there. Any other ways we can improve our cross-compilation scripts?

sroussey commented 7 months ago

I think it compiles fine now. This is a separate issue of bundling.

jlarmstrongiv commented 7 months ago

I’ll look at the package.json as well as try using esbuild bundle and see if that works (it also supports .node files)

The package https://www.npmjs.com/package/@vercel/ncc handles bundling with .node files, and worked with usearch before 2.10.x. Example: usearcharm64nodejs20__2_9_2.zip

If it can’t be bundled, it can’t be used in serverless like AWS Lambda.

jlarmstrongiv commented 7 months ago

I think @vercel/ncc is failing because the way the bindings import has changed from something bundlers can analyze:

const compiled = require('bindings')('usearch');

To dynamic code that bundlers can’t analyze:

const compiled: Compiled = build(getBuildDir(getDirName()));

interface Compiled {
  CompiledIndex: CompiledIndex;
  exactSearch(
    dataset: VectorOrMatrix,
    queries: VectorOrMatrix,
    dimensions: number,
    count: number,
    metric: MetricKind
  ): CompiledSearchResult;
}

function getBuildDir(dir: string) {
  if (existsSync(path.join(dir, "build"))) return dir;
  if (existsSync(path.join(dir, "prebuilds"))) return dir;
  if (path.basename(dir) === ".next") {
    // special case for next.js on custom node (not vercel)
    const sideways = path.join(dir, "..", "node_modules", "usearch");
    if (existsSync(sideways)) return getBuildDir(sideways);
  }
  if (dir === "/") throw new Error("Could not find native build for usearch");
  return getBuildDir(path.join(dir, ".."));
}

function getDirName() {
  try {
    if (__dirname) return __dirname;
  } catch (e) { }
  return getRoot(getFileName());
}

@sroussey is it possible to use the previous import syntax with the bindings?

In the meantime, I will try to see if esbuild bundling works


Note to self, add "./package.json": "./package.json" back to package.json field exports

sroussey commented 7 months ago

Yeah, prebuilt binaries have a different algorithm to find the binary, since there are several.

Have you tried --external ?

sroussey commented 7 months ago

At any rate, I don't use aws lambda, but if you give me some steps to reproduce locally, I'll have a look.

jlarmstrongiv commented 7 months ago

Sure, the easiest way to locally reproduce without getting docker involved is:

mkdir usearch-bundle
cd usearch-bundle
npm init -y
npm install usearch@2.11.1

To get the entrypoint, run node -p "require.resolve('usearch')" or just run the commands below:

Then, try bundling with @vercel/ncc (using --external doesn’t make sense in this case, because our goal is to bundle usearch, not skip it):

npx --yes @vercel/ncc build node_modules/usearch/javascript/dist/cjs/usearch.js -o ncc-usearch-bundled --debug

or with esbuild:

npx --yes esbuild node_modules/usearch/javascript/dist/cjs/usearch.js --bundle --outdir=esbuild-usearch-bundled --loader:.node=file --platform=node

Bundling works great with many other native addons that have prebuilds, such as:

module.exports = exports = binding;

- `hnswlib-node`
```js
const addon = require('bindings')('addon');
module.exports = addon;

It should be possible to add prebuilds without breaking bundling. @sroussey hopefully some of those package examples can be inspiration. I’ll look at it more, but I’m not familiar enough with prebuilds and node-gyp to immediately see what the solution is.

jlarmstrongiv commented 7 months ago

One thing I notice with better-sqlite3, duckdb, and @tensorflow/tfjs-node is that they don’t download the binaries for all platforms on install—they install the correct binary for the particular platform (named the same package-name.node file) at a well-known location for common libraries like bindings or @mapbox/node-pre-gyp to find.

sroussey commented 7 months ago

Great! I'll have a look.

Hopefully one of them uses prebuildify. I think the sqlite one (based on my poor memory) relies on a lifecycle script to download a prebuilt binary, and for security reasons people are moving away from having some deep dependency run arbitrary code on install on your machine (and another reason for dev containers). Bun, for example, does not run them.

I remember having issues since typescript doesn't have __dirname etc. I know some better ways around that now however.

ashvardanian commented 7 months ago

I am not sure if I broke something, but potentially after these cosmetic changes the Windows CI failed. @sroussey I think it might be a good ide to deconvolute the build commands for MacOS, Linux, and Windows, similar to how I do for other platforms in release.yml? I am also curious, why are we excluding those targets:

      matrix:
        arch:
          - x64
          - x86
        os:
          - macos-latest
          - ubuntu-latest
          - windows-latest
        exclude:
          - arch: x86
            os: macos-latest
          - arch: x86
            os: ubuntu-latest
sroussey commented 7 months ago

Those can cross compile, so faster to do it that way.

sroussey commented 7 months ago

Also, I don't think GitHub has arm64 for those.

sroussey commented 7 months ago

cosmetic changes

Maybe a red herring? It uses windows-latest so maybe that changed instead?

Looking at the changeset, I cannot see why the error would come up. You might try branching that off and do a force push of the last known good and see if that now fails.

sroussey commented 7 months ago

Then, try bundling with @vercel/ncc (using --external doesn’t make sense in this case, because our goal is to bundle usearch, not skip it):

Yeah, kinda. bundling and packaging are kinda being used interchangeably. A clearer way to think of it is that bundling is like inlining code (this is kinda sorta how the bundle ends up as one file), and packaging is taking this bundle and other assets and doing something with them. So external, kinda-sorta meaning don't inline, not so much don't include. I say kinda-sorta, because this is not C and linking and standard ABIs, etc., as things are much more... fluid... in the JS space, so every tool goes its own way.

sroussey commented 7 months ago

Then, try bundling with @vercel/ncc (using --external doesn’t make sense in this case, because our goal is to bundle usearch, not skip it):

npx --yes @vercel/ncc build node_modules/usearch/javascript/dist/cjs/usearch.js -o ncc-usearch-bundled --debug

OK, what should I expect? I get

❯ npx --yes @vercel/ncc build node_modules/usearch/javascript/dist/cjs/usearch.js -o ncc-usearch-bundled --debug
ncc: Version 0.38.1
ncc: Compiling file index.js into CJS
Skipping asset emission of /Users/steve/Code/usearch-bundle/package.json for /Users/steve/Code/usearch-bundle/node_modules/bindings/bindings.js as it is outside the package base /Users/steve/Code/usearch-bundle/node_modules/bindings
41kB  ncc-usearch-bundled/index.js
41kB  [304ms] - ncc 0.38.1
sroussey commented 7 months ago

These don't include prebuilt binaries (you won't find a .node file among them):

https://www.npmjs.com/package/better-sqlite3?activeTab=code https://www.npmjs.com/package/duckdb?activeTab=code https://www.npmjs.com/package/hnswlib-node?activeTab=code https://www.npmjs.com/package/@tensorflow/tfjs-node?activeTab=code

As opposed to usearch:

https://www.npmjs.com/package/usearch?activeTab=code

Frustrating.

Anyhow, I will look at ncc source code for ncc and see what they are doing for .node files.

jlarmstrongiv commented 7 months ago

OK, what should I expect? I get

That looks about right (I don’t remember the package.json warning). Though, before 2.10.x, it also included the .node file in the output

These don't include prebuilt binaries (you won't find a .node file among them):

Perhaps not in the npm package, but sometimes they are stored in github releases or other cache locations

Anyhow, I will look at ncc source code for ncc and see what they are doing for .node files.

Thank you for checking! I look forward to being able to use usearch again

sroussey commented 7 months ago

Perhaps not in the npm package, but sometimes they are stored in github releases or other cache locations

Yeah... unfortunately that means having an install script run.

Thank you for checking! I look forward to being able to use usearch again

Oh, you should be able to just copy theprebuilds folder over, right? People usually do this with webpack.

From the ncc dev: "We specifically include support for bindings and node-pre-gyp". I am pretty sure they don't anticipate multiple architectures. But I'll see what they do.

sroussey commented 7 months ago

Or this:

❯ npx --yes @vercel/ncc build test.js -o ncc-usearch-bundled --debug --external usearch
ncc: Version 0.38.1
ncc: Compiling file index.js into CJS
2kB  ncc-usearch-bundled/index.js
2kB  [113ms] - ncc 0.38.1
❯ cp -rp node_modules/usearch ncc-usearch-bundled
❯ node ncc-usearch-bundled/index.js
Index {}

That will contain some extra files though (all the stuff to build it)