
Research
/Security News
Popular npm Packages in the keyv and Cacheable Namespaces Compromised in Active Supply Chain Attack
Popular npm packages keyv and cacheable compromised.
@provenonce/beats-client
Advanced tools
Minimal client for the public Beats service.
From npm (after publish):
npm i @provenonce/beats-client
Local repo path (pre-publish):
npm i ./sdk/beats-client
import { createBeatsClient } from '@provenonce/beats-client';
const beats = createBeatsClient();
const anchor = await beats.getAnchor();
const receipt = await beats.timestampHash('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
const receiptValid = await beats.verifyReceipt(receipt);
const anchorValid = await beats.verifyAnchor(anchor);
const onChain = await beats.verifyOnChain(receipt.on_chain.tx_signature, { cluster: 'devnet' });
// Auto-verify anchor receipt:
const verifiedAnchor = await beats.getAnchor({ verify: true });
GET /api/healthGET /api/v1/beat/anchorGET /api/v1/beat/keyPOST /api/v1/beat/verifyPOST /api/v1/beat/timestampPOST /api/v1/beat/work-proofverifyReceipt(response) - offline Ed25519 verification of timestamp/anchor receipts.verifyAnchor(anchorResponse) - explicit offline verification helper for anchor responses.verifyOnChain(txSignature, { cluster | rpcUrl }) - direct Solana RPC status check.getAnchor({ verify: true }) - fetch anchor and verify attached receipt in one call.submitWorkProof(proof) - submit work proof, receive signed receipt.verifyWorkProofReceipt(response) - offline Ed25519 verification of work-proof receipts.Submit a proof that N SHA-256 beats were computed at difficulty D, anchored to a recent global beat. The Beats service verifies spot-checks and returns a signed receipt.
import { computeBeat, createGenesisBeat, createBeatsClient } from '@provenonce/beats-client';
const genesis = await createGenesisBeat('my-agent-hash');
let prev = genesis;
const spotChecks = [];
for (let i = 0; i < 1000; i++) {
prev = await computeBeat(prev.hash, prev.index + 1, 1000);
if (i % 333 === 0) spotChecks.push({ index: prev.index, hash: prev.hash, prev: prev.prev });
}
const beats = createBeatsClient();
const anchor = await beats.getAnchor();
const result = await beats.submitWorkProof({
from_hash: genesis.hash,
to_hash: prev.hash,
beats_computed: 1000,
difficulty: 1000,
anchor_index: anchor.anchor.beat_index,
anchor_hash: anchor.anchor.hash,
spot_checks: spotChecks,
});
if (result.valid) {
const verified = await beats.verifyWorkProofReceipt(result);
console.log('Receipt verified offline:', verified);
console.log('Receipt:', result.receipt);
}
Agent-side sequential SHA-256 hash chain. Computes beats locally — no network required. Use getProof() to generate a work proof and submit it to the Beats service.
Node.js only (uses node:crypto).
import { LocalBeatChain, createBeatsClient } from '@provenonce/beats-client';
const chain = await LocalBeatChain.create({ seed: 'my-agent-id', difficulty: 1000 });
const beats = createBeatsClient();
// Compute beats continuously
setInterval(async () => {
await chain.advance();
}, 10); // advance every 10ms
// Submit a work proof every minute
setInterval(async () => {
const anchor = await beats.getAnchor();
chain.setAnchorIndex(anchor.anchor.beat_index, anchor.anchor.hash);
const proof = chain.getProof();
const result = await beats.submitWorkProof(proof);
if (result.valid) console.log('Work proof accepted:', result.receipt.beats_verified, 'beats');
}, 60_000);
const chain = await LocalBeatChain.create({ seed: 'my-agent', difficulty: 1000 });
chain.startAutoAdvance({
intervalMs: 100,
onAdvance: (beat, state) => console.log(`beat ${beat.index}: ${beat.hash.slice(0, 8)}...`),
onError: (err) => console.error('advance failed:', err),
});
// Later:
chain.stopAutoAdvance();
import { LocalBeatChain } from '@provenonce/beats-client';
import { readFileSync, writeFileSync } from 'fs';
// On startup: restore or create
let chain;
try {
chain = await LocalBeatChain.restore(JSON.parse(readFileSync('chain.json', 'utf8')));
console.log('Restored at beat', chain.beatCount);
} catch {
chain = await LocalBeatChain.create({ seed: 'my-agent-id', difficulty: 1000 });
}
// Persist periodically
setInterval(() => {
writeFileSync('chain.json', chain.persist());
chain.clearHistory(200); // keep last 200 beats in memory
}, 30_000);
import { LocalBeatChain, BEATS_PER_ANCHOR, MAX_RESYNC_BEATS } from '@provenonce/beats-client';
const beats = createBeatsClient();
const chain = await LocalBeatChain.create({ seed: 'my-agent', difficulty: 1000, anchorIndex: 0 });
// On reconnect: detect and compute catch-up
const anchor = await beats.getAnchor();
const gap = chain.detectGap(anchor.anchor.beat_index);
if (gap.gap_beats_needed > 0) {
console.log(`Gap of ${gap.gap_anchors} anchors — computing ${gap.gap_beats_needed} catch-up beats`);
await chain.computeCatchup(anchor.anchor.beat_index, anchor.anchor.hash);
}
| Method | Description |
|---|---|
LocalBeatChain.create(opts) | Create a new chain from a seed string |
LocalBeatChain.restore(state) | Restore from JSON.parse(chain.persist()) |
chain.advance() | Compute and append the next beat |
chain.getProof(lo?, hi?, spotCheckCount?) | Build WorkProofRequest from history |
chain.detectGap(currentAnchorIndex) | Returns { gap_anchors, gap_beats_needed, last_anchor_index } |
chain.computeCatchup(anchorIndex, anchorHash?) | Compute catch-up beats, returns count |
chain.setAnchorIndex(index, hash?) | Update anchor without computing beats |
chain.clearHistory(keepLast?) | Trim history to N most recent beats |
chain.persist() | Serialize to JSON string (includes history) |
chain.getState() | State snapshot (no history) |
chain.startAutoAdvance(opts) | Start timer-based advancing |
chain.stopAutoAdvance() | Stop timer |
Constants:
BEATS_PER_ANCHOR = 100 — Expected beats per anchor intervalMAX_RESYNC_BEATS = 10_000 — Cap on catch-up beats per resyncBeats issues signed receipts for timestamps and work proofs. Each receipt type uses a different HKDF-derived key so signatures cannot be confused across types.
BEATS_ANCHOR_KEYPAIR (Ed25519 seed)
├── [HKDF "provenonce:beats:timestamp-receipt:v1"] → Timestamp signing key
└── [HKDF "provenonce:beats:work-proof:v1"] → Work-proof signing key
GET /api/v1/beat/key returns both public keys:
{
"keys": {
"timestamp": { "public_key_hex": "...", "signing_context": "provenonce:beats:timestamp-receipt:v1" },
"work_proof": { "public_key_hex": "...", "signing_context": "provenonce:beats:work-proof:v1" }
}
}
Third-party consumers can verify receipts without calling the Beats service:
GET /api/v1/beat/keykeys.work_proof.public_key_hex for work-proof receipts{ signature, ...payload } from the receiptEd25519.verify(canonicalJSON(payload), base64decode(signature), publicKey)canonicalJSON means: sort keys alphabetically, then JSON.stringify().
// Manual verification without beats-client
import { createPublicKey, verify } from 'node:crypto';
const { signature, ...payload } = receipt;
const sortedPayload = Object.fromEntries(Object.entries(payload).sort());
const message = Buffer.from(JSON.stringify(sortedPayload), 'utf8');
const sig = Buffer.from(signature, 'base64');
const spkiPrefix = Buffer.from('302a300506032b6570032100', 'hex');
const pubKeyBytes = Buffer.from(publicKeyHex, 'hex');
const pubKeyDer = Buffer.concat([spkiPrefix, pubKeyBytes]);
const pubKey = createPublicKey({ key: pubKeyDer, format: 'der', type: 'spki' });
const valid = verify(null, message, pubKey, sig);
FAQs
Minimal client for the public Provenonce Beats service
We found that @provenonce/beats-client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Popular npm packages keyv and cacheable compromised.

Security News
A misconfiguration gave three Anthropic models internet access, and one, believing it was in a simulation, shipped a credential-stealing package to PyPI.

Security News
/Company News
Socket has joined the new Composer and Packagist sponsorship program as a launch sponsor, supporting the team that keeps PHP's package ecosystem secure.