Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
12b8d93
fix(ci): arm64 tests — pass binding selector to container; build node…
Oct 2, 2025
dbef9ff
fix(ci): tests-arm64 jobs download core ffi artifact; improve node ad…
jgowdy-godaddy Oct 2, 2025
c26a3e5
fix(ci): tests-arm64 artifact path normalization; ensure ffi lib pres…
jgowdy-godaddy Oct 2, 2025
091f8de
ci: fast-fail arm64 matrix; add concurrency; build Python wheel as ma…
jgowdy-godaddy Oct 2, 2025
b7d7e50
ci: tolerate python packaging failure to unblock tests; skip python a…
jgowdy-godaddy Oct 3, 2025
4f2cad2
tests: build local FFI in arm64 test container to satisfy glibc 2.31
jgowdy-godaddy Oct 3, 2025
7874362
ci: retrigger workflow
jgowdy-godaddy Oct 3, 2025
6e09685
ci: retrigger workflow
Oct 3, 2025
fcbef9c
ci/tests: build node addon in arm64 test container; set LD_LIBRARY_PA…
jgowdy-godaddy Oct 3, 2025
e3fb6a4
tests: create target/{debug,release} symlinks for interop; set LD_LIB…
jgowdy-godaddy Oct 3, 2025
5e6f26f
tests(py): ensure interop CLI exists and LD_LIBRARY_PATH set before i…
jgowdy-godaddy Oct 3, 2025
be54f72
tests(py/java): robust interop binary lookup; pass java.library.path …
jgowdy-godaddy Oct 3, 2025
c65c181
tests(java): set ASHERAH_JAVA_NATIVE and pass -Dasherah.java.nativeLi…
jgowdy-godaddy Oct 3, 2025
3928f9c
tests(java): dump surefire reports on failure for diagnostics
jgowdy-godaddy Oct 4, 2025
b3f1d57
tests(java): copy libasherah_java.* into both release and debug dirs …
jgowdy-godaddy Oct 4, 2025
e08579a
tests(ruby): build debug ffi; set ASHERAH_RUBY_NATIVE to explicit .so…
jgowdy-godaddy Oct 4, 2025
b591040
fix(tests): build FFI before Python interop tests to provide libasher…
jgowdy-godaddy Oct 4, 2025
e814f40
fix(ci): build Python wheels in manylinux_2_28 containers for glibc c…
jgowdy-godaddy Oct 4, 2025
4a48318
fix(ci): use maturin-action for Python packaging in manylinux containers
jgowdy-godaddy Oct 4, 2025
d5cdb3c
fix(ci): remove explicit --target from maturin args to avoid platform…
jgowdy-godaddy Oct 4, 2025
fa1d382
fix(ci): restore only target-specific artifacts for Python to avoid p…
jgowdy-godaddy Oct 4, 2025
90cf338
fix(ci): allow Python cache restore to fail since maturin builds from…
jgowdy-godaddy Oct 6, 2025
acebf44
fix(ci): skip core artifact restore for Python - maturin builds from …
jgowdy-godaddy Oct 6, 2025
a22f668
build(py): unset cargo env vars for maturin-action to avoid target di…
jgowdy-godaddy Oct 6, 2025
4fb72e1
build(py): use before-script to clean target dir instead of env vars
jgowdy-godaddy Oct 6, 2025
389139f
build(py): skip all caching for python component to avoid maturin con…
jgowdy-godaddy Oct 6, 2025
5978e6e
build(py): clean target dir before maturin build
jgowdy-godaddy Oct 6, 2025
dfa5c40
fix(ci): unset CARGO_HOME and RUSTUP_HOME for maturin-action
jgowdy-godaddy Oct 6, 2025
a7023f0
fix(ci): also clean cargo/rustup caches for Python manylinux builds
jgowdy-godaddy Oct 6, 2025
bd6f8c1
fix(ci): explicitly unset all cache env vars for maturin-action
jgowdy-godaddy Oct 6, 2025
ee26d9e
fix(ci): clean output artifacts directory for Python before build
jgowdy-godaddy Oct 6, 2025
e6e267a
fix(ci): use direct docker run instead of maturin-action for Python
jgowdy-godaddy Oct 6, 2025
8672304
fix(ci): use correct Python path in manylinux containers
jgowdy-godaddy Oct 6, 2025
4d46519
perf(ci): reuse pre-built core artifacts for Python builds
jgowdy-godaddy Oct 6, 2025
7648f25
perf(ci): cross-compile arm64 Python on x86_64 instead of QEMU
jgowdy-godaddy Oct 6, 2025
f61faa3
fix(ci): use manylinux cross-compile container for arm64 Python
jgowdy-godaddy Oct 6, 2025
9cccc33
fix(ci): use x86_64 cross-compile container not arm64
jgowdy-godaddy Oct 6, 2025
8a71bbd
fix(ci): use pip3.11 instead of cp38 pip for SSL support
jgowdy-godaddy Oct 6, 2025
15205c4
fix(ci): set cross-compile env vars for arm64 Python build
jgowdy-godaddy Oct 6, 2025
968cf66
fix(ci): install cross-compile toolchain in standard manylinux container
jgowdy-godaddy Oct 6, 2025
7fb0d92
fix(ci): install glibc-devel.aarch64 for ARM64 system headers
jgowdy-godaddy Oct 6, 2025
008c66d
fix(ci): build arm64 Python wheel on host using cached artifacts
jgowdy-godaddy Oct 6, 2025
702bc14
fix(ci): skip auditwheel during build, repair manually after
jgowdy-godaddy Oct 6, 2025
e977124
fix(ci): skip auditwheel repair for arm64 Python wheel
jgowdy-godaddy Oct 6, 2025
2fe73b7
perf(tests): skip unnecessary Rust rebuilds in arm64 tests
jgowdy-godaddy Oct 7, 2025
677e5f0
fix(ci): build arm64 FFI in manylinux container for glibc compatibility
jgowdy-godaddy Oct 7, 2025
9a10789
fix(ci): cross-compile arm64 FFI from x86_64 manylinux container
jgowdy-godaddy Oct 7, 2025
46ff19b
fix(ci): install glibc-devel.aarch64 for ARM64 system headers
jgowdy-godaddy Oct 7, 2025
e84f34a
fix(ci): diagnose cross-compiler installation in manylinux
jgowdy-godaddy Oct 7, 2025
c112196
fix(ci): search for ARM64 sysroot packages in EPEL
jgowdy-godaddy Oct 7, 2025
4988777
fix(ci): use ubuntu-20.04 with cross-compiler for arm64 FFI build
jgowdy-godaddy Oct 7, 2025
0488bec
fix(ci): use ubuntu-latest for arm64 build (runner availability)
jgowdy-godaddy Oct 7, 2025
02d6a4e
fix(ci): use ubuntu-20.04 for arm64 FFI (glibc 2.31 required)
jgowdy-godaddy Oct 7, 2025
220aa22
fix(ci): use Debian Bullseye container for arm64 FFI build
jgowdy-godaddy Oct 7, 2025
180a9ea
fix(ci): use rust:1.86-bullseye container for arm64 build
jgowdy-godaddy Oct 7, 2025
d7c3b0c
fix(ci): use absolute paths for arm64 cache to fix container/host mis…
jgowdy-godaddy Oct 7, 2025
d3dd5fb
fix(ci): replace cache with artifacts for arm64 core build output
jgowdy-godaddy Oct 7, 2025
e4860aa
debug(ci): add logging to diagnose artifact download paths
jgowdy-godaddy Oct 7, 2025
707e33e
fix(ci): correct artifact upload/download paths for arm64 core
jgowdy-godaddy Oct 7, 2025
2846029
fix(node): ensure .node addon is copied from target dir for cross-com…
jgowdy-godaddy Oct 7, 2025
90f175e
fix(node): add comprehensive search and debug logging for .node addon
jgowdy-godaddy Oct 8, 2025
5b627e2
fix: search current directory for .node addon from napi-rs
jgowdy-godaddy Oct 8, 2025
b473e94
fix(ci): prevent ffi artifact from overwriting binding artifacts in t…
jgowdy-godaddy Oct 8, 2025
e558dcd
perf: cache arm64 test image with 7-day age-based refresh
jgowdy-godaddy Oct 8, 2025
ed57625
fix(ci): correct FFI artifact download logic for ARM64 tests
jgowdy-godaddy Oct 8, 2025
e9d1ba7
debug: add artifact directory listing to diagnose node test failure
jgowdy-godaddy Oct 8, 2025
d90e6b7
debug: add FFI library check to diagnose node addon loading failure
jgowdy-godaddy Oct 8, 2025
0ca1254
chore(node): bump version to 4.0.0 for major Rust backend release
jgowdy-godaddy Oct 8, 2025
55360a3
fix(ci): download FFI artifact for all bindings except python
jgowdy-godaddy Oct 8, 2025
b7d8fd8
debug: add ldd check and LD_LIBRARY_PATH verification for node addon
jgowdy-godaddy Oct 8, 2025
3efaa3f
fix(ci): build node ARM64 binding in Bullseye container for glibc 2.3…
jgowdy-godaddy Oct 8, 2025
8c8056c
fix(ci): download python artifact for ARM64 python tests
jgowdy-godaddy Oct 8, 2025
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
170 changes: 147 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
name: CI

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

on:
push:
branches: [ main ]
Expand Down Expand Up @@ -111,6 +115,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Restore workspace caches
if: matrix.component != 'python'
uses: actions/cache@v4
with:
path: |
Expand All @@ -126,6 +131,7 @@ jobs:
build-${{ runner.os }}-x86_64-${{ matrix.component }}-
build-${{ runner.os }}-x86_64-
- name: Restore x86_64 core artifacts
if: matrix.component != 'python'
uses: actions/cache/restore@v4
with:
path: |
Expand All @@ -141,7 +147,36 @@ jobs:
if: matrix.component == 'dotnet'
with:
dotnet-version: '8.0.x'
- name: Restore x86_64 core artifacts for Python
if: matrix.component == 'python'
uses: actions/cache/restore@v4
with:
path: |
target/x86_64-unknown-linux-gnu
target/release
key: core-target-${{ runner.os }}-x86_64-${{ github.run_id }}
fail-on-cache-miss: true
- name: Prepare Python build directory
if: matrix.component == 'python'
run: |
rm -rf artifacts/x86_64/python || true
mkdir -p artifacts/x86_64/python
- name: Package ${{ matrix.component }} (x86_64) - manylinux
if: matrix.component == 'python'
run: |
docker run --rm \
-v "$PWD":/io \
-w /io \
quay.io/pypa/manylinux_2_28_x86_64:latest \
bash -c "
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
source \$HOME/.cargo/env
/opt/python/cp38-cp38/bin/pip install maturin
/opt/python/cp38-cp38/bin/maturin build --release --manifest-path asherah-py/Cargo.toml --compatibility manylinux_2_28 --out artifacts/x86_64/python
"

