Skip to content

feat: Add @didcid/cl-hive client package #120

@macterra

Description

@macterra

Summary

Add a new @didcid/cl-hive package that provides a TypeScript client for interacting with the CLN node's REST API (clnrest plugin). This is the foundational package that enables Archon services to programmatically use the Lightning node deployed in #57.

Motivation

The cl-hive Docker container (#57) is running, but no Archon service can talk to it. This package bridges that gap — it wraps the clnrest API with a typed TypeScript client that other packages and services can depend on.

This is a prerequisite for:

Design

CLN REST API (clnrest)

The cl-hive container exposes clnrest on port 3001 (bound to localhost). Authentication uses CLN runes — bearer tokens with macaroon-like caveats. The API maps 1:1 to CLN's JSON-RPC commands via HTTP POST.

Package Scope

Wrap the subset of clnrest endpoints that Archon needs, not the entire CLN API. Start minimal, expand as needed.

Core (needed for L402 and basic operations):

  • getinfo — node pubkey, alias, network, block height, peers
  • invoice — create a Lightning invoice (amount, label, description)
  • listinvoices — check invoice status by payment_hash or label
  • waitinvoice — wait for invoice payment (long-poll)
  • pay — pay a BOLT11 invoice
  • keysend — send a keysend payment (for TLV-encoded data)

Identity:

  • getinfo pubkey extraction for DID binding

Utility:

  • listnodes — peer info
  • listfunds — on-chain and channel balances
  • listchannels — channel state

Package Structure

Following the @didcid/cipher / @didcid/ipfs pattern:

packages/cl-hive/
├── package.json
├── tsconfig.json
├── rollup.cjs.config.js
└── src/
    ├── index.ts          # public API re-exports
    ├── types.ts          # ClnConfig, Invoice, Payment, NodeInfo, etc.
    ├── errors.ts         # ClnError, ClnConnectionError, ClnAuthError, RuneError
    ├── cl-hive-client.ts # main client class
    └── rune.ts           # rune handling utilities

Client API

import { ClnClient } from '@didcid/cl-hive';

const cln = new ClnClient({
    restUrl: 'http://localhost:3001',
    rune: process.env.ARCHON_CLN_RUNE,
});

// Node identity
const info = await cln.getInfo();
// info.id = "02abc...def" (node pubkey)

// Create invoice
const invoice = await cln.createInvoice({
    amountMsat: 1000000,  // 1000 sats
    label: 'did-registration-001',
    description: 'DID registration on BTC:mainnet',
});
// invoice.bolt11, invoice.paymentHash, invoice.expiresAt

// Check payment
const status = await cln.getInvoice(invoice.paymentHash);
// status.status = 'paid' | 'unpaid' | 'expired'

// Wait for payment
const paid = await cln.waitForInvoice(invoice.label);
// paid.preimage, paid.amountReceivedMsat

// Pay an invoice
const payment = await cln.pay(bolt11String);

// Balances
const funds = await cln.listFunds();

Authentication

clnrest uses runes for auth, passed via HTTP header:

Rune: <rune-string>

The rune should be created with appropriate restrictions (e.g., read-only for monitoring, invoice-only for L402). The client accepts the rune via ClnConfig and attaches it to every request.

Configuration

New env vars:

ARCHON_CLN_REST_URL=http://localhost:3001
ARCHON_CLN_RUNE=<rune-string>

For Docker deployments, the gatekeeper/keymaster services would reach CLN at http://cln-mainnet-node:3001.

Dependencies

  • axios (already in monorepo) — HTTP client for clnrest API
  • @didcid/common — error types

No new external dependencies required.

Tests

tests/cl-hive/
├── helper.ts             # mock clnrest responses
├── cl-hive-client.test.ts # client methods with nock-mocked API
├── rune.test.ts          # rune handling
└── errors.test.ts        # error mapping from CLN API errors

Use nock (already a dev dependency) to mock the clnrest HTTP API.

Monorepo Integration

File Change
packages/cl-hive/ New package (all files above)
package.json (root) Add @didcid/cl-hive to build script (after @didcid/common)
tsconfig.json (root) Add @didcid/cl-hive path mappings
jest.config.js Add @didcid/cl-hive moduleNameMapper
sample.env Add ARCHON_CLN_REST_URL, ARCHON_CLN_RUNE
docker-compose.yml Pass CLN env vars to gatekeeper/keymaster services

Blocked By

None — cl-hive Docker service is already running (#57).

Enables

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions