{"_id":"@casper-ecosystem/cep-95-js-client","name":"@casper-ecosystem/cep-95-js-client","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@casper-ecosystem/cep-95-js-client","version":"1.0.0","license":"Apache-2.0","description":"JavaScript/TypeScript client for CEP-95 (ERC-721 equivalent) NFT contracts on the Casper Network","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/casper-ecosystem/cep-95-js-client.git"},"homepage":"https://github.com/casper-ecosystem/cep-95-js-client#readme","bugs":{"url":"https://github.com/casper-ecosystem/cep-95-js-client/issues"},"scripts":{"build":"tsc","clean":"rm -rf ./dist","format":"prettier --write \"src/**/*.ts\"","format:check":"prettier --check \"src/**/*.ts\"","test":"cross-env NODE_ENV=test TS_NODE_FILES=true mocha --require ts-node/register/transpile-only --extension ts \"src/tests/**/*.test.ts\"","prepublishOnly":"npm run format:check && npm test && npm run clean && npm run build","playground":"npm run dev --prefix playground"},"keywords":["Casper","CEP-95","NFT","ERC-721","blockchain","sdk"],"peerDependencies":{"casper-js-sdk":"^5.0.11"},"devDependencies":{"@types/chai":"^4.1.7","@types/mocha":"^5.2.7","@types/node":"^14.14.31","casper-js-sdk":"^5.0.11","chai":"^4.2.0","cross-env":"^7.0.3","mocha":"^10.1.0","prettier":"^3.0.0","ts-node":"^10.9.2","typescript":"^5.9.3"},"dependencies":{"@noble/hashes":"^1.3.3"},"publishConfig":{"access":"public"},"gitHead":"1448c6efce3936a4be543f662c25dad04cfe7cd6","_id":"@casper-ecosystem/cep-95-js-client@1.0.0","_nodeVersion":"18.14.2","_npmVersion":"9.5.0","dist":{"integrity":"sha512-yNCM6DORsIW8BMEmK+5MWbslLH7XwSfc6zqcTUQYnq0Bhhw6CQAbA1WKTwbB3f5HavpiVebR0pFY9HAKrh+WhA==","shasum":"e90fef87c7577ec61cb9b1756dda1cea438760c9","tarball":"https://registry.npmjs.org/@casper-ecosystem/cep-95-js-client/-/cep-95-js-client-1.0.0.tgz","fileCount":16,"unpackedSize":76037,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCYcWMTNBfPdmkMzSVkK9v0fL+11OMPTYrPpSmaNUQFogIgUay1IBVQMzuvzVgjROV9klYohcAEiewH49N+uXjnub4="}]},"_npmUser":{"name":"alex_myshchyshyn","email":"oleksandrm@make.services"},"directories":{},"maintainers":[{"name":"michaelsteuer","email":"michael@make.services"},{"name":"make.services","email":"david.hernando@make.services"},{"name":"burlachenko","email":"ihor.burlachenko@gmail.com"},{"name":"alex_myshchyshyn","email":"oleksandrm@make.services"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cep-95-js-client_1.0.0_1775765175383_0.1931514381887851"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-09T20:06:15.208Z","1.0.0":"2026-04-09T20:06:15.556Z","modified":"2026-04-09T20:06:15.945Z"},"maintainers":[{"name":"michaelsteuer","email":"michael@make.services"},{"name":"make.services","email":"david.hernando@make.services"},{"name":"burlachenko","email":"ihor.burlachenko@gmail.com"},{"name":"alex_myshchyshyn","email":"oleksandrm@make.services"}],"description":"JavaScript/TypeScript client for CEP-95 (ERC-721 equivalent) NFT contracts on the Casper Network","homepage":"https://github.com/casper-ecosystem/cep-95-js-client#readme","keywords":["Casper","CEP-95","NFT","ERC-721","blockchain","sdk"],"repository":{"type":"git","url":"git+https://github.com/casper-ecosystem/cep-95-js-client.git"},"bugs":{"url":"https://github.com/casper-ecosystem/cep-95-js-client/issues"},"license":"Apache-2.0","readme":"# @casper-ecosystem/cep-95-js-client\n\n<p>\n  <a href=\"https://www.npmjs.com/package/@casper-ecosystem/cep-95-js-client\"><img src=\"https://img.shields.io/npm/v/%40casper--ecosystem%2Fcep--95--js--client?color=crimson&label=npm\" alt=\"npm version\" /></a>\n  <a href=\"https://www.npmjs.com/package/casper-js-sdk\"><img src=\"https://img.shields.io/badge/casper--js--sdk-%5E5.0.0-blue\" alt=\"casper-js-sdk peer\" /></a>\n  <img src=\"https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript&logoColor=white\" alt=\"TypeScript\" />\n  <img src=\"https://img.shields.io/badge/CEP--95-NFT%20Standard-orange\" alt=\"CEP-95\" />\n  <img src=\"https://img.shields.io/badge/ERC--721-compatible-green\" alt=\"ERC-721 compatible\" />\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/license-Apache%202.0-brightgreen\" alt=\"license\" /></a>\n  <a href=\"CHANGELOG.md\"><img src=\"https://img.shields.io/badge/changelog-1.0.0-lightgrey\" alt=\"changelog\" /></a>\n</p>\n\nJavaScript/TypeScript client for **CEP-95** (ERC-721 equivalent) NFT contracts on the [Casper Network](https://casper.network).\n\nCEP-95 is the Casper NFT standard - each token is unique, indivisible, and identified by a `U256` token ID. This library provides a clean, typed interface for all read and write operations defined by the standard.\n\nBuilt on top of [`casper-js-sdk`](https://github.com/casper-ecosystem/casper-js-sdk).\n\n---\n\n## Installation\n\n```bash\nnpm install @casper-ecosystem/cep-95-js-client casper-js-sdk\n```\n\n---\n\n## Quick start\n\n```ts\nimport { Cep95Client } from '@casper-ecosystem/cep-95-js-client';\nimport { PublicKey, PrivateKey, KeyAlgorithm } from 'casper-js-sdk';\n\nconst client = new Cep95Client('http://<Node Address>:7777/rpc', 'casper-test');\n\nclient.setContractHash(\n  'contract-hash-834d3e29...', // versioned contract hash (for reads)\n  'contract-package-712bf529...' // contract package hash (for writes)\n);\n\n// Read collection info\nconst name = await client.name(); // \"NAME\"\nconst symbol = await client.symbol(); // \"SYM\"\nconst totalSupply = await client.totalSupply(); // \"10000\"\n\n// Query per-account / per-token state\nconst alice = PublicKey.fromHex('01aabbcc...');\nconst balance = await client.balanceOf(alice);\nconst owner = await client.ownerOf('42');\nconst meta = await client.tokenMetadata('42');\n\n// Submit a transfer\nconst privateKey = await PrivateKey.generate(KeyAlgorithm.ED25519);\nconst recipient = PublicKey.fromHex('01ddeeff...');\n\nconst result = await client.transferFrom({\n  args: { from: privateKey.publicKey, to: recipient, tokenId: '42' },\n  params: { sender: privateKey.publicKey, paymentAmount: '2500000000', signingKeys: [privateKey] }\n});\n\nconsole.log('TX hash:', result.transactionInfo.transactionHash.toHex());\n```\n\n### Awaiting on-chain execution (SSE)\n\nBy default write methods return as soon as the node accepts the transaction. Pass `sseUrl` and `waitForTransactionProcessed: true` to block until the node confirms execution and receive the `executionResult`:\n\n```ts\nconst client = new Cep95Client(\n  'http://<Node Address>:7777/rpc',\n  'casper-test',\n  'http://<Node Address>:9999/events/main' // SSE stream URL\n);\n\n// or set it later:\nclient.sseUrl = 'http://<Node Address>:9999/events/main';\n\nconst result = await client.mint({\n  args: { to: recipient, tokenId: '100' },\n  params: { sender: privateKey.publicKey, paymentAmount: '5000000000', signingKeys: [privateKey] },\n  waitForTransactionProcessed: true\n});\n\nconsole.log('TX hash:', result.transactionInfo.transactionHash.toHex());\nconsole.log('Error (if any):', result.executionResult?.errorMessage ?? 'none');\n```\n\n`waitForTransactionProcessed` is silently ignored when `sseUrl` is not set, so it is safe to always pass it and configure the URL only when needed. The SSE subscription times out after **60 seconds** and rejects with an error.\n\n---\n\n## API\n\n### `Cep95Client`\n\n#### Constructor\n\n```ts\nnew Cep95Client(rpcUrl: string, chainName?: string, sseUrl?: string)\n```\n\n| Parameter   | Description                                                                                                      |\n| ----------- | ---------------------------------------------------------------------------------------------------------------- |\n| `rpcUrl`    | Full URL of the Casper node RPC endpoint (e.g. `http://node:7777/rpc`).                                          |\n| `chainName` | Chain name for write transactions - `\"casper\"` (mainnet) or `\"casper-test\"` (testnet).                           |\n| `sseUrl`    | Optional SSE event-stream URL (e.g. `http://node:9999/events/main`). Required for `waitForTransactionProcessed`. |\n\n#### Properties\n\n| Property    | Type                  | Description                                     |\n| ----------- | --------------------- | ----------------------------------------------- |\n| `chainName` | `string \\| undefined` | Chain name used in write transactions.          |\n| `sseUrl`    | `string \\| undefined` | SSE stream URL for awaiting on-chain execution. |\n\n#### Methods\n\n| Method                                | Description                                                                        |\n| ------------------------------------- | ---------------------------------------------------------------------------------- |\n| `setContractHash(hash, packageHash?)` | Configure target contract. Accepts bare hex or prefixed strings. Returns `this`.   |\n| `name()`                              | Returns the NFT collection name (`String`).                                        |\n| `symbol()`                            | Returns the NFT collection symbol (`String`).                                      |\n| `totalSupply()`                       | Returns the total number of minted tokens (`U256` as decimal string).              |\n| `balanceOf(owner)`                    | Returns the token balance of `owner`. Returns `\"0\"` if no entry exists.            |\n| `ownerOf(tokenId)`                    | Returns the owner of a token as a prefixed string. Throws if token does not exist. |\n| `getApproved(tokenId)`                | Returns the approved spender for a token, or `null`.                               |\n| `isApprovedForAll(owner, operator)`   | Returns `true` if `operator` has blanket approval over `owner`'s tokens.           |\n| `tokenMetadata(tokenId)`              | Returns on-chain metadata as `Record<string, string>`. Returns `{}` if absent.     |\n| `transferFrom(params)`                | Transfers a token from one account to another.                                     |\n| `approve(params)`                     | Approves a spender for a specific token.                                           |\n| `revokeApproval(params)`              | Revokes a single-token approval.                                                   |\n| `approveForAll(params)`               | Grants an operator blanket permission over all caller's tokens.                    |\n| `revokeApprovalForAll(params)`        | Revokes blanket operator permission.                                               |\n| `mint(params)`                        | Mints a new token (requires minting to be enabled on the contract).                |\n| `burn(params)`                        | Burns (destroys) a token.                                                          |\n\n---\n\n## Storage layout\n\nUnderstanding the on-chain layout is helpful when debugging or reading state directly.\n\n### Named keys (scalar fields)\n\n| Named key      | CL type  | Description                   |\n| -------------- | -------- | ----------------------------- |\n| `name`         | `String` | NFT collection name           |\n| `symbol`       | `String` | NFT collection symbol         |\n| `total_supply` | `U256`   | Total number of minted tokens |\n\n### Dictionaries (mappings)\n\n| Dictionary       | Key encoding                                            | Value type                 | Description                        |\n| ---------------- | ------------------------------------------------------- | -------------------------- | ---------------------------------- |\n| `balances`       | `Base64(CLValue(Key).bytes())`                          | `U256`                     | Token count per owner              |\n| `owners`         | `Base64(CLValue(U256 tokenId).bytes())`                 | `Key`                      | Owner of each token                |\n| `approvals`      | `Base64(CLValue(U256 tokenId).bytes())`                 | `Key`                      | Approved spender per token         |\n| `operators`      | `hex(blake2b‑256(ownerKeyBytes \\|\\| operatorKeyBytes))` | `Bool`                     | Blanket operator approvals         |\n| `token_metadata` | `Base64(CLValue(U256 tokenId).bytes())`                 | `BTreeMap<String, String>` | Per-token metadata key-value pairs |\n\n---\n\n## Write operations\n\nAll write methods accept a `params` object:\n\n```ts\ntype Cep95TransactionParams = {\n  sender: PublicKey; // account paying for the transaction\n  paymentAmount: string; // gas in motes (\"2500000000\" = 2.5 CSPR)\n  signingKeys?: PrivateKey[]; // signs the transaction before submission\n  chainName?: string; // overrides the client-level chain name\n};\n```\n\nAnd return:\n\n```ts\ntype Cep95TransactionResult = {\n  transactionInfo: PutTransactionResult; // always present\n  executionResult?: ExecutionResult; // populated when waitForTransactionProcessed: true\n};\n```\n\nAll write methods also accept an optional `waitForTransactionProcessed` flag:\n\n```ts\ntype TransferFromParams = {\n  args: TransferFromArgs;\n  params: Cep95TransactionParams;\n  waitForTransactionProcessed?: boolean; // set sseUrl on the client to enable\n};\n```\n\nWhen `waitForTransactionProcessed: true` and `client.sseUrl` is set, the method subscribes to the SSE stream and resolves only after the node emits a `TransactionProcessed` event for the submitted hash. `executionResult.errorMessage` is non-null when the transaction was reverted on-chain.\n\n---\n\n## Finding contract hashes\n\n- **Contract hash** - used for all reads. Open the contract package on [cspr.live](https://cspr.live) or [testnet.cspr.live](https://testnet.cspr.live), go to **Contract Versions**, and copy the hash of the latest version.\n- **Contract package hash** - used for all writes. It is the hash in the URL: `cspr.live/contract-package/{packageHash}`.\n\nBoth accept bare hex, `\"contract-hash-...\"`, `\"hash-...\"`, or `\"contract-package-...\"` prefixed strings.\n\n---\n\n## `Cep95Entity` - accepted identity types\n\nAll methods that take an `owner`, `operator`, `from`, `to`, or `spender` accept any of:\n\n- `PublicKey` - resolved to its `account-hash`\n- `AccountHash`\n- `ContractHash`\n- `ContractPackageHash`\n- `AddressableEntityHash`\n\n---\n\n## Playground\n\nAn interactive playground for exploring and testing CEP-95 contracts is available at:\n\n**[https://casper-ecosystem.github.io/cep-95-js-client/](https://casper-ecosystem.github.io/cep-95-js-client/)**\n\nIt lets you connect any deployed CEP-95 contract and run all read and write operations directly from the browser - no local setup required.\n\n### Features\n\n- **Read operations** - query collection info, token ownership, approvals, balances, and metadata\n- **Write operations** - transfer, approve, mint, burn, and operator management via [cspr.click](https://cspr.click) wallet integration\n- **Custom RPC** - point at any Casper node (mainnet or testnet) without an App ID\n- **cspr.click proxy** - use the cloud-hosted RPC proxy by supplying a [CSPR.build](https://console.cspr.build) App ID\n- **SSE** - enter an SSE URL (`http://node:9999/events/main`) to see on-chain execution results (success/failure) directly in the activity log\n- **Explorer links** - transaction hashes in the activity log link directly to [cspr.live](https://cspr.live)\n\n### Running locally\n\n```bash\n# from the repo root\nnpm install\n\ncd playground\nnpm install\nnpm run dev    # http://localhost:3000\n```\n\n---\n\n## Development\n\n```bash\nnpm install\nnpm test       # run unit tests\nnpm run build  # compile to dist/\n```\n","readmeFilename":"README.md","_rev":"1-fbbf9cfb5877f2b2bc920709130c68da"}