Skip to content

Commit b23382d

Browse files
authored
feat(jsonwebtoken): support wasm32-wasi target (#798)
1 parent 3f1c657 commit b23382d

File tree

9 files changed

+310
-2
lines changed

9 files changed

+310
-2
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ jobs:
102102
build: yarn build --target aarch64-pc-windows-msvc
103103
- host: ubuntu-latest
104104
target: 'wasm32-wasi-preview1-threads'
105-
build: yarn workspaces foreach -A --no-private -j 1 --exclude "@node-rs/{jsonwebtoken,deno-lint}" run build --target wasm32-wasi-preview1-threads
105+
build: yarn workspaces foreach -A --no-private -j 1 --exclude "@node-rs/deno-lint" run build --target wasm32-wasi-preview1-threads
106106

107107
name: stable - ${{ matrix.settings.target }} - node@20
108108
runs-on: ${{ matrix.settings.host }}

packages/jsonwebtoken/browser.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from '@node-rs/jsonwebtoken-wasm32-wasi'
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import {
2+
instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync,
3+
getDefaultContext as __emnapiGetDefaultContext,
4+
WASI as __WASI,
5+
} from '@napi-rs/wasm-runtime'
6+
import { Volume as __Volume, createFsFromVolume as __createFsFromVolume } from '@napi-rs/wasm-runtime/fs'
7+
8+
import __wasmUrl from './jsonwebtoken.wasm32-wasi.wasm?url'
9+
10+
const __fs = __createFsFromVolume(
11+
__Volume.fromJSON({
12+
'/': null,
13+
}),
14+
)
15+
16+
const __wasi = new __WASI({
17+
version: 'preview1',
18+
fs: __fs,
19+
})
20+
21+
const __emnapiContext = __emnapiGetDefaultContext()
22+
23+
const __sharedMemory = new WebAssembly.Memory({
24+
initial: 1024,
25+
maximum: 10240,
26+
shared: true,
27+
})
28+
29+
const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer())
30+
31+
const {
32+
instance: __napiInstance,
33+
module: __wasiModule,
34+
napiModule: __napiModule,
35+
} = __emnapiInstantiateNapiModuleSync(__wasmFile, {
36+
context: __emnapiContext,
37+
asyncWorkPoolSize: 4,
38+
wasi: __wasi,
39+
onCreateWorker() {
40+
return new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {
41+
type: 'module',
42+
})
43+
},
44+
overwriteImports(importObject) {
45+
importObject.env = {
46+
...importObject.env,
47+
...importObject.napi,
48+
...importObject.emnapi,
49+
memory: __sharedMemory,
50+
}
51+
return importObject
52+
},
53+
beforeInit({ instance }) {
54+
__napi_rs_initialize_modules(instance)
55+
},
56+
})
57+
58+
function __napi_rs_initialize_modules(__napiInstance) {
59+
__napiInstance.exports['__napi_register__Algorithm_0']?.()
60+
__napiInstance.exports['__napi_register__decode_header_1']?.()
61+
__napiInstance.exports['__napi_register__Header_struct_2']?.()
62+
__napiInstance.exports['__napi_register__SignTask_impl_3']?.()
63+
__napiInstance.exports['__napi_register__sign_4']?.()
64+
__napiInstance.exports['__napi_register__sign_sync_5']?.()
65+
__napiInstance.exports['__napi_register__Validation_struct_6']?.()
66+
__napiInstance.exports['__napi_register__VerifyTask_impl_7']?.()
67+
__napiInstance.exports['__napi_register__verify_8']?.()
68+
__napiInstance.exports['__napi_register__verify_sync_9']?.()
69+
}
70+
export const Algorithm = __napiModule.exports.Algorithm
71+
export const decodeHeader = __napiModule.exports.decodeHeader
72+
export const sign = __napiModule.exports.sign
73+
export const signSync = __napiModule.exports.signSync
74+
export const verify = __napiModule.exports.verify
75+
export const verifySync = __napiModule.exports.verifySync
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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 {
12+
instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync,
13+
getDefaultContext: __emnapiGetDefaultContext,
14+
} = require('@napi-rs/wasm-runtime')
15+
16+
const __wasi = new __nodeWASI({
17+
version: 'preview1',
18+
env: process.env,
19+
preopens: {
20+
'/': '/'
21+
}
22+
})
23+
24+
const __emnapiContext = __emnapiGetDefaultContext()
25+
26+
const __sharedMemory = new WebAssembly.Memory({
27+
initial: 1024,
28+
maximum: 10240,
29+
shared: true,
30+
})
31+
32+
let __wasmFilePath = __nodePath.join(__dirname, 'jsonwebtoken.wasm32-wasi.wasm')
33+
34+
if (!__nodeFs.existsSync(__wasmFilePath)) {
35+
try {
36+
__wasmFilePath = __nodePath.resolve('@node-rs/jsonwebtoken-wasm32-wasi')
37+
} catch {
38+
throw new Error('Cannot find jsonwebtoken.wasm32-wasi.wasm file, and @node-rs/jsonwebtoken-wasm32-wasi package is not installed.')
39+
}
40+
}
41+
42+
const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), {
43+
context: __emnapiContext,
44+
asyncWorkPoolSize: (function() {
45+
const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE)
46+
// NaN > 0 is false
47+
if (threadsSizeFromEnv > 0) {
48+
return threadsSizeFromEnv
49+
} else {
50+
return 4
51+
}
52+
})(),
53+
wasi: __wasi,
54+
onCreateWorker() {
55+
return new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), {
56+
env: process.env,
57+
execArgv: ['--experimental-wasi-unstable-preview1'],
58+
})
59+
},
60+
overwriteImports(importObject) {
61+
importObject.env = {
62+
...importObject.env,
63+
...importObject.napi,
64+
...importObject.emnapi,
65+
memory: __sharedMemory,
66+
}
67+
return importObject
68+
},
69+
beforeInit({ instance }) {
70+
__napi_rs_initialize_modules(instance)
71+
}
72+
})
73+
74+
function __napi_rs_initialize_modules(__napiInstance) {
75+
__napiInstance.exports['__napi_register__Algorithm_0']?.()
76+
__napiInstance.exports['__napi_register__decode_header_1']?.()
77+
__napiInstance.exports['__napi_register__Header_struct_2']?.()
78+
__napiInstance.exports['__napi_register__SignTask_impl_3']?.()
79+
__napiInstance.exports['__napi_register__sign_4']?.()
80+
__napiInstance.exports['__napi_register__sign_sync_5']?.()
81+
__napiInstance.exports['__napi_register__Validation_struct_6']?.()
82+
__napiInstance.exports['__napi_register__VerifyTask_impl_7']?.()
83+
__napiInstance.exports['__napi_register__verify_8']?.()
84+
__napiInstance.exports['__napi_register__verify_sync_9']?.()
85+
}
86+
module.exports.Algorithm = __napiModule.exports.Algorithm
87+
module.exports.decodeHeader = __napiModule.exports.decodeHeader
88+
module.exports.sign = __napiModule.exports.sign
89+
module.exports.signSync = __napiModule.exports.signSync
90+
module.exports.verify = __napiModule.exports.verify
91+
module.exports.verifySync = __napiModule.exports.verifySync
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# `@node-rs/jsonwebtoken-wasm32-wasi`
2+
3+
This is the **wasm32-wasi-preview1-threads** binary for `@node-rs/jsonwebtoken`
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "@node-rs/jsonwebtoken-wasm32-wasi",
3+
"version": "0.4.0",
4+
"cpu": [
5+
"wasm32"
6+
],
7+
"main": "jsonwebtoken.wasi.cjs",
8+
"files": [
9+
"jsonwebtoken.wasm32-wasi.wasm",
10+
"jsonwebtoken.wasi.cjs",
11+
"jsonwebtoken.wasi-browser.js",
12+
"wasi-worker.mjs",
13+
"wasi-worker-browser.mjs"
14+
],
15+
"description": "Rust jsonwebtoken binding for Node.js",
16+
"keywords": [
17+
"jsonwebtoken",
18+
"jwt",
19+
"napi-rs",
20+
"node-rs"
21+
],
22+
"author": {
23+
"name": "Francesco Benedetto",
24+
"url": "https://github.com/nebarf",
25+
"email": "[email protected]"
26+
},
27+
"homepage": "https://github.com/napi-rs/node-rs#readme",
28+
"license": "MIT",
29+
"engines": {
30+
"node": ">=14.0.0"
31+
},
32+
"publishConfig": {
33+
"registry": "https://registry.npmjs.org/",
34+
"access": "public"
35+
},
36+
"repository": {
37+
"type": "git",
38+
"url": "git+https://github.com/napi-rs/node-rs.git"
39+
},
40+
"bugs": {
41+
"url": "https://github.com/napi-rs/node-rs/issues"
42+
},
43+
"browser": "jsonwebtoken.wasi-browser.js",
44+
"dependencies": {
45+
"@napi-rs/wasm-runtime": "^0.1.1"
46+
}
47+
}

