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

@aho-sdk/core

v0.1.2

Published

TypeScript/JavaScript SDK for the Aho Verifiable Credentials API

Readme

AhoSdk TypeScript SDK

Official TypeScript/JavaScript SDK for the Aho Verifiable Credentials API.

Installation

npm install @aho-sdk/core
# or
yarn add @aho-sdk/core
# or
pnpm add @aho-sdk/core

Quick Start

import { Issuer } from '@aho-sdk/core';

// Initialize the Issuer client
const issuer = new Issuer({ apiKey: process.env.AHO_ISSUER_API_KEY });

// Issue a credential
const credential = await issuer.credentials.create({
  schema_uuid: 'your-schema-uuid',
  subject_identifier: '[email protected]',
  claims: {
    name: 'Jane Doe',
    role: 'Engineer'
  }
});

console.log(credential.uuid);

Clients

The SDK provides the following clients:

| Client | Purpose | API Key Type | |--------|---------|--------------| | Account | Manage account settings, domains, and API keys | Account API Key | | System | System health and status endpoints | System API Key | | Holder | Manage holder credentials and presentations | Holder API Key | | Verifier | Create presentation requests and verify credentials | Verifier API Key | | Issuer | Issue and manage verifiable credentials | Issuer API Key | | Schemas | Browse and retrieve credential schemas | Schemas API Key | | Unauthenticated | Public endpoints (no authentication required) | None (public) |

Usage Examples

Issuing Credentials

import { Issuer } from '@aho-sdk/core';

const issuer = new Issuer({ apiKey: process.env.AHO_ISSUER_API_KEY });

// List all schemas
const schemas = await issuer.schemas.list();
for await (const schema of schemas) {
  console.log(schema.name);
}

// Create a schema
const schema = await issuer.schemas.create({
  name: 'EmployeeBadge',
  claims: [
    { name: 'employee_id', type: 'string', required: true },
    { name: 'department', type: 'string', required: true },
    { name: 'hire_date', type: 'date', required: false }
  ]
});

// Issue a credential
const credential = await issuer.credentials.create({
  schema_uuid: schema.uuid,
  subject_identifier: '[email protected]',
  claims: {
    employee_id: 'EMP-12345',
    department: 'Engineering',
    hire_date: '2024-01-15'
  }
});

// Revoke a credential
await issuer.credentials.revoke(credential.uuid, { reason: 'Employee departed' });

Verifying Credentials

import { Verifier } from '@aho-sdk/core';

const verifier = new Verifier({ apiKey: process.env.AHO_VERIFIER_API_KEY });

// Create a presentation request
const request = await verifier.requests.create({
  name: 'Employment Verification',
  query_format: 'dcql',
  credentials: [
    {
      id: 'employee_badge',
      format: 'vc+sd-jwt',
      claims: [
        { path: ['employee_id'] },
        { path: ['department'] }
      ]
    }
  ]
});

// Get the QR code for the request (supports 'png', 'svg' formats)
const qr = await verifier.requests.qrCode(request.uuid, 'svg');

// List responses to the request
const responses = await verifier.responses.list(request.uuid);

Managing Holder Credentials

import { Holder } from '@aho-sdk/core';

const holder = new Holder({ apiKey: process.env.AHO_HOLDER_API_KEY });

// List credentials
const credentials = await holder.credentials.list('active');

// Create a presentation (selective disclosure)
const presentation = await holder.presentations.create({
  credential_uuid: 'credential-uuid',
  disclosed_claims: ['name', 'department']
});

Account Management

import { Account } from '@aho-sdk/core';

const account = new Account({ apiKey: process.env.AHO_API_KEY });

// Manage domains
const domains = await account.domains.list();
await account.domains.verify(domain.id);

// Manage signing keys
const keys = await account.signingKeys.list();
await account.signingKeys.rotate(key.id);

// Configure webhooks
await account.webhooks.create({
  url: 'https://your-app.com/webhooks/aho',
  events: ['credential.issued', 'credential.revoked']
});

Pagination

List methods return Page objects with async iteration support:

// Iterate through all pages automatically
for await (const credential of issuer.credentials.list()) {
  console.log(credential.uuid);
}