- name: Package ${{ matrix.component }} (x86_64)
if: matrix.component != 'python'
env:
TARGET_ARCH: x86_64
BINDING_COMPONENTS: ${{ matrix.component }}
Expand All @@ -156,15 +191,38 @@ jobs:
arm64-test-image:
runs-on: ubuntu-latest
needs: lint
env:
CACHE_MAX_AGE_DAYS: 7
outputs:
cache-hit: ${{ steps.check-cache.outputs.cache-hit }}
steps:
- uses: actions/checkout@v4
- name: Calculate cache key
id: cache-key
run: |
DOCKERFILE_HASH=$(sha256sum docker/tests.Dockerfile | cut -d' ' -f1 | head -c 8)
# Get week number to force rebuild every N days
WEEK_NUM=$(( $(date +%s) / 86400 / ${{ env.CACHE_MAX_AGE_DAYS }} ))
CACHE_KEY="arm64-test-image-${DOCKERFILE_HASH}-week-${WEEK_NUM}"
echo "cache-key=${CACHE_KEY}" >> $GITHUB_OUTPUT
echo "Cache key: ${CACHE_KEY}"
- name: Check for cached image
id: check-cache
uses: actions/cache@v4
with:
path: /tmp/asherah-tests-arm64.tar
key: ${{ steps.cache-key.outputs.cache-key }}
lookup-only: true
- name: Set up QEMU
if: steps.check-cache.outputs.cache-hit != 'true'
uses: docker/setup-qemu-action@v3
with:
platforms: linux/arm64
- name: Set up Docker Buildx
if: steps.check-cache.outputs.cache-hit != 'true'
uses: docker/setup-buildx-action@v3
- name: Build arm64 test image
if: steps.check-cache.outputs.cache-hit != 'true'
run: |
docker buildx build \
--file docker/tests.Dockerfile \
Expand All @@ -174,6 +232,18 @@ jobs:
--cache-to type=gha,mode=max,scope=tests-arm64-image \
--output type=docker,dest=/tmp/asherah-tests-arm64.tar \
.
- name: Restore cached image
if: steps.check-cache.outputs.cache-hit == 'true'
uses: actions/cache/restore@v4
with:
path: /tmp/asherah-tests-arm64.tar
key: ${{ steps.cache-key.outputs.cache-key }}
- name: Save image to cache
if: steps.check-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: /tmp/asherah-tests-arm64.tar
key: ${{ steps.cache-key.outputs.cache-key }}
- name: Upload arm64 test image
uses: actions/upload-artifact@v4
with:
Expand All @@ -186,7 +256,7 @@ jobs:
- package-arm64
- arm64-test-image
strategy:
fail-fast: false
fail-fast: true
matrix:
binding: [ffi, python, node, dotnet, java]
steps:
Expand All @@ -210,6 +280,12 @@ jobs:
with:
name: bindings-linux-aarch64-part-${{ matrix.binding }}
path: artifacts/aarch64
- name: Download arm64 core FFI artifact
if: matrix.binding != 'python' && matrix.binding != 'ffi'
uses: actions/download-artifact@v4
with:
name: bindings-linux-aarch64-part-ffi
path: artifacts/aarch64
- name: Download arm64 test image
uses: actions/download-artifact@v4
with:
Expand Down Expand Up @@ -393,6 +469,7 @@ jobs:
core-arm64:
runs-on: ubuntu-latest
needs: lint
container: rust:1.86-bullseye # glibc 2.31, Rust pre-installed
env:
CARGO_HOME: ${{ github.workspace }}/.cache/cargo
RUSTUP_HOME: ${{ github.workspace }}/.cache/rustup
Expand All @@ -415,38 +492,53 @@ jobs:
key: build-${{ runner.os }}-arm64-core-${{ hashFiles('**/Cargo.lock', 'asherah-node/package-lock.json', 'asherah-py/Cargo.toml', 'asherah-py/pyproject.toml', 'asherah-java/java/pom.xml', 'asherah-dotnet/**/*.csproj') }}
restore-keys: |
build-${{ runner.os }}-arm64-core-
- name: Install cross toolchains
- name: Install cross-compile toolchain and Node.js for arm64
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross pkg-config
- name: Prepare Rust target
run: rustup target add aarch64-unknown-linux-gnu
- name: Build FFI core (arm64)
apt-get update
apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs
- name: Build FFI core (arm64) via cross-compilation
env:
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++
AR_aarch64_unknown_linux_gnu: aarch64-linux-gnu-ar
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
PKG_CONFIG_ALLOW_CROSS: 1
TARGET_ARCH: aarch64
BINDING_COMPONENTS: ffi
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_AR: aarch64-linux-gnu-ar
run: |
rustup target add aarch64-unknown-linux-gnu
./scripts/build-bindings.sh
- name: Build Node.js binding (arm64) in Bullseye container
env:
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++
AR_aarch64_unknown_linux_gnu: aarch64-linux-gnu-ar
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
PKG_CONFIG_ALLOW_CROSS: 1
TARGET_ARCH: aarch64
BINDING_COMPONENTS: node
SKIP_CORE_BUILD: "1"
run: ./scripts/build-bindings.sh
- name: Cache arm64 core artifacts
uses: actions/cache/save@v4
- name: Upload arm64 core target artifacts
uses: actions/upload-artifact@v4
with:
path: |
target/aarch64-unknown-linux-gnu
target/release
key: core-target-${{ runner.os }}-arm64-${{ github.run_id }}
name: arm64-core-artifacts
path: target/
- name: Upload arm64 node binding artifact
uses: actions/upload-artifact@v4
with:
name: bindings-linux-aarch64-part-node
path: artifacts/aarch64

