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

@zktx.io/ptb-builder

v0.5.0

Published

Sui programmable transaction blocks builder

Readme

Programmable Transaction Blocks Builder (PTB Builder)

PTB Builder is a graphical toolkit for authoring, inspecting, and rendering Programmable Transaction Blocks (PTBs) on the Sui blockchain. It provides an intuitive drag-and-drop interface, code rendering, and host integration points. The host application remains responsible for wallet connection, signing, simulation, and execution.

ptb-builder-editor.png

Demo

Architecture Boundary

@zktx.io/ptb-builder depends on @zktx.io/ptb-model so the builder can adopt the model package as its canonical PTB data boundary. Model package APIs are the boundary for PTB data validation, raw PTB conversion, Mermaid rendering, and TypeScript SDK code string rendering. The builder package owns React UI state, React Flow integration, document/provider lifecycle, SDK Core read helpers, object authoring policy, and the runtime adapter that turns a validated TransactionIR into a host-owned Sui Transaction.

Import the model package through @zktx.io/ptb-model only. Package-internal model imports, model dist imports, and relative imports across package boundaries are intentionally blocked for builder source.

The builder runtime accepts ptb_4 documents. Convert unsupported document shapes outside this package before calling builder/model APIs.

Features

1. Transaction Construction and Review

  • Visual Editor: Construct PTBs via a drag‑and‑drop UI (React Flow-based).
  • Code Rendering: Render TypeScript for the Sui TS SDK.
  • Host Review Hooks: Let the host application provide simulation or execution adapters when needed.

2. Host-Controlled Execution

  • Accessible: Users can create PTB structures without writing code.
  • Authority Stays Outside: Wallet connection, signing, simulation, and execution stay in the host app.
  • Real‑Time Feedback: Errors/warnings surface instantly during graph construction.

3. Save and Share

  • Graph Persistence: Save PTB graphs locally and reload them later.
  • Portable Documents: Share saved .ptb documents with other PTB Builder users.
  • Optional Export: Expose an Export .ptb button from the UI (hidden by default).

4. Structure Visualization and Debugging

  • Loaded Transaction Structure View: Visualize supported loaded PTB command and input structure as readable graphs.
  • Debugging Tools: Inspect graph wiring, inputs, outputs, and validation feedback while editing.

5. On‑Chain Transaction Loading

  • Load from Digest: Import an on‑chain transaction by digest and visualize its structure.

6. Use On‑Chain Assets as Objects

  • Asset Browser: Browse objects owned by the address prop when a host wallet/address is connected (coins, Move objects, modules, etc.).
  • Object Metadata Loading: Insert owned assets as Object nodes with object id and type metadata. Runtime construction uses the pinned SDK helper surface, such as tx.object(id), for unresolved object ids.
  • Resolved Ref Preservation: When a decoded raw or on-chain PTB already contains resolved object references, PTB Builder preserves those references for inspection and round-trip fidelity instead of asking the user to recreate them.

7. Themes

  • Initial Theme Selection: dark, light, cobalt2, tokyo-night, cream, mint-breeze.
  • Switch Anytime: Change themes dynamically from the workspace.

Supported Commands

The following command nodes are available from the builder context menu:

  • SplitCoins — split a coin object into multiple parts.
  • MergeCoins — merge multiple coins into one.
  • TransferObjects — transfer owned objects to a recipient.
  • MakeMoveVec — build a Move vector from typed elements. Set the Move type on the node before connecting element inputs.
  • MoveCall — call a Move function by loading the package module/function index from the configured SDK Core client, then choosing a module and function from the discovered package. The builder fetches the selected function signature when it is needed to materialize value and type handles. Generic Move type arguments are authored with dedicated Type Argument nodes connected to the MoveCall type handles.

Loaded PTBs may also render Publish and Upgrade command nodes for inspection. PTB Builder does not expose context-menu authoring for those commands because editing module bytes, dependencies, and package upgrade data requires the Move toolchain and remains outside the builder UI boundary.

The package does not expose a public command registry extension API.

Supported Inputs

Input authoring support:

  • Scalars: numbers, booleans, addresses, strings ✅
  • Objects: direct ownership/transfer supported ✅ (includes Coin<T>)
    • Objects can be selected from your owned assets via the Assets modal when address is provided.
    • Manual object authoring should use the object node lookup before runtime building so the graph carries SDK-reported object id and type tag.
    • Object nodes do not expose raw usage choices. Move function signatures determine argument expectations, and unresolved object ids are handed to the SDK runtime with tx.object(id).
  • Vectors: scalars only ✅ (❌ objects, including coins, are not supported in vectors)
  • Options: available for scalars ✅ (❌ not supported for objects)

