wasm-rquickjs 0.3.3

Tool for wrapping JavaScript modules as WebAssembly components using the QuickJS engine
Documentation
use rand::RngCore;
use rquickjs::TypedArray;
use std::slice;

fn randomize_typed_array<V>(array: TypedArray<V>) {
    if let Some(raw) = array.as_raw() {
        let slice = unsafe { slice::from_raw_parts_mut(raw.ptr.as_ptr(), raw.len) };
        rand::rng().fill_bytes(slice);
    }
}

#[rquickjs::module(rename_vars = "camelCase")]
pub mod native_module {
    use rquickjs::TypedArray;

    #[rquickjs::function]
    pub fn random_uuid_v4_string() -> String {
        let uuid = uuid::Uuid::new_v4();
        uuid.to_string()
    }

    #[rquickjs::function]
    pub fn random_bytes(len: u32) -> Vec<u8> {
        use rand::RngCore;
        let mut buf = vec![0u8; len as usize];
        rand::rng().fill_bytes(&mut buf);
        buf
    }

    #[rquickjs::function]
    pub fn random_int_range(min: f64, max: f64) -> Option<f64> {
        use rand::RngCore;
        let min_i = min as i64;
        let max_i = max as i64;
        if min_i >= max_i {
            return None;
        }
        let range = (max_i - min_i) as u64;
        let mut buf = [0u8; 8];
        rand::rng().fill_bytes(&mut buf);
        let random_val = u64::from_le_bytes(buf);
        let result = min_i + (random_val % range) as i64;
        Some(result as f64)
    }

    #[rquickjs::function]
    pub fn randomize_int8_array(array: TypedArray<'_, i8>) {
        super::randomize_typed_array(array);
    }

    #[rquickjs::function]
    pub fn randomize_uint8_array(array: TypedArray<'_, u8>) {
        super::randomize_typed_array(array);
    }

    #[rquickjs::function]
    pub fn randomize_uint8_clamped_array(array: TypedArray<'_, u8>) {
        super::randomize_typed_array(array);
    }

    #[rquickjs::function]
    pub fn randomize_int16_array(array: TypedArray<'_, i16>) {
        super::randomize_typed_array(array);
    }

    #[rquickjs::function]
    pub fn randomize_uint16_array(array: TypedArray<'_, u16>) {
        super::randomize_typed_array(array);
    }

    #[rquickjs::function]
    pub fn randomize_int32_array(array: TypedArray<'_, i32>) {
        super::randomize_typed_array(array);
    }

    #[rquickjs::function]
    pub fn randomize_uint32_array(array: TypedArray<'_, u32>) {
        super::randomize_typed_array(array);
    }

    #[rquickjs::function]
    pub fn randomize_bigint64_array(array: TypedArray<'_, i64>) {
        super::randomize_typed_array(array);
    }

    #[rquickjs::function]
    pub fn randomize_biguint64_array(array: TypedArray<'_, u64>) {
        super::randomize_typed_array(array);
    }
}

pub const WEB_CRYPTO_JS: &str = r#"
import {
  randomUuidV4String,
  randomBytes,
  randomIntRange,
  randomizeInt8Array,
  randomizeUint8Array,
  randomizeUint8ClampedArray,
  randomizeInt16Array,
  randomizeUint16Array,
  randomizeInt32Array,
  randomizeUint32Array,
  randomizeBigint64Array,
  randomizeBiguint64Array,
} from '__wasm_rquickjs_builtin/web_crypto_native';

function getRandomValues(array) {
  if (!(array instanceof ArrayBuffer) && !ArrayBuffer.isView(array)) {
    throw new TypeError('The argument must be a TypedArray');
  }
  if (array instanceof Float32Array || array instanceof Float64Array) {
    throw new DOMException('Float typed arrays are not supported', 'TypeMismatchError');
  }
  if (array.byteLength > 65536) {
    throw new DOMException('The ArrayBufferView byte length exceeds the limit (65536)', 'QuotaExceededError');
  }
  if (array instanceof Int8Array) randomizeInt8Array(array);
  else if (array instanceof Uint8ClampedArray) randomizeUint8ClampedArray(array);
  else if (array instanceof Uint8Array) randomizeUint8Array(array);
  else if (array instanceof Int16Array) randomizeInt16Array(array);
  else if (array instanceof Uint16Array) randomizeUint16Array(array);
  else if (array instanceof Int32Array) randomizeInt32Array(array);
  else if (array instanceof Uint32Array) randomizeUint32Array(array);
  else if (typeof BigInt64Array !== 'undefined' && array instanceof BigInt64Array) randomizeBigint64Array(array);
  else if (typeof BigUint64Array !== 'undefined' && array instanceof BigUint64Array) randomizeBiguint64Array(array);
  return array;
}

function randomUUID() {
  return randomUuidV4String();
}

export { getRandomValues, randomUUID };
export default { getRandomValues, randomUUID };
"#;

pub const REEXPORT_JS: &str = r#"
const msg = 'node:crypto is not available (crypto feature is not enabled)';
function notAvailable() { throw new Error(msg); }
export const createHash = notAvailable;
export const createHmac = notAvailable;
export const createCipheriv = notAvailable;
export const createDecipheriv = notAvailable;
export const createSign = notAvailable;
export const createVerify = notAvailable;
export const createDiffieHellman = notAvailable;
export const createDiffieHellmanGroup = notAvailable;
export const createECDH = notAvailable;
export const getDiffieHellman = notAvailable;
export const pbkdf2 = notAvailable;
export const pbkdf2Sync = notAvailable;
export const scrypt = notAvailable;
export const scryptSync = notAvailable;
export const hkdf = notAvailable;
export const hkdfSync = notAvailable;
export const randomBytes = notAvailable;
export const randomInt = notAvailable;
export const randomFillSync = notAvailable;
export const randomFill = notAvailable;
export const randomUUID = notAvailable;
export const generateKey = notAvailable;
export const generateKeySync = notAvailable;
export const generateKeyPair = notAvailable;
export const generateKeyPairSync = notAvailable;
export const getHashes = notAvailable;
export const getCiphers = notAvailable;
export const getCurves = notAvailable;
export const timingSafeEqual = notAvailable;
export const constants = {};
export default { createHash, createHmac, createCipheriv, createDecipheriv, createSign, createVerify, createDiffieHellman, createDiffieHellmanGroup, createECDH, getDiffieHellman, pbkdf2, pbkdf2Sync, scrypt, scryptSync, hkdf, hkdfSync, randomBytes, randomInt, randomFillSync, randomFill, randomUUID, generateKey, generateKeySync, generateKeyPair, generateKeyPairSync, getHashes, getCiphers, getCurves, timingSafeEqual, constants };
"#;

pub const WIRE_JS: &str = r#"
        import * as __wasm_rquickjs_web_crypto from '__wasm_rquickjs_builtin/web_crypto';
        globalThis.crypto = __wasm_rquickjs_web_crypto;
    "#;