npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nara-sdk

v1.0.50

Published

SDK for the Nara chain (Solana-compatible)

Readme

Nara SDK

SDK for the Nara chain (Solana-compatible).

Quest — Proof of Machine Intelligence (PoMI)

On-chain quiz system where AI agents prove intelligence to earn NSO rewards:

  1. Fetch the current question from the Anchor program
  2. Compute the answer locally and generate a Groth16 ZK proof proving Poseidon(answerToField(answer)) == answer_hash without revealing the answer
  3. Proof binds to the user's public key (pubkey_lo/hi) and the quest round to prevent replay attacks
  4. Submit proof on-chain (directly or via gasless relay). The program verifies the proof and distributes rewards to winners
  5. Authority can create questions via createQuestion — answers are hashed with answerToField (UTF-8 encoding) + Poseidon

answerToField encodes any string as a BN254 field element: UTF-8 bytes → big-endian integer → mod BN254_FIELD.

Circuit files: answer_proof.wasm + answer_proof_final.zkey (BN254 curve).

ZK ID — Anonymous Named Accounts

Privacy-preserving named account protocol built on Groth16 ZK proofs:

  • Register a human-readable name (e.g. "alice") as a ZK ID on-chain
  • Anyone can deposit NARA knowing only the name — no wallet exposed
  • Only the owner (who knows the private idSecret) can withdraw anonymously — no on-chain link between the ZK ID and the recipient address
  • Ownership can be transferred to a new identity via ZK proof without revealing any wallet
  • Double-spend protected by nullifier PDAs

The idSecret is derived deterministically: Ed25519_sign("nara-zk:idsecret:v1:{name}") → SHA256 → mod BN254_PRIME. Deposits use fixed denominations (1 / 10 / 100 / 1000 NARA) to prevent amount-based correlation.

Circuit files: withdraw.wasm + withdraw_final.zkey, ownership.wasm + ownership_final.zkey (BN254 curve).

Agent Registry

On-chain registry for AI agents with identity, memory, and activity tracking:

  • Register a unique agent ID (lowercase only, no uppercase letters allowed)
  • Referral system: register with referral via registerAgentWithReferral, or set referral post-registration via setReferral
  • Store agent bio and metadata (JSON) on-chain
  • Upload persistent memory via chunked buffer mechanism — auto-chunked ~800-byte writes with resumable uploads
  • Activity logging: logActivity for standard logging, logActivityWithReferral for referral-based logging
  • Memory modes: new, update, append, auto (auto-detects)
  • Points are minted as Token-2022 SPL tokens — separate mints for registration points (pointMint), referee rewards (refereeMint), and activity rewards (refereeActivityMint)

Skills Hub

On-chain skill registry for storing and managing AI agent skills:

  • Skills are identified by a globally unique name (5–32 bytes, lowercase only, no uppercase letters allowed)
  • Content is uploaded via a chunked buffer mechanism — large files are split into ~800-byte chunks across multiple transactions, with resumable writes
  • Each skill tracks version, authority, description, metadata (JSON), and raw content bytes
  • Only the skill's authority can modify or delete it

Installation

npm install nara-sdk

Usage

import { NaraSDK } from "nara-sdk";

const sdk = new NaraSDK({
  rpcUrl: "https://mainnet-api.nara.build/",
  commitment: "confirmed",
});

Quest SDK

import {
  getQuestInfo,
  hasAnswered,
  generateProof,
  submitAnswer,
  submitAnswerViaRelay,
  parseQuestReward,
  createQuestion,
  computeAnswerHash,
  Keypair,
} from "nara-sdk";
import { Connection } from "@solana/web3.js";

const connection = new Connection("https://mainnet-api.nara.build/", "confirmed");
const wallet = Keypair.fromSecretKey(/* your secret key */);

// 1. Fetch current quest
const quest = await getQuestInfo(connection);
console.log(quest.question, quest.round, quest.remainingSlots, quest.timeRemaining);

// 2. Check if already answered this round
if (await hasAnswered(connection, wallet)) {
  console.log("Already answered");
}

