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

@truesight_dao/dao-client

v1.1.0-rc.4

Published

Zero-dependency browser library for TrueSight DAO identity, signing, and Edgar submission

Downloads

990

Readme

@truesight_dao/dao-client

Zero-dependency browser library for TrueSight DAO identity management, cryptographic signing, and Edgar submission.

Installation

Browser (CDN)

<script src="https://unpkg.com/@truesight_dao/[email protected]/dist/dao-client.min.js"></script>
<script>
  // window.DaoClient is the class itself
  const client = new DaoClient();
</script>

Module (ESM / CJS)

import { DaoClient } from '@truesight_dao/dao-client';
const client = new DaoClient();

Quick Start

const client = new DaoClient();

// Submit any signed event to Edgar in one call
const result = await client.submitEvent({
  eventType: 'CONTRIBUTION EVENT',
  fields: {
    Type: 'Time (Minutes)',
    Amount: '30',
    Description: 'DAO standup and code review',
    'Contributor(s)': 'Your Name',
  },
});

console.log(result.status); // 'submitted'
console.log(result.slug);   // 'pk-a1b2c3d4e5f6'

API Reference

Constructor

const client = new DaoClient(options?: DaoClientOptions);

| Option | Type | Default | Description | |--------|------|---------|-------------| | edgarBase | string | 'https://edgar.truesight.me' | Base URL for Edgar API | | verifyUrl | string | 'https://dapp.truesight.me/verify_request.html' | URL for signature verification UI | | storagePrefix | string | 'truesight_dao_' | localStorage key prefix for keypair persistence | | generationSource | string | window.location.origin + pathname | Source URL embedded in signed payloads |

On construction, the client auto-loads an existing keypair from localStorage, or auto-generates a new RSA-2048 keypair if none exists. The keypair persists across page loads automatically.


client.submitEvent(options)Recommended

Submit any signed event to Edgar with safety features (auto-Timestamp injection, field value guarding).

const result = await client.submitEvent({
  eventType: 'PRACTICE EVENT',
  fields: {
    Program: 'capoeira-tribo-mirim',
    'Practice Type': 'training-session',
    'Captured At': new Date().toISOString(),
    'Source URL': window.location.href,
    Theme: 'ginga-basics',
    'Total Practice Minutes': '45',
  },
});

Returns: SubmitEventResponse


client.registerEmail(email)

Register an email address with the DAO identity system. Submits an [EMAIL REGISTERED EVENT].

const result = await client.registerEmail('[email protected]');

if (result.emailRegistration?.status === 'pending_verification') {
  console.log('Check your inbox for the verification link.');
}

After calling this, the user must click the verification link sent to their email to complete registration. The link must be opened in the same browser where the keypair lives (the signing key is in localStorage).

Returns: SubmitEventResponse with emailRegistration populated.


client.verifyEmail(email, verificationKey)

Complete email verification using the key from the email link. Submits an [EMAIL VERIFICATION EVENT].

// Call this when the user lands on your page with ?em=...&vk=... params
const params = new URLSearchParams(window.location.search);
const email = params.get('em');
const vk = params.get('vk');

if (email && vk) {
  const result = await client.verifyEmail(email, vk);
  if (result.ok) {
    console.log('Email verified!');
  }
}

Returns: SubmitEventResponse with emailRegistration populated.


client.checkRegistration()

Check the registration status of the current public key against Edgar. This is a read-only GET call (not a submission).

const status = await client.checkRegistration();

if (status.registered) {
  console.log(`Registered as ${status.contributor_name}`);
} else if (status.pending_verification) {
  console.log(`Pending verification for ${status.contributor_email}`);
} else {
  console.log('Not registered.');
}

Returns: CheckRegistrationResponse


client.getSlug()

Derive the public key slug — a pk- prefix followed by the first 12 characters of the SHA-256 hash of the public key.

const slug = await client.getSlug();
// e.g. 'pk-a1b2c3d4e5f6'

const cvUrl = `https://truesight.me/programs/truesight-grounding/credentials/#${slug}`;

This is used to build credential page URLs on truesight.me.

Returns: string


client.generateKeyPair()

Generate a new RSA-2048 keypair, store it in localStorage, and update the client instance.

const kp = await client.generateKeyPair();
console.log(kp.publicKey);  // SPKI base64 string
console.log(kp.privateKey); // PKCS#8 base64 string

Returns: { publicKey: string, privateKey: string }


client.verifyPayload(payload, txId)

Verify a signed payload against a transaction ID (signature).

const isValid = await client.verifyPayload(payloadText, signatureBase64);
console.log(isValid); // true or false

Returns: boolean


client.submit(eventName, attributes)Lower-level

Build a canonical payload, sign it, and submit to Edgar. This is the v1.0.x compatible method (no Timestamp injection, no field guard).

const { json, txId } = await client.submit('CONTRIBUTION EVENT', {
  Type: 'Time (Minutes)',
  Amount: '30',
});

Returns: { json: Record<string, unknown>, txId: string }


client.sign(eventName, attributes)Lower-level

Build and sign a payload without submitting. Useful for testing or manual workflows.

const { payload, txId, shareText } = await client.sign('CONTRIBUTION EVENT', {
  Type: 'Time (Minutes)',
  Amount: '30',
});

console.log(shareText); // Full signed text ready for Edgar

Returns: { payload: string, txId: string, shareText: string }


Static Methods

DaoClient.generateKeyPair()

Generate a new RSA-2048 keypair without instantiating a client.