Quick Start

Install the builder package plus its peer dependencies in your React app:

npm install @zktx.io/ptb-builder @mysten/sui @xyflow/react elkjs lucide-react re-resizable react react-dom

This package is developed and tested against the exact pinned @mysten/[email protected] SDK version used by the repository. Use that SDK version unless a later PTB Builder release states a different compatibility range.

For authoring, inspection, and TypeScript SDK code preview, the smallest useful setup is the component, CSS, a starting chain, and a sized container. Passing initialChain creates a fresh editable PTB document on mount. It is intentionally an initializer, not a network controller; use loadFromDoc() when your app needs to replace the active document.

import { PTBBuilder } from '@zktx.io/ptb-builder';

import '@zktx.io/ptb-builder/index.css';
import '@zktx.io/ptb-builder/styles/themes-all.css';

export function App() {
  return (
    <PTBBuilder
      initialChain="sui:testnet"
      style={{ width: '100vw', height: '100vh' }}
    />
  );
}

That minimal setup does not connect a wallet and does not execute or simulate transactions. It can still author PTB graphs, render code, export documents when enabled, and use the package default SDK Core client for read/load helpers.

Add host integration only for the capabilities your app owns. The next example assumes your app already wraps this component in the dapp-kit provider setup shown by the local packages/example app.

import {
  useCurrentAccount,
  useCurrentNetwork,
  useDAppKit,
} from '@mysten/dapp-kit-react';
import type { Transaction } from '@mysten/sui/transactions';
import { PTBBuilder, type Chain } from '@zktx.io/ptb-builder';

function chainToNetwork(chain: Chain) {
  const match = chain.match(/^sui:(mainnet|testnet|devnet)$/);
  if (!match) throw new Error(`Unsupported chain: ${chain}`);
  return match[1] as 'mainnet' | 'testnet' | 'devnet';
}

export function BuilderWithHostAdapters() {
  const account = useCurrentAccount();
  const network = useCurrentNetwork() ?? 'testnet';
  const dAppKit = useDAppKit();

  const createClient = (chain: Chain) =>
    dAppKit.getClient(chainToNetwork(chain));

  const simulateTx = async (chain: Chain, transaction?: Transaction) => {
    if (!transaction) return { error: 'No transaction to simulate' };
    const client = createClient(chain);
    const bytes = await transaction.build({ client });
    const result = await client.core.simulateTransaction({
      transaction: bytes,
      include: { effects: true },
    });
    const simulated =
      result.$kind === 'Transaction'
        ? result.Transaction
        : result.FailedTransaction;
    const error =
      simulated.status.error?.message || simulated.status.error?.$kind;
    return { success: simulated.status.success, error };
  };

  const executeTx = async (chain: Chain, transaction?: Transaction) => {
    if (!account) return { error: 'Wallet not connected' };
    if (!transaction) return { error: 'No transaction to execute' };
    if (network !== chainToNetwork(chain)) {
      return {
        error: `Switch to ${chainToNetwork(chain)} before executing this PTB`,
      };
    }
    const result = await dAppKit.signAndExecuteTransaction({ transaction });
    if (result.$kind === 'FailedTransaction') {
      const statusError = result.FailedTransaction.status.error;
      return {
        digest: result.FailedTransaction.digest,
        error:
          statusError?.message ||
          statusError?.$kind ||
          'Transaction execution failed',
      };
    }
    return { digest: result.Transaction.digest };
  };

  return (
    <PTBBuilder
      initialChain={`sui:${network}` as Chain}
      style={{ width: '100vw', height: '100vh' }}
      createClient={createClient}
      simulateTx={simulateTx}
      executeTx={executeTx}
      address={account?.address}
      showExportButton
    />
  );
}

The local packages/example app shows a complete dapp-kit host with network selection, undo/redo, document drop, on-chain transaction loading, and toast integration. loadFromDoc() accepts ptb_4 documents with explicit chain and view fields only. Convert unsupported document shapes outside this package.

SDK Core client boundary

createPtbCoreClient() and createPtbCoreClientForNetwork() return SDK Core clients for read/load paths. The exported PtbCoreClient type is an alias of the pinned @mysten/[email protected] ClientWithCoreApi type, not a separate stable client abstraction owned by PTB Builder. Host applications may provide their own ClientWithCoreApi-compatible client through createClient, but SDK Core type changes are part of the Sui SDK boundary and should be reviewed when upgrading @mysten/sui.

