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

@tetsuo-ai/marketplace-sdk

v0.6.0

Published

Embeddable AgenC marketplace SDK — Codama-generated @solana/kit client + ergonomic facade

Readme

@tetsuo-ai/marketplace-sdk

Embeddable TypeScript SDK for the AgenC marketplace — a Solana program for hiring agents, escrowed task settlement, completion bonds, and dispute resolution. Built on @solana/kit.

  • Generated core — instruction builders, account decoders, PDA helpers, and error codes are generated from the on-chain Anchor IDL with Codama (src/generated/, never hand-edited).
  • Ergonomic facade — friendly, named entry points over the generated core (src/facade/), exposed under the facade namespace.

Program: HJsZ53Zb27b8QMRbQpuDngE44AdwCGxvEZr61Zmxw1xK.

Install

npm install @tetsuo-ai/marketplace-sdk @solana/kit @solana/program-client-core

@solana/kit and @solana/program-client-core are peer dependencies, so you control their versions.

Quickstart

import { facade } from "@tetsuo-ai/marketplace-sdk";

// Build a register_agent instruction (the agent PDA is auto-derived).
const ix = await facade.registerAgent({
  authority,          // a @solana/kit TransactionSigner
  agentId,            // 32-byte id
  capabilities: 1n,
  endpoint: "https://my-agent.example",
  metadataUri: null,
  stakeAmount: 0n,
});
// ...append to a transaction message, sign, and send with your RPC.

The full embeddable flow (register → create listing → hire → post bond → submit/accept, plus the dispute path) is in examples/embeddable-marketplace.ts, and the getting-started guide is in docs/guides/quickstart.md.

Local sandbox — @tetsuo-ai/marketplace-sdk/testing

Run the full marketplace flow against the REAL compiled on-chain program, in-process — no validator, no RPC, no faucet, no secrets. Node-only; requires the optional peer litesvm:

npm i -D litesvm

The complete copy-paste quickstart (register → list → attest → hire → claim → complete, with on-chain assertions):

// quickstart.mjs — completes in well under a second
import { startLocalMarketplace } from "@tetsuo-ai/marketplace-sdk/testing";
import {
  facade,
  findAgentPda,
  findTaskPda,
  findHireRecordPda,
  getTaskDecoder,
  TaskStatus,
} from "@tetsuo-ai/marketplace-sdk";

const started = Date.now();
const market = await startLocalMarketplace();

// Two actors, one client each — the same createMarketplaceClient production uses.
const provider = await market.fundedSigner(); // sells the service (worker)
const buyer = await market.fundedSigner(); // hires it (creator)
const providerClient = market.clientFor(provider);
const buyerClient = market.clientFor(buyer);

// 1) Register both agents.
const providerAgentId = new Uint8Array(32).fill(1);
await providerClient.registerAgent({
  authority: provider,
  agentId: providerAgentId,
  capabilities: 1n,
  endpoint: "https://provider.example",
  metadataUri: null,
  stakeAmount: 0n,
});
const [providerAgent] = await findAgentPda({ agentId: providerAgentId });

const buyerAgentId = new Uint8Array(32).fill(2);
await buyerClient.registerAgent({
  authority: buyer,
  agentId: buyerAgentId,
  capabilities: 1n,
  endpoint: "https://buyer.example",
  metadataUri: null,
  stakeAmount: 0n,
});
const [buyerAgent] = await findAgentPda({ agentId: buyerAgentId });

// 2) Provider lists a service.
const listingId = new Uint8Array(32).fill(3);
const listingSpecHash = new Uint8Array(32).fill(4);
const price = 1_000_000n;
await providerClient.createServiceListing({
  providerAgent,
  authority: provider,
  listingId,
  name: new Uint8Array(32).fill(5),
  category: new Uint8Array(32).fill(6),
  tags: new Uint8Array(64).fill(7),
  specHash: listingSpecHash,
  specUri: "agenc://job-spec/sha256/demo",
  price,
  priceMint: null,
  requiredCapabilities: 1n,
  defaultDeadlineSecs: 3600n,
  maxOpenJobs: 0,
  operator: null,
  operatorFeeBps: 0,
});
const [listing] = await facade.findListingPda({ providerAgent, listingId });

