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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@kiloscribe/inscription-sdk

v2.0.4

Published

SDK for inscribing files on Hedera

Readme

Kiloscribe Inscription SDK

TypeScript/JavaScript SDK for inscribing files on the Hedera Hashgraph using Kiloscribe's inscription service.

Table of Contents

Prerequisites

Before you start, you'll need:

  1. Hedera Account:

    • Create a testnet account at portal.hedera.com
    • Save your Account ID (e.g., 0.0.123456)
    • Save your Private Key (DER Encoded)
  2. WalletConnect Project (for browser apps):

  3. Kiloscribe API Key:

  4. Development Environment:

    • Node.js 20 or later
    • npm or yarn

Installation

For Node.js/Backend Projects

# Install the SDK and its peer dependencies
npm install @kiloscribe/inscription-sdk @hashgraphonline/standards-sdk @hashgraph/sdk

For Browser/Frontend Projects

# Install the SDK and wallet connection dependencies
npm install @kiloscribe/inscription-sdk @hashgraphonline/standards-sdk @hashgraphonline/hashinal-wc @hashgraph/sdk @hashgraph/hedera-wallet-connect

Getting Started

Topic Id : 0.0.8084856

1. Set Up Your Environment

Create a .env file in your project root:

# Required for all projects
API_KEY=your_kiloscribe_api_key
HEDERA_NETWORK=testnet  # or mainnet

# For Node.js projects using private key
HEDERA_ACCOUNT_ID=0.0.123456
HEDERA_PRIVATE_KEY=302...

# For browser projects using WalletConnect
WALLETCONNECT_PROJECT_ID=your_project_id

2. Choose Your Integration Method

A. Browser Apps with WalletConnect (Recommended)

This method lets users connect their existing Hedera wallet (like HashPack):

  1. Install dependencies:
npm install @kiloscribe/inscription-sdk @hashgraphonline/standards-sdk @hashgraphonline/hashinal-wc @hashgraph/sdk
  1. Create your app:
import { HashinalsWalletConnectSDK } from '@hashgraphonline/hashinal-wc';
import { InscriptionSDK } from '@kiloscribe/inscription-sdk';
import { LedgerId } from '@hashgraph/sdk';

// Initialize SDKs
const wallet = new HashinalsWalletConnectSDK();
const sdk = new InscriptionSDK({
  apiKey: process.env.API_KEY,
  network: 'testnet',
});

// Connect wallet (shows QR code or deep links to wallet)
const { accountId } = await wallet.connectWallet(
  process.env.WALLETCONNECT_PROJECT_ID,
  {
    name: 'My dApp',
    description: 'Example dApp',
    url: window.location.origin,
    icons: ['https://my-dapp.com/icon.png'],
  },
  LedgerId.TESTNET
);

// Get signer for the connected account
const dAppSigner = wallet.dAppConnector.signers.find(
  (signer) => signer.getAccountId().toString() === accountId
)!;

// Create an inscription
const result = await sdk.inscribe(
  {
    file: {
      type: 'base64',
      base64: 'your_base64_data',
      fileName: 'example.png',
      mimeType: 'image/png',
    },
    holderId: accountId,
    mode: 'file', // or 'hashinal' for NFTs
    network: 'testnet',
    description: 'Example inscription',
  },
  dAppSigner
);

// Wait for inscription to complete
const complete = await sdk.waitForInscription(
  result.jobId,
  30, // max attempts
  4000, // interval in ms
  true // check for completion status
);

console.log('Inscription complete:', {
  topic_id: complete.topic_id,
  status: complete.status,
});

B. Loading via HCS-3 Recursion

Load the SDK directly from the Hedera Hashgraph using HCS-3 recursion:

