diff --git a/ceps-client-wasm-schema/pkg-nodejs/README.md b/ceps-client-wasm-schema/pkg-nodejs/README.md
new file mode 100644
index 0000000..f88ab12
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg-nodejs/README.md
@@ -0,0 +1,320 @@
+# ceps-rust-ts-client
+
+One **Rust** client for Casper **CEP-18**, **CEP-78**, **CEP-85**, and **CEP-95**, with a **`ceps-client-cli`**, **`ceps-rust-ts-client-mcp`**, and **WASM packs** so the same client can run from shell, agents, Node, or the browser.
+
+It replaces the separate TypeScript **`client-js`** packages that lived next to each CEP contract. Instead of per-CEP JS clients, you use one library: `CEP18Client` / `CEP78Client` / `CEP85Client` / `CEP95Client`, on top of [`casper-rust-wasm-sdk`](https://github.com/casper-ecosystem/casper-rust-wasm-sdk).
+
+```text
+CEP-18 client-js ─┐
+CEP-78 client-js ─┼─→ ceps-client (Rust) + ceps-client-cli + ceps-rust-ts-client-mcp + ceps-client-wasm
+CEP-85 client-js ─┤
+CEP-95 JS client ─┘
+```
+
+## What you get
+
+
+
+
+
Piece
+
Name
+
Role
+
In-tree path
+
+
+
+
+
Rust library
+
ceps‑client
+
CEP API for native Rust apps
+
ceps-client/
+
+
+
CLI
+
ceps‑client‑cli
+
Status and common queries from the shell
+
ceps-client-cli/
+
+
+
MCP server
+
ceps-rust-ts-client-mcp
+
Full CEP agent tools (stdio / HTTP :6790)
+
mcp/
+
+
+
Client JS packs
+
ceps‑client‑wasm
+
Same CEP classes for Node and browsers (replaces per-CEP client-js)
+
ceps-client-wasm/pkg / pkg-nodejs
+
+
+
Demo contract WASMs
+
ceps‑contracts
+
On-chain bytecode for install (demo tips)
+
tests/wasm/{cep18,cep78,cep85,cep95}/
+
+
+
+
+Release downloads use the same names: `ceps-client-cli-*-linux-x86_64`, `ceps-rust-ts-client-mcp-*-linux-x86_64`, `ceps-client-wasm-*.tgz`, and `ceps-contracts-*.tgz`. The library / CLI / MCP / JS packs are this client; `ceps-contracts` is sample contract bytecode, not the JS library.
+
+## What you can do
+
+| CEP | Standard | Typical flow |
+| ------ | -------------- | -------------------------------------------------------------------------- |
+| **18** | Fungible token | install → bind hash → `name` / `balance_of` → `transfer` / `mint` / `burn` |
+| **78** | Enhanced NFT | install → bind hash → `mint` → `owner_of` / `balance_of` |
+| **85** | Multi-token | install → bind hash → `mint` / `burn` → `balance_of(account, id)` |
+| **95** | NFT (Odra tip) | install → `bind_odra_install` → `mint` → `owner_of` / `approve` |
+
+Defaults talk to local NCTL (`http://127.0.0.1:11101`, SSE `…:18101/events`, chain `casper-net-1`).
+
+## Usage
+
+Needs a running node, a secret-key PEM, and on-chain contract `.wasm` bytes (your own build, or the [demo tips](#contract-wasms-demos) via `make wasm-from-ceps`).
+
+### CEP-18 - fungible
+
+```text
+install → named keys cep18_contract_hash_* / package_*
+ → set_contract_hash
+ → name / symbol / balance_of
+ → transfer | mint | burn
+```
+
+```rust
+use ceps_client::cep18::InstallArgs;
+use ceps_client::{CEP18Client, TransactionParams, EventsMode, Verbosity};
+
+let mut client = CEP18Client::new(
+ "http://127.0.0.1:11101",
+ Some("http://127.0.0.1:18101/events".into()),
+ Some("casper-net-1".into()),
+ Some(Verbosity::Low),
+)?;
+
+let put = client
+ .install(
+ &InstallArgs::new("MyToken", "MTK", 9, "1000000000")
+ .with_events_mode(EventsMode::CES)
+ .with_mint_and_burn(true),
+ &contract_wasm_bytes,
+ &TransactionParams::new(&secret_pem, "400000000000"),
+ )
+ .await?;
+client.set_contract_hash(&contract_hash, Some(&package_hash))?;
+let bal = client.balance_of("account-hash-…").await?;
+```
+
+Details: [docs/cep18/](docs/cep18/) · example: `cargo run -p ceps-client --example cep18_install`
+
+### CEP-78 - NFT
+
+```text
+install → named keys cep78_contract_hash_* / package_*
+ → set_contract_hash
+ → mint → owner_of / balance_of
+```
+
+```rust
+use ceps_client::cep78::InstallArgs;
+use ceps_client::{CEP78Client, TransactionParams, EventsMode78, Verbosity};
+
+let mut client = CEP78Client::new(/* rpc, sse, chain, verbosity */)?;
+client
+ .install(
+ &InstallArgs::new("MyNft", "NFT", 100).with_events_mode(EventsMode78::CES),
+ &contract_wasm_bytes,
+ &TransactionParams::new(&secret_pem, "600000000000"),
+ )
+ .await?;
+client.set_contract_hash(&contract_hash, Some(&package_hash))?;
+client
+ .mint(
+ "account-hash-…",
+ r#"{"name":"token-1"}"#,
+ None,
+ &TransactionParams::new(&secret_pem, "5000000000"),
+ )
+ .await?;
+let owner = client.owner_of(&token_id).await?;
+```
+
+Details: [docs/cep78/](docs/cep78/) · example: `cargo run -p ceps-client --example cep78_install`
+
+### CEP-85 - multi-token
+
+```text
+install → named keys cep85_contract_hash_* / package_*
+ → set_contract_hash
+ → mint / burn → balance_of(account, id)
+```
+
+```rust
+use ceps_client::cep85::InstallArgs;
+use ceps_client::{CEP85Client, TransactionParams, EventsMode, Verbosity};
+
+let mut client = CEP85Client::new(/* rpc, sse, chain, verbosity */)?;
+client
+ .install(
+ &InstallArgs::new("MyMulti", "https://example.com/{id}.json")
+ .with_events_mode(EventsMode::CES)
+ .with_enable_burn(true),
+ &contract_wasm_bytes,
+ &TransactionParams::new(&secret_pem, "550000000000"),
+ )
+ .await?;
+client.set_contract_hash(&contract_hash, Some(&package_hash))?;
+client.mint(&owner, "1", "10", None, &TransactionParams::new(&secret_pem, "5000000000")).await?;
+let bal = client.balance_of(&owner, "1").await?;
+```
+
+Details: [docs/cep85/](docs/cep85/) · example: `cargo run -p ceps-client --example cep85_install`
+
+### CEP-95 - NFT (Odra tip)
+
+```text
+install (odra_cfg_package_hash_key_name) → bind_odra_install
+ → name / symbol / balance_of / owner_of
+ → mint | burn | transfer_from | approve*
+```
+
+```rust
+use ceps_client::cep95::InstallArgs;
+use ceps_client::{CEP95Client, TransactionParams, Verbosity};
+
+let mut client = CEP95Client::new(/* rpc, sse, chain, verbosity */)?;
+client
+ .install(
+ &InstallArgs::new("MyNft", "MNFT", "cep95_pkg_demo"),
+ &contract_wasm_bytes,
+ &TransactionParams::new(&secret_pem, "600000000000"),
+ )
+ .await?;
+client.bind_odra_install(&installer_public_key, "cep95_pkg_demo").await?;
+client.mint(&owner, "1", None, &TransactionParams::new(&secret_pem, "5000000000")).await?;
+let owner_of = client.owner_of("1").await?;
+```
+
+Details: [docs/cep95/](docs/cep95/) · example: `cargo run -p ceps-client --example cep95_install`
+
+### CLI
+
+```bash
+cargo run -p ceps-client-cli -- status
+cargo run -p ceps-client-cli -- cep18 info
+cargo run -p ceps-client-cli -- cep78 balance --contract-hash --account
+cargo run -p ceps-client-cli -- cep85 balance --contract-hash --account <…> --id 1
+cargo run -p ceps-client-cli -- cep95 owner-of --contract-hash --token-id 1
+```
+
+Mutations are on the library / examples today. Flags: [docs/cli.md](docs/cli.md).
+
+### Try an install end-to-end
+
+```bash
+make prepare && make build
+make wasm-from-ceps # copy demo tip contract WASMs into tests/wasm/
+# NCTL running + SECRET_KEY_USER_1 set to a PEM:
+cargo run -p ceps-client --example cep18_install
+```
+
+More setup: [docs/getting-started.md](docs/getting-started.md).
+
+## Client JS packs (`ceps-client-wasm`)
+
+`ceps-client-wasm` is the **Rust CEP client compiled for JavaScript** (the replacement for per-CEP `client-js`). Use it from Node or the browser for the same `CEP18Client` / `CEP78Client` / `CEP85Client` surface.
+
+It is **not** on-chain contract bytecode (that is `tests/wasm/` / `ceps-contracts-*.tgz`).
+
+| Target | In-tree (committed) | Typical use |
+| ------ | ------------------------------ | -------------------------- |
+| Node | `ceps-client-wasm/pkg-nodejs/` | Backend / scripts / Vitest |
+| Web | `ceps-client-wasm/pkg/` | Bundled frontends |
+
+Rebuild locally with `make pack` (or `make nodejs` / `make web`). Details: [docs/wasm-ts.md](docs/wasm-ts.md) · [docs/releases.md](docs/releases.md).
+
+**Or** fetch a published pack (no local `wasm-pack`):
+
+```bash
+TAG=v1.0.0 # or dev-preview
+LABEL=${TAG#v}
+curl -fsSL -o ceps-client-wasm-nodejs.tgz \
+ "https://github.com/Interchouette-ITC/ceps-rust-ts-client/releases/download/${TAG}/ceps-client-wasm-nodejs-${LABEL}.tgz"
+mkdir -p ceps-client-wasm && tar -xzf ceps-client-wasm-nodejs.tgz -C ceps-client-wasm
+# -> ceps-client-wasm/pkg-nodejs/
+```
+
+```js
+import { CEP18Client } from "ceps-client-wasm"; // file:./ceps-client-wasm/pkg-nodejs after unpack
+
+const client = new CEP18Client(
+ "http://127.0.0.1:11101",
+ "http://127.0.0.1:18101/events",
+ "casper-net-1",
+ 0,
+);
+client.setContractHash(contractHash, packageHash);
+const name = await client.name();
+const bal = await client.balanceOf("account-hash-…");
+```
+
+Install from JS takes contract bytes as `Uint8Array` and returns JSON `{ transactionHash, hasExecutionResult }`. Bound methods today are a subset of the Rust API (see [docs/wasm-ts.md](docs/wasm-ts.md)); full parity is on `ceps-client`.
+
+## Contract WASMs (demos)
+
+This client is **not** a contract repo. You pass on-chain `.wasm` into `install`.
+
+**In-tree:** the last staged demo tip builds ship under `tests/wasm/{cep18,cep78,cep85}/` (same idea as committing `pkg` / `pkg-nodejs`). Use those bytes directly, or refresh with `make wasm-from-ceps`.
+
+**Or** download the release bundle (no tip checkout / no contract build):
+
+```bash
+TAG=v1.0.0
+LABEL=${TAG#v}
+curl -fsSL -o ceps-contracts.tgz \
+ "https://github.com/Interchouette-ITC/ceps-rust-ts-client/releases/download/${TAG}/ceps-contracts-${LABEL}.tgz"
+mkdir -p tests/wasm && tar -xzf ceps-contracts.tgz -C tests/wasm
+```
+
+Tips are short-lived entity-era builds for demos/CI, not a claim of "the" upstream CEP tip forever. Sources:
+
+| CEP | Demo tip repo | Branch | What you get |
+| --- | ------------- | ------ | ------------ |
+| 18 | [Interchouette-ITC/cep-18](https://github.com/Interchouette-ITC/cep-18) | `ceps-client-test` | Fungible contract WASM |
+| 78 | [Interchouette-ITC/cep-78-enhanced-nft](https://github.com/Interchouette-ITC/cep-78-enhanced-nft) | `ceps-client-test` | NFT + session WASMs |
+| 85 | [Interchouette-ITC/cep-85](https://github.com/Interchouette-ITC/cep-85) | `ceps-client-test` | Multi-token WASM |
+
+```bash
+# after checking out those tips and building contracts there:
+make wasm-from-ceps # → tests/wasm/{cep18,cep78,cep85}/
+```
+
+Override checkout roots with `CEP18_PRODUCT` / `CEP78_PRODUCT` / `CEP85_PRODUCT`. Pins and SHAs: [docs/contributing.md](docs/contributing.md). All release downloads: [docs/releases.md](docs/releases.md).
+
+## Documentation
+
+| Doc | Description |
+| ------------------------------------------------------------------------------------------------------------ | ----------------------------------- |
+| [Getting started](docs/getting-started.md) | Build, NCTL defaults, first run |
+| [Architecture](docs/architecture.md) | How lib / CLI / WASM sit on the SDK |
+| [docs/cep18/](docs/cep18/) · [cep78/](docs/cep78/) · [cep85/](docs/cep85/) | Per-CEP guides |
+| [CLI](docs/cli.md) · [WASM / TS](docs/wasm-ts.md) | Surfaces |
+| [Testing](docs/testing.md) · [CI / CD](docs/ci.md) · [Releases](docs/releases.md) · [Docker](docs/docker.md) | Verify and ship |
+| [Contributing](docs/contributing.md) · [SDK](docs/sdk.md) | Tips, pins, upgrades |
+| [SECURITY.md](docs/SECURITY.md) | Keys and reporting |
+| `make doc` | rustdoc → `docs/api-rust/` |
+
+## Docker
+
+```bash
+make release-cli-bin && make docker-build IMAGE_TAG=local
+docker run --rm ceps-rust-ts-client:local --help
+docker pull interchouette/ceps-rust-ts-client:dev
+```
+
+See [docs/docker.md](docs/docker.md).
+
+## License / security
+
+GPL-3.0. See [LICENSE](LICENSE) and [docs/SECURITY.md](docs/SECURITY.md).
diff --git a/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm.d.ts b/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm.d.ts
new file mode 100644
index 0000000..9a99391
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm.d.ts
@@ -0,0 +1,32 @@
+/* tslint:disable */
+/* eslint-disable */
+
+/**
+ * CEP-18 schema JSON.
+ */
+export function cep18SchemaJson(): string;
+
+/**
+ * CEP-78 schema JSON.
+ */
+export function cep78SchemaJson(): string;
+
+/**
+ * CEP-85 schema JSON.
+ */
+export function cep85SchemaJson(): string;
+
+/**
+ * CEP-95 schema JSON.
+ */
+export function cep95SchemaJson(): string;
+
+/**
+ * JSON schema for a CEP id (`cep18`, `cep78`, `cep85`, `cep95`).
+ */
+export function schemaJson(cep: string): string;
+
+/**
+ * Supported CEP id strings.
+ */
+export function supportedCeps(): any;
diff --git a/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm.js b/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm.js
new file mode 100644
index 0000000..40852aa
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm.js
@@ -0,0 +1,241 @@
+/* @ts-self-types="./ceps_client_wasm.d.ts" */
+
+/**
+ * CEP-18 schema JSON.
+ * @returns {string}
+ */
+function cep18SchemaJson() {
+ let deferred1_0;
+ let deferred1_1;
+ try {
+ const ret = wasm.cep18SchemaJson();
+ deferred1_0 = ret[0];
+ deferred1_1 = ret[1];
+ return getStringFromWasm0(ret[0], ret[1]);
+ } finally {
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
+ }
+}
+exports.cep18SchemaJson = cep18SchemaJson;
+
+/**
+ * CEP-78 schema JSON.
+ * @returns {string}
+ */
+function cep78SchemaJson() {
+ let deferred1_0;
+ let deferred1_1;
+ try {
+ const ret = wasm.cep78SchemaJson();
+ deferred1_0 = ret[0];
+ deferred1_1 = ret[1];
+ return getStringFromWasm0(ret[0], ret[1]);
+ } finally {
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
+ }
+}
+exports.cep78SchemaJson = cep78SchemaJson;
+
+/**
+ * CEP-85 schema JSON.
+ * @returns {string}
+ */
+function cep85SchemaJson() {
+ let deferred1_0;
+ let deferred1_1;
+ try {
+ const ret = wasm.cep85SchemaJson();
+ deferred1_0 = ret[0];
+ deferred1_1 = ret[1];
+ return getStringFromWasm0(ret[0], ret[1]);
+ } finally {
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
+ }
+}
+exports.cep85SchemaJson = cep85SchemaJson;
+
+/**
+ * CEP-95 schema JSON.
+ * @returns {string}
+ */
+function cep95SchemaJson() {
+ let deferred1_0;
+ let deferred1_1;
+ try {
+ const ret = wasm.cep95SchemaJson();
+ deferred1_0 = ret[0];
+ deferred1_1 = ret[1];
+ return getStringFromWasm0(ret[0], ret[1]);
+ } finally {
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
+ }
+}
+exports.cep95SchemaJson = cep95SchemaJson;
+
+/**
+ * JSON schema for a CEP id (`cep18`, `cep78`, `cep85`, `cep95`).
+ * @param {string} cep
+ * @returns {string}
+ */
+function schemaJson(cep) {
+ let deferred3_0;
+ let deferred3_1;
+ try {
+ const ptr0 = passStringToWasm0(cep, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ret = wasm.schemaJson(ptr0, len0);
+ var ptr2 = ret[0];
+ var len2 = ret[1];
+ if (ret[3]) {
+ ptr2 = 0; len2 = 0;
+ throw takeFromExternrefTable0(ret[2]);
+ }
+ deferred3_0 = ptr2;
+ deferred3_1 = len2;
+ return getStringFromWasm0(ptr2, len2);
+ } finally {
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
+ }
+}
+exports.schemaJson = schemaJson;
+
+/**
+ * Supported CEP id strings.
+ * @returns {any}
+ */
+function supportedCeps() {
+ const ret = wasm.supportedCeps();
+ if (ret[2]) {
+ throw takeFromExternrefTable0(ret[1]);
+ }
+ return takeFromExternrefTable0(ret[0]);
+}
+exports.supportedCeps = supportedCeps;
+function __wbg_get_imports() {
+ const import0 = {
+ __proto__: null,
+ __wbg___wbindgen_throw_bb96b2010945f0bc: function(arg0, arg1) {
+ throw new Error(getStringFromWasm0(arg0, arg1));
+ },
+ __wbg_parse_1cc93481b0865939: function() { return handleError(function (arg0, arg1) {
+ const ret = JSON.parse(getStringFromWasm0(arg0, arg1));
+ return ret;
+ }, arguments); },
+ __wbindgen_cast_0000000000000001: function(arg0, arg1) {
+ // Cast intrinsic for `Ref(String) -> Externref`.
+ const ret = getStringFromWasm0(arg0, arg1);
+ return ret;
+ },
+ __wbindgen_init_externref_table: function() {
+ const table = wasm.__wbindgen_externrefs;
+ const offset = table.grow(4);
+ table.set(0, undefined);
+ table.set(offset + 0, undefined);
+ table.set(offset + 1, null);
+ table.set(offset + 2, true);
+ table.set(offset + 3, false);
+ },
+ };
+ return {
+ __proto__: null,
+ "./ceps_client_wasm_bg.js": import0,
+ };
+}
+
+function addToExternrefTable0(obj) {
+ const idx = wasm.__externref_table_alloc();
+ wasm.__wbindgen_externrefs.set(idx, obj);
+ return idx;
+}
+
+function getStringFromWasm0(ptr, len) {
+ return decodeText(ptr >>> 0, len);
+}
+
+let cachedUint8ArrayMemory0 = null;
+function getUint8ArrayMemory0() {
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
+ }
+ return cachedUint8ArrayMemory0;
+}
+
+function handleError(f, args) {
+ try {
+ return f.apply(this, args);
+ } catch (e) {
+ const idx = addToExternrefTable0(e);
+ wasm.__wbindgen_exn_store(idx);
+ }
+}
+
+function passStringToWasm0(arg, malloc, realloc) {
+ if (realloc === undefined) {
+ const buf = cachedTextEncoder.encode(arg);
+ const ptr = malloc(buf.length, 1) >>> 0;
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
+ WASM_VECTOR_LEN = buf.length;
+ return ptr;
+ }
+
+ let len = arg.length;
+ let ptr = malloc(len, 1) >>> 0;
+
+ const mem = getUint8ArrayMemory0();
+
+ let offset = 0;
+
+ for (; offset < len; offset++) {
+ const code = arg.charCodeAt(offset);
+ if (code > 0x7F) break;
+ mem[ptr + offset] = code;
+ }
+ if (offset !== len) {
+ if (offset !== 0) {
+ arg = arg.slice(offset);
+ }
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
+ const ret = cachedTextEncoder.encodeInto(arg, view);
+
+ offset += ret.written;
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
+ }
+
+ WASM_VECTOR_LEN = offset;
+ return ptr;
+}
+
+function takeFromExternrefTable0(idx) {
+ const value = wasm.__wbindgen_externrefs.get(idx);
+ wasm.__externref_table_dealloc(idx);
+ return value;
+}
+
+let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
+cachedTextDecoder.decode();
+function decodeText(ptr, len) {
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
+}
+
+const cachedTextEncoder = new TextEncoder();
+
+if (!('encodeInto' in cachedTextEncoder)) {
+ cachedTextEncoder.encodeInto = function (arg, view) {
+ const buf = cachedTextEncoder.encode(arg);
+ view.set(buf);
+ return {
+ read: arg.length,
+ written: buf.length
+ };
+ };
+}
+
+let WASM_VECTOR_LEN = 0;
+
+const wasmPath = `${__dirname}/ceps_client_wasm_bg.wasm`;
+const wasmBytes = require('fs').readFileSync(wasmPath);
+const wasmModule = new WebAssembly.Module(wasmBytes);
+let wasmInstance = new WebAssembly.Instance(wasmModule, __wbg_get_imports());
+let wasm = wasmInstance.exports;
+wasm.__wbindgen_start();
diff --git a/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm_bg.wasm b/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm_bg.wasm
new file mode 100644
index 0000000..54c5e08
Binary files /dev/null and b/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm_bg.wasm differ
diff --git a/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm_bg.wasm.d.ts b/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm_bg.wasm.d.ts
new file mode 100644
index 0000000..4c995f3
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg-nodejs/ceps_client_wasm_bg.wasm.d.ts
@@ -0,0 +1,17 @@
+/* tslint:disable */
+/* eslint-disable */
+export const memory: WebAssembly.Memory;
+export const cep18SchemaJson: () => [number, number];
+export const cep78SchemaJson: () => [number, number];
+export const cep85SchemaJson: () => [number, number];
+export const cep95SchemaJson: () => [number, number];
+export const schemaJson: (a: number, b: number) => [number, number, number, number];
+export const supportedCeps: () => [number, number, number];
+export const __wbindgen_exn_store: (a: number) => void;
+export const __externref_table_alloc: () => number;
+export const __wbindgen_externrefs: WebAssembly.Table;
+export const __wbindgen_free: (a: number, b: number, c: number) => void;
+export const __wbindgen_malloc: (a: number, b: number) => number;
+export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
+export const __externref_table_dealloc: (a: number) => void;
+export const __wbindgen_start: () => void;
diff --git a/ceps-client-wasm-schema/pkg-nodejs/package.json b/ceps-client-wasm-schema/pkg-nodejs/package.json
new file mode 100644
index 0000000..6f3d74c
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg-nodejs/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "ceps-client-wasm-schema-nodejs",
+ "collaborators": [
+ "3099551+gRoussac@users.noreply.github.com"
+ ],
+ "description": "wasm-bindgen CEP client for Node and browsers (same API as ceps-client; replaces per-CEP client-js).",
+ "version": "1.0.0",
+ "license": "SEE LICENSE IN ../LICENSE",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Interchouette-ITC/ceps-rust-ts-client"
+ },
+ "files": [
+ "ceps_client_wasm_bg.wasm",
+ "ceps_client_wasm.js",
+ "ceps_client_wasm.d.ts"
+ ],
+ "main": "ceps_client_wasm.js",
+ "homepage": "https://github.com/Interchouette-ITC/ceps-rust-ts-client",
+ "types": "ceps_client_wasm.d.ts"
+}
diff --git a/ceps-client-wasm-schema/pkg/README.md b/ceps-client-wasm-schema/pkg/README.md
new file mode 100644
index 0000000..f88ab12
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg/README.md
@@ -0,0 +1,320 @@
+# ceps-rust-ts-client
+
+One **Rust** client for Casper **CEP-18**, **CEP-78**, **CEP-85**, and **CEP-95**, with a **`ceps-client-cli`**, **`ceps-rust-ts-client-mcp`**, and **WASM packs** so the same client can run from shell, agents, Node, or the browser.
+
+It replaces the separate TypeScript **`client-js`** packages that lived next to each CEP contract. Instead of per-CEP JS clients, you use one library: `CEP18Client` / `CEP78Client` / `CEP85Client` / `CEP95Client`, on top of [`casper-rust-wasm-sdk`](https://github.com/casper-ecosystem/casper-rust-wasm-sdk).
+
+```text
+CEP-18 client-js ─┐
+CEP-78 client-js ─┼─→ ceps-client (Rust) + ceps-client-cli + ceps-rust-ts-client-mcp + ceps-client-wasm
+CEP-85 client-js ─┤
+CEP-95 JS client ─┘
+```
+
+## What you get
+
+
+
+
+
Piece
+
Name
+
Role
+
In-tree path
+
+
+
+
+
Rust library
+
ceps‑client
+
CEP API for native Rust apps
+
ceps-client/
+
+
+
CLI
+
ceps‑client‑cli
+
Status and common queries from the shell
+
ceps-client-cli/
+
+
+
MCP server
+
ceps-rust-ts-client-mcp
+
Full CEP agent tools (stdio / HTTP :6790)
+
mcp/
+
+
+
Client JS packs
+
ceps‑client‑wasm
+
Same CEP classes for Node and browsers (replaces per-CEP client-js)
+
ceps-client-wasm/pkg / pkg-nodejs
+
+
+
Demo contract WASMs
+
ceps‑contracts
+
On-chain bytecode for install (demo tips)
+
tests/wasm/{cep18,cep78,cep85,cep95}/
+
+
+
+
+Release downloads use the same names: `ceps-client-cli-*-linux-x86_64`, `ceps-rust-ts-client-mcp-*-linux-x86_64`, `ceps-client-wasm-*.tgz`, and `ceps-contracts-*.tgz`. The library / CLI / MCP / JS packs are this client; `ceps-contracts` is sample contract bytecode, not the JS library.
+
+## What you can do
+
+| CEP | Standard | Typical flow |
+| ------ | -------------- | -------------------------------------------------------------------------- |
+| **18** | Fungible token | install → bind hash → `name` / `balance_of` → `transfer` / `mint` / `burn` |
+| **78** | Enhanced NFT | install → bind hash → `mint` → `owner_of` / `balance_of` |
+| **85** | Multi-token | install → bind hash → `mint` / `burn` → `balance_of(account, id)` |
+| **95** | NFT (Odra tip) | install → `bind_odra_install` → `mint` → `owner_of` / `approve` |
+
+Defaults talk to local NCTL (`http://127.0.0.1:11101`, SSE `…:18101/events`, chain `casper-net-1`).
+
+## Usage
+
+Needs a running node, a secret-key PEM, and on-chain contract `.wasm` bytes (your own build, or the [demo tips](#contract-wasms-demos) via `make wasm-from-ceps`).
+
+### CEP-18 - fungible
+
+```text
+install → named keys cep18_contract_hash_* / package_*
+ → set_contract_hash
+ → name / symbol / balance_of
+ → transfer | mint | burn
+```
+
+```rust
+use ceps_client::cep18::InstallArgs;
+use ceps_client::{CEP18Client, TransactionParams, EventsMode, Verbosity};
+
+let mut client = CEP18Client::new(
+ "http://127.0.0.1:11101",
+ Some("http://127.0.0.1:18101/events".into()),
+ Some("casper-net-1".into()),
+ Some(Verbosity::Low),
+)?;
+
+let put = client
+ .install(
+ &InstallArgs::new("MyToken", "MTK", 9, "1000000000")
+ .with_events_mode(EventsMode::CES)
+ .with_mint_and_burn(true),
+ &contract_wasm_bytes,
+ &TransactionParams::new(&secret_pem, "400000000000"),
+ )
+ .await?;
+client.set_contract_hash(&contract_hash, Some(&package_hash))?;
+let bal = client.balance_of("account-hash-…").await?;
+```
+
+Details: [docs/cep18/](docs/cep18/) · example: `cargo run -p ceps-client --example cep18_install`
+
+### CEP-78 - NFT
+
+```text
+install → named keys cep78_contract_hash_* / package_*
+ → set_contract_hash
+ → mint → owner_of / balance_of
+```
+
+```rust
+use ceps_client::cep78::InstallArgs;
+use ceps_client::{CEP78Client, TransactionParams, EventsMode78, Verbosity};
+
+let mut client = CEP78Client::new(/* rpc, sse, chain, verbosity */)?;
+client
+ .install(
+ &InstallArgs::new("MyNft", "NFT", 100).with_events_mode(EventsMode78::CES),
+ &contract_wasm_bytes,
+ &TransactionParams::new(&secret_pem, "600000000000"),
+ )
+ .await?;
+client.set_contract_hash(&contract_hash, Some(&package_hash))?;
+client
+ .mint(
+ "account-hash-…",
+ r#"{"name":"token-1"}"#,
+ None,
+ &TransactionParams::new(&secret_pem, "5000000000"),
+ )
+ .await?;
+let owner = client.owner_of(&token_id).await?;
+```
+
+Details: [docs/cep78/](docs/cep78/) · example: `cargo run -p ceps-client --example cep78_install`
+
+### CEP-85 - multi-token
+
+```text
+install → named keys cep85_contract_hash_* / package_*
+ → set_contract_hash
+ → mint / burn → balance_of(account, id)
+```
+
+```rust
+use ceps_client::cep85::InstallArgs;
+use ceps_client::{CEP85Client, TransactionParams, EventsMode, Verbosity};
+
+let mut client = CEP85Client::new(/* rpc, sse, chain, verbosity */)?;
+client
+ .install(
+ &InstallArgs::new("MyMulti", "https://example.com/{id}.json")
+ .with_events_mode(EventsMode::CES)
+ .with_enable_burn(true),
+ &contract_wasm_bytes,
+ &TransactionParams::new(&secret_pem, "550000000000"),
+ )
+ .await?;
+client.set_contract_hash(&contract_hash, Some(&package_hash))?;
+client.mint(&owner, "1", "10", None, &TransactionParams::new(&secret_pem, "5000000000")).await?;
+let bal = client.balance_of(&owner, "1").await?;
+```
+
+Details: [docs/cep85/](docs/cep85/) · example: `cargo run -p ceps-client --example cep85_install`
+
+### CEP-95 - NFT (Odra tip)
+
+```text
+install (odra_cfg_package_hash_key_name) → bind_odra_install
+ → name / symbol / balance_of / owner_of
+ → mint | burn | transfer_from | approve*
+```
+
+```rust
+use ceps_client::cep95::InstallArgs;
+use ceps_client::{CEP95Client, TransactionParams, Verbosity};
+
+let mut client = CEP95Client::new(/* rpc, sse, chain, verbosity */)?;
+client
+ .install(
+ &InstallArgs::new("MyNft", "MNFT", "cep95_pkg_demo"),
+ &contract_wasm_bytes,
+ &TransactionParams::new(&secret_pem, "600000000000"),
+ )
+ .await?;
+client.bind_odra_install(&installer_public_key, "cep95_pkg_demo").await?;
+client.mint(&owner, "1", None, &TransactionParams::new(&secret_pem, "5000000000")).await?;
+let owner_of = client.owner_of("1").await?;
+```
+
+Details: [docs/cep95/](docs/cep95/) · example: `cargo run -p ceps-client --example cep95_install`
+
+### CLI
+
+```bash
+cargo run -p ceps-client-cli -- status
+cargo run -p ceps-client-cli -- cep18 info
+cargo run -p ceps-client-cli -- cep78 balance --contract-hash --account
+cargo run -p ceps-client-cli -- cep85 balance --contract-hash --account <…> --id 1
+cargo run -p ceps-client-cli -- cep95 owner-of --contract-hash --token-id 1
+```
+
+Mutations are on the library / examples today. Flags: [docs/cli.md](docs/cli.md).
+
+### Try an install end-to-end
+
+```bash
+make prepare && make build
+make wasm-from-ceps # copy demo tip contract WASMs into tests/wasm/
+# NCTL running + SECRET_KEY_USER_1 set to a PEM:
+cargo run -p ceps-client --example cep18_install
+```
+
+More setup: [docs/getting-started.md](docs/getting-started.md).
+
+## Client JS packs (`ceps-client-wasm`)
+
+`ceps-client-wasm` is the **Rust CEP client compiled for JavaScript** (the replacement for per-CEP `client-js`). Use it from Node or the browser for the same `CEP18Client` / `CEP78Client` / `CEP85Client` surface.
+
+It is **not** on-chain contract bytecode (that is `tests/wasm/` / `ceps-contracts-*.tgz`).
+
+| Target | In-tree (committed) | Typical use |
+| ------ | ------------------------------ | -------------------------- |
+| Node | `ceps-client-wasm/pkg-nodejs/` | Backend / scripts / Vitest |
+| Web | `ceps-client-wasm/pkg/` | Bundled frontends |
+
+Rebuild locally with `make pack` (or `make nodejs` / `make web`). Details: [docs/wasm-ts.md](docs/wasm-ts.md) · [docs/releases.md](docs/releases.md).
+
+**Or** fetch a published pack (no local `wasm-pack`):
+
+```bash
+TAG=v1.0.0 # or dev-preview
+LABEL=${TAG#v}
+curl -fsSL -o ceps-client-wasm-nodejs.tgz \
+ "https://github.com/Interchouette-ITC/ceps-rust-ts-client/releases/download/${TAG}/ceps-client-wasm-nodejs-${LABEL}.tgz"
+mkdir -p ceps-client-wasm && tar -xzf ceps-client-wasm-nodejs.tgz -C ceps-client-wasm
+# -> ceps-client-wasm/pkg-nodejs/
+```
+
+```js
+import { CEP18Client } from "ceps-client-wasm"; // file:./ceps-client-wasm/pkg-nodejs after unpack
+
+const client = new CEP18Client(
+ "http://127.0.0.1:11101",
+ "http://127.0.0.1:18101/events",
+ "casper-net-1",
+ 0,
+);
+client.setContractHash(contractHash, packageHash);
+const name = await client.name();
+const bal = await client.balanceOf("account-hash-…");
+```
+
+Install from JS takes contract bytes as `Uint8Array` and returns JSON `{ transactionHash, hasExecutionResult }`. Bound methods today are a subset of the Rust API (see [docs/wasm-ts.md](docs/wasm-ts.md)); full parity is on `ceps-client`.
+
+## Contract WASMs (demos)
+
+This client is **not** a contract repo. You pass on-chain `.wasm` into `install`.
+
+**In-tree:** the last staged demo tip builds ship under `tests/wasm/{cep18,cep78,cep85}/` (same idea as committing `pkg` / `pkg-nodejs`). Use those bytes directly, or refresh with `make wasm-from-ceps`.
+
+**Or** download the release bundle (no tip checkout / no contract build):
+
+```bash
+TAG=v1.0.0
+LABEL=${TAG#v}
+curl -fsSL -o ceps-contracts.tgz \
+ "https://github.com/Interchouette-ITC/ceps-rust-ts-client/releases/download/${TAG}/ceps-contracts-${LABEL}.tgz"
+mkdir -p tests/wasm && tar -xzf ceps-contracts.tgz -C tests/wasm
+```
+
+Tips are short-lived entity-era builds for demos/CI, not a claim of "the" upstream CEP tip forever. Sources:
+
+| CEP | Demo tip repo | Branch | What you get |
+| --- | ------------- | ------ | ------------ |
+| 18 | [Interchouette-ITC/cep-18](https://github.com/Interchouette-ITC/cep-18) | `ceps-client-test` | Fungible contract WASM |
+| 78 | [Interchouette-ITC/cep-78-enhanced-nft](https://github.com/Interchouette-ITC/cep-78-enhanced-nft) | `ceps-client-test` | NFT + session WASMs |
+| 85 | [Interchouette-ITC/cep-85](https://github.com/Interchouette-ITC/cep-85) | `ceps-client-test` | Multi-token WASM |
+
+```bash
+# after checking out those tips and building contracts there:
+make wasm-from-ceps # → tests/wasm/{cep18,cep78,cep85}/
+```
+
+Override checkout roots with `CEP18_PRODUCT` / `CEP78_PRODUCT` / `CEP85_PRODUCT`. Pins and SHAs: [docs/contributing.md](docs/contributing.md). All release downloads: [docs/releases.md](docs/releases.md).
+
+## Documentation
+
+| Doc | Description |
+| ------------------------------------------------------------------------------------------------------------ | ----------------------------------- |
+| [Getting started](docs/getting-started.md) | Build, NCTL defaults, first run |
+| [Architecture](docs/architecture.md) | How lib / CLI / WASM sit on the SDK |
+| [docs/cep18/](docs/cep18/) · [cep78/](docs/cep78/) · [cep85/](docs/cep85/) | Per-CEP guides |
+| [CLI](docs/cli.md) · [WASM / TS](docs/wasm-ts.md) | Surfaces |
+| [Testing](docs/testing.md) · [CI / CD](docs/ci.md) · [Releases](docs/releases.md) · [Docker](docs/docker.md) | Verify and ship |
+| [Contributing](docs/contributing.md) · [SDK](docs/sdk.md) | Tips, pins, upgrades |
+| [SECURITY.md](docs/SECURITY.md) | Keys and reporting |
+| `make doc` | rustdoc → `docs/api-rust/` |
+
+## Docker
+
+```bash
+make release-cli-bin && make docker-build IMAGE_TAG=local
+docker run --rm ceps-rust-ts-client:local --help
+docker pull interchouette/ceps-rust-ts-client:dev
+```
+
+See [docs/docker.md](docs/docker.md).
+
+## License / security
+
+GPL-3.0. See [LICENSE](LICENSE) and [docs/SECURITY.md](docs/SECURITY.md).
diff --git a/ceps-client-wasm-schema/pkg/ceps_client_wasm.d.ts b/ceps-client-wasm-schema/pkg/ceps_client_wasm.d.ts
new file mode 100644
index 0000000..4d3a342
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg/ceps_client_wasm.d.ts
@@ -0,0 +1,74 @@
+/* tslint:disable */
+/* eslint-disable */
+
+/**
+ * CEP-18 schema JSON.
+ */
+export function cep18SchemaJson(): string;
+
+/**
+ * CEP-78 schema JSON.
+ */
+export function cep78SchemaJson(): string;
+
+/**
+ * CEP-85 schema JSON.
+ */
+export function cep85SchemaJson(): string;
+
+/**
+ * CEP-95 schema JSON.
+ */
+export function cep95SchemaJson(): string;
+
+/**
+ * JSON schema for a CEP id (`cep18`, `cep78`, `cep85`, `cep95`).
+ */
+export function schemaJson(cep: string): string;
+
+/**
+ * Supported CEP id strings.
+ */
+export function supportedCeps(): any;
+
+export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
+
+export interface InitOutput {
+ readonly memory: WebAssembly.Memory;
+ readonly cep18SchemaJson: () => [number, number];
+ readonly cep78SchemaJson: () => [number, number];
+ readonly cep85SchemaJson: () => [number, number];
+ readonly cep95SchemaJson: () => [number, number];
+ readonly schemaJson: (a: number, b: number) => [number, number, number, number];
+ readonly supportedCeps: () => [number, number, number];
+ readonly __wbindgen_exn_store: (a: number) => void;
+ readonly __externref_table_alloc: () => number;
+ readonly __wbindgen_externrefs: WebAssembly.Table;
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
+ readonly __externref_table_dealloc: (a: number) => void;
+ readonly __wbindgen_start: () => void;
+}
+
+export type SyncInitInput = BufferSource | WebAssembly.Module;
+
+/**
+ * Instantiates the given `module`, which can either be bytes or
+ * a precompiled `WebAssembly.Module`.
+ *
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
+ *
+ * @returns {InitOutput}
+ */
+export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
+
+/**
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
+ * for everything else, calls `WebAssembly.instantiate` directly.
+ *
+ * @param {{ module_or_path: InitInput | Promise }} module_or_path - Passing `InitInput` directly is deprecated.
+ *
+ * @returns {Promise}
+ */
+export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise } | InitInput | Promise): Promise;
diff --git a/ceps-client-wasm-schema/pkg/ceps_client_wasm.js b/ceps-client-wasm-schema/pkg/ceps_client_wasm.js
new file mode 100644
index 0000000..3b01b37
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg/ceps_client_wasm.js
@@ -0,0 +1,333 @@
+/* @ts-self-types="./ceps_client_wasm.d.ts" */
+
+/**
+ * CEP-18 schema JSON.
+ * @returns {string}
+ */
+export function cep18SchemaJson() {
+ let deferred1_0;
+ let deferred1_1;
+ try {
+ const ret = wasm.cep18SchemaJson();
+ deferred1_0 = ret[0];
+ deferred1_1 = ret[1];
+ return getStringFromWasm0(ret[0], ret[1]);
+ } finally {
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
+ }
+}
+
+/**
+ * CEP-78 schema JSON.
+ * @returns {string}
+ */
+export function cep78SchemaJson() {
+ let deferred1_0;
+ let deferred1_1;
+ try {
+ const ret = wasm.cep78SchemaJson();
+ deferred1_0 = ret[0];
+ deferred1_1 = ret[1];
+ return getStringFromWasm0(ret[0], ret[1]);
+ } finally {
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
+ }
+}
+
+/**
+ * CEP-85 schema JSON.
+ * @returns {string}
+ */
+export function cep85SchemaJson() {
+ let deferred1_0;
+ let deferred1_1;
+ try {
+ const ret = wasm.cep85SchemaJson();
+ deferred1_0 = ret[0];
+ deferred1_1 = ret[1];
+ return getStringFromWasm0(ret[0], ret[1]);
+ } finally {
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
+ }
+}
+
+/**
+ * CEP-95 schema JSON.
+ * @returns {string}
+ */
+export function cep95SchemaJson() {
+ let deferred1_0;
+ let deferred1_1;
+ try {
+ const ret = wasm.cep95SchemaJson();
+ deferred1_0 = ret[0];
+ deferred1_1 = ret[1];
+ return getStringFromWasm0(ret[0], ret[1]);
+ } finally {
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
+ }
+}
+
+/**
+ * JSON schema for a CEP id (`cep18`, `cep78`, `cep85`, `cep95`).
+ * @param {string} cep
+ * @returns {string}
+ */
+export function schemaJson(cep) {
+ let deferred3_0;
+ let deferred3_1;
+ try {
+ const ptr0 = passStringToWasm0(cep, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ret = wasm.schemaJson(ptr0, len0);
+ var ptr2 = ret[0];
+ var len2 = ret[1];
+ if (ret[3]) {
+ ptr2 = 0; len2 = 0;
+ throw takeFromExternrefTable0(ret[2]);
+ }
+ deferred3_0 = ptr2;
+ deferred3_1 = len2;
+ return getStringFromWasm0(ptr2, len2);
+ } finally {
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
+ }
+}
+
+/**
+ * Supported CEP id strings.
+ * @returns {any}
+ */
+export function supportedCeps() {
+ const ret = wasm.supportedCeps();
+ if (ret[2]) {
+ throw takeFromExternrefTable0(ret[1]);
+ }
+ return takeFromExternrefTable0(ret[0]);
+}
+function __wbg_get_imports() {
+ const import0 = {
+ __proto__: null,
+ __wbg___wbindgen_throw_bb96b2010945f0bc: function(arg0, arg1) {
+ throw new Error(getStringFromWasm0(arg0, arg1));
+ },
+ __wbg_parse_1cc93481b0865939: function() { return handleError(function (arg0, arg1) {
+ const ret = JSON.parse(getStringFromWasm0(arg0, arg1));
+ return ret;
+ }, arguments); },
+ __wbindgen_cast_0000000000000001: function(arg0, arg1) {
+ // Cast intrinsic for `Ref(String) -> Externref`.
+ const ret = getStringFromWasm0(arg0, arg1);
+ return ret;
+ },
+ __wbindgen_init_externref_table: function() {
+ const table = wasm.__wbindgen_externrefs;
+ const offset = table.grow(4);
+ table.set(0, undefined);
+ table.set(offset + 0, undefined);
+ table.set(offset + 1, null);
+ table.set(offset + 2, true);
+ table.set(offset + 3, false);
+ },
+ };
+ return {
+ __proto__: null,
+ "./ceps_client_wasm_bg.js": import0,
+ };
+}
+
+function addToExternrefTable0(obj) {
+ const idx = wasm.__externref_table_alloc();
+ wasm.__wbindgen_externrefs.set(idx, obj);
+ return idx;
+}
+
+function getStringFromWasm0(ptr, len) {
+ return decodeText(ptr >>> 0, len);
+}
+
+let cachedUint8ArrayMemory0 = null;
+function getUint8ArrayMemory0() {
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
+ }
+ return cachedUint8ArrayMemory0;
+}
+
+function handleError(f, args) {
+ try {
+ return f.apply(this, args);
+ } catch (e) {
+ const idx = addToExternrefTable0(e);
+ wasm.__wbindgen_exn_store(idx);
+ }
+}
+
+function passStringToWasm0(arg, malloc, realloc) {
+ if (realloc === undefined) {
+ const buf = cachedTextEncoder.encode(arg);
+ const ptr = malloc(buf.length, 1) >>> 0;
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
+ WASM_VECTOR_LEN = buf.length;
+ return ptr;
+ }
+
+ let len = arg.length;
+ let ptr = malloc(len, 1) >>> 0;
+
+ const mem = getUint8ArrayMemory0();
+
+ let offset = 0;
+
+ for (; offset < len; offset++) {
+ const code = arg.charCodeAt(offset);
+ if (code > 0x7F) break;
+ mem[ptr + offset] = code;
+ }
+ if (offset !== len) {
+ if (offset !== 0) {
+ arg = arg.slice(offset);
+ }
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
+ const ret = cachedTextEncoder.encodeInto(arg, view);
+
+ offset += ret.written;
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
+ }
+
+ WASM_VECTOR_LEN = offset;
+ return ptr;
+}
+
+function takeFromExternrefTable0(idx) {
+ const value = wasm.__wbindgen_externrefs.get(idx);
+ wasm.__externref_table_dealloc(idx);
+ return value;
+}
+
+let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
+cachedTextDecoder.decode();
+const MAX_SAFARI_DECODE_BYTES = 2146435072;
+let numBytesDecoded = 0;
+function decodeText(ptr, len) {
+ numBytesDecoded += len;
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
+ cachedTextDecoder.decode();
+ numBytesDecoded = len;
+ }
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
+}
+
+const cachedTextEncoder = new TextEncoder();
+
+if (!('encodeInto' in cachedTextEncoder)) {
+ cachedTextEncoder.encodeInto = function (arg, view) {
+ const buf = cachedTextEncoder.encode(arg);
+ view.set(buf);
+ return {
+ read: arg.length,
+ written: buf.length
+ };
+ };
+}
+
+let WASM_VECTOR_LEN = 0;
+
+let wasmModule, wasmInstance, wasm;
+function __wbg_finalize_init(instance, module) {
+ wasmInstance = instance;
+ wasm = instance.exports;
+ wasmModule = module;
+ cachedUint8ArrayMemory0 = null;
+ wasm.__wbindgen_start();
+ return wasm;
+}
+
+async function __wbg_load(module, imports) {
+ if (typeof Response === 'function' && module instanceof Response) {
+ if (!module.ok) {
+ throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`);
+ }
+
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
+ try {
+ return await WebAssembly.instantiateStreaming(module, imports);
+ } catch (e) {
+ const validResponse = expectedResponseType(module.type);
+
+ if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
+
+ } else { throw e; }
+ }
+ }
+
+ const bytes = await module.arrayBuffer();
+ return await WebAssembly.instantiate(bytes, imports);
+ } else {
+ const instance = await WebAssembly.instantiate(module, imports);
+
+ if (instance instanceof WebAssembly.Instance) {
+ return { instance, module };
+ } else {
+ return instance;
+ }
+ }
+
+ function expectedResponseType(type) {
+ switch (type) {
+ case 'basic': case 'cors': case 'default': return true;
+ }
+ return false;
+ }
+}
+
+function initSync(module) {
+ if (wasm !== undefined) return wasm;
+
+
+ if (module !== undefined) {
+ if (Object.getPrototypeOf(module) === Object.prototype) {
+ ({module} = module)
+ } else {
+ console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
+ }
+ }
+
+ const imports = __wbg_get_imports();
+ if (!(module instanceof WebAssembly.Module)) {
+ module = new WebAssembly.Module(module);
+ }
+ const instance = new WebAssembly.Instance(module, imports);
+ return __wbg_finalize_init(instance, module);
+}
+
+async function __wbg_init(module_or_path) {
+ if (wasm !== undefined) return wasm;
+
+
+ if (module_or_path !== undefined) {
+ if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
+ ({module_or_path} = module_or_path)
+ } else {
+ console.warn('using deprecated parameters for the initialization function; pass a single object instead')
+ }
+ }
+
+ if (module_or_path === undefined) {
+ module_or_path = new URL('ceps_client_wasm_bg.wasm', import.meta.url);
+ }
+ const imports = __wbg_get_imports();
+
+ if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
+ module_or_path = fetch(module_or_path);
+ }
+
+ const { instance, module } = await __wbg_load(await module_or_path, imports);
+
+ return __wbg_finalize_init(instance, module);
+}
+
+export { initSync, __wbg_init as default };
diff --git a/ceps-client-wasm-schema/pkg/ceps_client_wasm_bg.wasm b/ceps-client-wasm-schema/pkg/ceps_client_wasm_bg.wasm
new file mode 100644
index 0000000..54c5e08
Binary files /dev/null and b/ceps-client-wasm-schema/pkg/ceps_client_wasm_bg.wasm differ
diff --git a/ceps-client-wasm-schema/pkg/ceps_client_wasm_bg.wasm.d.ts b/ceps-client-wasm-schema/pkg/ceps_client_wasm_bg.wasm.d.ts
new file mode 100644
index 0000000..4c995f3
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg/ceps_client_wasm_bg.wasm.d.ts
@@ -0,0 +1,17 @@
+/* tslint:disable */
+/* eslint-disable */
+export const memory: WebAssembly.Memory;
+export const cep18SchemaJson: () => [number, number];
+export const cep78SchemaJson: () => [number, number];
+export const cep85SchemaJson: () => [number, number];
+export const cep95SchemaJson: () => [number, number];
+export const schemaJson: (a: number, b: number) => [number, number, number, number];
+export const supportedCeps: () => [number, number, number];
+export const __wbindgen_exn_store: (a: number) => void;
+export const __externref_table_alloc: () => number;
+export const __wbindgen_externrefs: WebAssembly.Table;
+export const __wbindgen_free: (a: number, b: number, c: number) => void;
+export const __wbindgen_malloc: (a: number, b: number) => number;
+export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
+export const __externref_table_dealloc: (a: number) => void;
+export const __wbindgen_start: () => void;
diff --git a/ceps-client-wasm-schema/pkg/package.json b/ceps-client-wasm-schema/pkg/package.json
new file mode 100644
index 0000000..2ae9d72
--- /dev/null
+++ b/ceps-client-wasm-schema/pkg/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "ceps-client-wasm-schema",
+ "type": "module",
+ "collaborators": [
+ "3099551+gRoussac@users.noreply.github.com"
+ ],
+ "description": "wasm-bindgen CEP client for Node and browsers (same API as ceps-client; replaces per-CEP client-js).",
+ "version": "1.0.0",
+ "license": "SEE LICENSE IN ../LICENSE",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Interchouette-ITC/ceps-rust-ts-client"
+ },
+ "files": [
+ "ceps_client_wasm_bg.wasm",
+ "ceps_client_wasm.js",
+ "ceps_client_wasm.d.ts"
+ ],
+ "main": "ceps_client_wasm.js",
+ "homepage": "https://github.com/Interchouette-ITC/ceps-rust-ts-client",
+ "types": "ceps_client_wasm.d.ts",
+ "sideEffects": [
+ "./snippets/*"
+ ]
+}
diff --git a/docker/Dockerfile b/docker/Dockerfile
index fc33ecd..a2449f5 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -4,6 +4,7 @@ FROM --platform=linux/amd64 node:24-alpine AS build
WORKDIR /app
COPY casper-rust-wasm-sdk ./casper-rust-wasm-sdk
+COPY ceps-client-wasm-schema ./ceps-client-wasm-schema
COPY wasm ./wasm
COPY www/package.json www/package-lock.json www/decorate-angular-cli.js ./www/
WORKDIR /app/www
diff --git a/www/apps/frontend/project.json b/www/apps/frontend/project.json
index 4e08b40..fe877d4 100644
--- a/www/apps/frontend/project.json
+++ b/www/apps/frontend/project.json
@@ -31,6 +31,11 @@
"input": "node_modules/casper-rust-wasm-sdk",
"glob": "casper_rust_wasm_sdk_bg.wasm",
"output": "assets"
+ },
+ {
+ "input": "node_modules/ceps-client-wasm-schema",
+ "glob": "ceps_client_wasm_bg.wasm",
+ "output": "assets"
}
],
"styles": [
diff --git a/www/libs/api-interfaces/src/index.ts b/www/libs/api-interfaces/src/index.ts
index db9b100..2ebd767 100644
--- a/www/libs/api-interfaces/src/index.ts
+++ b/www/libs/api-interfaces/src/index.ts
@@ -2,3 +2,4 @@ export * from './lib/api-interfaces';
export * from './lib/api-enums';
export * from './lib/cl-type';
export * from './lib/stored-value';
+export * from './lib/session-args';
diff --git a/www/libs/api-interfaces/src/lib/api-interfaces.ts b/www/libs/api-interfaces/src/lib/api-interfaces.ts
index 64915d5..dcae1a0 100644
--- a/www/libs/api-interfaces/src/lib/api-interfaces.ts
+++ b/www/libs/api-interfaces/src/lib/api-interfaces.ts
@@ -3,6 +3,10 @@ import { CLType } from './cl-type';
export type NamedCLTypeArg = {
name: string;
cl_type: CLType;
+ /** Prefer this when emitting session_args_json (from chain or ceps schema). */
+ session_type?: string | Record;
+ /** Prefill value from existing Args JSON. */
+ value?: unknown;
entry_points?: string[];
install?: boolean;
entry_point?: boolean;
diff --git a/www/libs/api-interfaces/src/lib/session-args.ts b/www/libs/api-interfaces/src/lib/session-args.ts
new file mode 100644
index 0000000..28c987f
--- /dev/null
+++ b/www/libs/api-interfaces/src/lib/session-args.ts
@@ -0,0 +1,439 @@
+/** Session args JSON helpers for the Args builder (casper-client session_args_json shape). */
+
+import { CLType } from './cl-type';
+import { NamedCLTypeArg } from './api-interfaces';
+
+/** One entry in session_args_json / ceps ArgField type field. */
+export type SessionArgType = string | Record;
+
+/** Parsed runtime arg row. */
+export type SessionArgRow = {
+ name: string;
+ type: SessionArgType;
+ value?: unknown;
+};
+
+/** ceps-client schema ArgField. */
+export type CepArgField = {
+ name: string;
+ type: SessionArgType;
+ optional?: boolean;
+};
+
+/** Full CEP schema from schemaJson(). */
+export type CepSchema = {
+ cep: string;
+ install: CepArgField[];
+ entrypoints: Record;
+};
+
+/** Parse session_args_json; empty / invalid → []. */
+export function parseSessionArgsJson(json: string | null | undefined): SessionArgRow[] {
+ if (!json || !String(json).trim()) {
+ return [];
+ }
+ try {
+ const parsed = JSON.parse(String(json).trim()) as unknown;
+ if (!Array.isArray(parsed)) {
+ return [];
+ }
+ const rows: SessionArgRow[] = [];
+ for (const item of parsed) {
+ if (!item || typeof item !== 'object') {
+ continue;
+ }
+ const name = (item as { name?: unknown }).name;
+ const type = (item as { type?: unknown }).type;
+ if (typeof name !== 'string' || name.length === 0 || type === undefined) {
+ continue;
+ }
+ rows.push({
+ name,
+ type: type as SessionArgType,
+ value: (item as { value?: unknown }).value,
+ });
+ }
+ return rows;
+ } catch {
+ return [];
+ }
+}
+
+/** Serialize rows to session_args_json. Omits rows with empty name or undefined value. */
+export function serializeSessionArgsJson(rows: SessionArgRow[]): string {
+ const out = rows
+ .filter((r) => r.name && r.value !== undefined && r.value !== '')
+ .map((r) => ({
+ name: r.name,
+ type: r.type,
+ value: r.value,
+ }));
+ return JSON.stringify(out);
+}
+
+/** RPC / Parameter cl_type → session_args_json type field. */
+export function clTypeToSessionType(clType: unknown): SessionArgType {
+ if (clType === null || clType === undefined) {
+ return 'Any';
+ }
+ if (typeof clType === 'string') {
+ return clType;
+ }
+ if (typeof clType === 'object') {
+ const obj = clType as Record;
+ if ('Option' in obj) {
+ return { Option: clTypeToSessionType(obj['Option']) };
+ }
+ if ('List' in obj) {
+ return { List: clTypeToSessionType(obj['List']) };
+ }
+ if ('ByteArray' in obj) {
+ return { ByteArray: obj['ByteArray'] as number };
+ }
+ if ('Result' in obj) {
+ const result = obj['Result'] as { ok?: unknown; err?: unknown } | unknown[];
+ if (Array.isArray(result) && result.length >= 2) {
+ return {
+ Result: {
+ ok: clTypeToSessionType(result[0]),
+ err: clTypeToSessionType(result[1]),
+ },
+ };
+ }
+ const r = result as { ok?: unknown; err?: unknown };
+ return {
+ Result: {
+ ok: clTypeToSessionType(r.ok),
+ err: clTypeToSessionType(r.err),
+ },
+ };
+ }
+ if ('Map' in obj) {
+ const map = obj['Map'] as { key?: unknown; value?: unknown } | unknown[];
+ if (Array.isArray(map) && map.length >= 2) {
+ return {
+ Map: {
+ key: clTypeToSessionType(map[0]),
+ value: clTypeToSessionType(map[1]),
+ },
+ };
+ }
+ const m = map as { key?: unknown; value?: unknown };
+ return {
+ Map: {
+ key: clTypeToSessionType(m.key),
+ value: clTypeToSessionType(m.value),
+ },
+ };
+ }
+ if ('Tuple1' in obj) {
+ const t = obj['Tuple1'];
+ const inner = Array.isArray(t) ? t[0] : t;
+ return { Tuple1: [clTypeToSessionType(inner)] };
+ }
+ if ('Tuple2' in obj) {
+ const t = obj['Tuple2'] as unknown[];
+ return {
+ Tuple2: [clTypeToSessionType(t?.[0]), clTypeToSessionType(t?.[1])],
+ };
+ }
+ if ('Tuple3' in obj) {
+ const t = obj['Tuple3'] as unknown[];
+ return {
+ Tuple3: [
+ clTypeToSessionType(t?.[0]),
+ clTypeToSessionType(t?.[1]),
+ clTypeToSessionType(t?.[2]),
+ ],
+ };
+ }
+ }
+ if (clType instanceof CLType || (clType as { toString?: () => string }).toString) {
+ return sessionTypeFromClTypeLabel(String(clType));
+ }
+ return 'Any';
+}
+
+/** Best-effort parse of CLType.toString() labels into session type. */
+function sessionTypeFromClTypeLabel(label: string): SessionArgType {
+ const trimmed = label.trim();
+ const option = /^Option\((.*)\)$/.exec(trimmed);
+ if (option) {
+ return { Option: sessionTypeFromClTypeLabel(option[1]) };
+ }
+ const list = /^List\((.*)\)$/.exec(trimmed);
+ if (list) {
+ return { List: sessionTypeFromClTypeLabel(list[1]) };
+ }
+ const map = /^Map\((.*), (.*)\)$/.exec(trimmed);
+ if (map) {
+ return {
+ Map: {
+ key: sessionTypeFromClTypeLabel(map[1]),
+ value: sessionTypeFromClTypeLabel(map[2]),
+ },
+ };
+ }
+ const tuple1 = /^Tuple1\((.*)\)$/.exec(trimmed);
+ if (tuple1) {
+ return { Tuple1: [sessionTypeFromClTypeLabel(tuple1[1])] };
+ }
+ const tuple2 = /^Tuple2\((.*), (.*)\)$/.exec(trimmed);
+ if (tuple2) {
+ return {
+ Tuple2: [
+ sessionTypeFromClTypeLabel(tuple2[1]),
+ sessionTypeFromClTypeLabel(tuple2[2]),
+ ],
+ };
+ }
+ const tuple3 = /^Tuple3\((.*), (.*), (.*)\)$/.exec(trimmed);
+ if (tuple3) {
+ return {
+ Tuple3: [
+ sessionTypeFromClTypeLabel(tuple3[1]),
+ sessionTypeFromClTypeLabel(tuple3[2]),
+ sessionTypeFromClTypeLabel(tuple3[3]),
+ ],
+ };
+ }
+ const result = /^Result\((.*), (.*)\)$/.exec(trimmed);
+ if (result) {
+ return {
+ Result: {
+ ok: sessionTypeFromClTypeLabel(result[1]),
+ err: sessionTypeFromClTypeLabel(result[2]),
+ },
+ };
+ }
+ return trimmed || 'Any';
+}
+
+/** Build a CLType for the argument select from a session type. */
+export function sessionTypeToClType(type: SessionArgType): CLType {
+ if (typeof type === 'string') {
+ switch (type) {
+ case 'Bool':
+ return CLType.Bool();
+ case 'I32':
+ return CLType.I32();
+ case 'I64':
+ return CLType.I64();
+ case 'U8':
+ return CLType.U8();
+ case 'U32':
+ return CLType.U32();
+ case 'U64':
+ return CLType.U64();
+ case 'U128':
+ return CLType.U128();
+ case 'U256':
+ return CLType.U256();
+ case 'U512':
+ return CLType.U512();
+ case 'Unit':
+ return CLType.Unit();
+ case 'String':
+ return CLType.String();
+ case 'Key':
+ return CLType.Key();
+ case 'URef':
+ return CLType.URef();
+ case 'PublicKey':
+ return CLType.PublicKey();
+ case 'ByteArray':
+ return CLType.ByteArray();
+ case 'Any':
+ return CLType.Any();
+ default:
+ return CLType.Any();
+ }
+ }
+ if (type && typeof type === 'object') {
+ if ('Option' in type) {
+ return CLType.Option(sessionTypeToClType(type['Option'] as SessionArgType));
+ }
+ if ('List' in type) {
+ return CLType.List(sessionTypeToClType(type['List'] as SessionArgType));
+ }
+ if ('ByteArray' in type) {
+ return CLType.ByteArray();
+ }
+ if ('Map' in type) {
+ const map = type['Map'] as { key: SessionArgType; value: SessionArgType };
+ return CLType.Map(
+ sessionTypeToClType(map.key),
+ sessionTypeToClType(map.value),
+ );
+ }
+ if ('Result' in type) {
+ const result = type['Result'] as {
+ ok: SessionArgType;
+ err: SessionArgType;
+ };
+ return CLType.Result(
+ sessionTypeToClType(result.ok),
+ sessionTypeToClType(result.err),
+ );
+ }
+ if ('Tuple1' in type) {
+ const t = type['Tuple1'] as SessionArgType[];
+ return CLType.Tuple1(sessionTypeToClType(t[0]));
+ }
+ if ('Tuple2' in type) {
+ const t = type['Tuple2'] as SessionArgType[];
+ return CLType.Tuple2(
+ sessionTypeToClType(t[0]),
+ sessionTypeToClType(t[1]),
+ );
+ }
+ if ('Tuple3' in type) {
+ const t = type['Tuple3'] as SessionArgType[];
+ return CLType.Tuple3(
+ sessionTypeToClType(t[0]),
+ sessionTypeToClType(t[1]),
+ sessionTypeToClType(t[2]),
+ );
+ }
+ }
+ return CLType.Any();
+}
+
+/** On-chain Parameter-like → NamedCLTypeArg for storage / Custom tab. */
+export function parameterToNamedArg(param: {
+ name?: string;
+ cl_type?: unknown;
+}): NamedCLTypeArg | null {
+ if (!param?.name || typeof param.name !== 'string') {
+ return null;
+ }
+ const sessionType = clTypeToSessionType(param.cl_type);
+ return {
+ name: param.name,
+ cl_type: sessionTypeToClType(sessionType),
+ session_type: sessionType,
+ };
+}
+
+/** ceps ArgField → NamedCLTypeArg. */
+export function cepFieldToNamedArg(field: CepArgField): NamedCLTypeArg {
+ return {
+ name: field.name,
+ cl_type: sessionTypeToClType(field.type),
+ session_type: field.type,
+ optional: !!field.optional,
+ };
+}
+
+/** Normalize any schema-like row into NamedCLTypeArg. */
+export function toNamedArg(raw: unknown): NamedCLTypeArg | null {
+ if (!raw || typeof raw !== 'object') {
+ return null;
+ }
+ const obj = raw as Record;
+ if (typeof obj['name'] !== 'string' || !obj['name']) {
+ return null;
+ }
+ if ('type' in obj && !('cl_type' in obj)) {
+ return cepFieldToNamedArg(obj as unknown as CepArgField);
+ }
+ if ('cl_type' in obj) {
+ const cl = obj['cl_type'];
+ if (cl instanceof CLType) {
+ return {
+ name: obj['name'] as string,
+ cl_type: cl,
+ session_type:
+ (obj['session_type'] as SessionArgType | undefined) ??
+ clTypeToSessionType(String(cl)),
+ optional: !!obj['optional'],
+ value: obj['value'],
+ };
+ }
+ const sessionType =
+ (obj['session_type'] as SessionArgType | undefined) ??
+ clTypeToSessionType(cl);
+ return {
+ name: obj['name'] as string,
+ cl_type: sessionTypeToClType(sessionType),
+ session_type: sessionType,
+ optional: !!obj['optional'],
+ value: obj['value'],
+ };
+ }
+ return null;
+}
+
+/**
+ * Merge schema (names/types) with existing JSON values by name.
+ * Schema types win; values come from the JSON rows when present.
+ */
+export function mergeSchemaWithValues(
+ schema: unknown[],
+ values: SessionArgRow[],
+): NamedCLTypeArg[] {
+ const byName = new Map(values.map((v) => [v.name, v]));
+ const rows: NamedCLTypeArg[] = [];
+ for (const raw of schema) {
+ const row = toNamedArg(raw);
+ if (!row) {
+ continue;
+ }
+ const existing = byName.get(row.name);
+ if (existing && existing.value !== undefined) {
+ rows.push({ ...row, value: existing.value });
+ } else {
+ rows.push(row);
+ }
+ }
+ return rows;
+}
+
+/** Coerce a form value for session_args_json based on session type. */
+export function coerceSessionValue(
+ type: SessionArgType,
+ raw: string,
+): unknown {
+ const trimmed = raw.trim();
+ if (trimmed === '') {
+ return undefined;
+ }
+ if (typeof type === 'string') {
+ switch (type) {
+ case 'Bool':
+ return trimmed.toLowerCase() === 'true';
+ case 'I32':
+ case 'I64':
+ case 'U8':
+ case 'U32':
+ case 'U64': {
+ const n = Number(trimmed);
+ return Number.isFinite(n) ? n : trimmed;
+ }
+ case 'U128':
+ case 'U256':
+ case 'U512':
+ return trimmed;
+ case 'Unit':
+ return null;
+ default:
+ return trimmed;
+ }
+ }
+ try {
+ return JSON.parse(trimmed);
+ } catch {
+ return trimmed;
+ }
+}
+
+/** NamedCLTypeArg list → SessionArgRow list for serialize. */
+export function namedArgsToSessionRows(args: NamedCLTypeArg[]): SessionArgRow[] {
+ return args
+ .filter((a) => a.name && a.value !== undefined && a.value !== '')
+ .map((a) => ({
+ name: a.name,
+ type: a.session_type ?? clTypeToSessionType(a.cl_type),
+ value: a.value,
+ }));
+}
diff --git a/www/libs/feature/deployer/src/lib/arg-builder/arg-builder.component.html b/www/libs/feature/deployer/src/lib/arg-builder/arg-builder.component.html
index 7f984b3..710df43 100644
--- a/www/libs/feature/deployer/src/lib/arg-builder/arg-builder.component.html
+++ b/www/libs/feature/deployer/src/lib/arg-builder/arg-builder.component.html
@@ -42,22 +42,12 @@