Public API (Provider + Hook)

Supported public imports are the package root (@zktx.io/ptb-builder) and the CSS subpaths declared in package.json exports. Files emitted under dist/types/ are build artifacts for those exports, not separate compatibility entry points. Helpers that are not re-exported from the package root are internal implementation details.

Provider (component)

import '@zktx.io/ptb-builder/index.css';
import '@zktx.io/ptb-builder/styles/themes-all.css';
// Or import a specific theme only: import '@zktx.io/ptb-builder/styles/theme-light.css';

import { PTBBuilder } from '@zktx.io/ptb-builder';

<PTBBuilder
  theme="dark" // initial theme (dark | light | cobalt2 | tokyo-night | cream | mint-breeze); defaults to "dark"
  initialChain="sui:testnet" // optional: start with a fresh editable PTB for this chain
  address={connectedAddress} // optional runtime sender and Assets modal owner; short or canonical form
  gasBudget={500_000_000} // optional runtime gas budget; number, bigint, or u64 string
  executeTx={execAdapter} // host-provided execution adapter
  createClient={clientFactory} // host-provided SDK Core client factory for reads/loads
  onDocChange={saveDoc} // PTBDoc autosave callback (debounced)
  showExportButton // optional: show Export .ptb button (default: hidden)
>
  {/* your app here */}
</PTBBuilder>;

Hook (public)

import { usePTB } from '@zktx.io/ptb-builder';

const {
  captureCurrentDocResult,
  exportDoc,
  exportDocResult,
  loadFromDoc,
  loadFromOnChainTx,
  undo,
  redo,
  canUndo,
  canRedo,
  setTheme,
} = usePTB();

// Export the active PTB document with structured error information
const exportResult = exportDocResult({ sender: connectedAddress });
if (!exportResult.ok) {
  console.warn(exportResult.error);
}

// Compatibility wrapper: returns undefined on failure
const doc = exportDoc({ sender: connectedAddress });

// Load document from memory or disk
if (doc) {
  const loadResult = loadFromDoc(doc);
  if (!loadResult.ok) {
    console.warn(loadResult.error);
  }
}

// Undo/redo is owned by the builder editor session state. It includes the live
// graph, chain, sender, modules, and objects, even when the current graph cannot
// be exported as a valid PTBDoc yet.
if (canUndo) undo();
if (canRedo) redo();

// Capture is side-effect-free; exportDocResult still reports UI export errors.
const current = captureCurrentDocResult();
if (current.ok) {
  console.log(current.doc);
}

// Load graph from on-chain transaction digest. Pure raw inputs that can be
// decoded losslessly are materialized for display, using fetched Move function
// signatures when the consumer type needs them.
const chainLoadResult = await loadFromOnChainTx('sui:testnet', '0x1234…');
if (!chainLoadResult.ok) {
  console.warn(chainLoadResult.error);
}

// Load an on-chain transaction as an editable template instead of a read-only viewer.
const editableLoadResult = await loadFromOnChainTx('sui:testnet', '0x1234…', {
  mode: 'editable',
});
if (!editableLoadResult.ok) {
  console.warn(editableLoadResult.error);
}

// Switch theme at runtime
setTheme('tokyo-night');

Styling & Theme imports

  • @zktx.io/ptb-builder/index.css contains the structural styles for nodes, edges, and the builder chrome. It should be imported exactly once in your host app (or exposed by your bundler) regardless of the theme you choose.
  • @zktx.io/ptb-builder/styles/themes-all.css is a self-contained bundle of every theme token file so you can switch themes at runtime with setTheme. Importing it includes all shipped themes; the package build emits it at roughly 43 kB before gzip.
  • To minimize CSS for static deployments, import only the theme(s) you actually ship, e.g. import '@zktx.io/ptb-builder/styles/theme-dark.css';. Picking a single one keeps the bundle lean while still allowing dynamic switching between the themes you explicitly include.
  • Do not import themes-all.css together with individual theme-*.css files. Choose the aggregate file for runtime theme switching, or choose individual theme files for a smaller static bundle.
  • When you only ship a single theme file, pass the matching theme value (e.g., theme="light") and set showThemeSelector={false} so the UI doesn’t expose choices that aren’t bundled.

