Node.js SDK for the public Starshine storage node. Cryptography stays in your process (HPKE, Reed–Solomon, PoRep, BAO, ML-DSA-65). The node never receives private keys or plaintext.
Requires Node 22+. This package is Node-only (@grpc/grpc-js); it is not a browser bundle.
git clone https://github.com/VoidCommandCenter/starshine-js-api.git
cd starshine-js-api
npm install
npm startThat generates keys.json, claims 100,000,000 VOID from the faucet, uploads a small blob, and downloads it again from the public Railway node:
| gRPC URL | http://maglev.proxy.rlwy.net:27561 |
| Protocol | Plain gRPC (HTTP/2), no TLS |
Do not use the Railway HTTP domain (*.up.railway.app) for gRPC. Override the endpoint with STARSHINE_SERVER if you run your own node.
Keep keys.json private. It holds HPKE, PoRep, and ML-DSA-65 secrets.
npm install github:VoidCommandCenter/starshine-js-apiimport { Starshine } from "starshine-js-api";
const ss = await Starshine.connect(); // public node
await ss.saveWallet("./keys.json");
await ss.faucet();
const put = await ss.put(Buffer.from("hello starshine"), { fileName: "hello.txt" });
const got = await ss.get(put.contentHash);
await ss.delete(put.contentHash);Load an existing wallet:
const ss = await Starshine.connect({ keys: "./keys.json" });put / get / delete pay VOID by default. Pass { pay: false } only for unpaid tests. 1 VOID = 1 aggregate shard byte stored or retrieved.
await Starshine.connect({
server?: string; // default STARSHINE_SERVER or the public Railway node
keys?: WalletFile | string;
dataShards?: number; // default 4
parityShards?: number; // default 2
});| Method | Returns | Notes |
|---|---|---|
saveWallet(path) |
void |
Writes JSON (mode 0600 on Unix) |
account() |
{ publicKey, balance, transactions, … } |
Void.GetAccount |
faucet() |
account | Credits 100,000,000 VOID |
transfer(toHpkeHex, amount) |
account | Void.Transfer |
transactions(limit?) |
tx[] | Node-wide Void.ListTransactions |
put(bytes, { fileName, pay, dataShards, parityShards }) |
{ contentHash, storedBytes, ledger } |
Seal locally, then Storage.Put |
get(hash, { fileName, pay, minimumShards }) |
{ plaintext, servedBytes, ledger } |
Default minimumShards: true |
delete(hash, { fileName, pay }) |
{ contentHash, ledger } |
Storage.Delete |
hash is 64 hex digits or a 32-byte Uint8Array. Content hashes are per upload, not per file bytes.
ledger is { balance, txId, amount } when the call was paid.
Errors: InsufficientVoidError (need, have), SignedVoidExceededError, or Error with the gRPC message (missing blob, bad signature, nonce replay).
{
"version": 2,
"hpke_public_key_hex": "…",
"hpke_private_key_hex": "…",
"porep_secret_hex": "…",
"mldsa_public_key_hex": "…",
"mldsa_private_key_hex": "…"
}Helpers: generateWallet(), loadWallet(path), saveWallet(path, wallet).
Sealed Put payloads are much larger than plaintext. The public node and this client default to 1 GiB (STARSHINE_MAX_PUT_BYTES).
npm run typecheck
npm testsrc/api.e2e.test.ts hits STARSHINE_SERVER (default: the public Railway node).
- The public endpoint has no API key. Anyone who can reach it can call Storage and Void.
- No TLS on the TCP proxy. Traffic is unencrypted in transit.
Getreturnsenc_keyand sealed shards. Treat content hashes as capabilities.- Keep HPKE, PoRep, and ML-DSA-65 private keys on the client.
Protocol and Rust node: starshine.