packages/jsonwebtoken/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"x86_64-unknown-linux-musl",
3232
"x86_64-unknown-freebsd",
3333
"i686-pc-windows-msvc",
34-
"armv7-linux-androideabi"
34+
"armv7-linux-androideabi",
35+
"wasm32-wasi-preview1-threads"
3536
]
3637
},
3738
"repository": {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { instantiateNapiModuleSync, MessageHandler, WASI } from '@napi-rs/wasm-runtime'
2+
import { Volume, createFsFromVolume } from '@napi-rs/wasm-runtime/fs'
3+
4+
const fs = createFsFromVolume(
5+
Volume.fromJSON({
6+
'/': null,
7+
}),
8+
)
9+
10+
const handler = new MessageHandler({
11+
onLoad({ wasmModule, wasmMemory }) {
12+
const wasi = new WASI({
13+
fs,
14+
print: function () {
15+
// eslint-disable-next-line no-console
16+
console.log.apply(console, arguments)
17+
},
18+
printErr: function() {
19+
// eslint-disable-next-line no-console
20+
console.error.apply(console, arguments)
21+
},
22+
})
23+
return instantiateNapiModuleSync(wasmModule, {
24+
childThread: true,
25+
wasi,
26+
overwriteImports(importObject) {
27+
importObject.env = {
28+
...importObject.env,
29+
...importObject.napi,
30+
...importObject.emnapi,
31+
memory: wasmMemory,
32+
}
33+
},
34+
})
35+
},
36+
})
37+
38+
globalThis.onmessage = function (e) {
39+
handler.handle(e)
40+
}

packages/jsonwebtoken/wasi-worker.mjs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import fs from "node:fs";
2+
import { createRequire } from "node:module";
3+
import { parentPort, Worker } from "node:worker_threads";
4+
5+
import { instantiateNapiModuleSync, MessageHandler, WASI } from "@napi-rs/wasm-runtime";
6+
7+
const require = createRequire(import.meta.url);
8+
9+
if (parentPort) {
10+
parentPort.on("message", (data) => {
11+
globalThis.onmessage({ data });
12+
});
13+
}
14+
15+
Object.assign(globalThis, {
16+
self: globalThis,
17+
require,
18+
Worker,
19+
importScripts: function (f) {
20+
;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f);
21+
},
22+
postMessage: function (msg) {
23+
if (parentPort) {
24+
parentPort.postMessage(msg);
25+
}
26+
},
27+
});
28+
29+
const handler = new MessageHandler({
30+
onLoad({ wasmModule, wasmMemory }) {
31+
const wasi = new WASI({ fs });
32+
33+
return instantiateNapiModuleSync(wasmModule, {
34+
childThread: true,
35+
wasi,
36+
overwriteImports(importObject) {
37+
importObject.env = {
38+
...importObject.env,
39+
...importObject.napi,
40+
...importObject.emnapi,
41+
memory: wasmMemory
42+
};
43+
},
44+
});
45+
},
46+
});
47+
48+
globalThis.onmessage = function (e) {
49+
handler.handle(e);
50+
};

0 commit comments

Comments
 (0)