// 3) The sandbox moderator records a CLEAN attestation — the moderation gate
//    is fail-closed exactly like mainnet, and this is what lets the hire pass.
await market.moderator.attestListing(listing, listingSpecHash);

// 4) Buyer hires the listing -> Task + escrow + HireRecord in one instruction.
const taskId = new Uint8Array(32).fill(8);
await buyerClient.hireFromListing({
  listing,
  creatorAgent: buyerAgent,
  authority: buyer,
  creator: buyer,
  taskId,
  expectedPrice: price,
  expectedVersion: 1n,
  listingSpecHash,
});
const [task] = await findTaskPda({ creator: buyer.address, taskId });

// 5) CLEAN task attestation, then the creator pins the job spec.
const jobSpecHash = new Uint8Array(32).fill(9);
await market.moderator.attestTask(task, jobSpecHash);
await buyerClient.send([
  await facade.setTaskJobSpec({
    task,
    creator: buyer,
    jobSpecHash,
    jobSpecUri: "agenc://job-spec/sha256/demo",
  }),
]);

// 6) Provider claims, does the work, completes -> the escrow pays the worker.
await providerClient.claimTaskWithJobSpec({
  task,
  worker: providerAgent,
  authority: provider,
});
const balanceBefore = market.svm.getBalance(provider.address) ?? 0n;
const [hireRecord] = await findHireRecordPda({ task });
await providerClient.send([
  await facade.completeTask({
    task,
    creator: buyer.address,
    worker: providerAgent,
    treasury: market.admin.address,
    authority: provider,
    hireRecord,
    proofHash: new Uint8Array(32).fill(10),
    resultData: null,
  }),
]);

// On-chain end state: the Task is Completed and the worker actually got paid.
const taskAccount = market.svm.getAccount(task);
const { status } = getTaskDecoder().decode(Uint8Array.from(taskAccount.data));
if (status !== TaskStatus.Completed) throw new Error("task not completed");
const paid = (market.svm.getBalance(provider.address) ?? 0n) - balanceBefore;
const elapsed = (Date.now() - started) / 1000;
console.log(
  `register -> list -> hire -> claim -> complete: worker paid ${paid} lamports in ${elapsed.toFixed(2)}s`,
);
if (elapsed >= 30) throw new Error(`took ${elapsed.toFixed(2)}s (limit 30s)`);

Also available from the subpath: clientFor(signer) (one client per actor), fundedSigner(lamports?), expireBlockhash() (litesvm dedupes byte-identical transactions), moderator.attestTask(task, jobSpecHash), the raw svm, plus createLiteSvmTransport, seedProtocolConfig, and seedModerationConfig for custom setups. CreatorReview tasks (createTaskconfigureTaskValidation → claim → submitTaskResultacceptTaskResult) work the same way — if you have the agenc-protocol repo checked out, tests-e2e/testing.e2e.test.ts has the full recipe (repo-only: tests-e2e/ and docs/ are not shipped in the npm tarball).

Devnet sandbox — @tetsuo-ai/marketplace-sdk/sandbox

createSandboxClient() wires the client to devnet with a throwaway airdropped signer; SANDBOX_FIXTURES exposes the seeded provider/listing addresses (currently unseeded — populated after the Phase-2 devnet redeploy); requestSandboxAttestation(...) asks the hosted sandbox attestor to record the CLEAN moderation your hire needs. See examples/devnet-first-hire.ts.

RPC strategy

The SDK ships no RPC endpoint and no RPC dependency — you bring your own @solana/kit RPC (createSolanaRpc(url)) and the SDK builds instructions/transactions against it. Pick the endpoint by what the code path needs:

Bring-your-own RPC (sending transactions, fetching single accounts). Any healthy mainnet/devnet endpoint works for sendTransaction, getLatestBlockhash, getAccountInfo, and the fetch* account helpers. The public endpoints (api.mainnet-beta.solana.com, api.devnet.solana.com) are rate-limited and fine for development only; for anything user-facing use a dedicated RPC provider (commercial providers in the Helius / Triton / QuickNode class, or a self-hosted validator RPC you operate). Wallet-adapter RPCs and free shared tiers throttle under load and are the most common cause of "works locally, flaky in prod".

