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

@spruceid/opencred-dc-api

v0.2.0

Published

TypeScript/Node.js wrapper for OpenCred DC API WASM binary

Readme

DC API WASM - Node.js/TypeScript Package

A WebAssembly-based Node.js/TypeScript package for the DC API, providing digital credential operations with OpenID4VP support and session management through wasm-bindgen generated bindings.

Installation

npm install @spruceid/opencred-dc-api

Quick Start

import { DcApi, JsOid4VpSessionStore } from '@spruceid/opencred-dc-api';

// Prepare your PKCS8 PEM encoded private key for signing
const privateKeyPem = `-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...
-----END PRIVATE KEY-----`;

// Create session stores
const oid4vpStore = JsOid4VpSessionStore.createMemoryStore();
const dcApiStore = {
  async newSession(sessionId: string, session: any) {
    // Implementation
    return { id: sessionId, secret: 'generated-secret' };
  },
  async getSession(id: string, clientSecret: string) {
    // Implementation
    return null;
  },
  async getSessionUnauthenticated(id: string) {
    // Implementation
    return null;
  },
  async updateSession(sessionId: string, session: any) {
    // Implementation
  },
  async removeSession(sessionId: string) {
    // Implementation
  }
};

// Create and initialize DC API instance
const dcApi = await DcApi.new(
  privateKeyPem,  // PKCS8 PEM encoded private key for signing
  'https://api.example.com',
  'https://api.example.com/submit',
  'https://api.example.com/reference',
  new Uint8Array([/* your cert chain */]),
  oid4vpStore,
  dcApiStore
);

// Create a session
const session = await dcApi.create_new_session();

// Make a request with the session
const request = {
  // Your DC API request data
};

const result = await dcApi.initiate_request(
  session.id,
  session.secret,
  request,
  'my-app/1.0.0'
);
console.log(result);

// Submit a response
const response = {
  // Your response data
};

const submitResult = await dcApi.submit_response(
  session.id,
  session.secret,
  response
);

// Clean up when done
dcApi.free();

Building from Source

This package wraps a Rust WASM binary. To build the complete package:

  1. Build the WASM binary:

    npm run build:wasm

    This runs the build script that uses wasm-bindgen to generate the JavaScript bindings.

  2. Build the TypeScript wrapper:

    npm run build:ts
  3. Build everything:

    npm run build

API Reference

DcApi Class

The main WebAssembly class generated by wasm-bindgen that provides DC API functionality.

import { DcApi } from '@spruceid/opencred-dc-api';

Constructor

static new(key: string, base_url: string, submission_endpoint: string, reference_endpoint: string, cert_chain_pem: Uint8Array, oid4vp_session_store: JsOid4VpSessionStore, js_dc_api_session_store: DcApiSessionStore): Promise<DcApi>

Create and initialize a new DC API instance.

Parameters:

  • key: PKCS8 PEM encoded private key used for signing operations
  • base_url: Base URL for the DC API
  • submission_endpoint: Endpoint for submitting responses
  • reference_endpoint: Endpoint for references
  • cert_chain_pem: Certificate chain in PEM format as Uint8Array
  • oid4vp_session_store: OID4VP session storage implementation
  • js_dc_api_session_store: DC API session storage implementation
const privateKeyPem = `-----BEGIN PRIVATE KEY-----
MIGH...
-----END PRIVATE KEY-----`;

const dcApi = await DcApi.new(
  privateKeyPem,
  'https://api.example.com',
  'https://api.example.com/submit',
  'https://api.example.com/reference',
  certChainPem,
  oid4vpStore,
  dcApiStore
);

Methods

create_new_session(): Promise<any>

Create a new DC API session.

const session = await dcApi.create_new_session();
console.log('Session:', session);
initiate_request(session_id: string, session_secret: string, request: any, user_agent?: string | null): Promise<any>

Initiate a DC API request with session credentials.

const result = await dcApi.initiate_request(
  sessionId,
  sessionSecret,
  request,
  'my-app/1.0.0'
);
submit_response(session_id: string, session_secret: string, response: any): Promise<any>

Submit a response for a DC API session.

const result = await dcApi.submit_response(
  sessionId,
  sessionSecret,
  response
);
free(): void

Free the WebAssembly memory used by this instance.

dcApi.free();

JsOid4VpSessionStore Class

WebAssembly-compatible session store that delegates to JavaScript storage implementations.

Constructor

constructor(store: Oid4VpSessionStore)

Creates a new WebAssembly session store with JavaScript storage implementation.