<!DOCTYPE html>
<html>
  <head>
    <title>Inscription SDK Demo</title>

    <script
      data-hcs-config
      data-hcs-cdn-url="https://kiloscribe.com/api/inscription-cdn/"
      data-hcs-network="mainnet"
      data-hcs-debug="true"
      data-hcs-retry-attempts="5"
      data-hcs-retry-backoff="500"
    ></script>

    <script
      data-src="hcs://1/0.0.8084872"
      data-script-id="wallet-connect"
      data-load-order="1"
    ></script>

    <script
      data-src="hcs://1/0.0.8084856"
      data-script-id="inscription-sdk"
      data-load-order="2"
    ></script>

    <style>
      body {
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
          Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
        margin: 0;
        padding: 20px;
        background: #f5f5f5;
      }

      .container {
        max-width: 800px;
        margin: 0 auto;
        background: white;
        padding: 20px;
        border-radius: 8px;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        margin-bottom: 10px;
        margin-top: 10px;
      }

      h1 {
        color: #333;
        text-align: center;
      }

      .upload-section {
        display: flex;
        gap: 10px;
        margin: 20px 0;
      }

      button {
        background: #2563eb;
        color: white;
        border: none;
        padding: 10px 20px;
        border-radius: 4px;
        cursor: pointer;
        font-weight: 500;
      }

      button:disabled {
        background: #94a3b8;
        cursor: not-allowed;
      }

      button:hover:not(:disabled) {
        background: #1d4ed8;
      }

      .status {
        margin: 20px 0;
        padding: 10px;
        border-radius: 4px;
      }

      .status.error {
        background: #fee2e2;
        color: #b91c1c;
      }

      .status.success {
        background: #dcfce7;
        color: #15803d;
      }

      .preview {
        margin: 20px 0;
        text-align: center;
      }

      .preview img {
        max-width: 100%;
        max-height: 400px;
        border-radius: 4px;
      }
    </style>
  </head>
  <body>
    <h1>Inscription SDK Demo</h1>

    <div class="container">
      <button id="connectWallet">Connect Wallet</button>
      <button id="disconnectWallet" style="display: none">Disconnect</button>
      <div id="accountInfo"></div>
    </div>

    <div class="container">
      <h2>Create Inscription</h2>
      <input type="file" id="fileInput" accept="image/*" />
      <button id="inscribeBtn" disabled>Inscribe File</button>
      <div id="inscriptionStatus"></div>
    </div>

    <script>
      // Initialize after HCS loads
      window.HCSReady = async () => {
        const hbarSDK = window.HashgraphSDK;
        const ledger = hbarSDK.LedgerId.TESTNET;
        const PROJECT_ID = 'bfd9ad3ea26e2c73eb21e8f9c750c166'; // Get from WalletConnect Dashboard
        const APP_METADATA = {
          name: 'Inscription SDK Demo',
          description: 'Demo app showing inscription creation and querying',
          url: window.location.origin,
          icons: ['https://kiloscribe.com/icon.png'],
        };

        // Get SDK instances
        const wcSDK = window.HashinalsWalletConnectSDK;
        let inscriptionSDK;
        let currentAccountId;

        // UI elements
        const connectBtn = document.getElementById('connectWallet');
        const disconnectBtn = document.getElementById('disconnectWallet');
        const accountInfo = document.getElementById('accountInfo');
        const inscribeBtn = document.getElementById('inscribeBtn');
        const inscriptionStatus = document.getElementById('inscriptionStatus');
        const queryResults = document.getElementById('queryResults');

        // UI update helper
        function updateUI(accountId, balance) {
          currentAccountId = accountId;

          if (accountId) {
            connectBtn.style.display = 'none';
            disconnectBtn.style.display = 'block';
            inscribeBtn.disabled = false;

            accountInfo.innerHTML = `
              Connected Account: ${accountId}<br>
              Balance: ${balance} HBAR
            `;

            // Initialize inscription SDK
            inscriptionSDK = new window.InscriptionSDK({
              apiKey: 'YOUR_API_KEY', // Get from Kiloscribe Dashboard
              network: 'testnet',
            });
          } else {
            connectBtn.style.display = 'block';
            disconnectBtn.style.display = 'none';
            inscribeBtn.disabled = true;
            accountInfo.innerHTML = '';
            currentAccountId = null;
          }
        }

        // Check for existing connection
        const accountResponse = await wcSDK.initAccount(
          PROJECT_ID,
          APP_METADATA,
          ledger
        );
        if (accountResponse && accountResponse.accountId) {
          updateUI(accountResponse.accountId, accountResponse.balance);
        }

        // Connect wallet
        connectBtn.addEventListener('click', async () => {
          try {
            const { accountId, balance } = await wcSDK.connectWallet(
              PROJECT_ID,
              APP_METADATA,
              ledger
            );
            updateUI(accountId, balance);
          } catch (error) {
            console.error('Connection failed:', error);
            alert('Failed to connect wallet');
          }
        });

        // Disconnect wallet
        disconnectBtn.addEventListener('click', async () => {
          try {
            await wcSDK.disconnectWallet();
            updateUI(null, null);
          } catch (error) {
            console.error('Disconnect failed:', error);
          }
        });

        // Handle file inscription
        inscribeBtn.addEventListener('click', async () => {
          const fileInput = document.getElementById('fileInput');
          const file = fileInput.files[0];
          if (!file) {
            alert('Please select a file first');
            return;
          }

          try {
            inscriptionStatus.textContent = 'Reading file...';

            // Convert file to base64
            const reader = new FileReader();
            reader.onload = async (e) => {
              const base64Data = e.target.result.split(',')[1];

              try {
                inscriptionStatus.textContent = 'Starting inscription...';

                const signer = wcSDK.dAppConnector.signers.find((signer) => {
                  return signer.getAccountId().toString() === currentAccountId;
                });

                // Start inscription
                const result = await inscriptionSDK.inscribe(
                  {
                    file: {
                      type: 'base64',
                      base64: base64Data,
                      fileName: file.name,
                    },
                    holderId: currentAccountId,
                    mode: 'hashinal',
                    metadataObject: {
                      name: 'Example NFT',
                      description: 'This is an example NFT',
                      attributes: [
                        {
                          trait_type: 'Example Trait',
                          value: 'Example Value',
                        },
                      ],
                    },
                  },
                  signer
                );

                inscriptionStatus.textContent = `Inscription started! Transaction ID: ${result.transactionId}`;

                // Poll for completion
                const checkStatus = async () => {
                  const status = await inscriptionSDK.retrieveInscription(
                    result.jobId
                  );
                  inscriptionStatus.textContent = `Status: ${status.status}`;

                  if (
                    status.status !== 'completed' &&
                    status.status !== 'failed'
                  ) {
                    setTimeout(checkStatus, 2000);
                  }
                };

                checkStatus();
              } catch (error) {
                inscriptionStatus.textContent = `Inscription failed: ${error.message}`;
              }
            };

            reader.readAsDataURL(file);
          } catch (error) {
            inscriptionStatus.textContent = `Error: ${error.message}`;
          }
        });
      };
    </script>
  </body>