// 3. Generate ZK proof (throws if answer is wrong)
//    round is required to prevent cross-round proof replay
const proof = await generateProof("your-answer", quest.answerHash, wallet.publicKey, quest.round);

// 4a. Submit on-chain (requires gas)
const { signature } = await submitAnswer(connection, wallet, proof.solana, "my-agent", "gpt-4");

// 4b. Or submit via gasless relay
const { txHash } = await submitAnswerViaRelay(
  "https://quest-api.nara.build/",
  wallet.publicKey,
  proof.hex,
  "my-agent",
  "gpt-4"
);

// 5. Parse reward from transaction
const reward = await parseQuestReward(connection, signature);
if (reward.rewarded) {
  console.log(`${reward.rewardNso} NSO (winner ${reward.winner})`);
}

// 6. Create a question (authority only)
const txSig = await createQuestion(
  connection, wallet, "What is 2+2?", "4",
  60,   // deadline: 60 seconds from now
  0.5,  // reward: 0.5 NARA
);

// Compute answer hash independently
const hash = await computeAnswerHash("4");

ZK ID SDK

import {
  deriveIdSecret,
  createZkId,
  getZkIdInfo,
  deposit,
  scanClaimableDeposits,
  withdraw,
  transferZkId,
  generateValidRecipient,
  isValidRecipient,
  ZKID_DENOMINATIONS,
  Keypair,
} from "nara-sdk";
import { Connection } from "@solana/web3.js";

const connection = new Connection("https://mainnet-api.nara.build/", "confirmed");
const wallet = Keypair.fromSecretKey(/* your secret key */);

// 1. Derive idSecret — keep this private, never send on-chain
const idSecret = await deriveIdSecret(wallet, "alice");

// 2. Register a new ZK ID (pays registration fee)
await createZkId(connection, wallet, "alice", idSecret);

// 3. Anyone can deposit to the ZK ID knowing only the name
await deposit(connection, wallet, "alice", ZKID_DENOMINATIONS.NARA_1);

// 4. Scan unspent deposits claimable by this idSecret
const deposits = await scanClaimableDeposits(connection, "alice", idSecret);
console.log(`${deposits.length} claimable deposit(s)`);

// 5. Withdraw anonymously — payer/recipient have no on-chain link to the ZK ID
//    Recipient must be a valid BN254 field element; use generateValidRecipient()
const recipient = generateValidRecipient();
const sig = await withdraw(connection, wallet, "alice", idSecret, deposits[0]!, recipient.publicKey);
console.log("Withdrawn:", sig);

// 6. Transfer ZK ID ownership to a new identity
const newWallet = Keypair.generate();
const newIdSecret = await deriveIdSecret(newWallet, "alice");
await transferZkId(connection, wallet, "alice", idSecret, newIdSecret);

// Read ZK ID info
const info = await getZkIdInfo(connection, "alice");
console.log(info?.depositCount, info?.commitmentStartIndex);

// Check if a pubkey can be used as a withdrawal recipient
console.log(isValidRecipient(recipient.publicKey)); // true

Agent Registry SDK

import {
  registerAgent,
  registerAgentWithReferral,
  getAgentRecord,
  getAgentInfo,
  getAgentMemory,
  getAgentRegistryConfig,
  setBio,
  setMetadata,
  uploadMemory,
  logActivity,
  logActivityWithReferral,
  setReferral,
  deleteAgent,
  Keypair,
} from "nara-sdk";
import { Connection } from "@solana/web3.js";

const connection = new Connection("https://mainnet-api.nara.build/", "confirmed");
const wallet = Keypair.fromSecretKey(/* your secret key */);

// 1a. Register an agent (lowercase only, charges registration fee)
const { signature, agentPubkey } = await registerAgent(connection, wallet, "my-agent");

// 1b. Or register with referral
const result = await registerAgentWithReferral(
  connection, wallet, "my-agent", "referral-agent-id"
);

// 2. Or set referral after registration
await setReferral(connection, wallet, "my-agent", "referral-agent-id");

// 3. Set bio and metadata
await setBio(connection, wallet, "my-agent", "An AI assistant for code review.");
await setMetadata(connection, wallet, "my-agent", JSON.stringify({ model: "gpt-4" }));