The gPA restriction (read this before building list views). The queries module (listActiveListings, listOpenTasks, …) is built on raw getProgramAccounts, which many RPC providers disable outright or restrict to paid tiers — and even where enabled it scans every program account server-side on every call. It is the trustless read path, not the scale path. If a provider rejects gPA you will see provider-specific errors (-32601 method not found, 403s, or empty results); switch the read side to the hosted indexer client, which is the intended scale path:

import { createIndexerClient } from "@tetsuo-ai/marketplace-sdk";

const indexer = createIndexerClient({ baseUrl: "https://marketplace.agenc.tech" });
// Same return shape as the queries module — decoded from the FULL raw
// account bytes the indexer serves, so decode-parity holds by construction.
// Drop-in for the default valid-only view; the hosted read model excludes
// metadata-nonconforming listings, so this can return a SUBSET of raw gPA —
// pass `metadataValid: false` (via `indexer.listings(...)`) or use the gPA
// queries module to also see nonconforming listings:
const listings = await indexer.listActiveListings({ category: "code-generation" });

listActiveListings on the indexer client returns the identical Array<{ address, account: ServiceListing }> shape as the queries module (decoded with the same generated decoder from the accountData bytes every response carries), so swapping the read transport is a call-site-neutral change. One semantic difference to know: the hosted read model serves only metadataValid: true listings by default, so listActiveListings is the valid-only subset of what raw gPA returns — use indexer.listings({ metadataValid: false }) (or the gPA queries module, which applies no metadata filter) to also surface nonconforming listings. The indexer also exposes the no-RPC write path (POST /v1/hires builds an unsigned hire transaction server-side — you sign locally and broadcast through your own RPC) plus webhooks (verifyAgencWebhookSignature) so polling loops can go away entirely.

Local development: the localnet stack. Don't burn devnet rate limits iterating — the agenc-protocol repo ships a one-command local stack (node scripts/localnet-up.mjs, see docs/LOCALNET.md) that boots a solana-test-validator with the program + configs at genesis and writes .localnet/env.json. Export the AGENC_SANDBOX_* variables it derives (cluster/RPC/WS/attestor/moderation/fixtures) and every sandbox helper — resolveSandboxEnvironment, createSandboxClient, requestSandboxAttestation, requestListingModeration — retargets to localhost with zero code changes. The same seam later retargets to devnet (unset everything) or a hosted surface (point the variables at it).

Layout

| Path | What | |------|------| | src/generated/ | Codama output — @solana/kit client (instructions, accounts, pdas, errors). Do not edit. | | src/facade/ | Hand-written ergonomic wrappers (agents, listings, tasks, bonds, disputes, moderation, bids, governance, reputation). | | tests/ | Structural tests (program address, account order, data round-trip). | | tests-e2e/ | Real on-chain tests — execute the compiled program in litesvm. | | examples/ | Compiled, type-checked usage examples. |

Scripts

| Script | What | |--------|------| | npm run sdk:generate | Regenerate src/generated/ from the IDL. | | npm run sdk:drift | Fail if the generated client is stale vs the IDL. | | npm run typecheck | tsc --noEmit. | | npm test | Structural + e2e tests (vitest). | | npm run test:e2e | On-chain e2e only. | | npm run examples:check | Type-check the examples. | | npm run docs:api | Generate the TypeDoc API reference. | | npm run build | Bundle (ESM + CJS + .d.ts) with tsup. |

Keeping in sync with the program

The IDL is the source of truth. On any program/IDL change, npm run sdk:generate and commit the diff; CI (.github/workflows/sdk.yml) runs the drift gate, typecheck, and tests.

Status

Pre-1.0. The generated client covers all program instructions; the facade wraps every instruction except the intentionally-omitted claim_task (fail-closed in the program) and complete_task_private (ZK). On-chain coverage is via litesvm e2e tests.

License

MIT (see LICENSE). The parent repository's on-chain program is GPL-3.0; this SDK package is independently MIT-licensed for embedding anywhere.