const kp = await DaoClient.generateKeyPair();
// { publicKey: 'MIIB...', privateKey: 'MIIE...' }

Returns: Promise<{ publicKey: string, privateKey: string }>


DaoClient.arrayBufferToBase64(buffer)

Convert an ArrayBuffer to a base64-encoded string.

const b64 = DaoClient.arrayBufferToBase64(new Uint8Array([72, 101, 108, 108, 111]).buffer);
// 'SGVsbG8='

Returns: string


DaoClient.base64ToArrayBuffer(base64)

Convert a base64-encoded string to an ArrayBuffer.

const buf = DaoClient.base64ToArrayBuffer('SGVsbG8=');

Returns: ArrayBuffer


DaoClient.base64ToBase64Url(base64)

Convert a standard base64 string to base64url format (replaces + with -, / with _, strips = padding).

const urlSafe = DaoClient.base64ToBase64Url('SGVsbG8=');
// 'SGVsbG8'

Returns: string


Response Types

SubmitEventResponse

Returned by submitEvent(), registerEmail(), and verifyEmail().

interface SubmitEventResponse {
  ok: boolean;
  status: 'submitted' | 'server_error' | 'signature_verification_failed';
  txId: string;
  slug: string;
  httpStatus: number;
  error?: string;
  emailRegistration?: {
    status: 'activated' | 'pending_verification' | 'already_consumed' | 'pubkey_mismatch' | 'not_found' | 'not_applicable';
    contributorEmail?: string;
  };
}

| Field | Description | |-------|-------------| | ok | true if the submission was accepted by Edgar | | status | High-level outcome string | | txId | The RSA signature (transaction ID) | | slug | The public key slug (pk-...) | | httpStatus | The HTTP response status code | | error | Error message if submission failed | | emailRegistration | Present only for email-related events; describes the registration state |

CheckRegistrationResponse

Returned by checkRegistration().

interface CheckRegistrationResponse {
  registered: boolean;
  contributor_name?: string;
  contributor_email?: string;
  pending_verification?: boolean;
  error?: string;
}

Complete Examples

Email Registration Flow

const client = new DaoClient();

// 1. Register
const regResult = await client.registerEmail('[email protected]');
console.log(regResult.emailRegistration?.status);
// → 'pending_verification' — check your inbox

// 2. User clicks email link, lands back on your page with ?em=&vk=
const params = new URLSearchParams(window.location.search);
const email = params.get('em');
const vk = params.get('vk');

if (email && vk) {
  const verifyResult = await client.verifyEmail(email, vk);
  if (verifyResult.ok) {
    console.log('✓ Email verified!');
  }
}

// 3. Check authoritative status
const status = await client.checkRegistration();
if (status.registered) {
  console.log(`Active as ${status.contributor_name}`);
}

Submitting a Practice Session

const client = new DaoClient();

const result = await client.submitEvent({
  eventType: 'PRACTICE EVENT',
  fields: {
    Program: 'capoeira-tribo-mirim',
    'Practice Type': 'training-session',
    'Captured At': new Date().toISOString(),
    'Source URL': window.location.href,
    Theme: 'ginga-basics',
    'Moves Practiced': JSON.stringify([
      { id: 'ginga', name_pt: 'Ginga', duration_seconds: 300 },
    ]),
    'Music Played': JSON.stringify(['berimbau-angola']),
    'Total Practice Minutes': '45',
  },
});

if (result.ok) {
  const cvUrl = `https://truesight.me/programs/capoeira-tribo-mirim/credentials/#${result.slug}`;
  console.log('Credential:', cvUrl);
}

Submitting a Contribution

const client = new DaoClient();

const result = await client.submitEvent({
  eventType: 'CONTRIBUTION EVENT',
  fields: {
    Type: 'Time (Minutes)',
    Amount: '120',
    Description: 'Built the new onboarding flow',
    'Contributor(s)': 'Your Name',
    'TDG Issued': '200.00',
  },
});

Identity & Storage

  • Keypairs are stored in localStorage under the configured prefix (truesight_dao_ by default).
  • The constructor auto-loads existing keys on every page load — no user action needed.
  • Keys persist across sessions and page reloads automatically.
  • To reset: localStorage.removeItem('truesight_dao_public_key') and localStorage.removeItem('truesight_dao_private_key').

Build

npm run build      # CJS + IIFE (browser)
npm run build:esm  # ESM
npm test           # Runtime smoke test on the built bundle

Publishing (automatic)

Releasing is just: bump the version → merge. On any push to main that changes packages/dao-client/package.json, the npm-publish-dao-client.yml workflow builds, runs the smoke test (npm test), and publishes only if that version is new on npm. No manual step, no token handling.

# release flow
1. bump "version" in packages/dao-client/package.json (in a PR)
2. merge to main
3. CI publishes automatically (skips if the version already exists; a failing
   smoke test blocks the publish)

workflow_dispatch and dao-client-v* tags also trigger it, as escape hatches.

npm token (it expires)

CI publishes with the NPM_TOKEN GitHub Actions secret on dao_protocol (an npm Automation token for the truesight_dao org). It expires (~2026-09-06) — when it does, publishes 401 and the weekly npm-token-health.yml check fails loudly. Rotation is governor-only: regenerate an Automation token on npmjs.com → update the NPM_TOKEN secret on dao_protocol. Tracked in agentic_ai_context/OPEN_FOLLOWUPS.md. Never put the token on a server or in chat — it only lives as the GH Actions secret.

License

MIT