feat: integrate with emnapi (#1669)

* Integrate with emnapi

* resolve conflict

* ignore wasm

* generate wasi file

* Add wasi test to workflow

* Fix wasi template

* emnapi new initialize api

* Finish test

* Purne tsconfig

* Generate wasi worker

* Fix electron test

* Finalize check

* Noop adjust_external_memory

* Apply cr suggestions
This commit is contained in:
LongYinan 2023-11-02 12:57:11 +08:00 committed by GitHub
parent 69c0223b9b
commit 13d0ce075e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 1387 additions and 313 deletions

2
.cargo/config.toml Normal file
View file

@ -0,0 +1,2 @@
[target.'cfg(target_os = "wasi")']
rustflags = ["-C", "target-feature=+atomics,+bulk-memory"]

View file

@ -14,4 +14,6 @@ target
scripts scripts
triples/index.js triples/index.js
rollup.config.js rollup.config.js
crates/cli/index.js crates/cli/index.js
examples/napi/index.wasi.mjs
examples/napi/wasi-worker.mjs

View file

@ -5,7 +5,8 @@ parserOptions:
jsx: true jsx: true
ecmaVersion: latest ecmaVersion: latest
sourceType: module sourceType: module
extraFileExtensions: ['.cjs', '.mjs'] project:
- ./tsconfig.root-lint.json
env: env:
browser: true browser: true
@ -23,6 +24,7 @@ extends:
globals: globals:
BigInt: 'readonly' BigInt: 'readonly'
NodeJS: 'readonly' NodeJS: 'readonly'
globalThis: true
rules: rules:
# 0 = off, 1 = warn, 2 = error # 0 = off, 1 = warn, 2 = error
@ -205,6 +207,15 @@ overrides:
project: project:
- ./examples/tsconfig.json - ./examples/tsconfig.json
rules: rules:
'import/order':
[
2,
{
'newlines-between': 'always',
'alphabetize': { 'order': 'asc', 'caseInsensitive': true },
},
]
'import/no-extraneous-dependencies': 0 'import/no-extraneous-dependencies': 0
- files: - files:
@ -223,6 +234,8 @@ overrides:
- files: - files:
- ./*.js - ./*.js
- ./*.cjs
- ./*.mjs
plugins: plugins:
- '@typescript-eslint' - '@typescript-eslint'
parserOptions: parserOptions:

View file

@ -63,7 +63,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node: ['16', '18', '20'] node: ['18', '20']
settings: settings:
- host: ubuntu-latest - host: ubuntu-latest
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@ -71,7 +71,7 @@ jobs:
test: | test: |
yarn test:cli yarn test:cli
yarn test --verbose yarn test --verbose
yarn tsc -p examples/napi/tsconfig.json --noEmit yarn tsc -p examples/napi/tsconfig.json --noEmit --skipLibCheck
yarn test:macro yarn test:macro
toolchain: stable toolchain: stable
- host: ubuntu-latest - host: ubuntu-latest
@ -80,7 +80,7 @@ jobs:
test: | test: |
yarn test:cli yarn test:cli
yarn test --verbose yarn test --verbose
yarn tsc -p examples/napi/tsconfig.json --noEmit yarn tsc -p examples/napi/tsconfig.json --noEmit --skipLibCheck
yarn test:macro yarn test:macro
toolchain: 1.65.0 toolchain: 1.65.0
- host: macos-latest - host: macos-latest
@ -89,7 +89,7 @@ jobs:
test: | test: |
yarn test:cli yarn test:cli
yarn test --verbose yarn test --verbose
yarn tsc -p examples/napi/tsconfig.json --noEmit yarn tsc -p examples/napi/tsconfig.json --noEmit --skipLibCheck
yarn test:macro yarn test:macro
toolchain: stable toolchain: stable
- host: windows-latest - host: windows-latest
@ -98,7 +98,7 @@ jobs:
test: | test: |
yarn test:cli yarn test:cli
yarn test --verbose yarn test --verbose
yarn tsc -p examples/napi/tsconfig.json --noEmit yarn tsc -p examples/napi/tsconfig.json --noEmit --skipLibCheck
yarn test:macro yarn test:macro
toolchain: stable toolchain: stable
- host: windows-latest - host: windows-latest
@ -118,9 +118,6 @@ jobs:
- settings: - settings:
toolchain: 1.65.0 toolchain: 1.65.0
node: 20 node: 20
- settings:
target: i686-pc-windows-msvc
node: 16
- settings: - settings:
target: i686-pc-windows-msvc target: i686-pc-windows-msvc
node: 18 node: 18
@ -311,7 +308,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node: [16, 18, 20] node: [18, 20]
settings: settings:
- image: 'node:{:version}-slim' - image: 'node:{:version}-slim'
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@ -486,6 +483,42 @@ jobs:
- name: Check build - name: Check build
run: cargo check -p ${{ matrix.settings.package }} -F ${{ matrix.settings.features }} run: cargo check -p ${{ matrix.settings.package }} -F ${{ matrix.settings.features }}
test-node-wasi:
runs-on: ubuntu-latest
name: Test node wasi target
timeout-minutes: 10
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'yarn'
- name: Install
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: wasm32-wasi-preview1-threads
- name: Cache cargo
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: stable-wasm32-wasi-preview1-threads-node@18-cargo-cache
- name: Install dependencies
run: yarn install --immutable --mode=skip-build
- name: Build
run: |
yarn build
yarn workspace @examples/napi build --target wasm32-wasi-preview1-threads
- name: Test
run: yarn workspace @examples/napi test -s
env:
WASI_TEST: 'true'
test-latest-bun: test-latest-bun:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Test latest bun name: Test latest bun

View file

@ -53,7 +53,7 @@ jobs:
- name: Install ziglang - name: Install ziglang
uses: goto-bus-stop/setup-zig@v2 uses: goto-bus-stop/setup-zig@v2
with: with:
version: 0.10.1 version: 0.11.0
- name: Install dependencies - name: Install dependencies
run: yarn install --immutable --mode=skip-build run: yarn install --immutable --mode=skip-build
- name: install MacOS SDK - name: install MacOS SDK

View file

@ -68,24 +68,48 @@
}, },
"dependencies": { "dependencies": {
"@octokit/rest": "^20.0.1", "@octokit/rest": "^20.0.1",
"@tybys/wasm-util": "0.8.0",
"clipanion": "^3.2.1", "clipanion": "^3.2.1",
"colorette": "^2.0.20", "colorette": "^2.0.20",
"debug": "^4.3.4", "debug": "^4.3.4",
"emnapi": "0.43.1",
"inquirer": "^9.2.8", "inquirer": "^9.2.8",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"toml": "^3.0.0",
"typanion": "^3.13.0" "typanion": "^3.13.0"
}, },
"devDependencies": { "devDependencies": {
"@emnapi/core": "0.43.1",
"@emnapi/runtime": "0.43.1",
"@types/debug": "^4.1.7",
"@types/inquirer": "^9.0.3", "@types/inquirer": "^9.0.3",
"@types/js-yaml": "^4.0.5", "@types/js-yaml": "^4.0.5",
"@types/lodash-es": "^4.17.8", "@types/lodash-es": "^4.17.8",
"ava": "^5.3.1", "ava": "^5.3.1",
"esbuild": "^0.19.0", "env-paths": "^3.0.0",
"esbuild": "^0.19.5",
"prettier": "^3.0.0", "prettier": "^3.0.0",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"tslib": "^2.6.1",
"typescript": "^5.1.6" "typescript": "^5.1.6"
}, },
"peerDependencies": {
"@emnapi/runtime": "0.43.1",
"@tybys/wasm-util": "0.8.0",
"emnapi": "0.43.1"
},
"peerDependenciesMeta": {
"@emnapi/runtime": {
"optional": true
},
"@tybys/wasm-util": {
"optional": true
},
"emnapi": {
"optional": true
}
},
"funding": { "funding": {
"type": "github", "type": "github",
"url": "https://github.com/sponsors/Brooooooklyn" "url": "https://github.com/sponsors/Brooooooklyn"

View file

@ -1,4 +1,4 @@
import { join, parse, resolve } from 'path' import { join, parse, resolve } from 'node:path'
import * as colors from 'colorette' import * as colors from 'colorette'

View file

@ -1,7 +1,8 @@
import { spawn } from 'child_process' import { spawn } from 'node:child_process'
import { createHash } from 'crypto' import { createHash } from 'node:crypto'
import { tmpdir } from 'os' import { createRequire } from 'node:module'
import { parse, join, resolve } from 'path' import { tmpdir } from 'node:os'
import { parse, join, resolve } from 'node:path'
import * as colors from 'colorette' import * as colors from 'colorette'
@ -20,6 +21,7 @@ import {
parseMetadata, parseMetadata,
parseTriple, parseTriple,
processTypeDef, processTypeDef,
readFileAsync,
readNapiConfig, readNapiConfig,
Target, Target,
targetToEnvVar, targetToEnvVar,
@ -28,11 +30,14 @@ import {
writeFileAsync, writeFileAsync,
} from '../utils/index.js' } from '../utils/index.js'
import { createWasiBinding } from './load-wasi-template.js'
import { createCjsBinding } from './templates/index.js' import { createCjsBinding } from './templates/index.js'
import { WASI_WORKER_TEMPLATE } from './wasi-worker-template.js'
const debug = debugFactory('build') const debug = debugFactory('build')
const require = createRequire(import.meta.url)
type OutputKind = 'js' | 'dts' | 'node' | 'exe' type OutputKind = 'js' | 'dts' | 'node' | 'exe' | 'wasm'
type Output = { type Output = {
kind: OutputKind kind: OutputKind
path: string path: string
@ -383,6 +388,16 @@ class Builder {
} }
// END LINKER // END LINKER
if (this.target.platform === 'wasi') {
const emnapi = join(
require.resolve('emnapi'),
'..',
'lib',
'wasm32-wasi-threads',
)
this.envs.EMNAPI_LINK_DIR = emnapi
}
debug('Set envs: ') debug('Set envs: ')
Object.entries(this.envs).forEach(([k, v]) => { Object.entries(this.envs).forEach(([k, v]) => {
debug(' %i', `${k}=${v}`) debug(' %i', `${k}=${v}`)
@ -471,7 +486,34 @@ class Builder {
// only for cdylib // only for cdylib
if (this.cdyLibName) { if (this.cdyLibName) {
const idents = await this.generateTypeDef() const idents = await this.generateTypeDef()
await this.writeJsBinding(idents) const intermediateWasiRegisterFile = this.envs.WASI_REGISTER_TMP_PATH
const wasiRegisterFunctions =
this.target.arch === 'wasm32'
? JSON.parse(
await readFileAsync(intermediateWasiRegisterFile, 'utf8').catch(
(err) => {
console.warn(
`Read ${colors.yellowBright(
intermediateWasiRegisterFile,
)} failed, reason: ${err.message}`,
)
return `[]`
},
),
)
: []
const jsOutput = await this.writeJsBinding(idents)
const wasmOutput = await this.writeWasiBinding(
wasiRegisterFunctions,
jsOutput?.path ?? 'index',
idents,
)
if (jsOutput) {
this.outputs.push(jsOutput)
}
if (wasmOutput) {
this.outputs.push(wasmOutput)
}
} }
return this.outputs return this.outputs
@ -517,6 +559,8 @@ class Builder {
? `lib${cdyLib}.dylib` ? `lib${cdyLib}.dylib`
: this.target.platform === 'win32' : this.target.platform === 'win32'
? `${cdyLib}.dll` ? `${cdyLib}.dll`
: this.target.platform === 'wasi' || this.target.platform === 'wasm'
? `${cdyLib}.wasm`
: `lib${cdyLib}.so` : `lib${cdyLib}.so`
let destName = this.config.binaryName let destName = this.config.binaryName
@ -526,7 +570,11 @@ class Builder {
if (this.options.platform) { if (this.options.platform) {
destName += `.${this.target.platformArchABI}` destName += `.${this.target.platformArchABI}`
} }
destName += '.node' if (srcName.endsWith('.wasm')) {
destName += '.wasi-wasm32.wasm'
} else {
destName += '.node'
}
return [srcName, destName] return [srcName, destName]
} else if (this.binName) { } else if (this.binName) {
@ -592,12 +640,42 @@ class Builder {
debug('Writing js binding to:') debug('Writing js binding to:')
debug(' %i', dest) debug(' %i', dest)
await writeFileAsync(dest, cjs, 'utf-8') await writeFileAsync(dest, cjs, 'utf-8')
this.outputs.push({ return {
kind: 'js', kind: 'js',
path: dest, path: dest,
}) } satisfies Output
} catch (e) { } catch (e) {
throw new Error('Failed to write js binding file', { cause: e }) throw new Error('Failed to write js binding file', { cause: e })
} }
} }
private async writeWasiBinding(
wasiRegisterFunctions: string[],
distFileName: string | undefined,
idents: string[],
) {
if (distFileName && wasiRegisterFunctions.length) {
const { name, dir } = parse(distFileName)
const newPath = join(dir, `${name}.wasi.mjs`)
const workerPath = join(dir, 'wasi-worker.mjs')
const declareCodes = `const { ${idents.join(', ')} } = binding\n`
const exportsCode = `export {\n${idents
.map((ident) => ` ${ident}`)
.join(',\n')}\n}`
await writeFileAsync(
newPath,
createWasiBinding(this.config.binaryName, wasiRegisterFunctions) +
declareCodes +
exportsCode +
'\n',
'utf8',
)
await writeFileAsync(workerPath, WASI_WORKER_TEMPLATE, 'utf8')
return {
kind: 'wasm',
path: newPath,
} satisfies Output
}
return null
}
} }

View file

@ -0,0 +1,65 @@
export const createWasiBinding = (
localName: string,
wasiRegisterFunctions: string[],
) => `/* eslint-disable */
/* prettier-ignore */
/* auto-generated by NAPI-RS */
import * as __nodeFsPromises from 'node:fs/promises'
import * as __nodePath from 'node:path'
import { WASI as __nodeWASI } from 'node:wasi'
import { Worker } from 'node:worker_threads'
import * as __nodeURL from 'node:url'
import { instantiateNapiModule as __emnapiInstantiateNapiModule } from '@emnapi/core'
import { getDefaultContext as __emnapiGetDefaultContext } from '@emnapi/runtime'
const __wasi = new __nodeWASI({
env: process.env,
preopens: {
'/': __nodePath.join(__nodeURL.fileURLToPath(import.meta.url), '..'),
}
})
const __dirname = __nodePath.join(__nodeURL.fileURLToPath(import.meta.url), '..')
const __emnapiContext = __emnapiGetDefaultContext()
const __sharedMemory = new WebAssembly.Memory({
initial: 1024,
maximum: 10240,
shared: true,
})
const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = await __emnapiInstantiateNapiModule(__nodeFsPromises.readFile(__nodePath.join(__dirname, '${localName}.wasi-wasm32.wasm')), {
context: __emnapiContext,
asyncWorkPoolSize: 4,
wasi: __wasi,
onCreateWorker() {
return new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), {
env: process.env,
execArgv: ['--experimental-wasi-unstable-preview1'],
})
},
overwriteImports(importObject) {
importObject.env = {
...importObject.env,
...importObject.napi,
...importObject.emnapi,
memory: __sharedMemory,
}
},
beforeInit({ instance }) {
__napi_rs_initialize_modules(instance)
}
})
function __napi_rs_initialize_modules(__napiInstance) {
${wasiRegisterFunctions
.map((name) => ` __napiInstance.exports['${name}']()`)
.join('\n')}
}
const binding = __napiModule.exports
`

View file

@ -157,10 +157,7 @@ function generateGithubWorkflow(options: NewOptions): Output | null {
return { return {
target: './.github/workflows/ci.yml', target: './.github/workflows/ci.yml',
content: createGithubActionsCIYml( content: createGithubActionsCIYml(options.targets),
getBinaryName(options.name),
options.targets,
),
} }
} }

View file

@ -195,4 +195,5 @@ Cargo.lock
!.yarn/versions !.yarn/versions
*.node *.node
*.wasm
` `

View file

@ -17,10 +17,7 @@ const TEST_LINUX_AARCH64_MUSL = 'test-linux-aarch64-musl-binding'
const TEST_LINUX_ARM_GNUEABIHF = 'test-linux-arm-gnueabihf-binding' const TEST_LINUX_ARM_GNUEABIHF = 'test-linux-arm-gnueabihf-binding'
const UNIVERSAL_MACOS = 'universal-macOS' const UNIVERSAL_MACOS = 'universal-macOS'
export const createGithubActionsCIYml = ( export const createGithubActionsCIYml = (targets: string[]) => {
binaryName: string,
targets: string[],
) => {
const allTargets = new Set( const allTargets = new Set(
targets.flatMap((t) => { targets.flatMap((t) => {
const platform = parseTriple(t) const platform = parseTriple(t)

View file

@ -0,0 +1,52 @@
export const WASI_WORKER_TEMPLATE = `import fs from "node:fs";
import { createRequire } from "node:module";
import { parentPort, Worker } from "node:worker_threads";
import { instantiateNapiModuleSync, MessageHandler } from "@emnapi/core";
import { WASI } from "@tybys/wasm-util";
const require = createRequire(import.meta.url);
if (parentPort) {
parentPort.on("message", (data) => {
globalThis.onmessage({ data });
});
}
Object.assign(globalThis, {
self: globalThis,
require,
Worker,
importScripts: function (f) {
;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f);
},
postMessage: function (msg) {
if (parentPort) {
parentPort.postMessage(msg);
}
},
});
const handler = new MessageHandler({
onLoad({ wasmModule, wasmMemory }) {
const wasi = new WASI({ fs });
return instantiateNapiModuleSync(wasmModule, {
childThread: true,
wasi,
overwriteImports(importObject) {
importObject.env = {
...importObject.env,
...importObject.napi,
...importObject.emnapi,
memory: wasmMemory
};
},
});
},
});
globalThis.onmessage = function (e) {
handler.handle(e);
};
`

View file

@ -1,5 +1,7 @@
import { execSync } from 'child_process' import { execSync } from 'child_process'
export type Platform = NodeJS.Platform | 'wasm' | 'wasi'
export const AVAILABLE_TARGETS = [ export const AVAILABLE_TARGETS = [
'aarch64-apple-darwin', 'aarch64-apple-darwin',
'aarch64-linux-android', 'aarch64-linux-android',
@ -63,24 +65,22 @@ export const NodeArchToCpu: Record<string, string> = {
riscv64: 'riscv64gc', riscv64: 'riscv64gc',
} }
const SysToNodePlatform: Record<string, NodeJS.Platform> = { const SysToNodePlatform: Record<string, Platform> = {
linux: 'linux', linux: 'linux',
freebsd: 'freebsd', freebsd: 'freebsd',
darwin: 'darwin', darwin: 'darwin',
windows: 'win32', windows: 'win32',
} }
export const UniArchsByPlatform: Partial< export const UniArchsByPlatform: Partial<Record<Platform, NodeJSArch[]>> = {
Record<NodeJS.Platform, NodeJSArch[]>
> = {
darwin: ['x64', 'arm64'], darwin: ['x64', 'arm64'],
} }
export interface Target { export interface Target {
triple: string triple: string
platformArchABI: string platformArchABI: string
platform: NodeJS.Platform platform: Platform
arch: NodeJSArch arch: NodeJSArch | 'wasm32'
abi: string | null abi: string | null
} }
@ -95,6 +95,15 @@ export interface Target {
* - `abi` = The ABI, for example `gnu`, `android`, `eabi`, etc. * - `abi` = The ABI, for example `gnu`, `android`, `eabi`, etc.
*/ */
export function parseTriple(rawTriple: string): Target { export function parseTriple(rawTriple: string): Target {
if (rawTriple === 'wasm32-wasi-preview1-threads') {
return {
triple: rawTriple,
platformArchABI: rawTriple,
platform: 'wasi',
arch: 'wasm32',
abi: 'wasi',
}
}
const triple = rawTriple.endsWith('eabi') const triple = rawTriple.endsWith('eabi')
? `${rawTriple.slice(0, -4)}-eabi` ? `${rawTriple.slice(0, -4)}-eabi`
: rawTriple : rawTriple
@ -114,7 +123,7 @@ export function parseTriple(rawTriple: string): Target {
;[cpu, , sys, abi = null] = triples ;[cpu, , sys, abi = null] = triples
} }
const platform = SysToNodePlatform[sys] ?? (sys as NodeJS.Platform) const platform = SysToNodePlatform[sys] ?? (sys as Platform)
const arch = CpuToNodeArch[cpu] ?? (cpu as NodeJSArch) const arch = CpuToNodeArch[cpu] ?? (cpu as NodeJSArch)
return { return {
triple: rawTriple, triple: rawTriple,

View file

@ -1,4 +1,5 @@
{ {
"extends": "../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"strict": true, "strict": true,
"target": "ES2022", "target": "ES2022",

View file

@ -1,5 +1,6 @@
mod android; mod android;
mod macos; mod macos;
mod wasi;
pub fn setup() { pub fn setup() {
println!("cargo:rerun-if-env-changed=DEBUG_GENERATED_CODE"); println!("cargo:rerun-if-env-changed=DEBUG_GENERATED_CODE");
@ -9,6 +10,9 @@ pub fn setup() {
macos::setup(); macos::setup();
} }
Ok("android") => if android::setup().is_ok() {}, Ok("android") => if android::setup().is_ok() {},
Ok("wasi") => {
wasi::setup();
}
_ => {} _ => {}
} }
} }

22
crates/build/src/wasi.rs Normal file
View file

@ -0,0 +1,22 @@
use std::env;
pub fn setup() {
let link_dir = env::var("EMNAPI_LINK_DIR").expect("EMNAPI_LINK_DIR must be set");
println!("cargo:rerun-if-env-changed=EMNAPI_LINK_DIR");
println!("cargo:rerun-if-env-changed=WASI_REGISTER_TMP_PATH");
println!("cargo:rustc-link-search={}", link_dir);
println!("cargo:rustc-link-lib=static=emnapi-basic-mt");
println!("cargo:rustc-link-arg=--export-dynamic");
println!("cargo:rustc-link-arg=--export=malloc");
println!("cargo:rustc-link-arg=--export=free");
println!("cargo:rustc-link-arg=--export=napi_register_wasm_v1");
println!("cargo:rustc-link-arg=--export-if-defined=node_api_module_get_api_version_v1");
println!("cargo:rustc-link-arg=--export-table");
println!("cargo:rustc-link-arg=--export=emnapi_async_worker_create");
println!("cargo:rustc-link-arg=--export=emnapi_async_worker_init");
println!("cargo:rustc-link-arg=--import-memory");
println!("cargo:rustc-link-arg=--import-undefined");
println!("cargo:rustc-link-arg=--shared-memory");
println!("cargo:rustc-link-arg=--max-memory=2147483648");
println!("cargo:rustc-link-arg=--no-check-features");
}

View file

@ -75,11 +75,11 @@ version = "0.8"
optional = true optional = true
version = "0.4" version = "0.4"
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_os = "wasi")'.dependencies]
tokio = { version = "1", optional = true, features = ["rt", "sync"] } tokio = { version = "1", optional = true, features = ["rt", "sync"] }
napi-derive = { path = "../macro", version = "2.10.1", default-features = false } napi-derive = { path = "../macro", version = "2.10.1", default-features = false }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_os = "wasi"))'.dependencies]
tokio = { version = "1", optional = true, features = [ tokio = { version = "1", optional = true, features = [
"rt", "rt",
"rt-multi-thread", "rt-multi-thread",

View file

@ -7,13 +7,24 @@ use std::sync::{
Arc, Arc,
}; };
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))] #[cfg(all(feature = "napi4", not(target_os = "wasi")))]
use crate::bindgen_prelude::{CUSTOM_GC_TSFN, THREADS_CAN_ACCESS_ENV, THREAD_DESTROYED}; use crate::bindgen_prelude::{CUSTOM_GC_TSFN, THREADS_CAN_ACCESS_ENV, THREAD_DESTROYED};
pub use crate::js_values::TypedArrayType; pub use crate::js_values::TypedArrayType;
use crate::{check_status, sys, Error, Result, Status}; use crate::{check_status, sys, Error, Result, Status};
use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue}; use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue};
#[cfg(target_os = "wasi")]
extern "C" {
fn emnapi_sync_memory(
env: crate::sys::napi_env,
js_to_wasm: bool,
arraybuffer_or_view: crate::sys::napi_value,
byte_offset: usize,
length: usize,
) -> crate::sys::napi_status;
}
trait Finalizer { trait Finalizer {
type RustType; type RustType;
@ -122,6 +133,49 @@ macro_rules! impl_typed_array {
impl $name { impl $name {
fn noop_finalize(_data: *mut $rust_type, _length: usize) {} fn noop_finalize(_data: *mut $rust_type, _length: usize) {}
#[cfg(target_os = "wasi")]
pub fn sync(&mut self, env: &crate::Env) {
if let Some((reference, _)) = self.raw {
let mut value = ptr::null_mut();
let mut array_buffer = ptr::null_mut();
crate::check_status_or_throw!(
env.raw(),
unsafe { crate::sys::napi_get_reference_value(env.raw(), reference, &mut value) },
"Failed to get reference value from TypedArray while syncing"
);
crate::check_status_or_throw!(
env.raw(),
unsafe {
crate::sys::napi_get_typedarray_info(
env.raw(),
value,
&mut ($typed_array_type as i32) as *mut i32,
&mut self.length as *mut usize,
ptr::null_mut(),
&mut array_buffer,
&mut self.byte_offset as *mut usize,
)
},
"Failed to get ArrayBuffer under the TypedArray while syncing"
);
crate::check_status_or_throw!(
env.raw(),
unsafe {
emnapi_sync_memory(
env.raw(),
false,
array_buffer,
self.byte_offset,
self.length,
)
},
"Failed to sync memory"
);
} else {
return;
}
}
pub fn new(mut data: Vec<$rust_type>) -> Self { pub fn new(mut data: Vec<$rust_type>) -> Self {
data.shrink_to_fit(); data.shrink_to_fit();
let ret = $name { let ret = $name {

View file

@ -34,17 +34,18 @@ pub unsafe extern "C" fn raw_finalize_unchecked<T: ObjectFinalize>(
finalize_data: *mut c_void, finalize_data: *mut c_void,
_finalize_hint: *mut c_void, _finalize_hint: *mut c_void,
) { ) {
let data = *unsafe { Box::from_raw(finalize_data as *mut T) }; let data: Box<T> = unsafe { Box::from_raw(finalize_data.cast()) };
if let Err(err) = data.finalize(unsafe { Env::from_raw(env) }) { if let Err(err) = data.finalize(unsafe { Env::from_raw(env) }) {
let e: JsError = err.into(); let e: JsError = err.into();
unsafe { e.throw_into(env) }; unsafe { e.throw_into(env) };
return;
} }
if let Some((_, ref_val, finalize_callbacks_ptr)) = if let Some((_, ref_val, finalize_callbacks_ptr)) =
REFERENCE_MAP.with(|reference_map| reference_map.borrow_mut().remove(&finalize_data)) REFERENCE_MAP.with(|reference_map| reference_map.borrow_mut().remove(&finalize_data))
{ {
let finalize_callbacks_rc = unsafe { Rc::from_raw(finalize_callbacks_ptr) }; let finalize_callbacks_rc = unsafe { Rc::from_raw(finalize_callbacks_ptr) };
#[cfg(debug_assertions)] #[cfg(all(debug_assertions, not(target_os = "wasi")))]
{ {
let rc_strong_count = Rc::strong_count(&finalize_callbacks_rc); let rc_strong_count = Rc::strong_count(&finalize_callbacks_rc);
// If `Rc` strong count is 2, it means the finalize of referenced `Object` is called before the `fn drop` of the `Reference` // If `Rc` strong count is 2, it means the finalize of referenced `Object` is called before the `fn drop` of the `Reference`

View file

@ -374,6 +374,7 @@ impl Env {
)) ))
} }
#[cfg(not(target_os = "wasi"))]
/// This function gives V8 an indication of the amount of externally allocated memory that is kept alive by JavaScript objects (i.e. a JavaScript object that points to its own memory allocated by a native module). /// This function gives V8 an indication of the amount of externally allocated memory that is kept alive by JavaScript objects (i.e. a JavaScript object that points to its own memory allocated by a native module).
/// ///
/// Registering externally allocated memory will trigger global garbage collections more often than it would otherwise. /// Registering externally allocated memory will trigger global garbage collections more often than it would otherwise.
@ -385,6 +386,12 @@ impl Env {
Ok(changed) Ok(changed)
} }
#[cfg(target_os = "wasi")]
#[allow(unused_variables)]
pub fn adjust_external_memory(&mut self, size: i64) -> Result<i64> {
Ok(0)
}
/// This API allocates a node::Buffer object and initializes it with data copied from the passed-in buffer. /// This API allocates a node::Buffer object and initializes it with data copied from the passed-in buffer.
/// ///
/// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice. /// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.

View file

@ -3,7 +3,9 @@ use std::marker::PhantomData;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::ptr; use std::ptr;
use crate::bindgen_runtime::{ToNapiValue, THREAD_DESTROYED}; #[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
use crate::bindgen_prelude::THREAD_DESTROYED;
use crate::bindgen_runtime::ToNapiValue;
use crate::{check_status, JsObject, Value}; use crate::{check_status, JsObject, Value};
use crate::{sys, Env, Error, Result}; use crate::{sys, Env, Error, Result};
#[cfg(feature = "deferred_trace")] #[cfg(feature = "deferred_trace")]

View file

@ -6,13 +6,13 @@ use tokio::runtime::Runtime;
use crate::{sys, JsDeferred, JsUnknown, NapiValue, Result}; use crate::{sys, JsDeferred, JsUnknown, NapiValue, Result};
fn create_runtime() -> Option<Runtime> { fn create_runtime() -> Option<Runtime> {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_os = "wasi"))]
{ {
let runtime = tokio::runtime::Runtime::new().expect("Create tokio runtime failed"); let runtime = tokio::runtime::Runtime::new().expect("Create tokio runtime failed");
Some(runtime) Some(runtime)
} }
#[cfg(target_arch = "wasm32")] #[cfg(target_os = "wasi")]
{ {
tokio::runtime::Builder::new_current_thread() tokio::runtime::Builder::new_current_thread()
.enable_all() .enable_all()

View file

@ -10,9 +10,7 @@ crate-type = ["cdylib", "lib"]
[dependencies] [dependencies]
napi = { path = "../../crates/napi", default-features = false, features = [ napi = { path = "../../crates/napi", default-features = false, features = [
"tokio_fs",
"napi8", "napi8",
"tokio_rt",
"serde-json", "serde-json",
"async", "async",
"experimental", "experimental",

View file

@ -1,2 +1,3 @@
*.node *.node
wip/ wip/
*.wasm

View file

@ -14,23 +14,43 @@ snmalloc = ["snmalloc-rs"]
[dependencies] [dependencies]
chrono = "0.4" chrono = "0.4"
futures = "0.3" futures = "0.3"
napi = { path = "../../crates/napi", default-features = false, features = [
"tokio_fs",
"napi9",
"tokio_rt",
"serde-json",
"async",
"experimental",
"latin1",
"chrono_date",
"deferred_trace",
] }
napi-derive = { path = "../../crates/macro", features = ["type-def"] } napi-derive = { path = "../../crates/macro", features = ["type-def"] }
napi-shared = { path = "../napi-shared" } napi-shared = { path = "../napi-shared" }
serde = "1" serde = "1"
serde_derive = "1" serde_derive = "1"
serde_json = "1" serde_json = "1"
tokio = { version = "1.20.0", features = ["full"] }
[target.'cfg(not(target_os = "wasi"))'.dependencies]
napi = { path = "../../crates/napi", default-features = false, features = [
"napi9",
"serde-json",
"experimental",
"latin1",
"chrono_date",
"tokio",
"async",
"tokio_rt",
"tokio_fs",
"tokio_macros",
"deferred_trace",
] }
tokio = { version = "1", features = ["rt", "time"] }
[target.'cfg(target_os = "wasi")'.dependencies]
napi = { path = "../../crates/napi", default-features = false, features = [
"napi9",
"serde-json",
"experimental",
"latin1",
"chrono_date",
"tokio",
"async",
"tokio_rt",
"tokio_macros",
"tokio_sync",
"deferred_trace",
] }
tokio = { version = "1", default-features = false, features = ["rt", "time"] }
[dependencies.snmalloc-rs] [dependencies.snmalloc-rs]
version = "0.3" version = "0.3"

View file

@ -1,10 +1,6 @@
import { createRequire } from 'node:module'
import test from 'ava' import test from 'ava'
const require = createRequire(import.meta.url) const { receiveString } = (await import('../index.js')).default
const { receiveString }: typeof import('../index.js') = require('../index.node')
test('Function message', (t) => { test('Function message', (t) => {
// @ts-expect-error // @ts-expect-error

View file

@ -1,14 +1,8 @@
import { createRequire } from 'node:module' import ava from 'ava'
import test from 'ava' const { Fib, Fib2, Fib3 } = (await import('../index.js')).default
const require = createRequire(import.meta.url) const test = process.env.WASI_TEST ? ava.skip : ava
const {
Fib,
Fib2,
Fib3,
}: typeof import('../index.js') = require('../index.node')
for (const [index, factory] of [ for (const [index, factory] of [
() => new Fib(), () => new Fib(),

View file

@ -1,12 +1,8 @@
import { createRequire } from 'node:module' import ava from 'ava'
import test from 'ava' const { NotWritableClass } = (await import('../index.js')).default
const require = createRequire(import.meta.url) const test = process.env.WASI_TEST ? ava.skip : ava
const {
NotWritableClass,
}: typeof import('../index.js') = require('../index.node')
test('Not Writable Class', (t) => { test('Not Writable Class', (t) => {
const obj = new NotWritableClass('1') const obj = new NotWritableClass('1')

View file

@ -1,9 +1,5 @@
import { createRequire } from 'node:module'
import test from 'ava' import test from 'ava'
const require = createRequire(import.meta.url)
const { const {
validateArray, validateArray,
validateTypedArray, validateTypedArray,
@ -24,7 +20,7 @@ const {
returnUndefinedIfInvalid, returnUndefinedIfInvalid,
returnUndefinedIfInvalidPromise, returnUndefinedIfInvalidPromise,
validateOptional, validateOptional,
}: typeof import('../index.d.ts') = require('../index.node') } = (await import('../index.js')).default
test('should validate array', (t) => { test('should validate array', (t) => {
t.is(validateArray([1, 2, 3]), 3) t.is(validateArray([1, 2, 3]), 3)
@ -127,8 +123,21 @@ test('should validate Map', (t) => {
}) })
}) })
test('should validate promise', async (t) => { test.only('should validate promise', async (t) => {
t.is(await validatePromise(Promise.resolve(1)), 2) if (process.env.WASI_TEST) {
t.pass()
return
}
t.is(
await validatePromise(
new Promise((resolve) => {
setTimeout(() => {
resolve(1)
}, 100)
}),
),
2,
)
// @ts-expect-error // @ts-expect-error
await t.throwsAsync(() => validatePromise(1), { await t.throwsAsync(() => validatePromise(1), {
code: 'InvalidArg', code: 'InvalidArg',

View file

@ -1,3 +1,3 @@
const { threadsafeFunctionFatalModeError } = require('../index.node') import('../index.js').then(({ default: { threadsafeFunctionFatalModeError } }) => {
return threadsafeFunctionFatalModeError(() => {})
threadsafeFunctionFatalModeError(() => {}) })

View file

@ -7,5 +7,9 @@ import test from 'ava'
const __dirname = join(fileURLToPath(import.meta.url), '..') const __dirname = join(fileURLToPath(import.meta.url), '..')
test('should generate correct type def file', (t) => { test('should generate correct type def file', (t) => {
t.snapshot(readFileSync(join(__dirname, '..', 'index.d.ts'), 'utf8')) if (process.env.WASI_TEST) {
t.pass()
} else {
t.snapshot(readFileSync(join(__dirname, '..', 'index.d.ts'), 'utf8'))
}
}) })

View file

@ -1,5 +1,4 @@
import { exec } from 'node:child_process' import { exec } from 'node:child_process'
import { createRequire } from 'node:module'
import { join } from 'node:path' import { join } from 'node:path'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
@ -9,7 +8,6 @@ import type { AliasedStruct } from '../index.js'
import { test } from './test.framework.js' import { test } from './test.framework.js'
const require = createRequire(import.meta.url)
const __dirname = join(fileURLToPath(import.meta.url), '..') const __dirname = join(fileURLToPath(import.meta.url), '..')
const { const {
@ -141,7 +139,10 @@ const {
chronoNativeDateTime, chronoNativeDateTime,
chronoNativeDateTimeReturn, chronoNativeDateTimeReturn,
throwAsyncError, throwAsyncError,
}: typeof import('../index.d.ts') = require('../index.node') } = (await import('../index.js')).default
const Napi4Test = Number(process.versions.napi) >= 4 ? test : test.skip
const isWasiTest = !!process.env.WASI_TEST
test('export const', (t) => { test('export const', (t) => {
t.is(DEFAULT_COST, 12) t.is(DEFAULT_COST, 12)
@ -310,7 +311,7 @@ test('should be able to into_reference', (t) => {
test('callback', (t) => { test('callback', (t) => {
getCwd((cwd) => { getCwd((cwd) => {
t.is(cwd, process.cwd()) t.is(cwd, process.env.WASI_TEST ? '/' : process.cwd())
}) })
t.throws( t.throws(
@ -345,7 +346,11 @@ test('return function', (t) => {
}) })
}) })
test('callback function return Promise', async (t) => { Napi4Test('callback function return Promise', async (t) => {
if (isWasiTest) {
t.pass()
return
}
const cbSpy = spy() const cbSpy = spy()
await callbackReturnPromise<string>(() => '1', spy) await callbackReturnPromise<string>(() => '1', spy)
t.is(cbSpy.callCount, 0) t.is(cbSpy.callCount, 0)
@ -360,7 +365,11 @@ test('callback function return Promise', async (t) => {
t.deepEqual(cbSpy.args, [['42']]) t.deepEqual(cbSpy.args, [['42']])
}) })
test('callback function return Promise and spawn', async (t) => { Napi4Test('callback function return Promise and spawn', async (t) => {
if (isWasiTest) {
t.pass()
return
}
const finalReturn = await callbackReturnPromiseAndSpawn((input) => const finalReturn = await callbackReturnPromiseAndSpawn((input) =>
Promise.resolve(`${input} world`), Promise.resolve(`${input} world`),
) )
@ -433,7 +442,9 @@ test('Async error with stack trace', async (t) => {
const err = await t.throwsAsync(() => throwAsyncError()) const err = await t.throwsAsync(() => throwAsyncError())
t.not(err?.stack, undefined) t.not(err?.stack, undefined)
t.deepEqual(err!.message, 'Async Error') t.deepEqual(err!.message, 'Async Error')
t.regex(err!.stack!, /.+at .+values\.spec\.ts:\d+:\d+.+/gm) if (!process.env.WASI_TEST) {
t.regex(err!.stack!, /.+at .+values\.spec\.ts:\d+:\d+.+/gm)
}
}) })
test('custom status code in Error', (t) => { test('custom status code in Error', (t) => {
@ -488,10 +499,13 @@ test('aliased rust struct and enum', (t) => {
}) })
test('serde-json', (t) => { test('serde-json', (t) => {
if (process.env.WASI_TEST) {
t.pass()
return
}
const packageJson = readPackageJson() const packageJson = readPackageJson()
t.is(packageJson.name, '@examples/napi') t.is(packageJson.name, '@examples/napi')
t.is(packageJson.version, '0.0.0') t.is(packageJson.version, '0.0.0')
t.is(packageJson.dependencies, undefined)
t.snapshot(Object.keys(packageJson.devDependencies!).sort()) t.snapshot(Object.keys(packageJson.devDependencies!).sort())
t.is(getPackageJsonName(packageJson), '@examples/napi') t.is(getPackageJsonName(packageJson), '@examples/napi')
@ -574,6 +588,10 @@ test('create external TypedArray', (t) => {
}) })
test('mutate TypedArray', (t) => { test('mutate TypedArray', (t) => {
if (isWasiTest) {
t.pass()
return
}
const input = new Float32Array([1, 2, 3, 4, 5]) const input = new Float32Array([1, 2, 3, 4, 5])
mutateTypedArray(input) mutateTypedArray(input)
t.deepEqual(input, new Float32Array([2.0, 4.0, 6.0, 8.0, 10.0])) t.deepEqual(input, new Float32Array([2.0, 4.0, 6.0, 8.0, 10.0]))
@ -587,6 +605,10 @@ test('deref uint8 array', (t) => {
}) })
test('async', async (t) => { test('async', async (t) => {
if (process.env.WASI_TEST) {
t.pass()
return
}
const bufPromise = readFileAsync(join(__dirname, '../package.json')) const bufPromise = readFileAsync(join(__dirname, '../package.json'))
await t.notThrowsAsync(bufPromise) await t.notThrowsAsync(bufPromise)
const buf = await bufPromise const buf = await bufPromise
@ -639,6 +661,11 @@ test('receive class reference in either', (t) => {
}) })
test('receive different class', (t) => { test('receive different class', (t) => {
// TODO: fix the napi_unwrap error from the emnapi
if (isWasiTest) {
t.pass()
return
}
const a = new JsClassForEither() const a = new JsClassForEither()
const b = new AnotherClassForEither() const b = new AnotherClassForEither()
t.is(receiveDifferentClass(a), 42) t.is(receiveDifferentClass(a), 42)
@ -764,8 +791,6 @@ BigIntTest('from i128 i64', (t) => {
t.is(bigintFromI128(), BigInt('-100')) t.is(bigintFromI128(), BigInt('-100'))
}) })
const Napi4Test = Number(process.versions.napi) >= 4 ? test : test.skip
Napi4Test('call thread safe function', (t) => { Napi4Test('call thread safe function', (t) => {
let i = 0 let i = 0
let value = 0 let value = 0
@ -820,13 +845,19 @@ Napi4Test('throw error from thread safe function fatal mode', (t) => {
return new Promise<void>((resolve) => { return new Promise<void>((resolve) => {
p.on('exit', (code) => { p.on('exit', (code) => {
t.is(code, 1) t.is(code, 1)
t.true(stderr.toString('utf8').includes(`[Error: Generic tsfn error]`)) const stderrMsg = stderr.toString('utf8')
console.info(stderrMsg)
t.true(stderrMsg.includes(`Error: Generic tsfn error`))
resolve() resolve()
}) })
}) })
}) })
Napi4Test('await Promise in rust', async (t) => { Napi4Test('await Promise in rust', async (t) => {
if (isWasiTest) {
t.pass()
return
}
const fx = 20 const fx = 20
const result = await asyncPlus100( const result = await asyncPlus100(
new Promise((resolve) => { new Promise((resolve) => {
@ -837,6 +868,10 @@ Napi4Test('await Promise in rust', async (t) => {
}) })
Napi4Test('Promise should reject raw error in rust', async (t) => { Napi4Test('Promise should reject raw error in rust', async (t) => {
if (isWasiTest) {
t.pass()
return
}
const fxError = new Error('What is Happy Planet') const fxError = new Error('What is Happy Planet')
const err = await t.throwsAsync(() => asyncPlus100(Promise.reject(fxError))) const err = await t.throwsAsync(() => asyncPlus100(Promise.reject(fxError)))
t.is(err, fxError) t.is(err, fxError)
@ -855,6 +890,10 @@ Napi4Test('call ThreadsafeFunction with callback', async (t) => {
}) })
Napi4Test('async call ThreadsafeFunction', async (t) => { Napi4Test('async call ThreadsafeFunction', async (t) => {
if (isWasiTest) {
t.pass()
return
}
await t.notThrowsAsync(() => await t.notThrowsAsync(() =>
tsfnAsyncCall((err, arg1, arg2, arg3) => { tsfnAsyncCall((err, arg1, arg2, arg3) => {
t.is(err, null) t.is(err, null)
@ -867,6 +906,10 @@ Napi4Test('async call ThreadsafeFunction', async (t) => {
}) })
test('Throw from ThreadsafeFunction JavaScript callback', async (t) => { test('Throw from ThreadsafeFunction JavaScript callback', async (t) => {
if (isWasiTest) {
t.pass()
return
}
const errMsg = 'ThrowFromJavaScriptRawCallback' const errMsg = 'ThrowFromJavaScriptRawCallback'
await t.throwsAsync( await t.throwsAsync(
() => () =>
@ -915,7 +958,11 @@ Napi4Test('accept ThreadsafeFunction tuple args', async (t) => {
}) })
}) })
test('threadsafe function return Promise and await in Rust', async (t) => { Napi4Test('threadsafe function return Promise and await in Rust', async (t) => {
if (isWasiTest) {
t.pass()
return
}
const value = await tsfnReturnPromise((err, value) => { const value = await tsfnReturnPromise((err, value) => {
if (err) { if (err) {
throw err throw err
@ -959,7 +1006,11 @@ Napi4Test('object only from js', (t) => {
}) })
}) })
test('promise in either', async (t) => { Napi4Test('promise in either', async (t) => {
if (isWasiTest) {
t.pass()
return
}
t.is(await promiseInEither(1), false) t.is(await promiseInEither(1), false)
t.is(await promiseInEither(20), true) t.is(await promiseInEither(20), true)
t.is(await promiseInEither(Promise.resolve(1)), false) t.is(await promiseInEither(Promise.resolve(1)), false)

View file

@ -1,13 +1,19 @@
const { join } = require('node:path') import { join } from 'node:path'
const { Worker } = require('node:worker_threads') import { fileURLToPath } from 'node:url'
import { Worker } from 'node:worker_threads'
const test = require('ava').default import test from 'ava'
const { Animal, Kind, DEFAULT_COST } = require('../index.node') const { Animal, Kind, DEFAULT_COST } = (await import('../index.js')).default
const __dirname = join(fileURLToPath(import.meta.url), '..')
// aarch64-unknown-linux-gnu is extremely slow in CI, skip it or it will timeout // aarch64-unknown-linux-gnu is extremely slow in CI, skip it or it will timeout
const t = const t =
process.arch === 'arm64' && process.platform === 'linux' ? test.skip : test (process.arch === 'arm64' && process.platform === 'linux') ||
process.env.WASI_TEST
? test.skip
: test
const concurrency = process.platform === 'win32' || process.platform === 'darwin' || (process.platform === 'linux' && process.arch === 'x64') ? 50 : 10 const concurrency = process.platform === 'win32' || process.platform === 'darwin' || (process.platform === 'linux' && process.arch === 'x64') ? 50 : 10
@ -15,9 +21,9 @@ t('should be able to require in worker thread', async (t) => {
await Promise.all( await Promise.all(
Array.from({ length: concurrency }).map(() => { Array.from({ length: concurrency }).map(() => {
const w = new Worker(join(__dirname, 'worker.cjs'), { const w = new Worker(join(__dirname, 'worker.cjs'), {
execArgv: [] execArgv: [],
}) })
return new Promise((resolve, reject) => { return new Promise<void>((resolve, reject) => {
w.postMessage({ type: 'require' }) w.postMessage({ type: 'require' })
w.on('message', (msg) => { w.on('message', (msg) => {
t.is(msg, Animal.withKind(Kind.Cat).whoami() + DEFAULT_COST) t.is(msg, Animal.withKind(Kind.Cat).whoami() + DEFAULT_COST)
@ -39,9 +45,9 @@ t('custom GC works on worker_threads', async (t) => {
await Promise.all( await Promise.all(
Array.from({ length: concurrency }).map(() => Array.from({ length: concurrency }).map(() =>
Promise.all([ Promise.all([
new Promise((resolve, reject) => { new Promise<Worker>((resolve, reject) => {
const w = new Worker(join(__dirname, 'worker.cjs'), { const w = new Worker(join(__dirname, 'worker.cjs'), {
execArgv: [] execArgv: [],
}) })
w.postMessage({ w.postMessage({
type: 'async:buffer', type: 'async:buffer',
@ -56,9 +62,9 @@ t('custom GC works on worker_threads', async (t) => {
}).then((w) => { }).then((w) => {
return w.terminate() return w.terminate()
}), }),
new Promise((resolve, reject) => { new Promise<Worker>((resolve, reject) => {
const w = new Worker(join(__dirname, 'worker.cjs'), { const w = new Worker(join(__dirname, 'worker.cjs'), {
execArgv: [] execArgv: [],
}) })
w.postMessage({ w.postMessage({
type: 'async:arraybuffer', type: 'async:arraybuffer',
@ -82,9 +88,9 @@ t('should be able to new Class in worker thread concurrently', async (t) => {
await Promise.all( await Promise.all(
Array.from({ length: concurrency }).map(() => { Array.from({ length: concurrency }).map(() => {
const w = new Worker(join(__dirname, 'worker.cjs'), { const w = new Worker(join(__dirname, 'worker.cjs'), {
execArgv: [] execArgv: [],
}) })
return new Promise((resolve, reject) => { return new Promise<void>((resolve, reject) => {
w.postMessage({ type: 'constructor' }) w.postMessage({ type: 'constructor' })
w.on('message', (msg) => { w.on('message', (msg) => {
t.is(msg, 'Ellie') t.is(msg, 'Ellie')

View file

@ -1,13 +1,16 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<meta charset="UTF-8" /> <head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Electron test</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head> <title>Electron test</title>
<body> </head>
<div>Electron test</div>
<script src="./index.js"></script> <body>
</body> <div>Electron test</div>
</html> <script src="./index.js"></script>
</body>
</html>

View file

@ -1,6 +1,6 @@
const { ipcRenderer } = require('electron') const { ipcRenderer } = require('electron')
const { callLongThreadsafeFunction } = require('../index') const { callLongThreadsafeFunction } = require('../index.node')
callLongThreadsafeFunction(() => {}) callLongThreadsafeFunction(() => {})

View file

@ -1,15 +1,8 @@
const assert = require('assert') const assert = require('node:assert')
const { readFileSync } = require('fs') const { readFileSync } = require('node:fs')
const { app, BrowserWindow, ipcMain } = require('electron') const { app, BrowserWindow, ipcMain } = require('electron')
const {
readFileAsync,
callThreadsafeFunction,
withAbortController,
createExternalTypedArray,
} = require('./index')
const FILE_CONTENT = readFileSync(__filename, 'utf8') const FILE_CONTENT = readFileSync(__filename, 'utf8')
const createWindowAndReload = async () => { const createWindowAndReload = async () => {
@ -39,16 +32,30 @@ const createWindowAndReload = async () => {
// reload to check if there is any crash // reload to check if there is any crash
win.reload() win.reload()
// make sure the renderer process is still alive
ipcMain.once('pong', () => {
console.info('pong')
resolve()
})
// Wait for a while to make sure if a crash happens, the 'resolve' function should be called after the crash // Wait for a while to make sure if a crash happens, the 'resolve' function should be called after the crash
setTimeout(() => { setTimeout(() => {
// make sure the renderer process is still alive
ipcMain.once('pong', () => resolve())
win.webContents.send('ping') win.webContents.send('ping')
}, 500) console.info('ping')
}, 1000)
}) })
} }
async function main() { async function main() {
const {
default: {
readFileAsync,
callThreadsafeFunction,
withAbortController,
createExternalTypedArray,
},
} = await import('./index.js')
const ctrl = new AbortController() const ctrl = new AbortController()
const promise = withAbortController(1, 2, ctrl.signal) const promise = withAbortController(1, 2, ctrl.signal)
try { try {

13
examples/napi/index.js Normal file
View file

@ -0,0 +1,13 @@
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
let exports
if (process.env.WASI_TEST) {
exports = await import('./index.wasi.mjs')
} else {
exports = require('./index.node')
}
export default exports

View file

@ -0,0 +1,448 @@
/* tslint:disable */
/* eslint-disable */
/* prettier-ignore */
/* auto-generated by NAPI-RS */
import * as __nodeFsPromises from 'node:fs/promises'
import * as __nodePath from 'node:path'
import { WASI as __nodeWASI } from 'node:wasi'
import { Worker } from 'node:worker_threads'
import * as __nodeURL from 'node:url'
import { instantiateNapiModule as __emnapiInstantiateNapiModule } from '@emnapi/core'
import { getDefaultContext as __emnapiGetDefaultContext } from '@emnapi/runtime'
const __wasi = new __nodeWASI({
env: process.env,
preopens: {
'/': __nodePath.join(__nodeURL.fileURLToPath(import.meta.url), '..'),
}
})
const __dirname = __nodePath.join(__nodeURL.fileURLToPath(import.meta.url), '..')
const __emnapiContext = __emnapiGetDefaultContext()
const __sharedMemory = new WebAssembly.Memory({
initial: 1024,
maximum: 10240,
shared: true,
})
const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = await __emnapiInstantiateNapiModule(__nodeFsPromises.readFile(__nodePath.join(__dirname, 'index.wasi-wasm32.wasm')), {
context: __emnapiContext,
asyncWorkPoolSize: 4,
wasi: __wasi,
onCreateWorker() {
return new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), {
env: process.env,
execArgv: ['--experimental-wasi-unstable-preview1'],
})
},
overwriteImports(importObject) {
importObject.env = {
...importObject.env,
...importObject.napi,
...importObject.emnapi,
memory: __sharedMemory,
}
},
beforeInit({ instance }) {
__napi_rs_initialize_modules(instance)
}
})
function __napi_rs_initialize_modules(__napiInstance) {
__napiInstance.exports['__napi_register__DEFAULT_COST_0']()
__napiInstance.exports['__napi_register__TYPE_SKIPPED_CONST_1']()
__napiInstance.exports['__napi_register__get_words_2']()
__napiInstance.exports['__napi_register__get_nums_3']()
__napiInstance.exports['__napi_register__sum_nums_4']()
__napiInstance.exports['__napi_register__to_js_obj_5']()
__napiInstance.exports['__napi_register__get_num_arr_6']()
__napiInstance.exports['__napi_register__get_nested_num_arr_7']()
__napiInstance.exports['__napi_register__read_file_async_8']()
__napiInstance.exports['__napi_register__async_multi_two_9']()
__napiInstance.exports['__napi_register__bigint_add_10']()
__napiInstance.exports['__napi_register__create_big_int_11']()
__napiInstance.exports['__napi_register__create_big_int_i64_12']()
__napiInstance.exports['__napi_register__bigint_get_u64_as_string_13']()
__napiInstance.exports['__napi_register__bigint_from_i64_14']()
__napiInstance.exports['__napi_register__bigint_from_i128_15']()
__napiInstance.exports['__napi_register__get_cwd_16']()
__napiInstance.exports['__napi_register__option_end_17']()
__napiInstance.exports['__napi_register__option_start_18']()
__napiInstance.exports['__napi_register__option_start_end_19']()
__napiInstance.exports['__napi_register__option_only_20']()
__napiInstance.exports['__napi_register__read_file_21']()
__napiInstance.exports['__napi_register__return_js_function_22']()
__napiInstance.exports['__napi_register__callback_return_promise_23']()
__napiInstance.exports['__napi_register__callback_return_promise_and_spawn_24']()
__napiInstance.exports['__napi_register__capture_error_in_callback_25']()
__napiInstance.exports['__napi_register__Animal_struct_26']()
__napiInstance.exports['__napi_register__Animal_impl_27']()
__napiInstance.exports['__napi_register__Dog_struct_28']()
__napiInstance.exports['__napi_register__Bird_struct_29']()
__napiInstance.exports['__napi_register__Bird_impl_30']()
__napiInstance.exports['__napi_register__Blake2bHasher_struct_31']()
__napiInstance.exports['__napi_register__Blake2bHasher_impl_32']()
__napiInstance.exports['__napi_register__Blake2bHasher_impl_33']()
__napiInstance.exports['__napi_register__Blake2bKey_struct_34']()
__napiInstance.exports['__napi_register__Context_struct_35']()
__napiInstance.exports['__napi_register__Context_impl_36']()
__napiInstance.exports['__napi_register__AnimalWithDefaultConstructor_struct_37']()
__napiInstance.exports['__napi_register__NinjaTurtle_struct_38']()
__napiInstance.exports['__napi_register__NinjaTurtle_impl_39']()
__napiInstance.exports['__napi_register__JsAssets_struct_40']()
__napiInstance.exports['__napi_register__JsAssets_impl_41']()
__napiInstance.exports['__napi_register__JsAsset_struct_42']()
__napiInstance.exports['__napi_register__JsAsset_impl_43']()
__napiInstance.exports['__napi_register__Optional_struct_44']()
__napiInstance.exports['__napi_register__Optional_impl_45']()
__napiInstance.exports['__napi_register__create_object_with_class_field_46']()
__napiInstance.exports['__napi_register__receive_object_with_class_field_47']()
__napiInstance.exports['__napi_register__NotWritableClass_struct_48']()
__napiInstance.exports['__napi_register__NotWritableClass_impl_49']()
__napiInstance.exports['__napi_register__CustomFinalize_struct_50']()
__napiInstance.exports['__napi_register__CustomFinalize_impl_51']()
__napiInstance.exports['__napi_register__Width_struct_52']()
__napiInstance.exports['__napi_register__plus_one_53']()
__napiInstance.exports['__napi_register__GetterSetterWithClosures_struct_54']()
__napiInstance.exports['__napi_register__GetterSetterWithClosures_impl_55']()
__napiInstance.exports['__napi_register__ClassWithFactory_struct_56']()
__napiInstance.exports['__napi_register__ClassWithFactory_impl_57']()
__napiInstance.exports['__napi_register__Selector_struct_58']()
__napiInstance.exports['__napi_register__date_to_number_59']()
__napiInstance.exports['__napi_register__chrono_date_to_millis_60']()
__napiInstance.exports['__napi_register__chrono_date_add_1_minute_61']()
__napiInstance.exports['__napi_register__chrono_native_date_time_62']()
__napiInstance.exports['__napi_register__chrono_native_date_time_return_63']()
__napiInstance.exports['__napi_register__either_string_or_number_64']()
__napiInstance.exports['__napi_register__return_either_65']()
__napiInstance.exports['__napi_register__either3_66']()
__napiInstance.exports['__napi_register__either4_67']()
__napiInstance.exports['__napi_register__JsClassForEither_struct_68']()
__napiInstance.exports['__napi_register__JsClassForEither_impl_69']()
__napiInstance.exports['__napi_register__AnotherClassForEither_struct_70']()
__napiInstance.exports['__napi_register__AnotherClassForEither_impl_71']()
__napiInstance.exports['__napi_register__receive_class_or_number_72']()
__napiInstance.exports['__napi_register__receive_mut_class_or_number_73']()
__napiInstance.exports['__napi_register__receive_different_class_74']()
__napiInstance.exports['__napi_register__return_either_class_75']()
__napiInstance.exports['__napi_register__either_from_option_76']()
__napiInstance.exports['__napi_register__either_from_objects_77']()
__napiInstance.exports['__napi_register__either_bool_or_function_78']()
__napiInstance.exports['__napi_register__promise_in_either_79']()
__napiInstance.exports['__napi_register__Kind_80']()
__napiInstance.exports['__napi_register__Empty_81']()
__napiInstance.exports['__napi_register__Status_82']()
__napiInstance.exports['__napi_register__CustomNumEnum_83']()
__napiInstance.exports['__napi_register__enum_to_i32_84']()
__napiInstance.exports['__napi_register__SkippedEnums_85']()
__napiInstance.exports['__napi_register__throw_error_86']()
__napiInstance.exports['__napi_register__panic_87']()
__napiInstance.exports['__napi_register__receive_string_88']()
__napiInstance.exports['__napi_register__custom_status_code_89']()
__napiInstance.exports['__napi_register__throw_async_error_90']()
__napiInstance.exports['__napi_register__create_external_91']()
__napiInstance.exports['__napi_register__create_external_string_92']()
__napiInstance.exports['__napi_register__get_external_93']()
__napiInstance.exports['__napi_register__mutate_external_94']()
__napiInstance.exports['__napi_register__validate_array_95']()
__napiInstance.exports['__napi_register__validate_buffer_96']()
__napiInstance.exports['__napi_register__validate_typed_array_97']()
__napiInstance.exports['__napi_register__validate_bigint_98']()
__napiInstance.exports['__napi_register__validate_boolean_99']()
__napiInstance.exports['__napi_register__validate_date_100']()
__napiInstance.exports['__napi_register__validate_date_time_101']()
__napiInstance.exports['__napi_register__validate_external_102']()
__napiInstance.exports['__napi_register__validate_function_103']()
__napiInstance.exports['__napi_register__validate_hash_map_104']()
__napiInstance.exports['__napi_register__validate_null_105']()
__napiInstance.exports['__napi_register__validate_undefined_106']()
__napiInstance.exports['__napi_register__validate_number_107']()
__napiInstance.exports['__napi_register__validate_promise_108']()
__napiInstance.exports['__napi_register__validate_string_109']()
__napiInstance.exports['__napi_register__validate_symbol_110']()
__napiInstance.exports['__napi_register__validate_optional_111']()
__napiInstance.exports['__napi_register__return_undefined_if_invalid_112']()
__napiInstance.exports['__napi_register__return_undefined_if_invalid_promise_113']()
__napiInstance.exports['__napi_register__ts_rename_114']()
__napiInstance.exports['__napi_register__override_individual_arg_on_function_115']()
__napiInstance.exports['__napi_register__override_individual_arg_on_function_with_cb_arg_116']()
__napiInstance.exports['__napi_register__Fib_struct_117']()
__napiInstance.exports['__napi_register__Fib_impl_118']()
__napiInstance.exports['__napi_register__Fib_impl_119']()
__napiInstance.exports['__napi_register__Fib2_struct_120']()
__napiInstance.exports['__napi_register__Fib2_impl_121']()
__napiInstance.exports['__napi_register__Fib2_impl_122']()
__napiInstance.exports['__napi_register__Fib3_struct_123']()
__napiInstance.exports['__napi_register__Fib3_impl_124']()
__napiInstance.exports['__napi_register__ALIGNMENT_125']()
__napiInstance.exports['__napi_register__xxh64_126']()
__napiInstance.exports['__napi_register__xxh128_127']()
__napiInstance.exports['__napi_register__Xxh3_struct_128']()
__napiInstance.exports['__napi_register__Xxh3_impl_129']()
__napiInstance.exports['__napi_register__xxh2_plus_130']()
__napiInstance.exports['__napi_register__xxh3_xxh64_alias_131']()
__napiInstance.exports['__napi_register__xxh64_alias_132']()
__napiInstance.exports['__napi_register__get_mapping_133']()
__napiInstance.exports['__napi_register__sum_mapping_134']()
__napiInstance.exports['__napi_register__map_option_135']()
__napiInstance.exports['__napi_register__return_null_136']()
__napiInstance.exports['__napi_register__return_undefined_137']()
__napiInstance.exports['__napi_register__add_138']()
__napiInstance.exports['__napi_register__fibonacci_139']()
__napiInstance.exports['__napi_register__list_obj_keys_140']()
__napiInstance.exports['__napi_register__create_obj_141']()
__napiInstance.exports['__napi_register__get_global_142']()
__napiInstance.exports['__napi_register__get_undefined_143']()
__napiInstance.exports['__napi_register__get_null_144']()
__napiInstance.exports['__napi_register__receive_all_optional_object_145']()
__napiInstance.exports['__napi_register__AliasedEnum_146']()
__napiInstance.exports['__napi_register__fn_received_aliased_147']()
__napiInstance.exports['__napi_register__receive_strict_object_148']()
__napiInstance.exports['__napi_register__get_str_from_object_149']()
__napiInstance.exports['__napi_register__create_obj_with_property_150']()
__napiInstance.exports['__napi_register__getter_from_obj_151']()
__napiInstance.exports['__napi_register__receive_object_only_from_js_152']()
__napiInstance.exports['__napi_register__async_plus_100_153']()
__napiInstance.exports['__napi_register__JsRepo_struct_154']()
__napiInstance.exports['__napi_register__JsRepo_impl_155']()
__napiInstance.exports['__napi_register__JsRemote_struct_156']()
__napiInstance.exports['__napi_register__JsRemote_impl_157']()
__napiInstance.exports['__napi_register__CSSRuleList_struct_158']()
__napiInstance.exports['__napi_register__CSSRuleList_impl_159']()
__napiInstance.exports['__napi_register__CSSStyleSheet_struct_160']()
__napiInstance.exports['__napi_register__AnotherCSSStyleSheet_struct_161']()
__napiInstance.exports['__napi_register__AnotherCSSStyleSheet_impl_162']()
__napiInstance.exports['__napi_register__CSSStyleSheet_impl_163']()
__napiInstance.exports['__napi_register__read_package_json_164']()
__napiInstance.exports['__napi_register__get_package_json_name_165']()
__napiInstance.exports['__napi_register__test_serde_roundtrip_166']()
__napiInstance.exports['__napi_register__test_serde_big_number_precision_167']()
__napiInstance.exports['__napi_register__return_from_shared_crate_168']()
__napiInstance.exports['__napi_register__contains_169']()
__napiInstance.exports['__napi_register__concat_str_170']()
__napiInstance.exports['__napi_register__concat_utf16_171']()
__napiInstance.exports['__napi_register__concat_latin1_172']()
__napiInstance.exports['__napi_register__roundtrip_str_173']()
__napiInstance.exports['__napi_register__set_symbol_in_obj_174']()
__napiInstance.exports['__napi_register__create_symbol_175']()
__napiInstance.exports['__napi_register__create_symbol_for_176']()
__napiInstance.exports['__napi_register__DelaySum_impl_177']()
__napiInstance.exports['__napi_register__without_abort_controller_178']()
__napiInstance.exports['__napi_register__with_abort_controller_179']()
__napiInstance.exports['__napi_register__call_threadsafe_function_180']()
__napiInstance.exports['__napi_register__call_long_threadsafe_function_181']()
__napiInstance.exports['__napi_register__threadsafe_function_throw_error_182']()
__napiInstance.exports['__napi_register__threadsafe_function_fatal_mode_183']()
__napiInstance.exports['__napi_register__threadsafe_function_fatal_mode_error_184']()
__napiInstance.exports['__napi_register__threadsafe_function_closure_capture_185']()
__napiInstance.exports['__napi_register__tsfn_call_with_callback_186']()
__napiInstance.exports['__napi_register__tsfn_async_call_187']()
__napiInstance.exports['__napi_register__accept_threadsafe_function_188']()
__napiInstance.exports['__napi_register__accept_threadsafe_function_fatal_189']()
__napiInstance.exports['__napi_register__accept_threadsafe_function_tuple_args_190']()
__napiInstance.exports['__napi_register__tsfn_return_promise_191']()
__napiInstance.exports['__napi_register__tsfn_return_promise_timeout_192']()
__napiInstance.exports['__napi_register__tsfn_throw_from_js_193']()
__napiInstance.exports['__napi_register__get_buffer_194']()
__napiInstance.exports['__napi_register__append_buffer_195']()
__napiInstance.exports['__napi_register__get_empty_buffer_196']()
__napiInstance.exports['__napi_register__convert_u32_array_197']()
__napiInstance.exports['__napi_register__create_external_typed_array_198']()
__napiInstance.exports['__napi_register__mutate_typed_array_199']()
__napiInstance.exports['__napi_register__deref_uint8_array_200']()
__napiInstance.exports['__napi_register__buffer_pass_through_201']()
__napiInstance.exports['__napi_register__array_buffer_pass_through_202']()
__napiInstance.exports['__napi_register__AsyncBuffer_impl_203']()
__napiInstance.exports['__napi_register__async_reduce_buffer_204']()
__napiInstance.exports['__napi_register__run_script_205']()
}
const binding = __napiModule.exports
const { Animal, AnimalWithDefaultConstructor, AnotherClassForEither, AnotherCssStyleSheet, AnotherCSSStyleSheet, Asset, JsAsset, Assets, JsAssets, Bird, Blake2BHasher, Blake2bHasher, Blake2BKey, Blake2bKey, ClassWithFactory, Context, CssRuleList, CSSRuleList, CssStyleSheet, CSSStyleSheet, CustomFinalize, Dog, Fib, Fib2, Fib3, GetterSetterWithClosures, JsClassForEither, JsRemote, JsRepo, NinjaTurtle, NotWritableClass, Optional, Selector, Width, acceptThreadsafeFunction, acceptThreadsafeFunctionFatal, acceptThreadsafeFunctionTupleArgs, add, ALIAS, AliasedEnum, appendBuffer, arrayBufferPassThrough, asyncMultiTwo, asyncPlus100, asyncReduceBuffer, bigintAdd, bigintFromI128, bigintFromI64, bigintGetU64AsString, bufferPassThrough, callbackReturnPromise, callbackReturnPromiseAndSpawn, callLongThreadsafeFunction, callThreadsafeFunction, captureErrorInCallback, chronoDateAdd1Minute, chronoDateToMillis, chronoNativeDateTime, chronoNativeDateTimeReturn, concatLatin1, concatStr, concatUtf16, contains, convertU32Array, createBigInt, createBigIntI64, createExternal, createExternalString, createExternalTypedArray, createObj, createObjectWithClassField, createObjWithProperty, createSymbol, createSymbolFor, CustomNumEnum, customStatusCode, dateToNumber, DEFAULT_COST, derefUint8Array, either3, either4, eitherBoolOrFunction, eitherFromObjects, eitherFromOption, eitherStringOrNumber, Empty, enumToI32, fibonacci, fnReceivedAliased, getBuffer, getCwd, getEmptyBuffer, getExternal, getGlobal, getMapping, getNestedNumArr, getNull, getNumArr, getNums, getPackageJsonName, getStrFromObject, getterFromObj, getUndefined, getWords, Kind, listObjKeys, mapOption, mutateExternal, mutateTypedArray, optionEnd, optionOnly, optionStart, optionStartEnd, overrideIndividualArgOnFunction, overrideIndividualArgOnFunctionWithCbArg, panic, plusOne, promiseInEither, readFile, readFileAsync, readPackageJson, receiveAllOptionalObject, receiveClassOrNumber, receiveDifferentClass, receiveMutClassOrNumber, receiveObjectOnlyFromJs, receiveObjectWithClassField, receiveStrictObject, receiveString, returnEither, returnEitherClass, returnFromSharedCrate, returnJsFunction, returnNull, returnUndefined, returnUndefinedIfInvalid, returnUndefinedIfInvalidPromise, roundtripStr, runScript, setSymbolInObj, Status, sumMapping, sumNums, testSerdeBigNumberPrecision, testSerdeRoundtrip, threadsafeFunctionClosureCapture, threadsafeFunctionFatalMode, threadsafeFunctionFatalModeError, threadsafeFunctionThrowError, throwAsyncError, throwError, toJsObj, tsfnAsyncCall, tsfnCallWithCallback, tsfnReturnPromise, tsfnReturnPromiseTimeout, tsfnThrowFromJs, tsRename, validateArray, validateBigint, validateBoolean, validateBuffer, validateDate, validateDateTime, validateExternal, validateFunction, validateHashMap, validateNull, validateNumber, validateOptional, validatePromise, validateString, validateSymbol, validateTypedArray, validateUndefined, withAbortController, withoutAbortController, xxh64Alias, xxh2, xxh3 } = binding
export {
Animal,
AnimalWithDefaultConstructor,
AnotherClassForEither,
AnotherCssStyleSheet,
AnotherCSSStyleSheet,
Asset,
JsAsset,
Assets,
JsAssets,
Bird,
Blake2BHasher,
Blake2bHasher,
Blake2BKey,
Blake2bKey,
ClassWithFactory,
Context,
CssRuleList,
CSSRuleList,
CssStyleSheet,
CSSStyleSheet,
CustomFinalize,
Dog,
Fib,
Fib2,
Fib3,
GetterSetterWithClosures,
JsClassForEither,
JsRemote,
JsRepo,
NinjaTurtle,
NotWritableClass,
Optional,
Selector,
Width,
acceptThreadsafeFunction,
acceptThreadsafeFunctionFatal,
acceptThreadsafeFunctionTupleArgs,
add,
ALIAS,
AliasedEnum,
appendBuffer,
arrayBufferPassThrough,
asyncMultiTwo,
asyncPlus100,
asyncReduceBuffer,
bigintAdd,
bigintFromI128,
bigintFromI64,
bigintGetU64AsString,
bufferPassThrough,
callbackReturnPromise,
callbackReturnPromiseAndSpawn,
callLongThreadsafeFunction,
callThreadsafeFunction,
captureErrorInCallback,
chronoDateAdd1Minute,
chronoDateToMillis,
chronoNativeDateTime,
chronoNativeDateTimeReturn,
concatLatin1,
concatStr,
concatUtf16,
contains,
convertU32Array,
createBigInt,
createBigIntI64,
createExternal,
createExternalString,
createExternalTypedArray,
createObj,
createObjectWithClassField,
createObjWithProperty,
createSymbol,
createSymbolFor,
CustomNumEnum,
customStatusCode,
dateToNumber,
DEFAULT_COST,
derefUint8Array,
either3,
either4,
eitherBoolOrFunction,
eitherFromObjects,
eitherFromOption,
eitherStringOrNumber,
Empty,
enumToI32,
fibonacci,
fnReceivedAliased,
getBuffer,
getCwd,
getEmptyBuffer,
getExternal,
getGlobal,
getMapping,
getNestedNumArr,
getNull,
getNumArr,
getNums,
getPackageJsonName,
getStrFromObject,
getterFromObj,
getUndefined,
getWords,
Kind,
listObjKeys,
mapOption,
mutateExternal,
mutateTypedArray,
optionEnd,
optionOnly,
optionStart,
optionStartEnd,
overrideIndividualArgOnFunction,
overrideIndividualArgOnFunctionWithCbArg,
panic,
plusOne,
promiseInEither,
readFile,
readFileAsync,
readPackageJson,
receiveAllOptionalObject,
receiveClassOrNumber,
receiveDifferentClass,
receiveMutClassOrNumber,
receiveObjectOnlyFromJs,
receiveObjectWithClassField,
receiveStrictObject,
receiveString,
returnEither,
returnEitherClass,
returnFromSharedCrate,
returnJsFunction,
returnNull,
returnUndefined,
returnUndefinedIfInvalid,
returnUndefinedIfInvalidPromise,
roundtripStr,
runScript,
setSymbolInObj,
Status,
sumMapping,
sumNums,
testSerdeBigNumberPrecision,
testSerdeRoundtrip,
threadsafeFunctionClosureCapture,
threadsafeFunctionFatalMode,
threadsafeFunctionFatalModeError,
threadsafeFunctionThrowError,
throwAsyncError,
throwError,
toJsObj,
tsfnAsyncCall,
tsfnCallWithCallback,
tsfnReturnPromise,
tsfnReturnPromiseTimeout,
tsfnThrowFromJs,
tsRename,
validateArray,
validateBigint,
validateBoolean,
validateBuffer,
validateDate,
validateDateTime,
validateExternal,
validateFunction,
validateHashMap,
validateNull,
validateNumber,
validateOptional,
validatePromise,
validateString,
validateSymbol,
validateTypedArray,
validateUndefined,
withAbortController,
withoutAbortController,
xxh64Alias,
xxh2,
xxh3
}

View file

@ -3,11 +3,11 @@
"private": true, "private": true,
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"main": "./index.node", "main": "./index.js",
"types": "./index.d.ts", "types": "./index.d.ts",
"scripts": { "scripts": {
"build": "napi-raw build --no-js", "build": "napi-raw build",
"test": "cross-env TS_NODE_PROJECT=./tsconfig.json node --es-module-specifier-resolution=node --loader ts-node/esm/transpile-only ../../node_modules/ava/entrypoints/cli.mjs" "test": "cross-env TS_NODE_PROJECT=./tsconfig.json node --es-module-specifier-resolution=node --loader ts-node/esm/transpile-only --experimental-wasi-unstable-preview1 ../../node_modules/ava/entrypoints/cli.mjs"
}, },
"devDependencies": { "devDependencies": {
"@napi-rs/cli": "workspace:*", "@napi-rs/cli": "workspace:*",
@ -25,11 +25,15 @@
"cjs": true "cjs": true
}, },
"files": [ "files": [
"__tests__/**/*.spec.ts", "__tests__/**/*.spec.{ts,cts,js,cjs,mjs}"
"__tests__/**/*.spec.cts",
"__tests__/**/*.spec.js",
"__tests__/**/*.spec.cjs"
], ],
"timeout": "10m" "timeout": "10m"
},
"dependencies": {
"@emnapi/core": "0.43.1",
"@tybys/wasm-util": "^0.8.0",
"@types/lodash": "^4.14.191",
"lodash": "^4.17.21",
"sinon": "^15.0.1"
} }
} }

View file

@ -1,18 +1,29 @@
#[cfg(not(target_arch = "wasm32"))]
use futures::prelude::*; use futures::prelude::*;
use napi::bindgen_prelude::*; use napi::bindgen_prelude::*;
use napi::tokio::{self, fs}; use napi::tokio;
#[cfg(not(target_arch = "wasm32"))]
use napi::tokio::fs;
#[napi] #[napi]
async fn read_file_async(path: String) -> Result<Buffer> { async fn read_file_async(path: String) -> Result<Buffer> {
fs::read(path) #[cfg(not(target_arch = "wasm32"))]
.map(|r| match r { {
Ok(content) => Ok(content.into()), fs::read(path)
Err(e) => Err(Error::new( .map(|r| match r {
Status::GenericFailure, Ok(content) => Ok(content.into()),
format!("failed to read file, {}", e), Err(e) => Err(Error::new(
)), Status::GenericFailure,
}) format!("failed to read file, {}", e),
.await )),
})
.await
}
#[cfg(target_arch = "wasm32")]
{
let conetent = std::fs::read(path)?;
Ok(conetent.into())
}
} }
#[napi] #[napi]

View file

@ -0,0 +1,6 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "ESNext"
}
}

View file

@ -2,6 +2,7 @@
"extends": "../tsconfig.json", "extends": "../tsconfig.json",
"include": ["."], "include": ["."],
"compilerOptions": { "compilerOptions": {
"moduleResolution": "node",
"outDir": "./dist", "outDir": "./dist",
"rootDir": ".", "rootDir": ".",
"target": "ESNext", "target": "ESNext",
@ -11,5 +12,11 @@
"types": ["bun-types"], "types": ["bun-types"],
"importHelpers": false "importHelpers": false
}, },
"exclude": ["dist", "electron.cjs", "electron-renderer", "node_modules"] "exclude": [
"dist",
"electron.js",
"electron-renderer",
"index.js",
"index.wasi.mjs"
]
} }

View file

@ -0,0 +1,51 @@
import fs from "node:fs";
import { createRequire } from "node:module";
import { parentPort, Worker } from "node:worker_threads";
import { instantiateNapiModuleSync, MessageHandler } from "@emnapi/core";
import { WASI } from "@tybys/wasm-util";
const require = createRequire(import.meta.url);
if (parentPort) {
parentPort.on("message", (data) => {
globalThis.onmessage({ data });
});
}
Object.assign(globalThis, {
self: globalThis,
require,
Worker,
importScripts: function (f) {
;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f);
},
postMessage: function (msg) {
if (parentPort) {
parentPort.postMessage(msg);
}
},
});
const handler = new MessageHandler({
onLoad({ wasmModule, wasmMemory }) {
const wasi = new WASI({ fs });
return instantiateNapiModuleSync(wasmModule, {
childThread: true,
wasi,
overwriteImports(importObject) {
importObject.env = {
...importObject.env,
...importObject.napi,
...importObject.emnapi,
memory: wasmMemory
};
},
});
},
});
globalThis.onmessage = function (e) {
handler.handle(e);
};

View file

@ -80,7 +80,7 @@
"c8": "^8.0.0", "c8": "^8.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"electron": "^27.0.0", "electron": "^27.0.0",
"esbuild": "^0.19.0", "esbuild": "^0.19.5",
"eslint": "^8.45.0", "eslint": "^8.45.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.27.5", "eslint-plugin-import": "^2.27.5",

View file

@ -23,7 +23,7 @@ const tripleLists: { [key: string]: { platform?: string } } = RAW_LIST.trim()
.split('\n') .split('\n')
.filter((line) => !line.startsWith('wasm') && line.trim().length) .filter((line) => !line.startsWith('wasm') && line.trim().length)
.map(parseTriple) .map(parseTriple)
.reduce((acc, cur) => { .reduce((acc: Record<string, { platform?: string }>, cur) => {
acc[cur.triple] = cur acc[cur.triple] = cur
return acc return acc
}, {}) }, {})

8
triples/tsconfig.json Normal file
View file

@ -0,0 +1,8 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"composite": true,
"noEmit": true
},
"include": ["."]
}

View file

@ -5,6 +5,9 @@
"./triples/index.js", "./triples/index.js",
"./memory-testing/*.js", "./memory-testing/*.js",
"./memory-testing/*.mjs", "./memory-testing/*.mjs",
"./crates/cli/index.js" "./crates/cli/index.js",
"./examples/**/*.js",
"./examples/**/*.mjs",
"./examples/**/*.cjs"
] ]
} }

374
yarn.lock
View file

@ -125,156 +125,174 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/android-arm64@npm:0.19.0": "@emnapi/core@npm:0.43.1":
version: 0.19.0 version: 0.43.1
resolution: "@esbuild/android-arm64@npm:0.19.0" resolution: "@emnapi/core@npm:0.43.1"
dependencies:
tslib: ^2.4.0
checksum: 5bd6bce73883ef4db9347c853dfecb7851cd8b60de21099ffe8be5fec7383df0f73c3e702a1f15f37e43493a766320a1d506296925b02fe88b265031d820a94a
languageName: node
linkType: hard
"@emnapi/runtime@npm:0.43.1":
version: 0.43.1
resolution: "@emnapi/runtime@npm:0.43.1"
dependencies:
tslib: ^2.4.0
checksum: 61ebf7346d745f87648b5a4373aa80aed7c731526615544253cbbcb50f1d0cc1159ca6504b6c67ce0df55d6afdd65ae272f988d03d01d568308ffc9f1f7dbfbb
languageName: node
linkType: hard
"@esbuild/android-arm64@npm:0.19.5":
version: 0.19.5
resolution: "@esbuild/android-arm64@npm:0.19.5"
conditions: os=android & cpu=arm64 conditions: os=android & cpu=arm64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/android-arm@npm:0.19.0": "@esbuild/android-arm@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/android-arm@npm:0.19.0" resolution: "@esbuild/android-arm@npm:0.19.5"
conditions: os=android & cpu=arm conditions: os=android & cpu=arm
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/android-x64@npm:0.19.0": "@esbuild/android-x64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/android-x64@npm:0.19.0" resolution: "@esbuild/android-x64@npm:0.19.5"
conditions: os=android & cpu=x64 conditions: os=android & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/darwin-arm64@npm:0.19.0": "@esbuild/darwin-arm64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/darwin-arm64@npm:0.19.0" resolution: "@esbuild/darwin-arm64@npm:0.19.5"
conditions: os=darwin & cpu=arm64 conditions: os=darwin & cpu=arm64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/darwin-x64@npm:0.19.0": "@esbuild/darwin-x64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/darwin-x64@npm:0.19.0" resolution: "@esbuild/darwin-x64@npm:0.19.5"
conditions: os=darwin & cpu=x64 conditions: os=darwin & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/freebsd-arm64@npm:0.19.0": "@esbuild/freebsd-arm64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/freebsd-arm64@npm:0.19.0" resolution: "@esbuild/freebsd-arm64@npm:0.19.5"
conditions: os=freebsd & cpu=arm64 conditions: os=freebsd & cpu=arm64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/freebsd-x64@npm:0.19.0": "@esbuild/freebsd-x64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/freebsd-x64@npm:0.19.0" resolution: "@esbuild/freebsd-x64@npm:0.19.5"
conditions: os=freebsd & cpu=x64 conditions: os=freebsd & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/linux-arm64@npm:0.19.0": "@esbuild/linux-arm64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/linux-arm64@npm:0.19.0" resolution: "@esbuild/linux-arm64@npm:0.19.5"
conditions: os=linux & cpu=arm64 conditions: os=linux & cpu=arm64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/linux-arm@npm:0.19.0": "@esbuild/linux-arm@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/linux-arm@npm:0.19.0" resolution: "@esbuild/linux-arm@npm:0.19.5"
conditions: os=linux & cpu=arm conditions: os=linux & cpu=arm
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/linux-ia32@npm:0.19.0": "@esbuild/linux-ia32@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/linux-ia32@npm:0.19.0" resolution: "@esbuild/linux-ia32@npm:0.19.5"
conditions: os=linux & cpu=ia32 conditions: os=linux & cpu=ia32
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/linux-loong64@npm:0.19.0": "@esbuild/linux-loong64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/linux-loong64@npm:0.19.0" resolution: "@esbuild/linux-loong64@npm:0.19.5"
conditions: os=linux & cpu=loong64 conditions: os=linux & cpu=loong64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/linux-mips64el@npm:0.19.0": "@esbuild/linux-mips64el@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/linux-mips64el@npm:0.19.0" resolution: "@esbuild/linux-mips64el@npm:0.19.5"
conditions: os=linux & cpu=mips64el conditions: os=linux & cpu=mips64el
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/linux-ppc64@npm:0.19.0": "@esbuild/linux-ppc64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/linux-ppc64@npm:0.19.0" resolution: "@esbuild/linux-ppc64@npm:0.19.5"
conditions: os=linux & cpu=ppc64 conditions: os=linux & cpu=ppc64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/linux-riscv64@npm:0.19.0": "@esbuild/linux-riscv64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/linux-riscv64@npm:0.19.0" resolution: "@esbuild/linux-riscv64@npm:0.19.5"
conditions: os=linux & cpu=riscv64 conditions: os=linux & cpu=riscv64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/linux-s390x@npm:0.19.0": "@esbuild/linux-s390x@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/linux-s390x@npm:0.19.0" resolution: "@esbuild/linux-s390x@npm:0.19.5"
conditions: os=linux & cpu=s390x conditions: os=linux & cpu=s390x
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/linux-x64@npm:0.19.0": "@esbuild/linux-x64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/linux-x64@npm:0.19.0" resolution: "@esbuild/linux-x64@npm:0.19.5"
conditions: os=linux & cpu=x64 conditions: os=linux & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/netbsd-x64@npm:0.19.0": "@esbuild/netbsd-x64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/netbsd-x64@npm:0.19.0" resolution: "@esbuild/netbsd-x64@npm:0.19.5"
conditions: os=netbsd & cpu=x64 conditions: os=netbsd & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/openbsd-x64@npm:0.19.0": "@esbuild/openbsd-x64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/openbsd-x64@npm:0.19.0" resolution: "@esbuild/openbsd-x64@npm:0.19.5"
conditions: os=openbsd & cpu=x64 conditions: os=openbsd & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/sunos-x64@npm:0.19.0": "@esbuild/sunos-x64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/sunos-x64@npm:0.19.0" resolution: "@esbuild/sunos-x64@npm:0.19.5"
conditions: os=sunos & cpu=x64 conditions: os=sunos & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/win32-arm64@npm:0.19.0": "@esbuild/win32-arm64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/win32-arm64@npm:0.19.0" resolution: "@esbuild/win32-arm64@npm:0.19.5"
conditions: os=win32 & cpu=arm64 conditions: os=win32 & cpu=arm64
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/win32-ia32@npm:0.19.0": "@esbuild/win32-ia32@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/win32-ia32@npm:0.19.0" resolution: "@esbuild/win32-ia32@npm:0.19.5"
conditions: os=win32 & cpu=ia32 conditions: os=win32 & cpu=ia32
languageName: node languageName: node
linkType: hard linkType: hard
"@esbuild/win32-x64@npm:0.19.0": "@esbuild/win32-x64@npm:0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "@esbuild/win32-x64@npm:0.19.0" resolution: "@esbuild/win32-x64@npm:0.19.5"
conditions: os=win32 & cpu=x64 conditions: os=win32 & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
@ -335,7 +353,9 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@examples/napi@workspace:examples/napi" resolution: "@examples/napi@workspace:examples/napi"
dependencies: dependencies:
"@emnapi/core": 0.43.1
"@napi-rs/cli": "workspace:*" "@napi-rs/cli": "workspace:*"
"@tybys/wasm-util": ^0.8.0
"@types/lodash": ^4.14.195 "@types/lodash": ^4.14.195
ava: ^5.3.1 ava: ^5.3.1
cross-env: 7.0.3 cross-env: 7.0.3
@ -498,7 +518,11 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@napi-rs/cli@workspace:cli" resolution: "@napi-rs/cli@workspace:cli"
dependencies: dependencies:
"@emnapi/core": 0.43.1
"@emnapi/runtime": 0.43.1
"@octokit/rest": ^20.0.1 "@octokit/rest": ^20.0.1
"@tybys/wasm-util": 0.8.0
"@types/debug": ^4.1.7
"@types/inquirer": ^9.0.3 "@types/inquirer": ^9.0.3
"@types/js-yaml": ^4.0.5 "@types/js-yaml": ^4.0.5
"@types/lodash-es": ^4.17.8 "@types/lodash-es": ^4.17.8
@ -506,14 +530,29 @@ __metadata:
clipanion: ^3.2.1 clipanion: ^3.2.1
colorette: ^2.0.20 colorette: ^2.0.20
debug: ^4.3.4 debug: ^4.3.4
esbuild: ^0.19.0 emnapi: 0.43.1
env-paths: ^3.0.0
esbuild: ^0.19.5
inquirer: ^9.2.8 inquirer: ^9.2.8
js-yaml: ^4.1.0 js-yaml: ^4.1.0
lodash-es: ^4.17.21 lodash-es: ^4.17.21
prettier: ^3.0.0 prettier: ^3.0.0
toml: ^3.0.0
ts-node: ^10.9.1 ts-node: ^10.9.1
tslib: ^2.6.1
typanion: ^3.13.0 typanion: ^3.13.0
typescript: ^5.1.6 typescript: ^5.1.6
peerDependencies:
"@emnapi/runtime": 0.43.1
"@tybys/wasm-util": 0.8.0
emnapi: 0.43.1
peerDependenciesMeta:
"@emnapi/runtime":
optional: true
"@tybys/wasm-util":
optional: true
emnapi:
optional: true
bin: bin:
napi: ./dist/cli.js napi: ./dist/cli.js
napi-raw: ./cli.mjs napi-raw: ./cli.mjs
@ -1281,6 +1320,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@tybys/wasm-util@npm:0.8.0, @tybys/wasm-util@npm:^0.8.0":
version: 0.8.0
resolution: "@tybys/wasm-util@npm:0.8.0"
dependencies:
tslib: ^2.4.0
checksum: ce110aa721abe0c31f93c25c0abcc621bcc03a30f1927fe940e13456ef30438f140ec436dfe6d2a288814299d68215b071e986bca8ed97dfc3108f80ad214093
languageName: node
linkType: hard
"@types/cacheable-request@npm:^6.0.1": "@types/cacheable-request@npm:^6.0.1":
version: 6.0.3 version: 6.0.3
resolution: "@types/cacheable-request@npm:6.0.3" resolution: "@types/cacheable-request@npm:6.0.3"
@ -1293,7 +1341,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/debug@npm:^4.1.8": "@types/debug@npm:^4.1.7, @types/debug@npm:^4.1.8":
version: 4.1.8 version: 4.1.8
resolution: "@types/debug@npm:4.1.8" resolution: "@types/debug@npm:4.1.8"
dependencies: dependencies:
@ -1421,16 +1469,16 @@ __metadata:
linkType: hard linkType: hard
"@types/node@npm:*, @types/node@npm:^20.4.2": "@types/node@npm:*, @types/node@npm:^20.4.2":
version: 20.4.5 version: 20.4.4
resolution: "@types/node@npm:20.4.5" resolution: "@types/node@npm:20.4.4"
checksum: 36a0304a8dc346a1b2d2edac4c4633eecf70875793d61a5274d0df052d7a7af7a8e34f29884eac4fbd094c4f0201477dcb39c0ecd3307ca141688806538d1138 checksum: 43f3c4a8acc38ae753e15a0e79bae0447d255b3742fa87f8e065d7b9d20ecb0e03d6c5b46c00d5d26f4552160381a00255f49205595a8ee48c2423e00263c930
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^18.11.18": "@types/node@npm:^18.11.18":
version: 18.17.1 version: 18.17.0
resolution: "@types/node@npm:18.17.1" resolution: "@types/node@npm:18.17.0"
checksum: 56201bda9a2d05d68602df63b4e67b0545ac8c6d0280bd5fb31701350a978a577a027501fbf49db99bf177f2242ebd1244896bfd35e89042d5bd7dfebff28d4e checksum: 3a43c5c5541342751b514485144818a515fac5427f663066068eaacbe8a108cbe1207aae75ec89d34c3b32414c334aad84e9083cf7fcf3ebfd970adc871314a4
languageName: node languageName: node
linkType: hard linkType: hard
@ -1508,14 +1556,14 @@ __metadata:
linkType: hard linkType: hard
"@typescript-eslint/eslint-plugin@npm:^6.0.0": "@typescript-eslint/eslint-plugin@npm:^6.0.0":
version: 6.2.1 version: 6.2.0
resolution: "@typescript-eslint/eslint-plugin@npm:6.2.1" resolution: "@typescript-eslint/eslint-plugin@npm:6.2.0"
dependencies: dependencies:
"@eslint-community/regexpp": ^4.5.1 "@eslint-community/regexpp": ^4.5.1
"@typescript-eslint/scope-manager": 6.2.1 "@typescript-eslint/scope-manager": 6.2.0
"@typescript-eslint/type-utils": 6.2.1 "@typescript-eslint/type-utils": 6.2.0
"@typescript-eslint/utils": 6.2.1 "@typescript-eslint/utils": 6.2.0
"@typescript-eslint/visitor-keys": 6.2.1 "@typescript-eslint/visitor-keys": 6.2.0
debug: ^4.3.4 debug: ^4.3.4
graphemer: ^1.4.0 graphemer: ^1.4.0
ignore: ^5.2.4 ignore: ^5.2.4
@ -1529,44 +1577,44 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: e73f3fe36519d895037d223f3ddf200b97e17bcde9390984118c38733add1edf996357c809ec2db92cec61bc7c9e5a3d9a583e0d0f92fa9c3919b68716a27b37 checksum: 1ef46b1c2e3e2013f66b4982dcfb9e198a3824cc1503b843e553201a108a3cb6e4adfb2c486158c89d993e5e4b9d99aeb2af28297e43da98c4750dae8f5131b5
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/parser@npm:^6.0.0": "@typescript-eslint/parser@npm:^6.0.0":
version: 6.2.1 version: 6.2.0
resolution: "@typescript-eslint/parser@npm:6.2.1" resolution: "@typescript-eslint/parser@npm:6.2.0"
dependencies: dependencies:
"@typescript-eslint/scope-manager": 6.2.1 "@typescript-eslint/scope-manager": 6.2.0
"@typescript-eslint/types": 6.2.1 "@typescript-eslint/types": 6.2.0
"@typescript-eslint/typescript-estree": 6.2.1 "@typescript-eslint/typescript-estree": 6.2.0
"@typescript-eslint/visitor-keys": 6.2.1 "@typescript-eslint/visitor-keys": 6.2.0
debug: ^4.3.4 debug: ^4.3.4
peerDependencies: peerDependencies:
eslint: ^7.0.0 || ^8.0.0 eslint: ^7.0.0 || ^8.0.0
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: cf4768cbfc696ce1d4b15ae55b3d2b52761e91a4a80e738cf3a75c501c2257d735cd6e462567965069d0d693a8cf5463ab9e8b97c36c6ed1fccd3c1c09855bdb checksum: ba79674f2d4599a24c7afa8f18ec28243b80df39f82a4a6b7a4ce7c584ec37d4ade40a3aa058d597a5cbf71647a40d0995866748d14cf4b52d8ad4420d10f669
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/scope-manager@npm:6.2.1": "@typescript-eslint/scope-manager@npm:6.2.0":
version: 6.2.1 version: 6.2.0
resolution: "@typescript-eslint/scope-manager@npm:6.2.1" resolution: "@typescript-eslint/scope-manager@npm:6.2.0"
dependencies: dependencies:
"@typescript-eslint/types": 6.2.1 "@typescript-eslint/types": 6.2.0
"@typescript-eslint/visitor-keys": 6.2.1 "@typescript-eslint/visitor-keys": 6.2.0
checksum: 3bb461678c7e729895c5ac16781ec7d66efc6ffa944bb49693ce8e9560f9a6cac70929157c0fc0875b2829ae19a5cdabb97973ddcfb7e81c16e22cdd5d39e3fd checksum: 75a650a3ede78bf841a3bf3f4880b94a06aa4c420f399a6fb9faee19a2e5998f7e330a13f78e07c4958413345bab58b0593f09fa163a77e8f6353012e795660c
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/type-utils@npm:6.2.1": "@typescript-eslint/type-utils@npm:6.2.0":
version: 6.2.1 version: 6.2.0
resolution: "@typescript-eslint/type-utils@npm:6.2.1" resolution: "@typescript-eslint/type-utils@npm:6.2.0"
dependencies: dependencies:
"@typescript-eslint/typescript-estree": 6.2.1 "@typescript-eslint/typescript-estree": 6.2.0
"@typescript-eslint/utils": 6.2.1 "@typescript-eslint/utils": 6.2.0
debug: ^4.3.4 debug: ^4.3.4
ts-api-utils: ^1.0.1 ts-api-utils: ^1.0.1
peerDependencies: peerDependencies:
@ -1574,23 +1622,23 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: 7f8d80f03e6ddc1838307a2a4df61dc4bd8400efb9dcc7316063ae293fce54afad238404a0c25cd2cdaceee73ae514f254b850bd7ff11e2def700d5d6b90af05 checksum: 9adb542fb3c49bf5c1fecca98549bee3fcfd28a0ceee5227817a1ceb0841b912e322f58ba1b3ca98a47fc998cbec0a3d69cacb9cf9ac4be1d133b11bb9d53aae
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/types@npm:6.2.1": "@typescript-eslint/types@npm:6.2.0":
version: 6.2.1 version: 6.2.0
resolution: "@typescript-eslint/types@npm:6.2.1" resolution: "@typescript-eslint/types@npm:6.2.0"
checksum: 388d32f15a9db8ad5d80794caf9ab280d6e5a428efdf4f6a6dfc4069afe4d19da32d628acf638e4c5b92ee77a9a18eecf728a778a3b91cc8a24484af579fc9cf checksum: 81878866cf7f49dbc335cce05adfbd994f348e2ebe9538fd6e934fa82e44186c16b2112b8d5f9f4c528ea127be157185be5e35e4913db4880d20ac495785baaf
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/typescript-estree@npm:6.2.1": "@typescript-eslint/typescript-estree@npm:6.2.0":
version: 6.2.1 version: 6.2.0
resolution: "@typescript-eslint/typescript-estree@npm:6.2.1" resolution: "@typescript-eslint/typescript-estree@npm:6.2.0"
dependencies: dependencies:
"@typescript-eslint/types": 6.2.1 "@typescript-eslint/types": 6.2.0
"@typescript-eslint/visitor-keys": 6.2.1 "@typescript-eslint/visitor-keys": 6.2.0
debug: ^4.3.4 debug: ^4.3.4
globby: ^11.1.0 globby: ^11.1.0
is-glob: ^4.0.3 is-glob: ^4.0.3
@ -1599,34 +1647,34 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: 3d9beeb5e36b8827de5c160ed8e5c111dd66ca00671b183409b051e242b291480679b900bb74aaf4895dcae49497037567d3fcbbe67fa9930786ddd01c685f04 checksum: 5bfd5bf09feff6c4807cfa65cf407dd0249f7d487d6820941dd05999ee35cacdabaacadf23c92b90b57920025e93088e93924bc8df41f393ac0366538eb2902f
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/utils@npm:6.2.1": "@typescript-eslint/utils@npm:6.2.0":
version: 6.2.1 version: 6.2.0
resolution: "@typescript-eslint/utils@npm:6.2.1" resolution: "@typescript-eslint/utils@npm:6.2.0"
dependencies: dependencies:
"@eslint-community/eslint-utils": ^4.4.0 "@eslint-community/eslint-utils": ^4.4.0
"@types/json-schema": ^7.0.12 "@types/json-schema": ^7.0.12
"@types/semver": ^7.5.0 "@types/semver": ^7.5.0
"@typescript-eslint/scope-manager": 6.2.1 "@typescript-eslint/scope-manager": 6.2.0
"@typescript-eslint/types": 6.2.1 "@typescript-eslint/types": 6.2.0
"@typescript-eslint/typescript-estree": 6.2.1 "@typescript-eslint/typescript-estree": 6.2.0
semver: ^7.5.4 semver: ^7.5.4
peerDependencies: peerDependencies:
eslint: ^7.0.0 || ^8.0.0 eslint: ^7.0.0 || ^8.0.0
checksum: d16356a633f39d988a9af159da15e28c6a28fa47abce372061c79cf186d193d148e1c32862c9702ff87e2a06f7a2f82773e4b56320a39f432f4b1a989f8005ad checksum: 54f062412a8ce23554ca4063d275327981640426b1ecd1073d30dd8b9464ff7af68b8f9f6272033bad9307815d56f2f922faa8a995421efdccd6165dd62557e1
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/visitor-keys@npm:6.2.1": "@typescript-eslint/visitor-keys@npm:6.2.0":
version: 6.2.1 version: 6.2.0
resolution: "@typescript-eslint/visitor-keys@npm:6.2.1" resolution: "@typescript-eslint/visitor-keys@npm:6.2.0"
dependencies: dependencies:
"@typescript-eslint/types": 6.2.1 "@typescript-eslint/types": 6.2.0
eslint-visitor-keys: ^3.4.1 eslint-visitor-keys: ^3.4.1
checksum: c05a1c45129f2cf9a8c49dadc3da10b675232e59b69dfe9fdc0bfb45d3be077ceff78097baf50e502dab3e71ce9fd799d2015e356a4be2787ee10c6c7a44ea8a checksum: b400c657c7e5c65b289304f6f5cee6536f23b3441306f82aff2d2e047e13770330715d4f7b29e734b0b2dab6030e41028894d5cd441696115bfea43ad18b2c54
languageName: node languageName: node
linkType: hard linkType: hard
@ -3357,6 +3405,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"emnapi@npm:0.43.1":
version: 0.43.1
resolution: "emnapi@npm:0.43.1"
peerDependencies:
node-addon-api: ">= 6.1.0"
peerDependenciesMeta:
node-addon-api:
optional: true
checksum: 0b5940adaa8f165fdd3cdbc155d6514bd32b449732a0746bfb0dbd190816f16f942a59d32d3d9a978b391bf86df941496ef0c9502de94e10bd8ba79ea5afa730
languageName: node
linkType: hard
"emoji-regex@npm:^8.0.0": "emoji-regex@npm:^8.0.0":
version: 8.0.0 version: 8.0.0
resolution: "emoji-regex@npm:8.0.0" resolution: "emoji-regex@npm:8.0.0"
@ -3405,6 +3465,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"env-paths@npm:^3.0.0":
version: 3.0.0
resolution: "env-paths@npm:3.0.0"
checksum: b2b0a0d0d9931a13d279c22ed94d78648a1cc5f408f05d47ff3e0c1616f0aa0c38fb33deec5e5be50497225d500607d57f9c8652c4d39c2f2b7608cd45768128
languageName: node
linkType: hard
"envinfo@npm:7.8.1": "envinfo@npm:7.8.1":
version: 7.8.1 version: 7.8.1
resolution: "envinfo@npm:7.8.1" resolution: "envinfo@npm:7.8.1"
@ -3515,32 +3582,32 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"esbuild@npm:^0.19.0": "esbuild@npm:^0.19.5":
version: 0.19.0 version: 0.19.5
resolution: "esbuild@npm:0.19.0" resolution: "esbuild@npm:0.19.5"
dependencies: dependencies:
"@esbuild/android-arm": 0.19.0 "@esbuild/android-arm": 0.19.5
"@esbuild/android-arm64": 0.19.0 "@esbuild/android-arm64": 0.19.5
"@esbuild/android-x64": 0.19.0 "@esbuild/android-x64": 0.19.5
"@esbuild/darwin-arm64": 0.19.0 "@esbuild/darwin-arm64": 0.19.5
"@esbuild/darwin-x64": 0.19.0 "@esbuild/darwin-x64": 0.19.5
"@esbuild/freebsd-arm64": 0.19.0 "@esbuild/freebsd-arm64": 0.19.5
"@esbuild/freebsd-x64": 0.19.0 "@esbuild/freebsd-x64": 0.19.5
"@esbuild/linux-arm": 0.19.0 "@esbuild/linux-arm": 0.19.5
"@esbuild/linux-arm64": 0.19.0 "@esbuild/linux-arm64": 0.19.5
"@esbuild/linux-ia32": 0.19.0 "@esbuild/linux-ia32": 0.19.5
"@esbuild/linux-loong64": 0.19.0 "@esbuild/linux-loong64": 0.19.5
"@esbuild/linux-mips64el": 0.19.0 "@esbuild/linux-mips64el": 0.19.5
"@esbuild/linux-ppc64": 0.19.0 "@esbuild/linux-ppc64": 0.19.5
"@esbuild/linux-riscv64": 0.19.0 "@esbuild/linux-riscv64": 0.19.5
"@esbuild/linux-s390x": 0.19.0 "@esbuild/linux-s390x": 0.19.5
"@esbuild/linux-x64": 0.19.0 "@esbuild/linux-x64": 0.19.5
"@esbuild/netbsd-x64": 0.19.0 "@esbuild/netbsd-x64": 0.19.5
"@esbuild/openbsd-x64": 0.19.0 "@esbuild/openbsd-x64": 0.19.5
"@esbuild/sunos-x64": 0.19.0 "@esbuild/sunos-x64": 0.19.5
"@esbuild/win32-arm64": 0.19.0 "@esbuild/win32-arm64": 0.19.5
"@esbuild/win32-ia32": 0.19.0 "@esbuild/win32-ia32": 0.19.5
"@esbuild/win32-x64": 0.19.0 "@esbuild/win32-x64": 0.19.5
dependenciesMeta: dependenciesMeta:
"@esbuild/android-arm": "@esbuild/android-arm":
optional: true optional: true
@ -3588,7 +3655,7 @@ __metadata:
optional: true optional: true
bin: bin:
esbuild: bin/esbuild esbuild: bin/esbuild
checksum: 77ef2e57a94d1b88657fb6cd79c3ad6e3161823fd1b615f2ce4b71f163755b85e98cb5b565ed6c38db1f788c52c092b5534caa6800178de99a25de0671f92186 checksum: 5a0227cf6ffffa3076714d88230af1dfdd2fc363d91bd712a81fb91230c315a395e2c9b7588eee62986aeebf4999804b9b1b59eeab8e2457184eb0056bfe20c8
languageName: node languageName: node
linkType: hard linkType: hard
@ -6530,7 +6597,7 @@ __metadata:
c8: ^8.0.0 c8: ^8.0.0
cross-env: ^7.0.3 cross-env: ^7.0.3
electron: ^27.0.0 electron: ^27.0.0
esbuild: ^0.19.0 esbuild: ^0.19.5
eslint: ^8.45.0 eslint: ^8.45.0
eslint-config-prettier: ^9.0.0 eslint-config-prettier: ^9.0.0
eslint-plugin-import: ^2.27.5 eslint-plugin-import: ^2.27.5
@ -8903,6 +8970,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"toml@npm:^3.0.0":
version: 3.0.0
resolution: "toml@npm:3.0.0"
checksum: 5d7f1d8413ad7780e9bdecce8ea4c3f5130dd53b0a4f2e90b93340979a137739879d7b9ce2ce05c938b8cc828897fe9e95085197342a1377dd8850bf5125f15f
languageName: node
linkType: hard
"tr46@npm:~0.0.3": "tr46@npm:~0.0.3":
version: 0.0.3 version: 0.0.3
resolution: "tr46@npm:0.0.3" resolution: "tr46@npm:0.0.3"
@ -8987,7 +9061,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.4.0, tslib@npm:^2.6.0": "tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.4.0, tslib@npm:^2.6.0, tslib@npm:^2.6.1":
version: 2.6.1 version: 2.6.1
resolution: "tslib@npm:2.6.1" resolution: "tslib@npm:2.6.1"
checksum: b0d176d176487905b66ae4d5856647df50e37beea7571c53b8d10ba9222c074b81f1410fb91da13debaf2cbc970663609068bdebafa844ea9d69b146527c38fe checksum: b0d176d176487905b66ae4d5856647df50e37beea7571c53b8d10ba9222c074b81f1410fb91da13debaf2cbc970663609068bdebafa844ea9d69b146527c38fe