</html>

C. Node.js Apps with Private Key

This method is for backend services or scripts:

  1. Install dependencies:
npm install @kiloscribe/inscription-sdk @hashgraph/sdk
  1. Create your script:
import { InscriptionSDK } from '@kiloscribe/inscription-sdk';
import * as fs from 'fs';

const sdk = new InscriptionSDK({
  apiKey: process.env.API_KEY,
  network: process.env.HEDERA_NETWORK,
});

// Read a file
const file = fs.readFileSync('path/to/file.png');
const base64 = file.toString('base64');

// Create an inscription
const result = await sdk.inscribeAndExecute(
  {
    file: {
      type: 'base64',
      base64,
      fileName: 'example.png',
      mimeType: 'image/png',
    },
    holderId: process.env.HEDERA_ACCOUNT_ID,
    mode: 'file',
    network: process.env.HEDERA_NETWORK,
    description: 'Example inscription',
  },
  {
    accountId: process.env.HEDERA_ACCOUNT_ID,
    privateKey: process.env.HEDERA_PRIVATE_KEY,
    network: process.env.HEDERA_NETWORK,
  }
);

Creating Different Types of Inscriptions

1. Basic File Inscription

Upload any supported file type:

// retrieve dAppConnector from hedera-wallet-connect

const dAppSigner = dAppConnector.signers.find((signer) => {
  return signer.getAccountId().toString() === accountId;
});
const result = await sdk.inscribe(
  {
    file: {
      type: 'base64',
      base64: 'your_base64_data',
      fileName: 'example.png',
      mimeType: 'image/png',
    },
    holderId: accountId,
    mode: 'file',
    network: 'testnet',
    description: 'My first inscription',
  },
  dAppSigner // or use inscribeAndExecute with private key
);

2. Hashinal NFT

Create an NFT with metadata:

async function inscribeHashinal() {
  const sdk = new InscriptionSDK({
    apiKey: process.env.KILOSCRIBE_API_KEY,
    network: 'testnet',
  });

  const imagePath = join(__dirname, 'assets', 'example.webp');
  const imageBuffer = readFileSync(imagePath);
  const base64Image = imageBuffer.toString('base64');

  try {
    const result = await sdk.inscribeAndExecute(
      {
        file: {
          type: 'base64',
          base64: base64Image,
          fileName: 'example.webp',
          mimeType: 'image/webp',
        },
        holderId: '0.0.123456',
        mode: 'hashinal',
        network: 'testnet',
        description: 'Example hashinal inscription',
        metadataObject: {
          name: 'Example NFT',
          description: 'This is an example NFT',
          attributes: [
            {
              trait_type: 'Example Trait',
              value: 'Example Value',
            },
          ],
        },
      },
      {
        accountId: '0.0.123456',
        privateKey: process.env.HEDERA_ACCOUNT_PRIVATE_KEY!,
        network: 'testnet',
      }
    );

    console.log('Inscription completed:', result);

    // You can also retrieve the inscription status
    const status = await sdk.retrieveInscription(result.jobId);
    console.log('Inscription status:', status);
  } catch (error) {
    console.error('Error:', error instanceof Error ? error.message : error);
  }
}

// Run the example
inscribeHashinal().catch(console.error);

3. URL Inscription

