@veilux/sdk 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # @veilux/sdk
2
+
3
+ TypeScript/JavaScript SDK for [VEILUX](https://github.com/VeiluxLabs/Veilux-Binary).
4
+ Build, sign, and submit commands to a VEILUX node from Node.js or the browser.
5
+
6
+ Signing (Ed25519) and hashing (BLAKE3) are **byte-compatible with the Rust
7
+ node**, so signatures produced here verify on-chain.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @veilux/sdk
13
+ ```
14
+
15
+ ## Quick start
16
+
17
+ ```ts
18
+ import { Client, PartyIdentity, builders, hashCommit, toHex } from "@veilux/sdk";
19
+
20
+ const client = new Client("http://127.0.0.1:8645");
21
+
22
+ // 32-byte seed (use real entropy in production)
23
+ const alice = PartyIdentity.fromSeed("alice", new Uint8Array(32).fill(1));
24
+
25
+ const info = await client.nodeInfo();
26
+ console.log("height", info.height, "prisms", info.prisms);
27
+
28
+ // Create a token
29
+ const create = builders.tokenCreate(
30
+ "alice", "Public", 0, "Gold Coin", "GLD", 18, 1_000_000n, true,
31
+ );
32
+ const res = await client.submit(alice.sign(create));
33
+ console.log("accepted", res.accepted);
34
+
35
+ // Transfer (token id is derived the same way the node does)
36
+ const te = new TextEncoder();
37
+ const tokenId = toHex(hashCommit("token/id",
38
+ [te.encode("alice"), te.encode("GLD"), te.encode("Gold Coin")]));
39
+ await client.submit(alice.sign(
40
+ builders.tokenTransfer("alice", "Public", 1, tokenId, "bob", 250_000n)));
41
+
42
+ // Read state
43
+ const bal = await client.getState(`token/bal/${tokenId}/bob`);
44
+ console.log("bob:", Buffer.from(bal.value_hex, "hex").toString());
45
+ ```
46
+
47
+ ## API
48
+
49
+ ### `PartyIdentity`
50
+ - `PartyIdentity.fromSeed(party, seed: Uint8Array)` — 32-byte seed
51
+ - `PartyIdentity.fromPassphrase(party, passphrase)` — dev convenience
52
+ - `PartyIdentity.generate(party)` — random
53
+ - `id.publicKey(): Uint8Array`
54
+ - `id.sign(command): SignedCommand`
55
+
56
+ ### `Client`
57
+ - `nodeInfo()`, `blockNumber()`, `blockByNumber(h)`, `getState(key)`
58
+ - `estimate(signed)`, `submit(signed)`
59
+
60
+ ### `builders`
61
+ - `tokenCreate`, `tokenTransfer`
62
+ - `nftCreateCollection`
63
+ - `storagePut`
64
+ - `contractDeploy`, `contractCall`
65
+
66
+ ### Encoding helpers
67
+ - `signingBytes(command)`, `commandId(command)`, `hashCommit(domain, parts)`, `toHex(bytes)`
68
+
69
+ ## Compatibility notes
70
+
71
+ - `Hash`-typed command fields (token id, contract address) are byte arrays on
72
+ the wire; the builders convert hex for you.
73
+ - Token amounts are `u128` and serialized as decimal strings.
74
+ - `Visibility` is `"Public"` or `{ Parties: ["alice", ...] }`.
75
+
76
+ ## License
77
+
78
+ MIT
@@ -0,0 +1,7 @@
1
+ import type { Command, PartyId, Visibility } from "./types.js";
2
+ export declare function tokenCreate(submitter: PartyId, visibility: Visibility, nonce: number, name: string, symbol: string, decimals: number, initialSupply: bigint | number | string, mintable: boolean): Command;
3
+ export declare function tokenTransfer(submitter: PartyId, visibility: Visibility, nonce: number, tokenIdHex: string, to: PartyId, amount: bigint | number | string): Command;
4
+ export declare function nftCreateCollection(submitter: PartyId, visibility: Visibility, nonce: number, name: string, symbol: string, maxSupply: number | null): Command;
5
+ export declare function storagePut(submitter: PartyId, visibility: Visibility, nonce: number, key: string, data: Uint8Array | number[]): Command;
6
+ export declare function contractDeploy(submitter: PartyId, visibility: Visibility, nonce: number, code: Uint8Array | number[]): Command;
7
+ export declare function contractCall(submitter: PartyId, visibility: Visibility, nonce: number, addressHex: string, args: number[], value: number, gasLimit: number): Command;
@@ -0,0 +1,73 @@
1
+ const enc = new TextEncoder();
2
+ /** Encode a prism command object as the kernel `payload` byte array. */
3
+ function payloadOf(obj) {
4
+ return Array.from(enc.encode(JSON.stringify(obj)));
5
+ }
6
+ /**
7
+ * Convert a `0x`-prefixed (or bare) hex hash to a 32-number array, because the
8
+ * Rust `Hash(pub [u8;32])` newtype serializes as a JSON array of bytes — not a
9
+ * hex string. Hash-typed command fields must use this.
10
+ */
11
+ function hashBytes(hex) {
12
+ const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
13
+ if (clean.length !== 64)
14
+ throw new Error(`hash must be 32 bytes (64 hex chars), got ${clean.length}`);
15
+ const out = [];
16
+ for (let i = 0; i < 64; i += 2)
17
+ out.push(parseInt(clean.slice(i, i + 2), 16));
18
+ return out;
19
+ }
20
+ function cmd(prism, submitter, visibility, nonce, payloadObj) {
21
+ return { prism, submitter, visibility, payload: payloadOf(payloadObj), nonce };
22
+ }
23
+ // ---- Token Prism (amounts are decimal strings, matching Rust u128 serde) ----
24
+ export function tokenCreate(submitter, visibility, nonce, name, symbol, decimals, initialSupply, mintable) {
25
+ return cmd("token", submitter, visibility, nonce, {
26
+ op: "create",
27
+ name,
28
+ symbol,
29
+ decimals,
30
+ initial_supply: String(initialSupply),
31
+ mintable,
32
+ });
33
+ }
34
+ export function tokenTransfer(submitter, visibility, nonce, tokenIdHex, to, amount) {
35
+ return cmd("token", submitter, visibility, nonce, {
36
+ op: "transfer",
37
+ token_id: hashBytes(tokenIdHex),
38
+ to,
39
+ amount: String(amount),
40
+ });
41
+ }
42
+ // ---- NFT Prism ----
43
+ export function nftCreateCollection(submitter, visibility, nonce, name, symbol, maxSupply) {
44
+ return cmd("nft", submitter, visibility, nonce, {
45
+ op: "create_collection",
46
+ name,
47
+ symbol,
48
+ max_supply: maxSupply,
49
+ });
50
+ }
51
+ // ---- Storage Prism ----
52
+ export function storagePut(submitter, visibility, nonce, key, data) {
53
+ return cmd("storage", submitter, visibility, nonce, {
54
+ key,
55
+ data: Array.from(data),
56
+ });
57
+ }
58
+ // ---- Contract Prism (PhotonVM) ----
59
+ export function contractDeploy(submitter, visibility, nonce, code) {
60
+ return cmd("contract", submitter, visibility, nonce, {
61
+ op: "deploy",
62
+ code: Array.from(code),
63
+ });
64
+ }
65
+ export function contractCall(submitter, visibility, nonce, addressHex, args, value, gasLimit) {
66
+ return cmd("contract", submitter, visibility, nonce, {
67
+ op: "call",
68
+ address: hashBytes(addressHex),
69
+ args,
70
+ value,
71
+ gas_limit: gasLimit,
72
+ });
73
+ }
@@ -0,0 +1,31 @@
1
+ import { type BlockView, type EstimateResult, type NodeInfo, type SignedCommand, type StateResult, type SubmitResult } from "./types.js";
2
+ export declare class RpcClientError extends Error {
3
+ code: number;
4
+ constructor(code: number, message: string);
5
+ }
6
+ /** A JSON-RPC client for a VEILUX node. Uses the global `fetch`. */
7
+ export declare class Client {
8
+ private readonly endpoint;
9
+ private id;
10
+ constructor(endpoint: string);
11
+ private call;
12
+ nodeInfo(): Promise<NodeInfo>;
13
+ blockNumber(): Promise<number>;
14
+ blockByNumber(height: number): Promise<BlockView>;
15
+ getState(key: string): Promise<StateResult>;
16
+ estimate(command: SignedCommand): Promise<EstimateResult>;
17
+ submit(command: SignedCommand): Promise<SubmitResult>;
18
+ /**
19
+ * Read a token balance as a bigint (0 if the account has none).
20
+ * `tokenIdHex` is the `0x`-prefixed token id (see `ids.tokenId`).
21
+ */
22
+ tokenBalance(tokenIdHex: string, party: string): Promise<bigint>;
23
+ /**
24
+ * Poll until the chain reaches at least `target` height (or times out).
25
+ * Useful after submitting to a non-instant-mining node.
26
+ */
27
+ waitForHeight(target: number, opts?: {
28
+ timeoutMs?: number;
29
+ intervalMs?: number;
30
+ }): Promise<number>;
31
+ }
package/dist/client.js ADDED
@@ -0,0 +1,88 @@
1
+ import { RPC_METHODS, } from "./types.js";
2
+ export class RpcClientError extends Error {
3
+ constructor(code, message) {
4
+ super(`rpc error ${code}: ${message}`);
5
+ this.code = code;
6
+ this.name = "RpcClientError";
7
+ }
8
+ }
9
+ /** A JSON-RPC client for a VEILUX node. Uses the global `fetch`. */
10
+ export class Client {
11
+ constructor(endpoint) {
12
+ this.endpoint = endpoint;
13
+ this.id = 1;
14
+ }
15
+ async call(method, params) {
16
+ const body = JSON.stringify({
17
+ jsonrpc: "2.0",
18
+ method,
19
+ params,
20
+ id: this.id++,
21
+ });
22
+ const resp = await fetch(this.endpoint, {
23
+ method: "POST",
24
+ headers: { "Content-Type": "application/json" },
25
+ body,
26
+ });
27
+ const json = (await resp.json());
28
+ if (json.error) {
29
+ throw new RpcClientError(json.error.code, json.error.message);
30
+ }
31
+ if (json.result === undefined) {
32
+ throw new Error("missing result in RPC response");
33
+ }
34
+ return json.result;
35
+ }
36
+ nodeInfo() {
37
+ return this.call(RPC_METHODS.nodeInfo, {});
38
+ }
39
+ blockNumber() {
40
+ return this.call(RPC_METHODS.blockNumber, {});
41
+ }
42
+ blockByNumber(height) {
43
+ return this.call(RPC_METHODS.getBlockByNumber, { height });
44
+ }
45
+ getState(key) {
46
+ return this.call(RPC_METHODS.getState, { key });
47
+ }
48
+ estimate(command) {
49
+ return this.call(RPC_METHODS.estimate, { command });
50
+ }
51
+ submit(command) {
52
+ return this.call(RPC_METHODS.submit, { command });
53
+ }
54
+ /**
55
+ * Read a token balance as a bigint (0 if the account has none).
56
+ * `tokenIdHex` is the `0x`-prefixed token id (see `ids.tokenId`).
57
+ */
58
+ async tokenBalance(tokenIdHex, party) {
59
+ const r = await this.getState(`token/bal/${tokenIdHex}/${party}`);
60
+ if (!r.found)
61
+ return 0n;
62
+ const clean = r.value_hex.startsWith("0x") ? r.value_hex.slice(2) : r.value_hex;
63
+ const bytes = new Uint8Array(clean.length / 2);
64
+ for (let i = 0; i < bytes.length; i++) {
65
+ bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
66
+ }
67
+ const text = new TextDecoder().decode(bytes);
68
+ return text ? BigInt(text) : 0n;
69
+ }
70
+ /**
71
+ * Poll until the chain reaches at least `target` height (or times out).
72
+ * Useful after submitting to a non-instant-mining node.
73
+ */
74
+ async waitForHeight(target, opts) {
75
+ const timeoutMs = opts?.timeoutMs ?? 30000;
76
+ const intervalMs = opts?.intervalMs ?? 500;
77
+ const deadline = Date.now() + timeoutMs;
78
+ for (;;) {
79
+ const h = await this.blockNumber();
80
+ if (h >= target)
81
+ return h;
82
+ if (Date.now() > deadline) {
83
+ throw new Error(`timed out waiting for height ${target} (current ${h})`);
84
+ }
85
+ await new Promise((r) => setTimeout(r, intervalMs));
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,25 @@
1
+ import type { Command, Visibility } from "./types.js";
2
+ /** Concatenate byte arrays. */
3
+ declare function concat(...parts: Uint8Array[]): Uint8Array;
4
+ declare function u64le(n: number): Uint8Array;
5
+ /**
6
+ * Serialize `Visibility` exactly like serde_json on the Rust side, so the
7
+ * signed bytes match byte-for-byte:
8
+ * Public -> "Public" (a quoted JSON string)
9
+ * Parties([...]) -> {"Parties":["alice","bob"]}
10
+ */
11
+ export declare function visibilityJson(v: Visibility): Uint8Array;
12
+ /**
13
+ * Reproduce `Command::signing_bytes` from the Rust kernel:
14
+ * b"veilux/command/v1" 0xff prism 0xff submitter 0xff nonce_le vis 0xff payload
15
+ */
16
+ export declare function signingBytes(cmd: Command): Uint8Array;
17
+ /**
18
+ * Reproduce `Hash::commit(domain, parts)`:
19
+ * blake3(domain || 0xff || for each part: len_le_u64 || part)
20
+ */
21
+ export declare function hashCommit(domain: string, parts: Uint8Array[]): Uint8Array;
22
+ /** Reproduce `Command::id` -> 32-byte BLAKE3 hash. */
23
+ export declare function commandId(cmd: Command): Uint8Array;
24
+ export declare function toHex(bytes: Uint8Array): string;
25
+ export { concat, u64le };
@@ -0,0 +1,68 @@
1
+ import { blake3 } from "@noble/hashes/blake3";
2
+ const textEncoder = new TextEncoder();
3
+ /** Concatenate byte arrays. */
4
+ function concat(...parts) {
5
+ let len = 0;
6
+ for (const p of parts)
7
+ len += p.length;
8
+ const out = new Uint8Array(len);
9
+ let off = 0;
10
+ for (const p of parts) {
11
+ out.set(p, off);
12
+ off += p.length;
13
+ }
14
+ return out;
15
+ }
16
+ function u64le(n) {
17
+ const buf = new Uint8Array(8);
18
+ const view = new DataView(buf.buffer);
19
+ view.setBigUint64(0, BigInt(n), true);
20
+ return buf;
21
+ }
22
+ /**
23
+ * Serialize `Visibility` exactly like serde_json on the Rust side, so the
24
+ * signed bytes match byte-for-byte:
25
+ * Public -> "Public" (a quoted JSON string)
26
+ * Parties([...]) -> {"Parties":["alice","bob"]}
27
+ */
28
+ export function visibilityJson(v) {
29
+ if (v === "Public") {
30
+ return textEncoder.encode('"Public"');
31
+ }
32
+ // serde_json emits compact JSON with no spaces.
33
+ const inner = v.Parties.map((p) => JSON.stringify(p)).join(",");
34
+ return textEncoder.encode(`{"Parties":[${inner}]}`);
35
+ }
36
+ /**
37
+ * Reproduce `Command::signing_bytes` from the Rust kernel:
38
+ * b"veilux/command/v1" 0xff prism 0xff submitter 0xff nonce_le vis 0xff payload
39
+ */
40
+ export function signingBytes(cmd) {
41
+ const sep = new Uint8Array([0xff]);
42
+ return concat(textEncoder.encode("veilux/command/v1"), sep, textEncoder.encode(cmd.prism), sep, textEncoder.encode(cmd.submitter), sep, u64le(cmd.nonce), visibilityJson(cmd.visibility), sep, Uint8Array.from(cmd.payload));
43
+ }
44
+ /**
45
+ * Reproduce `Hash::commit(domain, parts)`:
46
+ * blake3(domain || 0xff || for each part: len_le_u64 || part)
47
+ */
48
+ export function hashCommit(domain, parts) {
49
+ const chunks = [textEncoder.encode(domain), new Uint8Array([0xff])];
50
+ for (const p of parts) {
51
+ chunks.push(u64le(p.length));
52
+ chunks.push(p);
53
+ }
54
+ return blake3(concat(...chunks));
55
+ }
56
+ /** Reproduce `Command::id` -> 32-byte BLAKE3 hash. */
57
+ export function commandId(cmd) {
58
+ return hashCommit("command", [
59
+ textEncoder.encode(cmd.prism),
60
+ textEncoder.encode(cmd.submitter),
61
+ u64le(cmd.nonce),
62
+ Uint8Array.from(cmd.payload),
63
+ ]);
64
+ }
65
+ export function toHex(bytes) {
66
+ return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
67
+ }
68
+ export { concat, u64le };
@@ -0,0 +1,23 @@
1
+ import type { Command, PartyId, SignedCommand } from "./types.js";
2
+ /**
3
+ * A party's signing identity. Mirrors the Rust `PartyIdentity`:
4
+ * the 32-byte seed IS the Ed25519 secret key (dalek `from_bytes`).
5
+ */
6
+ export declare class PartyIdentity {
7
+ readonly party: PartyId;
8
+ private readonly secret;
9
+ constructor(party: PartyId, seed: Uint8Array);
10
+ /** Deterministic identity from a label + raw 32-byte seed. */
11
+ static fromSeed(party: PartyId, seed: Uint8Array): PartyIdentity;
12
+ /**
13
+ * Convenience: derive a 32-byte seed from a passphrase via BLAKE3.
14
+ * (Use real entropy in production; this mirrors test/dev helpers.)
15
+ */
16
+ static fromPassphrase(party: PartyId, passphrase: string): PartyIdentity;
17
+ /** Generate a random identity. */
18
+ static generate(party: PartyId): PartyIdentity;
19
+ /** The 32-byte Ed25519 public key. */
20
+ publicKey(): Uint8Array;
21
+ /** Sign a command, producing a SignedCommand ready for submission. */
22
+ sign(command: Command): SignedCommand;
23
+ }
@@ -0,0 +1,48 @@
1
+ import * as ed from "@noble/ed25519";
2
+ import { sha512 } from "@noble/hashes/sha512";
3
+ import { blake3 } from "@noble/hashes/blake3";
4
+ import { signingBytes } from "./encoding.js";
5
+ // @noble/ed25519 v2 needs sha512 wired up for synchronous signing.
6
+ ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));
7
+ /**
8
+ * A party's signing identity. Mirrors the Rust `PartyIdentity`:
9
+ * the 32-byte seed IS the Ed25519 secret key (dalek `from_bytes`).
10
+ */
11
+ export class PartyIdentity {
12
+ constructor(party, seed) {
13
+ if (seed.length !== 32)
14
+ throw new Error("seed must be 32 bytes");
15
+ this.party = party;
16
+ this.secret = seed;
17
+ }
18
+ /** Deterministic identity from a label + raw 32-byte seed. */
19
+ static fromSeed(party, seed) {
20
+ return new PartyIdentity(party, seed);
21
+ }
22
+ /**
23
+ * Convenience: derive a 32-byte seed from a passphrase via BLAKE3.
24
+ * (Use real entropy in production; this mirrors test/dev helpers.)
25
+ */
26
+ static fromPassphrase(party, passphrase) {
27
+ const seed = blake3(new TextEncoder().encode(passphrase));
28
+ return new PartyIdentity(party, seed);
29
+ }
30
+ /** Generate a random identity. */
31
+ static generate(party) {
32
+ return new PartyIdentity(party, ed.utils.randomPrivateKey());
33
+ }
34
+ /** The 32-byte Ed25519 public key. */
35
+ publicKey() {
36
+ return ed.getPublicKey(this.secret);
37
+ }
38
+ /** Sign a command, producing a SignedCommand ready for submission. */
39
+ sign(command) {
40
+ const msg = signingBytes(command);
41
+ const signature = ed.sign(msg, this.secret);
42
+ return {
43
+ command,
44
+ public_key: Array.from(this.publicKey()),
45
+ signature: Array.from(signature),
46
+ };
47
+ }
48
+ }
package/dist/ids.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { PartyId } from "./types.js";
2
+ /**
3
+ * Derive a token id exactly like the Token Prism:
4
+ * `keccak/blake3 commit("token/id", [submitter, symbol, name])`.
5
+ */
6
+ export declare function tokenId(submitter: PartyId, symbol: string, name: string): string;
7
+ /**
8
+ * Derive an NFT collection id like the NFT Prism:
9
+ * `commit("nft/coll-id", [submitter, symbol, name])`.
10
+ */
11
+ export declare function collectionId(submitter: PartyId, symbol: string, name: string): string;
12
+ /**
13
+ * Derive a deployed contract address like the Contract Prism:
14
+ * `commit("contract/address", [submitter, nonce_le, code])`.
15
+ */
16
+ export declare function contractAddress(submitter: PartyId, nonce: number, code: Uint8Array | number[]): string;
17
+ /** State key helpers (matching each Prism's namespacing). */
18
+ export declare const stateKeys: {
19
+ tokenMeta: (id: string) => string;
20
+ tokenBalance: (id: string, party: PartyId) => string;
21
+ tokenAllowance: (id: string, owner: PartyId, spender: PartyId) => string;
22
+ nftCollection: (id: string) => string;
23
+ nftOwner: (id: string, index: number) => string;
24
+ contractCode: (addr: string) => string;
25
+ };
26
+ /** Decode a hex state value into a UTF-8 string (e.g. token balances). */
27
+ export declare function decodeStringValue(valueHex: string): string;
package/dist/ids.js ADDED
@@ -0,0 +1,45 @@
1
+ import { hashCommit, toHex, u64le } from "./encoding.js";
2
+ const te = new TextEncoder();
3
+ /**
4
+ * Derive a token id exactly like the Token Prism:
5
+ * `keccak/blake3 commit("token/id", [submitter, symbol, name])`.
6
+ */
7
+ export function tokenId(submitter, symbol, name) {
8
+ return toHex(hashCommit("token/id", [te.encode(submitter), te.encode(symbol), te.encode(name)]));
9
+ }
10
+ /**
11
+ * Derive an NFT collection id like the NFT Prism:
12
+ * `commit("nft/coll-id", [submitter, symbol, name])`.
13
+ */
14
+ export function collectionId(submitter, symbol, name) {
15
+ return toHex(hashCommit("nft/coll-id", [te.encode(submitter), te.encode(symbol), te.encode(name)]));
16
+ }
17
+ /**
18
+ * Derive a deployed contract address like the Contract Prism:
19
+ * `commit("contract/address", [submitter, nonce_le, code])`.
20
+ */
21
+ export function contractAddress(submitter, nonce, code) {
22
+ return toHex(hashCommit("contract/address", [
23
+ te.encode(submitter),
24
+ u64le(nonce),
25
+ Uint8Array.from(code),
26
+ ]));
27
+ }
28
+ /** State key helpers (matching each Prism's namespacing). */
29
+ export const stateKeys = {
30
+ tokenMeta: (id) => `token/meta/${id}`,
31
+ tokenBalance: (id, party) => `token/bal/${id}/${party}`,
32
+ tokenAllowance: (id, owner, spender) => `token/allow/${id}/${owner}/${spender}`,
33
+ nftCollection: (id) => `nft/coll/${id}`,
34
+ nftOwner: (id, index) => `nft/owner/${id}/${index}`,
35
+ contractCode: (addr) => `contract/code/${addr}`,
36
+ };
37
+ /** Decode a hex state value into a UTF-8 string (e.g. token balances). */
38
+ export function decodeStringValue(valueHex) {
39
+ const clean = valueHex.startsWith("0x") ? valueHex.slice(2) : valueHex;
40
+ const bytes = new Uint8Array(clean.length / 2);
41
+ for (let i = 0; i < bytes.length; i++) {
42
+ bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
43
+ }
44
+ return new TextDecoder().decode(bytes);
45
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * VEILUX TypeScript SDK
3
+ *
4
+ * Build, sign, and submit commands to a VEILUX node from JavaScript/TypeScript.
5
+ * Signing and hashing are byte-compatible with the Rust node, so signatures
6
+ * produced here verify on-chain.
7
+ */
8
+ export * from "./types.js";
9
+ export * from "./encoding.js";
10
+ export * from "./identity.js";
11
+ export * from "./client.js";
12
+ export * from "./ids.js";
13
+ export * as builders from "./builders.js";
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * VEILUX TypeScript SDK
3
+ *
4
+ * Build, sign, and submit commands to a VEILUX node from JavaScript/TypeScript.
5
+ * Signing and hashing are byte-compatible with the Rust node, so signatures
6
+ * produced here verify on-chain.
7
+ */
8
+ export * from "./types.js";
9
+ export * from "./encoding.js";
10
+ export * from "./identity.js";
11
+ export * from "./client.js";
12
+ export * from "./ids.js";
13
+ export * as builders from "./builders.js";
@@ -0,0 +1,66 @@
1
+ /** A party identifier. Serializes as a bare JSON string (newtype struct). */
2
+ export type PartyId = string;
3
+ /**
4
+ * Disclosure scope for an event.
5
+ * Rust serde: `Public` -> "Public", `Parties(vec)` -> { "Parties": [...] }.
6
+ */
7
+ export type Visibility = "Public" | {
8
+ Parties: PartyId[];
9
+ };
10
+ /**
11
+ * A command. `payload` is a byte array (Rust `Vec<u8>` -> JSON number array).
12
+ */
13
+ export interface Command {
14
+ prism: string;
15
+ submitter: PartyId;
16
+ visibility: Visibility;
17
+ payload: number[];
18
+ nonce: number;
19
+ }
20
+ /** A signed command ready for submission. */
21
+ export interface SignedCommand {
22
+ command: Command;
23
+ public_key: number[];
24
+ signature: number[];
25
+ }
26
+ export interface NodeInfo {
27
+ network: string;
28
+ protocol: string;
29
+ token: string;
30
+ height: number;
31
+ head_hash: string;
32
+ state_root: string;
33
+ prisms: string[];
34
+ }
35
+ export interface SubmitResult {
36
+ accepted: boolean;
37
+ command_id: string;
38
+ mempool_len: number;
39
+ }
40
+ export interface BlockView {
41
+ height: number;
42
+ hash: string;
43
+ parent: string;
44
+ state_root: string;
45
+ events_root: string;
46
+ proposer: string;
47
+ timestamp: number;
48
+ command_count: number;
49
+ event_count: number;
50
+ }
51
+ export interface StateResult {
52
+ key: string;
53
+ found: boolean;
54
+ value_hex: string;
55
+ }
56
+ export interface EstimateResult {
57
+ cost: number;
58
+ }
59
+ export declare const RPC_METHODS: {
60
+ readonly nodeInfo: "veilux_nodeInfo";
61
+ readonly submit: "veilux_submit";
62
+ readonly blockNumber: "veilux_blockNumber";
63
+ readonly getBlockByNumber: "veilux_getBlockByNumber";
64
+ readonly getState: "veilux_getState";
65
+ readonly estimate: "veilux_estimate";
66
+ };
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ // Wire types mirroring the Rust kernel's serde representation exactly.
2
+ export const RPC_METHODS = {
3
+ nodeInfo: "veilux_nodeInfo",
4
+ submit: "veilux_submit",
5
+ blockNumber: "veilux_blockNumber",
6
+ getBlockByNumber: "veilux_getBlockByNumber",
7
+ getState: "veilux_getState",
8
+ estimate: "veilux_estimate",
9
+ };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@veilux/sdk",
3
+ "version": "0.2.0",
4
+ "description": "VEILUX TypeScript SDK — build, sign, and submit commands to a VEILUX node",
5
+ "license": "MIT",
6
+ "author": "nathan <nathan@winnode.xyz>",
7
+ "repository": "https://github.com/VeiluxLabs/Veilux-Binary",
8
+ "type": "module",
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "pretest": "tsc && tsc test/compat.test.ts --rootDir test --outDir test-dist --module ESNext --target ES2020 --moduleResolution Bundler --skipLibCheck --types node",
27
+ "test": "node --test test-dist/",
28
+ "example": "node --loader ts-node/esm examples/quickstart.ts",
29
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true});require('fs').rmSync('test-dist',{recursive:true,force:true})\""
30
+ },
31
+ "dependencies": {
32
+ "@noble/ed25519": "^2.1.0",
33
+ "@noble/hashes": "^1.4.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^25.9.1",
37
+ "typescript": "^5.4.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=18"
41
+ }
42
+ }