Describe the bug
@skalenetwork/t-encrypt@0.8.0-develop.0 (used by @skalenetwork/bite@0.8.0-develop.0 and implemented by #37 and #38 ) embeds WASM as a base64 data URI and compiles it dynamically at runtime via WebAssembly.instantiate(binary, imports). This fails in Cloudflare Workers because the runtime blocks dynamic WASM compilation for security reasons (same policy as
eval()).
The error:
CompileError: WebAssembly.instantiate(): Wasm code generation disallowed by embedder
The relevant code path in t-encrypt/encrypt.js (minified):
// 1. WASM is embedded as base64 data URI
var wasmBinaryFile = "data:application/octet-stream;base64,AGFzbQ...";
// 2. At runtime, it decodes the base64 into a buffer
var binary = base64Decode(filename.slice(dataURIPrefix.length));
// 3. Then tries dynamic compilation — this is what Workers blocks
var instance = await WebAssembly.instantiate(binary, imports);
Cloudflare Workers only allows WASM that is imported as a static module at build time, so bundlers (esbuild/wrangler) can pre-compile it during deploy.
To Reproduce
- Install
@skalenetwork/bite@0.8.0-develop.0
- Create a Cloudflare Worker that imports and uses
BITE:
import { BITE } from '@skalenetwork/bite';
export default {
async fetch(req: Request): Promise<Response> {
const bite = new BITE('https://hackathon-sandbox.skale.network');
const encrypted = await bite.encryptTransaction({
to: '0x...',
data: '0x...',
gasLimit: '0x15f90',
});
return Response.json(encrypted);
},
};
- Configure
wrangler.jsonc with "compatibility_flags": ["nodejs_compat"]
- Deploy with
wrangler deploy
- Call the worker → error:
Wasm code generation disallowed by embedder
Expected behavior
@skalenetwork/t-encrypt should work in Cloudflare Workers. The 0.8.0 release halved the WASM from 5.8MB to 2.7MB, which is ok within Workers' 10MB limit (and 3MB for free plans) — but the dynamic instantiation pattern prevents it from running there.
Suggested fix
Ship the WASM as a separate .wasm file alongside the JS entry point instead of base64-embedding it. This allows bundlers to handle it as a static asset:
// What bundlers (esbuild, webpack, wrangler) can handle:
import wasmModule from './encrypt.wasm';
// Then instantiate from the pre-compiled module:
const instance = await WebAssembly.instantiate(wasmModule, imports);
Emscripten supports this via the -sSINGLE_FILE=0 flag (which is actually the default — -sSINGLE_FILE=1 is what embeds base64). The build should:
- Remove
-sSINGLE_FILE=1 from the Emscripten build flags so WASM is emitted as a separate file
- Export the
.wasm file in the package's exports/files field
- Optionally support the
Module.instantiateWasm callback so consumers can provide a pre-compiled module
This would make t-encrypt compatible with Cloudflare Workers, Vercel Edge Functions, Deno Deploy, and any other edge runtime that restricts dynamic WASM compilation.
Environment
@skalenetwork/bite: 0.8.0-develop.0
@skalenetwork/t-encrypt: 0.8.0-develop.0
- Runtime: Cloudflare Workers with
nodejs_compat
- Bundler: wrangler 4.x (esbuild)
Additional context
We also hit a secondary issue: the Emscripten code references __dirname when process.versions.node is truthy (which it is under Workers' nodejs_compat). We shimmed that with globalThis.__dirname = '', but the WASM compilation block is the real blocker. Fixing the WASM loading would likely resolve the __dirname issue too,
since the Node.js code path that uses __dirname is only needed for loading WASM from the filesystem.
Describe the bug
@skalenetwork/t-encrypt@0.8.0-develop.0(used by@skalenetwork/bite@0.8.0-develop.0and implemented by #37 and #38 ) embeds WASM as a base64 data URI and compiles it dynamically at runtime viaWebAssembly.instantiate(binary, imports). This fails in Cloudflare Workers because the runtime blocks dynamic WASM compilation for security reasons (same policy aseval()).The error:
The relevant code path in
t-encrypt/encrypt.js(minified):Cloudflare Workers only allows WASM that is imported as a static module at build time, so bundlers (esbuild/wrangler) can pre-compile it during deploy.
To Reproduce
@skalenetwork/bite@0.8.0-develop.0BITE:wrangler.jsoncwith"compatibility_flags": ["nodejs_compat"]wrangler deployWasm code generation disallowed by embedderExpected behavior
@skalenetwork/t-encryptshould work in Cloudflare Workers. The 0.8.0 release halved the WASM from 5.8MB to 2.7MB, which is ok within Workers' 10MB limit (and 3MB for free plans) — but the dynamic instantiation pattern prevents it from running there.Suggested fix
Ship the WASM as a separate
.wasmfile alongside the JS entry point instead of base64-embedding it. This allows bundlers to handle it as a static asset:Emscripten supports this via the
-sSINGLE_FILE=0flag (which is actually the default —-sSINGLE_FILE=1is what embeds base64). The build should:-sSINGLE_FILE=1from the Emscripten build flags so WASM is emitted as a separate file.wasmfile in the package'sexports/filesfieldModule.instantiateWasmcallback so consumers can provide a pre-compiled moduleThis would make t-encrypt compatible with Cloudflare Workers, Vercel Edge Functions, Deno Deploy, and any other edge runtime that restricts dynamic WASM compilation.
Environment
@skalenetwork/bite:0.8.0-develop.0@skalenetwork/t-encrypt:0.8.0-develop.0nodejs_compatAdditional context
We also hit a secondary issue: the Emscripten code references
__dirnamewhenprocess.versions.nodeis truthy (which it is under Workers'nodejs_compat). We shimmed that withglobalThis.__dirname = '', but the WASM compilation block is the real blocker. Fixing the WASM loading would likely resolve the__dirnameissue too,since the Node.js code path that uses
__dirnameis only needed for loading WASM from the filesystem.