class MySessionStore {
  async initiate(session) {
    // Store session in your preferred storage
    localStorage.setItem(`session_${session.uuid}`, JSON.stringify(session));
  }

  async updateStatus(uuid, status) {
    // Update session status
    const session = JSON.parse(localStorage.getItem(`session_${uuid}`));
    session.status = status;
    localStorage.setItem(`session_${uuid}`, JSON.stringify(session));
  }

  async getSession(uuid) {
    // Get session from storage
    const sessionData = localStorage.getItem(`session_${uuid}`);
    if (!sessionData) throw new Error('Session not found');
    return JSON.parse(sessionData);
  }

  async removeSession(uuid) {
    // Remove session from storage
    localStorage.removeItem(`session_${uuid}`);
  }
}

const sessionStore = new JsOid4VpSessionStore(new MySessionStore());

Static Methods

createMemoryStore(): JsOid4VpSessionStore

Create a simple in-memory session store for testing purposes.

const sessionStore = JsOid4VpSessionStore.createMemoryStore();
generateSessionUuid(): string

Generate a new UUID for session identification.

const uuid = JsOid4VpSessionStore.generateSessionUuid();
parseUuid(uuid_str: string): string

Parse and validate a UUID string.

const parsed = JsOid4VpSessionStore.parseUuid('550e8400-e29b-41d4-a716-446655440000');
Status Creation Helpers
// Create different status types
const sentRequestByRef = JsOid4VpSessionStore.createStatusSentRequestByReference();
const sentRequest = JsOid4VpSessionStore.createStatusSentRequest();
const receivedResponse = JsOid4VpSessionStore.createStatusReceivedResponse();
const success = JsOid4VpSessionStore.createStatusCompleteSuccess({ data: 'result' });
const failure = JsOid4VpSessionStore.createStatusCompleteFailure('reason');
const error = JsOid4VpSessionStore.createStatusCompleteError('cause');

Session Storage Interfaces

OID4VP Session Store Interface

interface Oid4VpSessionStore {
  initiate(session: any): Promise<void>;
  updateStatus(uuid: string, status: any): Promise<void>;
  getSession(uuid: string): Promise<any>;
  removeSession(uuid: string): Promise<void>;
}

DC API Session Store Interface

interface DcApiSessionStore {
  newSession(sessionId: string, session: any): Promise<SessionCreationResponse>;
  getSession(id: string, clientSecret: string): Promise<any | null>;
  getSessionUnauthenticated(id: string): Promise<any | null>;
  updateSession(sessionId: string, session: any): Promise<void>;
  removeSession(sessionId: string): Promise<void>;
}

JsDcApiSessionDriver Class

A supporting class for DC API session management (generated by wasm-bindgen).

class JsDcApiSessionDriver {
  free(): void;
}

This class is primarily used internally by the DC API implementation.

Error Handling

The WASM functions may throw errors that are propagated as JavaScript exceptions:

try {
  const result = await dcApi.initiate_request(
    sessionId,
    sessionSecret,
    request
  );
} catch (error) {
  console.error('DC API Error:', error);
}

CI/CD & Releases

This package uses automated CI/CD workflows for testing, validation, and publishing.

Automated Testing

Every push and pull request triggers comprehensive testing:

  • WASM Build Validation: Ensures the Rust/WASM build succeeds
  • Package Structure: Validates correct file locations and package.json structure
  • Integration Tests: Tests that generated bindings load correctly
  • Security Audits: npm and Cargo dependency vulnerability scanning
  • Code Quality: Rust formatting and Clippy linting

Automated Publishing

Releases are triggered by pushing git tags in the format npm/v[version]:

# Create and push a release
npm run release:patch  # Creates tag npm/v1.0.1
git push origin npm/v1.0.1

The release workflow will:

  1. Validate the package version matches the tag
  2. Set up Rust toolchain and wasm-bindgen
  3. Build the WASM binary and JS bindings
  4. Publish to npm with public access

Release Process

For detailed release instructions, see RELEASE.md.

Quick release workflow:

# Increment version and create tag
npm run release:minor  # or release:patch, release:major

# Push the tag to trigger publishing
git push origin npm/v$(node -p "require('./package.json').version")

Manual Development

For local development without CI:

Prerequisites

  • Node.js 16+
  • Rust toolchain with wasm32-unknown-unknown target
  • wasm-bindgen-cli

Setup

  1. Clone the repository

  2. Install dependencies:

    npm install
  3. Build the project:

    npm run build

