pack wasm

This commit is contained in:
thesimplekid
2023-10-02 21:35:10 +01:00
parent 66cdd149cb
commit cbe16b5420
11 changed files with 171 additions and 7 deletions

View File

@@ -20,6 +20,9 @@ serde_json.workspace = true
serde.workspace = true
wasm-bindgen = { version = "0.2.87", features = ["serde-serialize"] }
wasm-bindgen-futures = "0.4.37"
console_error_panic_hook = "0.1"
[package.metadata.wasm-pack.profile.release]
wasm-opt = true

View File

@@ -1,5 +1,12 @@
const Amount = require("../");
const {Amount, loadWasmAsync, loadWasmSync } = require("..");
let amount = Amount.fromSat(10);
console.log(amount)
function main() {
loadWasmSync();
let amount = Amount.fromSat(BigInt(10));
console.log(amount.toSat())
}
main();

View File

@@ -2,4 +2,4 @@ build:
wasm-pack build
pack:
wasm-pack pack
npm run package

View File

@@ -37,5 +37,8 @@
"node": ">= 10"
},
"scripts": {
"build": "WASM_PACK_ARGS=--release ./scripts/build.sh",
"build:dev": "WASM_PACK_ARGS=--dev ./scripts/build.sh",
"package": "npm run build && npm pack"
}
}

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022-2023 Yuki Kishimoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,35 @@
#!/bin/bash
#
# Build the JavaScript modules
#
# This script is really a workaround for https://github.com/rustwasm/wasm-pack/issues/1074.
#
# Currently, the only reliable way to load WebAssembly in all the JS
# environments we want to target (web-via-webpack, web-via-browserify, jest)
# seems to be to pack the WASM into base64, and then unpack it and instantiate
# it at runtime.
#
# Hopefully one day, https://github.com/rustwasm/wasm-pack/issues/1074 will be
# fixed and this will be unnecessary.
set -e
cd $(dirname "$0")/..
WASM_BINDGEN_WEAKREF=1 wasm-pack build --target nodejs --scope rust-cashu --out-dir pkg "${WASM_PACK_ARGS[@]}"
# Convert the Wasm into a JS file that exports the base64'ed Wasm.
echo "module.exports = \`$(base64 pkg/cashu_js_bg.wasm)\`;" > pkg/cashu_js_bg.wasm.js
# In the JavaScript:
# 1. Strip out the lines that load the WASM, and our new epilogue.
# 2. Remove the imports of `TextDecoder` and `TextEncoder`. We rely on the global defaults.
{
sed -e '/Text..coder.*= require(.util.)/d' \
-e '/^const path = /,$d' pkg/cashu_js.js
cat scripts/epilogue.js
} > pkg/cashu_js.js.new
mv pkg/cashu_js.js.new pkg/cashu_js.js
# also extend the typescript
cat scripts/epilogue.d.ts >> pkg/cashu_js.d.ts

10
bindings/cashu-js/scripts/epilogue.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
/**
* Load the WebAssembly module in the background, if it has not already been loaded.
*
* Returns a promise which will resolve once the other methods are ready.
*
* @returns {Promise<void>}
*/
export function loadWasmAsync(): Promise<void>;
export function loadWasmSync(): void;

View File

@@ -0,0 +1,76 @@
let inited = false;
module.exports.loadWasmSync = function () {
if (inited) {
return;
}
if (initPromise) {
throw new Error("Asynchronous initialisation already in progress: cannot initialise synchronously");
}
const bytes = unbase64(require("./cashu_js_bg.wasm.js"));
const mod = new WebAssembly.Module(bytes);
const instance = new WebAssembly.Instance(mod, imports);
wasm = instance.exports;
wasm.__wbindgen_start();
inited = true;
};
let initPromise = null;
/**
* Load the WebAssembly module in the background, if it has not already been loaded.
*
* Returns a promise which will resolve once the other methods are ready.
*
* @returns {Promise<void>}
*/
module.exports.loadWasmAsync = function () {
if (inited) {
return Promise.resolve();
}
if (!initPromise) {
initPromise = Promise.resolve()
.then(() => require("./cashu_js_bg.wasm.js"))
.then((b64) => WebAssembly.instantiate(unbase64(b64), imports))
.then((result) => {
wasm = result.instance.exports;
wasm.__wbindgen_start();
inited = true;
});
}
return initPromise;
};
const b64lookup = new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 62, 0, 62, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
]);
// base64 decoder, based on the code at https://developer.mozilla.org/en-US/docs/Glossary/Base64#solution_2_%E2%80%93_rewriting_atob_and_btoa_using_typedarrays_and_utf-8
function unbase64(sBase64) {
const sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, "");
const nInLen = sB64Enc.length;
const nOutLen = (nInLen * 3 + 1) >> 2;
const taBytes = new Uint8Array(nOutLen);
let nMod3;
let nMod4;
let nUint24 = 0;
let nOutIdx = 0;
for (let nInIdx = 0; nInIdx < nInLen; nInIdx++) {
nMod4 = nInIdx & 3;
nUint24 |= b64lookup[sB64Enc.charCodeAt(nInIdx)] << (6 * (3 - nMod4));
if (nMod4 === 3 || nInLen - nInIdx === 1) {
nMod3 = 0;
while (nMod3 < 3 && nOutIdx < nOutLen) {
taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255;
nMod3++;
nOutIdx++;
}
nUint24 = 0;
}
}
return taBytes;
}

View File

@@ -1,3 +1,12 @@
use wasm_bindgen::prelude::*;
pub mod error;
pub mod nuts;
pub mod types;
pub use types::JsAmount;
#[wasm_bindgen(start)]
pub fn start() {
console_error_panic_hook::set_once();
}

View File

@@ -26,9 +26,9 @@ impl From<Amount> for JsAmount {
#[wasm_bindgen(js_class = Amount)]
impl JsAmount {
#[wasm_bindgen(constructor)]
pub fn new(sats: u64) -> Self {
pub fn new(sats: u32) -> Self {
Self {
inner: Amount::from_sat(sats),
inner: Amount::from_sat(sats as u64),
}
}

View File

@@ -3,7 +3,7 @@
"strict": true
},
"typedocOptions": {
"entryPoints": ["pkg/nostr_js.d.ts"],
"entryPoints": ["pkg/cashu_js.d.ts"],
"readme": "README.md"
}
}