Inscribe a file from a URL:

const result = await sdk.inscribe(
  {
    file: {
      type: 'url',
      url: 'https://example.com/image.png',
    },
    holderId: accountId,
    mode: 'file',
    network: 'testnet',
    description: 'URL inscription',
  },
  dAppSigner
);

Querying Inscriptions

Get Inscriptions

You can fetch inscriptions by their sequence numbers:

// Get inscription details by sequence number
const inscriptions = await sdk.getInscriptionNumbers({
  inscriptionNumber: 1234, // Optional: specific inscription number
  sort: 'desc', // Optional: 'asc' or 'desc'
  limit: 10, // Optional: max results to return
});

console.log(inscriptions);

Get Holder Inscriptions

You can fetch all inscriptions owned by a specific holder:

// Get all inscriptions for a specific holder
const holderInscriptions = await sdk.getHolderInscriptions({
  holderId: '0.0.123456', // Required: Hedera account ID of the holder
  includeCollections: true, // Optional: Include collection inscriptions
});

console.log(`Found ${holderInscriptions.length} inscriptions`);

// Access individual inscription details
holderInscriptions.forEach((inscription) => {
  console.log(`ID: ${inscription.id}`);
  console.log(`Status: ${inscription.status}`);
  console.log(`File URL: ${inscription.fileUrl}`);
  console.log(`Topic ID: ${inscription.topic_id}`);
});

Checking Inscription Status

The SDK provides two methods for checking inscription status:

1. Simple Status Check

const status = await sdk.retrieveInscription(result.jobId);
console.log('Status:', status.status);

2. Wait for Completion

The waitForInscription method will poll until the inscription meets completion criteria:

const complete = await sdk.waitForInscription(
  result.jobId,
  30, // max attempts (optional, default: 30)
  4000, // interval in ms (optional, default: 4000)
  true // check completion status (optional, default: false)
);

Completion criteria varies by inscription type:

  • Regular files: Need topic_id
  • Hashinal NFTs: Need both topic_id and jsonTopicId
  • Dynamic files (HCS-6): Need topic_id, jsonTopicId, and registryTopicId

If checkCompletion is true, also verifies status === 'completed'.

Examples

Vanilla JavaScript Demo

A minimal example using vanilla JavaScript and HCS-3 recursion is available in the demo/vanilla directory.

See the full example in demo/vanilla/index.html for wallet integration and inscription querying.

Try the Interactive Demo

We've included a complete demo app in the demo directory that shows:

  • Wallet connection with QR code
  • File selection with preview
  • Inscription creation
  • Status updates

To run it:

  1. Clone the repository:
git clone https://github.com/kiloscribe/inscription-sdk.git
cd inscription-sdk
  1. Set up the demo:
cd demo
npm install
cp .env.example .env
  1. Configure the demo: Edit .env and add:
  • Your Kiloscribe API key
  • Your WalletConnect Project ID
  1. Start the demo:
npm run dev
  1. Open http://localhost:3000 and try it out!

File Support

Size Limits

  • URL files: Up to 100MB
  • Base64/Local files: Up to 2MB

Supported Formats

  • Images: jpg, jpeg, png, gif, bmp, webp, tiff, svg
  • Video: mp4, webm
  • Audio: mp3
  • Documents: pdf, doc, docx, xls, xlsx, ppt, pptx
  • Web: html, css, js
  • Data: csv, json, txt
  • 3D: glb

Common Issues

1. "Account ID not found"

  • Make sure you're using the correct Account ID format (0.0.123456)
  • Check if you're on the right network (testnet/mainnet)

2. "Transaction failed"

  • Ensure your account has enough HBAR (at least 1 HBAR recommended)
  • Check if your private key matches your account ID
  • Verify you're using the correct network

3. "File too large"

  • URL inscriptions: Max 100MB
  • Base64/Local files: Max 2MB
  • Try compressing your file or using a URL instead

4. WalletConnect Issues

  • Ensure your wallet (e.g., HashPack) is installed and on the correct network
  • Check if your WalletConnect Project ID is correct
  • Try clearing your browser cache

Error Handling

Always wrap SDK calls in try-catch:

try {
  const result = await sdk.inscribe(config, signer);
  console.log('Inscription started:', result.jobId);

  // Poll for status
  const checkStatus = async () => {
    const status = await sdk.retrieveInscription(result.jobId);
    console.log('Status:', status.status);

    if (status.status !== 'completed' && status.status !== 'failed') {
      setTimeout(checkStatus, 2000); // Check every 2 seconds
    }
  };

  checkStatus();
} catch (error) {
  console.error('Error:', error instanceof Error ? error.message : error);
}

Support

Need help? We've got you covered:

License

Apache-2.0