Skip to content

Commit 12f25b5

Browse files
authored
feat(*): support wasi-wasm32 target (#752)
* feat(*): support wasi-wasm32 target * patch * fix filter
1 parent d38c394 commit 12f25b5

File tree

148 files changed

+1776
-549
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

148 files changed

+1776
-549
lines changed

.eslintignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ coverage
99
target
1010
packages/deno-lint/cli.js
1111
packages/deno-lint/cli.d.ts
12+
packages/*/*.wasi.cjs
13+
packages/*/wasi-worker.mjs
14+
packages/*/index.js
15+
packages/*/index.d.ts

.github/workflows/ci.yaml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ jobs:
6969
- host: windows-latest
7070
target: 'aarch64-pc-windows-msvc'
7171
build: yarn build --target aarch64-pc-windows-msvc
72+
- host: ubuntu-latest
73+
target: 'wasm32-wasi-preview1-threads'
74+
build: yarn workspaces foreach -A --no-private -j 1 --exclude "@node-rs/{jsonwebtoken,deno-lint}" run build --target wasm32-wasi-preview1-threads
7275

7376
name: stable - ${{ matrix.settings.target }} - node@20
7477
runs-on: ${{ matrix.settings.host }}
@@ -133,11 +136,20 @@ jobs:
133136

134137
- name: Upload artifact
135138
uses: actions/upload-artifact@v4
139+
if: ${{ matrix.settings.target != 'wasm32-wasi-preview1-threads' }}
136140
with:
137141
name: bindings-${{ matrix.settings.target }}
138142
path: packages/*/*.node
139143
if-no-files-found: error
140144

145+
- name: Upload artifact
146+
uses: actions/upload-artifact@v4
147+
if: ${{ matrix.settings.target == 'wasm32-wasi-preview1-threads' }}
148+
with:
149+
name: bindings-${{ matrix.settings.target }}
150+
path: packages/*/*.wasm
151+
if-no-files-found: error
152+
141153
build-freebsd:
142154
runs-on: macos-12
143155
name: Build FreeBSD
@@ -520,6 +532,40 @@ jobs:
520532
yarn test -s
521533
ls -la
522534
535+
test-wasi-nodejs:
536+
name: Test bindings on wasi - node@${{ matrix.node }}
537+
needs:
538+
- build
539+
strategy:
540+
fail-fast: false
541+
matrix:
542+
node: ['18', '20']
543+
runs-on: ubuntu-latest
544+
steps:
545+
- uses: actions/checkout@v4
546+
- uses: actions/setup-node@v4
547+
with:
548+
node-version: ${{ matrix.node }}
549+
cache: yarn
550+
- name: 'Install dependencies'
551+
run: yarn install --immutable --mode=skip-build
552+
- name: Download artifacts
553+
uses: actions/download-artifact@v4
554+
with:
555+
name: bindings-wasm32-wasi-preview1-threads
556+
path: artifacts
557+
- name: Move artifacts
558+
run: yarn artifacts
559+
shell: bash
560+
- name: List packages
561+
run: ls -R .
562+
- name: Test
563+
run: |
564+
yarn build:ts
565+
yarn test -s
566+
env:
567+
NAPI_RS_FORCE_WASI: 'true'
568+
523569
publish:
524570
name: Publish
525571
runs-on: ubuntu-latest
@@ -532,6 +578,7 @@ jobs:
532578
- test-linux-aarch64-musl-binding
533579
- test-linux-arm-gnueabihf-binding
534580
- test-macOS-windows-binding
581+
- test-wasi-nodejs
535582
steps:
536583
- uses: actions/checkout@v4
537584

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ temp/
177177
# End of https://www.gitignore.io/api/node
178178

179179
*.node
180+
*.wasm
180181
lib
181182
artifacts
182183

@@ -186,4 +187,4 @@ artifacts
186187
!.yarn/plugins
187188
!.yarn/releases
188189
!.yarn/sdks
189-
!.yarn/versions
190+
!.yarn/versions

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ node_modules
33
lib
44
.yarn
55
yarn.lock
6+
packages/*/*.wasi.js
7+
packages/*/index.js
8+
packages/*/index.d.ts

ava.config.mjs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export default {
1+
const avaConfig = {
22
extensions: ['ts'],
33
workerThreads: false,
44
cache: false,
@@ -9,3 +9,9 @@ export default {
99
TS_NODE_PROJECT: './tsconfig.test.json',
1010
},
1111
}
12+
13+
if (process.env.NAPI_RS_FORCE_WASI) {
14+
avaConfig.files.push(`!packages/jsonwebtoken/**/*.spec.ts`)
15+
}
16+
17+
export default avaConfig

crates/alloc/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ version = "0.1.0"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

8-
[target.'cfg(not(target_os = "linux"))'.dependencies]
8+
[target.'cfg(all(not(target_os = "linux"), not(target_family = "wasm")))'.dependencies]
99
mimalloc = { version = "0.1" }
1010

1111
[target.'cfg(target_os = "linux")'.dependencies]

crates/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
#[cfg(not(target_family = "wasm"))]
12
#[global_allocator]
23
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
"postinstall": "husky install"
2525
},
2626
"devDependencies": {
27-
"@napi-rs/cli": "^3.0.0-alpha.25",
27+
"@emnapi/core": "^0.45.0",
28+
"@emnapi/runtime": "^0.45.0",
29+
"@napi-rs/cli": "^3.0.0-alpha.29",
2830
"@swc-node/core": "^1.10.6",
2931
"@swc-node/register": "^1.6.8",
3032
"@swc/core": "^1.3.101",

packages/argon2/argon2.wasi.cjs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* eslint-disable */
2+
/* prettier-ignore */
3+
4+
/* auto-generated by NAPI-RS */
5+
6+
const __nodeFs= require('node:fs')
7+
const __nodePath = require('node:path')
8+
const { WASI: __nodeWASI } = require('node:wasi')
9+
const { Worker } = require('node:worker_threads')
10+
11+
const { instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync } = require('@emnapi/core')
12+
const { getDefaultContext: __emnapiGetDefaultContext } = require('@emnapi/runtime')
13+
14+
const __wasi = new __nodeWASI({
15+
version: 'preview1',
16+
env: process.env,
17+
preopens: {
18+
'/': '/'
19+
}
20+
})
21+
22+
const __emnapiContext = __emnapiGetDefaultContext()
23+
24+
const __sharedMemory = new WebAssembly.Memory({
25+
initial: 1024,
26+
maximum: 10240,
27+
shared: true,
28+
})
29+
30+
let __wasmFilePath = __nodePath.join(__dirname, 'argon2.wasm32-wasi.wasm')
31+
32+
if (!__nodeFs.existsSync(__wasmFilePath)) {
33+
try {
34+
__wasmFilePath = __nodePath.resolve('@node-rs/argon2-wasm32-wasi')
35+
} catch {
36+
throw new Error('Cannot find argon2.wasm32-wasi.wasm file, and @node-rs/argon2-wasm32-wasi package is not installed.')
37+
}
38+
}
39+
40+
const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), {
41+
context: __emnapiContext,
42+
asyncWorkPoolSize: (function() {
43+
const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE)
44+
// NaN > 0 is false
45+
if (threadsSizeFromEnv > 0) {
46+
return threadsSizeFromEnv
47+
} else {
48+
return 4
49+
}
50+
})(),
51+
wasi: __wasi,
52+
onCreateWorker() {
53+
return new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), {
54+
env: process.env,
55+
execArgv: ['--experimental-wasi-unstable-preview1'],
56+
})
57+
},
58+
overwriteImports(importObject) {
59+
importObject.env = {
60+
...importObject.env,
61+
...importObject.napi,
62+
...importObject.emnapi,
63+
memory: __sharedMemory,
64+
}
65+
return importObject
66+
},
67+
beforeInit({ instance }) {
68+
__napi_rs_initialize_modules(instance)
69+
}
70+
})
71+
72+
function __napi_rs_initialize_modules(__napiInstance) {
73+
__napiInstance.exports['__napi_register__Algorithm_0']?.()
74+
__napiInstance.exports['__napi_register__Version_1']?.()
75+
__napiInstance.exports['__napi_register__Options_struct_2']?.()
76+
__napiInstance.exports['__napi_register__HashTask_impl_3']?.()
77+
__napiInstance.exports['__napi_register__hash_4']?.()
78+
__napiInstance.exports['__napi_register__hash_sync_5']?.()
79+
__napiInstance.exports['__napi_register__RawHashTask_impl_6']?.()
80+
__napiInstance.exports['__napi_register__hash_raw_7']?.()
81+
__napiInstance.exports['__napi_register__hash_raw_sync_8']?.()
82+
__napiInstance.exports['__napi_register__VerifyTask_impl_9']?.()
83+
__napiInstance.exports['__napi_register__verify_10']?.()
84+
__napiInstance.exports['__napi_register__verify_sync_11']?.()
85+
}
86+
module.exports.Algorithm = __napiModule.exports.Algorithm,
87+
module.exports.hash = __napiModule.exports.hash,
88+
module.exports.hashRaw = __napiModule.exports.hashRaw,
89+
module.exports.hashRawSync = __napiModule.exports.hashRawSync,
90+
module.exports.hashSync = __napiModule.exports.hashSync,
91+
module.exports.verify = __napiModule.exports.verify,
92+
module.exports.verifySync = __napiModule.exports.verifySync,
93+
module.exports.Version = __napiModule.exports.Version

packages/argon2/index.d.ts

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,12 @@ export const enum Algorithm {
1717
* Hybrid that mixes Argon2i and Argon2d passes.
1818
* Uses the Argon2i approach for the first half pass over memory and Argon2d approach for subsequent passes. This effectively places it in the “middle” between the other two: it doesn’t provide as good TMTO/GPU cracking resistance as Argon2d, nor as good of side-channel resistance as Argon2i, but overall provides the most well-rounded approach to both classes of attacks.
1919
*/
20-
Argon2id = 2,
20+
Argon2id = 2
2121
}
2222

23-
export function hash(
24-
password: string | Buffer,
25-
options?: Options | undefined | null,
26-
abortSignal?: AbortSignal | undefined | null,
27-
): Promise<string>
23+
export function hash(password: string | Buffer, options?: Options | undefined | null, abortSignal?: AbortSignal | undefined | null): Promise<string>
2824

29-
export function hashRaw(
30-
password: string | Buffer,
31-
options?: Options | undefined | null,
32-
abortSignal?: AbortSignal | undefined | null,
33-
): Promise<Buffer>
25+
export function hashRaw(password: string | Buffer, options?: Options | undefined | null, abortSignal?: AbortSignal | undefined | null): Promise<Buffer>
3426

3527
export function hashRawSync(password: string | Buffer, options?: Options | undefined | null): Buffer
3628

@@ -73,18 +65,9 @@ export interface Options {
7365
salt?: Buffer
7466
}
7567

76-
export function verify(
77-
hashed: string | Buffer,
78-
password: string | Buffer,
79-
options?: Options | undefined | null,
80-
abortSignal?: AbortSignal | undefined | null,
81-
): Promise<boolean>
68+
export function verify(hashed: string | Buffer, password: string | Buffer, options?: Options | undefined | null, abortSignal?: AbortSignal | undefined | null): Promise<boolean>
8269

83-
export function verifySync(
84-
hashed: string | Buffer,
85-
password: string | Buffer,
86-
options?: Options | undefined | null,
87-
): boolean
70+
export function verifySync(hashed: string | Buffer, password: string | Buffer, options?: Options | undefined | null): boolean
8871

8972
export const enum Version {
9073
/** Version 16 (0x10 in hex) */
@@ -93,5 +76,6 @@ export const enum Version {
9376
* Default value
9477
* Version 19 (0x13 in hex)
9578
*/
96-
V0x13 = 1,
79+
V0x13 = 1
9780
}
81+

0 commit comments

Comments
 (0)