Autosave, undo/redo & onDocChange

  • PTB Builder batches graph/content onDocChange emissions briefly and debounces viewport-only changes by 250 ms so autosave targets are not overwhelmed while the user edits or pans the canvas.
  • loadFromDoc(doc) imports a document as a new editable baseline and applies the document's saved viewport. loadFromDoc(chain) creates a fresh editable document for that chain and applies the default viewport. These transitions do not infer the saved baseline from a post-load viewport fit.
  • undo() and redo() use builder-owned editor session history, not onDocChange. The history source of truth is the editor state (graph, chain, sender, modules, and objects) and excludes viewport-only changes. When the restored state can be serialized as a PTBDoc, the builder immediately attempts an onDocChange emission for autosave; invalid-but-editable graphs still restore and remain undoable while autosave/export reports document diagnostics.
  • loadFromOnChainTx(..., { mode: 'editable' }) computes the generated transaction layout from a fixed transaction-load target, not from the previously visible viewport, before applying provider state. It then emits that laid-out graph with the default editable viewport as the editable baseline. The default read-only loadFromOnChainTx path does not emit onDocChange, because read-only transaction inspection is not an editable document autosave event.
  • captureCurrentDocResult() captures the live React Flow graph and viewport without setting UI error state or showing a toast. Use it for explicit document export or custom host flows, not as the source of builder undo/redo.
  • The address prop is the runtime envelope sender and Assets-modal owner address. It does not become PTBDoc.sender; imported document senders are preserved, and export helpers use an explicit sender option when the host wants a saved document sender.
  • When integrating your own autosave pipeline, expect onDocChange to fire often during graph edits but only after the debounce window for viewport-only motions.

Props Reference (<PTBBuilder />)

| Prop | Type | Default | Description | | ------------------- | ------------------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | theme | Theme (dark | light | cobalt2 | tokyo-night | cream | mint-breeze) | "dark" | Initial UI theme. | | initialChain | Chain | – | Optional chain used to create a fresh editable PTB on mount. Later document changes should use loadFromDoc(). | | className | string | – | Optional class for a host-controlled container around the builder. | | style | React.CSSProperties | – | Optional style for the same container; useful for setting width/height directly on <PTBBuilder />. | | showThemeSelector | boolean | true | Renders the theme dropdown in the CodePip panel. | | address | string | – | Optional runtime envelope sender and owner address for the Assets modal. Short or canonical Sui address forms are accepted and normalized before runtime helpers use them. It is not substituted into graph arguments. | | gasBudget | number \| bigint \| string | – | Optional runtime envelope gas budget. String values must be unsigned u64 strings. | | executeTx | (chain: Chain, tx?: Transaction) => Promise<{ digest?: string; error?: string }> | – | Host-provided execution adapter. | | simulateTx | (chain: Chain, tx?: Transaction) => Promise<{ success?: boolean; error?: string }> | – | Optional host-provided simulation adapter; required only when the Dry run action is used. | | createClient | (chain: Chain) => ClientWithCoreApi | gRPC | Optional host-provided SDK Core client factory for read/load paths. | | toast | ToastAdapter | console | Custom toast adapter used by the provider. | | onDocChange | (doc: PTBDoc) => void | – | Autosave callback (debounced). | | showExportButton | boolean | false | If true, shows Export .ptb button in the CodePip panel. | | children | React.ReactNode | – | Children rendered inside the Provider. |


Document Format

PTB Builder persists graphs as PTBDoc objects containing:

  • version — documents use ptb_4
  • graph — nodes and edges of the PTB
  • modules — embedded Move function signature metadata for MoveCall functions whose signatures were fetched while authoring or inspecting. Function entries retain both the resolved PTB port types and the SDK Core open signatures needed to recompute generic MoveCall ports after reload. Package module/function indexes are runtime discovery data and are not stored in the document.
  • objects — embedded object metadata for display and type lookup. Runtime object arguments must come from graph raw input data such as SDK-reported object id, version, and digest; metadata embeds are not a source of signing authority.
  • chain — target Sui network (e.g., sui:testnet)
  • view — saved editor viewport { x, y, zoom }

This enables saving, sharing, and reloading graphs consistently across environments.


Notes on Network Sync

  • Use useCurrentNetwork() and useDAppKit().switchNetwork() from @mysten/dapp-kit-react to read/change the active Sui network.
  • Keep PTB doc.chain in the form sui:<network>, e.g., sui:testnet.
  • On file drop, prefer validating with /^sui:(mainnet|testnet|devnet)$/ before switching the network.