package-arm64:
runs-on: ubuntu-latest
needs: core-arm64
strategy:
fail-fast: false
matrix:
component: [ffi, node, python, dotnet, java]
component: [ffi, python, dotnet, java]
env:
CARGO_HOME: ${{ github.workspace }}/.cache/cargo
RUSTUP_HOME: ${{ github.workspace }}/.cache/rustup
Expand All @@ -456,6 +548,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Restore workspace caches
if: matrix.component != 'python'
uses: actions/cache@v4
with:
path: |
Expand All @@ -470,19 +563,19 @@ jobs:
restore-keys: |
build-${{ runner.os }}-arm64-${{ matrix.component }}-
build-${{ runner.os }}-arm64-
- name: Restore arm64 core artifacts
uses: actions/cache/restore@v4
- name: Download arm64 core artifacts
if: matrix.component != 'python'
uses: actions/download-artifact@v4
with:
path: |
target/aarch64-unknown-linux-gnu
target/release
key: core-target-${{ runner.os }}-arm64-${{ github.run_id }}
fail-on-cache-miss: true
name: arm64-core-artifacts
path: target/
- name: Install cross toolchains
if: matrix.component != 'python'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross pkg-config
- name: Prepare Rust target
if: matrix.component != 'python'
run: rustup target add aarch64-unknown-linux-gnu
- uses: actions/setup-node@v4
if: matrix.component == 'node'
Expand All @@ -492,7 +585,38 @@ jobs:
if: matrix.component == 'dotnet'
with:
dotnet-version: '8.0.x'
- name: Download arm64 core artifacts for Python
if: matrix.component == 'python'
uses: actions/download-artifact@v4
with:
name: arm64-core-artifacts
path: target/
- name: Prepare Python build directory
if: matrix.component == 'python'
run: |
rm -rf artifacts/aarch64/python || true
mkdir -p artifacts/aarch64/python
- name: Install cross-compile toolchain for arm64
if: matrix.component == 'python'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Build Python wheel for arm64 (using cached core artifacts)
if: matrix.component == 'python'
env:
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++
AR_aarch64_unknown_linux_gnu: aarch64-linux-gnu-ar
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
run: |
pip install maturin
rustup target add aarch64-unknown-linux-gnu
# Build with cached arm64 core artifacts - only compiles the Python binding wrapper
# Skip auditwheel because GitHub runner has too-new GLIBC but maturin still tags correctly
maturin build --release --target aarch64-unknown-linux-gnu --manifest-path asherah-py/Cargo.toml --skip-auditwheel --out artifacts/aarch64/python