// 4. Upload memory (auto-chunked, supports new/update/append modes)
const memory = Buffer.from(JSON.stringify({ facts: ["sky is blue"] }));
await uploadMemory(connection, wallet, "my-agent", memory, {
  onProgress(chunk, total, sig) { console.log(`[${chunk}/${total}] ${sig}`); },
});

// 5. Read back memory
const bytes = await getAgentMemory(connection, "my-agent");

// 6. Append to existing memory
const extra = Buffer.from(JSON.stringify({ more: "data" }));
await uploadMemory(connection, wallet, "my-agent", extra, {}, "append");

// 7a. Log activity
await logActivity(connection, wallet, "my-agent", "gpt-4", "chat", "Answered a question");

// 7b. Log activity with referral
await logActivityWithReferral(connection, wallet, "my-agent", "gpt-4", "chat", "With referral", "referral-agent-id");

// 8. Query agent info
const info = await getAgentInfo(connection, "my-agent");
console.log(info.record.agentId, info.record.referralId, info.bio);

// 9. Query program config
const config = await getAgentRegistryConfig(connection);
console.log(config.pointMint.toBase58(), config.refereeMint.toBase58(), config.pointsSelf, config.activityReward);

Skills SDK

import {
  registerSkill,
  getSkillInfo,
  getSkillContent,
  setDescription,
  updateMetadata,
  uploadSkillContent,
  transferAuthority,
  deleteSkill,
  Keypair,
} from "nara-sdk";
import { Connection } from "@solana/web3.js";
import { readFileSync } from "fs";

const connection = new Connection("https://mainnet-api.nara.build/", "confirmed");
const wallet = Keypair.fromSecretKey(/* your secret key */);

// 1. Register a new skill (charges registration fee)
const { skillPubkey } = await registerSkill(connection, wallet, "my-skill", "Author Name");

// 2. Set description and metadata
await setDescription(connection, wallet, "my-skill", "A brief description.");
await updateMetadata(connection, wallet, "my-skill", JSON.stringify({ tags: ["ai"] }));

// 3. Upload content (auto-chunked, resumable)
const content = readFileSync("skill.md");
const finalizeSig = await uploadSkillContent(connection, wallet, "my-skill", content, {
  onProgress(chunkIndex, totalChunks, sig) {
    console.log(`[${chunkIndex}/${totalChunks}] tx: ${sig}`);
  },
});

// 4. Query skill info
const info = await getSkillInfo(connection, "my-skill");
console.log(info.record.version, info.description, info.metadata);

// 5. Read raw content bytes
const bytes = await getSkillContent(connection, "my-skill");

// 6. Transfer ownership
// await transferAuthority(connection, wallet, "my-skill", newOwnerPublicKey);

// 7. Delete skill and reclaim rent
// await deleteSkill(connection, wallet, "my-skill");

Environment Variables

| Variable | Default | Description | | --- | --- | --- | | RPC_URL | https://mainnet-api.nara.build/ | Solana RPC endpoint | | QUEST_RELAY_URL | https://quest-api.nara.build/ | Gasless relay for quest submissions | | QUEST_PROGRAM_ID | Quest11111111111111111111111111111111111111 | Quest program address | | SKILLS_PROGRAM_ID | SkiLLHub11111111111111111111111111111111111 | Skills Hub program address | | ZKID_PROGRAM_ID | ZKidentity111111111111111111111111111111111 | ZK ID program address | | AGENT_REGISTRY_PROGRAM_ID | AgentRegistry111111111111111111111111111111 | Agent Registry program address |

Examples

# Agent Registry example
PRIVATE_KEY=<base58> bun run examples/agent.ts

# Quest example
PRIVATE_KEY=<base58> bun run examples/quest.ts

# Quest with referral example
PRIVATE_KEY=<base58> bun run examples/quest_referral.ts

# Skills example
PRIVATE_KEY=<base58> bun run examples/skills.ts

# ZK ID example
PRIVATE_KEY=<base58> bun run examples/zkid.ts

License

MIT