// Or handle pages manually
let page = await issuer.credentials.list(1, 50);
while (page) {
  for (const credential of page.data) {
    console.log(credential.uuid);
  }
  page = await page.nextPage();
}

// Collect all items
const allCredentials = await issuer.credentials.list().toArrayAll();

File Uploads

For endpoints that accept file uploads:

import * as fs from 'fs';

// Upload a file
await issuer.media.upload({
  file: fs.createReadStream('document.pdf'),
  metadata: { description: 'Employee contract' }
});

// In the browser, use File or Blob
const fileInput = document.querySelector<HTMLInputElement>('#fileInput');
await issuer.media.upload({
  file: fileInput.files[0]
});

Binary Responses

Some endpoints return binary data (images, PDFs):

import * as fs from 'fs';

// Get QR code as PNG (returns ArrayBuffer)
const pngData = await verifier.requests.qrCode(uuid, 'png');
fs.writeFileSync('qr.png', Buffer.from(pngData));

// Get QR code as SVG
const svgData = await verifier.requests.qrCode(uuid, 'svg');
fs.writeFileSync('qr.svg', Buffer.from(svgData));

Error Handling

import {
  Issuer,
  ValidationError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  ApiError
} from '@aho-sdk/core';

try {
  await issuer.credentials.create(invalidParams);
} catch (error) {
  if (error instanceof ValidationError) {
    // 422 - Validation failed
    for (const fieldError of error.fieldErrors) {
      console.log(`${fieldError.field}: ${fieldError.hint}`);
    }
  } else if (error instanceof AuthenticationError) {
    // 401 - Invalid API key
    console.log('Check your API key');
  } else if (error instanceof NotFoundError) {
    // 404 - Resource not found
    console.log(`Resource not found: ${error.message}`);
  } else if (error instanceof RateLimitError) {
    // 429 - Rate limited (SDK auto-retries with exponential backoff)
    console.log(`Retry after ${error.retryAfter} seconds`);
  } else if (error instanceof ApiError) {
    // Other API errors
    console.log(`Error ${error.statusCode}: ${error.message}`);
    console.log(`Request ID: ${error.requestId}`);
  }
}

Error Classes

| Error Class | HTTP Status | Description | |-------------|-------------|-------------| | AuthenticationError | 401 | Invalid or missing API key | | ForbiddenError | 403 | Insufficient permissions | | NotFoundError | 404 | Resource not found | | ConflictError | 409 | Resource conflict | | ValidationError | 422 | Request validation failed | | RateLimitError | 429 | Rate limit exceeded | | ServerError | 5xx | Server-side error | | NetworkError | - | Connection/timeout error | | ApiError | * | Base class for all API errors |

Rate Limiting

The SDK automatically handles rate limits with exponential backoff:

  • Idempotent methods (GET, DELETE, PUT): Auto-retry up to 3 times
  • Non-idempotent methods (POST, PATCH): Only retry with idempotency key
// Use idempotency keys for safe retries on POST/PATCH
await issuer.credentials.create({
  schema_uuid: '...',
  claims: { ... },
  idempotencyKey: 'unique-request-id'
});

Configuration

// Custom configuration
const issuer = new Issuer({
  apiKey: process.env.AHO_ISSUER_API_KEY,
  baseUrl: 'https://api.aho.com',  // Custom base URL
  timeout: 60000,                   // Request timeout in milliseconds
  logger: {                         // Enable debug logging
    debug: (msg) => console.debug(msg),
    warn: (msg) => console.warn(msg)
  }
});

Browser Support

The SDK uses the Fetch API and works in modern browsers (Chrome, Firefox, Safari, Edge) as well as Node.js 18+.

TypeScript

The SDK is written in TypeScript and includes full type definitions:

import { Issuer, Page } from '@aho-sdk/core';

// Types are inferred
const credential = await issuer.credentials.get('uuid');
// credential: Record<string, unknown> | null

const page = await issuer.credentials.list();
// page: Page<Record<string, unknown>>

Requirements

  • Node.js 18+ or modern browser with Fetch API support
  • TypeScript 5.0+ (for TypeScript users)

License

MIT