- name: Package ${{ matrix.component }} (arm64)
if: matrix.component != 'python'
env:
TARGET_ARCH: aarch64
BINDING_COMPONENTS: ${{ matrix.component }}
Expand Down
42 changes: 42 additions & 0 deletions BUILD_RULES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Build Rules

## Rust Compilation

**NEVER compile Rust code under QEMU emulation or any other emulation.**

All Rust builds must be either:
1. Native compilation on the target architecture
2. Cross-compilation from a native host

Emulated builds are unacceptably slow (60-90 minutes vs 5-10 minutes) and are forbidden.

### Examples

❌ **WRONG**: `docker run --platform linux/arm64` on x86_64 (runs under QEMU)
❌ **WRONG**: Building in ARM64 container on x86_64 host
❌ **WRONG**: `cargo build` inside emulated environment

✅ **CORRECT**: Cross-compile from x86_64 to aarch64 with proper toolchain
✅ **CORRECT**: Native build on actual ARM64 hardware
✅ **CORRECT**: Using manylinux_2_28_x86_64 container with aarch64 cross-compiler

### CI Implementation

- Use manylinux_2_28 containers for glibc 2.28 compatibility
- Install cross-compile toolchains (gcc-aarch64-linux-gnu, etc.)
- Set proper environment variables for cross-compilation
- Trust pre-built artifacts from earlier pipeline stages

### Current Hardcoded Assumptions

The CI workflow currently assumes x86_64 as the native architecture and cross-compiles to aarch64:
- Job names: `core-x86_64`, `package-x86_64`, `core-arm64`, `package-arm64`
- Artifact paths: `artifacts/x86_64`, `artifacts/aarch64`
- Cache keys: `-x86_64-`, `-arm64-`
- Manylinux containers: `manylinux_2_28_x86_64` for native, cross-compilers for aarch64

**Future Work**: The workflow could be made bidirectional by:
1. Detecting host architecture (`uname -m`)
2. Setting native=x86_64 cross=aarch64 (or vice versa)
3. Using variables throughout instead of hardcoded values
4. This would allow the same workflow to run on ARM64 laptops/runners
5 changes: 4 additions & 1 deletion asherah-node/npm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ const attempts = [
path.join(__dirname, '..', 'index.node'),
];

let lastErr = null;
for (const candidate of attempts) {
try {
module.exports = require(candidate);
module.exports.__binary = candidate;
return;
} catch (err) {
lastErr = err;
if (
err.code !== 'MODULE_NOT_FOUND' &&
err.code !== 'ERR_MODULE_NOT_FOUND' &&
Expand All @@ -21,4 +23,5 @@ for (const candidate of attempts) {
}
}

throw new Error('Failed to load Asherah native addon.');
const detail = lastErr ? `: ${lastErr.message || String(lastErr)}` : '';
throw new Error('Failed to load Asherah native addon' + detail);
11 changes: 6 additions & 5 deletions asherah-node/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "asherah-node",
"version": "0.1.0",
"private": true,
"version": "4.0.0",
"private": false,
"description": "Node.js addon for Asherah (napi-rs)",
"main": "npm/index.js",
"types": "index.d.ts",
Expand All @@ -24,8 +24,9 @@
"node": ">= 18"
},
"optionalDependencies": {
"asherah-win32-x64-msvc": "0.1.0",
"asherah-darwin-x64": "0.1.0",
"asherah-linux-x64-gnu": "0.1.0"
"asherah-win32-x64-msvc": "4.0.0",
"asherah-darwin-x64": "4.0.0",
"asherah-linux-x64-gnu": "4.0.0",
"asherah-linux-arm64-gnu": "4.0.0"
}
}
Loading
Loading