Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ jobs:
arch: arm64
generator: Ninja
build: npm run build:rust -- --target aarch64-pc-windows-msvc
# Cross-compiled: the Android SDK is only on the x86_64 runner images.
- host: ubuntu-24.04
target: aarch64-linux-android
arch: x64
build: npm run build:rust -- --target aarch64-linux-android

name: Build - ${{ matrix.settings.target }}
runs-on: ${{ matrix.settings.host }}
Expand Down Expand Up @@ -238,6 +243,36 @@ jobs:
print("pointed the ASM language at clang-cl for windows-arm64")
PY

- name: Locate libclang for bindgen (Android)
if: matrix.settings.target == 'aarch64-linux-android'
# The image ships Clang, so no apt install: asking for clang and
# libclang-dev here once sat for an hour before being cancelled.
run: |
set -eux
libclang=$(find /usr/lib/llvm-* -name "libclang.so*" 2>/dev/null | head -1)
test -n "$libclang"
echo "LIBCLANG_PATH=$(dirname "$libclang")" >> "$GITHUB_ENV"

- name: Build native module (Android)
if: matrix.settings.target == 'aarch64-linux-android'
env:
CARGO_BUILD_TARGET: aarch64-linux-android
CARGO_TARGET_DIR: rust/target
run: |
set -eux
NDK_BIN="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"
SYSROOT="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/sysroot"
export PATH="$NDK_BIN:$PATH"

# API 24 is Termux's floor; btls-sys asks cmake for 21.
export CC_aarch64_linux_android="$NDK_BIN/aarch64-linux-android24-clang"
export CXX_aarch64_linux_android="$NDK_BIN/aarch64-linux-android24-clang++"
export AR_aarch64_linux_android="$NDK_BIN/llvm-ar"
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$CC_aarch64_linux_android"
export BINDGEN_EXTRA_CLANG_ARGS="--target=aarch64-linux-android24 --sysroot=$SYSROOT"

${{ matrix.settings.build }}

- name: Build native module (x86_64 musl target)
if: matrix.settings.target == 'x86_64-unknown-linux-musl'
env:
Expand Down Expand Up @@ -396,6 +431,36 @@ jobs:
node:20-alpine \
node scripts/smoke-native.cjs

- name: Smoke test native addon (Termux, android-arm64)
if: matrix.settings.target == 'aarch64-linux-android'
# termux/termux-docker is the Termux userland - Bionic, the $PREFIX
# layout, pkg - as an image. The aarch64 tag matches what we just built
# and needs binfmt here, since the Android SDK pins the build to x86_64.
#
# This exists because the addon carries NEEDED libc++_shared.so, which
# ships with the NDK rather than with Android. Termux has it in
# $PREFIX/lib, so the load works - assert that rather than trust it.
run: |
set -eux
docker run --rm --privileged aptman/qus -s -- -p aarch64

docker run --rm --privileged \
-v "$PWD:/data/data/com.termux/files/home/wreq-js" \
-w /data/data/com.termux/files/home/wreq-js \
termux/termux-docker:aarch64 \
/entrypoint.sh bash -lc '
set -eux
# /entrypoint.sh hands off to a login shell, which rebuilds the
# environment, so docker -e does not reach in here.
export WREQ_PLATFORM_ARCH=android-arm64

pkg update -y
pkg install -y nodejs
node -e "console.log(process.platform, process.arch)"
ls -l "$PREFIX/lib/libc++_shared.so"
node scripts/smoke-native.cjs
'

- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
Expand Down
44 changes: 44 additions & 0 deletions .github/workflows/experiment-targets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,50 @@ jobs:
echo "--- NEEDED ---"
readelf -d rust/*.node | grep NEEDED || true

- name: Load the addon in a real Termux userland
# The question this probe exists to answer. btls-sys links libc++ as a
# shared library, so the addon carries NEEDED libc++_shared.so, which
# ships with the NDK rather than with Android. Termux resolves it from
# $PREFIX/lib, and its nodejs package depends on libc++, so any Termux
# that can run Node already has it - but that has to be demonstrated,
# not assumed.
#
# termux/termux-docker is the Termux userland (Bionic, $PREFIX layout,
# pkg) as an image. The aarch64 tag matches the addon we just built and
# needs binfmt on an x86_64 runner; the Android SDK is only on the
# x86_64 runner images, so building here and emulating for the load is
# the way round that works.
run: |
set -eux
docker run --rm --privileged aptman/qus -s -- -p aarch64

docker run --rm --privileged \
-e WREQ_PLATFORM_ARCH=android-arm64 \
-v "$PWD:/data/data/com.termux/files/home/wreq-js" \
-w /data/data/com.termux/files/home/wreq-js \
termux/termux-docker:aarch64 \
/entrypoint.sh bash -lc '
set -eux
# /entrypoint.sh hands off to a login shell, which rebuilds the
# environment from Termux profile, so docker -e does not survive
# into here. Set it where the test actually runs.
export WREQ_PLATFORM_ARCH=android-arm64

pkg update -y
pkg install -y nodejs
node --version

# The loader keys off these two, and Bionic answers "android".
node -e "console.log(process.platform, process.arch)"

# The dependency this probe exists to check. libc++ is baseline in
# Termux and a declared dependency of its nodejs package, so it is
# here before we ask for it - show that rather than assume it.
ls -l "$PREFIX/lib/libc++_shared.so"

node scripts/smoke-native.cjs
'

- name: Upload addon
uses: actions/upload-artifact@v7
with:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ npm install wreq-js
# or: yarn add wreq-js / pnpm add wreq-js / bun add wreq-js
```

Prebuilt native binaries ship for macOS (Intel and Apple Silicon), Linux (x64 and arm64, glibc and musl), and Windows (x64 and arm64). Each one lives in its own `@wreq-js/binding-*` package listed under `optionalDependencies`, so an install downloads only the addon your platform actually loads. Platforms outside that list are not supported; build from source with a Rust toolchain instead (see [docs/BUILD.md](docs/BUILD.md)).
Prebuilt native binaries ship for macOS (Intel and Apple Silicon), Linux (x64 and arm64, glibc and musl), Windows (x64 and arm64), and Android arm64 under Termux. Each one lives in its own `@wreq-js/binding-*` package listed under `optionalDependencies`, so an install downloads only the addon your platform actually loads. Platforms outside that list are not supported; build from source with a Rust toolchain instead (see [docs/BUILD.md](docs/BUILD.md)).

Node.js 20 or newer.

Expand Down
2 changes: 2 additions & 0 deletions docs/api-reference/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
getOperatingSystems,
getEmulationHeaders,
resolveProfile,
isNativeAvailable,

// Classes
Headers,
Expand Down Expand Up @@ -52,6 +53,7 @@ import {
| [`getOperatingSystems()`](/api-reference/utilities#getoperatingsystems) | List available operating systems |
| [`getEmulationHeaders()`](/api-reference/utilities#getemulationheaders) | Read the headers a browser profile injects |
| [`resolveProfile()`](/api-reference/utilities#resolveprofile) | Resolve a family alias to a concrete profile |
| [`isNativeAvailable()`](/api-reference/utilities#isnativeavailable) | Check whether the native addon can be loaded |

## TypeScript support

Expand Down
36 changes: 36 additions & 0 deletions docs/api-reference/utilities.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,42 @@ const response = await fetch('https://example.com', {

---

## isNativeAvailable()

Report whether the native addon for the current platform can be loaded.

### Signature

```typescript
function isNativeAvailable(): boolean
```

### Returns

`true` when the addon is loadable, `false` otherwise.

The addon is loaded on first use, not when the module is imported, so `import 'wreq-js'`
never throws — a host that cannot run without it is free to check and fall back instead of
wrapping its own import in a `try`/`catch`. Calling any other export while this returns
`false` throws with the underlying reason.

It returns `false` when the platform has no published addon, when the matching
`@wreq-js/binding-*` package was skipped at install time (`--no-optional`, a strict package
manager layout, or an install performed for a different platform), or when an addon is
present but refuses to load, such as on an ABI mismatch.

### Example

```typescript
import { isNativeAvailable } from 'wreq-js';

if (!isNativeAvailable()) {
console.warn('wreq-js native addon unavailable, falling back to global fetch');
}
```

---

## Headers

The `Headers` class for working with HTTP headers.
Expand Down
1 change: 1 addition & 0 deletions docs/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Configured native targets in `package.json` include:
| Linux | arm64 (musl) |
| Windows | x64 |
| Windows | arm64 |
| Android | arm64 (Termux) |

## Building from source

Expand Down
3 changes: 3 additions & 0 deletions npm/android-arm64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `@wreq-js/binding-android-arm64`

This is the **aarch64-linux-android** binary for `@wreq-js/binding`
55 changes: 55 additions & 0 deletions npm/android-arm64/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "@wreq-js/binding-android-arm64",
"version": "3.1.0",
"cpu": [
"arm64"
],
"main": "wreq-js.android-arm64.node",
"files": [
"wreq-js.android-arm64.node"
],
"description": "Node.js/TypeScript HTTP client with browser TLS fingerprint impersonation (JA3/JA4). Bypass Cloudflare and anti-bot detection. Rust-powered, fetch()-compatible.",
"keywords": [
"cloudflare",
"cloudflare-bypass",
"anti-bot",
"bypass",
"tls-fingerprint",
"browser-fingerprint",
"ja3",
"ja4",
"impersonation",
"browser-emulation",
"tls",
"http2",
"fetch",
"http-client",
"web-scraping",
"web-scraper",
"crawler",
"typescript",
"nodejs",
"rust",
"wreq",
"browser"
],
"author": "Oleksandr Herasymov <herasymov7@icloud.com>",
"homepage": "https://wreq.sqdsh.win",
"license": "MIT",
"engines": {
"node": ">=20.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sqdshguy/wreq-js.git"
},
"bugs": {
"url": "https://github.com/sqdshguy/wreq-js/issues"
},
"publishConfig": {
"access": "public"
},
"os": [
"android"
]
}
12 changes: 2 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,6 @@
"engines": {
"node": ">=20.0.0"
},
"os": [
"darwin",
"linux",
"win32"
],
"cpu": [
"x64",
"arm64"
],
"files": [
"dist"
],
Expand All @@ -133,7 +124,8 @@
"x86_64-unknown-linux-musl",
"aarch64-unknown-linux-musl",
"x86_64-pc-windows-msvc",
"aarch64-pc-windows-msvc"
"aarch64-pc-windows-msvc",
"aarch64-linux-android"
]
}
}
1 change: 1 addition & 0 deletions scripts/smoke-native.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const targetMap = {
"aarch64-unknown-linux-musl": "linux-arm64-musl",
"x86_64-pc-windows-msvc": "win32-x64-msvc",
"aarch64-pc-windows-msvc": "win32-arm64-msvc",
"aarch64-linux-android": "android-arm64",
};

const platformArch = platformArchOverride ?? (target ? targetMap[target] : undefined);
Expand Down
Loading