Lumera Cascade
Guides

Node.js Environment

Current status, known limitations, and workarounds for using the Lumera SDK in Node.js.

Known Issue: The Lumera JS SDK currently has compatibility issues in Node.js environments. The browser environment is the recommended target for production applications. This page documents the current state and available workarounds.

The Problem

The SDK relies on several WASM modules that behave differently in Node.js vs browser environments:

ModuleBrowserNode.js
rq-library-wasm (RaptorQ)Works via ESM WASM importFails — createRequire + WASM file path resolution issues
@bokuweb/zstd-wasm (Zstd)Works via WASM loaderWorks via @mongodb-js/zstd native binding
blake3Works via blake3/browser-asyncWorks via native binding

The primary failure point is the RaptorQ WASM proxy (raptorq-proxy.node.ts), which uses createRequire to load the WASM binary from disk. In some environments (bundlers, ESM-only projects, certain Node.js configurations), this fails to locate or instantiate the WASM file.

Additionally, the RaptorQ WASM module expects a window global, which the SDK polyfills:

if (typeof (globalThis as any).window === "undefined") {
  (globalThis as any).window = globalThis;
}

This polyfill can cause side effects with other libraries that check for window to detect browser environments.

What Works in Node.js

Despite the RaptorQ issue, several SDK operations work in Node.js:

  • Client creation: createLumeraClient() connects to RPC and LCD endpoints
  • Blockchain queries: client.Blockchain.getAction(), getActionParams(), etc.
  • Downloads: client.Cascade.downloader.download() — downloading does not require RaptorQ encoding
  • Signing: DirectSecp256k1HdWallet works for all signing operations

What Does Not Work

  • Uploads: The full upload pipeline requires RaptorQ layout generation, which depends on the WASM module
  • Specifically, client.Cascade.uploader.uploadFile() and client.Cascade.uploader.registerAction() fail at the layout generation step

Workarounds

Build your application as a browser SPA or SSR app where Cascade operations run client-side:

┌──────────────┐     ┌──────────────┐     ┌─────────────┐
│   Browser    │────▶│  Lumera SDK  │────▶│  Cascade    │
│   (Vite/CRA) │     │  (works!)    │     │  (SN-API)   │
└──────────────┘     └──────────────┘     └─────────────┘

       │ API calls (metadata only)

┌──────────────┐
│  Your API    │
│  (Node.js)   │
│  (no Cascade)│
└──────────────┘

Your Node.js backend handles business logic, databases, and authentication. The browser frontend handles all Cascade interactions directly.

2. Source Code Patching

If you need Node.js uploads (e.g., for a CLI tool or backend service), you can fork @lumera-protocol/sdk-js and patch the WASM loading:

git clone https://github.com/LumeraProtocol/sdk-js.git
cd sdk-js

The key file to modify is src/wasm/raptorq-proxy.node.ts. The issue is typically in how the WASM binary path is resolved. Potential fixes:

  1. Inline the WASM as base64: Convert the .wasm file to a base64 string and load it via WebAssembly.instantiate
  2. Use an absolute path: Replace the createRequire approach with a known absolute path to the WASM file
  3. Use the browser WASM loader in Node.js: Force the browser import path which uses standard ESM WASM imports

After patching, build the SDK locally:

npm run build
npm link
# In your project:
npm link @lumera-protocol/sdk-js

3. Use the Go or Rust SDK

For server-side applications, the Go and Rust SDKs have full Node/server compatibility without WASM issues:

Go SDK:

import "github.com/LumeraProtocol/sdk-go/client"
 
cfg := &client.Config{
    ChainID:     "lumera-testnet-2",
    GRPCAddress: "grpc.testnet.lumera.io:443",
    RPCAddress:  "https://rpc.testnet.lumera.io",
    SnApiURL:    "https://snapi.testnet.lumera.io",
}
 
c, err := client.New(cfg)
// Full upload and download support

Rust SDK:

[dependencies]
lumera-sdk-rs = "0.1"

4. Download-Only Node.js Service

If your Node.js service only needs to read files from Cascade (not upload), the SDK works without issues:

download-service.ts
import { createLumeraClient } from "@lumera-protocol/sdk-js";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
 
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(
  process.env.LUMERA_MNEMONIC!,
  { prefix: "lumera" }
);
const [account] = await wallet.getAccounts();
 
const client = await createLumeraClient({
  preset: "testnet",
  signer: wallet,
  address: account.address,
  gasPrice: "0.025ulume",
});
 
// This works in Node.js!
const stream = await client.Cascade.downloader.download("your-action-id");
const reader = stream.getReader();
const chunks: Uint8Array[] = [];
 
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  if (value) chunks.push(value);
}

Current Status

The Lumera team is actively working on improving Node.js compatibility. Track progress at LumeraProtocol/sdk-js.

If you encounter issues or find workarounds, please contribute to the SDK repository or report them on the Lumera Discord.

Next Steps

On this page