Scripts

  • npm run build - Build only WASM (for publishing)
  • npm run build:dev - Build WASM + TypeScript (for development)
  • npm run build:wasm - Build only the WASM binary
  • npm run build:ts - Build only TypeScript wrapper
  • npm run clean - Clean build artifacts
  • npm run prerelease - Validate package before release

Testing

Run the test suite:

npm test

Tests include:

  • Unit tests for all API classes
  • Session management tests
  • WASM loader tests
  • Error handling tests
  • Storage implementation tests

Package Structure

npm-package/
├── dist/                       # Built output (published to npm)
│   ├── dc_api_wasm.js         # wasm-bindgen generated JavaScript
│   ├── dc_api_wasm.d.ts       # wasm-bindgen generated TypeScript definitions
│   ├── dc_api_wasm_bg.wasm    # WebAssembly binary
│   └── dc_api_wasm_bg.wasm.d.ts  # WebAssembly TypeScript definitions
├── src/                        # TypeScript source files (if any)
├── tests/                      # Test files (excluded from npm)
├── build-wasm.sh              # WASM build script (excluded from npm)
├── package.json               # Package configuration
├── tsconfig.json              # TypeScript configuration (excluded from npm)
├── README.md                  # Package documentation
└── RELEASE.md                 # Release process documentation (excluded from npm)

Example: Complete Flow

import { DcApi, JsOid4VpSessionStore } from '@spruceid/opencred-dc-api';

async function main() {
  // Create session stores
  const oid4vpStore = JsOid4VpSessionStore.createMemoryStore();

  const dcApiStore = {
    async newSession(sessionId: string, session: any) {
      console.log('Creating new session:', sessionId);
      return { id: sessionId, secret: 'generated-secret' };
    },
    async getSession(id: string, clientSecret: string) {
      console.log('Getting session:', id);
      return null;
    },
    async getSessionUnauthenticated(id: string) {
      return null;
    },
    async updateSession(sessionId: string, session: any) {
      console.log('Updating session:', sessionId);
    },
    async removeSession(sessionId: string) {
      console.log('Removing session:', sessionId);
    }
  };

  // Initialize the API
  const privateKeyPem = process.env.PRIVATE_KEY_PEM!; // PKCS8 PEM private key
  const dcApi = await DcApi.new(
    privateKeyPem,
    process.env.DC_API_URL!,
    process.env.DC_API_SUBMIT_URL!,
    process.env.DC_API_REFERENCE_URL!,
    new Uint8Array(Buffer.from(process.env.CERT_CHAIN!, 'base64')),
    oid4vpStore,
    dcApiStore
  );

  try {
    // Create a session
    const session = await dcApi.create_new_session();
    console.log('Created session:', session);

    // Prepare a request
    const request = {
      type: 'credential_request',
      data: {
        // Request data
      }
    };

    // Make the request
    const result = await dcApi.initiate_request(
      session.id,
      session.secret,
      request,
      'my-app/1.0.0'
    );

    console.log('Request result:', result);

    // Submit a response if needed
    const response = {
      // Response data
    };

    const submitResult = await dcApi.submit_response(
      session.id,
      session.secret,
      response
    );

    console.log('Submit result:', submitResult);
  } catch (error) {
    console.error('Error:', error);
  } finally {
    // Clean up
    dcApi.free();
  }
}

main().catch(console.error);

Requirements

  • Node.js: >= 16.0.0
  • WASM Support: Node.js has built-in WebAssembly support

License

MIT

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Run npm test
  6. Submit a pull request

Troubleshooting

WASM Module Not Found

If you get errors about missing WASM files:

npm run build:wasm

Make sure wasm-bindgen-cli is installed:

cargo install wasm-bindgen-cli

Build Failures

If the WASM build fails, ensure you have the correct environment:

# Ensure the correct target is available
rustup target add wasm32-unknown-unknown

# Install wasm-bindgen-cli if not already installed
cargo install wasm-bindgen-cli

Runtime Errors

If you encounter runtime errors:

  1. Ensure dcApi.init(config) was called with valid configuration before using other methods
  2. Check that the WASM binary is properly included in your bundle
  3. Verify Node.js version compatibility (>= 16.0.0)
  4. Make sure session credentials are valid when making requests

Session Management Issues

  • Sessions have limited lifetimes; create new sessions as needed
  • Store session credentials securely
  • Don't reuse sessions across different security contexts

Support

For issues and questions:

  • GitHub Issues: Create an issue
  • Documentation: Check the inline TypeScript documentation
  • Examples: See the tests/ directory for usage examples